Imported Upstream version 8.2.2 upstream upstream/8.2.2
authorANZ1217 <chihun.jeong@samsung.com>
Wed, 17 Jan 2024 07:07:00 +0000 (16:07 +0900)
committerANZ1217 <chihun.jeong@samsung.com>
Wed, 17 Jan 2024 07:07:00 +0000 (16:07 +0900)
1213 files changed:
BUILD.md
CMakeLists.txt
CONFIG.md
COPYING
ChangeLog
Makefile.am
Makefile.in
NEWS
README
README.md
README.python.md
RELEASING.md
TESTING.md
TODO [deleted file]
config.h.in
configure
configure.ac
docs/Makefile.am
docs/Makefile.in
docs/harfbuzz-docs.xml
docs/harfbuzz-sections.txt
docs/html/a-simple-shaping-example.html
docs/html/api-index-0-6-0.html
docs/html/api-index-0-9-10.html
docs/html/api-index-0-9-2.html
docs/html/api-index-1-4-0.html
docs/html/api-index-1-4-2.html
docs/html/api-index-1-7-2.html
docs/html/api-index-1-7-7.html
docs/html/api-index-3-4-0.html
docs/html/api-index-4-0-0.html [new file with mode: 0644]
docs/html/api-index-4-1-0.html [new file with mode: 0644]
docs/html/api-index-4-2-0.html [new file with mode: 0644]
docs/html/api-index-4-3-0.html [moved from docs/html/api-index-1-7-5.html with 59% similarity]
docs/html/api-index-4-4-0.html [new file with mode: 0644]
docs/html/api-index-5-0-0.html [new file with mode: 0644]
docs/html/api-index-5-3-0.html [new file with mode: 0644]
docs/html/api-index-6-0-0.html [new file with mode: 0644]
docs/html/api-index-7-0-0.html [new file with mode: 0644]
docs/html/api-index-7-1-0.html [new file with mode: 0644]
docs/html/api-index-7-3-0.html [new file with mode: 0644]
docs/html/api-index-8-0-0.html [new file with mode: 0644]
docs/html/api-index-8-1-0.html [new file with mode: 0644]
docs/html/api-index-8-2-0.html [new file with mode: 0644]
docs/html/api-index-full.html
docs/html/core-api.html
docs/html/deprecated-api-index.html
docs/html/fonts-and-faces-custom-functions.html
docs/html/fonts-and-faces-variable.html
docs/html/fonts-and-faces.html
docs/html/glyphs-and-rendering.html [new file with mode: 0644]
docs/html/harfbuzz-hb-blob.html
docs/html/harfbuzz-hb-buffer.html
docs/html/harfbuzz-hb-cairo.html [new file with mode: 0644]
docs/html/harfbuzz-hb-common.html
docs/html/harfbuzz-hb-deprecated.html
docs/html/harfbuzz-hb-directwrite.html
docs/html/harfbuzz-hb-draw.html [new file with mode: 0644]
docs/html/harfbuzz-hb-face.html
docs/html/harfbuzz-hb-features.html [new file with mode: 0644]
docs/html/harfbuzz-hb-font.html
docs/html/harfbuzz-hb-ft.html
docs/html/harfbuzz-hb-graphite2.html
docs/html/harfbuzz-hb-map.html
docs/html/harfbuzz-hb-ot-color.html
docs/html/harfbuzz-hb-ot-layout.html
docs/html/harfbuzz-hb-ot-math.html
docs/html/harfbuzz-hb-ot-metrics.html
docs/html/harfbuzz-hb-ot-name.html
docs/html/harfbuzz-hb-paint.html [new file with mode: 0644]
docs/html/harfbuzz-hb-set.html
docs/html/harfbuzz-hb-shape-plan.html
docs/html/harfbuzz-hb-shape.html
docs/html/harfbuzz-hb-style.html
docs/html/harfbuzz-hb-subset.html
docs/html/harfbuzz-hb-unicode.html
docs/html/harfbuzz-hb-version.html
docs/html/harfbuzz.devhelp2
docs/html/index.html
docs/html/integration-api.html
docs/html/integration-cairo.html [new file with mode: 0644]
docs/html/integration-freetype.html
docs/html/integration-uniscribe.html
docs/html/integration.html
docs/html/opentype-shaping-models.html
docs/html/reference-manual.html
docs/html/reordering-in-levels-0-and-1.html
docs/html/script-specific-shaping.html [moved from docs/html/complex-scripts.html with 65% similarity]
docs/html/shaping-and-shape-plans.html
docs/html/shaping-concepts.html
docs/html/shaping-opentype-features.html
docs/html/shaping-operations.html
docs/html/style-api.html
docs/html/terminology.html
docs/html/unicode-character-categories.html
docs/html/user-manual.html
docs/html/what-does-harfbuzz-do.html
docs/html/working-with-harfbuzz-clusters.html
docs/meson.build
docs/usermanual-clusters.xml
docs/usermanual-fonts-and-faces.xml
docs/usermanual-getting-started.xml
docs/usermanual-integration.xml
docs/usermanual-opentype-features.xml
docs/usermanual-shaping-concepts.xml
docs/usermanual-what-is-harfbuzz.xml
docs/version.xml
harfbuzz.doap
meson.build
meson_options.txt
mingw-configure.sh
perf/Makefile.am [new file with mode: 0644]
perf/Makefile.in [new file with mode: 0644]
perf/benchmark-font.cc [new file with mode: 0644]
perf/benchmark-map.cc [new file with mode: 0644]
perf/benchmark-ot.cc [new file with mode: 0644]
perf/benchmark-set.cc [new file with mode: 0644]
perf/benchmark-shape.cc [new file with mode: 0644]
perf/benchmark-subset.cc [new file with mode: 0644]
perf/meson.build
perf/perf-draw.hh [deleted file]
perf/perf-extents.hh [deleted file]
perf/perf-shaping.hh [deleted file]
perf/perf.cc [deleted file]
perf/texts/duployan.txt [new file with mode: 0644]
perf/texts/fa-monologue.txt [deleted file]
perf/texts/fa-words.txt [new file with mode: 0644]
perf/texts/hi-words.txt [new file with mode: 0644]
src/Makefile.am
src/Makefile.in
src/Makefile.sources
src/OT/Color/CBDT/CBDT.hh [moved from src/hb-ot-color-cbdt-table.hh with 92% similarity]
src/OT/Color/COLR/COLR.hh [moved from src/hb-ot-color-colr-table.hh with 55% similarity]
src/OT/Color/COLR/colrv1-closure.hh [moved from src/hb-ot-color-colrv1-closure.hh with 94% similarity]
src/OT/Color/CPAL/CPAL.hh [moved from src/hb-ot-color-cpal-table.hh with 75% similarity]
src/OT/Color/sbix/sbix.hh [moved from src/hb-ot-color-sbix-table.hh with 87% similarity]
src/OT/Color/svg/svg.hh [moved from src/hb-ot-color-svg-table.hh with 83% similarity]
src/OT/Layout/Common/Coverage.hh [new file with mode: 0644]
src/OT/Layout/Common/CoverageFormat1.hh [new file with mode: 0644]
src/OT/Layout/Common/CoverageFormat2.hh [new file with mode: 0644]
src/OT/Layout/Common/RangeRecord.hh [new file with mode: 0644]
src/OT/Layout/GDEF/GDEF.hh [new file with mode: 0644]
src/OT/Layout/GPOS/Anchor.hh [new file with mode: 0644]
src/OT/Layout/GPOS/AnchorFormat1.hh [new file with mode: 0644]
src/OT/Layout/GPOS/AnchorFormat2.hh [new file with mode: 0644]
src/OT/Layout/GPOS/AnchorFormat3.hh [new file with mode: 0644]
src/OT/Layout/GPOS/AnchorMatrix.hh [new file with mode: 0644]
src/OT/Layout/GPOS/ChainContextPos.hh [new file with mode: 0644]
src/OT/Layout/GPOS/Common.hh [new file with mode: 0644]
src/OT/Layout/GPOS/ContextPos.hh [new file with mode: 0644]
src/OT/Layout/GPOS/CursivePos.hh [new file with mode: 0644]
src/OT/Layout/GPOS/CursivePosFormat1.hh [new file with mode: 0644]
src/OT/Layout/GPOS/ExtensionPos.hh [new file with mode: 0644]
src/OT/Layout/GPOS/GPOS.hh [new file with mode: 0644]
src/OT/Layout/GPOS/LigatureArray.hh [new file with mode: 0644]
src/OT/Layout/GPOS/MarkArray.hh [new file with mode: 0644]
src/OT/Layout/GPOS/MarkBasePos.hh [new file with mode: 0644]
src/OT/Layout/GPOS/MarkBasePosFormat1.hh [new file with mode: 0644]
src/OT/Layout/GPOS/MarkLigPos.hh [new file with mode: 0644]
src/OT/Layout/GPOS/MarkLigPosFormat1.hh [new file with mode: 0644]
src/OT/Layout/GPOS/MarkMarkPos.hh [new file with mode: 0644]
src/OT/Layout/GPOS/MarkMarkPosFormat1.hh [new file with mode: 0644]
src/OT/Layout/GPOS/MarkRecord.hh [new file with mode: 0644]
src/OT/Layout/GPOS/PairPos.hh [new file with mode: 0644]
src/OT/Layout/GPOS/PairPosFormat1.hh [new file with mode: 0644]
src/OT/Layout/GPOS/PairPosFormat2.hh [new file with mode: 0644]
src/OT/Layout/GPOS/PairSet.hh [new file with mode: 0644]
src/OT/Layout/GPOS/PairValueRecord.hh [new file with mode: 0644]
src/OT/Layout/GPOS/PosLookup.hh [new file with mode: 0644]
src/OT/Layout/GPOS/PosLookupSubTable.hh [new file with mode: 0644]
src/OT/Layout/GPOS/SinglePos.hh [new file with mode: 0644]
src/OT/Layout/GPOS/SinglePosFormat1.hh [new file with mode: 0644]
src/OT/Layout/GPOS/SinglePosFormat2.hh [new file with mode: 0644]
src/OT/Layout/GPOS/ValueFormat.hh [new file with mode: 0644]
src/OT/Layout/GSUB/AlternateSet.hh [new file with mode: 0644]
src/OT/Layout/GSUB/AlternateSubst.hh [new file with mode: 0644]
src/OT/Layout/GSUB/AlternateSubstFormat1.hh [new file with mode: 0644]
src/OT/Layout/GSUB/ChainContextSubst.hh [new file with mode: 0644]
src/OT/Layout/GSUB/Common.hh [new file with mode: 0644]
src/OT/Layout/GSUB/ContextSubst.hh [new file with mode: 0644]
src/OT/Layout/GSUB/ExtensionSubst.hh [new file with mode: 0644]
src/OT/Layout/GSUB/GSUB.hh [new file with mode: 0644]
src/OT/Layout/GSUB/Ligature.hh [new file with mode: 0644]
src/OT/Layout/GSUB/LigatureSet.hh [new file with mode: 0644]
src/OT/Layout/GSUB/LigatureSubst.hh [new file with mode: 0644]
src/OT/Layout/GSUB/LigatureSubstFormat1.hh [new file with mode: 0644]
src/OT/Layout/GSUB/MultipleSubst.hh [new file with mode: 0644]
src/OT/Layout/GSUB/MultipleSubstFormat1.hh [new file with mode: 0644]
src/OT/Layout/GSUB/ReverseChainSingleSubst.hh [new file with mode: 0644]
src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh [new file with mode: 0644]
src/OT/Layout/GSUB/Sequence.hh [new file with mode: 0644]
src/OT/Layout/GSUB/SingleSubst.hh [new file with mode: 0644]
src/OT/Layout/GSUB/SingleSubstFormat1.hh [new file with mode: 0644]
src/OT/Layout/GSUB/SingleSubstFormat2.hh [new file with mode: 0644]
src/OT/Layout/GSUB/SubstLookup.hh [new file with mode: 0644]
src/OT/Layout/GSUB/SubstLookupSubTable.hh [new file with mode: 0644]
src/OT/Layout/types.hh [new file with mode: 0644]
src/OT/glyf/CompositeGlyph.hh [new file with mode: 0644]
src/OT/glyf/Glyph.hh [new file with mode: 0644]
src/OT/glyf/GlyphHeader.hh [new file with mode: 0644]
src/OT/glyf/SimpleGlyph.hh [new file with mode: 0644]
src/OT/glyf/SubsetGlyph.hh [new file with mode: 0644]
src/OT/glyf/VarCompositeGlyph.hh [new file with mode: 0644]
src/OT/glyf/composite-iter.hh [new file with mode: 0644]
src/OT/glyf/coord-setter.hh [new file with mode: 0644]
src/OT/glyf/glyf-helpers.hh [new file with mode: 0644]
src/OT/glyf/glyf.hh [new file with mode: 0644]
src/OT/glyf/loca.hh [new file with mode: 0644]
src/OT/glyf/path-builder.hh [new file with mode: 0644]
src/OT/name/name.hh [new file with mode: 0644]
src/check-c-linkage-decls.py
src/check-header-guards.py
src/check-includes.py
src/check-libstdc++.py
src/check-static-inits.py
src/check-symbols.py
src/fix_get_types.py [changed mode: 0644->0755]
src/gen-arabic-joining-list.py
src/gen-arabic-table.py
src/gen-def.py
src/gen-emoji-table.py
src/gen-harfbuzzcc.py
src/gen-hb-version.py
src/gen-indic-table.py
src/gen-tag-table.py
src/gen-ucd-table.py
src/gen-use-table.py
src/gen-vowel-constraints.py
src/graph/classdef-graph.hh [new file with mode: 0644]
src/graph/coverage-graph.hh [new file with mode: 0644]
src/graph/graph.hh [new file with mode: 0644]
src/graph/gsubgpos-context.cc [new file with mode: 0644]
src/graph/gsubgpos-context.hh [new file with mode: 0644]
src/graph/gsubgpos-graph.hh [new file with mode: 0644]
src/graph/markbasepos-graph.hh [new file with mode: 0644]
src/graph/pairpos-graph.hh [new file with mode: 0644]
src/graph/serialize.hh [new file with mode: 0644]
src/graph/split-helpers.hh [new file with mode: 0644]
src/graph/test-classdef-graph.cc [new file with mode: 0644]
src/harfbuzz-cairo.pc.in [new file with mode: 0644]
src/harfbuzz-config.cmake.in
src/harfbuzz-subset.cc [new file with mode: 0644]
src/harfbuzz-subset.pc.in
src/harfbuzz.cc
src/hb-aat-layout-bsln-table.hh
src/hb-aat-layout-common.hh
src/hb-aat-layout-feat-table.hh
src/hb-aat-layout-just-table.hh
src/hb-aat-layout-kerx-table.hh
src/hb-aat-layout-morx-table.hh
src/hb-aat-layout-opbd-table.hh
src/hb-aat-layout-trak-table.hh
src/hb-aat-layout.cc
src/hb-aat-layout.hh
src/hb-aat-map.cc
src/hb-aat-map.hh
src/hb-algs.hh
src/hb-array.hh
src/hb-atomic.hh
src/hb-bimap.hh
src/hb-bit-page.hh
src/hb-bit-set-invertible.hh
src/hb-bit-set.hh
src/hb-blob.cc
src/hb-blob.h
src/hb-blob.hh
src/hb-buffer-deserialize-json.hh
src/hb-buffer-deserialize-json.rl
src/hb-buffer-deserialize-text-glyphs.hh [new file with mode: 0644]
src/hb-buffer-deserialize-text-glyphs.rl [moved from src/hb-buffer-deserialize-text.rl with 62% similarity]
src/hb-buffer-deserialize-text-unicode.hh [new file with mode: 0644]
src/hb-buffer-deserialize-text-unicode.rl [new file with mode: 0644]
src/hb-buffer-deserialize-text.hh [deleted file]
src/hb-buffer-serialize.cc
src/hb-buffer-verify.cc
src/hb-buffer.cc
src/hb-buffer.h
src/hb-buffer.hh
src/hb-cache.hh
src/hb-cairo-utils.cc [new file with mode: 0644]
src/hb-cairo-utils.hh [new file with mode: 0644]
src/hb-cairo.cc [new file with mode: 0644]
src/hb-cairo.h [new file with mode: 0644]
src/hb-cff-interp-common.hh
src/hb-cff-interp-cs-common.hh
src/hb-cff-interp-dict-common.hh
src/hb-cff1-interp-cs.hh
src/hb-cff2-interp-cs.hh
src/hb-common.cc
src/hb-common.h
src/hb-config.hh
src/hb-coretext.cc
src/hb-cplusplus.hh [new file with mode: 0644]
src/hb-debug.hh
src/hb-deprecated.h
src/hb-directwrite.cc
src/hb-draw.cc
src/hb-draw.h
src/hb-draw.hh
src/hb-face-builder.cc [new file with mode: 0644]
src/hb-face.cc
src/hb-face.h
src/hb-face.hh
src/hb-fallback-shape.cc
src/hb-features.h.in [new file with mode: 0644]
src/hb-font.cc
src/hb-font.h
src/hb-font.hh
src/hb-ft-colr.hh [new file with mode: 0644]
src/hb-ft.cc
src/hb-ft.h
src/hb-glib.cc
src/hb-gobject-enums.h.tmpl
src/hb-gobject-structs.cc
src/hb-gobject-structs.h
src/hb-graphite2.cc
src/hb-graphite2.h
src/hb-iter.hh
src/hb-kern.hh
src/hb-limits.hh [new file with mode: 0644]
src/hb-machinery.hh
src/hb-map.cc
src/hb-map.h
src/hb-map.hh
src/hb-meta.hh
src/hb-ms-feature-ranges.hh
src/hb-multimap.hh [new file with mode: 0644]
src/hb-mutex.hh
src/hb-null.hh
src/hb-number.cc
src/hb-object.hh
src/hb-open-file.hh
src/hb-open-type.hh
src/hb-ot-cff-common.hh
src/hb-ot-cff1-table.cc
src/hb-ot-cff1-table.hh
src/hb-ot-cff2-table.cc
src/hb-ot-cff2-table.hh
src/hb-ot-cmap-table.hh
src/hb-ot-color.cc
src/hb-ot-color.h
src/hb-ot-deprecated.h
src/hb-ot-face-table-list.hh
src/hb-ot-face.cc
src/hb-ot-face.hh
src/hb-ot-font.cc
src/hb-ot-glyf-table.hh
src/hb-ot-hdmx-table.hh
src/hb-ot-head-table.hh
src/hb-ot-hmtx-table.hh
src/hb-ot-layout-base-table.hh
src/hb-ot-layout-common.hh
src/hb-ot-layout-gdef-table.hh
src/hb-ot-layout-gpos-table.hh
src/hb-ot-layout-gsub-table.hh
src/hb-ot-layout-gsubgpos.hh
src/hb-ot-layout.cc
src/hb-ot-layout.h
src/hb-ot-layout.hh
src/hb-ot-map.cc
src/hb-ot-map.hh
src/hb-ot-math-table.hh
src/hb-ot-math.cc
src/hb-ot-maxp-table.hh
src/hb-ot-meta-table.hh
src/hb-ot-metrics.cc
src/hb-ot-metrics.h
src/hb-ot-name-language-static.hh
src/hb-ot-name-table.hh
src/hb-ot-name.cc
src/hb-ot-name.h
src/hb-ot-os2-table.hh
src/hb-ot-os2-unicode-ranges.hh
src/hb-ot-post-table-v2subset.hh
src/hb-ot-post-table.hh
src/hb-ot-shape-complex-indic-machine.hh [deleted file]
src/hb-ot-shape-complex-indic-table.cc [deleted file]
src/hb-ot-shape-complex-indic.hh [deleted file]
src/hb-ot-shape-complex-khmer-machine.hh [deleted file]
src/hb-ot-shape-complex-khmer.hh [deleted file]
src/hb-ot-shape-complex-myanmar-machine.hh [deleted file]
src/hb-ot-shape-complex-myanmar.hh [deleted file]
src/hb-ot-shape-complex-use-machine.hh [deleted file]
src/hb-ot-shape-complex-use-table.hh [deleted file]
src/hb-ot-shape-normalize.cc
src/hb-ot-shape.cc
src/hb-ot-shape.hh
src/hb-ot-shaper-arabic-fallback.hh [moved from src/hb-ot-shape-complex-arabic-fallback.hh with 77% similarity]
src/hb-ot-shaper-arabic-joining-list.hh [moved from src/hb-ot-shape-complex-arabic-joining-list.hh with 73% similarity]
src/hb-ot-shaper-arabic-pua.hh [new file with mode: 0644]
src/hb-ot-shaper-arabic-table.hh [moved from src/hb-ot-shape-complex-arabic-table.hh with 74% similarity]
src/hb-ot-shaper-arabic-win1256.hh [moved from src/hb-ot-shape-complex-arabic-win1256.hh with 98% similarity]
src/hb-ot-shaper-arabic.cc [moved from src/hb-ot-shape-complex-arabic.cc with 89% similarity]
src/hb-ot-shaper-arabic.hh [moved from src/hb-ot-shape-complex-arabic.hh with 90% similarity]
src/hb-ot-shaper-default.cc [moved from src/hb-ot-shape-complex-default.cc with 93% similarity]
src/hb-ot-shaper-hangul.cc [moved from src/hb-ot-shape-complex-hangul.cc with 98% similarity]
src/hb-ot-shaper-hebrew.cc [moved from src/hb-ot-shape-complex-hebrew.cc with 82% similarity]
src/hb-ot-shaper-indic-machine.hh [new file with mode: 0644]
src/hb-ot-shaper-indic-machine.rl [moved from src/hb-ot-shape-complex-indic-machine.rl with 75% similarity]
src/hb-ot-shaper-indic-table.cc [new file with mode: 0644]
src/hb-ot-shaper-indic.cc [moved from src/hb-ot-shape-complex-indic.cc with 81% similarity]
src/hb-ot-shaper-indic.hh [new file with mode: 0644]
src/hb-ot-shaper-khmer-machine.hh [new file with mode: 0644]
src/hb-ot-shaper-khmer-machine.rl [moved from src/hb-ot-shape-complex-khmer-machine.rl with 70% similarity]
src/hb-ot-shaper-khmer.cc [moved from src/hb-ot-shape-complex-khmer.cc with 87% similarity]
src/hb-ot-shaper-myanmar-machine.hh [new file with mode: 0644]
src/hb-ot-shaper-myanmar-machine.rl [moved from src/hb-ot-shape-complex-myanmar-machine.rl with 62% similarity]
src/hb-ot-shaper-myanmar.cc [moved from src/hb-ot-shape-complex-myanmar.cc with 68% similarity]
src/hb-ot-shaper-syllabic.cc [moved from src/hb-ot-shape-complex-syllabic.cc with 72% similarity]
src/hb-ot-shaper-syllabic.hh [moved from src/hb-ot-shape-complex-syllabic.hh with 82% similarity]
src/hb-ot-shaper-thai.cc [moved from src/hb-ot-shape-complex-thai.cc with 95% similarity]
src/hb-ot-shaper-use-machine.hh [new file with mode: 0644]
src/hb-ot-shaper-use-machine.rl [moved from src/hb-ot-shape-complex-use-machine.rl with 74% similarity]
src/hb-ot-shaper-use-table.hh [new file with mode: 0644]
src/hb-ot-shaper-use.cc [moved from src/hb-ot-shape-complex-use.cc with 90% similarity]
src/hb-ot-shaper-vowel-constraints.cc [moved from src/hb-ot-shape-complex-vowel-constraints.cc with 91% similarity]
src/hb-ot-shaper-vowel-constraints.hh [moved from src/hb-ot-shape-complex-vowel-constraints.hh with 87% similarity]
src/hb-ot-shaper.hh [moved from src/hb-ot-shape-complex.hh with 84% similarity]
src/hb-ot-stat-table.hh
src/hb-ot-tag-table.hh
src/hb-ot-tag.cc
src/hb-ot-var-avar-table.hh
src/hb-ot-var-common.hh
src/hb-ot-var-cvar-table.hh [new file with mode: 0644]
src/hb-ot-var-fvar-table.hh
src/hb-ot-var-gvar-table.hh
src/hb-ot-var-hvar-table.hh
src/hb-ot-var-mvar-table.hh
src/hb-ot-var.cc
src/hb-ot-vorg-table.hh
src/hb-outline.cc [new file with mode: 0644]
src/hb-outline.hh [new file with mode: 0644]
src/hb-paint-extents.cc [new file with mode: 0644]
src/hb-paint-extents.hh [new file with mode: 0644]
src/hb-paint.cc [new file with mode: 0644]
src/hb-paint.h [new file with mode: 0644]
src/hb-paint.hh [new file with mode: 0644]
src/hb-pool.hh
src/hb-priority-queue.hh
src/hb-repacker.hh
src/hb-sanitize.hh
src/hb-serialize.hh
src/hb-set-digest.hh
src/hb-set.cc
src/hb-set.h
src/hb-set.hh
src/hb-shape-plan.cc
src/hb-shape-plan.h
src/hb-shape-plan.hh
src/hb-shape.cc
src/hb-shape.h
src/hb-shaper-list.hh
src/hb-shaper.cc
src/hb-static.cc
src/hb-style.cc
src/hb-style.h
src/hb-subset-accelerator.hh [new file with mode: 0644]
src/hb-subset-cff-common.cc
src/hb-subset-cff-common.hh
src/hb-subset-cff1.cc
src/hb-subset-cff2.cc
src/hb-subset-input.cc
src/hb-subset-input.hh
src/hb-subset-instancer-solver.cc [new file with mode: 0644]
src/hb-subset-instancer-solver.hh [new file with mode: 0644]
src/hb-subset-plan-member-list.hh [new file with mode: 0644]
src/hb-subset-plan.cc
src/hb-subset-plan.hh
src/hb-subset-repacker.cc [new file with mode: 0644]
src/hb-subset-repacker.h [new file with mode: 0644]
src/hb-subset.cc
src/hb-subset.h
src/hb-subset.hh
src/hb-ucd-table.hh
src/hb-ucd.cc
src/hb-unicode-emoji-table.hh
src/hb-unicode.cc
src/hb-unicode.h
src/hb-unicode.hh
src/hb-uniscribe.cc
src/hb-utf.hh
src/hb-vector.hh
src/hb-version.h
src/hb-wasm-api-blob.hh [new file with mode: 0644]
src/hb-wasm-api-buffer.hh [new file with mode: 0644]
src/hb-wasm-api-common.hh [moved from src/hb-subset-cff2.hh with 71% similarity]
src/hb-wasm-api-face.hh [new file with mode: 0644]
src/hb-wasm-api-font.hh [new file with mode: 0644]
src/hb-wasm-api-shape.hh [new file with mode: 0644]
src/hb-wasm-api.cc [moved from src/hb-subset-cff1.hh with 72% similarity]
src/hb-wasm-api.h [new file with mode: 0644]
src/hb-wasm-api.hh [new file with mode: 0644]
src/hb-wasm-shape.cc [new file with mode: 0644]
src/hb.h
src/hb.hh
src/main.cc
src/meson.build
src/relative_to.py [new file with mode: 0755]
src/test-algs.cc
src/test-array.cc
src/test-buffer-serialize.cc
src/test-gsub-get-alternates.cc [new file with mode: 0644]
src/test-item-varstore.cc [new file with mode: 0644]
src/test-iter.cc
src/test-map.cc
src/test-multimap.cc [new file with mode: 0644]
src/test-ot-glyphname.cc
src/test-ot-meta.cc
src/test-priority-queue.cc
src/test-repacker.cc
src/test-serialize.cc
src/test-set.cc
src/test-subset-instancer-solver.cc [new file with mode: 0644]
src/test-tuple-varstore.cc [new file with mode: 0644]
src/test-unicode-ranges.cc
src/test-use-table.cc [new file with mode: 0644]
src/test-vector.cc
src/test.cc
subprojects/cairo.wrap
subprojects/freetype2.wrap
subprojects/glib.wrap
subprojects/google-benchmark.wrap
subprojects/packagefiles/ragel/meson.build
subprojects/ttf-parser.wrap [deleted file]
test/COPYING [moved from test/shape/data/in-house/COPYING with 100% similarity]
test/Makefile.am
test/Makefile.in
test/api/Makefile.am
test/api/Makefile.in
test/api/fonts/AdobeVFPrototype.abc.static.otf [new file with mode: 0644]
test/api/fonts/AdobeVFPrototype.ac.retaingids.otf
test/api/fonts/RocherColorGX.abc.ttf [new file with mode: 0644]
test/api/fonts/SourceSansVariable-Roman.abc.ttf
test/api/fonts/SourceSansVariable-Roman.ac.retaingids.ttf
test/api/fonts/SourceSansVariable-Roman.ac.ttf
test/api/fonts/TestGVAREight.ttf
test/api/fonts/adwaita.ttf [new file with mode: 0644]
test/api/fonts/bad_colrv1.ttf [new file with mode: 0644]
test/api/fonts/base-minmax.ttf [new file with mode: 0644]
test/api/fonts/base2.ttf [new file with mode: 0644]
test/api/fonts/nameID.override.expected.ttf [new file with mode: 0644]
test/api/fonts/noto_handwriting-cff2_colr_1.otf [new file with mode: 0644]
test/api/fonts/notosansitalic.ttf [new file with mode: 0644]
test/api/fonts/repacker_expected.otf [new file with mode: 0644]
test/api/fonts/test_glyphs-glyf_colr_1.ttf [new file with mode: 0644]
test/api/fonts/test_glyphs-glyf_colr_1_variable.ttf [new file with mode: 0644]
test/api/hb-test.h
test/api/meson.build
test/api/results/bad-154 [new file with mode: 0644]
test/api/results/hand-10 [new file with mode: 0644]
test/api/results/hand-10.2 [new file with mode: 0644]
test/api/results/rocher-1 [new file with mode: 0644]
test/api/results/rocher-2 [new file with mode: 0644]
test/api/results/rocher-3 [new file with mode: 0644]
test/api/results/test-10 [new file with mode: 0644]
test/api/results/test-106 [new file with mode: 0644]
test/api/results/test-116 [new file with mode: 0644]
test/api/results/test-123 [new file with mode: 0644]
test/api/results/test-154 [new file with mode: 0644]
test/api/results/test-165 [new file with mode: 0644]
test/api/results/test-175 [new file with mode: 0644]
test/api/results/test-6 [new file with mode: 0644]
test/api/results/test-92 [new file with mode: 0644]
test/api/results/testvf-10 [new file with mode: 0644]
test/api/results/testvf-106 [new file with mode: 0644]
test/api/results/testvf-116 [new file with mode: 0644]
test/api/results/testvf-123 [new file with mode: 0644]
test/api/results/testvf-154 [new file with mode: 0644]
test/api/results/testvf-165 [new file with mode: 0644]
test/api/results/testvf-175 [new file with mode: 0644]
test/api/results/testvf-6 [new file with mode: 0644]
test/api/results/testvf-92 [new file with mode: 0644]
test/api/test-base-minmax.c [new file with mode: 0644]
test/api/test-baseline.c
test/api/test-be-glyph-advance.c [new file with mode: 0644]
test/api/test-be-num-glyphs.c [new file with mode: 0644]
test/api/test-c.c
test/api/test-collect-unicodes.c
test/api/test-common.c
test/api/test-coretext.c [new file with mode: 0644]
test/api/test-cplusplus.cc
test/api/test-draw.c
test/api/test-extents.c [new file with mode: 0644]
test/api/test-ft.c [new file with mode: 0644]
test/api/test-glyph-names.c [new file with mode: 0644]
test/api/test-instance-cff2.c [new file with mode: 0644]
test/api/test-ot-color.c
test/api/test-ot-face.c
test/api/test-ot-metrics-tt-var.c
test/api/test-ot-name.c
test/api/test-paint.c [new file with mode: 0644]
test/api/test-set.c
test/api/test-style.c
test/api/test-subset-nameids.c
test/api/test-subset-repacker.c [new file with mode: 0644]
test/api/test-subset.c
test/api/test-unicode.c
test/api/test-var-coords.c
test/fuzzing/Makefile.am
test/fuzzing/Makefile.in
test/fuzzing/README [deleted file]
test/fuzzing/README.md [new file with mode: 0644]
test/fuzzing/fonts/AdobeVFPrototype.ABC.otf [new file with mode: 0644]
test/fuzzing/fonts/Roboto-Variable.ABC.ttf [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5446125635633152 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5508865908670464 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5979721620652032 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5667125715927040 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5692635449524224 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-4579249263345664 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-4877513265119232 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6490945267564544 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6697168080338944 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-4523349576908800 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-4787105656864768 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5114131137822720 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5349416110784512 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5965759719538688 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-6377756666757120 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-6635625931735040 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4549472192692224 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4549523149553664 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4552226966994944 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4575222591520768 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4801020053291008 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4875306193518592.fuzz [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4877336988483584 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4916785942757376 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5029952234586112 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5120246288875520 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5145429829877760 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5191907895279616 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5192684970311680 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5234369031176192 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5388270411579392 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5417800474165248 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5419002026131456 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5458896606855168 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5568200165687296 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5693568490012672 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5793182905663488 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5842152921628672 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5844352760152064 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5845846876356608 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5855710991482880.fuzz [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6032126569742336 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6164014466203648 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6169920089227264 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6187272924692480 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6292420615340032 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6362213417353216 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6365271012540416 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6442117271257088 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6521393809588224 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6525813890875392 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6608005089853440 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6681253479579648 [new file with mode: 0644]
test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6742230974201856 [new file with mode: 0644]
test/fuzzing/fonts/sbix-extents.ttf [new file with mode: 0644]
test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-5196242811748352 [new file with mode: 0644]
test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-5390364397928448 [new file with mode: 0644]
test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-5475787333828608 [new file with mode: 0644]
test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6014493291577344 [new file with mode: 0644]
test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6419865171525632 [new file with mode: 0644]
test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6714085985353728 [new file with mode: 0644]
test/fuzzing/graphs/crash-3bf72494aa4c9f8cbbcbf887fdc2a2858c87feb4 [new file with mode: 0644]
test/fuzzing/graphs/crash-442bfac994a3d9929cf06262ae9fb00f6ee1f774 [new file with mode: 0644]
test/fuzzing/graphs/leak-a77f29b25edb873729f3ab120148fdb213cfa527 [new file with mode: 0644]
test/fuzzing/graphs/noto_nastaliq_urdu [new file with mode: 0644]
test/fuzzing/hb-draw-fuzzer.cc
test/fuzzing/hb-fuzzer.hh
test/fuzzing/hb-repacker-fuzzer.cc [new file with mode: 0644]
test/fuzzing/hb-set-fuzzer.cc
test/fuzzing/hb-shape-fuzzer.cc
test/fuzzing/hb-subset-fuzzer.cc
test/fuzzing/meson.build
test/fuzzing/run-repacker-fuzzer-tests.py [new file with mode: 0644]
test/fuzzing/sets/clusterfuzz-testcase-minimized-hb-set-fuzzer-6255224052514816 [new file with mode: 0644]
test/fuzzing/sets/intersect_01 [new file with mode: 0644]
test/fuzzing/sets/subtract_01 [new file with mode: 0644]
test/fuzzing/sets/symmetric_diff_01 [new file with mode: 0644]
test/fuzzing/sets/union_01 [new file with mode: 0644]
test/meson.build
test/shape/Makefile.am
test/shape/Makefile.in
test/shape/README.md
test/shape/data/Makefile.in
test/shape/data/aots/Makefile.in
test/shape/data/in-house/Makefile.am
test/shape/data/in-house/Makefile.in
test/shape/data/in-house/Makefile.sources
test/shape/data/in-house/fonts/086d83239e8f958391ff6cdd8fda9376a4bd3673.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/190a621e48d4af1fffd8144bd41d2027e9a32fbf.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/23406a60ab081c4fb15e1596ea1cd4f27ae8443e.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/41071178fbce4956d151f50967af458dbf555f7b.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/507637795ce4f2975593da54d12b46f76c7cc4cc.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/5bbf3712e6f79775c66a4407837a90e591efbef2.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/5f73fff1ffc07b5a99a90c0909609f2b09fef274.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/641ca9d7808b01cafa9a666c13811c9b56eb9c52.ttf [deleted file]
test/shape/data/in-house/fonts/7c24183f26d60df414578a0a9f5e79ab9d32a22b.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/8339c821814d9bad7c77169332327ad8b0f33c81.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/9d8c53cb64b8747abdd2b70755cce2ee0eb42ef7.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/SimpArabicTest.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/TradArabicTest.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/a232bb734d4c6c898a44506547d19768f0eba6a6.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/a56745bac8449d0ad94918b2bb5930716ba02fe3.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/a59fd13f1525a91cbe529c882e93d9d1fbb80463.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/bef923f4ccb474f961c43b63a9c74b7d9b7a023f.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/d0430ea499348c420946f6abc2efc84fdf8f00e3.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/e716f6bd00a108d186b7e9f47b4515565f784f36.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf [new file with mode: 0644]
test/shape/data/in-house/fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf [new file with mode: 0644]
test/shape/data/in-house/meson.build
test/shape/data/in-house/tests/arabic-fallback-shaping.tests
test/shape/data/in-house/tests/arabic-mark-attach.tests [deleted file]
test/shape/data/in-house/tests/arabic-phags-pa.tests [new file with mode: 0644]
test/shape/data/in-house/tests/arabic-stch.tests
test/shape/data/in-house/tests/automatic-fractions.tests
test/shape/data/in-house/tests/collections.tests
test/shape/data/in-house/tests/context-matching.tests
test/shape/data/in-house/tests/coretext.tests [new file with mode: 0644]
test/shape/data/in-house/tests/cursive-positioning.tests
test/shape/data/in-house/tests/directwrite.tests [new file with mode: 0644]
test/shape/data/in-house/tests/emoji-clusters.tests
test/shape/data/in-house/tests/hebrew-diacritics.tests [new file with mode: 0644]
test/shape/data/in-house/tests/indic-decompose.tests
test/shape/data/in-house/tests/indic-feature-order.tests [new file with mode: 0644]
test/shape/data/in-house/tests/indic-malayalam-dot-reph.tests [new file with mode: 0644]
test/shape/data/in-house/tests/indic-special-cases.tests
test/shape/data/in-house/tests/indic-syllable.tests
test/shape/data/in-house/tests/khmer-misc.tests
test/shape/data/in-house/tests/ligature-id.tests
test/shape/data/in-house/tests/macos.tests
test/shape/data/in-house/tests/myanmar-misc.tests
test/shape/data/in-house/tests/sara-am.tests [new file with mode: 0644]
test/shape/data/in-house/tests/spaces.tests
test/shape/data/in-house/tests/uniscribe.tests [new file with mode: 0644]
test/shape/data/in-house/tests/unsafe-to-concat.tests
test/shape/data/in-house/tests/use-javanese.tests [new file with mode: 0644]
test/shape/data/in-house/tests/use-syllable.tests
test/shape/data/in-house/tests/use.tests
test/shape/data/in-house/tests/vertical.tests
test/shape/data/text-rendering-tests/Makefile.in
test/shape/data/text-rendering-tests/fonts/TestGVAR-Composite-0.ttf
test/shape/data/text-rendering-tests/fonts/TestGVAR-Composite-Missing.ttf
test/shape/data/text-rendering-tests/fonts/TestGVAREight.ttf
test/shape/meson.build
test/shape/record-test.sh
test/shape/run-tests.py
test/shape/texts/in-house/shaper-arabic/script-arabic/language-persian/mehran.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/2grams.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/3grams.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/4grams.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/5grams.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/6grams.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/7grams.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/8grams.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/LICENSE [deleted file]
test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/README [deleted file]
test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/SOURCES [deleted file]
test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/lam-alef.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-arabic.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-persian.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-urdu.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/ligature-components.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/ligature-diacritics.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/mark-skipping.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/misc.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/non-joining.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/poem.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/variation-selectors.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-nko/misc/misc.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-phags-pa/misc/misc.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-syriac/misc/abbreviation-mark.txt [deleted file]
test/shape/texts/in-house/shaper-arabic/script-syriac/misc/alaph.txt [deleted file]
test/shape/texts/in-house/shaper-default/script-ethiopic/misc/misc.txt [deleted file]
test/shape/texts/in-house/shaper-default/script-han/misc/cjk-compat.txt [deleted file]
test/shape/texts/in-house/shaper-default/script-hiragana/misc/kazuraki-liga-lines.txt [deleted file]
test/shape/texts/in-house/shaper-default/script-hiragana/misc/kazuraki-liga.txt [deleted file]
test/shape/texts/in-house/shaper-default/script-linear-b/misc/misc.txt [deleted file]
test/shape/texts/in-house/shaper-default/script-tifinagh/misc/misc.txt [deleted file]
test/shape/texts/in-house/shaper-hangul/script-hangul/misc/misc.txt [deleted file]
test/shape/texts/in-house/shaper-hebrew/script-hebrew/misc/diacritics.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/LICENSE [deleted file]
test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/README [deleted file]
test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/SOURCES [deleted file]
test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gsub/IndicFontFeatureGSUB.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-bengali/bengali-vowel-letters.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-bengali/misc/misc.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-bengali/misc/reph.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/LICENSE [deleted file]
test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/README [deleted file]
test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/SOURCES [deleted file]
test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gsub/IndicFontFeatureGSUB.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/devanagari-atomic-consonants.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/devanagari-vowel-letters.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/misc/dottedcircle.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/misc/eyelash.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/misc/joiners.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/misc/misc.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/misc/spec-deviations.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/misc/tricky-reordering.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/LICENSE [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/README [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/SOURCES [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DevnagariSpecificAddition.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-GenericPunctuation.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gsub/IndicFontFeatureGSUB.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gujarati/gujarati-vowel-letters.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/LICENSE [deleted file]
test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/README [deleted file]
test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/SOURCES [deleted file]
test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gsub/IndicFontFeatureGSUB.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gurmukhi/gurmukhi-vowel-letters.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gurmukhi/misc/misc.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/LICENSE [deleted file]
test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/README [deleted file]
test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/SOURCES [deleted file]
test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-GurmukhiSpecific.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gsub/IndicFontFeatureGSUB.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-kannada/kannada-vowel-letters.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-kannada/misc/misc.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-kannada/misc/right-matras.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/LICENSE [deleted file]
test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/README [deleted file]
test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/SOURCES [deleted file]
test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/gsub/IndicFontFeatureGSUB.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-malayalam/malayalam-vowel-letters.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-malayalam/misc/cibu.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-malayalam/misc/dot-reph.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-malayalam/misc/misc.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/LICENSE [deleted file]
test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/README [deleted file]
test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/SOURCES [deleted file]
test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/gsub/IndicFontFeatureGSUB.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-oriya/misc/bindu.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-oriya/misc/misc.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-oriya/oriya-vowel-letters.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/LICENSE [deleted file]
test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/README [deleted file]
test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/SOURCES [deleted file]
test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-OriyaSpecific.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/gsub/IndicFontFeatureGSUB.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/misc/extensive.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/misc/misc.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/misc/reph.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/misc/split-matras.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/LICENSE [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/README [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/SOURCES [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Punctuation.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gpos/IndicFontFeatureGPOS.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Conjunct.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Rakaaraansaya.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Repaya.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Special-Cases.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-TouchingLetters.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Yansaya.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-tamil/misc/misc.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/LICENSE [deleted file]
test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/README [deleted file]
test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/SOURCES [deleted file]
test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-CurrencySymbols.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Numerics.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Symbols.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-TamilSymbol.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gsub/IndicFontFeatureGSUB.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-telugu/misc/misc.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-telugu/telugu-vowel-letters.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/LICENSE [deleted file]
test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/README [deleted file]
test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/SOURCES [deleted file]
test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt [deleted file]
test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/gsub/IndicFontFeatureGSUB.txt [deleted file]
test/shape/texts/in-house/shaper-khmer/misc.txt [deleted file]
test/shape/texts/in-house/shaper-khmer/other-marks-invalid.txt [deleted file]
test/shape/texts/in-house/shaper-khmer/other-marks.txt [deleted file]
test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/misc.txt [deleted file]
test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/otspec.txt [deleted file]
test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/utn11.txt [deleted file]
test/shape/texts/in-house/shaper-thai/script-lao/misc/sara-am.txt [deleted file]
test/shape/texts/in-house/shaper-thai/script-thai/misc/misc.txt [deleted file]
test/shape/texts/in-house/shaper-thai/script-thai/misc/phinthu.txt [deleted file]
test/shape/texts/in-house/shaper-thai/script-thai/misc/pua-shaping.txt [deleted file]
test/shape/texts/in-house/shaper-thai/script-thai/misc/sara-am.txt [deleted file]
test/shape/texts/in-house/shaper-tibetan/script-tibetan/misc/contractions.txt [deleted file]
test/shape/texts/in-house/shaper-tibetan/script-tibetan/misc/misc.txt [deleted file]
test/shape/texts/in-house/shaper-use/script-batak/misc.txt [deleted file]
test/shape/texts/in-house/shaper-use/script-buginese/misc.txt [deleted file]
test/shape/texts/in-house/shaper-use/script-cham/misc.txt [deleted file]
test/shape/texts/in-house/shaper-use/script-javanese/misc.txt [deleted file]
test/shape/texts/in-house/shaper-use/script-kaithi/misc.txt [deleted file]
test/shape/texts/in-house/shaper-use/script-kharoshti/misc.txt [deleted file]
test/shape/texts/in-house/shaper-use/script-tai-tham/misc.txt [deleted file]
test/shape/texts/in-house/shaper-use/script-tai-tham/torture.txt [deleted file]
test/subset/Makefile.in
test/subset/data/Makefile.am
test/subset/data/Makefile.in
test/subset/data/Makefile.sources
test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62,63,64.otf [new file with mode: 0644]
test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62.otf [new file with mode: 0644]
test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,63.otf [new file with mode: 0644]
test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,64.otf [new file with mode: 0644]
test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61.otf [new file with mode: 0644]
test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.62.otf [new file with mode: 0644]
test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.63.otf [new file with mode: 0644]
test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.64.otf [new file with mode: 0644]
test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62,63,64.otf [new file with mode: 0644]
test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62.otf [new file with mode: 0644]
test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,63.otf [new file with mode: 0644]
test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,64.otf [new file with mode: 0644]
test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61.otf [new file with mode: 0644]
test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.62.otf [new file with mode: 0644]
test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.63.otf [new file with mode: 0644]
test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.64.otf [new file with mode: 0644]
test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.retain-all-codepoint.wght=300.ttf [new file with mode: 0644]
test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.retain-all-codepoint.wght=700.ttf [new file with mode: 0644]
test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.retain-all-codepoint.wght=300.ttf [new file with mode: 0644]
test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.retain-all-codepoint.wght=700.ttf [new file with mode: 0644]
test/subset/data/expected/collect_name_ids/SourceSerif4Variable-Roman_subset.keep-all-layout-features.retain-all-codepoint.otf [new file with mode: 0644]
test/subset/data/expected/colr_with_components/colr-table.default.6B.ttf
test/subset/data/expected/colr_with_components/colr-table.drop-hints-retain-gids.6B.ttf
test/subset/data/expected/colr_with_components/colr-table.drop-hints.6B.ttf
test/subset/data/expected/colr_with_components/colr-table.retain-gids.6B.ttf
test/subset/data/expected/colrv1_copy_varstore/Foldit.default.41,42.ttf [new file with mode: 0644]
test/subset/data/expected/colrv1_copy_varstore/Foldit.default.41.ttf [new file with mode: 0644]
test/subset/data/expected/colrv1_copy_varstore/Foldit.default.retain-all-codepoint.ttf [new file with mode: 0644]
test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.41,42.ttf [new file with mode: 0644]
test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.41.ttf [new file with mode: 0644]
test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.retain-all-codepoint.ttf [new file with mode: 0644]
test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.41,42.ttf [new file with mode: 0644]
test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.41.ttf [new file with mode: 0644]
test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.retain-all-codepoint.ttf [new file with mode: 0644]
test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.41,42.ttf [new file with mode: 0644]
test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.41.ttf [new file with mode: 0644]
test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.retain-all-codepoint.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.1FC,21,41,20,62,63.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.1FC,21,41,20,62,63.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.D7,D8,D9,DA,DE.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.1FC,21,41,20,62,63.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.D7,D8,D9,DA,DE.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/Roboto-Regular.no-scripts.1FC,21,41,20,62,63.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/Roboto-Regular.no-scripts.D7,D8,D9,DA,DE.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.1FC,21,41,20,62,63.ttf
test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.1FC,21,41,20,62,63.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.1FC,21,41,20,62,63.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.D7,D8,D9,DA,DE.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.1FC,21,41,20,62,63.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.D7,D8,D9,DA,DE.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.1FC,21,41,20,62,63.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63.ttf [new file with mode: 0644]
test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.D7,D8,D9,DA,DE.ttf [new file with mode: 0644]
test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=150,wdth=80.ttf [new file with mode: 0644]
test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=300,wdth=90.ttf [new file with mode: 0644]
test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=150,wdth=80.ttf [new file with mode: 0644]
test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=300,wdth=90.ttf [new file with mode: 0644]
test/subset/data/expected/glyph_map/Roboto-Regular.glyph_map_roboto.41,43,61,66,69.ttf [new file with mode: 0644]
test/subset/data/expected/instance_comp_glyph_empty_child/RobotoMono.default.retain-all-codepoint.wght=700.ttf [new file with mode: 0644]
test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.30DD.wght=100.ttf [new file with mode: 0644]
test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.30DD.wght=400.ttf [new file with mode: 0644]
test/subset/data/expected/instance_no_double_free/Handjet.default.retain-all-codepoint.wght=100,ELGR=1,ELSH=2.ttf [new file with mode: 0644]
test/subset/data/expected/instance_no_double_free/Handjet.notdef-outline.retain-all-codepoint.wght=100,ELGR=1,ELSH=2.ttf [new file with mode: 0644]
test/subset/data/expected/instantiate_cff2/AdobeVFPrototype.default.retain-all-codepoint.wght=650,CNTR=50.otf [new file with mode: 0644]
test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.default.retain-all-codepoint.wght=800.otf [new file with mode: 0644]
test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.retain-gids.retain-all-codepoint.wght=800.otf [new file with mode: 0644]
test/subset/data/expected/instantiate_colrv1/Foldit.default.retain-all-codepoint.wght=900.ttf [new file with mode: 0644]
test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=200,wdth=90.ttf [new file with mode: 0644]
test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=650,wdth=85.ttf [new file with mode: 0644]
test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=200,wdth=90.ttf [new file with mode: 0644]
test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=650,wdth=85.ttf [new file with mode: 0644]
test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42.otf
test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42,43.otf
test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42.otf
test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
test/subset/data/expected/layout.default_features/FranklinGothic-Regular.default.61,63,68,69.ttf [deleted file]
test/subset/data/expected/layout.default_features/FranklinGothic-Regular.default.retain-all-codepoint.ttf [deleted file]
test/subset/data/expected/layout.default_features/FranklinGothic-Regular.layout-test.61,63,68,69.ttf [deleted file]
test/subset/data/expected/layout.default_features/FranklinGothic-Regular.layout-test.retain-all-codepoint.ttf [deleted file]
test/subset/data/expected/layout.default_features/FranklinGothic-Regular.retain-gids.61,63,68,69.ttf [deleted file]
test/subset/data/expected/layout.default_features/FranklinGothic-Regular.retain-gids.retain-all-codepoint.ttf [deleted file]
test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.retain-all-codepoint.ttf
test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.retain-all-codepoint.ttf
test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.retain-all-codepoint.ttf
test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43,57.otf
test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43.otf
test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42.otf
test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,56,57.otf
test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41.otf
test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.42,57.otf
test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43,57.otf
test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43.otf
test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42.otf
test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,56,57.otf
test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41.otf
test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.42,57.otf
test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf
test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42.otf
test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf
test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42,43.otf
test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42.otf
test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.retain-all-codepoint.otf
test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,62D,628.ttf
test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,6D2.ttf
test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.63A,64A,631.ttf
test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.retain-all-codepoint.ttf
test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,62D,628.ttf
test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,6D2.ttf
test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.63A,64A,631.ttf
test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.retain-all-codepoint.ttf
test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.retain-all-codepoint.wght=150,wdth=80,CTGR=0.ttf [new file with mode: 0644]
test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.retain-all-codepoint.wght=300,wdth=90,CTGR=0.ttf [new file with mode: 0644]
test/subset/data/expected/no_layout_closure/Roboto-Regular.no-layout-closure-gids.no-unicodes.ttf [new file with mode: 0644]
test/subset/data/expected/no_layout_closure/Roboto-Regular.no-layout-closure-gids2.no-unicodes.ttf [new file with mode: 0644]
test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=400,wdth=100.0.ttf [new file with mode: 0644]
test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=drop,wdth=100.ttf [new file with mode: 0644]
test/subset/data/expected/post_apply_mvar_delta/Recursive-ABC.no-layout.retain-all-codepoint.wght=400,CASL=0,CRSV=0,MONO=0,slnt=0.ttf [new file with mode: 0644]
test/subset/data/expected/preprocess/Roboto-Regular.gids.61,62,63,30D9.ttf [new file with mode: 0644]
test/subset/data/expected/variable/Fraunces.default.61.ttf
test/subset/data/expected/variable/Fraunces.retain-gids.26,66,69,124,125.ttf [new file with mode: 0644]
test/subset/data/expected/variable/Fraunces.retain-gids.61.ttf [new file with mode: 0644]
test/subset/data/fonts/32bit_var_store.otf [new file with mode: 0644]
test/subset/data/fonts/Cantarell-VF-ABC.otf [new file with mode: 0644]
test/subset/data/fonts/Foldit.ttf [new file with mode: 0644]
test/subset/data/fonts/FranklinGothic-Regular.ttf [deleted file]
test/subset/data/fonts/Handjet.ttf [new file with mode: 0644]
test/subset/data/fonts/MPLUS1-Variable.ttf [new file with mode: 0644]
test/subset/data/fonts/Muli-ABC.ttf [new file with mode: 0644]
test/subset/data/fonts/NotoSans-VF.abc.ttf [new file with mode: 0644]
test/subset/data/fonts/NotoSansDevanagari-Regular.ttf [moved from perf/fonts/NotoSansDevanagari-Regular.ttf with 100% similarity]
test/subset/data/fonts/Recursive-ABC.ttf [new file with mode: 0644]
test/subset/data/fonts/Roboto-Variable.ABC.ttf [new file with mode: 0644]
test/subset/data/fonts/Roboto-Variable.composite.ttf [new file with mode: 0644]
test/subset/data/fonts/Roboto-Variable.ttf [new file with mode: 0644]
test/subset/data/fonts/RobotoFlex-Variable.ttf [new file with mode: 0644]
test/subset/data/fonts/RobotoMono.ttf [new file with mode: 0644]
test/subset/data/fonts/SourceSerif4Variable-Roman_subset.otf [new file with mode: 0644]
test/subset/data/fonts/colr-table.ttf
test/subset/data/profiles/filter-scripts-features.2.txt [new file with mode: 0644]
test/subset/data/profiles/filter-scripts-features.txt [new file with mode: 0644]
test/subset/data/profiles/filter-scripts.txt [new file with mode: 0644]
test/subset/data/profiles/glyph_map_roboto.txt [new file with mode: 0644]
test/subset/data/profiles/no-layout-closure-gids.txt [new file with mode: 0644]
test/subset/data/profiles/no-layout-closure-gids2.txt [new file with mode: 0644]
test/subset/data/profiles/no-layout.txt [new file with mode: 0644]
test/subset/data/profiles/no-scripts.txt [new file with mode: 0644]
test/subset/data/profiles/no-tables-with-item-variations.txt [new file with mode: 0644]
test/subset/data/repack_tests/Makefile.in
test/subset/data/tests/32bit_var_store.tests [new file with mode: 0644]
test/subset/data/tests/apply_cvar_delta.tests [new file with mode: 0644]
test/subset/data/tests/collect_name_ids.tests [new file with mode: 0644]
test/subset/data/tests/colrv1_copy_varstore.tests [moved from test/subset/data/tests/layout.default_features.tests with 50% similarity]
test/subset/data/tests/full-font.tests
test/subset/data/tests/full_instance.tests [new file with mode: 0644]
test/subset/data/tests/glyph_map.tests [new file with mode: 0644]
test/subset/data/tests/instance_comp_glyph_empty_child.tests [new file with mode: 0644]
test/subset/data/tests/instance_feature_variations.tests [new file with mode: 0644]
test/subset/data/tests/instance_no_double_free.tests [new file with mode: 0644]
test/subset/data/tests/instantiate_cff2.tests [new file with mode: 0644]
test/subset/data/tests/instantiate_cff2_update_metrics.tests [new file with mode: 0644]
test/subset/data/tests/instantiate_colrv1.tests [new file with mode: 0644]
test/subset/data/tests/instantiate_glyf.tests [new file with mode: 0644]
test/subset/data/tests/mvar_full_instance.tests [new file with mode: 0644]
test/subset/data/tests/no_layout_closure.tests [new file with mode: 0644]
test/subset/data/tests/pin_all_at_default.tests [new file with mode: 0644]
test/subset/data/tests/post_apply_mvar_delta.tests [new file with mode: 0644]
test/subset/data/tests/preprocess.tests [new file with mode: 0644]
test/subset/data/tests/variable.tests
test/subset/meson.build
test/subset/run-tests.py
test/subset/subset_test_suite.py
test/threads/Makefile.am [new file with mode: 0644]
test/threads/Makefile.in [new file with mode: 0644]
test/threads/hb-shape-threads.cc [new file with mode: 0644]
test/threads/hb-subset-threads.cc [new file with mode: 0644]
test/threads/meson.build [new file with mode: 0644]
util/Makefile.am
util/Makefile.in
util/Makefile.sources
util/ansi-print.hh
util/face-options.hh
util/font-options.hh
util/hb-info.cc [new file with mode: 0644]
util/hb-ot-shape-closure.cc
util/hb-shape.cc
util/hb-subset.cc
util/helper-cairo-ansi.hh
util/helper-cairo-ft.hh [new file with mode: 0644]
util/helper-cairo.hh
util/main-font-text.hh
util/meson.build
util/options.hh
util/shape-consumer.hh
util/shape-format.hh
util/shape-options.hh
util/shape-output.hh [new file with mode: 0644]
util/text-options.hh
util/view-cairo.hh
util/view-options.hh

index f64f868..55e950e 100644 (file)
--- a/BUILD.md
+++ b/BUILD.md
@@ -1,27 +1,32 @@
-On Linux, install the development packages for FreeType,
-Cairo, and GLib. For example, on Ubuntu / Debian, you would do:
+On Linux, install the development packages for FreeType, Cairo, and GLib. For
+example, on Ubuntu / Debian, you would do:
 
-    sudo apt-get install meson pkg-config ragel gtk-doc-tools gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev
+    sudo apt-get install meson pkg-config ragel gtk-doc-tools gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev
 
 whereas on Fedora, RHEL, CentOS, and other Red Hat based systems you would do:
 
-    sudo dnf install meson pkgconfig gtk-doc gcc gcc-c++ freetype-devel glib2-devel cairo-dev
+    $ sudo dnf install meson pkgconfig gtk-doc gcc gcc-c++ freetype-devel glib2-devel cairo-devel
 
 and on ArchLinux and Manjaro:
 
-    sudo pacman -Suy meson pkg-config ragel gcc freetype2 glib2 cairo
+    sudo pacman -Suy meson pkg-config ragel gcc freetype2 glib2 cairo
 
-then use meson to build the project like `meson build && meson test -Cbuild`.
+On macOS:
 
-On macOS, `brew install pkg-config ragel gtk-doc freetype glib cairo meson` then use
-meson like above.
+    brew install pkg-config ragel gtk-doc freetype glib cairo meson
 
-On Windows, meson can build the project like above if a working MSVC's cl.exe (`vcvarsall.bat`)
-or gcc/clang is already on your path, and if you use something like `meson build --wrap-mode=default`
-it fetches and compiles most of the dependencies also.
+Then use meson to build the project like:
 
-Our CI configurations is also a good source of learning how to build HarfBuzz.
+    meson build && meson test -Cbuild
 
-There is also amalgam source provided with HarfBuzz which reduces whole process of building
-HarfBuzz like `g++ src/harfbuzz.cc -fno-exceptions` but there is not guarantee provided
-with buildability and reliability of features you get.
+On Windows, meson can build the project like above if a working MSVC's cl.exe
+(`vcvarsall.bat`) or gcc/clang is already on your path, and if you use
+something like `meson build --wrap-mode=default` it fetches and compiles most
+of the dependencies also.  It is recommended to install CMake either manually
+or via the Visual Studio installer when building with MSVC, using meson.
+
+Our CI configurations are also a good source of learning how to build HarfBuzz.
+
+There is also amalgamated source provided with HarfBuzz which reduces whole process
+of building HarfBuzz to `g++ src/harfbuzz.cc -fno-exceptions` but there is
+no guarantee provided with buildability and reliability of features you get.
index 3259ca9..e22f2cf 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.1)
+cmake_minimum_required(VERSION 3.12)
 project(harfbuzz)
 
 message(WARN "HarfBuzz has a Meson port and tries to migrate all the other build systems to it, please consider using it as we might remove our cmake port soon.")
@@ -80,6 +80,7 @@ include (FindPythonInterp)
 ## Functions and headers
 include (CheckFunctionExists)
 include (CheckIncludeFile)
+include (CheckIncludeFiles)
 macro (check_funcs) # Similar to AC_CHECK_FUNCS of autotools
   foreach (func_name ${ARGN})
     string(TOUPPER ${func_name} definition_to_add)
@@ -106,12 +107,17 @@ if (${HAVE_STDBOOL_H})
   add_definitions(-DHAVE_STDBOOL_H)
 endif ()
 
+# These will be used while making pkg-config .pc files
+set(PC_REQUIRES_PRIV "")
+set(PC_LIBS_PRIV "")
+
 if (NOT MSVC)
   set(THREADS_PREFER_PTHREAD_FLAG ON)
   find_package(Threads)
   if (CMAKE_USE_PTHREADS_INIT)
     add_definitions("-DHAVE_PTHREAD")
     list(APPEND THIRD_PARTY_LIBS Threads::Threads)
+    list(APPEND PC_LIBS_PRIV -pthread)
   endif ()
 endif ()
 
@@ -207,6 +213,10 @@ if (HB_HAVE_FREETYPE AND NOT TARGET freetype)
   check_funcs(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var)
 endif ()
 
+if (HB_HAVE_FREETYPE)
+  list(APPEND PC_REQUIRES_PRIV "freetype2 >= 12.0.6")
+endif ()
+
 if (HB_HAVE_GRAPHITE2)
   add_definitions(-DHAVE_GRAPHITE2)
 
@@ -219,6 +229,8 @@ if (HB_HAVE_GRAPHITE2)
 
   list(APPEND THIRD_PARTY_LIBS ${GRAPHITE2_LIBRARY})
 
+  list(APPEND PC_REQUIRES_PRIV "graphite2 >= 1.2.0")
+
   mark_as_advanced(GRAPHITE2_INCLUDE_DIR GRAPHITE2_LIBRARY)
 endif ()
 
@@ -239,6 +251,8 @@ if (HB_HAVE_GLIB)
 
   list(APPEND THIRD_PARTY_LIBS ${GLIB_LIBRARIES})
 
+  list(APPEND PC_REQUIRES_PRIV "glib-2.0 >= 2.19.1")
+
   mark_as_advanced(GLIB_LIBRARIES GLIBCONFIG_INCLUDE_DIR GLIB_INCLUDE_DIR)
 endif ()
 
@@ -271,24 +285,28 @@ if (APPLE AND HB_HAVE_CORETEXT)
     find_library(COREFOUNDATION CoreFoundation)
     if (COREFOUNDATION)
       list(APPEND THIRD_PARTY_LIBS ${COREFOUNDATION})
+      list(APPEND PC_LIBS_PRIV "-framework CoreFoundation")
     endif ()
     mark_as_advanced(COREFOUNDATION)
 
     find_library(CORETEXT CoreText)
     if (CORETEXT)
       list(APPEND THIRD_PARTY_LIBS ${CORETEXT})
+      list(APPEND PC_LIBS_PRIV "-framework CoreText")
     endif ()
     mark_as_advanced(CORETEXT)
 
     find_library(COREGRAPHICS CoreGraphics)
     if (COREGRAPHICS)
       list(APPEND THIRD_PARTY_LIBS ${COREGRAPHICS})
+      list(APPEND PC_LIBS_PRIV "-framework CoreGraphics")
     endif ()
     mark_as_advanced(COREGRAPHICS)
   else ()
     find_library(APPLICATION_SERVICES_FRAMEWORK ApplicationServices)
     if (APPLICATION_SERVICES_FRAMEWORK)
       list(APPEND THIRD_PARTY_LIBS ${APPLICATION_SERVICES_FRAMEWORK})
+      list(APPEND PC_LIBS_PRIV "-framework ApplicationServices")
     endif ()
 
     mark_as_advanced(APPLICATION_SERVICES_FRAMEWORK)
@@ -299,18 +317,27 @@ if (WIN32 AND HB_HAVE_GDI)
   add_definitions(-DHAVE_GDI)
   list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-gdi.h)
   list(APPEND THIRD_PARTY_LIBS gdi32)
+  list(APPEND PC_LIBS_PRIV -lgdi32)
 endif ()
 
 if (WIN32 AND HB_HAVE_UNISCRIBE)
   add_definitions(-DHAVE_UNISCRIBE)
   list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-uniscribe.h)
   list(APPEND THIRD_PARTY_LIBS usp10 gdi32 rpcrt4)
+  list(APPEND PC_LIBS_PRIV -lusp10 -lgdi32 -lrpcrt4)
 endif ()
 
 if (WIN32 AND HB_HAVE_DIRECTWRITE)
+  if (CMAKE_VERSION VERSION_GREATER 3.12)
+    check_include_files("windows.h;dwrite_1.h" HAVE_DWRITE_1_H LANGUAGE CXX)
+  else ()
+    check_include_files("windows.h;dwrite_1.h" HAVE_DWRITE_1_H)
+  endif ()
+  if (NOT HAVE_DWRITE_1_H)
+    message(FATAL_ERROR "DirectWrite was enabled explicitly, but required header is missing")
+  endif ()
   add_definitions(-DHAVE_DIRECTWRITE)
   list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-directwrite.h)
-  list(APPEND THIRD_PARTY_LIBS dwrite rpcrt4)
 endif ()
 
 if (HB_HAVE_GOBJECT)
@@ -426,7 +453,7 @@ target_include_directories(harfbuzz PUBLIC
                            "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>"
                            "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/harfbuzz>")
 if (HB_HAVE_FREETYPE AND TARGET freetype)
-  target_link_libraries(harfbuzz PUBLIC freetype)
+  target_link_libraries(harfbuzz freetype)
 endif ()
 
 
@@ -462,7 +489,9 @@ if (UNIX OR MINGW)
     link_libraries(-Bsymbolic-functions)
   endif ()
 
-  if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+  # As of CMake 3.0.0, the compiler id for Apple-provided Clang is now "AppleClang";
+  # thus we use MATCHES instead of STREQUAL to include either regular Clang or AppleClang
+  if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
     # Make sure we don't link to libstdc++
     set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
     set (CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "m") # libm
@@ -537,7 +566,7 @@ if (HB_HAVE_INTROSPECTION)
   # We need to account for the varying output directories
   # when we build using Visual Studio projects
   if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio*")
-    set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>")
+    set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
   else ()
     set (hb_libpath "$<TARGET_FILE_DIR:harfbuzz-gobject>")
   endif ()
@@ -691,6 +720,44 @@ if (NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL)
   endif ()
 endif ()
 
+# get these variables in the required format
+list(REMOVE_DUPLICATES PC_REQUIRES_PRIV)
+string(REPLACE ";" ", " PC_REQUIRES_PRIV "${PC_REQUIRES_PRIV}")
+list(REMOVE_DUPLICATES PC_LIBS_PRIV)
+string(REPLACE ";" " " PC_LIBS_PRIV "${PC_LIBS_PRIV}")
+
+# Macro to write pkg-config .pc configuration files
+macro ( make_pkgconfig_pc_file name )
+  file(READ "${PROJECT_SOURCE_DIR}/src/${name}.pc.in" FSTR)
+
+  string(REPLACE "%prefix%" "${CMAKE_INSTALL_PREFIX}" FSTR ${FSTR})
+  string(REPLACE "%exec_prefix%" "\${prefix}" FSTR ${FSTR})
+
+  if (IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
+    string(REPLACE "%includedir%" "${CMAKE_INSTALL_INCLUDEDIR}" FSTR ${FSTR})
+  else ()
+    string(REPLACE "%includedir%" "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}" FSTR ${FSTR})
+  endif ()
+
+  if (IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
+    string(REPLACE "%libdir%" "${CMAKE_INSTALL_LIBDIR}" FSTR ${FSTR})
+  else ()
+    string(REPLACE "%libdir%" "\${prefix}/${CMAKE_INSTALL_LIBDIR}" FSTR ${FSTR})
+  endif ()  
+
+  string(REPLACE "%VERSION%" "${HB_VERSION}" FSTR ${FSTR})
+  string(REPLACE "%requires_private%" "${PC_REQUIRES_PRIV}" FSTR ${FSTR})
+  string(REPLACE "%libs_private%" "${PC_LIBS_PRIV}" FSTR ${FSTR})
+
+  file(WRITE "${PROJECT_BINARY_DIR}/${name}.pc" ${FSTR})
+
+  install(
+    FILES "${PROJECT_BINARY_DIR}/${name}.pc"
+    DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
+    COMPONENT pkgconfig
+  )
+endmacro ( make_pkgconfig_pc_file )
+
 if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
   install(TARGETS harfbuzz
     EXPORT harfbuzzConfig
@@ -699,6 +766,7 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
     RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
     FRAMEWORK DESTINATION Library/Frameworks
   )
+  make_pkgconfig_pc_file("harfbuzz")
   install(EXPORT harfbuzzConfig
       NAMESPACE harfbuzz::
       DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/harfbuzz
@@ -710,11 +778,13 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
       RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
       FRAMEWORK DESTINATION Library/Frameworks
     )
+    make_pkgconfig_pc_file("harfbuzz-icu")
   endif ()
   if (HB_BUILD_SUBSET)
     install(TARGETS harfbuzz-subset
       ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
-  )
+    )
+    make_pkgconfig_pc_file("harfbuzz-subset")
   endif ()
   if (HB_BUILD_UTILS)
     if (WIN32 AND BUILD_SHARED_LIBS)
@@ -743,9 +813,10 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
       LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
       RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
     )
+    make_pkgconfig_pc_file("harfbuzz-gobject")
     if (HB_HAVE_INTROSPECTION)
       if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio*")
-        set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>")
+        set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
       else ()
         set (hb_libpath "$<TARGET_FILE_DIR:harfbuzz-gobject>")
       endif ()
index 15b4ffa..f0fc065 100644 (file)
--- a/CONFIG.md
+++ b/CONFIG.md
@@ -100,13 +100,14 @@ This is very rarely what you need.  Make sure you understand exactly what you
 are doing.
 
 Defining `HB_NO_FALLBACK_SHAPE` however is pretty harmless.  That removes the
-(unused) "fallback" shaper.
+(unused) "fallback" shaper.  This is defined by the `HB_TINY` profile already
+(more below).
 
 
 ## Thread-safety
 
 By default HarfBuzz builds as a thread-safe library.  The exception is that
-the `HB_TINY` predefined configuring (more below) disables thread-safety.
+the `HB_TINY` predefined configuration (more below) disables thread-safety.
 
 If you do *not* need thread-safety in the library (eg. you always call into
 HarfBuzz from the same thread), you can disable thread-safety by defining
@@ -140,10 +141,10 @@ configurations from the command-line.
 However, configuration can still be overridden from a file.  To do that, add your
 override instructions (mostly `undef` instructions) to a header file and define
 the macro `HB_CONFIG_OVERRIDE_H` to the string containing to that header file's
-name.  HarfBuzz will then include that file at appropriate right place during
+name.  HarfBuzz will then include that file at the appropriate place during
 configuration.
 
-Up until HarfBuzz 3.1.2 the the configuration override header file's name was
+Up until HarfBuzz 3.1.2, the configuration override header file's name was
 fixed and called `config-override.h`, and was activated by defining the macro
 `HAVE_CONFIG_OVERRIDE_H`.  That still works.
 
@@ -154,4 +155,4 @@ Note that the config option `HB_NO_CFF`, which is enabled by `HB_LEAN` and
 `HB_TINY` does *not* mean that the resulting library won't work with CFF fonts.
 The library can shape valid CFF fonts just fine, with or without this option.
 This option disables (among other things) the code to calculate glyph extents
-for CFF fonts.
+for CFF fonts, which many clients might not need.
diff --git a/COPYING b/COPYING
index 48d1b30..1dd917e 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -2,19 +2,23 @@ HarfBuzz is licensed under the so-called "Old MIT" license.  Details follow.
 For parts of HarfBuzz that are licensed under different licenses see individual
 files names COPYING in subdirectories where applicable.
 
-Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020  Google, Inc.
-Copyright © 2018,2019,2020  Ebrahim Byagowi
+Copyright © 2010-2022  Google, Inc.
+Copyright © 2015-2020  Ebrahim Byagowi
 Copyright © 2019,2020  Facebook, Inc.
-Copyright © 2012  Mozilla Foundation
+Copyright © 2012,2015  Mozilla Foundation
 Copyright © 2011  Codethink Limited
 Copyright © 2008,2010  Nokia Corporation and/or its subsidiary(-ies)
 Copyright © 2009  Keith Stribley
-Copyright © 2009  Martin Hosken and SIL International
+Copyright © 2011  Martin Hosken and SIL International
 Copyright © 2007  Chris Wilson
-Copyright © 2005,2006,2020,2021  Behdad Esfahbod
-Copyright © 2005  David Turner
-Copyright © 2004,2007,2008,2009,2010  Red Hat, Inc.
-Copyright © 1998-2004  David Turner and Werner Lemberg
+Copyright © 2005,2006,2020,2021,2022,2023  Behdad Esfahbod
+Copyright © 2004,2007,2008,2009,2010,2013,2021,2022,2023  Red Hat, Inc.
+Copyright © 1998-2005  David Turner and Werner Lemberg
+Copyright © 2016  Igalia S.L.
+Copyright © 2022  Matthias Clasen
+Copyright © 2018,2021  Khaled Hosny
+Copyright © 2018,2019,2020  Adobe, Inc
+Copyright © 2013-2015  Alexei Podtelezhnikov
 
 For full copyright notices consult the individual files in the package.
 
index efc2473..5a1e01a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
+commit 18a6e78549e8e04a281129ea8ca784ce85f111b8
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Oct 18 01:10:44 2023 +0300
+
+    8.2.2
+
+ NEWS             | 11 +++++++++++
+ configure.ac     |  2 +-
+ meson.build      |  2 +-
+ src/hb-version.h |  4 ++--
+ 4 files changed, 15 insertions(+), 4 deletions(-)
+
+commit 52bc78e70de9f8288e3412a8017f88d2e0a31dea
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Oct 10 21:44:52 2023 +0000
+
+    s/PairPos/MarkBasePos/ in MarkBasePos repacking implementation.
+
+ src/graph/markbasepos-graph.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 6190bb0b8ed8af3d182d1936fbe859c15fb0f817
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Oct 16 14:08:31 2023 -0400
+
+    [layout] Change order of feature collection
+    
+    See comments for rationale.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4445
+
+ src/hb-ot-layout.cc | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+commit 4992456cfadabb6ecbc7b4efc5c1af9ec91f6dd3
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Oct 16 10:07:42 2023 +0000
+
+    Bump ninja from 1.11.1 to 1.11.1.1 in /.ci
+    
+    Bumps [ninja](https://github.com/ninja-build/ninja) from 1.11.1 to 1.11.1.1.
+    - [Release notes](https://github.com/ninja-build/ninja/releases)
+    - [Commits](https://github.com/ninja-build/ninja/commits)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: ninja
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .ci/requirements.txt | 34 ++++++++++++++++------------------
+ 1 file changed, 16 insertions(+), 18 deletions(-)
+
+commit 397b32e585cbb29349e0e97fad2e84cb57a9a6d1
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Oct 16 10:29:00 2023 +0000
+
+    Bump github/codeql-action from 2.22.0 to 2.22.3
+    
+    Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.22.0 to 2.22.3.
+    - [Release notes](https://github.com/github/codeql-action/releases)
+    - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
+    - [Commits](https://github.com/github/codeql-action/compare/2cb752a87e96af96708ab57187ab6372ee1973ab...0116bc2df50751f9724a2e35ef1f24d22f90e4e1)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: github/codeql-action
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/scorecard.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1f395cbaf91be284f443c27b8b35be0edd788c34
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Oct 12 10:06:00 2023 -0700
+
+    [instancer] templatize the priority queue, use custom type for varstore
+    
+    when instantiating varstore, we need to pop a tuple like
+    (combined_gain, i, j), if combined gain is the same then we compare the
+    value of i, and then j. So we'd like to use custom type as the key when
+    popping from the queue. This would match fonttool's algorithm cause it
+    uses heappop().
+
+ src/graph/graph.hh         |  4 ++--
+ src/hb-ot-var-common.hh    | 47 ++++++++++++++++++++++++++++++++++------------
+ src/hb-priority-queue.hh   |  5 +++--
+ src/test-priority-queue.cc |  4 ++--
+ 4 files changed, 42 insertions(+), 18 deletions(-)
+
+commit bbd53fcfa49e9d4a8b3899ce2c109377886a3ba9
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Oct 10 21:41:42 2023 +0000
+
+    Remove glyph_map test that uses retain gids.
+    
+    We no longer allow the use of glyph map + retain gids (see: https://github.com/harfbuzz/harfbuzz/blob/main/src/hb-subset-plan.cc#L817). Also add the test to the meson file so it will be run by default.
+
+ test/subset/data/Makefile.am                             |   1 +
+ test/subset/data/Makefile.sources                        |   1 +
+ ...gular.glyph_map_roboto_retain_gids.41,43,61,66,69.ttf | Bin 7936 -> 0 bytes
+ .../data/profiles/glyph_map_roboto_retain_gids.txt       |   4 ----
+ test/subset/data/tests/glyph_map.tests                   |   1 -
+ test/subset/meson.build                                  |   1 +
+ 6 files changed, 3 insertions(+), 5 deletions(-)
+
+commit 9648799e53edae7072505849fb551a6e621b8f6c
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Oct 9 10:34:48 2023 +0000
+
+    Bump ossf/scorecard-action from 2.2.0 to 2.3.0
+    
+    Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 2.2.0 to 2.3.0.
+    - [Release notes](https://github.com/ossf/scorecard-action/releases)
+    - [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
+    - [Commits](https://github.com/ossf/scorecard-action/compare/08b4669551908b1024bb425080c797723083c031...483ef80eb98fb506c348f7d62e28055e49fe2398)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: ossf/scorecard-action
+      dependency-type: direct:production
+      update-type: version-update:semver-minor
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/scorecard.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit cf930decce6cffabff55a8a314eb7f9f34cff322
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Oct 9 10:34:42 2023 +0000
+
+    Bump actions/setup-python from 4.7.0 to 4.7.1
+    
+    Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4.7.0 to 4.7.1.
+    - [Release notes](https://github.com/actions/setup-python/releases)
+    - [Commits](https://github.com/actions/setup-python/compare/61a6322f88396a6271a6ee3565807d608ecaddd1...65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: actions/setup-python
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/msvc-ci.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 0cfc4ebfbade5b794956f0eae3939e7b1fade2b8
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Oct 9 10:34:36 2023 +0000
+
+    Bump github/codeql-action from 2.21.9 to 2.22.0
+    
+    Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.9 to 2.22.0.
+    - [Release notes](https://github.com/github/codeql-action/releases)
+    - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
+    - [Commits](https://github.com/github/codeql-action/compare/ddccb873888234080b77e9bc2d4764d5ccaaccf9...2cb752a87e96af96708ab57187ab6372ee1973ab)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: github/codeql-action
+      dependency-type: direct:production
+      update-type: version-update:semver-minor
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/scorecard.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a317b5a7ea49c08e21a0e47beaaa5c31f52f28ea
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Oct 9 10:06:13 2023 +0000
+
+    Bump fonttools from 4.43.0 to 4.43.1 in /.ci
+    
+    Bumps [fonttools](https://github.com/fonttools/fonttools) from 4.43.0 to 4.43.1.
+    - [Release notes](https://github.com/fonttools/fonttools/releases)
+    - [Changelog](https://github.com/fonttools/fonttools/blob/main/NEWS.rst)
+    - [Commits](https://github.com/fonttools/fonttools/compare/4.43.0...4.43.1)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: fonttools
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .ci/requirements-fonttools.txt | 86 +++++++++++++++++++++---------------------
+ .ci/requirements.txt           | 86 +++++++++++++++++++++---------------------
+ 2 files changed, 86 insertions(+), 86 deletions(-)
+
+commit a7b3fe3523891a81be501c907b6bf817615df174
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Oct 5 12:16:00 2023 -0600
+
+    Fix test
+
+ src/test-tuple-varstore.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit fc563bb437b379334913b15489caec98a504fcd3
+Merge: f26fd69d8 2415d5f23
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Oct 5 11:07:17 2023 -0600
+
+    Merge pull request #4421 from googlefonts/GDEF_GPOS
+    
+    [instancer] support GDEF/GPOS tables
+
+commit f26fd69d858642d76413b8f4068eaf9b57c40a5f
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Oct 2 10:06:40 2023 +0000
+
+    Bump github/codeql-action from 2.21.8 to 2.21.9
+    
+    Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.8 to 2.21.9.
+    - [Release notes](https://github.com/github/codeql-action/releases)
+    - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
+    - [Commits](https://github.com/github/codeql-action/compare/6a28655e3dcb49cb0840ea372fd6d17733edd8a4...ddccb873888234080b77e9bc2d4764d5ccaaccf9)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: github/codeql-action
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/scorecard.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1522eb9199ed07b8fba9c3131806205834b0a18a
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Oct 2 10:48:02 2023 +0000
+
+    Bump fonttools from 4.42.1 to 4.43.0 in /.ci
+    
+    Bumps [fonttools](https://github.com/fonttools/fonttools) from 4.42.1 to 4.43.0.
+    - [Release notes](https://github.com/fonttools/fonttools/releases)
+    - [Changelog](https://github.com/fonttools/fonttools/blob/main/NEWS.rst)
+    - [Commits](https://github.com/fonttools/fonttools/compare/4.42.1...4.43.0)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: fonttools
+      dependency-type: direct:production
+      update-type: version-update:semver-minor
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .ci/requirements-fonttools.txt | 78 +++++++++++++++++++++++-------------------
+ .ci/requirements.txt           | 78 +++++++++++++++++++++++-------------------
+ 2 files changed, 86 insertions(+), 70 deletions(-)
+
+commit 2d67e52a47945e2563b12e681336ab9d04613aad
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Oct 2 10:47:40 2023 +0000
+
+    Bump meson from 1.2.1 to 1.2.2 in /.ci
+    
+    Bumps [meson](https://github.com/mesonbuild/meson) from 1.2.1 to 1.2.2.
+    - [Release notes](https://github.com/mesonbuild/meson/releases)
+    - [Commits](https://github.com/mesonbuild/meson/compare/1.2.1...1.2.2)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: meson
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .ci/requirements.in  | 2 +-
+ .ci/requirements.txt | 6 +++---
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit 6e06a193b3e6784b87380641d693fee1e507228e
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Sep 30 01:12:16 2023 +0300
+
+    Add some tests for hb_feature_[from|to]_string()
+
+ test/api/test-common.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 108 insertions(+)
+
+commit f360d704fad6551dd05fe62bf9c4ce2f9a857e03
+Author: jfkthame <jfkthame@gmail.com>
+Date:   Fri Sep 29 13:15:01 2023 +0100
+
+    Check for closing quote in parse_tag
+    
+    Fixes #4414.
+
+ src/hb-common.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 333946b00e849ff6722781bc5e46bd9fcc83311a
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Sep 28 19:02:37 2023 +0000
+
+    [subset] Fix fuzzer timeout.
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5458896606855168. Limit iteration over coverage in MarkLigPosFormat1 subsetting to the number of glyphs in the liga array.
+
+ src/OT/Layout/GPOS/MarkLigPosFormat1.hh                  |   5 +++--
+ ...-testcase-minimized-hb-subset-fuzzer-5458896606855168 | Bin 0 -> 2410 bytes
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+commit 9ceb800ac26fd81a5eaf27ef366d5fce47e80447
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Sep 28 10:37:48 2023 -0700
+
+    fuzzer fix https://oss-fuzz.com/testcase-detail/5842152921628672
+    
+    Access TupleVariationData through blob, because we don't sanitize
+    var_data
+
+ src/hb-ot-var-cvar-table.hh                             |   7 ++++---
+ src/test-tuple-varstore.cc                              |  16 +++++++++++++++-
+ ...testcase-minimized-hb-subset-fuzzer-5842152921628672 | Bin 0 -> 2501 bytes
+ 3 files changed, 19 insertions(+), 4 deletions(-)
+
+commit 7cb7a7999b542cb4ae75a3d289a429a68df6a86a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Sep 28 09:24:06 2023 -0600
+
+    [map] Fix undefined integer-overflow
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5814850435284992
+
+ src/hb-map.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 2415d5f23927cbfcd8a2928f7ecadf7e9626cd51
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Sep 27 13:33:09 2023 -0700
+
+    [instancer] update tests to include GDEF/GPOS tables
+
+ ...n-all-codepoint.wght=200-300-500,wdth=80-90.ttf | Bin 8432 -> 8728 bytes
+ ...s.retain-all-codepoint.wght=300-600,wdth=85.ttf | Bin 7336 -> 7612 bytes
+ ...n-all-codepoint.wght=200-300-500,wdth=80-90.ttf | Bin 7484 -> 7592 bytes
+ ...s.retain-all-codepoint.wght=300-600,wdth=85.ttf | Bin 6848 -> 6956 bytes
+ ...odepoint.wght=200-600,wdth=80-90,CTGR=20-60.ttf | Bin 4108 -> 4340 bytes
+ ...ariations.retain-all-codepoint.wght=300-600.ttf | Bin 6616 -> 6848 bytes
+ ...ariations.retain-all-codepoint.wght=500-800.ttf | Bin 7096 -> 7328 bytes
+ ...ariations.retain-all-codepoint.wght=300-600.ttf | Bin 197056 -> 305092 bytes
+ ...ariations.retain-all-codepoint.wght=500-800.ttf | Bin 145004 -> 250164 bytes
+ .../profiles/no-tables-with-item-variations.txt    |   2 +-
+ 10 files changed, 1 insertion(+), 1 deletion(-)
+
+commit f9b04b2145a2021cc56868daca89c3514f6a8966
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Sep 27 09:36:52 2023 -0700
+
+    [instancer] match fonttools'r order when calculating chars
+    
+    Also fix a bug, make sure map set is happening before std::move
+
+ src/hb-ot-layout-common.hh | 6 ++++--
+ src/hb-ot-var-common.hh    | 4 ++--
+ 2 files changed, 6 insertions(+), 4 deletions(-)
+
+commit f39e9bf1ed52140d2658b4d845f3bbacc215221b
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Sep 25 08:59:11 2023 -0700
+
+    [instancer] instantiate GPOS
+    
+    Just need to update var_idxes and deltas
+
+ src/OT/Layout/GDEF/GDEF.hh          | 18 ++++++++++--------
+ src/OT/Layout/GPOS/AnchorFormat3.hh | 23 ++++++++++++++++++-----
+ src/hb-ot-layout-common.hh          |  4 ++--
+ 3 files changed, 30 insertions(+), 15 deletions(-)
+
+commit 5c6795e2701d7c2031bc3e7c6c1b356961350291
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Sep 21 12:04:03 2023 -0700
+
+    [instancer] make GPOS depend on GDEF when partial instancing
+    
+    GPOS needs to wait for GDEF remapping layout var idxes
+
+ src/hb-subset.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit c8594baa478d09b60e1553dacae32345efef4272
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Sep 21 11:45:01 2023 -0700
+
+    [instancer] instantiate GDEF varStore
+    
+    And update layout var idxes accordingly
+
+ src/OT/Layout/GDEF/GDEF.hh        | 38 +++++++++++++++++++++++++++++++++++++-
+ src/hb-subset-plan-member-list.hh |  2 +-
+ 2 files changed, 38 insertions(+), 2 deletions(-)
+
+commit 77f24d822e726b0075d9aab4dc8600eb1b7dc481
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Sep 22 14:47:11 2023 -0700
+
+    [instancer] remap layout var_idxes code update
+    
+    make hb_collect_variation_indices_context_t only collect layout
+    variation indices.
+
+ src/OT/Layout/GDEF/GDEF.hh | 26 +++++++++++++++++++-------
+ src/hb-ot-layout-common.hh | 28 +++-------------------------
+ src/hb-subset-plan.cc      | 26 ++++++--------------------
+ 3 files changed, 28 insertions(+), 52 deletions(-)
+
+commit c8c97864e8c810068123ef62947be13675df54c2
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Sep 21 11:29:43 2023 -0700
+
+    [instancer] simplify item_variations_t API calls
+    
+    merge create,instantiate and as_item_varstore into one API
+
+ src/hb-ot-var-common.hh     | 19 +++++++++++++++++--
+ src/hb-ot-var-hvar-table.hh | 18 ++++--------------
+ src/hb-ot-var-mvar-table.hh |  7 +------
+ src/test-item-varstore.cc   |  2 +-
+ 4 files changed, 23 insertions(+), 23 deletions(-)
+
+commit 00de5d0068d189a7dcbd1ccb10f55db95d240340
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Sep 25 10:25:15 2023 +0000
+
+    Bump actions/checkout from 4.0.0 to 4.1.0
+    
+    Bumps [actions/checkout](https://github.com/actions/checkout) from 4.0.0 to 4.1.0.
+    - [Release notes](https://github.com/actions/checkout/releases)
+    - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
+    - [Commits](https://github.com/actions/checkout/compare/3df4ab11eba7bda6032a0b82a6bb43b11571feac...8ade135a41bc03ea155e62e844d188df1ea18608)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: actions/checkout
+      dependency-type: direct:production
+      update-type: version-update:semver-minor
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/arm-ci.yml        | 2 +-
+ .github/workflows/configs-build.yml | 2 +-
+ .github/workflows/coverity-scan.yml | 2 +-
+ .github/workflows/linux-ci.yml      | 2 +-
+ .github/workflows/macos-ci.yml      | 2 +-
+ .github/workflows/msvc-ci.yml       | 2 +-
+ .github/workflows/msys2-ci.yml      | 2 +-
+ .github/workflows/scorecard.yml     | 2 +-
+ 8 files changed, 8 insertions(+), 8 deletions(-)
+
+commit 42b8534b14419580dd35f865944081196217cb6c
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Sep 25 10:25:08 2023 +0000
+
+    Bump github/codeql-action from 2.21.7 to 2.21.8
+    
+    Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.7 to 2.21.8.
+    - [Release notes](https://github.com/github/codeql-action/releases)
+    - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
+    - [Commits](https://github.com/github/codeql-action/compare/04daf014b50eaf774287bf3f0f1869d4b4c4b913...6a28655e3dcb49cb0840ea372fd6d17733edd8a4)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: github/codeql-action
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/scorecard.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 69da5aae028417dacf4c6617e49beb7dfbeb20e3
+Author: inobelar <inobelar@gmail.com>
+Date:   Fri Sep 22 21:27:12 2023 +0000
+
+    Added minor fixes to build without errors with gcc 4.9.2
+
+ src/hb-map.hh    | 22 +++++++++++-----------
+ src/hb-vector.hh |  2 +-
+ 2 files changed, 12 insertions(+), 12 deletions(-)
+
+commit b8121ccbb687dc853118e81810cc0565ce0037d4
+Author: Duncan Overbruck <mail@duncano.de>
+Date:   Thu Sep 21 15:41:09 2023 +0200
+
+    [meson] keep asserts in test programs
+
+ src/meson.build | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 5aa4865a86fd97e76e857823dd4b32c65d2fa0ad
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Sep 20 14:52:58 2023 -0700
+
+    [instancer] fix compile warnings
+    
+    In constructor ‘OT::delta_row_encoding_t::delta_row_encoding_t(OT::delta_row_encoding_t&&)’,
+        inlined from ‘Type* hb_vector_t<Type, sorted>::push(Args&& ...) [with Args = {OT::delta_row_encoding_t}; Type = OT::delta_row_encoding_t; bool sorted = false]’ at ../src/hb-vector.hh:221:12,
+        inlined from ‘bool OT::item_variations_t::as_item_varstore(bool, bool)’ at ../src/hb-ot-var-common.hh:1985:24:
+    ../src/hb-ot-layout-common.hh:2304:8: warning: ‘obj.OT::delta_row_encoding_t::width’ may be used uninitialized [-Wmaybe-uninitialized]
+     2304 | struct delta_row_encoding_t
+          |        ^~~~~~~~~~~~~~~~~~~~
+    ../src/hb-ot-var-common.hh: In member function ‘bool OT::item_variations_t::as_item_varstore(bool, bool)’:
+    ../src/hb-ot-var-common.hh:1981:30: note: ‘obj.OT::delta_row_encoding_t::width’ was declared here
+     1981 |         delta_row_encoding_t obj;
+          |                              ^~~
+    In constructor ‘OT::delta_row_encoding_t::delta_row_encoding_t(OT::delta_row_encoding_t&&)’,
+        inlined from ‘Type* hb_vector_t<Type, sorted>::push(Args&& ...) [with Args = {OT::delta_row_encoding_t}; Type = OT::delta_row_encoding_t; bool sorted = false]’ at ../src/hb-vector.hh:221:12,
+        inlined from ‘bool OT::item_variations_t::as_item_varstore(bool, bool)’ at ../src/hb-ot-var-common.hh:1985:24:
+    ../src/hb-ot-layout-common.hh:2304:8: warning: ‘obj.OT::delta_row_encoding_t::overhead’ may be used uninitialized [-Wmaybe-uninitialized]
+     2304 | struct delta_row_encoding_t
+          |        ^~~~~~~~~~~~~~~~~~~~
+    ../src/hb-ot-var-common.hh: In member function ‘bool OT::item_variations_t::as_item_varstore(bool, bool)’:
+    ../src/hb-ot-var-common.hh:1981:30: note: ‘obj.OT::delta_row_encoding_t::overhead’ was declared here
+     1981 |         delta_row_encoding_t obj;
+
+ src/hb-ot-layout-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 4b3aa0104ea4c7859095b0e78662e440483068da
+Merge: da2c59d71 ef4ff1d6a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Sep 20 14:37:42 2023 -0600
+
+    Merge pull request #4410 from googlefonts/HVAR_instance
+    
+    [instancer] instantiate HVAR/VVAR
+
+commit da2c59d71f687c38a29389d81d6d6f911994c403
+Author: Thomas Petillon <tpetillon@gmail.com>
+Date:   Tue Sep 19 17:01:04 2023 +0200
+
+    [instancer] Delete redundant code block in cvar subsetting
+    
+    That case is handled in hb-subset.cc.
+    
+    It also made compilation with HB_NO_VAR fail because it accessed table.fvar.
+
+ src/hb-ot-var-cvar-table.hh | 13 -------------
+ 1 file changed, 13 deletions(-)
+
+commit 284889b0317c317ae00fe1a6e32db1f9213cb5e2
+Author: Thomas Petillon <tpetillon@gmail.com>
+Date:   Wed Sep 20 20:17:48 2023 +0200
+
+    [subset] Drop fvar, avar, cvar, MVAR tables when in HB_NO_VAR mode
+
+ src/hb-subset.cc | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit ef4ff1d6a4f2343440e278ef1177b07f6af8f5dc
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Sep 20 11:35:33 2023 -0700
+
+    [instancer] make varstore items sorting method match fonttool's
+    
+    Also update expected tests
+
+ src/hb-ot-var-common.hh                            |   9 ++++++++-
+ ...n-all-codepoint.wght=200-300-500,wdth=80-90.ttf | Bin 8432 -> 8432 bytes
+ ...s.retain-all-codepoint.wght=300-600,wdth=85.ttf | Bin 7336 -> 7336 bytes
+ ...n-all-codepoint.wght=200-300-500,wdth=80-90.ttf | Bin 7484 -> 7484 bytes
+ ...s.retain-all-codepoint.wght=300-600,wdth=85.ttf | Bin 6848 -> 6848 bytes
+ ...odepoint.wght=200-600,wdth=80-90,CTGR=20-60.ttf | Bin 4108 -> 4108 bytes
+ ...ariations.retain-all-codepoint.wght=300-600.ttf | Bin 6616 -> 6616 bytes
+ ...ariations.retain-all-codepoint.wght=300-600.ttf | Bin 197056 -> 197056 bytes
+ ...ariations.retain-all-codepoint.wght=500-800.ttf | Bin 145004 -> 145004 bytes
+ 9 files changed, 8 insertions(+), 1 deletion(-)
+
+commit b5f7ca1ab49b3842d3c2ba4ac9fbd0531378d7b6
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Sep 20 11:28:15 2023 -0700
+
+    [instancer] fix bots
+
+ src/hb-ot-var-common.hh     | 2 +-
+ src/hb-ot-var-hvar-table.hh | 4 ++--
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+commit 5ec21d4af4bc620cb58ff715e2a66288128c8d6f
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Sep 20 09:31:03 2023 -0700
+
+    [instancer] fix delta_row_encoding_t constructor
+    
+    always move chars_
+
+ src/hb-ot-layout-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 2d2818c0963d44cde07e612c5310ac2dc85cc846
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Sep 20 10:30:47 2023 -0700
+
+    [instancer] update expected tests to include HVAR/VVAR tables
+
+ ...n-all-codepoint.wght=200-300-500,wdth=80-90.ttf | Bin 8256 -> 8432 bytes
+ ...s.retain-all-codepoint.wght=300-600,wdth=85.ttf | Bin 7244 -> 7336 bytes
+ ...n-all-codepoint.wght=200-300-500,wdth=80-90.ttf | Bin 7292 -> 7484 bytes
+ ...s.retain-all-codepoint.wght=300-600,wdth=85.ttf | Bin 6760 -> 6848 bytes
+ ...odepoint.wght=200-600,wdth=80-90,CTGR=20-60.ttf | Bin 3800 -> 4108 bytes
+ ...ariations.retain-all-codepoint.wght=300-600.ttf | Bin 6280 -> 6616 bytes
+ ...ariations.retain-all-codepoint.wght=500-800.ttf | Bin 6760 -> 7096 bytes
+ ...ariations.retain-all-codepoint.wght=300-600.ttf | Bin 194432 -> 197056 bytes
+ ...ariations.retain-all-codepoint.wght=500-800.ttf | Bin 143840 -> 145004 bytes
+ .../profiles/no-tables-with-item-variations.txt    |   2 +-
+ 10 files changed, 1 insertion(+), 1 deletion(-)
+
+commit 58e5d45de886319104007249d7e6a2b5b6584247
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Sep 19 10:33:32 2023 -0700
+
+    [instancer] instantiate HVAR/VVAR
+
+ src/hb-ot-var-hvar-table.hh | 87 ++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 83 insertions(+), 4 deletions(-)
+
+commit e81ad14dba9ddc70aca11a46242cfc20b593e878
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Sep 19 13:23:58 2023 -0700
+
+    [instancer] change optimize() to as_item_varstore()
+    
+    which allows another option to skip optimization
+
+ src/hb-ot-var-common.hh     | 23 +++++++++++++++++++++--
+ src/hb-ot-var-mvar-table.hh |  2 +-
+ src/test-item-varstore.cc   |  2 +-
+ 3 files changed, 23 insertions(+), 4 deletions(-)
+
+commit 97d0e7a19f5e341a77c156faaa37eed8df6d8db7
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Sep 19 11:25:14 2023 -0700
+
+    [instancer] add inner_maps as optional argument when creating item_variations_t
+    
+    This allows that we create item_variations_t with only a subset of
+    the original varstore
+
+ src/hb-ot-var-common.hh | 17 ++++++++++++-----
+ 1 file changed, 12 insertions(+), 5 deletions(-)
+
+commit 005582e0cb80821fb5bbbdfb6cef4be05078d060
+Merge: d69813374 da9b83891
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Sep 20 09:10:10 2023 -0600
+
+    Merge pull request #4370 from 2xsaiko/outgoing/cmake-now-for-real
+    
+    Re-do and clean up CMake support, making it use relocatable paths
+
+commit da9b838910e62825717a8b2de8ce9c92e396136e
+Author: Marco Rebhan <me@dblsaiko.net>
+Date:   Tue Aug 8 14:33:03 2023 +0200
+
+    Re-do and clean up CMake support, making it use relocatable paths
+    
+    Closes #4025.
+
+ meson.build                  | 21 ++++++++++
+ meson_options.txt            |  4 ++
+ src/Makefile.am              |  2 +-
+ src/harfbuzz-config.cmake.in | 97 ++++++++------------------------------------
+ src/meson.build              | 92 ++++++++++++++++++++++++++++++++++++++---
+ src/relative_to.py           |  6 +++
+ 6 files changed, 135 insertions(+), 87 deletions(-)
+
+commit d698133743caffe9611b57137cd5027ce076613f
+Merge: 0967a3e24 c330c2917
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Sep 19 13:30:43 2023 -0600
+
+    Merge pull request #4393 from googlefonts/instantiate_item_varstore
+    
+    [instancer] instantiate item varstore
+
+commit b5a1c2b483263896e563402cd285a46229e42f3c
+Author: Marco Rebhan <me@dblsaiko.net>
+Date:   Mon Aug 7 01:55:10 2023 +0200
+
+    Revert "Pass through absolute paths to cmake config directly"
+    
+    This reverts commit db292f6f0238581a489aa8cddc585129b6e920cd.
+
+ src/harfbuzz-config.cmake.in | 44 ++++++++++++++++++++++++++++++++++++--------
+ src/meson.build              |  4 ++--
+ 2 files changed, 38 insertions(+), 10 deletions(-)
+
+commit c330c2917524ad8a15340e5fa1df5a57a1409efa
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Sep 18 12:14:21 2023 -0700
+
+    [instancer] add a unit testcase for instantiating item variations
+
+ src/Makefile.am           |  5 ++++
+ src/meson.build           |  1 +
+ src/test-item-varstore.cc | 66 +++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 72 insertions(+)
+
+commit 7741fa329998f23ef1495f9828c919ae2f6ada1e
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Sep 18 10:44:47 2023 -0700
+
+    [instancer] bug fix: dont add duplicate rows into delta_row_encoding_t
+    
+    Also fix compile_varidx_map()
+
+ src/hb-ot-var-common.hh | 57 ++++++++++++++++++++++++++++---------------------
+ 1 file changed, 33 insertions(+), 24 deletions(-)
+
+commit 6c658b410593e15416a800daf8fd0492c69d9ba5
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Sep 15 11:49:47 2023 -0700
+
+    [instancer] bug fix
+
+ src/hb-ot-var-common.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 11cc47964695661c2a0e8ba24d80304ac1457ab6
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Sep 11 09:57:14 2023 -0700
+
+    [instancer] fix columns and get_chars_overhead() in delta_row_encoding_t
+    
+    make columns a vector of uint8_t so it supports more than 32 columns
+
+ src/hb-ot-layout-common.hh | 29 +++++++++++++++++++----------
+ src/hb-ot-var-common.hh    |  1 +
+ 2 files changed, 20 insertions(+), 10 deletions(-)
+
+commit 6e49128afda813238cfbccd304db1c55ed98f0e5
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Sep 1 10:27:40 2023 -0700
+
+    [instancer] always check and update default wght/width/slnt if necessary
+    
+    Sometimes default values in original file are incorrect, and if default value for an axis is not changed, then these values won't be updated
+
+ src/hb-ot-os2-table.hh                             |  23 ++++++++-------------
+ src/hb-ot-post-table.hh                            |  10 ++++-----
+ ...ariations.retain-all-codepoint.wght=300-600.ttf | Bin 0 -> 194432 bytes
+ ...ariations.retain-all-codepoint.wght=500-800.ttf | Bin 0 -> 143840 bytes
+ test/subset/data/tests/update_def_wght.tests       |  12 +++++++++++
+ test/subset/meson.build                            |   6 +++++-
+ 6 files changed, 31 insertions(+), 20 deletions(-)
+
+commit 7b5daff5eb347a29d9d9d59f2a41f938781d84de
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Aug 31 17:50:34 2023 -0700
+
+    [instancer] add tests for mvar partial instancing
+
+ ...-all-codepoint.wght=200-600,wdth=80-90,CTGR=20-60.ttf | Bin 0 -> 3800 bytes
+ ...item-variations.retain-all-codepoint.wght=300-600.ttf | Bin 0 -> 6280 bytes
+ ...item-variations.retain-all-codepoint.wght=500-800.ttf | Bin 0 -> 6760 bytes
+ .../data/profiles/no-tables-with-item-variations.txt     |   2 +-
+ test/subset/data/tests/mvar_partial_instance.tests       |  13 +++++++++++++
+ test/subset/meson.build                                  |   2 +-
+ 6 files changed, 15 insertions(+), 2 deletions(-)
+
+commit 45c2d05d0068ebd4fe5a9ea6ca38af5d8bab57c9
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Aug 31 15:45:22 2023 -0700
+
+    [instancer] add subset() for MVAR
+
+ src/hb-ot-var-mvar-table.hh | 61 ++++++++++++++++++++++++++++++++++++++++++++-
+ src/hb-subset-input.cc      |  1 -
+ src/hb-subset.cc            |  4 +++
+ 3 files changed, 64 insertions(+), 2 deletions(-)
+
+commit e4e1ac44f062078ed7da04321f8269df9f202c7b
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Aug 31 15:34:26 2023 -0700
+
+    [instancer] add serialize() for VariationStore
+    
+    Input region_list and encoding_rows are from item_variations_t
+
+ src/hb-ot-layout-common.hh | 106 +++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 106 insertions(+)
+
+commit 2326879229535f97ce099958e494005d1092ee5b
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Aug 31 15:28:06 2023 -0700
+
+    [instancer] add serialize() for VarRegionList
+    
+    The region list argument comes from item_variations_t.get_region_list()
+
+ src/hb-ot-layout-common.hh        | 47 +++++++++++++++++++++++++++++++++++++++
+ src/hb-subset-plan-member-list.hh |  2 ++
+ src/hb-subset-plan.cc             |  1 +
+ 3 files changed, 50 insertions(+)
+
+commit b153af8553a8cce1c93682b63a2b4756e44986be
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Aug 31 13:12:08 2023 -0700
+
+    [instancer] add optimize(), which optimizes varstore's storage
+
+ src/hb-ot-var-common.hh | 225 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 225 insertions(+)
+
+commit 3565ad815009ff74fc42dc5ef23ad8a2bf8fdecf
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Aug 31 13:07:54 2023 -0700
+
+    [instancer] add build_region_list() method
+
+ src/hb-ot-var-common.hh | 73 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 73 insertions(+)
+
+commit e4db29b102c78cec7c42469e01656c3ac5365863
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Aug 31 12:59:39 2023 -0700
+
+    [instancer] add instantiate() method
+    
+    Also make change_tuple_variations_axis_limits() deterministic, use
+    sorted vector instead of iterating map keys
+
+ src/hb-ot-var-common.hh | 44 +++++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 37 insertions(+), 7 deletions(-)
+
+commit 5f058a93388caa0ce5c6d3800d7dbf97e3273dc8
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Aug 31 12:55:04 2023 -0700
+
+    [instancer] add create_from_item_varstore () method
+
+ src/hb-ot-layout-common.hh | 63 +++++++++++++++++++++++++++++++++++++++++++++-
+ src/hb-ot-var-common.hh    | 62 +++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 124 insertions(+), 1 deletion(-)
+
+commit 152448881fffbe46ae6ffb884351b86dcc7354d8
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Aug 31 12:40:30 2023 -0700
+
+    [instancer] add struct definition item_variations_t
+    
+    And struct delta_row_encoding_t
+
+ src/hb-ot-layout-common.hh | 141 +++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-ot-var-common.hh    |  47 +++++++++++++++
+ 2 files changed, 188 insertions(+)
+
+commit 0967a3e24ab5d79cc55dbe224652d8aabd942def
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Sep 18 21:18:27 2023 +0300
+
+    8.2.1
+
+ NEWS             | 6 ++++++
+ configure.ac     | 2 +-
+ meson.build      | 2 +-
+ src/hb-version.h | 4 ++--
+ 4 files changed, 10 insertions(+), 4 deletions(-)
+
+commit eab4e07d6c7acce1f9eb26963c9d4d0d00b75ce2
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Sep 18 10:22:37 2023 +0000
+
+    Bump github/codeql-action from 2.21.5 to 2.21.7
+    
+    Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.5 to 2.21.7.
+    - [Release notes](https://github.com/github/codeql-action/releases)
+    - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
+    - [Commits](https://github.com/github/codeql-action/compare/00e563ead9f72a8461b24876bee2d0c2e8bd2ee8...04daf014b50eaf774287bf3f0f1869d4b4c4b913)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: github/codeql-action
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/scorecard.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 609a7cc534aa22466de5deb31f1b8678dee8e111
+Merge: 37457412b c459b8a51
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Sep 17 14:59:58 2023 -0600
+
+    Merge pull request #4406 from harfbuzz/unicode-15.1
+    
+    Update to Unicode 15.1.0
+
+commit c459b8a51acf96e0d83d9b961ee3409fb5849389
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Sep 16 10:27:07 2023 -0400
+
+    [Unicode 15.1] Add tests
+
+ test/api/test-unicode.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit c6d53ab570e564b8e0226a234d0fd307c297738b
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Sep 16 10:21:11 2023 -0400
+
+    [Unicode 15.1] Update the vowel constraint table
+
+ src/hb-ot-shaper-vowel-constraints.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit f318e104be4c2c58daf92a792b96c6a9974201a1
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Sep 16 10:20:14 2023 -0400
+
+    [Unicode 15.1] Update the Indic table
+
+ src/hb-ot-shaper-indic-table.cc | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit c03e4c10a4bcab59b447a3d5416f26191c8af788
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Sep 16 10:06:24 2023 -0400
+
+    [Unicode 15.1] Update emoji table and cluster test
+
+ src/hb-unicode-emoji-table.hh                      |   6 +-
+ .../shape/data/in-house/tests/emoji-clusters.tests | 301 +++++++++++++++++++++
+ 2 files changed, 304 insertions(+), 3 deletions(-)
+
+commit d8d4a192bdd0b3e0307046dc25ff813850a910c9
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Sep 16 10:00:07 2023 -0400
+
+    Update IANA Language Subtag Registry to 2023-08-02
+
+ src/hb-ot-tag-table.hh | 17 ++++++++++-------
+ 1 file changed, 10 insertions(+), 7 deletions(-)
+
+commit 6ed6ccac4c6f650ef6abba3929bc48dff12e328d
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Sep 16 09:54:21 2023 -0400
+
+    [Unicode 15.1] Update the USE table
+
+ src/hb-ot-shaper-use-table.hh | 24 ++++++++++++------------
+ 1 file changed, 12 insertions(+), 12 deletions(-)
+
+commit f485b6a9c05b852cafea890069ce87bd5a76c20e
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Sep 16 09:49:29 2023 -0400
+
+    [Unicode 15.1] Update the Arabic joining script list
+
+ src/hb-ot-shaper-arabic-joining-list.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit f15fe524423c61dede0b35a148ca917b3746935f
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Sep 16 09:45:51 2023 -0400
+
+    [Unicode 15.1] Update the Arabic table
+
+ src/hb-ot-shaper-arabic-table.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit b3705cbf070d3dc984c5b3e18c7657aadd2b1a0f
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Sep 16 09:40:56 2023 -0400
+
+    [Unicode 15.1] Update the UCD table
+
+ src/hb-ucd-table.hh | 3450 ++++++++++++++++++++++++++-------------------------
+ 1 file changed, 1727 insertions(+), 1723 deletions(-)
+
+commit 767f937833f82257169dc278e4aaa22c44bfebf8
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Fri Sep 15 23:11:26 2023 -0400
+
+    [USE] Update the data files
+    
+    This uses the data files from
+    <https://github.com/microsoft/font-tools/tree/9e02b86c85d1a98a1d411e565d36723468f9e884/USE>
+    and closes #4404.
+
+ src/gen-use-table.py                              |   16 +-
+ src/hb-ot-shaper-use-machine.hh                   | 1381 +++++++++++----------
+ src/hb-ot-shaper-use-machine.rl                   |    6 +-
+ src/hb-ot-shaper-use-table.hh                     |  940 +++++++-------
+ src/ms-use/IndicPositionalCategory-Additional.txt |    1 +
+ src/ms-use/IndicSyllabicCategory-Additional.txt   |   57 +-
+ 6 files changed, 1223 insertions(+), 1178 deletions(-)
+
+commit 02c2e24749b9d20ec6371766d7faeb4d5d2caa67
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Sep 16 09:22:43 2023 -0400
+
+    Regenerate files using Ragel 6.10
+
+ src/hb-buffer-deserialize-json.hh         |    8 +-
+ src/hb-buffer-deserialize-text-glyphs.hh  |   10 +-
+ src/hb-buffer-deserialize-text-unicode.hh |   10 +-
+ src/hb-number-parser.hh                   |    8 +-
+ src/hb-ot-shaper-indic-machine.hh         |   14 +-
+ src/hb-ot-shaper-khmer-machine.hh         |   14 +-
+ src/hb-ot-shaper-myanmar-machine.hh       |   14 +-
+ src/hb-ot-shaper-use-machine.hh           | 1875 ++++++++++++++---------------
+ 8 files changed, 942 insertions(+), 1011 deletions(-)
+
+commit 37457412b3212463c5f53119080cd1af375aae23
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Sep 11 10:33:26 2023 +0000
+
+    Bump actions/checkout from 3.5.3 to 4.0.0
+    
+    Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.3 to 4.0.0.
+    - [Release notes](https://github.com/actions/checkout/releases)
+    - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
+    - [Commits](https://github.com/actions/checkout/compare/c85c95e3d7251135ab7dc9ce3241c5835cc595a9...3df4ab11eba7bda6032a0b82a6bb43b11571feac)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: actions/checkout
+      dependency-type: direct:production
+      update-type: version-update:semver-major
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/arm-ci.yml        | 2 +-
+ .github/workflows/configs-build.yml | 2 +-
+ .github/workflows/coverity-scan.yml | 2 +-
+ .github/workflows/linux-ci.yml      | 2 +-
+ .github/workflows/macos-ci.yml      | 2 +-
+ .github/workflows/msvc-ci.yml       | 2 +-
+ .github/workflows/msys2-ci.yml      | 2 +-
+ .github/workflows/scorecard.yml     | 2 +-
+ 8 files changed, 8 insertions(+), 8 deletions(-)
+
+commit 7384aaae4300da4380ce13adbca0aa7c6fe443e1
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Sep 11 10:33:29 2023 +0000
+
+    Bump actions/upload-artifact from 3.1.2 to 3.1.3
+    
+    Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3.1.2 to 3.1.3.
+    - [Release notes](https://github.com/actions/upload-artifact/releases)
+    - [Commits](https://github.com/actions/upload-artifact/compare/0b7f8abb1508181956e8e162db84b466c27e18ce...a8a3f3ad30e3422c9c7b888a15615d19a852ae32)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: actions/upload-artifact
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/cifuzz.yml    | 2 +-
+ .github/workflows/msys2-ci.yml  | 2 +-
+ .github/workflows/scorecard.yml | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+commit 978918c32a66af41df86386510cf73a4c0e8d393
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Sep 11 11:04:08 2023 +0100
+
+    [aat] Simplify complex condition
+    
+    Based on https://github.com/RazrFalcon/rustybuzz/discussions/79#discussioncomment-6960324
+
+ src/hb-aat-layout-common.hh | 72 ++++++++++++++++++++++-----------------------
+ 1 file changed, 35 insertions(+), 37 deletions(-)
+
+commit 17ee3cd7f4e3123d8289694f59a03c782035103f
+Author: Vincent Torri <vtorri@outlook.fr>
+Date:   Sun Sep 10 07:29:08 2023 +0200
+
+    fix warning with unsigned long
+
+ src/graph/graph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c1eb66d4159fec311334aee5c0a59384491d3989
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Sep 8 21:54:32 2023 +0300
+
+    8.2.0
+
+ NEWS                   | 12 ++++++++++++
+ configure.ac           |  2 +-
+ docs/harfbuzz-docs.xml |  1 +
+ meson.build            |  2 +-
+ src/hb-paint.cc        |  2 +-
+ src/hb-paint.h         |  4 ++--
+ src/hb-version.h       |  6 +++---
+ 7 files changed, 21 insertions(+), 8 deletions(-)
+
+commit d5cb1a315380e9bd78ff377a586b78bc42abafa6
+Author: L. E. Segovia <amy@amyspark.me>
+Date:   Thu Aug 31 23:41:10 2023 -0300
+
+    [meson] Add gitignore entries for wrap sources
+
+ subprojects/.gitignore | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit 617e44785476178107c4216964f185937e312a09
+Author: L. E. Segovia <amy@amyspark.me>
+Date:   Thu Aug 31 23:39:29 2023 -0300
+
+    [meson] Set C++14 as minimum as implied by MSVC support
+    
+    Microsoft's STL uses C++14 as minimum. Using C++11 is actually enforced
+    by clang-cl and clang, which will lead to all sorts of compilation
+    errors.
+
+ meson.build | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit 15bc9e342f989c7cd27de3a3fb68933259bf59e2
+Author: L. E. Segovia <amy@amyspark.me>
+Date:   Thu Aug 31 23:37:08 2023 -0300
+
+    [meson] Detect Microsoft compilers through _MSC_FULL_VER
+    
+    Microsoft ships three compilers nowadays: MSVC, clang-cl, and Clang.
+    The latter is always skipped by `compiler.get_argument_syntax()`,
+    which leads to the incorrect export macro being applied.
+    
+    This commit also removes the tests that are affected in Microsoft Clang.
+
+ src/meson.build | 30 +++++++++++++++---------------
+ 1 file changed, 15 insertions(+), 15 deletions(-)
+
+commit fd3eb2c6723c3ce241011f1d3429e48c3226af1c
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Aug 24 08:59:18 2023 -0700
+
+    fuzzer fix: https://oss-fuzz.com/testcase-detail/6032126569742336
+
+ src/hb-ot-var-gvar-table.hh                        |  24 ++++++---------------
+ ...ase-minimized-hb-subset-fuzzer-6032126569742336 | Bin 0 -> 1970 bytes
+ 2 files changed, 6 insertions(+), 18 deletions(-)
+
+commit 0340ba1c50da110787a420a633a7b8b2dabe42c4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Sep 5 14:56:09 2023 +0300
+
+    [bit-page] Add a few operators
+
+ src/hb-bit-page.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit a0b758f7d779376f4582c968d6fc3c5e7cde1e50
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Sep 4 10:34:27 2023 +0000
+
+    Bump github/codeql-action from 2.21.4 to 2.21.5
+    
+    Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.4 to 2.21.5.
+    - [Release notes](https://github.com/github/codeql-action/releases)
+    - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
+    - [Commits](https://github.com/github/codeql-action/compare/a09933a12a80f87b87005513f0abb1494c27a716...00e563ead9f72a8461b24876bee2d0c2e8bd2ee8)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: github/codeql-action
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/scorecard.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4cfc6d8e173e800df086d7be078da2e8c5cfca19
+Author: Ben Wagner <bungeman@chromium.org>
+Date:   Thu Aug 31 13:54:34 2023 -0400
+
+    Specify tuple_variations_t special member functions
+    
+    Building with clang complains about the use of `tuple_variations_t`'s
+    implicit copy constructor and copy assignment operator, since automatic
+    generation of these is deprecated when declaring a non-default
+    destructor. This is a good warning because it isn't obvious that copies
+    were being made instead of the object being moved and this struct should
+    be moved and not copied. Declare all the special member functions,
+    defaulting the moves and deleting the copies.
+    
+    After making `tuple_variations_t` move only, an issue is revealed in
+    `hb_vector_t::push` which has been requiring that objects be copyable.
+    Remove the old non-emplacing `push` now that this works with all
+    existing objects and make a single `push` which is more like
+    `std::vector::emplace_back` since that is somewhat what the newer `push`
+    is attempting to do.
+
+ src/hb-ot-var-common.hh |  5 +++++
+ src/hb-vector.hh        | 22 ++--------------------
+ 2 files changed, 7 insertions(+), 20 deletions(-)
+
+commit 4668b43e2cbc9d2ae19a9e9b53ad694da35240a1
+Author: Benoit Pierre <benoit.pierre@gmail.com>
+Date:   Thu Aug 31 19:33:29 2023 +0200
+
+    [meson] add source fallback URL to freetype2 wrap
+
+ subprojects/freetype2.wrap | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 8d22a57065d286dd2e920ece70c12bba5f59a8b1
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Aug 28 18:33:31 2023 +0000
+
+    [repacker] fix potential use after free in repacker.
+    
+    During table splitting we iterate over the lookups map which can be modified during table splitting. This can result in a use after free in the iterator. Create a local copy of the lookup indices to avoid this.
+
+ src/hb-repacker.hh | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit a1f034eaacb5547fdfc62fd1c4df23f9d2b40104
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Aug 28 21:10:16 2023 +0000
+
+    [repacker] fix fuzzer failure.
+    
+    Fixes: https://oss-fuzz.com/testcase-detail/6490945267564544
+
+ src/graph/markbasepos-graph.hh                         |   4 +++-
+ ...tcase-minimized-hb-repacker-fuzzer-6490945267564544 | Bin 0 -> 358352 bytes
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+commit f380a32825a1b2c51bbe21dc7acb9b3cc0921f69
+Author: Bruce Mitchener <bruce.mitchener@gmail.com>
+Date:   Fri Aug 25 14:01:01 2023 +0700
+
+    Fix some typos.
+
+ CONFIG.md                            |  2 +-
+ src/OT/Layout/GPOS/PairPosFormat2.hh |  2 +-
+ src/hb-bimap.hh                      |  2 +-
+ src/hb-bit-set.hh                    |  4 ++--
+ src/hb-buffer.cc                     |  4 ++--
+ src/hb-buffer.h                      |  2 +-
+ src/hb-font.cc                       |  2 +-
+ src/hb-map.cc                        |  2 +-
+ src/hb-ot-shape.cc                   |  2 +-
+ src/hb-sanitize.hh                   |  2 +-
+ src/hb-set.cc                        | 24 ++++++++++++------------
+ src/hb-vector.hh                     |  2 +-
+ src/hb-wasm-shape.cc                 |  2 +-
+ 13 files changed, 26 insertions(+), 26 deletions(-)
+
+commit c28fdc39b25269aadafca2ba0507c149b2779da2
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Aug 23 22:16:39 2023 +0000
+
+    [repacker] fix bot failure.
+
+ src/graph/gsubgpos-context.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit d7ee328f807cd4890b701d5b2dab5993270ace7f
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Aug 23 22:06:55 2023 +0000
+
+    [repacker] include the size of all lookup tables in the layer size estimates from the start.
+    
+    In extension promotion previously we incrementally added the contribution of the lookup table to the layer size estimates as the lookups were processed. However, this isn't quite correct as regardless of the promotion decision the full lookup table size will be incurred. So the size should be added to the initial sizes.
+
+ src/hb-repacker.hh | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+commit 5587247d5bb46e3ff5d0c4601b145dfbae50e27c
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Aug 23 21:54:15 2023 +0000
+
+    [repacker] create only one extension subtable per physical subtable.
+    
+    During extension promotion when multiple lookups refer to a shared subtable node create and reuse a single extension subtable for it. Fixes: https://github.com/fonttools/fonttools/issues/3260.
+
+ src/graph/graph.hh            | 12 +++++++++++
+ src/graph/gsubgpos-context.hh |  1 +
+ src/graph/gsubgpos-graph.hh   | 19 +++++++++++++----
+ src/test-repacker.cc          | 47 +++++++++++++++++++++++++++++++++++++------
+ 4 files changed, 69 insertions(+), 10 deletions(-)
+
+commit 56e8a290328c6628a92971c7837f773194e7584f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 22 15:49:00 2023 -0600
+
+    Fix static_size declaration
+    
+    I have a vague memory that it was intentionally written
+    that way, but I can't recall :-(.
+
+ src/OT/Color/COLR/COLR.hh | 4 ++--
+ src/hb-null.hh            | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+commit 2023384bdf74992c2a38ed7ddc81dfd14d8a6649
+Merge: 970d2c438 dd8d35766
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 22 13:09:26 2023 -0700
+
+    Merge pull request #4368 from googlefonts/support_gvar
+    
+    Initial implementation for gvar partial instancing
+
+commit dd8d35766bb31ef43848180c419c621be302ac5d
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Aug 22 12:54:50 2023 -0700
+
+    [instancer] enable partial instancing tests when experimental api is on
+
+ src/hb-ot-var-common.hh | 2 +-
+ test/subset/meson.build | 5 ++++-
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+commit 970d2c438f849700b879d76e8c183c2edfbaccdb
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Aug 21 10:10:17 2023 +0000
+
+    Bump github/codeql-action from 2.21.3 to 2.21.4
+    
+    Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.3 to 2.21.4.
+    - [Release notes](https://github.com/github/codeql-action/releases)
+    - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
+    - [Commits](https://github.com/github/codeql-action/compare/5b6282e01c62d02e720b81eb8a51204f527c3624...a09933a12a80f87b87005513f0abb1494c27a716)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: github/codeql-action
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/scorecard.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 6c7aed1000c52a7236f2368aae2bbedab6b133ff
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Aug 21 10:52:43 2023 +0000
+
+    Bump fonttools from 4.42.0 to 4.42.1 in /.ci
+    
+    Bumps [fonttools](https://github.com/fonttools/fonttools) from 4.42.0 to 4.42.1.
+    - [Release notes](https://github.com/fonttools/fonttools/releases)
+    - [Changelog](https://github.com/fonttools/fonttools/blob/main/NEWS.rst)
+    - [Commits](https://github.com/fonttools/fonttools/compare/4.42.0...4.42.1)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: fonttools
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .ci/requirements-fonttools.txt | 70 +++++++++++++++++++++---------------------
+ .ci/requirements.txt           | 70 +++++++++++++++++++++---------------------
+ 2 files changed, 70 insertions(+), 70 deletions(-)
+
+commit ca906e8747ac45ccf235c3f3e9ee9b69a693d7e4
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Aug 16 23:37:03 2023 +0000
+
+    [repacker] fix fuzzer timeout.
+    
+    Corrects some mistakes in the handling of incoming_edges_ when memory allocation failures happen.
+
+ src/graph/graph.hh                                      |  11 +++++++++--
+ ...stcase-minimized-hb-repacker-fuzzer-6697168080338944 | Bin 0 -> 68766 bytes
+ 2 files changed, 9 insertions(+), 2 deletions(-)
+
+commit c7f2d440f463be31ae24cbae7ceb6ea72a15e990
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Aug 16 09:55:23 2023 -0700
+
+    [hb-view] Better cairo version check
+
+ util/view-cairo.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e714e7d4f3d3bd1a49c460f6c3bd2c3f09192722
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Aug 16 09:54:08 2023 -0700
+
+    [hb-view] Work around old cairo
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4378
+
+ util/view-cairo.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit bea26446d2063cadb0cd83c1c627d3eed95cbcf6
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Aug 15 14:20:54 2023 -0700
+
+    [instancer] reference all points for gvar
+    
+    If a point is not referenced and delta is not inferred, set delta to 0
+
+ src/hb-ot-var-common.hh                               |  16 ++++++++++++++--
+ ...tain-all-codepoint.wght=200-300-500,wdth=80-90.ttf | Bin 7452 -> 7292 bytes
+ ...ions.retain-all-codepoint.wght=300-600,wdth=85.ttf | Bin 6780 -> 6760 bytes
+ 3 files changed, 14 insertions(+), 2 deletions(-)
+
+commit 06ff3bcb8db2ac9eac80bef21644c4d70f60573a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 15 14:41:18 2023 -0600
+
+    [COLR,glyf] Use map instead of set for tracking current glyphs / layers
+
+ src/OT/Color/COLR/COLR.hh | 4 ++--
+ src/OT/glyf/Glyph.hh      | 4 ++--
+ src/hb-ft-colr.hh         | 4 ++--
+ src/hb-map.hh             | 5 +++++
+ 4 files changed, 11 insertions(+), 6 deletions(-)
+
+commit b530e485cdcd466cdfd7f80fd341a67883fb8c71
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 15 14:31:40 2023 -0600
+
+    [glyf] Don't recuse into alread-active composite glyphs
+    
+    Deny loops.
+
+ src/OT/glyf/Glyph.hh | 40 ++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 38 insertions(+), 2 deletions(-)
+
+commit 8f039ab4d624c545dd472e477c705c3f013f66c6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 15 11:27:19 2023 -0600
+
+    [COLR] Avoid infinite-loop through PaintColrLayers
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4376
+    Fixes https://oss-fuzz.com/testcase-detail/5717524023738368
+
+ src/OT/Color/COLR/COLR.hh |  8 ++++++++
+ src/hb-ft-colr.hh         | 10 ++++++++++
+ 2 files changed, 18 insertions(+)
+
+commit 0c80aec10b38c8880b0f353b4774b8843a4b4126
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 15 10:30:38 2023 -0600
+
+    [COLR] Move cycle-detection to the renderer instead of cairo
+    
+    Alternative fix for https://github.com/harfbuzz/harfbuzz/issues/4375
+
+ src/OT/Color/COLR/COLR.hh |  10 ++
+ src/hb-cairo-utils.hh     |   3 -
+ src/hb-cairo.cc           |   8 -
+ src/hb-ft-colr.hh         |  17 +-
+ test/api/results/bad-154  | 440 +---------------------------------------------
+ 5 files changed, 26 insertions(+), 452 deletions(-)
+
+commit 21a894f055bbff6afb45cbcceed89ac92091bb3e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 15 10:21:26 2023 -0600
+
+    [cairo] Protect against infinite loops
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4375
+    
+    Maybe we should do this in hb-ft and COLR instead?
+
+ src/hb-cairo-utils.hh | 3 +++
+ src/hb-cairo.cc       | 8 ++++++++
+ 2 files changed, 11 insertions(+)
+
+commit 7d7541e35d5701953e5e768ac1ef41b23223edb1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Aug 14 17:55:09 2023 -0600
+
+    [test-paint] Print paint-color-glyph
+
+ test/api/results/bad-154    | 34 +++++++++++++++++++++++++++++++++-
+ test/api/results/test-154   |  4 +++-
+ test/api/results/testvf-154 |  4 +++-
+ test/api/test-paint.c       | 15 +++++++++++++++
+ 4 files changed, 54 insertions(+), 3 deletions(-)
+
+commit 5560eb60d75945a331427b0e8112282dc4ff0d94
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Aug 14 17:05:22 2023 -0600
+
+    [paint] Fix docs
+
+ src/hb-paint.h | 9 ---------
+ 1 file changed, 9 deletions(-)
+
+commit 47231bdc701df1f3ba0dafb901dc92db54e7ff78
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Aug 14 16:52:44 2023 -0600
+
+    [COLR/cairo/ft] Fixups to paint-color-glyph and implement for hb-ft
+
+ docs/harfbuzz-sections.txt  |  3 +++
+ src/hb-ft-colr.hh           | 11 ++++++++
+ test/api/results/bad-154    | 66 ++++++++++++++++++++++++++++++++++++++++++++-
+ test/api/results/testvf-154 |  6 ++++-
+ 4 files changed, 84 insertions(+), 2 deletions(-)
+
+commit 58effbcc4f1b6aa1870738f0da3d999f4f1810be
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Aug 14 16:47:01 2023 -0600
+
+    .
+
+ src/OT/Color/COLR/COLR.hh |  5 +++++
+ src/hb-cairo.cc           | 10 +++++++++-
+ test/api/results/test-154 |  6 +++++-
+ test/api/test-paint.c     |  2 +-
+ 4 files changed, 20 insertions(+), 3 deletions(-)
+
+commit 74527670fc5b0517e1d2cba2c26e3695547302e1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Aug 14 15:57:24 2023 -0600
+
+    [COLR/cairo] Add paint_color_glyph func
+    
+    Implement in cairo to use scaled-font's glyph cache.
+
+ src/OT/Color/COLR/COLR.hh |  4 ++++
+ src/hb-cairo.cc           | 19 ++++++++++++++++++
+ src/hb-paint.cc           | 25 +++++++++++++++++++++++
+ src/hb-paint.h            | 51 +++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-paint.hh           |  8 ++++++++
+ 5 files changed, 107 insertions(+)
+
+commit 8d19274c2d6e7205dc32d416c60c3542a3f353e9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Aug 14 14:40:26 2023 -0600
+
+    [layout] Speed up VarStoreInstancer
+
+ src/hb-ot-var-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1da4c61550ed8216c811765de6d8904727df0e65
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Aug 14 10:51:00 2023 +0000
+
+    Bump github/codeql-action from 2.21.2 to 2.21.3
+    
+    Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.2 to 2.21.3.
+    - [Release notes](https://github.com/github/codeql-action/releases)
+    - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
+    - [Commits](https://github.com/github/codeql-action/compare/0ba4244466797eb048eb91a6cd43d5c03ca8bd05...5b6282e01c62d02e720b81eb8a51204f527c3624)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: github/codeql-action
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/scorecard.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 8d44562b429afc1cca8cf5472905ae189929a506
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Aug 14 10:50:49 2023 +0000
+
+    Bump hendrikmuhs/ccache-action from 1.2.9 to 1.2.10
+    
+    Bumps [hendrikmuhs/ccache-action](https://github.com/hendrikmuhs/ccache-action) from 1.2.9 to 1.2.10.
+    - [Release notes](https://github.com/hendrikmuhs/ccache-action/releases)
+    - [Commits](https://github.com/hendrikmuhs/ccache-action/compare/ca3acd2731eef11f1572ccb126356c2f9298d35e...6d1841ec156c39a52b1b23a810da917ab98da1f4)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: hendrikmuhs/ccache-action
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/linux-ci.yml | 2 +-
+ .github/workflows/macos-ci.yml | 2 +-
+ .github/workflows/msvc-ci.yml  | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+commit a8fb56e0f313558dc1f18df2d76ca691567330b9
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Aug 14 10:36:33 2023 +0000
+
+    Bump meson from 1.2.0 to 1.2.1 in /.ci
+    
+    Bumps [meson](https://github.com/mesonbuild/meson) from 1.2.0 to 1.2.1.
+    - [Release notes](https://github.com/mesonbuild/meson/releases)
+    - [Commits](https://github.com/mesonbuild/meson/compare/1.2.0...1.2.1)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: meson
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .ci/requirements.in  | 2 +-
+ .ci/requirements.txt | 6 +++---
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit e8eb1dc5ff695427abc137d3d15c4eec64ab6c78
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Aug 9 15:35:59 2023 -0600
+
+    [parse_tag] Accept non-ALNUM in tag name
+
+ src/hb-common.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9a7afe922b7c661267ecd2211b5199f5ae4df180
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Aug 9 12:00:41 2023 -0600
+
+    [perf] Benchmark glyph painting
+
+ perf/benchmark-font.cc | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+commit 077c4308cc2650bcd761b60c2b64eea77c5d399c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Aug 9 10:41:04 2023 -0600
+
+    [limits] Increase COLRv1 edge-count
+    
+    We have a "pixel" color font that was easily hitting the limit...
+
+ src/hb-limits.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 45c1ad05126c33408ccf862a0fde69f608147f04
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Aug 9 10:27:45 2023 -0600
+
+    [paint] Add tracing
+
+ src/OT/Color/COLR/COLR.hh | 22 ++++++++++++++++++++++
+ src/hb-debug.hh           | 19 +++++++++++++++++--
+ 2 files changed, 39 insertions(+), 2 deletions(-)
+
+commit 483bc0a3847ae55860bd55fa0eb214f899a02b31
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 8 15:58:20 2023 -0600
+
+    [arabic/stch] Center the stretched group over the digits
+    
+    Mostly relevant when there's one digit only.
+    
+    https://github.com/harfbuzz/harfbuzz/issues/4369#issuecomment-1670361856
+
+ src/hb-ot-shaper-arabic.cc                       | 5 ++++-
+ test/shape/data/in-house/tests/arabic-stch.tests | 1 +
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+commit 9daef6ed4eda12e13628b1ae8bff590d4e6adaf6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 8 13:33:11 2023 -0600
+
+    [arabic] Add test for previous commit
+
+ .../fonts/507637795ce4f2975593da54d12b46f76c7cc4cc.ttf   | Bin 0 -> 2200 bytes
+ test/shape/data/in-house/tests/arabic-stch.tests         |   1 +
+ 2 files changed, 1 insertion(+)
+
+commit 313c772989ca838f7ba9c2119ffb953ba8a4418b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 8 13:06:12 2023 -0600
+
+    [arabic/stch] Also work in left-to-right direction
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4369
+
+ src/hb-ot-shaper-arabic.cc | 25 ++++++++++++++++++++-----
+ 1 file changed, 20 insertions(+), 5 deletions(-)
+
+commit 40bfabd1f97d7ad665140ba764157a6058e6a3b7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 8 12:17:25 2023 -0600
+
+    [arabic/stch] Zero advances
+    
+    This was working for our test suite because those glyphs were
+    declared mark and their advances zeroed automatically. But is
+    not the case in eg. the font posted at:
+    
+    https://github.com/harfbuzz/harfbuzz/issues/4369
+
+ src/hb-ot-shaper-arabic.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 0aa5dafefd85d01d486d0d26b75387df3a2927e3
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Aug 8 08:33:11 2023 -0700
+
+    fix bots.
+    
+    -Also disable partial instancing tests for now, cause the command option
+    is wrapped by experimental_api
+
+ test/subset/data/Makefile.am      | 1 -
+ test/subset/data/Makefile.sources | 1 -
+ test/subset/meson.build           | 2 +-
+ util/hb-subset.cc                 | 4 ++++
+ 4 files changed, 5 insertions(+), 3 deletions(-)
+
+commit 77b158c72d355e8e5e32f0d9748174041fddc8dd
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Aug 7 16:02:02 2023 -0700
+
+    [instancer] add tests for gvar partial instancing
+
+ test/subset/data/Makefile.am                             |   1 +
+ test/subset/data/Makefile.sources                        |   1 +
+ ....retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf | Bin 0 -> 8256 bytes
+ ...iations.retain-all-codepoint.wght=300-600,wdth=85.ttf | Bin 0 -> 7244 bytes
+ ....retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf | Bin 0 -> 7452 bytes
+ ...iations.retain-all-codepoint.wght=300-600,wdth=85.ttf | Bin 0 -> 6780 bytes
+ .../data/profiles/no-tables-with-item-variations.txt     |   1 +
+ test/subset/data/tests/glyf_partial_instancing.tests     |  13 +++++++++++++
+ test/subset/generate-expected-outputs.py                 |   1 +
+ test/subset/meson.build                                  |   1 +
+ 10 files changed, 18 insertions(+)
+
+commit 32cfa37e2edd6a8dbc07c75c010fd2fc68c4346a
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon May 8 13:30:39 2023 -0700
+
+    [instancer] command line support for partial instancing
+    
+    -Also updated hb_subset_input_set_axis_range (), so user can define
+    default value as well
+
+ src/hb-subset-input.cc | 19 ++++++++----
+ src/hb-subset.h        |  3 +-
+ util/hb-subset.cc      | 80 ++++++++++++++++++++++++++++++++++++++++----------
+ 3 files changed, 80 insertions(+), 22 deletions(-)
+
+commit 0065658e96c79f8b51c2a702908e84d9d23e0971
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Aug 7 11:12:02 2023 -0700
+
+    [instancer] enable cvar instancing code
+
+ src/hb-subset-input.cc | 1 -
+ src/hb-subset.cc       | 3 +++
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+commit 0ba4d539b365039b602d9f88133fc0cae9cd0e30
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Aug 7 11:49:03 2023 -0600
+
+    Bump fonttools from 4.41.1 to 4.42.0 in /.ci (#4365)
+    
+    Bumps [fonttools](https://github.com/fonttools/fonttools) from 4.41.1 to 4.42.0.
+    - [Release notes](https://github.com/fonttools/fonttools/releases)
+    - [Changelog](https://github.com/fonttools/fonttools/blob/main/NEWS.rst)
+    - [Commits](https://github.com/fonttools/fonttools/compare/4.41.1...4.42.0)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: fonttools
+      dependency-type: direct:production
+      update-type: version-update:semver-minor
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+
+ .ci/requirements-fonttools.txt | 70 +++++++++++++++++++++---------------------
+ .ci/requirements.txt           | 70 +++++++++++++++++++++---------------------
+ 2 files changed, 70 insertions(+), 70 deletions(-)
+
+commit 366ffd1ef0f26cf719ee45e08f59fc9fb4b38a05
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Aug 7 10:32:47 2023 -0700
+
+    [instancer] fix move constructor for tuple_delta_t
+
+ src/hb-ot-var-common.hh | 16 +++++++++++-----
+ 1 file changed, 11 insertions(+), 5 deletions(-)
+
+commit 1d91622ddf082cd0777e9ae67876fe13fc7e454d
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Jul 18 09:52:40 2023 -0700
+
+    [instancer] add a hashing impl for floating point type
+
+ src/hb-algs.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 5a4694b6934f9e3ca3dc89cc905b4351920085b6
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Aug 7 09:55:30 2023 -0700
+
+    [instancer] add calc_inferred_deltas() for gvar
+
+ src/hb-ot-var-common.hh    | 104 +++++++++++++++++++++++++++++++++++++++++++++
+ src/test-tuple-varstore.cc |   3 +-
+ 2 files changed, 105 insertions(+), 2 deletions(-)
+
+commit fb44727401d36adc14615deda91574a6e7ec2cd6
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Aug 7 09:44:41 2023 -0700
+
+    [instancer] add instantiate () for gvar
+
+ src/hb-ot-var-common.hh     | 11 ++++++++---
+ src/hb-ot-var-gvar-table.hh | 22 ++++++++++++++++++++++
+ 2 files changed, 30 insertions(+), 3 deletions(-)
+
+commit 746b112faf6adcd4a9d7325b067c4ba46a973a95
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Aug 7 09:26:42 2023 -0700
+
+    [instancer] add serialize () for gvar
+
+ src/hb-ot-var-common.hh     |   6 ++-
+ src/hb-ot-var-cvar-table.hh |   1 +
+ src/hb-ot-var-gvar-table.hh | 114 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 120 insertions(+), 1 deletion(-)
+
+commit 3c86b096a9bf310a00086a7ed566cf1436da786c
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Jul 28 16:18:51 2023 -0700
+
+    [instancer] Add instantiate () and compile_bytes() for gvar
+    
+    -Also add support for using shared_points and shared_tuples
+
+ src/hb-ot-var-common.hh     | 85 +++++++++++++++++++++++++++++++++++++--------
+ src/hb-ot-var-cvar-table.hh |  7 ++--
+ src/hb-ot-var-gvar-table.hh | 29 ++++++++++++++++
+ src/test-tuple-varstore.cc  |  2 +-
+ 4 files changed, 106 insertions(+), 17 deletions(-)
+
+commit 198612c1c83d3b19b953a2fcc73406287104e5a2
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Jul 28 15:41:54 2023 -0700
+
+    [instancer] add decompile_glyph_variations () for gvar
+
+ src/hb-ot-var-common.hh     |  1 +
+ src/hb-ot-var-gvar-table.hh | 81 +++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 82 insertions(+)
+
+commit eb116e163e0bb8476cdd53a07630389d25ec3b97
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Jul 28 15:27:07 2023 -0700
+
+    [instancer] Add new_gid->contour_points vector map in subset plan
+    
+    - Add an API in Glyph to export original contour_points vector, which is
+      needed by infer_deltas when merging tuple variations with the same
+      tent
+
+ src/OT/glyf/Glyph.hh              | 57 +++++++++++++++++++++++++++++++++++++++
+ src/hb-ot-var-gvar-table.hh       | 34 -----------------------
+ src/hb-subset-plan-member-list.hh |  3 +++
+ src/hb-subset-plan.cc             | 32 ++++++++++++++++++++++
+ src/hb-subset-plan.hh             | 34 +++++++++++++++++++++++
+ 5 files changed, 126 insertions(+), 34 deletions(-)
+
+commit a0f810effcb497e77be25328a251e608b5863999
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Jul 28 15:04:47 2023 -0700
+
+    [instancer] add struct glyph_variations_t for gvar
+    
+    -Add compile_peak_coords () in tuple_delta_t
+    -Add compile_shared_tuples () for glyph_variations_t
+
+ src/hb-ot-var-common.hh     |  33 ++++++++++++++
+ src/hb-ot-var-gvar-table.hh | 105 ++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 138 insertions(+)
+
+commit cb92210b4cf93f6d7986dc75632c831092b4de19
+Author: Bruce Mitchener <bruce.mitchener@gmail.com>
+Date:   Tue Aug 8 00:19:30 2023 +0700
+
+    Improve Markdown formatting. (#4366)
+
+ BUILD.md  | 23 +++++++++++++----------
+ README.md |  4 ++--
+ 2 files changed, 15 insertions(+), 12 deletions(-)
+
+commit 49dbe0cd30a47258af0523822c924e9698a3e845
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Aug 6 15:07:57 2023 -0600
+
+    Another try
+
+ src/OT/Color/COLR/COLR.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 483d4a8741890ac72fa22d167ed53d4e39e9bd1d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Aug 6 14:40:45 2023 -0600
+
+    Fix bot
+
+ src/OT/Layout/GPOS/CursivePosFormat1.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 7989702abadc8fff69a99a47cfad2db08f5b8184
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Aug 6 14:17:50 2023 -0600
+
+    Audit and fix up serialize_subset uses
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4362
+
+ src/OT/Color/COLR/COLR.hh                | 11 ++++++-----
+ src/OT/Layout/GPOS/AnchorMatrix.hh       |  5 +++--
+ src/OT/Layout/GPOS/CursivePosFormat1.hh  | 11 +++++------
+ src/OT/Layout/GPOS/LigatureArray.hh      | 13 +++++++------
+ src/OT/Layout/GPOS/MarkArray.hh          |  6 +++---
+ src/OT/Layout/GPOS/MarkBasePosFormat1.hh | 15 +++++++--------
+ src/OT/Layout/GPOS/MarkLigPosFormat1.hh  | 14 +++++++-------
+ src/OT/Layout/GPOS/MarkMarkPosFormat1.hh | 12 +++++++-----
+ src/OT/Layout/GPOS/MarkRecord.hh         | 11 +++++------
+ src/hb-ot-layout-common.hh               |  3 +--
+ 10 files changed, 51 insertions(+), 50 deletions(-)
+
+commit 1d665c2b521512cdd56964138fc601debd1f1177
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Aug 2 23:44:56 2023 +0300
+
+    8.1.1
+
+ NEWS             | 8 ++++++++
+ configure.ac     | 2 +-
+ meson.build      | 2 +-
+ src/hb-version.h | 4 ++--
+ 4 files changed, 12 insertions(+), 4 deletions(-)
+
+commit 91c449a64a6924afd2aee4d3eb0b80c8c7d9ad07
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Aug 2 14:40:55 2023 -0600
+
+    [graph] Make space_for non-recursive
+    
+    It was tail-recursive so perhaps the compiler did the same.
+    Anyway, make it explicit now.
+
+ src/graph/graph.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit dcd3afcabfeb447a075b189f20cd523e177a0a9d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 1 20:09:34 2023 -0600
+
+    [skippy-iter] Remove unused num_items
+
+ src/OT/Layout/GPOS/CursivePosFormat1.hh  |  2 +-
+ src/OT/Layout/GPOS/MarkMarkPosFormat1.hh |  2 +-
+ src/OT/Layout/GPOS/PairPosFormat1.hh     |  2 +-
+ src/OT/Layout/GPOS/PairPosFormat2.hh     |  2 +-
+ src/OT/Layout/GSUB/LigatureSet.hh        |  2 +-
+ src/hb-kern.hh                           |  2 +-
+ src/hb-ot-layout-gsubgpos.hh             | 24 +++++++-----------------
+ 7 files changed, 13 insertions(+), 23 deletions(-)
+
+commit 5b337130e28eeaef3b5cfe884b514059417e3384
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 1 20:02:21 2023 -0600
+
+    Add test for previous commit
+
+ .../fonts/bef923f4ccb474f961c43b63a9c74b7d9b7a023f.ttf   | Bin 0 -> 2180 bytes
+ test/shape/data/in-house/tests/context-matching.tests    |   1 +
+ 2 files changed, 1 insertion(+)
+
+commit 39048099cb421095e24cdcc027b9cdc2a7fcf93e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 1 19:41:12 2023 -0600
+
+    [skippy-iter] Remove early stop
+    
+    The optimization in (Chain)RuleSet matching relies on
+    matching one, even if num_items is out of range.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4358
+
+ src/hb-ot-layout-gsubgpos.hh | 12 ++----------
+ 1 file changed, 2 insertions(+), 10 deletions(-)
+
+commit 70b3fbed2850f310658b65a68a058232b78ebeee
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 1 15:16:16 2023 -0600
+
+    [graph] Fix invalid read when map gets resized
+    
+    I don't fully understand how the old code was wrong, since
+    *v should be evaluated before the set() method call.
+    Yet this seems to fix a bug that could be reproduced
+    with HB_DEBUG_SUBSET_REPACK enabled and the following:
+    
+    $ hb-repacker-fuzzer test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6419865171525632
+
+ src/graph/graph.hh | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+commit 94d4283b12037d66ceb3b195f47d3bca96eb6627
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 1 15:05:17 2023 -0600
+
+    [graph] Handle a malloc fail
+    
+    Fixes https://oss-fuzz.com/testcase-detail/4579249263345664
+
+ src/graph/graph.hh                                   |  19 ++++++++++++-------
+ ...ase-minimized-hb-repacker-fuzzer-4579249263345664 | Bin 0 -> 173466 bytes
+ 2 files changed, 12 insertions(+), 7 deletions(-)
+
+commit 603920e911dc0fde79dc0ddde2be393f5c123d30
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 1 14:58:33 2023 -0600
+
+    [graph] Minor asserts
+
+ src/graph/graph.hh | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+commit 8d00476fbf99f770608644e424712cf95d3950b8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 1 14:27:37 2023 -0600
+
+    [graph] Minor restructure a condition
+
+ src/graph/graph.hh | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+commit 7946984b9624338b8d15fa53ac21664a734e93d3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 1 14:18:03 2023 -0600
+
+    [graph] More assert
+
+ src/graph/graph.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit 3b386c3773f24e30ec26bbbf86422ac67a6fb7b9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 1 14:12:43 2023 -0600
+
+    [graph] Minor assert
+
+ src/graph/graph.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 07e7033076d9acfeeaa7a91ea878fa130a022824
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 1 12:25:45 2023 -0600
+
+    [graph] Error check
+
+ src/graph/graph.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 7a9aac1ae3f7b836ddb314636d6f50d8ad7ec5d2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 1 12:05:22 2023 -0600
+
+    [graph] Fixes to parent handling
+
+ src/graph/graph.hh | 19 ++++++++++++++-----
+ 1 file changed, 14 insertions(+), 5 deletions(-)
+
+commit 2feac50b40f1dff06655c8efcadcc55088b34dad
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 31 19:53:06 2023 -0600
+
+    Revert "[gsubgpos] Keep another digest in the applicable_t"
+    
+    This reverts commit fd79c7cecdf68fe4626943f29bd5edf1e603d2b2.
+
+ src/hb-ot-layout-gsubgpos.hh | 32 ++++++++++----------------------
+ 1 file changed, 10 insertions(+), 22 deletions(-)
+
+commit fd79c7cecdf68fe4626943f29bd5edf1e603d2b2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 31 19:52:15 2023 -0600
+
+    [gsubgpos] Keep another digest in the applicable_t
+    
+    The digest for all the remaining subtables combined.
+    The idea is to get out of the subtable look as soon as
+    no more can be applied.
+    
+    Doesn't seem to speed up anything I tested. Going to revert.
+
+ src/hb-ot-layout-gsubgpos.hh | 32 ++++++++++++++++++++++----------
+ 1 file changed, 22 insertions(+), 10 deletions(-)
+
+commit e3fd69c88958fead68a62cecef7454990f7757fd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 31 19:07:42 2023 -0600
+
+    [layout] Inline another function
+    
+    Code is smaller too.
+
+ src/hb-ot-layout-gsubgpos.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 9cdc043c16d319268677a9098c83dc572d279c99
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 31 18:53:29 2023 -0600
+
+    [Cursive] Only sanitize what we use
+
+ src/OT/Layout/GPOS/CursivePosFormat1.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 25e9defa516d63b12a659282a13dc9e1fe522cc8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 31 17:12:07 2023 -0600
+
+    [sanitize] Inline check_struct
+    
+    Though seems like the compiler was always inlining it anyway.
+
+ src/hb-sanitize.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 44026aa8a992b7105a615f1fbaaf0e342b634efa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 31 16:47:06 2023 -0600
+
+    [Cursive] Minor, adjust unsafe-to-concat if prev didn't sanitize
+
+ src/OT/Layout/GPOS/CursivePosFormat1.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit b382e616cc807fe16da0fe7baca6dc2335fab987
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 31 16:29:28 2023 -0600
+
+    [GPOS] Sanitize Cursive positioning anchors lazily
+    
+    Speeds up Duployan-Regular.otf load time by 30%.
+    Doesn't seem to slow down shaping in a measurable way.
+
+ src/OT/Layout/GPOS/CursivePosFormat1.hh | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+commit fcb9e5915f5d20b20576612efd4ee15d9da04c8a
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Aug 1 00:57:06 2023 +0300
+
+    8.1.0
+
+ NEWS                   | 21 +++++++++++++++++++--
+ configure.ac           |  2 +-
+ docs/harfbuzz-docs.xml |  1 +
+ meson.build            |  2 +-
+ src/hb-ot-layout.cc    |  2 +-
+ src/hb-version.h       |  6 +++---
+ 6 files changed, 26 insertions(+), 8 deletions(-)
+
+commit 847e4a7607b6ddd97bd9d59c047d18736a566428
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Jul 31 15:21:51 2023 -0600
+
+    Bump github/codeql-action from 2.21.0 to 2.21.2 (#4352)
+    
+    Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.0 to 2.21.2.
+    - [Release notes](https://github.com/github/codeql-action/releases)
+    - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
+    - [Commits](https://github.com/github/codeql-action/compare/1813ca74c3faaa3a2da2070b9b8a0b3e7373a0d8...0ba4244466797eb048eb91a6cd43d5c03ca8bd05)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: github/codeql-action
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+
+ .github/workflows/scorecard.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit db608229d1633f9cbea3b5223d6548e803fb08c7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 31 15:16:43 2023 -0600
+
+    [README] Update
+
+ README.md | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit 59f5f2651525c9d41d3394f9ef021f624b097346
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 31 15:09:11 2023 -0600
+
+    [ci/msys] Don't install freetype (#4354)
+    
+    * [ci/msys] Try deleting system harfbuzz DLL
+
+ .github/workflows/msys2-ci.yml | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+commit bd84458a951e2e8e7390ec45d3c0b0bfc30eca19
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 31 13:27:15 2023 -0600
+
+    [ci] Try uploading msys artefacts (#4353)
+    
+    * [ci] Try uploading msys artefacts
+    
+    * [ci] Always upload DLLs from msys2
+    
+    * [ci] Rename artifacts
+    
+    * Another try
+
+ .github/workflows/msys2-ci.yml | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit d9c4d3edf0e2dcc8e1653cffad114110a59f691d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 31 12:43:12 2023 -0600
+
+    [uniscribe] Fix warnings
+
+ src/hb-uniscribe.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 29ad9304e2b0cd84fbf125dfa907cd20d141fc70
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 30 17:06:25 2023 -0600
+
+    [layout] Minor add prealloc
+
+ src/hb-ot-layout.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit a41368bd7a0bf14c54b311a4455f7fdc5aa2df4b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 30 17:04:02 2023 -0600
+
+    [buffer] Minor micro-optimize
+
+ src/hb-buffer.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit dc35a0fbcb960f57df6c09a548651028c19e9790
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 30 16:32:11 2023 -0600
+
+    [ot-map] Speed up feature finding
+    
+    New API:
+    - hb_ot_layout_collect_feature_map()
+
+ docs/harfbuzz-sections.txt |  1 +
+ src/hb-ot-layout.cc        | 39 ++++++++++++++++++++++++++++++++++++++-
+ src/hb-ot-layout.h         |  7 +++++++
+ src/hb-ot-map.cc           | 22 +++++++++++++++-------
+ 4 files changed, 61 insertions(+), 8 deletions(-)
+
+commit ebdfa9838bd0170ee2f3bc766dbdad659a0e870c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 30 12:22:55 2023 -0600
+
+    [perf] Measure freetype face loading as well
+
+ perf/benchmark-font.cc | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+commit 202888ec3ed27f1ac575a13d93688776545a62bf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 30 11:49:08 2023 -0600
+
+    Fix mac bot
+    
+    I think the new unsafe-to-concat is correct...
+
+ src/hb-ot-shaper-use-machine.hh            | 1893 ++++++++++++++--------------
+ test/shape/data/in-house/tests/macos.tests |    2 +-
+ 2 files changed, 971 insertions(+), 924 deletions(-)
+
+commit 35a026c89ab4f55a962f0e837a7b7650eb3e7c31
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 30 11:28:59 2023 -0600
+
+    [shape] Unsafe-to-concat around fraction slash
+
+ src/hb-ot-shape.cc | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit f19ca24a8ed92373342adb0c69ac5975b44f50e1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 30 11:26:11 2023 -0600
+
+    Revert "Revert "Require numerator and denominator in auto fraction""
+    
+    This reverts commit 8fe506e153c530affd529e7175e813c3a878faed.
+
+ src/hb-ot-shape.cc                                       | 2 ++
+ test/shape/data/in-house/tests/automatic-fractions.tests | 4 ++++
+ 2 files changed, 6 insertions(+)
+
+commit b2a73166d4d7874565ac61dcfca74f651f922e5c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 30 11:23:19 2023 -0600
+
+    [buffer] Fix unsafe_to_concat()
+    
+    Ouch!
+
+ src/hb-buffer.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 8fe506e153c530affd529e7175e813c3a878faed
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 30 10:43:28 2023 -0600
+
+    Revert "Require numerator and denominator in auto fraction"
+    
+    This reverts commit f3e86937df345d7709de879af1d1a1502e84e1e9.
+
+ src/hb-ot-shape.cc                                       | 2 --
+ test/shape/data/in-house/tests/automatic-fractions.tests | 4 ----
+ 2 files changed, 6 deletions(-)
+
+commit f3e86937df345d7709de879af1d1a1502e84e1e9
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sun Jul 30 08:28:23 2023 -0400
+
+    Require numerator and denominator in auto fraction
+
+ src/hb-ot-shape.cc                                       | 2 ++
+ test/shape/data/in-house/tests/automatic-fractions.tests | 4 ++++
+ 2 files changed, 6 insertions(+)
+
+commit 23838e5a2e7f5627d77fb85c50a0bfd9e004d6a8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 29 13:20:14 2023 -0600
+
+    [graph] Error handling
+
+ src/graph/graph.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 04f4909257b2da56d76c24872075f6f655ae4438
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 28 14:37:52 2023 -0600
+
+    [graph] Use a move instead of swap
+
+ src/graph/graph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3bedb0eeed62aaab3c6be849480a54214a59715b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 27 16:04:01 2023 -0600
+
+    [graph] Minor rename
+
+ src/graph/graph.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit bb1f53c2540a1e45c18eb8fbe4935b9c4e4fefa8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 27 13:29:56 2023 -0600
+
+    [graph] Try fixing infinite loop found by CIFuzz under malloc fail
+
+ src/graph/graph.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit db3314c1f860ee5cf68c81ccce5771b9b0366bca
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 27 13:20:32 2023 -0600
+
+    [graph] Minor space type change
+
+ src/graph/graph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 6a218eaeea3de3455825be63a099e6028c56508d
+Merge: 45a0d65c6 6bb61708e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 27 13:14:52 2023 -0600
+
+    Merge pull request #4343 from harfbuzz/graph-parents-map
+    
+    [graph] Use a hb_map_t to keep parents, instead of hb_vector_t
+
+commit 6bb61708ed2059abdbbb6eb7e8a9b721de64dd73
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 27 13:02:55 2023 -0600
+
+    [graph] Try fixing bots
+
+ src/graph/graph.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 1b5abb178197876d73584a4f51325323563b50dc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 27 12:41:43 2023 -0600
+
+    [graph] Speed-up vertices having only one parent
+
+ src/graph/graph.hh | 55 +++++++++++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 42 insertions(+), 13 deletions(-)
+
+commit f3d0b11d570eb790bb1ef5114f48fb59fbb260b6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 27 12:20:39 2023 -0600
+
+    [graph] Make parents private
+
+ src/graph/graph.hh | 31 +++++++++++++++++++++----------
+ 1 file changed, 21 insertions(+), 10 deletions(-)
+
+commit d3b997ee70e87d4e6b3e22ce99a21372c94d5a14
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 26 15:39:14 2023 -0600
+
+    [graph] Use a hb_map_t to keep parents, instead of hb_vector_t
+    
+    In some fonts, for example Noto Duployan-Regular, nodes can
+    have over a thousand parents... Speeds up 10% subsetting.
+
+ src/graph/classdef-graph.hh |  2 +-
+ src/graph/coverage-graph.hh |  2 +-
+ src/graph/graph.hh          | 94 +++++++++++++++++++++++++++++----------------
+ src/graph/gsubgpos-graph.hh |  6 +--
+ src/graph/pairpos-graph.hh  |  2 +-
+ 5 files changed, 66 insertions(+), 40 deletions(-)
+
+commit 45a0d65c6219c755245ea1df24b2e8d644420971
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Jul 27 09:06:02 2023 -0700
+
+    [instancer] cosmetic change
+
+ src/hb-ot-var-common.hh | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+commit cb320d22228d366c06dd97d43bf06f7ad7afd5f2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 27 10:43:07 2023 -0600
+
+    Revert "[cff] Use float instead of double"
+    
+    This reverts commit c8f67ac28eb18e65adda75818e2c472ad3936874.
+    
+    Tests failing.
+
+ src/hb-cff-interp-common.hh      | 14 +++++++-------
+ src/hb-cff-interp-dict-common.hh |  4 ++--
+ src/hb-cff2-interp-cs.hh         |  8 ++++----
+ src/hb-subset-cff2.cc            |  6 +++---
+ 4 files changed, 16 insertions(+), 16 deletions(-)
+
+commit c8f67ac28eb18e65adda75818e2c472ad3936874
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 27 10:34:45 2023 -0600
+
+    [cff] Use float instead of double
+    
+    Reduces memory usage slightly.
+
+ src/hb-cff-interp-common.hh      | 14 +++++++-------
+ src/hb-cff-interp-dict-common.hh |  4 ++--
+ src/hb-cff2-interp-cs.hh         |  8 ++++----
+ src/hb-subset-cff2.cc            |  6 +++---
+ 4 files changed, 16 insertions(+), 16 deletions(-)
+
+commit b36b100ef1c94012456c807167b2ac07443380ce
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 26 14:42:46 2023 -0600
+
+    [var] Remove byte_data_t; use hb_bytes_t
+    
+    Now that we have hopefully fixed the bug preventing hb_bytes_t
+    use, remove the hack.
+    
+    Ref.
+    5690840ceb190341f9960d2b975c4366566ae86b
+    https://github.com/harfbuzz/harfbuzz/issues/4138
+
+ src/hb-ot-var-common.hh | 55 ++++++++++++++++---------------------------------
+ 1 file changed, 18 insertions(+), 37 deletions(-)
+
+commit c25b8c06129d5abca2124a69a170b54dff215c41
+Merge: 5690840ce 5cab0709a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 26 12:47:15 2023 -0600
+
+    Merge pull request #4335 from googlefonts/bug_fixes
+    
+    [instancer] support avar table, fix issues in STAT/fvar tables
+
+commit 5cab0709a4f7267a01eb6f254c02d8bbcb4832e6
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Jul 26 09:56:07 2023 -0700
+
+    [instancer] fix for missing to update tuple indices flag in operator +=
+
+ src/hb-ot-var-common.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 515f85d545debf3c769b6aa7aa8c90908ce2f7f6
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Jul 24 11:10:17 2023 -0700
+
+    [instancer] fix incorrect encoded_len
+
+ src/hb-ot-var-common.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit bccdcf5b18861fbdb599189ab1dcb45e339b02b2
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Jul 21 10:17:43 2023 -0700
+
+    [instancer] fix a bug in compiling deltas_y for gvar
+
+ src/hb-ot-var-common.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 5690840ceb190341f9960d2b975c4366566ae86b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 26 09:53:32 2023 -0600
+
+    [map] Another try at fixing archaic clang
+    
+    Fixes (?) https://github.com/harfbuzz/harfbuzz/issues/4138
+
+ src/hb-map.hh | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+commit a3b18062b7b19345f8c2818669d3d08f678d0bce
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 25 11:11:07 2023 -0600
+
+    [trak] Fix a couple return values
+
+ src/hb-aat-layout-trak-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 62e6f7835c1e2520108bba2e3b6ded43f93339bc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 25 08:32:21 2023 -0600
+
+    [Cursive] round
+
+ src/OT/Layout/GPOS/CursivePosFormat1.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 60db142784bb145426e4a02635bbad4f2f260d16
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 24 20:49:32 2023 -0600
+
+    [layout] Remove unused "max-size" cruft
+
+ src/OT/Layout/GPOS/PairValueRecord.hh |  1 -
+ src/OT/Layout/GSUB/Ligature.hh        |  1 -
+ src/hb-machinery.hh                   |  5 -----
+ src/hb-null.hh                        |  9 ---------
+ src/hb-open-type.hh                   | 30 ------------------------------
+ src/hb-ot-layout-gsubgpos.hh          |  2 --
+ 6 files changed, 48 deletions(-)
+
+commit 8eb7889fd4cd03f84c78eb84514e05927fb6bd2c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 24 20:31:12 2023 -0600
+
+    Add max-size to static-size objects
+
+ src/hb-machinery.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit e322949b9b94b3d28d952d0b7f337abb4b05c1fb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 24 20:28:37 2023 -0600
+
+    [ArrayOf] Remove fast-path for offset to max-sized objects
+    
+    Fixes timeout https://oss-fuzz.com/testcase-detail/6153196517851136
+
+ src/hb-open-type.hh | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+commit 9ffea6328e71fbaea159116e609d3b0c005564a8
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Jul 24 10:37:25 2023 +0000
+
+    Bump github/codeql-action from 2.20.4 to 2.21.0
+    
+    Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.20.4 to 2.21.0.
+    - [Release notes](https://github.com/github/codeql-action/releases)
+    - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
+    - [Commits](https://github.com/github/codeql-action/compare/489225d82a57396c6f426a40e66d461b16b3461d...1813ca74c3faaa3a2da2070b9b8a0b3e7373a0d8)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: github/codeql-action
+      dependency-type: direct:production
+      update-type: version-update:semver-minor
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/scorecard.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1a267f22ff3a608e5a8370224557268b0504f857
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Jul 24 11:01:01 2023 +0000
+
+    Bump fonttools from 4.41.0 to 4.41.1 in /.ci
+    
+    Bumps [fonttools](https://github.com/fonttools/fonttools) from 4.41.0 to 4.41.1.
+    - [Release notes](https://github.com/fonttools/fonttools/releases)
+    - [Changelog](https://github.com/fonttools/fonttools/blob/main/NEWS.rst)
+    - [Commits](https://github.com/fonttools/fonttools/compare/4.41.0...4.41.1)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: fonttools
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .ci/requirements-fonttools.txt | 70 +++++++++++++++++++++---------------------
+ .ci/requirements.txt           | 70 +++++++++++++++++++++---------------------
+ 2 files changed, 70 insertions(+), 70 deletions(-)
+
+commit ca7e7e925b920ee54a0d0ad256f4a7daa0763684
+Author: Nikolaus Waxweiler <madigens@gmail.com>
+Date:   Sun Jul 23 22:20:09 2023 +0100
+
+    Fix wasm-micro-runtime build instructions
+
+ docs/wasm-shaper.md | 11 ++++-------
+ 1 file changed, 4 insertions(+), 7 deletions(-)
+
+commit a32278acd89a5e29774c7a03b0d11b669cfbb3fc
+Author: Nikolaus Waxweiler <madigens@gmail.com>
+Date:   Sun Jul 23 22:19:51 2023 +0100
+
+    Fix example code
+
+ docs/wasm-shaper.md | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 55f41e287f8ff846584269cb0dbbc730402cab75
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 21 12:10:46 2023 -0600
+
+    [perf] Add duployan.txt
+    
+    From https://kaltashwawa.ca/2022/01/20/lovecraft-in-chinook-puspus-kopa-ulthar-tawn/
+
+ perf/texts/duployan.txt | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+commit c91899be14c82ae3d27c4cba2a1b920b6989a4f7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 21 11:43:47 2023 -0600
+
+    [gdef] Use set-digest for mark-filterint-sets
+    
+    Speeds up Noto Duployan-Regular.otf by 45% percent!
+
+ src/OT/Layout/GDEF/GDEF.hh   | 33 +++++++++++++++++++++++++++++++++
+ src/hb-null.hh               |  2 +-
+ src/hb-ot-layout-gsubgpos.hh |  2 +-
+ 3 files changed, 35 insertions(+), 2 deletions(-)
+
+commit e8948a4e86902202005193f5859980e6602ff2b4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 20 22:12:53 2023 -0600
+
+    [gsubgpos] Fix optimization
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4336
+
+ src/hb-ot-layout-gsubgpos.hh | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit 36c7ec443b9e5881502f2056331abb6c8508db28
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 20 18:56:46 2023 -0600
+
+    [sanitize] Simplify a return
+
+ src/hb-sanitize.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 13f05ab9b39202aed98923b8ed0488b344e88a6f
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Jul 20 09:57:02 2023 -0700
+
+    [instancer] support avar table partial instancing
+
+ src/hb-ot-var-avar-table.hh | 164 ++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-subset-input.cc      |   1 -
+ src/hb-subset.cc            |   4 ++
+ 3 files changed, 168 insertions(+), 1 deletion(-)
+
+commit 837885f0fabdd99f7c804adbb449d1eab67401a8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 20 12:58:16 2023 -0600
+
+    Revert "[sanitize/Coverage] Keep a map of sane coverages"
+    
+    This reverts commit a689114898cc3e8f1c6ba7cc49cd6c3639d91250.
+
+ src/OT/Layout/Common/Coverage.hh | 22 +++++-----------------
+ src/hb-sanitize.hh               |  3 ---
+ 2 files changed, 5 insertions(+), 20 deletions(-)
+
+commit 0ab906715e51859f5c88bae2a9e7611e3c251bec
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 20 12:57:16 2023 -0600
+
+    [sanitize/Coverage] Keep a map of sane coverages
+    
+    Fonts like Gulzar reuse the same coverage over a thousand times
+    sometimes.
+    
+    However, this doesn't speed up sanitize unfortunately. Looks
+    like calling Coverage::sanitize() is already very fast. We're
+    just doing A LOT of it.
+    
+    The map slowed it down in fact. A set was even slower.
+    
+    Going to revert.
+
+ src/OT/Layout/Common/Coverage.hh | 22 +++++++++++++++++-----
+ src/hb-sanitize.hh               |  3 +++
+ 2 files changed, 20 insertions(+), 5 deletions(-)
+
+commit 7de2f515a0792048556078a0860c940a1ee32739
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 20 12:46:54 2023 -0600
+
+    [set] Remove dependency on hb-machinery.hh
+
+ src/hb-bit-set.hh | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+commit e8de5cb08f209ce3901c53e86eade2238e0fb894
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 20 11:31:13 2023 -0600
+
+    [gsubgpos] Use a couple variables
+
+ src/hb-ot-layout-gsubgpos.hh | 30 ++++++++++++++++++------------
+ 1 file changed, 18 insertions(+), 12 deletions(-)
+
+commit 0ccd61a3b2ff0d94a9c72fe3ce965221ef6a7d5b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 19 16:42:30 2023 -0600
+
+    [gsubgpos] Micro-optimize
+
+ src/hb-ot-layout-gsubgpos.hh | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+commit b01c165034ebd26cc6d76301a6a272a813d42526
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 19 16:35:10 2023 -0600
+
+    [gsubgpos] Minor error handling
+
+ src/hb-ot-layout-gsubgpos.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit ee5f200bf1a61f43538e36716ba96cd229ebb1ba
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 19 12:26:50 2023 -0600
+
+    [gsubgpos] Remove un unnecessary variable
+
+ src/hb-ot-layout-gsubgpos.hh | 20 ++++----------------
+ 1 file changed, 4 insertions(+), 16 deletions(-)
+
+commit a0bb2d3a9b107d45d1f5f4e2ce27a0cbd46710ed
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Jul 19 11:21:01 2023 -0700
+
+    [instancer] support STAT table for all instancing operations
+
+ src/hb-subset.cc | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+commit 42c6a3a18a7d9106e0daf063371a1ba00543f73b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 19 12:07:19 2023 -0600
+
+    [gsubgpos] Remove unnecessary condition
+    
+    Second is always set in this branch.
+
+ src/hb-ot-layout-gsubgpos.hh | 14 ++++----------
+ 1 file changed, 4 insertions(+), 10 deletions(-)
+
+commit b5de54e1d49701073c1a9356c5e689e135cd8aec
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 19 11:19:06 2023 -0600
+
+    [gsubgpos] Also match second component in (Chain)RuleSet::apply()
+    
+    Another 40% speedup in shaping Gulzar-Regular.
+
+ src/hb-ot-layout-gsubgpos.hh | 98 +++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 75 insertions(+), 23 deletions(-)
+
+commit 73d94dbde35f5e01014f7858730e7d60b369aefd
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Jul 19 10:33:57 2023 -0700
+
+    [instancer] bug fixes in fvar: add missing instanceCount, update axis limit
+
+ src/hb-ot-var-fvar-table.hh | 35 ++++++++++++++++++++++++++++-------
+ 1 file changed, 28 insertions(+), 7 deletions(-)
+
+commit 02b00d774368bb82b97348436b0620b9ffe1bf0f
+Author: Richard Dodd (dodj) <richard.o.dodd@gmail.com>
+Date:   Wed Jul 19 11:22:07 2023 +0100
+
+    Update wasm-shaper.md (just a small typo)
+
+ docs/wasm-shaper.md | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 730f579f68c9062b0f493d400f445946f2ee032d
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Jul 18 15:09:36 2023 -0700
+
+    [instancer] store float value rather than F2DOT14 int value in axes_location map
+
+ src/hb-ot-layout-common.hh | 19 +++++++++++--------
+ src/hb-subset-plan.cc      |  6 +++---
+ 2 files changed, 14 insertions(+), 11 deletions(-)
+
+commit efbd257a325fedcf9000a9cccbf2d97d38769b98
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Jul 18 14:50:32 2023 -0700
+
+    [instancer] memory leak fix in cvar
+
+ src/hb-ot-var-cvar-table.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit a9e9279bee736d45eb58931ff7a363932e548090
+Merge: aa381ae96 5ee015ecf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 18 12:24:17 2023 -0600
+
+    Merge pull request #4329 from googlefonts/instancer_solver_fix
+    
+    port instancer solver normalizeValue fixes from fonttools
+
+commit aa381ae963fedadc227afcc154e3cf95d9aa84c1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 18 10:42:13 2023 -0600
+
+    [ReverseChain] Remove SIZE_MAX
+    
+    Oops. Can't set it since the struct has offsets.
+
+ src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit e583c9e904d3825b6f6e7a2996d555d16c67753b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 18 10:34:26 2023 -0600
+
+    [ReverseChain] Add max-size
+
+ src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 7a2f9dcfb9cd892191f295c8fd9ca39d6675d9ed
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 18 04:36:15 2023 -0600
+
+    [matcher] Move initializers inline
+
+ src/hb-ot-layout-gsubgpos.hh | 26 ++++++++------------------
+ 1 file changed, 8 insertions(+), 18 deletions(-)
+
+commit 5ee015ecf60aac27ea3cd6309b1b1fb3c3566196
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Jul 17 13:54:34 2023 -0700
+
+    [instancer-solver] remove unused normalizeValue() code
+
+ src/hb-subset-instancer-solver.cc | 30 ------------------------------
+ 1 file changed, 30 deletions(-)
+
+commit 6c25c752f608dfaa0b153b4c62bd96225c670080
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Jul 17 13:47:38 2023 -0700
+
+    [instancer] use renormalized values when instantiating Condition table
+
+ src/hb-ot-layout-common.hh | 22 +++++++++++++++++++++-
+ 1 file changed, 21 insertions(+), 1 deletion(-)
+
+commit 73ce3015bbaa04ce5a2a9da358e3695c7db10c44
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Jul 17 13:46:57 2023 -0700
+
+    [instancer-solver] port optimization and more tests from fonttools
+
+ src/hb-subset-instancer-solver.cc   |  5 ++---
+ src/test-subset-instancer-solver.cc | 19 +++++++++++++++++++
+ 2 files changed, 21 insertions(+), 3 deletions(-)
+
+commit 350423df8d7bc3c87b030c6304c9611136e60e68
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Jul 17 11:10:19 2023 -0700
+
+    [instancer-solver] fix tests
+
+ src/test-subset-instancer-solver.cc | 59 +++++++++++++++++++------------------
+ src/test-tuple-varstore.cc          |  5 +++-
+ 2 files changed, 34 insertions(+), 30 deletions(-)
+
+commit 12be4cb184c6600f26285f8a56b9b27b80931f22
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Jul 17 11:08:54 2023 -0700
+
+    [instancer-solver] fix APIs calling rebase_tent() with TripleDistances
+
+ src/hb-ot-var-common.hh     | 21 ++++++++++++++-------
+ src/hb-ot-var-cvar-table.hh |  2 +-
+ 2 files changed, 15 insertions(+), 8 deletions(-)
+
+commit 165f3e60ace3a086a3d5741146da83d2c82a409b
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Jul 17 09:46:03 2023 -0700
+
+    [instancer-solver] add renormalizeValue() and store axis->distances map
+
+ src/hb-ot-var-fvar-table.hh       |  7 +++++++
+ src/hb-subset-instancer-solver.cc | 43 +++++++++++++++++++++++++++++++++++++--
+ src/hb-subset-instancer-solver.hh | 24 +++++++++++++++++++++-
+ src/hb-subset-plan-member-list.hh |  2 ++
+ src/hb-subset-plan.cc             | 12 ++++++-----
+ 5 files changed, 80 insertions(+), 8 deletions(-)
+
+commit d92a7a58d83952782d2cf54391e129a09c4b306d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 17 11:27:38 2023 -0600
+
+    [gsubgpos] Inline a couple functions
+    
+    Produces smaller code.
+
+ src/hb-ot-layout-gsubgpos.hh | 34 ++++++++++++++++++----------------
+ 1 file changed, 18 insertions(+), 16 deletions(-)
+
+commit 4ea3737d04c575cd9b6ffda1e4e0f2c9d2b60d9c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 17 09:50:28 2023 -0600
+
+    [gsubgpos] Add fast-path for end-of-string in (Chain)RuleSet::apply()
+
+ src/hb-ot-layout-gsubgpos.hh | 26 ++++++++++++++++++++++++--
+ 1 file changed, 24 insertions(+), 2 deletions(-)
+
+commit e7ce633946e40e3f753880e8cfd4b86a51a878be
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 17 08:52:12 2023 -0600
+
+    [algs] Fix -Wcomma errors
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4328
+
+ src/hb-algs.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit af095d90e3ecd602feefad529ceaf6ee126103ac
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Jul 17 10:22:42 2023 +0000
+
+    Bump github/codeql-action from 2.20.3 to 2.20.4
+    
+    Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.20.3 to 2.20.4.
+    - [Release notes](https://github.com/github/codeql-action/releases)
+    - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
+    - [Commits](https://github.com/github/codeql-action/compare/46ed16ded91731b2df79a2893d3aea8e9f03b5c4...489225d82a57396c6f426a40e66d461b16b3461d)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: github/codeql-action
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/scorecard.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b031bbde94c962b287528402985e2c8a8f4b83b5
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Jul 17 10:22:45 2023 +0000
+
+    Bump actions/setup-python from 4.6.1 to 4.7.0
+    
+    Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4.6.1 to 4.7.0.
+    - [Release notes](https://github.com/actions/setup-python/releases)
+    - [Commits](https://github.com/actions/setup-python/compare/bd6b4b6205c4dbad673328db7b31b7fab9e241c0...61a6322f88396a6271a6ee3565807d608ecaddd1)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: actions/setup-python
+      dependency-type: direct:production
+      update-type: version-update:semver-minor
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/msvc-ci.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ae8fea081a09d478986427d4861c74eb0b9582d0
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Jul 17 10:28:35 2023 +0000
+
+    Bump fonttools from 4.40.0 to 4.41.0 in /.ci
+    
+    Bumps [fonttools](https://github.com/fonttools/fonttools) from 4.40.0 to 4.41.0.
+    - [Release notes](https://github.com/fonttools/fonttools/releases)
+    - [Changelog](https://github.com/fonttools/fonttools/blob/main/NEWS.rst)
+    - [Commits](https://github.com/fonttools/fonttools/compare/4.40.0...4.41.0)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: fonttools
+      dependency-type: direct:production
+      update-type: version-update:semver-minor
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .ci/requirements-fonttools.txt | 72 +++++++++++++++++++++---------------------
+ .ci/requirements.txt           | 70 ++++++++++++++++++++--------------------
+ 2 files changed, 71 insertions(+), 71 deletions(-)
+
+commit da84a078ee89d3d9cbd2a030722d01ee85f1bcde
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Jul 17 10:28:55 2023 +0000
+
+    Bump meson from 1.1.1 to 1.2.0 in /.ci
+    
+    Bumps [meson](https://github.com/mesonbuild/meson) from 1.1.1 to 1.2.0.
+    - [Release notes](https://github.com/mesonbuild/meson/releases)
+    - [Commits](https://github.com/mesonbuild/meson/compare/1.1.1...1.2.0)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: meson
+      dependency-type: direct:production
+      update-type: version-update:semver-minor
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .ci/requirements.in  | 2 +-
+ .ci/requirements.txt | 6 +++---
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit 49730531097cb0b29b6435fa62d10e5060852388
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 16 13:09:49 2023 -0600
+
+    Config
+
+ src/OT/Layout/GSUB/LigatureSet.hh | 4 ++--
+ src/hb-config.hh                  | 2 +-
+ src/hb-ot-layout-gsubgpos.hh      | 8 ++++++--
+ 3 files changed, 9 insertions(+), 5 deletions(-)
+
+commit 645fabd1013e94693f6da2d4263b0edd3b0b014d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 16 11:36:59 2023 -0600
+
+    [gsubgpos] Vastly speed up ChainRuleSet / RuleSet matching
+    
+    Match the first component in a fast loop.
+    
+    Idea replicated from LigatureSet.
+    
+    Speeds up Gulzar shaping by 22%!
+    37% in NotoNastaliqUrdu!
+
+ src/OT/Layout/GSUB/LigatureSet.hh |  4 +-
+ src/hb-ot-layout-gsubgpos.hh      | 82 +++++++++++++++++++++++++++++++++++----
+ 2 files changed, 77 insertions(+), 9 deletions(-)
+
+commit 77080f86f85744600a052e4f10bea50f331c44b0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 16 11:26:32 2023 -0600
+
+    .
+
+ src/OT/Layout/GSUB/LigatureSet.hh |  7 +---
+ src/hb-ot-layout-gsubgpos.hh      | 84 +++++++++++++++++++++++++++++++++++----
+ 2 files changed, 79 insertions(+), 12 deletions(-)
+
+commit 5c8f3b7fec330897d66bf72559aa2ac26862ae99
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 16 09:39:18 2023 -0600
+
+    [gsubgpos] Conditionally cache backtrack again
+
+ src/hb-ot-layout-gsubgpos.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 52237eb1fe6a53de649917ec64382adac89f8e54
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 16 09:07:25 2023 -0600
+
+    [ChainContext] More caching
+
+ src/hb-ot-layout-gsubgpos.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit 62e10c9fa0fce0b4798ccc13640f9fe85206f227
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 16 08:43:18 2023 -0600
+
+    Revert "[gsubgpos] Allocate iterators further up"
+    
+    This reverts commit b9f364b8fcacf8ab32d0272190d8509f214e55f2.
+
+ src/OT/Layout/GSUB/Ligature.hh                     |   5 +-
+ .../Layout/GSUB/ReverseChainSingleSubstFormat1.hh  |   8 +-
+ src/hb-ot-layout-gsubgpos.hh                       | 117 +++++++++------------
+ 3 files changed, 55 insertions(+), 75 deletions(-)
+
+commit b9f364b8fcacf8ab32d0272190d8509f214e55f2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 16 08:42:36 2023 -0600
+
+    [gsubgpos] Allocate iterators further up
+    
+    To avoid calling set_match_func repeatedly.
+    
+    Doesn't show speedup. Going to revert.
+
+ src/OT/Layout/GSUB/Ligature.hh                     |   5 +-
+ .../Layout/GSUB/ReverseChainSingleSubstFormat1.hh  |   8 +-
+ src/hb-ot-layout-gsubgpos.hh                       | 117 ++++++++++++---------
+ 3 files changed, 75 insertions(+), 55 deletions(-)
+
+commit c2f454c7e2e8f05636cfbf76f5e6b3dc3919378d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 16 08:23:59 2023 -0600
+
+    [gsubgpos] Fix residual from 5af80f349c4e040bfa853ee3f561ac16538b5988
+
+ src/hb-ot-layout-gsubgpos.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4e641103d40b5ada7f77dba3b6f0891de60388bb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 16 07:40:20 2023 -0600
+
+    [buffer] Inline a method
+
+ src/hb-buffer.hh | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 5af80f349c4e040bfa853ee3f561ac16538b5988
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 16 07:27:28 2023 -0600
+
+    [ChainContext] Cache two class values
+    
+    7% speedup shaping Gulzar.
+
+ src/hb-ot-layout-gsubgpos.hh | 38 ++++++++++++++++++++++++++------------
+ 1 file changed, 26 insertions(+), 12 deletions(-)
+
+commit 8cde4fa9a0e8cb6e42770a2ff7da158f2914cdb2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 16 06:01:06 2023 -0600
+
+    [gsubgpos] Inline a couple methods
+
+ src/hb-ot-layout-gsubgpos.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit f94508edd60e26a015586c37c29104d6bdc26462
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 15 15:28:19 2023 -0600
+
+    [Ligature] Micro-optimize
+
+ src/OT/Layout/GSUB/LigatureSet.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 76de3451e68168912bfd4b1a500ddbc45200b706
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 15 15:00:23 2023 -0600
+
+    [ot-shape] Short-circuit spaces as well
+
+ src/hb-ot-shape.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 765da4db1949b88eff921eb1b909dc4054e55f37
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 15 14:55:36 2023 -0600
+
+    [ot-shape] Minor short-circuit
+
+ src/hb-ot-shape.cc | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+commit 7b8e0bbb9f41561c2ee29a2868de9d7d155c9194
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 15 14:53:15 2023 -0600
+
+    [ot-shape] Minor short-circuit
+
+ src/hb-ot-shape.cc | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+commit b2d648e41b5f963fdfe37536467c03c02cd99d2f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 15 14:26:06 2023 -0600
+
+    [perf/benchmark-subset] Rename subset_codepoints to subset_unicodes
+
+ perf/benchmark-subset.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit a56288488c70036832414145c64ce9e42d7464a6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 15 13:59:10 2023 -0600
+
+    [subset] Speed up a couple of set iteration loops
+    
+    Need to speed up set::next_range() for the second one to have
+    any effect.
+
+ src/hb-ot-layout-common.hh | 11 ++++++++++-
+ src/hb-subset-plan.cc      |  9 ++++++---
+ 2 files changed, 16 insertions(+), 4 deletions(-)
+
+commit 326d319f93fe6173344602929fdbb5ba27412388
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 15 13:14:34 2023 -0600
+
+    [graph] Micro-optimize
+
+ src/graph/graph.hh | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+commit 548230e45e0bc9fa985d80714ede4c39a347d508
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 15 13:13:16 2023 -0600
+
+    [graph] Early return from a function
+
+ src/graph/graph.hh | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit 09706b04fce2afe42cade4cbf1b36db23edde94c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 15 13:11:04 2023 -0600
+
+    [graph] Add a pre-alloc to map
+
+ src/graph/graph.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit d1ddfc4d10e169c7fdd6187b38dd7a14f59e1def
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 14 14:52:43 2023 -0600
+
+    [graph] Use move instead of swap
+
+ src/graph/graph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 07cb6bf87af604dcc1a025257aea43c9e991c065
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 14 13:38:33 2023 -0600
+
+    [graph] Minor, type
+
+ src/graph/graph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 867640af31e8f88d65cd72a2c7f86f4632b98539
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 14 13:09:16 2023 -0600
+
+    Revert "[set] Add test_and_add / test_and_del"
+    
+    This reverts commit de1237fbf2660b5952dde4db171a62d9b1a77c92.
+    
+    This seems to be a net loss.
+
+ src/graph/graph.hh           | 17 ++++++++++++-----
+ src/hb-bit-page.hh           | 25 -------------------------
+ src/hb-bit-set-invertible.hh |  2 --
+ src/hb-bit-set.hh            | 16 ----------------
+ src/hb-set.hh                |  2 --
+ 5 files changed, 12 insertions(+), 50 deletions(-)
+
+commit 10b776b0c3afeefa19ec47c40196cf205a112c8b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 14 13:08:19 2023 -0600
+
+    [graph] Micro-optimize
+
+ src/graph/graph.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit de1237fbf2660b5952dde4db171a62d9b1a77c92
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 14 12:38:56 2023 -0600
+
+    [set] Add test_and_add / test_and_del
+    
+    Use in graph.
+
+ src/graph/graph.hh           | 17 +++++------------
+ src/hb-bit-page.hh           | 25 +++++++++++++++++++++++++
+ src/hb-bit-set-invertible.hh |  2 ++
+ src/hb-bit-set.hh            | 16 ++++++++++++++++
+ src/hb-set.hh                |  2 ++
+ 5 files changed, 50 insertions(+), 12 deletions(-)
+
+commit 7f1ff9c8819edc9cdb2e48cfc4042e38a05777a9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 14 12:22:24 2023 -0600
+
+    [graph] Micro-optimize array access
+
+ src/graph/graph.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit d9cf9b5f071c77b385d92d4740d5fd053cf6f8c7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 14 12:19:10 2023 -0600
+
+    [priority-queue] Inline insert()
+
+ src/hb-priority-queue.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit d00b88737e0a704d2af3b6539592dd9bb33a4722
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 14 11:26:51 2023 -0600
+
+    Revert "[subset/closure] Batch recursions in scheduled stages"
+    
+    This reverts commit f2aaeeb3016e10bf91c251296391a381d5fc6385.
+
+ src/hb-ot-layout-gsub-table.hh |  9 ++-------
+ src/hb-ot-layout-gsubgpos.hh   | 15 ---------------
+ 2 files changed, 2 insertions(+), 22 deletions(-)
+
+commit 5e42f7bb6d025f14955e60c94ea08aca472e08dd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 14 11:26:38 2023 -0600
+
+    Revert "Revert "[priority-queue] Inline a couple more""
+    
+    This reverts commit 915410e5267cba5bfc6154548c8856ae077bfefe.
+    
+    Mistake.
+
+ src/hb-priority-queue.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 915410e5267cba5bfc6154548c8856ae077bfefe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 14 11:18:09 2023 -0600
+
+    Revert "[priority-queue] Inline a couple more"
+    
+    This reverts commit 8704d73213da2294281687ecd7a40d408e9bf26a.
+
+ src/hb-priority-queue.hh | 3 ---
+ 1 file changed, 3 deletions(-)
+
+commit f2aaeeb3016e10bf91c251296391a381d5fc6385
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 14 11:17:37 2023 -0600
+
+    [subset/closure] Batch recursions in scheduled stages
+    
+    Going to revert. Doesn't pass tests and savings are minor.
+
+ src/hb-ot-layout-gsub-table.hh |  9 +++++++--
+ src/hb-ot-layout-gsubgpos.hh   | 15 +++++++++++++++
+ 2 files changed, 22 insertions(+), 2 deletions(-)
+
+commit 5a65ede5d43711098982995c4d2d6cd7f8eecad1
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Jul 12 10:18:31 2023 +0300
+
+    Minor
+
+ NEWS | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit d160d9389cb4c5b15ebea9b41eb74018c4358924
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Jul 12 08:27:25 2023 +0300
+
+    8.0.1
+
+ NEWS             | 11 +++++++++++
+ configure.ac     |  2 +-
+ meson.build      |  2 +-
+ src/hb-version.h |  4 ++--
+ 4 files changed, 15 insertions(+), 4 deletions(-)
+
+commit 8704d73213da2294281687ecd7a40d408e9bf26a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 10 18:08:13 2023 -0600
+
+    [priority-queue] Inline a couple more
+
+ src/hb-priority-queue.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 4c9e8b848b82dd8e268d596e69d0a5a32b724e01
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 10 18:04:03 2023 -0600
+
+    [priority-queue] Always-inline a method
+
+ src/hb-priority-queue.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit c41b0d7b8318710d792066f2915cf8c02c89162e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 10 17:23:58 2023 -0600
+
+    [sanitize/PairValueRecord] Add a max_size for faster sanitize
+
+ src/OT/Layout/GPOS/PairValueRecord.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit c14f94f76bd323108bad6e61483b88ed3eac35c3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 10 16:28:22 2023 -0600
+
+    Fix compiler error
+    
+    hb-ot-var-common.hh:758:32: error: implicit conversion from 'int' to 'char' changes value from 191 to -65 [-Werror,
+    -Wconstant-conversion]
+          *it++ = (DELTAS_ARE_ZERO | 63);
+
+ src/hb-ot-var-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit fcc5d3df39219a2bf8803026e5976504d696e99f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 10 16:21:28 2023 -0600
+
+    Add -Wconstant-conversion to errors
+
+ src/hb.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit d1855e902d371471b2120af8b8bfd1bf9a629b75
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Jul 10 10:26:31 2023 +0000
+
+    Bump github/codeql-action from 2.20.1 to 2.20.3
+    
+    Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.20.1 to 2.20.3.
+    - [Release notes](https://github.com/github/codeql-action/releases)
+    - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
+    - [Commits](https://github.com/github/codeql-action/compare/f6e388ebf0efc915c6c5b165b019ee61a6746a38...46ed16ded91731b2df79a2893d3aea8e9f03b5c4)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: github/codeql-action
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/scorecard.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 997986ab307bb7868b780a3ff608bd608fb9e077
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 9 15:15:33 2023 -0600
+
+    [subset/hvar] Error handling
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5029952234586112
+
+ src/hb-ot-var-hvar-table.hh                               |   2 +-
+ ...z-testcase-minimized-hb-subset-fuzzer-5029952234586112 | Bin 0 -> 837 bytes
+ 2 files changed, 1 insertion(+), 1 deletion(-)
+
+commit 0980e2b7481890685ce1869fc25a2915ecac92f4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 9 15:13:57 2023 -0600
+
+    Minor casts
+
+ src/hb-algs.hh     | 4 ++--
+ src/hb-bit-page.hh | 8 ++++----
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+commit db3aeeb547c1a2cad46ea03e162593d22f700cb4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 9 12:32:49 2023 -0600
+
+    [subset] Fix cast-align issue
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4316
+
+ src/hb-serialize.hh | 2 +-
+ src/hb-subset.cc    | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit fc24ffbfb3384286efa20728fe054c884d487fb0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 9 11:05:13 2023 -0600
+
+    [priority-queue] Minor simplify
+    
+    Tail-recursion definitely was being optimized by compiler,
+    but I prefer writing it this way.
+
+ src/hb-priority-queue.hh | 19 +++++++++++--------
+ 1 file changed, 11 insertions(+), 8 deletions(-)
+
+commit 557653abceeb4305a449851b74c62918540d03b0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 9 10:18:04 2023 -0600
+
+    [cff] Minor; add tableTag
+
+ src/hb-ot-cff1-table.hh | 2 ++
+ src/hb-ot-cff2-table.hh | 2 ++
+ 2 files changed, 4 insertions(+)
+
+commit 6df8ce7b41294fcaf028e425ccb6be331b37ced5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 9 09:58:02 2023 -0600
+
+    [bit-page] Remove disabled assertion
+
+ src/hb-bit-page.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 9b9a9c6f4a47307e3cb5be3a4774f4bd1feeb180
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 9 09:55:00 2023 -0600
+
+    [bit-page] Speed up is_empty()
+
+ src/hb-bit-page.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 2f4ed5e939fb9619ca27786b6d71b577d909c15f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 9 09:45:46 2023 -0600
+
+    [bit-page] Short-circuit is_subset()
+
+ src/hb-bit-page.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 347c1f701313d7449002e3b0426b38bbb870c8b5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 9 09:33:04 2023 -0600
+
+    [set] Keep (lazy) population per bit-page
+    
+    36% speedup in:
+    BM_subset/subset_glyphs/merged.devalast.ttf/10
+
+ src/hb-bit-page.hh | 20 ++++++++++++++------
+ src/hb-bit-set.hh  |  5 +++--
+ 2 files changed, 17 insertions(+), 8 deletions(-)
+
+commit 04ee306b9ae7c2382baf17c9b7ae47a2527c38aa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 9 07:37:57 2023 -0600
+
+    [subset/hmtx] Another TODO
+
+ src/hb-ot-hmtx-table.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit caef35b3ef478462a996e3fdb988bcc9cca492c8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 9 07:23:16 2023 -0600
+
+    [subset/hmtx] TODO
+
+ src/hb-ot-hmtx-table.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 982554c71c06a485b9e93ffd9a55c7b1d1add23c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 9 06:58:02 2023 -0600
+
+    [subset/cff1] Speed up plan_subset_charset more
+    
+    16% speed up in retaingid subsetting NotoSansCJKkr-Regular.otf.
+
+ src/hb-subset-cff1.cc | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+commit 15d8f0ca7c7c9f293bc35034c3e9a3c12451cfd9
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sun Jul 9 10:56:36 2023 +0300
+
+    [doc] Fix warning: Section has no title and no file
+    
+    Move the private macros to the hb-common section, instead of a file-less
+    one.
+
+ docs/harfbuzz-sections.txt | 11 ++++-------
+ 1 file changed, 4 insertions(+), 7 deletions(-)
+
+commit e60ec9dcd3b0f94d13b8baf7ba12cd6cf0626064
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 20:47:34 2023 -0600
+
+    [subset/cff2] Speedup retaingids serialize
+    
+    10% speedup in subset_glyphs/SourceHanSans-VF.otf/retaingids/10
+
+ src/hb-ot-cff-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit b583978bdf0e83ab597c797d8a0b10291f976362
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 20:41:58 2023 -0600
+
+    [subset/DeltaSetMapIndex] Speedup retaingids serialize()
+
+ src/hb-ot-var-common.hh | 17 ++++++++++-------
+ 1 file changed, 10 insertions(+), 7 deletions(-)
+
+commit 3505486a0d7c44217c2629c193f4d78cf29aa9ae
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 20:28:45 2023 -0600
+
+    [subset/DeltaSetMapIndex] Micro-optimize
+
+ src/hb-ot-var-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c8f6ae1df7d559180c40511a8ad8c2da7b303dff
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 20:21:49 2023 -0600
+
+    [subset/hvar/retaingids] Synthesize a DeltaSetIndexMap if needed
+    
+    Before we were emitting the entire VarStore rows if advMap
+    was Null. Instead, synthesize an advMap.
+    
+    20% speed up in subset_glyphs/SourceHanSans-VF.otf/retaingids benchmark.
+
+ src/hb-ot-var-hvar-table.hh                        |  32 ++++++---------------
+ test/api/fonts/AdobeVFPrototype.ac.retaingids.otf  | Bin 4584 -> 4584 bytes
+ test/api/fonts/SourceSansVariable-Roman.abc.ttf    | Bin 3196 -> 5160 bytes
+ .../SourceSansVariable-Roman.ac.retaingids.ttf     | Bin 2976 -> 4584 bytes
+ test/api/fonts/SourceSansVariable-Roman.ac.ttf     | Bin 2964 -> 4580 bytes
+ 5 files changed, 9 insertions(+), 23 deletions(-)
+
+commit 1f4645c6fc4c7cc4d551791b6c04f67e71f4952d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 18:49:47 2023 -0600
+
+    [subset/hvar] Speed up
+
+ src/hb-ot-var-hvar-table.hh | 19 +++++++++----------
+ 1 file changed, 9 insertions(+), 10 deletions(-)
+
+commit 8d99db5c3b4bebf22b06bfa12cf90dad6af9555a
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sun Jul 9 03:41:48 2023 +0300
+
+    [wasm] Typo [ci skip]
+
+ docs/wasm-shaper.md | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 8115033ac338067f9fb1050294eb2cfd8f86e784
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 18:33:13 2023 -0600
+
+    [hvar] Speed up retaingids planning
+    
+    35% speedup in:
+    BM_subset/subset_glyphs/SourceHanSans-VF.otf/retaingids/10
+
+ src/hb-ot-var-hvar-table.hh | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+commit 1fe1a497902249c37f2212d98ed7d76d4dee3307
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 18:24:09 2023 -0600
+
+    [bimap] Minor vector pre-alloc
+
+ src/hb-bimap.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 7a7001dfcf2f9d4a9847acd4b423f6ebf3ee6276
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 17:48:00 2023 -0600
+
+    Typo
+
+ src/hb-subset-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b4305532a7746422e0b615eee6304119c1092fd8
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sun Jul 9 02:54:30 2023 +0300
+
+    8.0.0
+
+ NEWS                   | 42 ++++++++++++++++++++++++++++++++++++++++++
+ configure.ac           |  2 +-
+ docs/harfbuzz-docs.xml |  1 +
+ meson.build            |  2 +-
+ src/hb-common.h        |  2 +-
+ src/hb-ot-layout.cc    |  8 ++++----
+ src/hb-version.h       |  6 +++---
+ 7 files changed, 53 insertions(+), 10 deletions(-)
+
+commit 5b8ba51251b8d1603c792366b7062de836bb525c
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sun Jul 9 02:50:45 2023 +0300
+
+    [doc] Fix warning about missing hb-gobject section
+    
+    We don’t build hb-gobject docs anymore, lets not bother gtk-doc with it.
+
+ src/hb-gobject-structs.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 0ed946c379f1fe90c855f37dd31e5377beae4946
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sun Jul 9 03:01:47 2023 +0300
+
+    [wasm] Fix warning
+    
+    In file included from src/harfbuzz.cc:62:
+    src/hb-wasm-shape.cc:27:9: warning: 'HB_DEBUG_WASM' macro redefined [-Wmacro-redefined]
+            ^
+    src/hb-debug.hh:393:9: note: previous definition is here
+            ^
+    1 warning generated.
+
+ src/hb-wasm-shape.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit afe0910295f0b5bd245d68d5b142bcc9319b87ee
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sun Jul 9 02:45:52 2023 +0300
+
+    [font] Actually deprecate get_glyph_shape()
+    
+    We previously marked it as deprecated in the documentation but didn’t
+    actually deprecate it in code. Now the only known users have migrated to
+    draw_glyph(), lets deprecate o=it for good.
+
+ docs/harfbuzz-sections.txt |  6 +++---
+ src/hb-deprecated.h        | 46 ++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-font.cc             |  4 ++++
+ src/hb-font.h              | 45 +--------------------------------------------
+ src/main.cc                |  4 ++--
+ test/api/test-ot-face.c    |  2 +-
+ 6 files changed, 57 insertions(+), 50 deletions(-)
+
+commit c6a01441d9ce638634f193dbc9aadd8c432de55b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 16:32:15 2023 -0600
+
+    [sanitize] Always-inline OffsetTo::sanitize()
+    
+    8% speed up in sanitizing Gulzar.
+
+ src/hb-open-type.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit f60dbd906a4bf89354af1ed0616a61a5099d8c1a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 16:21:24 2023 -0600
+
+    Fix thinko
+    
+    Fixes https://oss-fuzz.com/testcase-detail/4787105656864768
+
+ src/hb-open-type.hh                                        |   8 ++++----
+ ...uzz-testcase-minimized-hb-shape-fuzzer-4787105656864768 | Bin 0 -> 44 bytes
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit d84c5f29b71aa7b1ff2d09cf4dc2cf3fccc5659e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 15:22:51 2023 -0600
+
+    Revert "[gsubgpos] Make (Chain)Context funcs templatized"
+    
+    This reverts commit 03ac08d267eb7ad2f1ac039115fc0030ea475fae.
+
+ src/OT/Layout/GSUB/Ligature.hh                     | 13 +--
+ .../Layout/GSUB/ReverseChainSingleSubstFormat1.hh  |  8 +-
+ src/hb-ot-layout-gsubgpos.hh                       | 93 +++++++++-------------
+ 3 files changed, 47 insertions(+), 67 deletions(-)
+
+commit e73223b9e59a4f0af54880d3e26f8db55688f291
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 15:22:18 2023 -0600
+
+    [gsubgpos] Make (Chain)Context funcs templatized
+    
+    Unfortunately they still won't be inlined because the matcher_t
+    needs function pointers. So, no speed up.  Going to revert.
+
+ src/OT/Layout/GSUB/Ligature.hh                     | 13 ++-
+ .../Layout/GSUB/ReverseChainSingleSubstFormat1.hh  |  8 +-
+ src/hb-ot-layout-gsubgpos.hh                       | 93 +++++++++++++---------
+ 3 files changed, 67 insertions(+), 47 deletions(-)
+
+commit 3e3820badd9d72d908334a862d546bcb64ccfd30
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 14:36:23 2023 -0600
+
+    Simplify a few bool returns
+    
+    Unnecessary. Cast to bool does the job.
+
+ src/hb-ot-layout.hh | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+commit 1c8d54deeff506d66e91ff84a8bd43698ec91387
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 14:28:07 2023 -0600
+
+    [shape] Another always-inline
+
+ src/hb-ot-layout-gsubgpos.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit df45067fbb14a62c2048bf1b01349bf17f90ee6d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 14:22:59 2023 -0600
+
+    [shape] More always-inline
+
+ src/hb-ot-layout-gsubgpos.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit c3a28be5094f23b0806f94c069ff3d888f065d48
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 14:20:45 2023 -0600
+
+    [shape] One more always-inline
+
+ src/hb-ot-layout-gsubgpos.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 728812348185194de87e5558a5770351d12447bf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 14:14:27 2023 -0600
+
+    Allow overriding HB_ALWAYS_INLINE
+
+ src/hb.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 9fea19ebff62a4e9aa344e271d58acf416214d2a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 13:56:24 2023 -0600
+
+    [shape] Another always-inline
+
+ src/hb-ot-layout-gsubgpos.hh | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+commit 5b45c56c9ecae7a5d67d336219aab4d971573bab
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 13:47:41 2023 -0600
+
+    [shape] Always-inline more
+    
+    Another 10% speedup in BM_Shape Gulzar-Regular.
+
+ src/hb-ot-layout-gsubgpos.hh | 47 ++++++++++++++++++++++++++++++++------------
+ 1 file changed, 34 insertions(+), 13 deletions(-)
+
+commit bb9692e8a3b1a17481dae46c57e1727361f96e26
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 13:45:48 2023 -0600
+
+    [shape] Always-inline match_input
+    
+    10% speedup in BM_Shape Gulzar-Regular.
+
+ src/hb-ot-layout-gsubgpos.hh | 19 +++++++++++--------
+ 1 file changed, 11 insertions(+), 8 deletions(-)
+
+commit 6c451054fbbee75ffc4a68e423786bf19648e315
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 12:55:34 2023 -0600
+
+    [sanitize] Sprinkle a few unlikely's
+
+ src/hb-ot-layout-gsubgpos.hh | 28 ++++++++++++++--------------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+commit 4ecc62c28d392a00d8f613da565fae335930a88d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 12:53:23 2023 -0600
+
+    [sanitize] Simplify ChainRule::sanitize again
+    
+    check_struct does the same now.
+
+ src/hb-ot-layout-gsubgpos.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 253ec08b3db433f07175f21f90555657a9ce55f3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 12:48:05 2023 -0600
+
+    [sanitize] Speed up check_struct on x64
+
+ src/hb-sanitize.hh | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit fb02f4a8975655b405ac4bc3f9982383f33ea6dc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 8 12:29:18 2023 -0600
+
+    [sanitize] Micro-optimize ChainRule::sanitize
+
+ src/hb-ot-layout-gsubgpos.hh |  7 ++++---
+ src/hb-sanitize.hh           | 18 ++++++++++++++++++
+ 2 files changed, 22 insertions(+), 3 deletions(-)
+
+commit c650858c639764717f3d7276ad67bd5bf55aaedc
+Author: Khaled Hosny <khaled@libreoffice.org>
+Date:   Sat Jul 8 13:57:05 2023 +0300
+
+    [graphite] Fix cluster advance width
+    
+    Based on https://github.com/harfbuzz/harfbuzz/issues/4309#issuecomment-1624730406
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4309
+
+ src/hb-graphite2.cc        | 5 +++--
+ src/wasm/graphite/shape.cc | 5 +++--
+ 2 files changed, 6 insertions(+), 4 deletions(-)
+
+commit 73ee9c346f3acccbe14a4caf258b636de7c459be
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 7 22:47:20 2023 -0600
+
+    Revert "[sanitize] Only check trailing edge of ranges"
+    
+    This reverts commit e4856cf8098b9741a910e7f7979096cf11d8fead.
+    
+    This is wrong on at least 32-bit systems. Might add a condition
+    version later.
+
+ src/hb-sanitize.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 0b879afb5abda0af4624dd2cedf609acb4d17c87
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 7 22:35:43 2023 -0600
+
+    [sanitize] Inline Coverage::sanitize
+
+ src/OT/Layout/Common/Coverage.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 92448910a76e399afce6375923dbcf36bc3a541e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 7 22:16:24 2023 -0600
+
+    [sanitize] Minor inline a few more short functions
+
+ src/hb-open-type.hh | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit d84504206c420250bfe80bee25f6a59a7177c9eb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 7 21:56:17 2023 -0600
+
+    [sanitize] Optimize away an overflow check when not needed
+    
+    When the length argument is 16bit...
+
+ src/hb-open-type.hh |  8 ++++----
+ src/hb-sanitize.hh  | 14 ++++++++++++++
+ 2 files changed, 18 insertions(+), 4 deletions(-)
+
+commit e4856cf8098b9741a910e7f7979096cf11d8fead
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 7 21:21:33 2023 -0600
+
+    [sanitize] Only check trailing edge of ranges
+    
+    Assumptions...
+    
+    Speeds up Gulzar load_face_and_shape benchmark by 7%.
+
+ src/hb-sanitize.hh | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+commit 6a683ea6ebc4d187d3f9ccf1a5c087b30cd82f27
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 7 21:02:15 2023 -0600
+
+    [sanitize] Enlighten check_range() some more
+    
+    No need to check for len=0 arrays. They must still be in range.
+
+ src/hb-ot-var-fvar-table.hh | 3 ++-
+ src/hb-sanitize.hh          | 7 +++----
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+commit c24ea1036b45ea48ecc3081698ec04be646b74d0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 7 20:43:20 2023 -0600
+
+    [sanitize] Minor tweak to len=0 case which is handled otherwise anyway
+
+ src/hb-sanitize.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 403bc7caa41474644b4a7c14046c70ec8013c385
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 7 20:17:32 2023 -0600
+
+    [sanitize] Simplify Rule::sanitize()
+
+ src/hb-ot-layout-gsubgpos.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 385896ff665a167ffcc633ebf84280549d9f5b2e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 7 19:56:19 2023 -0600
+
+    [sanitize] Speed up ChainRule::sanitize()
+    
+    10% speedup in sanitizing Gulzar-Regular.
+
+ src/hb-ot-layout-gsubgpos.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 2006d3211f300b1f602d9701f4b26634fe6f21b7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 7 17:07:11 2023 -0600
+
+    [sanitize] Add "fastpath" for ArrayOfOffset16To<> objects with max size
+    
+    Unfortunately this doesn't speed up NotoNastaliq or Gulzar as I was
+    hoping for. Their GSUB tables are not large enough for this to kick
+    in...
+
+ src/OT/Layout/GSUB/Ligature.hh |  1 +
+ src/hb-machinery.hh            |  4 ++++
+ src/hb-null.hh                 |  9 +++++++++
+ src/hb-open-type.hh            | 25 +++++++++++++++++++++++++
+ src/hb-ot-layout-gsubgpos.hh   |  2 ++
+ 5 files changed, 41 insertions(+)
+
+commit 7a85663c2bd9a0e553bf6c02ca92f7c645bed915
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 7 19:21:18 2023 -0600
+
+    Revert "[sanitize] Add "fastpath" for ArrayOfOffset16To<> objects with max size"
+    
+    This reverts commit 10f8556c73f3cf231c6b5a900a6a1903f9516f90.
+    
+    This was, unfortunately, wrong :(.
+
+ src/OT/Layout/GSUB/Ligature.hh |  5 +----
+ src/hb-machinery.hh            |  4 ----
+ src/hb-null.hh                 |  9 ---------
+ src/hb-open-type.hh            | 25 -------------------------
+ src/hb-ot-layout-gsubgpos.hh   | 12 ++----------
+ 5 files changed, 3 insertions(+), 52 deletions(-)
+
+commit f2a3680fab317a67416c267ea8fc51cc7206b3f0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 7 19:21:03 2023 -0600
+
+    Revert "[gsubgpos] Limit (Chain)ContextFormat3 for consistency"
+    
+    This reverts commit 90b48917dadbef51bc5e90904d0f81e81199b9e2.
+
+ src/hb-ot-layout-gsubgpos.hh | 32 +++++++++++++-------------------
+ 1 file changed, 13 insertions(+), 19 deletions(-)
+
+commit 90b48917dadbef51bc5e90904d0f81e81199b9e2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 7 18:50:01 2023 -0600
+
+    [gsubgpos] Limit (Chain)ContextFormat3 for consistency
+
+ src/hb-ot-layout-gsubgpos.hh | 32 +++++++++++++++++++-------------
+ 1 file changed, 19 insertions(+), 13 deletions(-)
+
+commit 3b02f694e80dd3c1b0517145ef7b075c9c9acb05
+Merge: 10f8556c7 68b789145
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 7 18:39:28 2023 -0600
+
+    [sanitize/GSUBGPOS] Limit max-size of a few offset arrays
+    
+    This significantly speeds up Gulzar-Regular sanitize, by 40%.
+
+commit 10f8556c73f3cf231c6b5a900a6a1903f9516f90
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 7 17:07:11 2023 -0600
+
+    [sanitize] Add "fastpath" for ArrayOfOffset16To<> objects with max size
+
+ src/OT/Layout/GSUB/Ligature.hh |  5 ++++-
+ src/hb-machinery.hh            |  4 ++++
+ src/hb-null.hh                 |  9 +++++++++
+ src/hb-open-type.hh            | 25 +++++++++++++++++++++++++
+ src/hb-ot-layout-gsubgpos.hh   | 12 ++++++++++--
+ 5 files changed, 52 insertions(+), 3 deletions(-)
+
+commit 68b78914595347008eb344859699dc62257a7a67
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 7 17:07:11 2023 -0600
+
+    [sanitize] Add "fastpath" for ArrayOfOffset16To<> objects with max size
+    
+    Unfortunately this doesn't speed up NotoNastaliq or Gulzar as I was
+    hoping for. Their GSUB tables are not large enough for this to kick
+    in...
+
+ src/OT/Layout/GSUB/Ligature.hh |  1 +
+ src/hb-machinery.hh            |  4 ++++
+ src/hb-null.hh                 |  9 +++++++++
+ src/hb-open-type.hh            | 25 +++++++++++++++++++++++++
+ src/hb-ot-layout-gsubgpos.hh   |  2 ++
+ 5 files changed, 41 insertions(+)
+
+commit 90752cd5b76d1768afc10e9bcab4235d97e7686f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 7 15:47:28 2023 -0600
+
+    [type] Add HeadlessArray16Of
+
+ src/OT/Layout/GSUB/Ligature.hh | 2 +-
+ src/hb-open-type.hh            | 3 ++-
+ src/hb-ot-layout-gsubgpos.hh   | 2 +-
+ 3 files changed, 4 insertions(+), 3 deletions(-)
+
+commit 59abcda269e7148131d00d17218f5718f217bf13
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 7 14:27:18 2023 -0600
+
+    [sanitize] Add an ALWAYS_INLINE
+    
+    Looks like it was always inlined anyway.
+
+ src/hb-sanitize.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 45a17212304de8787b509cc9375bb92571fca9f5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 6 16:06:50 2023 -0600
+
+    [ot-font] Prefer CFF2 over CFF1
+
+ src/hb-ot-font.cc | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 43d0aff672981f2efca6b7398e81f020676ad442
+Author: أحمد المحمودي <96682+aelmahmoudy@users.noreply.github.com>
+Date:   Tue Jul 4 09:22:53 2023 +0300
+
+    [introspection] Pass both libharfbuzz_gobject & libharfbuzz as positional parameters
+    
+    Fixes #4304
+
+ src/meson.build | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 25297408de73f8bf31ebecd241f959455ed00e95
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 3 10:34:26 2023 -0600
+
+    [COLR] Fix PaintComposite sanitize timeout
+    
+    Was timing out after recent sanitize() change.
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5692635449524224
+
+ src/OT/Color/COLR/COLR.hh                                 |   1 +
+ ...uzz-testcase-minimized-hb-draw-fuzzer-5692635449524224 | Bin 0 -> 185 bytes
+ 2 files changed, 1 insertion(+)
+
+commit a8c655e6510c33de2241b854c1a37ffbe2eee9ff
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Jul 3 10:17:36 2023 +0000
+
+    Bump actions/checkout from 3.5.1 to 3.5.3
+    
+    Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.1 to 3.5.3.
+    - [Release notes](https://github.com/actions/checkout/releases)
+    - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
+    - [Commits](https://github.com/actions/checkout/compare/v3.5.1...c85c95e3d7251135ab7dc9ce3241c5835cc595a9)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: actions/checkout
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/scorecard.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit de2c10732df151156ac55afdf648f3fd296dfa50
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 2 16:44:48 2023 -0600
+
+    [ot-map] Speed up for default shaper
+    
+    Sort late, the reduced number of features.
+
+ src/hb-ot-map.cc   | 6 ++++--
+ src/hb-ot-map.hh   | 8 ++++++++
+ src/hb-ot-shape.cc | 7 +++++++
+ 3 files changed, 19 insertions(+), 2 deletions(-)
+
+commit 8156c5a6856a3c9c0cc98714dc047fe4a703d603
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 2 16:35:32 2023 -0600
+
+    [ot-map] Minor micro-optimize
+
+ src/hb-ot-map.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 5ac9eaa035402fe0369baadea3c945c58a4534ed
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 2 16:18:08 2023 -0600
+
+    [sanitize] Minor micro-optimize
+
+ src/hb-sanitize.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e8948d634e1835f379053d9b924b834137967b86
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 2 15:35:18 2023 -0600
+
+    [set-digest] Micro-optimize more
+
+ src/hb-set-digest.hh | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+commit cb73ba710480f698828b8d6526605849d6899bad
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 2 15:27:26 2023 -0600
+
+    [set-digest] Fixup for previous commit
+
+ src/hb-set-digest.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 918ad8929403d2106fdca1370a1c3e9929e301f9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 2 14:54:24 2023 -0600
+
+    [set-digest] Early terminate add_range() if we're full
+
+ src/hb-set-digest.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit bb33675e60be3884a3d6adf6417c353f0202e70f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 2 14:11:40 2023 -0600
+
+    [sanitize] Micro-optimize check_range()
+
+ src/hb-sanitize.hh | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+commit d1c82a1cc68667ff8ca6c1fe2b4fa277504c0a5c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 2 13:38:22 2023 -0600
+
+    [sanitize] Speed up check_struct()
+    
+    Don't account for length here. Should not be a problem.
+    Fingers crossed fuzzers.
+    
+    18% speed up in load_face_and_shape Gulzar-Regular.
+
+ src/hb-sanitize.hh | 21 +++++++++++++++++++--
+ 1 file changed, 19 insertions(+), 2 deletions(-)
+
+commit ec943866229b44b26b79cd271a1e3f874fe16e7c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 2 13:29:53 2023 -0600
+
+    [OffsetTo] Micro-optimize away a check
+
+ src/hb-open-type.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit eae8278896e1dcd6d8eecb9401785acdf76f81a6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 2 13:07:26 2023 -0600
+
+    [GPOS] Micro-optimize lazy_some_gpos check
+    
+    Speeds up 11% in:
+    BM_Font/load_face_and_shape/Roboto-Regular.ttf/hb
+
+ src/OT/Layout/GPOS/PairPosFormat2.hh | 5 +++--
+ src/OT/Layout/GPOS/PairSet.hh        | 5 +++--
+ src/OT/Layout/GPOS/ValueFormat.hh    | 6 +++---
+ 3 files changed, 9 insertions(+), 7 deletions(-)
+
+commit 46e54a23907eb5f46977ceac22abb4d43fcd7061
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 2 13:03:16 2023 -0600
+
+    [GPOS] Remove extra check
+
+ src/OT/Layout/GPOS/ValueFormat.hh | 3 ---
+ 1 file changed, 3 deletions(-)
+
+commit 13438da16e5967b2600cb347ad5a179812526ba2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 2 12:56:13 2023 -0600
+
+    [benchmark-font] Minor move a variable
+
+ perf/benchmark-font.cc | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 7f5380fe949ba64fab19d86f670e2215249cbb96
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 2 12:19:22 2023 -0600
+
+    [Composite] Don't apply transformation if phantom_only
+
+ src/OT/glyf/Glyph.hh | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+commit 0cf759b0d4c8c1252347f2d92dd10202672d4191
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 2 12:15:43 2023 -0600
+
+    [Glyph] Don't shift anchored Composite if phantom_only
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5114131137822720
+
+ src/OT/glyf/Glyph.hh                                     |   2 +-
+ ...z-testcase-minimized-hb-shape-fuzzer-5114131137822720 | Bin 0 -> 5119 bytes
+ 2 files changed, 1 insertion(+), 1 deletion(-)
+
+commit 645bde473818a14368ea9f95261037160c574d05
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 2 12:07:22 2023 -0600
+
+    [Glyph] Pass phantom-only to gvar only for SIMPLE glyphs
+    
+    For Composites we need to get the translation offset deltas.
+
+ src/OT/glyf/Glyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e92eefaabbed7aa04fe98214ae43b061d1497735
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 2 11:35:51 2023 -0600
+
+    [gvar] Cache two values in shared_tuple_active_idx
+    
+    Speeds up varc-hangul.ttf draw_glyph by 10%.
+
+ src/hb-ot-var-common.hh     | 17 ++++++++++++-----
+ src/hb-ot-var-gvar-table.hh | 15 +++++++++------
+ 2 files changed, 21 insertions(+), 11 deletions(-)
+
+commit 7d72fdd5bf423dcbdf19b5bae25494e6b3c59cd0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 2 09:55:37 2023 -0600
+
+    [benchmark-font] Do some work in draw_glyph callbacks
+    
+    For no good reason other than matching what I'm adding to
+    skrifa benchmark.  Doesn't seem to affect benchmarks whatsoever.
+
+ perf/benchmark-font.cc | 33 +++++++++++++++++++++++++++------
+ 1 file changed, 27 insertions(+), 6 deletions(-)
+
+commit 47b5ee6789ca9125cc4299da1f3a3c05300dff78
+Merge: 7a3566825 2d6091fc4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 1 14:48:39 2023 -0400
+
+    Merge pull request #4306 from harfbuzz/gpos-lazy-device
+    
+    GPOS lazy Device
+
+commit 2d6091fc42c81ba68fe6710de42d313cfda7a309
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 30 11:48:56 2023 -0600
+
+    [GPOS] Make AnchorMatrix sanitize lazy again
+    
+    Was reverted in the previous commit, because it was incomplete.
+
+ src/OT/Layout/GPOS/AnchorFormat3.hh |  3 ---
+ src/OT/Layout/GPOS/AnchorMatrix.hh  | 14 ++++++++++----
+ src/OT/Layout/GPOS/MarkArray.hh     |  2 +-
+ src/OT/Layout/GPOS/ValueFormat.hh   |  6 +++---
+ src/hb-ot-layout-gsubgpos.hh        |  2 +-
+ src/hb-sanitize.hh                  |  4 ++--
+ 6 files changed, 17 insertions(+), 14 deletions(-)
+
+commit 0887382cdf64f9c590eb9c086f7f5622c482e32c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 30 11:39:46 2023 -0600
+
+    [GPOS] Fix sanitize
+
+ src/OT/Layout/GPOS/AnchorMatrix.hh | 3 ---
+ 1 file changed, 3 deletions(-)
+
+commit 83eb744e09bb8ff7a9c78c79569100f560f129fb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 30 11:33:39 2023 -0600
+
+    [sanizie] Inline check_range if not OPTIMIZE_SIZE
+    
+    BM_Font/load_face_and_shape/NotoNastaliqUrdu-Regular.ttf/hb                     -0.1046         -0.1051           194           173           193           172
+    BM_Font/load_face_and_shape/NotoSerifMyanmar-Regular.otf/hb                     -0.2401         -0.2412            36            27            36            27
+
+ src/hb-sanitize.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 690af7aa69b05db6a925bcdaeac4ea0d7efba5da
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 30 10:36:01 2023 -0600
+
+    [GPOS] Sanitize Device tables lazily
+    
+    This speeds up face loading for variable fonts by 80%!
+    
+    Comparing before to after
+    Benchmark                                                                          Time             CPU      Time Old      Time New       CPU Old       CPU New
+    ---------------------------------------------------------------------------------------------------------------------------------------------------------------
+    BM_Font/load_face_and_shape/Roboto-Regular.ttf/hb                               -0.0368         -0.0366            20            20            20            19
+    BM_Font/load_face_and_shape/RobotoFlex-Variable.ttf/hb                          -0.7149         -0.7162            77            22            77            22
+    BM_Font/load_face_and_shape/RobotoFlex-Variable.ttf/var/hb                      -0.7241         -0.7255            80            22            79            22
+    BM_Font/load_face_and_shape/SourceSansPro-Regular.otf/hb                        -0.1441         -0.1445            28            24            28            24
+    BM_Font/load_face_and_shape/AdobeVFPrototype.otf/hb                             -0.7893         -0.7910            66            14            66            14
+    BM_Font/load_face_and_shape/AdobeVFPrototype.otf/var/hb                         -0.7865         -0.7882            67            14            66            14
+    BM_Font/load_face_and_shape/SourceSerifVariable-Roman.ttf/hb                    -0.8895         -0.8900           227            25           226            25
+    BM_Font/load_face_and_shape/SourceSerifVariable-Roman.ttf/var/hb                -0.8895         -0.8900           226            25           225            25
+    BM_Font/load_face_and_shape/Comfortaa-Regular-new.ttf/hb                        -0.5512         -0.5531            42            19            42            19
+    BM_Font/load_face_and_shape/NotoNastaliqUrdu-Regular.ttf/hb                     -0.1511         -0.1510           227           192           225           191
+    BM_Font/load_face_and_shape/NotoSerifMyanmar-Regular.otf/hb                     -0.1494         -0.1498            41            35            40            34
+    OVERALL_GEOMEAN                                                                 -0.6443         -0.6456             0             0             0             0
+
+ src/OT/Layout/GPOS/AnchorFormat3.hh    | 11 +++++--
+ src/OT/Layout/GPOS/AnchorMatrix.hh     |  4 +++
+ src/OT/Layout/GPOS/SinglePosFormat1.hh |  3 +-
+ src/OT/Layout/GPOS/SinglePosFormat2.hh |  3 +-
+ src/OT/Layout/GPOS/ValueFormat.hh      | 52 +++++++++++++++++++++++++---------
+ src/hb-kern.hh                         |  2 +-
+ src/hb-ot-layout-gsubgpos.hh           | 12 ++++++--
+ src/hb-ot-layout.cc                    |  5 ++--
+ src/hb-ot-shaper-arabic-fallback.hh    |  2 +-
+ src/hb-sanitize.hh                     | 18 +++++++++++-
+ 10 files changed, 87 insertions(+), 25 deletions(-)
+
+commit 7a35668258f8e93c867cf560ca0999d8952d1c93
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 30 10:50:25 2023 -0600
+
+    Minor variable fix
+
+ src/hb-machinery.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d338506ccf892b0ce489314d2d2f94c6b875368a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 30 10:13:05 2023 -0600
+
+    [GPOS] Reuse sanitize_values_stride_unsafe in another function
+
+ src/OT/Layout/GPOS/ValueFormat.hh | 14 +++-----------
+ 1 file changed, 3 insertions(+), 11 deletions(-)
+
+commit 0fceaef0f7ec123e931fc31f9d71ba87fa60b079
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 30 08:50:49 2023 -0600
+
+    [benchmark-subset] Report in microseconds, not milli
+    
+    We're in that range now. :)
+
+ perf/benchmark-subset.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 547dc1a40ef6d83eb426afd1470bddf2b11bdfab
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 30 08:48:43 2023 -0600
+
+    [benchmark-font] Add load_face_and_shape benchmark
+    
+    To measure face-loading performance
+
+ perf/benchmark-font.cc | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+commit fcf70af1349f2eeb9f58f67d2cc7d8e2c3ebf012
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 30 08:43:10 2023 -0600
+
+    [perf] Fix break
+
+ perf/benchmark-font.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 794fac327cf13b4b4d8a66281c15df6aac2d15c6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 20:55:52 2023 -0600
+
+    [glyf] Minor another range for loop
+
+ src/OT/glyf/glyf.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 0ae167662657c084ecc26db27830b51c469240f2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 20:38:42 2023 -0600
+
+    [CompositeGlyph] Minor use a range for loop
+
+ src/OT/glyf/CompositeGlyph.hh | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+commit 05c01ad5d34cf6ca4f350233eccbec129f860231
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 16:49:20 2023 -0600
+
+    [SimpleGlyph] Minor use a range for loop
+
+ src/OT/glyf/SimpleGlyph.hh | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+commit 4123e0c75762ed1e6fa69e2926a4d4cee5e6747c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 16:27:35 2023 -0600
+
+    [path-builder] Speed up mid-point calculation
+
+ src/OT/glyf/path-builder.hh | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+commit 73376b24cfe7cfe27b7b4b9abbe46ff441189b2a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 16:14:45 2023 -0600
+
+    [subset/cff1] More error handling
+
+ src/hb-subset-cff1.cc | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit cc44b3bce0a7be5536df7df910b5bc73a5e4a741
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 16:12:10 2023 -0600
+
+    [subset/cff1] Handle an error condition
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5191907895279616
+
+ src/hb-subset-cff1.cc                                    |  11 +++++++----
+ ...-testcase-minimized-hb-subset-fuzzer-5191907895279616 | Bin 0 -> 2025 bytes
+ 2 files changed, 7 insertions(+), 4 deletions(-)
+
+commit fc38c01ab06ac376b42b8d70c9453da45afabcc5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 15:29:15 2023 -0600
+
+    Minor inline a function
+
+ src/hb-ot-var-gvar-table.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit a520177e523eab8bf9a407aab46d8308ac12439a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 14:56:05 2023 -0600
+
+    [gvar] Remove unnecessary initialization
+
+ src/hb-ot-var-gvar-table.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit ca44c38c5298e9ffc9b0b843c3fd5df63c9747a7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 14:41:21 2023 -0600
+
+    Add HB_ALWAYS_INLINE
+    
+    With MSVC implementation as well.
+
+ src/OT/glyf/glyf.hh         |  2 +-
+ src/OT/glyf/path-builder.hh |  2 +-
+ src/hb-draw.hh              | 20 ++++++++++----------
+ src/hb.hh                   |  6 ++++++
+ 4 files changed, 18 insertions(+), 12 deletions(-)
+
+commit 0a00dc0c7197b61b7662d40d12e9432f27dbd6ec
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 14:17:47 2023 -0600
+
+    [draw] Add a few unlikely's
+
+ src/hb-draw.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit 2d9c3da06ad63066a748be486c33bed81f418868
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 13:31:11 2023 -0600
+
+    [draw] Inline more functions
+
+ src/hb-draw.hh | 15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+commit 17f29c81110bed6b9be684b6c0cfdacb01414bb1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 13:27:09 2023 -0600
+
+    [benchmark_font/draw_glyphs] Implement quadratic_to
+    
+    Not interested in the fallback implementation here.
+
+ perf/benchmark-font.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit d26b3adebee059cbcc72850f4ad31ecf3f2b913f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 13:25:52 2023 -0600
+
+    [draw-session] Inline small functions
+
+ src/hb-draw.hh | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit 7aba1e6dd2f5be40e818838ef23d0a0d605a8485
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 12:44:34 2023 -0600
+
+    [cache] Minor use a range for loop
+
+ src/hb-cache.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit afae537c3ca4d2ddae2b8bee400966a08bf74e6e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 12:42:44 2023 -0600
+
+    [cache] Minor remove .init()
+    
+    Use constructor.
+
+ src/hb-cache.hh   | 4 +---
+ src/hb-ft.cc      | 2 +-
+ src/hb-ot-font.cc | 6 +++---
+ 3 files changed, 5 insertions(+), 7 deletions(-)
+
+commit c49ca371151ef3afc3a4ecf0b8918cdd8ac16541
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 12:38:45 2023 -0600
+
+    [Glyph] Minor micro-optimize away a function call
+    
+    For when coords are not set.
+
+ src/OT/glyf/Glyph.hh        | 9 +++++----
+ src/hb-ot-var-gvar-table.hh | 2 --
+ 2 files changed, 5 insertions(+), 6 deletions(-)
+
+commit 5fb7b02ac1212e9dfde920738285a2a58d19f9e1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 12:28:43 2023 -0600
+
+    [CompositeGlyph] Minor use range loop
+
+ src/OT/glyf/CompositeGlyph.hh | 19 ++++++++-----------
+ 1 file changed, 8 insertions(+), 11 deletions(-)
+
+commit 20b32b049bad64d802b33979372c8cdc5a0c4cb4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 12:08:11 2023 -0600
+
+    [SimpleGlyph] Micro-optimize phantom_only
+
+ src/OT/glyf/SimpleGlyph.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit d1660eaf32777c50400326d99211926e82ec2f35
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 11:59:03 2023 -0600
+
+    [subset/cff] Minor use HB_OPTIMIZE_SIZE_VAL
+
+ src/hb-ot-cff-common.hh | 96 +++++++++++++++++++++++++------------------------
+ 1 file changed, 49 insertions(+), 47 deletions(-)
+
+commit 04809ede8e5d9943be8a294acecdffe2f0be492f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 11:58:53 2023 -0600
+
+    [CompositeGlyph] Micro-optimize translate()
+
+ src/OT/glyf/CompositeGlyph.hh | 24 +++++++++++++++++++++---
+ 1 file changed, 21 insertions(+), 3 deletions(-)
+
+commit 229db9735e3832ca81a751ec318ba396aeb89d85
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 11:54:10 2023 -0600
+
+    [CompositeGlyph] Minor use vector::push()
+
+ src/OT/glyf/CompositeGlyph.hh | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+commit 75101802a169b48a69a82f64e49169d810ded741
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 10:54:49 2023 -0600
+
+    [CompositeGlyph] Micro-optimize
+
+ src/OT/glyf/CompositeGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e9d74d6bb352a2ac01554f8bdea65c3acc2879b5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 10:53:52 2023 -0600
+
+    [SimpleGlyph] Minor add an unlikely to error condition
+
+ src/OT/glyf/SimpleGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 6abca413aeb7be1342180aa945f54fd45cdea12f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 10:39:49 2023 -0600
+
+    [path-builder] Micro-optimize
+    
+    No need to initialize these when has_data=false.
+
+ src/OT/glyf/path-builder.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 5703c1c4ea5cc47120cba8f8b0f4fc1178f6efef
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 29 10:35:23 2023 -0600
+
+    [path-builder] Add a couple of unlikely's
+
+ src/OT/glyf/path-builder.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit f5eead04e63e6092fba494471b18016cabe50a15
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 28 15:07:15 2023 -0600
+
+    [glyf/gvar] Optimize getting variable phantom points
+    
+    Used when there's no HVAR table and get_h_advance().
+    
+    I see some 10% speedup with a SourceSerifVariable-Roman with
+    the HVAR table removed.
+
+ src/OT/glyf/Glyph.hh        |  3 ++-
+ src/hb-ot-var-gvar-table.hh | 30 +++++++++++++++++-------------
+ 2 files changed, 19 insertions(+), 14 deletions(-)
+
+commit e42d6df55e034b92979fb41db852c648114c18c0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 28 14:25:11 2023 -0600
+
+    [glyf] Minor refactor a couple of lines and micro-optimize
+
+ src/OT/glyf/glyf.hh | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+commit c31471d10e14ca66a1b668905fac2ab40941ea41
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 28 13:51:54 2023 -0600
+
+    [glyf] Micro-optimize
+
+ src/OT/glyf/glyf.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 83d75d5e9b32866e62e21ca155bb176b6d3fa81e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 28 13:35:24 2023 -0600
+
+    [glyf] always_inline consume_point
+    
+    7% speedup in:
+    BM_Font/draw_glyph/Roboto-Regular.ttf/hb
+
+ src/OT/glyf/path-builder.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 8795ccedd61ea26793d0912b5ee02fe9ae45c9aa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 28 13:29:29 2023 -0600
+
+    Revert "[SimpleGlyph] Avoid branches in read_points"
+    
+    This reverts commit ba062c713e469f91f57f3c85990f721789ec7c2a.
+
+ src/OT/glyf/SimpleGlyph.hh | 21 ++++-----------------
+ 1 file changed, 4 insertions(+), 17 deletions(-)
+
+commit ba062c713e469f91f57f3c85990f721789ec7c2a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 28 13:24:37 2023 -0600
+
+    [SimpleGlyph] Avoid branches in read_points
+    
+    Calculate total bytes in read_flags and bounds-check once.
+    
+    This slows things down apparently, so going to revert.
+
+ src/OT/glyf/SimpleGlyph.hh | 21 +++++++++++++++++----
+ 1 file changed, 17 insertions(+), 4 deletions(-)
+
+commit 62f5ed461ea5fa4fd63631ddeb505ea16e2becb4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 28 12:02:52 2023 -0600
+
+    [subset/cff] Fix an infinite loop
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5419002026131456
+
+ src/hb-ot-cff-common.hh                                  |   6 +++---
+ src/hb-subset-cff-common.cc                              |   3 ++-
+ ...-testcase-minimized-hb-subset-fuzzer-5419002026131456 | Bin 0 -> 1718 bytes
+ 3 files changed, 5 insertions(+), 4 deletions(-)
+
+commit 87b573615f5f521650a325d8eb29afc736d1c8cc
+Author: Chun-wei Fan <fanchunwei@src.gnome.org>
+Date:   Wed Jun 28 15:38:40 2023 +0800
+
+    README.python.md: Add some notes for Windows
+    
+    Note that the DLLs for HarfBuzz and its deps must be found %PATH% on Windows so
+    that pygobject is able to import and use HarfBuzz in Python scripts.
+    
+    Also note that for Visual Studio builds, it is recommended that Visual Studio
+    2019 or later is used for the build, possibly in regards with how the
+    preprocessor handles C++ code when running g-ir-scanner.
+
+ README.python.md | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit 10b9ca54e17379584bc7583b018268697f925dfd
+Author: أحمد المحمودي (Ahmed El-Mahmoudy) <aelmahmoudy@users.sourceforge.net>
+Date:   Wed Jun 28 07:46:33 2023 +0200
+
+    Fix typo: subtitution -> substitution
+
+ src/OT/Layout/GSUB/Sequence.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 73a82af1f4abe15f3e96074b5bf1a636c890c85f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 27 17:05:22 2023 -0600
+
+    [subset/cff] Remove stale wrong code
+    
+    With my recent rewrite of serialize_header, this seems to
+    work now.
+
+ src/hb-ot-cff-common.hh | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+commit 158eba66b32c4e61a95d33fdcf9107de84073475
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 27 16:22:54 2023 -0600
+
+    [subset/cff] Fix compiler error
+    
+    About variable with internal linkage with no definition.
+
+ src/hb-ot-cff-common.hh | 19 ++++++++++---------
+ 1 file changed, 10 insertions(+), 9 deletions(-)
+
+commit b04721993f0501519af4835d074fdfa3700935d1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 27 16:07:54 2023 -0600
+
+    [subset/cff1] Micro-optimize code
+    
+    Let compiler see whether optional argument is present.
+
+ src/hb-ot-cff-common.hh | 8 ++++++--
+ src/hb-subset-cff1.cc   | 2 +-
+ src/hb-subset-cff2.cc   | 2 +-
+ 3 files changed, 8 insertions(+), 4 deletions(-)
+
+commit 1cabb65b0a8cb4db16b7616f48f245f3ace08bd3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 27 16:01:17 2023 -0600
+
+    [subset/cff] Micro-optimize CFFIndex::serialize_header
+    
+    Unfortunately hb_array_t::begin/end are faster than its _begin/_end.
+    As such, a range loop on array itself is faster than range loop on
+    pipeline starting with array. Rework code to loop on the array always.
+
+ src/hb-ot-cff-common.hh | 69 ++++++++++++++++++++++++++++++-------------------
+ src/hb-subset-cff1.cc   |  2 +-
+ 2 files changed, 43 insertions(+), 28 deletions(-)
+
+commit dfaf9cd54b06e5d4d2765abae2e09183c7765815
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 27 14:56:32 2023 -0600
+
+    [subset/cff1] Minor optimize
+
+ src/hb-subset-cff1.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 41f85d0179dd60ee49e3064213bd4bbf5edaec96
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 27 12:50:04 2023 -0600
+
+    [benchmark-font] Add RobotoFlex
+    
+    We didn't have a variable TTF before!
+
+ perf/benchmark-font.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 585c84268dedc94cd41edf932b86b2a28c014032
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 27 11:28:38 2023 -0600
+
+    [subset/cff1] Minor micro-optimize
+
+ src/hb-subset-cff1.cc | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+commit 00904503d865c56495a49a5cf4b8c313f959dd9c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 27 08:18:18 2023 -0600
+
+    [config] Graduate avar2 from boring-expansion
+
+ src/hb-config.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 3edd6cdcd55dabec87ed8da9ffed82b1c41e0720
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 27 06:56:00 2023 -0600
+
+    [vector] Minor micro-optimize shrink_vector
+    
+    The compiler seems to understand this pattern better.
+
+ src/hb-vector.hh | 17 +++++++++--------
+ 1 file changed, 9 insertions(+), 8 deletions(-)
+
+commit aed215639a89a7241fa5d647483326c0cad6f535
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 22:51:50 2023 -0600
+
+    [subset/cff1] Micro-optimize
+
+ src/hb-ot-cff1-table.hh | 4 ++--
+ src/hb-subset-cff1.cc   | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+commit 40a1c08f4c7a74b71a7a832b86b94fe8f6aa06b3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 19:03:04 2023 -0600
+
+    [subset/cff1] Micro-optimize
+
+ src/hb-subset-cff1.cc | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit bd3e78770e166c9813031d4be76ecd23c39c0c8b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 18:55:39 2023 -0600
+
+    [subset/cff1] Reuse a function
+
+ src/hb-ot-cff1-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit ffd23d3a310caf400d9458e286adbbd4aadcbece
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 18:54:06 2023 -0600
+
+    [subset/cff1] Micro-optimize Charset serialization
+
+ src/hb-ot-cff1-table.hh | 22 ++++++++++++++--------
+ 1 file changed, 14 insertions(+), 8 deletions(-)
+
+commit 452557cd18e8072b07e48464a0428fecf732f32c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 18:40:54 2023 -0600
+
+    Replace a free with hb_free
+    
+    Ouch.
+
+ src/OT/glyf/CompositeGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1fc128f6095f4caa29cc1001cd87090b9f0dce80
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 18:34:27 2023 -0600
+
+    Replace a few memset/memcpy's with hb_ equivalents
+
+ src/OT/glyf/VarCompositeGlyph.hh |  2 +-
+ src/OT/name/name.hh              |  2 +-
+ src/hb-cairo-utils.cc            |  2 +-
+ src/hb-cairo.cc                  |  2 +-
+ src/hb-map.hh                    |  2 +-
+ src/hb-shape.cc                  |  2 +-
+ src/hb-vector.hh                 |  4 ++--
+ src/hb-wasm-api-buffer.hh        | 12 ++++++------
+ src/hb-wasm-api-face.hh          |  2 +-
+ src/hb-wasm-api-font.hh          |  6 +++---
+ src/hb-wasm-shape.cc             |  2 +-
+ 11 files changed, 19 insertions(+), 19 deletions(-)
+
+commit 2c359635dfb05a9f3a1ed4740203b9efae2379a8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 18:28:11 2023 -0600
+
+    [face-builder] Don't zero allocation
+    
+    We overwrite it.
+
+ src/hb-open-file.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 347b94481100d2eefc88c1e6bc71aa20dcb907bb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 18:09:40 2023 -0600
+
+    [null] Fix getting Crap(hb_bytes_t)
+    
+    Fixes https://oss-fuzz.com/testcase-detail/6187272924692480
+
+ src/hb-null.hh                                            |   6 +++---
+ ...z-testcase-minimized-hb-subset-fuzzer-6187272924692480 | Bin 0 -> 609 bytes
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+commit 49c52fa95316042390bc07bc9fe9438b63cd3320
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 17:55:29 2023 -0600
+
+    [cmap] Don't zero a few allocations unnecessarily
+
+ src/hb-ot-cmap-table.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit e4b2d9c3f33be4e216d5ab6893e9899907f20680
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 17:52:37 2023 -0600
+
+    [pool] Don't clear unused memory
+
+ src/hb-pool.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 6129702eb8a13eac75176772a61adfc63c185f34
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 17:34:54 2023 -0600
+
+    [subset/cff] Simplify some allocation embedding
+
+ src/hb-ot-cff1-table.hh | 18 +++++-------------
+ 1 file changed, 5 insertions(+), 13 deletions(-)
+
+commit 99db06b4d2fa420f46dceccd4c9a625d5325d8b3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 17:30:31 2023 -0600
+
+    [var] Simplify a couple of copy operations
+
+ src/hb-ot-var-common.hh | 20 +++++---------------
+ 1 file changed, 5 insertions(+), 15 deletions(-)
+
+commit 73bcd3f241aa641935235753492ddfebebf9373f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 17:24:40 2023 -0600
+
+    [var] Adjust a few allocations to not clean space
+    
+    Since we immediately copy.
+
+ src/hb-ot-var-common.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit b1e7e8ba2f6705efee8633c4a63513686308c891
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 17:19:45 2023 -0600
+
+    [algs] Fix return of hb_memset()
+
+ src/hb-algs.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c2bab073916870f336ca0b4b658bf70aa99a401c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 16:34:53 2023 -0600
+
+    [subset/cff] Minor optimization
+
+ src/hb-ot-cff-common.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 570fb4df58fcaa58c82b363f4edb5d61f1d948fb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 16:26:12 2023 -0600
+
+    [subset/cff] Add a vector pre-alloc
+
+ src/hb-ot-cff-common.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit e447d394a60ee2878e16bc772d36c988c546caa6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 16:02:41 2023 -0600
+
+    [subset/cff1] Micro-optimize
+
+ src/hb-subset-cff1.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 50499e9e4094825700fdfbf19d85bcd0cdbd506d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 15:32:27 2023 -0600
+
+    [subset/cff1] Minor use rvalues in a few vector push() places
+
+ src/hb-subset-cff1.cc | 13 +++----------
+ 1 file changed, 3 insertions(+), 10 deletions(-)
+
+commit e5b3d4b10588befb7a2e63f5a3137344356908b7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 14:24:38 2023 -0600
+
+    [subset/cff1] Minor use ?:
+
+ src/hb-subset-cff1.cc | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+commit 81e2db7cbcb87668c562329390a49d95a3a604bb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 14:17:44 2023 -0600
+
+    [subset/cff1] Speed up plan_subset_charset
+
+ src/hb-ot-cff-common.hh |  2 +-
+ src/hb-ot-cff1-table.hh |  7 ++++---
+ src/hb-subset-cff1.cc   | 13 ++++++++++++-
+ 3 files changed, 17 insertions(+), 5 deletions(-)
+
+commit d3f90a8ca709f3f1b61484f832303b644ddb8744
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 14:02:26 2023 -0600
+
+    [subset/cff] Use a typedef for glyph_to_sid_map_t
+
+ src/hb-ot-cff-common.hh     |  2 ++
+ src/hb-ot-cff1-table.hh     | 12 ++++++------
+ src/hb-subset-cff-common.hh |  4 ++--
+ src/hb-subset-cff1.cc       |  8 ++++----
+ 4 files changed, 14 insertions(+), 12 deletions(-)
+
+commit 6783701b4e4443ae0db754d74349f05244e4316b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 12:31:22 2023 -0600
+
+    [subset] Handle an error condition
+    
+    Fixes https://oss-fuzz.com/testcase-detail/6306810588692480
+
+ src/hb-subset-plan.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 7d3d157de8c4ba87246f3ccefaede95e0f4b0566
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 12:02:21 2023 -0600
+
+    [subset/cff] Speed up hb_plan_subset_cff_fdselect
+
+ src/hb-subset-cff-common.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit f79d961a319e57213e194421bede954c148cdfd7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 11:32:37 2023 -0600
+
+    [vector] Speedup push()
+
+ src/hb-subset-cff1.cc | 8 +-------
+ src/hb-vector.hh      | 5 ++---
+ 2 files changed, 3 insertions(+), 10 deletions(-)
+
+commit b4b80bcaeabdc2e3c08649a2d75c4af0c4fb72ae
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 11:29:32 2023 -0600
+
+    [subset/cff1] Speed up plan_subset_charset
+
+ src/hb-subset-cff1.cc | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+commit 7305ec47b1359ad791b1ae152d3c39aa19423715
+Merge: 4a628b236 3bdb8639e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 26 12:35:03 2023 -0400
+
+    Merge pull request #4300 from pnacht/scorecard-action
+    
+    Add Scorecard action
+
+commit 4a628b236f2adbc715d5f923143022c097c298d5
+Author: arch1t3cht <arch1t3cht@gmail.com>
+Date:   Mon Jun 26 15:19:29 2023 +0200
+
+    [meson] Remove incorrect option for ICU subproject
+    
+    Fixes #4298 .
+
+ meson.build | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 3bdb8639e43ddf2f145c3b5c803d3648f49b834a
+Author: Pedro Nacht <pedro.k.night@gmail.com>
+Date:   Mon Jun 26 11:25:10 2023 -0300
+
+    Add Scorecard badge to README
+
+ README.md | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 27ef6c081ea26897d36d1ee3dbd6e503e72c9c33
+Author: Pedro Nacht <pedro.k.night@gmail.com>
+Date:   Mon Jun 26 11:22:18 2023 -0300
+
+    Create scorecard.yml
+
+ .github/workflows/scorecard.yml | 64 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 64 insertions(+)
+
+commit 6c4f975dcb7d807b30c074aacb5d2b551078dbd1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 25 23:37:08 2023 -0600
+
+    Add a fuzzer font
+
+ ...-testcase-minimized-hb-subset-fuzzer-4552226966994944 | Bin 0 -> 1524 bytes
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+
+commit 87f1b80d27527d50d99b998a0d734115390bcd3f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 25 23:14:01 2023 -0600
+
+    [bimap] Write with a map & vector combo
+    
+    Faster for getting keys.
+    
+    Speeds up 10% in:
+    BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/retaingids/10
+
+ src/hb-bimap.hh            | 61 ++++++++++++++++++++++++++++++++++++++--------
+ src/hb-ot-layout-common.hh |  4 +--
+ 2 files changed, 53 insertions(+), 12 deletions(-)
+
+commit e7ad017ca6607d9576c4292d82b6c417710a4e54
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 25 22:25:24 2023 -0600
+
+    [subset/cff] Allocate more memory for retain-gids
+    
+    To avoid serializing twice.
+    
+    20% speedup in:
+    BM_subset/subset_glyphs/SourceSansPro-Regular.otf/retaingids/10
+
+ src/hb-subset.cc | 35 +++++++++++++++++++++++++----------
+ 1 file changed, 25 insertions(+), 10 deletions(-)
+
+commit 30f1ab86eacdaba8c98579f3d520d7b23989b4ca
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 25 19:29:03 2023 -0600
+
+    [subset/cff1] Fix typo
+
+ src/hb-subset-cff1.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 7c7db0fcba4513e5121f8a6ff74aaec634caa26a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 25 19:07:40 2023 -0600
+
+    [subset/cff1] Minor shuffle code around
+
+ src/hb-subset-cff1.cc | 26 ++++++++++++--------------
+ 1 file changed, 12 insertions(+), 14 deletions(-)
+
+commit 1e09ebebc1164108e7768b3ba1c66041c424daff
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 25 18:24:42 2023 -0600
+
+    [subset/cff1] Minor use vector length instead of map population
+
+ src/hb-subset-cff1.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 23109dde5ed517a0904a49f912c14017fcb3b10d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 25 18:21:57 2023 -0600
+
+    [subset/cff1] Minor use an exact allocation
+
+ src/hb-subset-cff1.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 393f0f9f16944654ddd2235eacef20951ce598b7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 25 18:14:56 2023 -0600
+
+    [map] Rename resize() to alloc()
+    
+    Better matches the functionality, and hb_vector_t.
+
+ src/hb-bimap.hh                  | 10 +++++-----
+ src/hb-map.hh                    | 12 ++++++------
+ src/hb-multimap.hh               |  4 ++--
+ src/hb-ot-cmap-table.hh          |  2 +-
+ src/hb-ot-post-table-v2subset.hh |  6 +++---
+ src/hb-subset-accelerator.hh     |  2 +-
+ src/hb-subset-cff-common.hh      |  2 +-
+ src/hb-subset-cff1.cc            |  6 +++---
+ src/hb-subset-plan.cc            | 10 +++++-----
+ 9 files changed, 27 insertions(+), 27 deletions(-)
+
+commit 793f663bad20a226919ec45e23ff03c3176777c3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 25 17:33:57 2023 -0600
+
+    [vector] Speed up hb_vector_t<hb_array_t<U>>
+
+ src/hb-vector.hh | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+commit 289bad82f0ff949403e5d058372e20cc32450cbd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 25 17:26:40 2023 -0600
+
+    [subset/cff1] Minor use a dagger
+
+ src/hb-ot-cff1-table.hh | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+commit 31d971d1aa410ef14513792b794ddb4514c0499d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 25 17:23:52 2023 -0600
+
+    [vector] Sprinkle std::addressof
+
+ src/hb-vector.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit c03c0a9d765f2ea0b67b15f4ead4aa35c76279ae
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 25 17:13:59 2023 -0600
+
+    [subset/cff1] Remove unnecessary remap_sid_t::reset
+    
+    The object is initialized automatically.
+
+ src/hb-subset-cff1.cc | 9 ---------
+ 1 file changed, 9 deletions(-)
+
+commit 6ed0d04b699f6353feb3ce1d23eca9348271284a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 25 17:10:36 2023 -0600
+
+    [subset/cff1] In remap_sid_t::reset(), reset everything
+    
+    Previous code wasn't resetting next=0; tests were passing.
+    It's always called when sidmap is empty. So, redundant,
+    but keeping as is.
+
+ src/hb-subset-cff1.cc | 22 ++++++++++++++++------
+ 1 file changed, 16 insertions(+), 6 deletions(-)
+
+commit 7e97233c352b614aa316dfeb3a161db62c7b2bcd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 25 17:06:02 2023 -0600
+
+    [subset/cff1] Comment
+
+ src/hb-ot-cff1-table.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 86a550dc7e182a53eb950278b42d0243b7185f73
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 25 17:01:40 2023 -0600
+
+    [subset/cff1] Speed up string writing
+
+ src/hb-ot-cff1-table.hh | 10 +++++-----
+ src/hb-subset-cff1.cc   | 17 ++++++++++++++++-
+ 2 files changed, 21 insertions(+), 6 deletions(-)
+
+commit dc1b172408ae02a64cac6edefd333d3651f7e92c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 25 16:35:36 2023 -0600
+
+    [subset/cff1] Minor reuse a returned value
+
+ src/hb-subset-cff1.cc | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 95341bcc15944efdb352c415a3b38b6c13ba5221
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 25 16:31:54 2023 -0600
+
+    [subset/cff1] Minor use {} initialization syntax
+
+ src/hb-subset-cff1.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit be0cec288b3cabf5d20f93fc32e3586cd4a9093e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 25 16:01:13 2023 -0600
+
+    [map] Micro-optimize iteration
+    
+    Make is_real() faster (removes a shift). is_used() gets inlined
+    so is not slowed down by this change.
+
+ src/hb-map.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 9dbea6071a41eb8595e888146c74ea7efb790455
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 25 14:28:02 2023 -0600
+
+    [subset/cff1] Fix resource leak in error case
+
+ src/hb-subset-cff1.cc | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+commit e310473cec824c91a249bd23910ccb975d278b50
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Jun 24 21:50:58 2023 -0400
+
+    [use] Allow multiple CMAbv glyphs on subjoined
+
+ src/hb-ot-shaper-use-machine.rl | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d4bbe3f48663944385f25f608438e1eb678fc4b7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 18:13:30 2023 -0600
+
+    [subset/cff] Reuse a calculate index total data size
+
+ src/hb-ot-cff-common.hh | 24 ++++++++++++++++--------
+ src/hb-subset-cff1.cc   |  5 +++--
+ src/hb-subset-cff2.cc   |  5 +++--
+ 3 files changed, 22 insertions(+), 12 deletions(-)
+
+commit ec0fbf8fa6ada90f6564b2d5c69c181aa3f4011f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 16:13:13 2023 -0600
+
+    [subset/ClassDef] Micro-optimize use_class_zero calc
+    
+    Probably never matters.
+
+ src/hb-ot-layout-common.hh | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+commit b557a84123a0bc9dec4dc3178301fd9a67a6c709
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 15:31:54 2023 -0600
+
+    [algs] Speed up fasthash for aligned uint64_t
+
+ src/hb-algs.hh | 26 ++++++++++++++++++++++----
+ 1 file changed, 22 insertions(+), 4 deletions(-)
+
+commit fc80d20cb5cd25ee2d2579f2da018870e76aaa0e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 15:21:30 2023 -0600
+
+    [serialize] Only hash at most 128 bytes for object_t
+    
+    Optimization. Shouldn't in reality bring down the hash performance.
+    Byte objects differ in their early bytes anyway.
+
+ src/hb-serialize.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 19eb5e3b6ceb7f844af4f9cefdc2312ff2d763b1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 15:12:13 2023 -0600
+
+    [subset/cff1] Micro-optimize Charset::serialize
+
+ src/hb-ot-cff1-table.hh | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+commit d36b87bde4ff91ad0eb0dbb19c7183c7d6d46d81
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 14:42:21 2023 -0600
+
+    [vector] Speed up hb_vector_t<hb_vector_t<U>>::realloc_vector
+    
+    Use in CFF subsetting.
+
+ src/hb-vector.hh | 19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+commit b96eed02942e816b723abab73b272ab99b430390
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 14:30:21 2023 -0600
+
+    [vector] Speed up vector_t<vector_t<U>>::resize()
+    
+    Used in CFF subsetting...
+
+ src/hb-vector.hh | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+commit b80b628a8aef423f7c04887e9802caab14fea187
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 13:41:42 2023 -0600
+
+    [subset/cff1] Speed up plan_subset_charset
+
+ src/hb-ot-cff1-table.hh | 21 +++++++++++++--------
+ src/hb-subset-cff1.cc   |  8 ++++++++
+ 2 files changed, 21 insertions(+), 8 deletions(-)
+
+commit 1902f6ccbb90fea33da74973657e6ecfec7a6c99
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 13:21:21 2023 -0600
+
+    [map] Inline an accessor function
+
+ src/hb-map.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 43d2ced8417c2a7666faf01f8e65fa14e40da2cb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 13:16:51 2023 -0600
+
+    [map] Minor remove a conditional
+
+ src/hb-map.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 817236dcb89672f1bd9fbbf9d43ffd5189da395e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 13:12:40 2023 -0600
+
+    [map] Speed up is_real
+
+ src/hb-map.hh | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+commit 628ffd052e2c7d6c4e9ffdce529e29b319066c30
+Merge: 33507a9c2 b10cff990
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 14:43:09 2023 -0400
+
+    Merge pull request #4287 from googlefonts/tuple_varstore_compile
+    
+    [instancer] compile tuple variations
+
+commit 33507a9c27cb45947e9e1cf6999e69891d0a7ae3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 12:40:35 2023 -0600
+
+    [subset/cff] Micro-optimize hb_plan_subset_cff_fdselect
+
+ src/hb-subset-cff-common.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit ecb46f701376e127de68f40ee0bda98c0ec6c63a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 12:18:33 2023 -0600
+
+    [subset/cff1] Comment
+
+ src/hb-subset-plan.cc | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 4332cb3376b03cf5d4acfb044228632da50a2a6a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 12:03:42 2023 -0600
+
+    [subset] Fix bot failure
+
+ src/hb-subset.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit c4b2950debbe5ebeca88c68ec43f42398d4969a7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 11:55:39 2023 -0600
+
+    [subset/cff1] Use cached subset-accel for seac calculations
+    
+    Before we were creating a new (non-subset) accel each time.
+
+ src/hb-ot-cff1-table.cc | 6 +++---
+ src/hb-ot-cff1-table.hh | 4 +++-
+ src/hb-ot-cff2-table.hh | 2 ++
+ src/hb-subset-plan.cc   | 9 +++++----
+ 4 files changed, 13 insertions(+), 8 deletions(-)
+
+commit b10cff9906de237cb7f56abd9e4ba99959966954
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Jun 20 13:36:10 2023 -0700
+
+    [instancer] address review comments
+    
+    manage memory through vector when possible
+
+ src/hb-ot-var-common.hh     | 267 ++++++++++++++++++++++----------------------
+ src/hb-ot-var-cvar-table.hh |  18 ++-
+ src/test-tuple-varstore.cc  |   8 +-
+ 3 files changed, 149 insertions(+), 144 deletions(-)
+
+commit 5f3991391863e97f84842d32c0b18e83e5ed2081
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 11:22:01 2023 -0600
+
+    [subset/cff] Move lazy cff-accelerator to cff-subset-accelerator
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4295
+
+ src/hb-ot-cff1-table.hh      |  8 ++++++++
+ src/hb-ot-cff2-table.hh      |  8 ++++++++
+ src/hb-subset-accelerator.hh |  4 ----
+ src/hb-subset-cff-common.hh  |  9 +++------
+ src/hb-subset-cff1.cc        | 13 ++++++-------
+ src/hb-subset-plan.cc        |  3 ---
+ src/hb-subset.cc             |  8 ++++++--
+ 7 files changed, 31 insertions(+), 22 deletions(-)
+
+commit 3a827123a1a4db75ab621e2c94e65816e4eaba58
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 11:16:57 2023 -0600
+
+    [benchmark-subset] Free cached face upon exist
+    
+    For better valgrind output.
+
+ perf/benchmark-subset.cc | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+commit 97d63e8d1d935cb1fdca08ccb0b53646a0165b13
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 10:43:34 2023 -0600
+
+    [subset/cff] Move serialize to accelerator
+
+ src/hb-ot-cff1-table.hh |  2 ++
+ src/hb-ot-cff2-table.hh |  3 +++
+ src/hb-subset-cff1.cc   | 33 ++++++++++++++++++---------------
+ src/hb-subset-cff2.cc   | 34 ++++++++++++++++++----------------
+ 4 files changed, 41 insertions(+), 31 deletions(-)
+
+commit 7344411cc248742358d623b4954558bcd21daa73
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 10:27:44 2023 -0600
+
+    [subset] Sprinkle some HB_NO_SUBSET_CFF
+
+ src/hb-subset-accelerator.hh | 3 +++
+ src/hb-subset-plan.cc        | 7 +++++--
+ src/hb-subset-plan.hh        | 2 ++
+ src/hb-subset.cc             | 2 ++
+ 4 files changed, 12 insertions(+), 2 deletions(-)
+
+commit 26f320dcd349813ec687fa0aaab40b2e844db6ca
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 10:24:32 2023 -0600
+
+    [subset/cff] Remove unused method
+
+ src/hb-ot-cff1-table.hh | 2 --
+ src/hb-ot-cff2-table.hh | 2 --
+ src/hb-subset-cff1.cc   | 7 -------
+ src/hb-subset-cff2.cc   | 7 -------
+ 4 files changed, 18 deletions(-)
+
+commit 43ec78f92c4c26c50a9cddabfb36de697b41d4e0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 23 10:22:30 2023 -0600
+
+    [subset/cff] Cache CFF accelerator in hb_subset_plan_t
+    
+    This shows 7% speedup in:
+    BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/retaingids/10
+
+ src/hb-atomic.hh             |  1 +
+ src/hb-machinery.hh          |  9 ++++++-
+ src/hb-ot-cff1-table.hh      | 15 ++++++++++-
+ src/hb-ot-cff2-table.hh      | 15 ++++++++++-
+ src/hb-subset-accelerator.hh | 29 +++++++++++----------
+ src/hb-subset-cff-common.hh  |  5 +---
+ src/hb-subset-cff1.cc        | 13 +++++-----
+ src/hb-subset-cff2.cc        | 11 ++++----
+ src/hb-subset-plan.cc        | 40 +++++++++++++++++++++++++++-
+ src/hb-subset-plan.hh        | 62 ++++++++++++++++++++++----------------------
+ src/hb-subset.cc             | 38 +++++++++++++++++++++------
+ 11 files changed, 165 insertions(+), 73 deletions(-)
+
+commit 154aae3af6db4c9b20060ec9e610fcdd0c1db366
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 22 20:41:16 2023 -0600
+
+    [subset] Minor use an auto variable
+    
+    I need this later. :D
+
+ src/hb-subset.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 64e49e0f71d02ccc1209f75aa725ef073a7fb036
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 22 20:27:20 2023 -0600
+
+    [subset-cff2] Store num_glyphs in plan
+    
+    Like cff1 code does.
+    
+    Also, check for .notdef, like cff1 code does.
+
+ src/hb-subset-cff2.cc | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+commit f05561dd4ef8002e89eaec4cac92b64090417660
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 22 20:25:04 2023 -0600
+
+    [subset-cff1] Use plan.num_glyphs instead of passing again
+
+ src/hb-subset-cff1.cc | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+commit 7a124a0b4e4a3b901f3cb7bd9d4df76f176be0c6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 22 20:18:20 2023 -0600
+
+    [cff1] Use constructor for accelerator_templ_t
+
+ src/hb-ot-cff1-table.hh | 68 ++++++++++++++++++++++++-------------------------
+ src/hb-ot-cff2-table.hh |  1 -
+ src/hb-subset-cff1.cc   |  8 ++----
+ 3 files changed, 36 insertions(+), 41 deletions(-)
+
+commit ad025ddf05f1c9dc3eaaea00cd1a80adba7fa8bd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 22 20:09:36 2023 -0600
+
+    [subset-cff] Simplify a bit
+
+ src/Makefile.sources        |  2 --
+ src/hb-ot-cff1-table.hh     |  3 +--
+ src/hb-ot-cff2-table.hh     |  3 +--
+ src/hb-subset-cff-common.hh |  3 +++
+ src/hb-subset-cff1.cc       |  3 +--
+ src/hb-subset-cff1.hh       | 37 -------------------------------------
+ src/hb-subset-cff2.cc       |  3 +--
+ src/hb-subset-cff2.hh       | 37 -------------------------------------
+ src/meson.build             |  2 --
+ 9 files changed, 7 insertions(+), 86 deletions(-)
+
+commit e1753782c18beea4cee93001924985b83db92ccf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 22 19:45:29 2023 -0600
+
+    [subset-cff] Handle an error condition
+
+ src/hb-subset-cff-common.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit cb5f4d0c68d081f75245bdd0da9d75b0726acac5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 22 18:46:33 2023 -0600
+
+    [subset-plan] Avoid a copy in freeing name-table-overrides
+
+ src/hb-map.hh         | 2 +-
+ src/hb-subset-plan.hh | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit d8fba5c6b016e7d6cead4b000b6947b9db240176
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Thu Jun 22 19:25:54 2023 -0400
+
+    [use] Add FM categories to `POST_BASE_FLAGS64`
+
+ src/hb-ot-shaper-use.cc                                  |   3 +++
+ .../fonts/d0430ea499348c420946f6abc2efc84fdf8f00e3.ttf   | Bin 0 -> 1308 bytes
+ test/shape/data/in-house/tests/use-syllable.tests        |   1 +
+ 3 files changed, 4 insertions(+)
+
+commit 6a17622a75cf8dea9f1cf5f7b1e4d9be9145ac49
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 22 18:35:10 2023 -0600
+
+    [array] Speed up iteration
+    
+    These are faster than relying on the random-access methods
+    (forward, rewind, item_it).
+
+ src/hb-array.hh | 21 +++++++++++++++++++++
+ 1 file changed, 21 insertions(+)
+
+commit f839bd11d250b953712733bdb3187eec3bf67419
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 22 17:29:57 2023 -0600
+
+    [multimap] Use one fewer object
+    
+    Also fix error-checking to check for sub-object errors.
+
+ src/hb-multimap.hh | 29 ++++++++++++++---------------
+ 1 file changed, 14 insertions(+), 15 deletions(-)
+
+commit 280edb909b0f0b244b8deb6e0e24eb2516ac038f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 22 17:07:31 2023 -0600
+
+    [map] Use a variable instead of function for is_trivial
+
+ src/hb-map.hh | 17 +++++++----------
+ 1 file changed, 7 insertions(+), 10 deletions(-)
+
+commit 0aa939e70f575e8f7715530a48550ef12ae68d4d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 22 17:05:55 2023 -0600
+
+    [map] Add a constexpr
+
+ src/hb-map.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit cf386e8ce2f28ae1ca40cec849b55e71c36636cf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 22 17:02:10 2023 -0600
+
+    [map] Speed up resize()
+
+ src/hb-map.hh | 26 ++++++++++++++++++++------
+ 1 file changed, 20 insertions(+), 6 deletions(-)
+
+commit abd6c305ff5d1a6126624b906ceec870cd5f15ee
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 22 16:44:29 2023 -0600
+
+    [subset-plan] Micro-optimize
+
+ src/hb-subset-plan.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 7b53d2dbdde3b90f35651a449fc55ea27a7230d9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 22 16:35:11 2023 -0600
+
+    [subset] Avoid copying gid_to_unicode multimap
+    
+    Construct it in the accelerator directly.
+
+ src/hb-subset-accelerator.hh | 21 +++++++++++++--------
+ src/hb-subset-plan.cc        | 13 -------------
+ 2 files changed, 13 insertions(+), 21 deletions(-)
+
+commit 272e159c8987afb8b6d139b89cc1267b802027aa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 22 16:31:50 2023 -0600
+
+    [subset] Speed up populating reverse cmap
+
+ src/hb-subset-plan.cc | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 8f80d9d38db92a391ff5c0794f2a38176cd97e9e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 22 16:22:47 2023 -0600
+
+    [subset-accelerator] Avoid a multimap copy
+
+ src/hb-subset-accelerator.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f55619b8360505ff352c60e728dbf0c2e960e303
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Jun 20 12:37:05 2023 -0700
+
+    [instancer] add subset () for cvar
+
+ src/hb-ot-var-cvar-table.hh | 40 +++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 39 insertions(+), 1 deletion(-)
+
+commit e39e02017e1537cd9f085b1f5999887a309c20c6
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Jun 20 11:48:53 2023 -0700
+
+    [instancer] add serialize() method for TupleVariationData
+
+ src/hb-ot-var-common.hh | 67 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 67 insertions(+)
+
+commit 5ef0199da331959e6b27da90d1032f78d3d775ef
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Jun 20 11:39:20 2023 -0700
+
+    [instancer] instantiate() and compile_bytes () for tuple_variations_t
+    
+    Also add testing code
+
+ src/hb-ot-var-common.hh    | 28 ++++++++++++++++++++++++++++
+ src/test-tuple-varstore.cc | 23 +++++++++++++++++++++++
+ 2 files changed, 51 insertions(+)
+
+commit 48c70ce5f667d6b24d7d4a72bc03095760dc3752
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Jun 20 11:30:51 2023 -0700
+
+    [instancer] add compile_tuple_var_header()
+
+ src/hb-ot-var-common.hh | 116 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 116 insertions(+)
+
+commit 6354b71f81bb85951d84d245eb68ec4e107aea55
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Jun 20 11:24:05 2023 -0700
+
+    [instancer] add compile_deltas() for tuple_delta_t
+
+ src/hb-ot-var-common.hh | 70 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 70 insertions(+)
+
+commit a00ad83a3bc0e86a16a791c0085403dd9a42b5a4
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Jun 20 11:17:11 2023 -0700
+
+    [instancer] add encode_delta_run()
+
+ src/hb-ot-var-common.hh | 165 ++++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 158 insertions(+), 7 deletions(-)
+
+commit 19e5033b9c8d24ee6ce2df124576d5d724d80fc2
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Jun 20 11:02:41 2023 -0700
+
+    [instancer] add compile_all_point_sets() and find_shared_points ()
+    
+    compiled bytes for points set are stored in a hashmap
+
+ src/hb-ot-var-common.hh | 61 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 61 insertions(+)
+
+commit 065e0af5925f260a5fcd40ec0a502ec8aa3ada85
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Jun 20 10:58:24 2023 -0700
+
+    [instancer] add compile_point_set() for tuple_variations_t
+    
+    Also add a byte_data_t struct to store compiled bytes
+
+ src/hb-ot-var-common.hh | 103 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 103 insertions(+)
+
+commit e41b688b50506844739794d715596f24c6ae9545
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Jun 12 13:25:19 2023 -0700
+
+    [instancer] fix bug in tuple varstore decompiling
+    
+    when points count is 0, it means deltas will apply to all points
+
+ src/hb-ot-var-common.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 5c2aa1a8e726b657db49b881c88ccf2c95a64899
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 22 11:02:22 2023 -0600
+
+    [syllabic] Add buffer messages for inserting dotted-circle
+
+ src/hb-ot-shaper-syllabic.cc | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+commit f0f6f6a8057a80ddb8a96ed05f1584e7780f29f0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 22 10:58:44 2023 -0600
+
+    [layout] More message massaging
+
+ src/hb-ot-layout.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 7232c01dce7384ad6c9acd3c9b97780abbe85c1f
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Jun 22 09:37:48 2023 -0700
+
+    [instancer-solver] add tests for instancer-solver crossing calculation fix
+
+ src/test-subset-instancer-solver.cc | 28 ++++++++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+commit 37555f84891c50dfd7ca4478e81acfd8c9393988
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 22 10:21:19 2023 -0600
+
+    [layout] Trace chosen script tag
+
+ src/hb-ot-layout.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit c56275c09c426261723c029644f7f355823c05b8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 21 19:01:46 2023 -0600
+
+    [instancer-solver] Notation
+
+ src/hb-subset-instancer-solver.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit dbac23357f0ad9cba73965a4a00ca85bf01dcef9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 21 18:54:11 2023 -0600
+
+    [instancer-solver] Simplify, from upstream
+
+ src/hb-subset-instancer-solver.cc | 65 ++++++++-------------------------------
+ 1 file changed, 12 insertions(+), 53 deletions(-)
+
+commit 32a9ac2e3a581c68fffac0203d568944bb1d133b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 21 18:30:31 2023 -0600
+
+    [instancer/L4] Add a comment from upstream
+
+ src/hb-subset-instancer-solver.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 244f3224b9a6e9e22f65796a984ef7058e7af930
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 21 17:54:49 2023 -0600
+
+    [instancer-solver] Port optimization from upstream
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4291
+
+ src/hb-subset-instancer-solver.cc   | 165 +++++++++++++++++++++---------------
+ src/test-subset-instancer-solver.cc |   6 +-
+ 2 files changed, 101 insertions(+), 70 deletions(-)
+
+commit 197bb35972d66fa01b26bf6fcb1a2268717ef574
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 21 15:16:53 2023 -0600
+
+    [instancer-solver] Further simplify
+    
+    From https://github.com/fonttools/fonttools/pull/3179/commits/94e081611c6b40fa6284049a753479d1038bdb1c
+
+ src/hb-subset-instancer-solver.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 6788932d81c163cc7634a6b04115e556a1b19299
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 21 15:16:19 2023 -0600
+
+    [instancer-solver] Simplify
+    
+    From https://github.com/fonttools/fonttools/pull/3179/commits/7385cbbc34080d5ed3e9017eb38945cfb03cfe17
+
+ src/hb-subset-instancer-solver.cc | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit de0c5aed5b7ca26570eb91e25930813e9123fe56
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 21 15:14:23 2023 -0600
+
+    [instancer-solver] Backport bugfix from fonttools
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4289
+    
+    Test not ported yet.
+
+ src/hb-subset-instancer-solver.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a77f28286569b1d187aa7470a4721222a3fc44e7
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Jun 19 22:51:01 2023 +0000
+
+    Bump meson from 0.62.0 to 1.1.1 in /.ci
+    
+    Bumps [meson](https://github.com/mesonbuild/meson) from 0.62.0 to 1.1.1.
+    - [Release notes](https://github.com/mesonbuild/meson/releases)
+    - [Commits](https://github.com/mesonbuild/meson/compare/0.62.0...1.1.1)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: meson
+      dependency-type: direct:production
+      update-type: version-update:semver-major
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .ci/requirements.in  |  2 +-
+ .ci/requirements.txt | 14 +++++++-------
+ 2 files changed, 8 insertions(+), 8 deletions(-)
+
+commit a094a6bd9c9504bb9b6f7673ec5a81e8f0f89cbb
+Merge: db700b567 0be1e5a73
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 19 18:50:02 2023 -0400
+
+    Merge pull request #4275 from pnacht/pinned_pip
+    
+    Hash-pin Python dependencies in CI
+
+commit 0be1e5a73dc0d987848ff32592c569d34e7b2024
+Author: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+Date:   Mon Jun 19 20:49:38 2023 +0000
+
+    Use meson 0.62.0, remove retry
+    
+    Signed-off-by: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+
+ .ci/requirements.in           |  2 +-
+ .ci/requirements.txt          |  6 +++---
+ .github/workflows/msvc-ci.yml | 33 +++++++--------------------------
+ 3 files changed, 11 insertions(+), 30 deletions(-)
+
+commit 3679293a450f62c1eb5318d87992b8f727c6517a
+Author: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+Date:   Mon Jun 19 19:46:41 2023 +0000
+
+    msvc-ci: Retry if meson setup is flaky
+    
+    Signed-off-by: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+
+ .github/workflows/msvc-ci.yml | 35 +++++++++++++++++++++++++++--------
+ 1 file changed, 27 insertions(+), 8 deletions(-)
+
+commit 0ccb5c365f61319a68506ab5c5c08c9f12ea1ca5
+Author: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+Date:   Mon Jun 19 19:39:58 2023 +0000
+
+    Only use fonttools in msys2-ci
+    
+    Signed-off-by: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+
+ .github/workflows/msys2-ci.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 546508733d940202d009f95d9414aa229d17150c
+Author: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+Date:   Mon Jun 19 19:36:43 2023 +0000
+
+    Move fonttools to separate requirements file
+    
+    Necessary because msys2/mingw don't accept the other deps
+    (not supported?), and msys2-ci.yml only needs fonttools.
+    
+    Signed-off-by: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+
+ .ci/requirements-fonttools.in  |  1 +
+ .ci/requirements-fonttools.txt | 42 ++++++++++++++++++++++++++++++++++++++++++
+ .ci/requirements.in            |  2 +-
+ .ci/requirements.txt           | 40 ++++++++++++++++++++++++++++++++++++----
+ 4 files changed, 80 insertions(+), 5 deletions(-)
+
+commit db700b5670d9475cc8ed4880cc9447b232c5e432
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Jun 12 23:38:26 2023 +0000
+
+    [subset] fix fuzzer timeout.
+    
+    Fixes: https://oss-fuzz.com/testcase-detail/6681253479579648. Limits iteration of coverage table during MATH subset to valid glyphs.
+
+ src/hb-iter.hh                                           |   2 +-
+ src/hb-ot-math-table.hh                                  |   9 +++++----
+ ...-testcase-minimized-hb-subset-fuzzer-6681253479579648 | Bin 0 -> 3472 bytes
+ 3 files changed, 6 insertions(+), 5 deletions(-)
+
+commit e2722696793cacc8e58546e902451a9b2c65bac4
+Author: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+Date:   Mon Jun 12 14:36:49 2023 +0000
+
+    Bump meson to 0.60.0
+    
+    Signed-off-by: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+
+ .ci/requirements.in  | 2 +-
+ .ci/requirements.txt | 5 +++--
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+commit e39c4cf5a92881d81ba0219a7153116bb53ad59c
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Jun 12 10:58:52 2023 +0000
+
+    Bump ilammy/msvc-dev-cmd from 1.12.0 to 1.12.1
+    
+    Bumps [ilammy/msvc-dev-cmd](https://github.com/ilammy/msvc-dev-cmd) from 1.12.0 to 1.12.1.
+    - [Release notes](https://github.com/ilammy/msvc-dev-cmd/releases)
+    - [Commits](https://github.com/ilammy/msvc-dev-cmd/compare/7315a94840631165970262a99c72cfb48a65d25d...cec98b9d092141f74527d0afa6feb2af698cfe89)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: ilammy/msvc-dev-cmd
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/msvc-ci.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d82c7623c5c146abeb4cea6e5dc8e6318a139a24
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Jun 12 10:58:57 2023 +0000
+
+    Bump actions/checkout from 3.5.2 to 3.5.3
+    
+    Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.2 to 3.5.3.
+    - [Release notes](https://github.com/actions/checkout/releases)
+    - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
+    - [Commits](https://github.com/actions/checkout/compare/8e5e7e5ab8b370d6c329ec480221332ada57f0ab...c85c95e3d7251135ab7dc9ce3241c5835cc595a9)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: actions/checkout
+      dependency-type: direct:production
+      update-type: version-update:semver-patch
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/arm-ci.yml        | 2 +-
+ .github/workflows/configs-build.yml | 2 +-
+ .github/workflows/coverity-scan.yml | 2 +-
+ .github/workflows/linux-ci.yml      | 2 +-
+ .github/workflows/macos-ci.yml      | 2 +-
+ .github/workflows/msvc-ci.yml       | 2 +-
+ .github/workflows/msys2-ci.yml      | 2 +-
+ 7 files changed, 7 insertions(+), 7 deletions(-)
+
+commit 1159b9d3ee0b5c772728aee035fe1a5220da11a9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 10 10:54:32 2023 -0600
+
+    [subset/cff1] Remove always-true check
+
+ src/hb-subset-cff1.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit fad2c4aea6087e39c4589d5698acf93d1a56c173
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 10 10:22:27 2023 -0600
+
+    [subset/cff] Simplify a few serialize calls
+
+ src/hb-subset-cff1.cc | 24 ++++++++----------------
+ src/hb-subset-cff2.cc | 12 ++++--------
+ 2 files changed, 12 insertions(+), 24 deletions(-)
+
+commit 2e6919d5262e5fc747f6ac18057e8c0e286ade89
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 10 10:08:56 2023 -0600
+
+    [subset/cff2] Error handling
+    
+    Fixes https://oss-fuzz.com/testcase-detail/4916785942757376
+
+ src/hb-subset-cff2.cc                                     |  12 ++++++++++--
+ ...z-testcase-minimized-hb-subset-fuzzer-4916785942757376 | Bin 0 -> 331 bytes
+ 2 files changed, 10 insertions(+), 2 deletions(-)
+
+commit 5906f90ce1feb3894da4019fe4b34e788eb21c5b
+Author: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+Date:   Wed Jun 7 18:54:57 2023 +0000
+
+    Hash-pin Actions
+    
+    Signed-off-by: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+
+ .github/workflows/arm-ci.yml        | 2 +-
+ .github/workflows/cifuzz.yml        | 2 +-
+ .github/workflows/configs-build.yml | 2 +-
+ .github/workflows/coverity-scan.yml | 2 +-
+ .github/workflows/linux-ci.yml      | 6 +++---
+ .github/workflows/macos-ci.yml      | 6 +++---
+ .github/workflows/msvc-ci.yml       | 8 ++++----
+ .github/workflows/msys2-ci.yml      | 4 ++--
+ 8 files changed, 16 insertions(+), 16 deletions(-)
+
+commit 0935b3279565ca3c5608a43dc5a4ce65e90b851f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 8 18:47:33 2023 -0600
+
+    [vector] Speed up shrink_vector for trivial destructors
+
+ src/hb-vector.hh | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+commit da2e2c8c25b45cadcebd814a3f42e3d32c4b5e93
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 8 17:16:53 2023 -0600
+
+    [subset/cff] Speed up offset writing
+
+ src/hb-ot-cff-common.hh | 52 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 52 insertions(+)
+
+commit c85ca75eff9658f727059afe3c79a8bc34281ece
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 8 15:57:49 2023 -0600
+
+    [buffer-verify] Simplify a couple ifs
+
+ src/hb-buffer-verify.cc | 19 ++++++-------------
+ 1 file changed, 6 insertions(+), 13 deletions(-)
+
+commit e527c17e239fbbc0856add5723be9b57e3a48662
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 8 15:56:12 2023 -0600
+
+    [buffer-verify] Don't consider shaping failure as error
+
+ src/hb-buffer-verify.cc | 18 ++----------------
+ 1 file changed, 2 insertions(+), 16 deletions(-)
+
+commit cb516075b6880352900d07016f1ccce2dada9c62
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 8 15:50:53 2023 -0600
+
+    [buffer-verify] Error handling
+
+ src/hb-buffer-verify.cc | 41 +++++++++++++++++++++++------------------
+ 1 file changed, 23 insertions(+), 18 deletions(-)
+
+commit 39dd777a12573d488c05c4b59693302cb38f37e7
+Merge: fea47dd3f 3669a6271
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 8 15:25:20 2023 -0600
+
+    Merge pull request #4271 from googlefonts/change_axis_limits
+    
+    [instancer] change tuple variations' axis limits
+
+commit 3669a6271043912de8d0ee566a4effc3a56927f9
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Jun 8 13:26:37 2023 -0700
+
+    fix bot
+
+ src/hb-ot-var-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9fd367663a25bbcdcdff958ebc3665ddf8017077
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Jun 8 12:27:36 2023 -0700
+
+    [instancer] add testing code for change_tuple_variation_axis_limits()
+    
+    Also fixed a small bug
+
+ src/Makefile.am            |  2 +-
+ src/hb-ot-var-common.hh    |  2 +-
+ src/meson.build            |  2 +-
+ src/test-tuple-varstore.cc | 35 +++++++++++++++++++++++++++++++++++
+ 4 files changed, 38 insertions(+), 3 deletions(-)
+
+commit 8057661f077dbca4f8b1f702771b70a9e1e29dd4
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Jun 8 12:10:27 2023 -0700
+
+    [instancer] use axis tag as hashmap key instead of axis index
+    
+    This makes remove_axis() and set_tent() faster, which are used by
+    change_axis_limits ()
+
+ src/hb-ot-var-common.hh     | 16 ++++++++++++----
+ src/hb-ot-var-cvar-table.hh |  2 ++
+ src/test-tuple-varstore.cc  | 11 ++++++++---
+ 3 files changed, 22 insertions(+), 7 deletions(-)
+
+commit 389446c563f9caab73df6d58a43fc5d1ed991920
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Jun 8 09:07:47 2023 -0700
+
+    [instancer] add merge_tuple_variations ()
+
+ src/hb-ot-var-common.hh           | 27 +++++++++++++++++++++++++++
+ src/hb-subset-instancer-solver.hh | 18 ++++++++++++++++++
+ 2 files changed, 45 insertions(+)
+
+commit fea47dd3f2186175feaa710200277158f3698506
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 8 15:03:27 2023 -0600
+
+    [vector] Fix vector error handling when allocation used to be 0
+
+ src/hb-vector.hh | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+commit 11308c4d1f4a8aaab11893810e9809cb76e4e1c6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 8 14:51:18 2023 -0600
+
+    [graph] Remove manual destruction
+    
+    Happens automatically by destructor.
+
+ src/graph/graph.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit d08aee5a7e5dde5158393e8f03c63fad8a4f3682
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 8 13:20:28 2023 -0600
+
+    Add fuzzing test
+
+ ...-testcase-minimized-hb-subset-fuzzer-6442117271257088 | Bin 0 -> 4043 bytes
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+
+commit dbdeb2649d3506b5179ff1bdedf3bc9b5442a038
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 8 12:08:29 2023 -0600
+
+    [vector] Keep allocated size when in error
+
+ src/hb-vector.hh | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+commit 9df07c3c303299ea782176aad901cd7831f4e025
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 8 11:46:06 2023 -0600
+
+    [gsubgpos] Prevent a leak in closure
+    
+    If the push wasn't successful we were constructing an
+    hb_set_t on the Crap data...  At least that's my reading
+    of the code.
+
+ src/hb-ot-layout-gsubgpos.hh | 48 ++++++++++++++++++++++++++------------------
+ 1 file changed, 29 insertions(+), 19 deletions(-)
+
+commit 0f0b3bee2157be6ad0c2ef9bbac39a9cae29e85c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 8 11:13:33 2023 -0600
+
+    [map] Fix use-after-move issue
+
+ src/hb-map.hh | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit a67a7867d2f8e83b9c307f70b8997dedf3f9d154
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 20:24:02 2023 -0600
+
+    [cff] Tweak CFFIndex accessors again
+    
+    Faster; avoiding multiply.
+
+ src/hb-ot-cff-common.hh | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+commit 04c5e46ac6258cc7fafda479cfce1594edb90a2b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 19:18:04 2023 -0600
+
+    [subset/cff] Fix comment
+
+ src/hb-ot-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 8832da83091358c919f3b685d9d168bd92e1c1d5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 18:58:52 2023 -0600
+
+    [subset/cff] Comment
+
+ src/hb-ot-cff-common.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 092373f3512ea6b5f4e8280b5e81dc22ed2e4844
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 17:49:13 2023 -0600
+
+    [subset/cff] Comment
+
+ src/hb-ot-cff-common.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit e0b60bd08d8af88e61fea3b399b1654f3683be4f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 17:25:47 2023 -0600
+
+    [subset/cff1] Speed up remap_sids
+
+ src/hb-map.hh         | 13 +++++++++----
+ src/hb-subset-cff1.cc | 10 +++++-----
+ 2 files changed, 14 insertions(+), 9 deletions(-)
+
+commit 67b16247274d1fc04d36d4242680b0a06912eae0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 16:15:48 2023 -0600
+
+    [set] Simplify a few set iterations as range loop
+
+ src/OT/Layout/Common/CoverageFormat1.hh | 2 +-
+ src/OT/Layout/Common/CoverageFormat2.hh | 2 +-
+ src/graph/graph.hh                      | 3 +--
+ src/hb-bimap.hh                         | 3 +--
+ src/hb-ot-cmap-table.hh                 | 3 +--
+ src/hb-ot-layout-common.hh              | 5 ++---
+ src/hb-ot-layout.cc                     | 5 ++---
+ src/hb-ot-os2-table.hh                  | 3 +--
+ src/hb-subset-cff-common.hh             | 3 +--
+ src/test-gsub-get-alternates.cc         | 2 +-
+ 10 files changed, 12 insertions(+), 19 deletions(-)
+
+commit 988e4f068ebc3797a419eaefa16d2f8547c780bd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 15:57:47 2023 -0600
+
+    [iter] Comment
+
+ src/hb-iter.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 0364c69e6d6209b65739968fb72f73e504e1fd20
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 15:52:18 2023 -0600
+
+    [iter] Add has_fast_len
+    
+    Set iterators are not random_access, but have fast len().
+
+ src/hb-array.hh              | 2 ++
+ src/hb-bit-set-invertible.hh | 1 +
+ src/hb-bit-set.hh            | 1 +
+ src/hb-iter.hh               | 1 +
+ src/hb-map.hh                | 2 +-
+ src/hb-vector.hh             | 2 +-
+ 6 files changed, 7 insertions(+), 2 deletions(-)
+
+commit 2d1589221ddcc64dedd6fa72b853e34b0fff0fab
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 15:47:08 2023 -0600
+
+    [subset/hdmx] Remove an unintended vector copy
+
+ src/hb-ot-hdmx-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 81b2a56d5423d5b1476f279d0c720bb00ffa231b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 15:04:20 2023 -0600
+
+    [set] Micro-optimize iteration
+
+ src/hb-bit-set-invertible.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ad620af6f6d36f2e10d6affaf2112e3f35c656c9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 14:59:22 2023 -0600
+
+    Revert "[iter] Another try at writing some for loops as range loops"
+    
+    This reverts commit 69c6928289cad871b5b096fbdcd2827fdb80c3ad.
+    
+    This had code size increase, and slows down non-random-access
+    iterators since it accesses __end__ which is O(n).
+
+ src/hb-iter.hh | 23 ++++++++++++-----------
+ 1 file changed, 12 insertions(+), 11 deletions(-)
+
+commit 59f2d2f6c2aa61e9e859934a7b710d822e905610
+Author: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+Date:   Wed Jun 7 19:50:09 2023 +0000
+
+    Set dependabot to update requirements.txt
+    
+    Signed-off-by: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+
+ .github/dependabot.yml | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 7c08bb85d589cc1ae5f506832dd90efddf0a06a6
+Author: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+Date:   Wed Jun 7 19:47:57 2023 +0000
+
+    Adopt requirements.txt file in workflows
+    
+    Signed-off-by: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+
+ .github/workflows/linux-ci.yml | 2 +-
+ .github/workflows/macos-ci.yml | 2 +-
+ .github/workflows/msvc-ci.yml  | 2 +-
+ .github/workflows/msys2-ci.yml | 2 +-
+ 4 files changed, 4 insertions(+), 4 deletions(-)
+
+commit a8e2f1b6eaf31d76e41e46dc70aba35263c671be
+Author: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+Date:   Wed Jun 7 19:40:26 2023 +0000
+
+    Add .ci/requirements files
+    
+    Signed-off-by: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+
+ .ci/requirements.in  |   4 ++
+ .ci/requirements.txt | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 179 insertions(+)
+
+commit 80d6e996d75e46e3aa2c3ab32fc898a6d22af556
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 14:21:40 2023 -0600
+
+    [subset/cff1] Fix wrong comma location!
+
+ src/hb-ot-cff1-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 69c6928289cad871b5b096fbdcd2827fdb80c3ad
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 14:11:02 2023 -0600
+
+    [iter] Another try at writing some for loops as range loops
+
+ src/hb-iter.hh | 23 +++++++++++------------
+ 1 file changed, 11 insertions(+), 12 deletions(-)
+
+commit 138461beb474cc65fe4b967efbd12b4e7753ead1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 14:07:39 2023 -0600
+
+    [susbet/cff] Minor remove one indirection
+
+ src/hb-ot-cff-common.hh | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+commit 41369b661735242937ebc7734edea27984ca3b1d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 14:04:42 2023 -0600
+
+    Revert "[subset/cff1] Optimize writing of consecutive names"
+    
+    This reverts commit 3b25a630403b65eb5608d10c3b8d082a141bd5c8.
+    
+    Not worth it. Shows 0.5% speedup only on SourceSansPro/retaingids/10
+    
+    Doesn't have code size increase though.
+
+ src/hb-ot-cff-common.hh | 23 -----------------------
+ src/hb-ot-cff1-table.hh |  2 +-
+ 2 files changed, 1 insertion(+), 24 deletions(-)
+
+commit 3b25a630403b65eb5608d10c3b8d082a141bd5c8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 14:04:25 2023 -0600
+
+    [subset/cff1] Optimize writing of consecutive names
+
+ src/hb-ot-cff-common.hh | 23 +++++++++++++++++++++++
+ src/hb-ot-cff1-table.hh |  2 +-
+ 2 files changed, 24 insertions(+), 1 deletion(-)
+
+commit 78082357c8bcee2adea53caa9da8cee1c7ec2970
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 12:43:05 2023 -0600
+
+    Revert "[iter] Rewrite some loops as range loops"
+    
+    This reverts commit 7a5242a30f3c41755a095909989221b4d22690ef.
+    
+    This times out test-set. Obviously broke something (in hb_all
+    I think). Not bothering to figure out right now.
+
+ src/hb-iter.hh | 35 ++++++++++++++++++-----------------
+ 1 file changed, 18 insertions(+), 17 deletions(-)
+
+commit 7a5242a30f3c41755a095909989221b4d22690ef
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 12:36:15 2023 -0600
+
+    [iter] Rewrite some loops as range loops
+
+ src/hb-iter.hh | 35 +++++++++++++++++------------------
+ 1 file changed, 17 insertions(+), 18 deletions(-)
+
+commit cc9651d55d4909ba3baed8b089ee44f8a2a6c270
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 12:20:48 2023 -0600
+
+    [map] Micro-optimize
+
+ src/hb-map.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 79113ec3b19b80f79efb92214c04774cb7556c7c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 12:14:43 2023 -0600
+
+    [subset/cff1] Micro-optimize String writing
+
+ src/hb-ot-cff1-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 5fe96213aae0cac6f6ef25fdbb7ef64a0c6cd557
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 12:05:57 2023 -0600
+
+    [subset/cff] Micro-optimize CFFIndex writing
+
+ src/hb-ot-cff-common.hh | 25 +++++++++++++------------
+ 1 file changed, 13 insertions(+), 12 deletions(-)
+
+commit 70b13ef00ba86f8315a56d44f3ad065b9a81763c
+Merge: b80b6a4f5 01f9b7977
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 7 11:46:37 2023 -0600
+
+    Merge pull request #4267 from googlefonts/decompile_tuple_varstore
+    
+    [instancer] decompile tuple varstore
+
+commit b80b6a4f5fc64027c43adbe60942a468db81a017
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 6 18:11:55 2023 -0600
+
+    [cff] Remove unused types
+
+ src/hb-ot-cff-common.hh | 5 +----
+ src/hb-ot-cff1-table.hh | 3 +--
+ src/hb-ot-cff2-table.hh | 1 -
+ 3 files changed, 2 insertions(+), 7 deletions(-)
+
+commit 26ac1d4b485c2b96fdc9069583f443b1ab455ab5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 6 18:08:59 2023 -0600
+
+    [cff] Remove unused method
+
+ src/hb-ot-cff-common.hh | 40 +---------------------------------------
+ 1 file changed, 1 insertion(+), 39 deletions(-)
+
+commit c6ce1f81ece74e20e4ae8b4b4d424a1694c3ed15
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 6 17:17:29 2023 -0600
+
+    [cff] Micro-optimize CFFIndex::operator[]
+
+ src/hb-ot-cff-common.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit a55d0b88662c01471f254a452650703586820b4e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 6 17:13:09 2023 -0600
+
+    [subset/cff] Inline type only used once
+
+ src/hb-cff-interp-common.hh | 2 --
+ src/hb-ot-cff1-table.hh     | 2 +-
+ 2 files changed, 1 insertion(+), 3 deletions(-)
+
+commit 2960d13f1bcd573f985b44a40f7340694a99dd9b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 6 16:24:28 2023 -0600
+
+    [subset/cff1] Micro-optimize string writing
+
+ src/hb-ot-cff1-table.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 35e152b9f44a3bbac48a1837d91962fa8619d80f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 6 16:21:14 2023 -0600
+
+    [subset/cff] Micro-optimize CFFIndex for empty strings
+
+ src/hb-ot-cff-common.hh | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit acae5ed25c0da62153c9dd5c1d377886039384cc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 6 16:18:44 2023 -0600
+
+    [subset/cff1] Speed up sid mapping
+    
+    Don't need a full inc_bimap.
+
+ src/hb-ot-cff1-table.hh |  2 +-
+ src/hb-subset-cff1.cc   | 13 +++++++++++--
+ 2 files changed, 12 insertions(+), 3 deletions(-)
+
+commit 9e80f6b1b6a8481252368923ae5b4f10ee7c1d2c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 6 15:38:14 2023 -0600
+
+    [subset/cff1] Speed up plan_subset_charset
+    
+    25% speedup in --benchmark_filter=subset_glyphs/SourceSansPro'.*retaingids/10
+
+ src/hb-subset-cff1.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit fd13aa9effceb1ad87d48ad35c2271217324b6c0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 6 15:33:51 2023 -0600
+
+    [subset/cff1] Optimize CFF::CFF1StringIndex::serialize
+
+ src/hb-ot-cff1-table.hh | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+commit ada1e9a924b7a38071757511117892d3b76cb475
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 6 14:46:06 2023 -0600
+
+    [graph/serialize] Handle empty blob
+    
+    Fixes https://oss-fuzz.com/testcase-detail/4877513265119232
+
+ src/graph/serialize.hh                                     |   3 +++
+ ...-testcase-minimized-hb-repacker-fuzzer-4877513265119232 | Bin 0 -> 10 bytes
+ 2 files changed, 3 insertions(+)
+
+commit a92b288e655a94e076f0c3205f99e9162d35e20c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 6 14:32:25 2023 -0600
+
+    [serializer] Handle snapshotting when current is nullptr
+    
+    Happens with memory failure / fuzzing.
+    
+    Fixes https://oss-fuzz.com/testcase-detail/6292420615340032
+
+ src/hb-serialize.hh                                    |  17 +++++++++++++----
+ ...estcase-minimized-hb-subset-fuzzer-6292420615340032 | Bin 0 -> 2116 bytes
+ 2 files changed, 13 insertions(+), 4 deletions(-)
+
+commit 01f9b79777ab4ad26a04b37f96bd6db841fdbe33
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Jun 5 17:26:20 2023 -0700
+
+    address review comments
+
+ src/Makefile.am                                    |  8 +++----
+ src/hb-ot-var-common.hh                            | 26 ++++++----------------
+ src/hb-ot-var-cvar-table.hh                        |  2 +-
+ src/meson.build                                    |  2 +-
+ ...le-tuple-varstore.cc => test-tuple-varstore.cc} |  0
+ 5 files changed, 13 insertions(+), 25 deletions(-)
+
+commit f01ebe97b294444704c06c0501afddf999faddbe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 5 21:38:37 2023 -0600
+
+    [vector] Minor write more idiomatic
+
+ src/hb-vector.hh | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+commit cd8f7c02017e8b574639463587460d09f12b4477
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 5 17:17:44 2023 -0600
+
+    [subset/cff] Optimize fdselect
+
+ src/hb-subset-cff-common.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 796a0df93e7c84f97aaba13ddb41a00447e2e902
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Jun 5 15:33:43 2023 -0700
+
+    try to fix bot
+
+ src/hb-ot-var-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit dcecb4d16b6ed34a79db245bb191d7b295585fdd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 5 16:03:36 2023 -0600
+
+    [subset/ValueFormat] Micro-optimize
+
+ src/OT/Layout/GPOS/ValueFormat.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 5676adefbc49174aaa654bf2df826c2712a039a9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 5 15:56:19 2023 -0600
+
+    [subset/cff1] Remove an unneeded copy method
+    
+    Same as serializer embed().
+
+ src/hb-ot-cff-common.hh | 10 ----------
+ src/hb-subset-cff1.cc   |  2 +-
+ 2 files changed, 1 insertion(+), 11 deletions(-)
+
+commit 7d9698123ce38fbada898760c748bddad0662831
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 5 15:44:50 2023 -0600
+
+    [subset/cff1] Micro-optimize
+    
+    Is ugly but shows speedup.
+
+ src/hb-ot-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 469e82a2275355e8dd814fc9d6b3f01788c08dfa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 5 15:23:22 2023 -0600
+
+    [subset/PairPos] Micro-optimize
+
+ src/OT/Layout/GPOS/PairPosFormat2.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 6593d2aabac47a1e1953a0b9e74a401c02a02e93
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 5 15:11:43 2023 -0600
+
+    [subset/PairPos] Speed up
+
+ src/OT/Layout/GPOS/PairPosFormat2.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit ed6bee20047ed5b97e6ed9ee460bf5c551341e71
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Jun 5 14:03:22 2023 -0700
+
+    [instancer] add a test for decompile cvar tuple variations data
+
+ src/Makefile.am                      |  5 +++
+ src/meson.build                      |  1 +
+ src/test-decompile-tuple-varstore.cc | 79 ++++++++++++++++++++++++++++++++++++
+ 3 files changed, 85 insertions(+)
+
+commit bd9cdecd59b24f0886df3ce605fc1a8be18c4546
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Jun 5 13:52:05 2023 -0700
+
+    [instancer] add decompile_tuple_variations() for cvar table
+
+ src/hb-ot-var-cvar-table.hh | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+commit 452990edcae85e5f46e083cbb4494a38845ae791
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 17:46:36 2023 -0600
+
+    [cff1] Add TODO
+
+ src/hb-ot-cff1-table.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 072c9c06e0ebba7b93e1e1eb1388c59dac6d8d8f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 16:04:29 2023 -0600
+
+    Revert "[subset/cff1] Micro-optimize"
+    
+    This reverts commit 93020621f0651920ff92e19f543fbf2351c8311b.
+    
+    This slowed down the common path actually.
+
+ src/hb-ot-cff1-table.hh | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+commit f102d57a526a8c32de2e89bec630c0f8aa417bc7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 16:03:34 2023 -0600
+
+    [subset/cff1] Micro-optimize
+
+ src/hb-ot-cff1-table.hh | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+commit cdfbd7b6c6d00a6ff31496d1797c957406b94239
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 15:58:14 2023 -0600
+
+    [subset/cff1] Micro-optimize
+
+ src/hb-ot-cff1-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 7b97262b03bf86fe19901820903fe508e563787a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 15:55:18 2023 -0600
+
+    [subset/cff1] Micro-optimize
+
+ src/hb-ot-cff1-table.hh | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+commit 59387dbe43806d37e094bea15ee3b017a3fbaa8c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 5 14:47:27 2023 -0600
+
+    [subset/cff] Speed up sid mapping
+
+ src/hb-ot-cff1-table.hh | 47 +++++++++++++++++++++++++++++++++--------------
+ src/hb-subset-cff1.cc   | 14 ++++++++------
+ 2 files changed, 41 insertions(+), 20 deletions(-)
+
+commit 2012df0755f88f7d104e7c08897ad85b52b659ea
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Jun 5 13:46:04 2023 -0700
+
+    [instancer] add struct tuple_variation_t
+    
+    And add function to decompile TupleVariationData into the struct
+
+ src/hb-ot-var-common.hh | 111 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 111 insertions(+)
+
+commit 9f508b7393ed4cb9dbcd3ebf1ccd30cc33e5add8
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Jun 5 13:35:28 2023 -0700
+
+    [instancer] add unpack_axis_tuples () in TupleVariationHeader
+
+ src/hb-ot-var-common.hh | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 47 insertions(+)
+
+commit ffc6899b0cb788304d2ee7a8c415c3be8d04691b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 5 14:16:47 2023 -0600
+
+    [subset/cff1] Use a vector, instead of map, for glyph_to_sid_map
+    
+    Much faster.
+
+ src/hb-ot-cff1-table.hh     | 20 ++++++++++++--------
+ src/hb-ot-cff2-table.hh     |  2 +-
+ src/hb-subset-cff-common.hh | 12 +++++++++---
+ src/hb-subset-cff1.cc       | 13 ++++++++-----
+ 4 files changed, 30 insertions(+), 17 deletions(-)
+
+commit 7b0ecbd8960e376c9c2d8bb9e95b4d9b616d1743
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Jun 5 13:08:12 2023 -0700
+
+    [instancer] add struct tuple_delta_t to represent 1 tuple variation
+
+ src/hb-ot-var-common.hh | 126 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 126 insertions(+)
+
+commit 1636e112c477369e0c95192ce7c94966fe48c85c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 5 13:44:00 2023 -0600
+
+    [cff] Micro-optimize
+
+ src/hb-ot-cff-common.hh | 18 ++++++------------
+ 1 file changed, 6 insertions(+), 12 deletions(-)
+
+commit 27299e0d20fa06dfbde60631c6273db8624ac0c4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 5 13:41:04 2023 -0600
+
+    [subset/cff] Minor use hb_len()
+
+ src/hb-ot-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 377ccb31e16389887980bdea2830ce7829b50960
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 5 13:38:06 2023 -0600
+
+    [subset/cff] Speed up set_offset_at
+
+ src/hb-ot-cff-common.hh | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+commit 90122925ffcd786365bfb1907c3e6b88230b73d0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 5 13:33:10 2023 -0600
+
+    [subset/cff1] Minor speedup
+
+ src/hb-subset-cff1.cc | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+commit 238cb0fbfd6f7143ad718c7aa488c30865f253fd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 5 13:27:03 2023 -0600
+
+    [subset/cff1] Speed up for retaingids
+
+ src/hb-subset-cff1.cc | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+commit 9de413bf010d7a73082931ee081f595fa5e24acd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 17:43:48 2023 -0600
+
+    [subset/cff1] Micro-optimize
+
+ src/hb-subset-cff1.cc | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit ca353e644d3b920f9559cdc7b29b7460edee7f88
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 17:25:29 2023 -0600
+
+    [subset/cff1] Style
+
+ src/hb-subset-cff1.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit e077ca893eadd993bd52bb902c6f43e488f4a509
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 16:23:36 2023 -0600
+
+    [subset/cff] Micro-optimize
+
+ src/hb-subset-cff1.cc | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+commit 126d1441964840808a1551fe404beec7f1fe8c5e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 16:23:36 2023 -0600
+
+    [subset/cff] Micro-optimize
+
+ src/hb-subset-cff-common.cc | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit a24025c90d6ccc2846b1bec71fa3ad86329fe3c4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 16:15:43 2023 -0600
+
+    [subset/cff1] Micro-optimize
+
+ src/hb-subset-cff1.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 5a3ac0ab349067308dec04a36fac4d58f46c4c42
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 15:37:25 2023 -0600
+
+    [subset/cff1] Another micro-optimization
+
+ src/hb-subset-cff1.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 331398286aa5a7ec7fc7066ae9959756f8ee1735
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 15:33:22 2023 -0600
+
+    [subset/cff1] Micro-optimize
+
+ src/hb-subset-cff1.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 595aa58379bbbb14149212b9619f6047751d6f78
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 15:24:36 2023 -0600
+
+    [UnsizedArray] Minor simplify operator[]
+
+ src/hb-open-type.hh | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+commit 319ea3b967fdcac14af55ce229740f2fd3c764af
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 15:23:20 2023 -0600
+
+    [UnsizedArrayOf] Simplify operator[]
+    
+    No need to check for overflow. Caller is responsible for correct
+    access.
+
+ src/hb-open-type.hh | 10 ++--------
+ 1 file changed, 2 insertions(+), 8 deletions(-)
+
+commit 6188a3f5a42644b1b86082012c046c23ba443393
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 15:12:56 2023 -0600
+
+    [subset/cff] Minor signedness change
+
+ src/hb-ot-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 887f299351a79f608ac93fbee1ec4f4f7fc7e02c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 15:11:17 2023 -0600
+
+    [susbet/cff] Reuse iterator
+
+ src/hb-ot-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f5b82846336fd01e6ef613c8bd0cf5456da2db35
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 15:10:08 2023 -0600
+
+    [subset/cff1] Minor use hb_len
+
+ src/hb-ot-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 70638170714e417921eb98db001c3248ed235d46
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 15:03:16 2023 -0600
+
+    [subset/cff1] Speed up writing 1byte charstrings
+    
+    As in the holes of retaingids.
+
+ src/hb-ot-cff-common.hh | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+commit 21ff023a46b567b4d2b6297088e205b83ab1bbdf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 14:08:24 2023 -0600
+
+    [subset/cff1] Speed up encoding for retaingids
+
+ src/hb-subset-cff1.cc | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+commit b15222399822baf52a735743ca281bcd98173fec
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 13:58:10 2023 -0600
+
+    [cff] Minor type change
+
+ src/hb-ot-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 640774b9f190226609d5948183d1df8055ceceb4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 13:26:14 2023 -0600
+
+    [subset/cff] Speed up subsr subset for retaingids
+
+ src/hb-subset-cff-common.hh | 32 +++++++++++++++-----------------
+ 1 file changed, 15 insertions(+), 17 deletions(-)
+
+commit 6b11a3d971807f6fa90f284739491acc4ed21cca
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 13:18:43 2023 -0600
+
+    [subset/cff] Speed up closure_subroutines for retaingids
+
+ src/hb-subset-cff-common.hh | 14 ++++++--------
+ 1 file changed, 6 insertions(+), 8 deletions(-)
+
+commit 31014832a9925bbc2ad892fa5de1704e8e8f5312
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 12:58:02 2023 -0600
+
+    [cff1] More hygiene
+
+ src/hb-ot-cff1-table.hh | 15 ++++++++++-----
+ src/hb-subset-cff1.cc   |  4 ++--
+ 2 files changed, 12 insertions(+), 7 deletions(-)
+
+commit bf0a08c930506a7301517f5678c2fdb1b34b6595
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 12:54:35 2023 -0600
+
+    [cff1] Hygiene
+
+ src/hb-open-type.hh     |  2 +-
+ src/hb-ot-cff1-table.hh | 13 +++++++------
+ src/hb-subset-cff1.cc   |  2 +-
+ 3 files changed, 9 insertions(+), 8 deletions(-)
+
+commit ebc5257e29fb803e0b7c893a2dc0187c3641040f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 11:25:16 2023 -0600
+
+    [cff1] Add a couple of unlikely's
+
+ src/hb-ot-cff1-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 9cdc0b6419d3371c94c919a100b64ece99e89fe0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 11:18:56 2023 -0600
+
+    [subset/cff] Speed up subset_cff_fdselect
+
+ src/hb-ot-cff-common.hh     | 31 +++++++++++++++++++++++++++----
+ src/hb-subset-cff-common.cc |  5 ++++-
+ 2 files changed, 31 insertions(+), 5 deletions(-)
+
+commit 858a022358807720d6ff7fc20206484997766524
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 10:55:41 2023 -0600
+
+    Revert "[cff] Optimize writing out Index offsets"
+    
+    This reverts commit 78ba23c58766c16992ddc4e3af403824aa845fe2.
+    
+    Not enough gain, and bloats code size.
+
+ src/hb-ot-cff-common.hh | 52 -------------------------------------------------
+ 1 file changed, 52 deletions(-)
+
+commit 78ba23c58766c16992ddc4e3af403824aa845fe2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 10:52:19 2023 -0600
+
+    [cff] Optimize writing out Index offsets
+
+ src/hb-ot-cff-common.hh | 52 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 52 insertions(+)
+
+commit 89ce804833a3d4f53cbdfdc728eea3c393a84ecd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 10:20:39 2023 -0600
+
+    [serialize] Remove attribute malloc
+    
+    This broke tests. It wasn't technically correct.
+
+ src/hb-serialize.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit 3f2a1b644a470d5dcc9b8347a2cc1914b3550da3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 10:13:53 2023 -0600
+
+    Fix build
+
+ src/hb-ot-cmap-table.hh | 2 +-
+ src/hb-serialize.hh     | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit e1715056fc15ce37ff486486ea89ee51412d3e51
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 10:09:02 2023 -0600
+
+    [serialize] One more attribute
+
+ src/hb-serialize.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 15048e50ece21a8b22b4c00c728f7c841175f560
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 10:07:04 2023 -0600
+
+    [serialize] Add more function attributes
+
+ src/OT/glyf/SubsetGlyph.hh | 2 +-
+ src/hb-serialize.hh        | 6 ++++--
+ 2 files changed, 5 insertions(+), 3 deletions(-)
+
+commit aad12ca649ddb0979f4815b0fd824bae9c918abe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 09:57:51 2023 -0600
+
+    [serialize] Add a few function attributes
+
+ src/hb-serialize.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 4e076da9d0492dba35d38305876cc6d5badf6f75
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 09:48:42 2023 -0600
+
+    Another try at fixing build
+
+ src/OT/name/name.hh | 14 ++++++--------
+ 1 file changed, 6 insertions(+), 8 deletions(-)
+
+commit b08866afda7f88b8df4e6603e4e35adfbe7e0761
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 09:44:37 2023 -0600
+
+    Fix build
+
+ src/OT/name/name.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit 82741304d3636de1a6ffbe5ca13012bebb94229b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 09:41:41 2023 -0600
+
+    [subset] start_embed never returns nullptr
+    
+    Remove checks.
+
+ src/OT/Color/CBDT/CBDT.hh                          |  8 +-----
+ src/OT/Color/COLR/COLR.hh                          |  3 +--
+ src/OT/Color/sbix/sbix.hh                          |  5 ----
+ src/OT/Layout/GDEF/GDEF.hh                         |  3 ---
+ src/OT/Layout/GPOS/AnchorFormat3.hh                |  1 -
+ src/OT/Layout/GPOS/CursivePosFormat1.hh            |  1 -
+ .../Layout/GSUB/ReverseChainSingleSubstFormat1.hh  |  1 -
+ src/OT/glyf/glyf.hh                                |  5 ++--
+ src/OT/name/name.hh                                |  3 +--
+ src/hb-ot-cff-common.hh                            |  2 +-
+ src/hb-ot-cmap-table.hh                            |  8 ++----
+ src/hb-ot-hdmx-table.hh                            |  3 +--
+ src/hb-ot-hmtx-table.hh                            |  3 +--
+ src/hb-ot-layout-common.hh                         | 14 +++++-----
+ src/hb-ot-layout-gsubgpos.hh                       |  6 +----
+ src/hb-ot-math-table.hh                            |  4 ---
+ src/hb-ot-post-table.hh                            |  3 +--
+ src/hb-ot-stat-table.hh                            |  2 --
+ src/hb-ot-var-common.hh                            |  1 -
+ src/hb-ot-vorg-table.hh                            |  2 +-
+ src/hb-subset-cff1.cc                              | 31 +++++++---------------
+ src/hb-subset-cff2.cc                              | 20 +++++---------
+ 22 files changed, 37 insertions(+), 92 deletions(-)
+
+commit c2eaedd2cda2da854834f1fd59dadffeec9b45cd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 09:25:07 2023 -0600
+
+    [fuzzing] Add a test font
+    
+    From https://oss-fuzz.com/testcase-detail/5855710991482880
+
+ ...case-minimized-hb-subset-fuzzer-5855710991482880.fuzz | Bin 0 -> 1048 bytes
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+
+commit af3fdf1f9e09fb7e47d4528d81fd510730b80745
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 09:22:42 2023 -0600
+
+    [subset/glyf] Simplify error handling
+
+ src/OT/glyf/glyf.hh | 31 ++++++++++---------------------
+ 1 file changed, 10 insertions(+), 21 deletions(-)
+
+commit 3dd1de46d637f36bc30bbd7dd8be3a058d1f1864
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 09:15:14 2023 -0600
+
+    [subset/glyf] Fix a few return_trace's
+
+ src/OT/glyf/glyf.hh | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+commit 73f2f935a077274fef3343e36352b4e01678d662
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 4 09:12:18 2023 -0600
+
+    [subset/glyf] Fix another leak
+
+ src/OT/glyf/glyf.hh | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+commit 3d08a2f10cada7c72513d9491ddf66820ef008fb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 23:38:38 2023 -0600
+
+    [subset/glyf] Fix leak
+
+ src/OT/glyf/glyf.hh | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit fc33200d79aacd007773b8ed6c64486848b8ebc7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 23:29:39 2023 -0600
+
+    [subset/glyf] Avoid a vector copy
+    
+    Oops!
+
+ src/OT/glyf/glyf.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3bfcbd61490a3fc44f28b813aa8a89bcb9e60e48
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 23:17:56 2023 -0600
+
+    [subset/glyf] Minor use range lopp
+
+ src/OT/glyf/glyf.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 917c8d0ac526ef1a0217e74f2e9553fd81cbb6b9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 23:15:56 2023 -0600
+
+    [subset/glyf] Minor change of value
+
+ src/OT/glyf/glyf.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 2b8c43135ad409c9d613a1e80a43924594fa1c3f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 23:01:27 2023 -0600
+
+    [vector] Oops!
+
+ src/hb-vector.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 054f966a570ef37e0153b6591cbb2ff165517738
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 22:52:16 2023 -0600
+
+    [subset/cff1] Don't allocate memory for retaingid holes
+    
+    40% speedup in BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/retaingids/10
+    benchmark.
+
+ src/hb-cff-interp-common.hh |  2 ++
+ src/hb-static.cc            |  3 +++
+ src/hb-subset-cff-common.hh | 14 ++++++++++++--
+ src/hb-vector.hh            | 10 ++++++++--
+ 4 files changed, 25 insertions(+), 4 deletions(-)
+
+commit b5792f117a8df69025baf0543bc978a0e0f6ee72
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 22:24:06 2023 -0600
+
+    [subset] Reuse num_glyphs in various places
+
+ src/OT/Color/CBDT/CBDT.hh   | 3 ++-
+ src/hb-ot-var-hvar-table.hh | 3 ++-
+ src/hb-subset-cff-common.hh | 6 ++++--
+ src/hb-subset-cff1.cc       | 5 +++--
+ 4 files changed, 11 insertions(+), 6 deletions(-)
+
+commit 7e4311a868e33d21eccb0f714572f552028931c0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 22:11:47 2023 -0600
+
+    [cff] Speed up for retaingids
+
+ src/hb-subset-cff-common.hh | 26 ++++++++++++++++----------
+ 1 file changed, 16 insertions(+), 10 deletions(-)
+
+commit ca237e6ba89193c92161298accc57b2a6542a296
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 22:07:29 2023 -0600
+
+    [subset/cff] Reuse num_glyphs
+
+ src/hb-subset-cff-common.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit 1590754ba8f292df6e1e1b58ff874fb0efda87ee
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 22:04:52 2023 -0600
+
+    [subset/cff] Speed up for retaingids
+
+ src/hb-subset-cff-common.cc | 20 ++++++++++++--------
+ 1 file changed, 12 insertions(+), 8 deletions(-)
+
+commit dff3a936d21703d0a548546f5fcfa3a122beda27
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 22:00:28 2023 -0600
+
+    [subset/cff1] Speed up for retaingids
+
+ src/hb-subset-cff1.cc | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+commit fa8d15d520b9b1f9012aef7ecdf4f3947c162e96
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 21:58:21 2023 -0600
+
+    [subset/cff1] Reuse num_glyphs
+
+ src/hb-subset-cff1.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 937ead2f02a13d551b428a8358a5e17550387ee6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 21:38:56 2023 -0600
+
+    [subset/hvar] Speed up for retaingids
+
+ src/hb-ot-var-hvar-table.hh | 32 ++++++++++++++++++--------------
+ 1 file changed, 18 insertions(+), 14 deletions(-)
+
+commit acab716b1c8b1a071d0551f8e4df07444b2c0446
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 21:15:36 2023 -0600
+
+    [subset/hvar] Speed up for retaingids
+
+ src/hb-ot-var-hvar-table.hh | 24 ++++++++++++------------
+ 1 file changed, 12 insertions(+), 12 deletions(-)
+
+commit bc6dbf436a373579f405b6bf91c256b7ac779f92
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 21:09:33 2023 -0600
+
+    [subset/gvar] Micro-optimize
+
+ src/hb-ot-var-gvar-table.hh | 18 ++++++++++++------
+ 1 file changed, 12 insertions(+), 6 deletions(-)
+
+commit 841347533adfbdc3de79f7bb288220e380246d56
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 21:08:30 2023 -0600
+
+    [subset/gvar] Speed up for retaingids
+
+ src/hb-ot-var-gvar-table.hh | 53 ++++++++++++++++++++++++++++++---------------
+ 1 file changed, 36 insertions(+), 17 deletions(-)
+
+commit 87cf09bd2c7b7bb001a974296de13617a34e6627
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 21:00:56 2023 -0600
+
+    [subset/loca] Fix up for retaingid null glyphs at the end
+    
+    We currently don't have those, but in case we add.
+
+ src/OT/glyf/glyf-helpers.hh | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 2fb670a5281bbfe057d9ebc1dd84fb67d9d6c8f7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 20:56:04 2023 -0600
+
+    [subset/gvar] Speed up for retaingids
+
+ src/hb-ot-var-gvar-table.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit 5b1679343afc9d6a7acc8a6e0f3c1974516e3501
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 20:45:52 2023 -0600
+
+    [subset/hdmx] Micro-optimize
+
+ src/hb-ot-hdmx-table.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 9b733532dff1e31b93d03a30443af6e67229da4c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 20:44:08 2023 -0600
+
+    [subset/hdmx] Fix build
+
+ src/hb-ot-hdmx-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4d4792ce3db59844b8a220712e12cd6873d3d7c3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 20:34:51 2023 -0600
+
+    [subset/hdmx] Speed up more for retaingids
+
+ src/hb-ot-hdmx-table.hh | 37 +++++++++++++++++++++----------------
+ 1 file changed, 21 insertions(+), 16 deletions(-)
+
+commit a3f7ed709b8dec880fab338d8db6494c2d7de998
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 20:25:14 2023 -0600
+
+    [subset/hdmx] Don't clear memory unnecessarily
+
+ src/hb-ot-hdmx-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e263c3ccbbca438767c180431e695a99c575a695
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 20:20:57 2023 -0600
+
+    [subset/hdmx] Speed up
+
+ src/hb-ot-hdmx-table.hh | 2 +-
+ src/hb-subset-plan.hh   | 9 ---------
+ 2 files changed, 1 insertion(+), 10 deletions(-)
+
+commit 0e16be9b2cfc549edbaa4a643d9c15c6570771bd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 19:45:44 2023 -0600
+
+    [subset-plan] Reuse glyph_for_gid result
+
+ src/hb-subset-plan.cc | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 590fb3529a27a2a652c74baa2c8bebad34ec5c42
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 19:21:22 2023 -0600
+
+    [subset] Reduce memory pressure
+
+ src/hb-subset.cc | 67 +++++++++++++++++++++++++++++---------------------------
+ 1 file changed, 35 insertions(+), 32 deletions(-)
+
+commit c03c3000164c873275a8b60fa07661a9fe74243e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 19:05:10 2023 -0600
+
+    [subset] Tweak memory allocation
+    
+    Reduces chances of rework, specially for glyf table if padding
+    is needed...
+
+ src/hb-subset.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 38fa0323303bf6c289314932ad4d41ac40734eac
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 18:51:09 2023 -0600
+
+    Revert "[subset/loca] Build in the serializer memory"
+    
+    This reverts commit 546b51818666ca1ddb01824f752eccbd6a751b4b.
+
+ src/OT/glyf/glyf-helpers.hh | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+commit 546b51818666ca1ddb01824f752eccbd6a751b4b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 18:50:35 2023 -0600
+
+    [subset/loca] Build in the serializer memory
+    
+    Because it's hot. Doesn't seem to speed up though. Slight
+    slowdown. Going to revert.
+
+ src/OT/glyf/glyf-helpers.hh | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+commit 3cb2b49e61fed1aef8c17432abd25f536a919c30
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 18:44:56 2023 -0600
+
+    [subset/loca] Shuffle code around
+
+ src/OT/glyf/glyf-helpers.hh | 15 +++++++--------
+ src/OT/glyf/glyf.hh         | 21 +++++++++------------
+ 2 files changed, 16 insertions(+), 20 deletions(-)
+
+commit f014112d16a205e5b9e9406205e7854076df8b02
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 18:27:24 2023 -0600
+
+    Revert "[subset] Allow adding table directly from subset()"
+    
+    This reverts commit 25a6514887ebe899bd4ede1e283e067f97e15def.
+
+ src/hb-ot-hmtx-table.hh | 39 +++++++++++++++++----------------------
+ src/hb-subset.cc        | 18 ++----------------
+ 2 files changed, 19 insertions(+), 38 deletions(-)
+
+commit 25a6514887ebe899bd4ede1e283e067f97e15def
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 18:26:36 2023 -0600
+
+    [subset] Allow adding table directly from subset()
+    
+    And do it for hmtx. Going to revert since it slows things down.
+    Apparently the serializer buffer is in caches and hot, so faster
+    to write to and copy even.
+
+ src/hb-ot-hmtx-table.hh | 39 ++++++++++++++++++++++-----------------
+ src/hb-subset.cc        | 18 ++++++++++++++++--
+ 2 files changed, 38 insertions(+), 19 deletions(-)
+
+commit b0d0babb2e9fe81ee1e96dddfc1fadfeac0b3bab
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 17:14:55 2023 -0600
+
+    [subset/loca] Rewrite loop faster
+
+ src/OT/glyf/glyf-helpers.hh | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+commit 8dab4441021822f37b3c17194357932c1afc3313
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 17:06:30 2023 -0600
+
+    [subset/hmtx] Micro-optimize last commit
+    
+    hb_zip has its own overhead...
+
+ src/hb-ot-hmtx-table.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit e981dc24c8f04c42addce2a595ab4d60d76dae36
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 17:01:52 2023 -0600
+
+    [subset/hmtx] Rewrite loop faster for retaingid
+
+ src/hb-ot-hmtx-table.hh | 23 ++++++++++-------------
+ 1 file changed, 10 insertions(+), 13 deletions(-)
+
+commit 4a9da0261925c116e738917d8692ecf9d5c90d77
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 16:46:29 2023 -0600
+
+    [subset/hmtx] Micro-optimize
+
+ src/hb-ot-hmtx-table.hh | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+commit 6a3fcc64f3f8d72eb87c15f23720665b42c22f27
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 16:38:18 2023 -0600
+
+    [map] Don't call hash() if map is empty
+
+ src/hb-map.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 735d249639a83b7c12c1792551ed4cbbebce7ef2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 16:35:03 2023 -0600
+
+    [map] Remove an unlikely
+    
+    Empty maps are common in some subsetting operations.
+
+ src/hb-map.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ca27925d55b89a049c1013888a55c4784d255f47
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 16:18:15 2023 -0600
+
+    Use hb_codepoint_pair_t in more places
+
+ src/OT/Layout/GSUB/Common.hh      |  2 --
+ src/OT/glyf/glyf-helpers.hh       |  4 ++--
+ src/graph/pairpos-graph.hh        | 10 +++++-----
+ src/graph/test-classdef-graph.cc  |  2 +-
+ src/hb-algs.hh                    |  2 ++
+ src/hb-bit-set-invertible.hh      |  4 ++--
+ src/hb-bit-set.hh                 |  2 +-
+ src/hb-map.hh                     |  2 +-
+ src/hb-ot-cmap-table.hh           |  6 +++---
+ src/hb-ot-hmtx-table.hh           |  4 ++--
+ src/hb-ot-layout-common.hh        |  8 ++++----
+ src/hb-set.hh                     |  4 ++--
+ src/hb-subset-plan-member-list.hh |  4 ++--
+ src/hb-subset-plan.cc             |  9 ++++-----
+ src/test-map.cc                   |  6 +++---
+ src/test-set.cc                   |  2 +-
+ 16 files changed, 35 insertions(+), 36 deletions(-)
+
+commit 841e86fd9873dba727af843d638880d8257c89fb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 16:09:45 2023 -0600
+
+    [subset/hmtx] Further speedup!
+
+ src/hb-ot-hmtx-table.hh | 44 +++++++++++++++++++++++++++-----------------
+ 1 file changed, 27 insertions(+), 17 deletions(-)
+
+commit de729ec10566e8dd8bf1f22d9bbf73c2b9f54aeb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 15:48:54 2023 -0600
+
+    [meta] Return reference from reference-wrapper
+
+ src/hb-iter.hh | 6 +++---
+ src/hb-meta.hh | 8 ++++----
+ 2 files changed, 7 insertions(+), 7 deletions(-)
+
+commit c7493efeafcf2ac9af39e8049a2a907065e26756
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 15:39:27 2023 -0600
+
+    [subset/loca] Micro-optimize
+
+ src/OT/glyf/glyf-helpers.hh | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+commit 13a4c7b3d3bb6c3fb2cbbed1f1de717f58162dae
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 15:12:53 2023 -0600
+
+    [subset/hmtx] Comment
+
+ src/hb-ot-hmtx-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4da2996fe2dba5134e7e7f40cb089c9a1e30fb64
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 15:08:20 2023 -0600
+
+    [doc] Fix
+
+ src/hb-common.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c3e7f4516658d18c60160b567939bad746404d6e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 3 14:56:47 2023 -0600
+
+    Add HB_CODEPOINT_INVALID
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4262
+
+ docs/harfbuzz-sections.txt |  1 +
+ src/hb-common.h            | 10 ++++++++++
+ src/hb-map.h               |  2 +-
+ src/hb-set.h               |  2 +-
+ 4 files changed, 13 insertions(+), 2 deletions(-)
+
+commit efefec13ccedc1461867544e2066e2042e86c66f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 2 20:33:52 2023 -0600
+
+    [subset/glyf] Remove unneeded codepath
+
+ src/OT/glyf/SubsetGlyph.hh | 7 -------
+ 1 file changed, 7 deletions(-)
+
+commit ac1f5ca0d9cb94089954a2e4ddf7e064600c5004
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 2 17:07:44 2023 -0600
+
+    [subset/loca] Micro-optimize
+
+ src/OT/glyf/glyf-helpers.hh | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+commit 6eae932566330f1485be920bc942069020ca24b0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 2 17:05:27 2023 -0600
+
+    [subset/loca] Reduce a vector allocation
+
+ src/OT/glyf/glyf-helpers.hh | 46 +++++++++++++++++++++++++++++----------------
+ src/OT/glyf/glyf.hh         | 34 ++++++++++++++-------------------
+ 2 files changed, 44 insertions(+), 36 deletions(-)
+
+commit cd249d236494784b21502b151d90b326259bae93
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 2 16:15:05 2023 -0600
+
+    [subset/hmtx] Micro-optimize
+
+ src/hb-ot-hmtx-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ec8965e432db27f81b3275c6979fef707f3b9da9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 2 16:10:25 2023 -0600
+
+    [subset/glyf] Don't clear loca allocation
+
+ src/OT/glyf/glyf-helpers.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 916629d1827bbf450d41f06639af27a708634713
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 2 16:08:49 2023 -0600
+
+    [subset/hmtx] Don't clear allocation
+
+ src/hb-ot-hmtx-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 24b069cd53cec2d8afa4e7b90cf5b47c91e215c9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 2 15:55:53 2023 -0600
+
+    [subset] Pre-alloc a few maps
+
+ src/hb-multimap.hh               |  5 +++++
+ src/hb-ot-post-table-v2subset.hh | 12 +++++++++---
+ src/hb-subset-plan.cc            |  2 ++
+ 3 files changed, 16 insertions(+), 3 deletions(-)
+
+commit 7319d0d71226c15c6c744c6d4e2def72cd20b368
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 2 15:41:47 2023 -0600
+
+    [subset-plan] Add a couple of map pre-allocations
+    
+    Approximate...
+
+ src/hb-subset-plan.cc | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 76904b0423119ad1a2540bd98bb69246781eacc5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 2 15:30:12 2023 -0600
+
+    [subset-plan] Simplify / speedup planning glyphset
+
+ src/hb-subset-plan.cc | 27 ++++++++-------------------
+ 1 file changed, 8 insertions(+), 19 deletions(-)
+
+commit 965ce7bba4bf8203cce04b6d21b393532e2e7131
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 2 15:24:00 2023 -0600
+
+    [subset-plan] Speed up planning new_to_old_gid_list
+
+ src/hb-subset-plan.cc | 20 +++++++++++++++-----
+ 1 file changed, 15 insertions(+), 5 deletions(-)
+
+commit b67e464b1cefb733df073590588ab8fcca320bfc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 2 15:11:06 2023 -0600
+
+    [subset/retaingid] Regain perf lost
+    
+    In 0f12fd5a66a5dd1c3c9ac5ea8a52341bafcfe567
+
+ src/OT/glyf/glyf.hh               | 20 ++++++--------------
+ src/hb-ot-hmtx-table.hh           | 14 ++++++++------
+ src/hb-subset-plan-member-list.hh |  2 +-
+ src/hb-subset-plan.cc             | 10 ++++------
+ 4 files changed, 19 insertions(+), 27 deletions(-)
+
+commit 0f12fd5a66a5dd1c3c9ac5ea8a52341bafcfe567
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 2 13:58:55 2023 -0600
+
+    [subset/glyf] Fix for non-monotonic glyphmap
+    
+    Slows things down again, but is correct. Still a good win
+    combined with the previous changes.
+
+ src/OT/glyf/glyf.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 66ce902c3aeccede074a21abafa7482ca24e5031
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 2 13:53:21 2023 -0600
+
+    [glyf] Reduce allocation again
+
+ src/OT/glyf/glyf.hh | 35 ++++++++++++++++++++++-------------
+ 1 file changed, 22 insertions(+), 13 deletions(-)
+
+commit 0e0110e7f210e568e8afc6d63a200e2e28004ebe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 2 13:34:58 2023 -0600
+
+    [glyf] Avoid a SubsetGlyph copy
+    
+    Unfortunately hb_second() always does a copy...
+
+ src/OT/glyf/glyf.hh | 10 +++-------
+ 1 file changed, 3 insertions(+), 7 deletions(-)
+
+commit 33ea8b5e5d152159cd2acbd4054b99cd5559d195
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 2 13:10:52 2023 -0600
+
+    [subset/glyf] Don't allocate empty SubsetGlyf's
+    
+    Shows 33% speedup on Mplus/retaingid/10 benchmark:
+    
+    Comparing before to after
+    Benchmark                                                                   Time             CPU      Time Old      Time New       CPU Old       CPU New
+    --------------------------------------------------------------------------------------------------------------------------------------------------------
+    BM_subset/subset_glyphs/Mplus1p-Regular.ttf/retaingids/10                -0.3296         -0.3294             0             0             0             0
+
+ src/OT/glyf/glyf.hh | 47 +++++++++++++++++++++++++++++------------------
+ 1 file changed, 29 insertions(+), 18 deletions(-)
+
+commit ad872e231349a5cfdd2daf34a8021216431f5d59
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jun 2 18:32:09 2023 +0000
+
+    [subset] Optimize hmtx/vmtx serialization.
+    
+    Make serializer allocation up front to avoid bounds checking overhead for each metric.
+    
+    Benchmarks:
+    BM_subset/subset_glyphs/Mplus1p-Regular.ttf/retaingids/10_median                   -0.1005         -0.1005             0             0             0             0
+    BM_subset/subset_glyphs/Mplus1p-Regular.ttf/retaingids/64_median                   -0.0693         -0.0692             0             0             0             0
+    BM_subset/subset_glyphs/Mplus1p-Regular.ttf/retaingids/512_median                  -0.0294         -0.0293             1             1             1             1
+    BM_subset/subset_glyphs/Mplus1p-Regular.ttf/retaingids/4096_median                 -0.0033         -0.0032             3             3             3             3
+    BM_subset/subset_glyphs/Mplus1p-Regular.ttf/retaingids/10000_median                +0.0170         +0.0171             7             7             7             7
+
+ src/hb-ot-hmtx-table.hh | 24 +++++++++---------------
+ 1 file changed, 9 insertions(+), 15 deletions(-)
+
+commit c6368e014dbfaef1515507b41414a99f998d8616
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 1 20:51:17 2023 -0600
+
+    [map] Return const reference from operator()
+    
+    Like we do in operator[].
+
+ src/hb-map.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b04ca1c188bfd7113c9c4ef546fa8b1535a28d30
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 1 20:43:07 2023 -0600
+
+    Revert "[subset/glyf] Exact allocation"
+    
+    This reverts commit a830f085c849846f8441f5d92d4db36130ef71f8.
+    
+    Weirdly enough in a benchmark I'm running I see this show
+    some slowdown. Makes zero sense.
+
+ src/OT/glyf/glyf.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a830f085c849846f8441f5d92d4db36130ef71f8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 1 20:37:29 2023 -0600
+
+    [subset/glyf] Exact allocation
+
+ src/OT/glyf/glyf.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ff0b85cf571cb94dbbc5091179f7874926a88dbe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 1 20:30:56 2023 -0600
+
+    [subset/glyf] Empty .notdef only if old-gid was also 0
+    
+    Otherwise it wasn't a .notdef, even if new-gid is 0.
+
+ src/OT/glyf/glyf.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 65a7d8c6f033963d70d03885226bb5a07a397488
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 1 20:20:00 2023 -0600
+
+    [glyf] Empty glyphs need no padding
+
+ src/OT/glyf/SubsetGlyph.hh | 12 +-----------
+ 1 file changed, 1 insertion(+), 11 deletions(-)
+
+commit 73c18d1d42792cba70634a0cf8b7324f79c9e701
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 1 20:06:42 2023 -0600
+
+    [glyf] Micro-optimize padded_offsets
+
+ src/OT/glyf/glyf.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 88d8a6d69f7baf57d29aaa1fe29be0f05956652b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 1 19:24:02 2023 -0600
+
+    [BEInt] Use packed-int trick for writing as well
+
+ src/hb-algs.hh | 67 +++++++++++++++++++++++++++++++++++++++-------------------
+ 1 file changed, 45 insertions(+), 22 deletions(-)
+
+commit 4d853b8ba6e491ec85a7077abb208740b44e61bf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 1 18:47:58 2023 -0600
+
+    [subset/regaingid/glyf] Add a fastpath for empty glyphs
+    
+    Mplus benchmark:
+    Comparing before to after
+    Benchmark                                                                      Time             CPU      Time Old      Time New       CPU Old       CPU New
+    -----------------------------------------------------------------------------------------------------------------------------------------------------------
+    BM_subset/subset_glyphs/Mplus1p-Regular.ttf/retaingids/10                   -0.1764         -0.1771             0             0             0             0
+    BM_subset/subset_glyphs/Mplus1p-Regular.ttf/retaingids/64                   -0.1394         -0.1394             0             0             0             0
+    BM_subset/subset_glyphs/Mplus1p-Regular.ttf/retaingids/512                  -0.0644         -0.0645             0             0             0             0
+    BM_subset/subset_glyphs/Mplus1p-Regular.ttf/retaingids/4096                 +0.0132         +0.0131             1             1             1             1
+    BM_subset/subset_glyphs/Mplus1p-Regular.ttf/retaingids/10000                -0.0029         -0.0034             3             3             3             3
+    BM_subset/subset_glyphs/Mplus1p-Regular.ttf/10                              +0.0364         +0.0362             0             0             0             0
+    BM_subset/subset_glyphs/Mplus1p-Regular.ttf/64                              +0.0346         +0.0343             0             0             0             0
+    BM_subset/subset_glyphs/Mplus1p-Regular.ttf/512                             +0.0271         +0.0268             0             0             0             0
+    BM_subset/subset_glyphs/Mplus1p-Regular.ttf/4096                            +0.0193         +0.0193             1             1             1             1
+    BM_subset/subset_glyphs/Mplus1p-Regular.ttf/10000                           -0.0240         -0.0243             2             2             2             2
+    OVERALL_GEOMEAN                                                             -0.0305         -0.0307             0             0             0             0
+
+ src/OT/glyf/SubsetGlyph.hh | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+commit 6ec7629fba96f8be175eac108f7eee83de6cae21
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 1 18:18:30 2023 -0600
+
+    [subset/glyf] Add a const
+
+ src/OT/glyf/SubsetGlyph.hh | 2 +-
+ src/OT/glyf/glyf.hh        | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 9f54ab922f42e954f19432aeacb4bb4022c27e3d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 1 17:45:03 2023 -0600
+
+    [subset-plan] Keep a reverse-gid vector
+    
+    To speed up iteration.
+
+ src/hb-ot-hmtx-table.hh           | 16 +++++++++-------
+ src/hb-subset-plan-member-list.hh |  2 ++
+ src/hb-subset-plan.cc             |  9 ++++++++-
+ 3 files changed, 19 insertions(+), 8 deletions(-)
+
+commit 6b0d3867978c3f42ab8dfbebcedd7567adf28bfe
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 1 23:59:55 2023 +0000
+
+    [subset] in subset benchmarks switch nohinting with retaingids.
+    
+    retain gids is a more interesting case than no hinting for performance.
+
+ perf/benchmark-subset.cc | 21 +++++++++++++--------
+ 1 file changed, 13 insertions(+), 8 deletions(-)
+
+commit 1ae99d1a10e4add937488591632f94edca7bdbdd
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Jun 1 15:22:26 2023 -0700
+
+    bug fix
+
+ src/hb-ot-var-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit aa7dd70a862d6fa516e0aa8194e4cd4983cda934
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 1 14:24:33 2023 -0600
+
+    [hmtx] Reduce map usage slightly
+
+ src/hb-ot-hmtx-table.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit f41c5ec961c559a99045cc84760bac422998b2e3
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 1 18:38:05 2023 +0000
+
+    [map] update map benchmark to also test lookups that hit.
+
+ perf/benchmark-map.cc | 52 ++++++++++++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 45 insertions(+), 7 deletions(-)
+
+commit 4acf6a82bf47a602a9378c84d80a9ccb885145d0
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue May 30 09:26:58 2023 -0700
+
+    [instancer-solver] port solver fix from fonttools
+    
+    See https://github.com/fonttools/fonttools/issues/3139
+
+ src/hb-subset-instancer-solver.cc   |  2 +-
+ src/test-subset-instancer-solver.cc | 18 ++++++++++++++++++
+ 2 files changed, 19 insertions(+), 1 deletion(-)
+
+commit f3b4d35f362efb818959814b741e94facda5fd29
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon May 29 22:38:40 2023 +0000
+
+    [subset] Fix fuzzer crash.
+    
+    https://oss-fuzz.com/testcase-detail/6608005089853440
+
+ src/hb-serialize.hh                                       |   6 +++++-
+ ...z-testcase-minimized-hb-subset-fuzzer-6608005089853440 | Bin 0 -> 999 bytes
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+commit ff326fbe8f5dfb579b6468ffba13bad279322d2b
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon May 29 21:31:01 2023 +0000
+
+    [repacker] check the result of add_buffer() in other places where it's called.
+
+ src/graph/classdef-graph.hh |  8 +++++++-
+ src/graph/coverage-graph.hh |  8 +++++++-
+ src/graph/gsubgpos-graph.hh | 12 +++++++++---
+ 3 files changed, 23 insertions(+), 5 deletions(-)
+
+commit 66a84355ab8a6c2b1e724e844ef4a79ca22a5cf7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 29 17:17:15 2023 -0600
+
+    [hash] Use unsigned types
+    
+    Hopefully ubsan wouldn't complain about overflows now.
+
+ src/hb-algs.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 4a93576bca0f56e82a1d8ad67733df9c5ddb8dcd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun May 28 13:22:35 2023 -0600
+
+    Revert "[map] Speedup for int types"
+    
+    This reverts commit c1b75f5ff0460274229801816265a0efe5731b3a.
+    
+    I was seeing very long chains (140) and a 17% slowdown in
+    BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/512
+    
+    Bummer.
+
+ src/hb-map.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit c1b75f5ff0460274229801816265a0efe5731b3a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun May 28 12:53:17 2023 -0600
+
+    [map] Speedup for int types
+    
+    Since our int hash is now good, we don't need the modulo prime
+    here, so forgo it.  Major speedup:
+    
+    Comparing before to after
+    Benchmark                              Time             CPU      Time Old      Time New       CPU Old       CPU New
+    -------------------------------------------------------------------------------------------------------------------
+    BM_MapInsert/16                     -0.4136         -0.4137             6             4             6             4
+    BM_MapInsert/64                     -0.4442         -0.4441             6             3             6             3
+    BM_MapInsert/512                    -0.5382         -0.5383             8             4             8             4
+    BM_MapInsert/4096                   -0.4160         -0.4162             8             5             8             5
+    BM_MapInsert/32768                  -0.3256         -0.3258            12             8            12             8
+    BM_MapInsert/262144                 -0.1723         -0.1727            11            10            11             9
+    BM_MapInsert/1048576                -0.2310         -0.2309            28            22            28            22
+    BM_MapLookup/16                     -0.0247         -0.0247             3             3             3             3
+    BM_MapLookup/64                     -0.1039         -0.1038             3             3             3             3
+    BM_MapLookup/512                    -0.1076         -0.1079             4             3             4             3
+    BM_MapLookup/4096                   -0.3729         -0.3732             9             6             9             6
+    BM_MapLookup/32768                  +0.2467         +0.2468             9            12             9            12
+    BM_MapLookup/262144                 -0.1862         -0.1868            14            11            14            11
+    BM_MapLookup/1048576                +0.1159         +0.1160            15            17            15            17
+    OVERALL_GEOMEAN                     -0.2414         -0.2416             0             0             0             0
+
+ src/hb-map.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 7f111787e467a52b9b29daae3783a27b620c5593
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat May 27 12:41:05 2023 -0600
+
+    [benchmark-map] Remove overhead
+
+ perf/benchmark-map.cc | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit 5666807328c0cf0f6ac5d6f9079d33edb5b42d88
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat May 27 12:37:36 2023 -0600
+
+    [benchmark-map] Improve Insert benchmark
+    
+    Previously it was enlarging the map depending on whatever
+    number of runs the benchmark-runner decided to run the loop.
+    That wasn't very useful...
+
+ perf/benchmark-map.cc | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+commit 00900f761f45fd963f727241ffe56d14b2b1b768
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat May 27 10:13:53 2023 -0600
+
+    [hash] Enable better hash for integers
+    
+    https://github.com/harfbuzz/harfbuzz/pull/4228#issuecomment-1565079537
+
+ src/hb-algs.hh | 13 +++----------
+ 1 file changed, 3 insertions(+), 10 deletions(-)
+
+commit 20c564bc7620be7f9325376601797fc20622f845
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri May 26 23:04:25 2023 +0000
+
+    [repacker] Fix fuzzer memory leak.
+    
+    https://oss-fuzz.com/testcase-detail/6419865171525632
+
+ src/graph/graph.hh                                      |   3 ++-
+ src/graph/gsubgpos-context.cc                           |   6 +++++-
+ src/graph/gsubgpos-context.hh                           |   4 ++--
+ ...stcase-minimized-hb-repacker-fuzzer-6419865171525632 | Bin 0 -> 65751 bytes
+ 4 files changed, 9 insertions(+), 4 deletions(-)
+
+commit 5abe713203210cfc190a1b94482b9aceab0ec724
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 26 15:56:30 2023 -0600
+
+    [map] Resize map on long chain probes
+
+ src/hb-map.hh | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+commit a652281ed6125e49ab43f0b25e88bc72b2d98085
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri May 26 19:47:50 2023 +0000
+
+    [subset] Fix fuzzer timeout.
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5979721620652032. Timeout was caused by degenerate map insert behaviour due to poor integer hash function. Presize the map to avoid it. Also fixes collect_mapping() for cmap format 13.
+
+ src/hb-ot-cmap-table.hh                                    |  13 ++++++++++---
+ .../clusterfuzz-testcase-hb-subset-fuzzer-5979721620652032 | Bin 0 -> 80 bytes
+ 2 files changed, 10 insertions(+), 3 deletions(-)
+
+commit 208c9490cb29e057dd57f897de739076746d84c2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 26 12:02:03 2023 -0600
+
+    [VarComposite] Limit number of axes that are copied
+    
+    Bandaid for https://oss-fuzz.com/testcase-detail/4591122882887680
+
+ src/OT/glyf/Glyph.hh        | 5 ++++-
+ src/OT/glyf/coord-setter.hh | 2 ++
+ src/hb-limits.hh            | 4 ++++
+ 3 files changed, 10 insertions(+), 1 deletion(-)
+
+commit 5872bdf64ddbf99f7863da382f79ab408cd99e8c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 26 11:41:54 2023 -0600
+
+    [vector] Add copy-constructor for array_t's
+
+ src/OT/glyf/Glyph.hh |  2 +-
+ src/hb-vector.hh     | 22 +++++++++++++++++-----
+ src/test-vector.cc   |  5 +++++
+ 3 files changed, 23 insertions(+), 6 deletions(-)
+
+commit 42aba5ff30647587d446ab6279d02f8dbe2a84cf
+Author: Chun-wei Fan <fanc999@yahoo.com.tw>
+Date:   Wed May 24 12:19:50 2023 +0800
+
+    harfbuzz-config.cmake.in: Support Windows usage
+    
+    Apply the appropriate library prefix/suffix by whether we are building
+    as a statib build in Meson, or by using
+    ${CMAKE_[SHARED|IMPORT]_LIBRARY_PREFIX} and
+    ${CMAKE_[SHARED|IMPORT]_LIRBARY_SUFFIX} as appropriate according to
+    the target platform for shared builds.
+
+ src/harfbuzz-config.cmake.in | 15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+commit 84354d3f23241a17878b54d635ff68c65508aa71
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 23 11:57:22 2023 -0600
+
+    [cff] When max-ops is reached return false
+    
+    Slight speedup too.
+
+ src/hb-cff-interp-cs-common.hh | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+commit 2655b7607c21e1233378959f87a210e4431ad4d7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 23 10:57:58 2023 -0600
+
+    [map] Micro-optimize
+    
+    This shows a speedup.
+
+ src/hb-map.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 12b0680e60ece83844436f61d4269ce38f689c8f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 23 10:49:41 2023 -0600
+
+    [map] Fix set()
+    
+    This was broken in 2133aa2407657d0b3b4b73a4951c05ed26d055f2.
+    
+    We have to keep probing over tombstones.
+
+ src/hb-map.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 4056315c868693c655373856a83603fdc1587aab
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 22 14:17:12 2023 -0600
+
+    [font] Remove redundant avar mapping line
+    
+    The avar mapping happens in hb_ot_var_normalize_coords() call.
+
+ src/hb-font.cc | 3 ---
+ 1 file changed, 3 deletions(-)
+
+commit 592a3d0e96db8ba75432ea2de1fa106a533da09f
+Merge: 2f21dc23b 0d354e044
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun May 21 22:00:53 2023 +0200
+
+    Merge pull request #4237 from harfbuzz/layout-font-extents
+    
+    [layout] Add hb_ot_layout_get_font_extents()
+
+commit 0d354e0442d12b71aec58ac83e7b6ede377c263e
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sun May 21 19:01:04 2023 +0300
+
+    [layout] Add tests for baseline 2 APIs
+
+ test/api/test-baseline.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+commit e047b1abbcb7edc9c4a5263b524a9a52f6a6198d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat May 20 10:27:31 2023 -0600
+
+    [layout] Improve docs
+
+ src/hb-ot-layout.cc | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+commit 132391ad62b90c27a95429b81a27febf4b183a37
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 19 15:01:49 2023 -0600
+
+    [layout] Add test for font_extents
+
+ test/api/Makefile.am           |   1 +
+ test/api/fonts/base-minmax.ttf | Bin 0 -> 352 bytes
+ test/api/meson.build           |   1 +
+ test/api/test-base-minmax.c    |  66 +++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 68 insertions(+)
+
+commit 6996e64f72896ee1d210f5fdc5fea143590f9f3f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 19 14:22:13 2023 -0600
+
+    [BASE] Sanitize and get_min_max fixups
+    
+    Seems to work now.
+
+ src/hb-ot-layout-base-table.hh | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+commit 02e0e9394b42d8f5290a2e9699890b180c09d151
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 19 13:18:06 2023 -0600
+
+    [layout] Fetch default font extents if localized extents not found
+
+ src/hb-ot-layout.cc | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+commit 8ccc1ff21e404ab02f673a0727af58cbadc822a9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 19 13:14:57 2023 -0600
+
+    [layout] Mark language as nullable
+    
+    GI needs it apparently.
+
+ src/hb-ot-layout.cc | 6 +++---
+ src/hb-ot-tag.cc    | 2 +-
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit 792ca22ca3212dc5f69f3c85901f63b538ae00b5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 19 11:42:20 2023 -0600
+
+    [layout] Document new API
+
+ src/hb-ot-layout.cc | 39 ++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 36 insertions(+), 3 deletions(-)
+
+commit 0894813a38d7ba7db1e58c829be15fe4149811b3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 19 11:30:03 2023 -0600
+
+    [layout] Add "2" version of BASE table API
+    
+    ...that do the script/language resolution.
+    
+    Part of https://github.com/harfbuzz/harfbuzz/pull/4237
+    
+    Ref https://github.com/harfbuzz/harfbuzz/issues/3439
+
+ docs/harfbuzz-sections.txt |   3 ++
+ src/hb-ot-layout.cc        | 109 +++++++++++++++++++++++++++++++++++++++++++--
+ src/hb-ot-layout.h         |  32 +++++++++++--
+ 3 files changed, 136 insertions(+), 8 deletions(-)
+
+commit 3e110c69c45a0d4d453ca9db74848442b6670671
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 19 11:06:26 2023 -0600
+
+    [layout] Add hb_ot_layout_get_font_extents()
+    
+    Untested.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3290
+
+ docs/harfbuzz-sections.txt     |  1 +
+ src/hb-ot-layout-base-table.hh |  3 +--
+ src/hb-ot-layout.cc            | 21 +++++++++++++++++++++
+ src/hb-ot-layout.h             |  6 ++++++
+ 4 files changed, 29 insertions(+), 2 deletions(-)
+
+commit 2f21dc23b51043bb95343d3c6a910a105536f8c2
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Thu May 18 07:14:28 2023 +0100
+
+    [wasm] [docs] Improve build flags information
+
+ docs/wasm-shaper.md | 17 +++++++++++++++--
+ 1 file changed, 15 insertions(+), 2 deletions(-)
+
+commit 134cc8edfa14bd50be0802f644f36b03030d17a7
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Wed May 17 16:58:49 2023 +0100
+
+    [wasm] [docs] How to build
+
+ docs/wasm-shaper.md | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+commit 5543d05885011d5acb0ef53759a85e759168918f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 17 17:29:44 2023 +0200
+
+    [subset] Use vector instead of map for glyph bounds (#4232)
+    
+    * [subset] Use vector instead of map for glyph bounds
+    
+    Is faster.
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/4231
+    
+    * [subset] initialize bounds_vec value to 0xFFFFFFFF
+    
+    Some non-EMPTY glyph might have 0 bounds width/height
+    
+    ---------
+    
+    Co-authored-by: Qunxin Liu <qxliu@google.com>
+
+ src/OT/glyf/Glyph.hh              |  8 ++++----
+ src/hb-ot-hmtx-table.hh           | 12 +++++++-----
+ src/hb-subset-plan-member-list.hh |  4 ++--
+ src/hb-subset-plan.cc             | 11 +++++++++--
+ 4 files changed, 22 insertions(+), 13 deletions(-)
+
+commit ccfd7ef08c28c2f49d7fc52dbbc4b3fa7461b5e5
+Merge: c248fd913 6ed792ef4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 17 16:00:33 2023 +0200
+
+    Merge pull request #4131 from harfbuzz/wasm
+    
+    [wasm] WebAssembly shaper
+
+commit 6ed792ef4b00287e16e0b5eda7fe9488e6060e9a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 17 07:58:27 2023 -0600
+
+    [meson] Report WebAssembly build
+
+ meson.build       | 3 ++-
+ meson_options.txt | 2 +-
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+commit 56af88d04848dec4d4d4ad6d713b22d92edff7e8
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Wed May 17 12:38:59 2023 +0100
+
+    [wasm] More thorough API docs
+
+ docs/wasm-shaper.md | 368 +++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 367 insertions(+), 1 deletion(-)
+
+commit c248fd91334feb0a427051aab75dfe9fb93f6d22
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 10 01:44:10 2023 -0600
+
+    [hash] Comment
+
+ src/hb-algs.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 42f4dab8dbd0fab994170047700076fbf1c85a23
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 10 01:11:32 2023 -0600
+
+    [hash] Switch to Knuth multiplicative hash
+    
+    Wow, the old adhoc one was why the cmap test was timing out!
+
+ src/hb-algs.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 0270e3e97492d975c7f65bb01dd819a4c9314cae
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 23:46:18 2023 -0600
+
+    [map] Reinstate quadratic probing
+
+ src/hb-map.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 19b628bdf074a30c222b04b5f2c50f1db655f03b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 23:40:07 2023 -0600
+
+    Revert "[map] Implement Robinhood hashing"
+    
+    This reverts commit 705617856818056a44a627f340c91e335c57f310.
+
+ src/hb-algs.hh |  2 +-
+ src/hb-map.hh  | 40 ++++++----------------------------------
+ 2 files changed, 7 insertions(+), 35 deletions(-)
+
+commit 18c3ba5018a7c1cd6701775e397d699cb7e7a11b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 22:44:22 2023 -0600
+
+    [map] Implement Robinhood hashing
+    
+    Numbers are not improved though. :(
+
+ src/hb-algs.hh |  2 +-
+ src/hb-map.hh  | 40 ++++++++++++++++++++++++++++++++++------
+ 2 files changed, 35 insertions(+), 7 deletions(-)
+
+commit 2133aa2407657d0b3b4b73a4951c05ed26d055f2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 21:06:17 2023 -0600
+
+    [map] Inline code for set()
+
+ src/hb-map.hh | 32 ++++++++++++++------------------
+ 1 file changed, 14 insertions(+), 18 deletions(-)
+
+commit 5bf5188ea2d31cd162f61b923e56614c446e7ad3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 20:47:46 2023 -0600
+
+    [map] Simplify del()
+
+ src/hb-map.hh | 20 ++++++++++++--------
+ 1 file changed, 12 insertions(+), 8 deletions(-)
+
+commit 2ffec3a6f4881cabab6f4ca8d3e200a952f2d083
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 20:44:23 2023 -0600
+
+    [map] Shuffle fetch_item
+
+ src/hb-map.hh | 28 ++++++++++++++++------------
+ 1 file changed, 16 insertions(+), 12 deletions(-)
+
+commit 1dc99128b92f4bb7b2737c129961082e642f7c4c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 20:37:12 2023 -0600
+
+    [map] Separate has() code from set() code
+
+ src/hb-map.hh | 26 ++++++++++++++++++--------
+ 1 file changed, 18 insertions(+), 8 deletions(-)
+
+commit 2dd0803c850521d104bb927de8fc54e2b9d64166
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 20:35:09 2023 -0600
+
+    [map] Downgrade from quadratic to linear probing
+
+ src/hb-map.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 498197671a8d828d4a4254818693dbd502707ed2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 20:24:12 2023 -0600
+
+    [map] Write get() in terms of has()
+
+ src/hb-map.hh | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+commit f37941bb52457f3be81f34de62e4f5b93f048cf0
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue May 9 11:53:15 2023 -0700
+
+    [instancer] add tests for instancer-solver from python test suite
+    
+    Also fix bug in the solver code
+
+ src/Makefile.am                     |   5 +
+ src/hb-subset-instancer-solver.cc   |   4 +-
+ src/meson.build                     |   1 +
+ src/test-subset-instancer-solver.cc | 351 ++++++++++++++++++++++++++++++++++++
+ 4 files changed, 359 insertions(+), 2 deletions(-)
+
+commit 39ac79a7f5afb812880e8f376b00a85c509c0cf5
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed May 10 10:22:49 2023 -0700
+
+    address review comments
+
+ src/hb-ot-stat-table.hh           | 20 ++++-------------
+ src/hb-ot-var-fvar-table.hh       | 47 ++++++++++++++++++++-------------------
+ src/hb-subset-instancer-solver.hh |  3 +++
+ src/hb-subset-plan.cc             |  3 ---
+ 4 files changed, 31 insertions(+), 42 deletions(-)
+
+commit 58f68dd37a595c51f8e9545de165cd5a1ff5479e
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu May 4 14:25:14 2023 -0700
+
+    [instancer] wrap hb_subset_input_Set_axis_range() under experimental
+    
+    Also add notes: it's not actually working yet.
+
+ docs/harfbuzz-sections.txt | 1 +
+ src/gen-def.py             | 1 +
+ src/hb-subset-input.cc     | 6 +++++-
+ src/hb-subset.h            | 2 +-
+ 4 files changed, 8 insertions(+), 2 deletions(-)
+
+commit f3a3c3b29d2c0e4557dc8bc9666bb1efab11af82
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu May 4 13:19:12 2023 -0700
+
+    fix bot
+
+ src/hb-ot-stat-table.hh | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit efc77dc68fea89e8ddc03d09b605e7d6ad6ff240
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu May 4 10:59:09 2023 -0700
+
+    [instancer] update code for collecting FeatureVariationRecord
+
+ src/hb-ot-layout-common.hh | 95 +++++++++++++++++++++++++++++-----------------
+ src/hb-subset-plan.cc      | 27 +++++++++----
+ 2 files changed, 80 insertions(+), 42 deletions(-)
+
+commit bf298e505064e6b02757e31d5557a611a0a065be
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon May 1 13:40:19 2023 -0700
+
+    [instancer ]update OS_2/post/glyf tables to accept Triple for axes positions
+
+ src/OT/glyf/glyf.hh     | 2 +-
+ src/hb-ot-os2-table.hh  | 4 ++--
+ src/hb-ot-post-table.hh | 2 +-
+ 3 files changed, 4 insertions(+), 4 deletions(-)
+
+commit 51c7451bb52ab0a16539b33b46f7d9a725f8f989
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon May 1 13:38:02 2023 -0700
+
+    [instancer] update fvar table to accept Tripe for axes positions
+
+ src/hb-ot-stat-table.hh     |  2 +-
+ src/hb-ot-var-fvar-table.hh | 78 +++++++++++++++++++++++++++++++--------------
+ src/hb-subset-plan.cc       |  2 +-
+ 3 files changed, 56 insertions(+), 26 deletions(-)
+
+commit bf46d566f9522b39cd4d1def1e33335b1918fff1
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon May 1 11:23:51 2023 -0700
+
+    [instancer] update STAT table to accept Triples for axes positions
+
+ src/hb-ot-stat-table.hh | 59 +++++++++++++++++++++++++++++--------------------
+ 1 file changed, 35 insertions(+), 24 deletions(-)
+
+commit 779e8ba080014402fc62ec9dcef3b61d4a5aa21a
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Apr 27 13:48:24 2023 -0700
+
+    [instancer] update subset-plan.cc to accept Triple as axes positions
+
+ src/hb-subset-plan.cc | 27 +++++++++++++++++++--------
+ 1 file changed, 19 insertions(+), 8 deletions(-)
+
+commit 22cca43dedecdec80278d26bd1626c8a1992787f
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Apr 20 14:37:29 2023 -0700
+
+    [instancer ]update internal hashmap to use Triple instead of single value
+    
+    -Added hb-subset-instancer-solver.hh file and moved Triple struct to the
+    head file
+
+ src/Makefile.sources              |  1 +
+ src/hb-subset-input.cc            |  7 ++--
+ src/hb-subset-input.hh            |  3 +-
+ src/hb-subset-instancer-solver.cc | 39 +---------------------
+ src/hb-subset-instancer-solver.hh | 69 +++++++++++++++++++++++++++++++++++++++
+ src/hb-subset-plan-member-list.hh |  8 ++---
+ src/hb-subset-plan.hh             |  4 +++
+ src/meson.build                   |  1 +
+ 8 files changed, 86 insertions(+), 46 deletions(-)
+
+commit 0799afe2b6b9c1e06505a7e6a604cfb597b5c9ef
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Apr 20 14:02:20 2023 -0700
+
+    [instancer] Add hb_subset_input_set_axis_range() API
+
+ src/hb-subset-input.cc | 40 ++++++++++++++++++++++++++++++++++++++++
+ src/hb-subset.h        |  7 +++++++
+ 2 files changed, 47 insertions(+)
+
+commit 5d543d64222c6ce45332d0c188790f90691ef112
+Merge: 4584bcdc3 5d0cc0062
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 19:02:26 2023 -0600
+
+    Merge pull request #4228 from harfbuzz/better-hash
+    
+    Better hash
+
+commit 5d0cc0062a75013a388f6929b59cbfa7939dc6e1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 18:40:35 2023 -0600
+
+    [hash] Disable int hash as it has negative performance gain
+
+ src/hb-algs.hh | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+commit 1fbb08584b172553651a7842ec9ee977991c93c7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 17:11:05 2023 -0600
+
+    [hash] Adjust prime number
+    
+    Previous one wasn't a prime. Ouch!
+
+ src/hb-algs.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 9cc7eb80ffac20cc5cfa90b80bcff2872f6c466b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 16:13:46 2023 -0600
+
+    [hash] Speed-up int64 hash
+
+ src/hb-algs.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4584bcdc326564829d3cee3572386c90e4fd1974
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed May 10 00:20:25 2023 +0300
+
+    7.3.0
+
+ NEWS                   | 21 +++++++++++++++++++++
+ configure.ac           |  2 +-
+ docs/harfbuzz-docs.xml |  1 +
+ meson.build            |  2 +-
+ src/hb-subset-input.cc |  2 +-
+ src/hb-version.h       |  4 ++--
+ 6 files changed, 27 insertions(+), 5 deletions(-)
+
+commit 826fe2c9f78932af8c5aed4ba4db6328f83f44fe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 13:48:38 2023 -0600
+
+    [hash] Wrap specialization in HB_OPTIMIZE_SIZE_MORE
+
+ src/hb-array.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit b2b15fa30aeaad022a7953f2a150442d69e30e5b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 13:39:52 2023 -0600
+
+    [hash] Links
+
+ src/hb-algs.hh  | 3 ++-
+ src/hb-array.hh | 3 +++
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+commit 05567da082b59bc422356c8c10cbe8fc87a6bd13
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 12:22:43 2023 -0600
+
+    Revert "[hash] Use fasthash for integer hash"
+    
+    This reverts commit 3bf758a57071572a0ffae3c359b4cfec5a096312.
+    
+    This was resulting in long chains again :(.
+
+ src/hb-algs.hh | 10 ++--------
+ 1 file changed, 2 insertions(+), 8 deletions(-)
+
+commit bdaa74d25ff5477c72f69249181b5d840cb4cb59
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 11:58:35 2023 -0600
+
+    [hash] Use fasthash for integer hash
+    
+    This seems to speed things up surprisingly.
+
+ src/hb-algs.hh | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+commit a58bbe5408b76c6b22d3b097649b7eef530c3e13
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 12:06:35 2023 -0600
+
+    [set] Use better hash
+
+ src/hb-bit-page.hh | 5 +----
+ src/hb-bit-set.hh  | 6 +++++-
+ 2 files changed, 6 insertions(+), 5 deletions(-)
+
+commit fe3339ea241528652f3480fb061abca3c6bb2ed8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 11:31:06 2023 -0600
+
+    [algs] Add hash for 64bit ints
+
+ src/hb-algs.hh | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit 33ef96b649fd249808af6a13f376efb819e31882
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 11:13:51 2023 -0600
+
+    [glyf] Micro-optimize a few hash operations
+
+ src/OT/glyf/Glyph.hh | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+commit abb92388cc8bebff0cf40cbed0045292e038bcd8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 10:54:54 2023 -0600
+
+    Revert "[map] Adjust resizing criteria"
+    
+    This reverts commit 1fa4b415315257bdbae08e6539f2ca63423572e8.
+
+ src/hb-map.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1fa4b415315257bdbae08e6539f2ca63423572e8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 10:52:58 2023 -0600
+
+    [map] Adjust resizing criteria
+
+ src/hb-map.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f04d08b883d9b4894d5329cec351d2f0ea50590b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 02:14:30 2023 -0600
+
+    [fasthash] Remove GNU extension
+
+ src/hb-algs.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 99f5050ccd35e6e447661af2ed330f509ae9bcd8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 02:07:54 2023 -0600
+
+    [algs] Remove HB_NO_PACKED
+    
+    We depend on packed attribute in fasthash now.
+
+ src/hb-algs.hh | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+commit da619c69c8f1a4be9e29bbc95cf684bf38641468
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 02:06:37 2023 -0600
+
+    [fasthash] Try to fix unaligned access
+
+ src/hb-algs.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 075ecff750088854854147d0b32b88b120693a48
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 01:43:39 2023 -0600
+
+    [hash] Work around g++ bug?!
+    
+    I kid you not. Revert this and see src/test-map loop forever
+    eating your memory freezing your maching.
+    
+    In this loop:
+    
+      {
+        hb_hashmap_t<int, int> m0;
+        hb_hashmap_t<std::string, int> m1;
+        hb_hashmap_t<int, std::string> m2;
+        hb_hashmap_t<std::string, std::string> m3;
+    
+        std::string s;
+        for (unsigned i = 1; i < 1000; i++)
+        {
+          s += "x";
+          m0.set (i, i);
+          m1.set (s, i);
+          m2.set (i, s);
+          m3.set (s, s);
+        }
+      }
+    
+    i will not stop at 1000 and just keeps going.  If you figure out
+    what's going on, please enlighten me!
+
+ src/hb-algs.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9fbab46f2636aabf70ff10acc6c141b147794a2a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 9 01:42:44 2023 -0600
+
+    [cairo] Fix a clang warning
+
+ src/hb-cairo-utils.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e2fd49ff1a419dad6d6dd077aa25c20d054530ff
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 8 23:37:47 2023 -0600
+
+    [hash] Comment
+
+ src/hb-algs.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit fa64e42d755709df2837fcfb8d60ff6d8b1179fb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 8 23:31:52 2023 -0600
+
+    [algs] Adjust int hash
+
+ src/hb-algs.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 078b2a510189088ceda4cf23bc7c0197518831dd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 8 22:28:48 2023 -0600
+
+    [hash] Use a Mersenne prime for int hash
+    
+    And hope that compiler optimizes to int ops instead of modula.
+    
+    Improves chaining it seems.
+    
+    Part of https://github.com/harfbuzz/harfbuzz/pull/4228
+
+ src/hb-algs.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit fe0f7dc57bc7411c7cc7eb80fa44c8dd8c5e4644
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 8 22:19:02 2023 -0600
+
+    [bytes] Use fasthash as hash algorithm
+    
+    Part of https://github.com/harfbuzz/harfbuzz/pull/4228
+
+ src/hb-algs.hh  | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-array.hh | 18 ++------------
+ 2 files changed, 78 insertions(+), 16 deletions(-)
+
+commit 4bbcff2c5c00d4e2029a176c3388ad4fe77945df
+Author: Rod S <rsheeter@google.com>
+Date:   Mon May 8 20:29:35 2023 -0700
+
+    Help noobs who don't know their segment properties
+
+ docs/usermanual-getting-started.xml | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit c005e3a2e30eaea700e67907dc816709263b4046
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 8 16:33:31 2023 -0600
+
+    [bytes] Simplify hash function
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/4227
+
+ src/hb-array.hh | 32 ++++----------------------------
+ 1 file changed, 4 insertions(+), 28 deletions(-)
+
+commit 0e026808036f59d3ea4e5954b1a19fcfcb9a9702
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 8 16:31:58 2023 -0600
+
+    [hash] Add hash impl for integers
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/4227
+
+ src/hb-algs.hh | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit b7a8d23bc8594c84c72d54dbbffa1c1acbb92c67
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 8 14:32:24 2023 -0600
+
+    [map] Micro-optimize for hb_map_t
+
+ src/hb-map.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 2f05c32c3632062a593022d24e628aa991f30939
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 8 14:29:07 2023 -0600
+
+    [Coverage] Minor access arrayZ directly in a couple places
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit c0e6a96af365d678037819944daf8176c5649bfd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 8 14:02:55 2023 -0600
+
+    [bit-set] Minor access an array directly
+
+ src/hb-bit-set.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f4d3b49e5d3b6e8c64aa92caa9c3666507e04b0a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 8 13:59:48 2023 -0600
+
+    [set] Micro-optimize iteration
+
+ src/hb-bit-set.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 3416086de3ac9c3f36e3e9d566fa141ccc915573
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 8 13:39:48 2023 -0600
+
+    [set] Optimize is_subset()
+
+ src/hb-bit-set.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 45afbdff2c6bf35403e635b9be453408e673cbd4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 8 11:19:55 2023 -0600
+
+    [array] Add a const to a cast
+
+ src/hb-array.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 4ad443d5eabeaf0b38b70631cea8de345f00ef7b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 8 10:14:43 2023 -0600
+
+    [Coverage/ClassDef] Don't call qsort if sorted already
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 8 +++++++-
+ src/hb-ot-layout-common.hh              | 9 ++++++++-
+ 2 files changed, 15 insertions(+), 2 deletions(-)
+
+commit 3c2a925b7fef104597dd37848f85a963307f16e4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 8 09:43:01 2023 -0600
+
+    [graph] Micro-optimize
+
+ src/graph/serialize.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 62bc2841d939760a43c4118ad92818cb5a923273
+Merge: b6516f3bb 8eb9f3126
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 8 09:12:34 2023 -0600
+
+    Merge pull request #4221 from googlefonts/user_glyph_map
+    
+    [subset] Add API method to allow a custom glyph map to be specified.
+
+commit b6516f3bbf6f52aced2a9b34ade44c2f631e149b
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon May 8 15:31:24 2023 +0300
+
+    [cff] Fix the case of HB_OT_TAG_cff(1|2) macros
+    
+    Should be upper case like other HB_OT_TAG_* macros of upper case tables.
+
+ src/hb-ot-cff1-table.hh | 4 ++--
+ src/hb-ot-cff2-table.hh | 4 ++--
+ src/hb-subset.cc        | 8 ++++----
+ 3 files changed, 8 insertions(+), 8 deletions(-)
+
+commit 8df5cdbcda495a582e72a7e2ce35d6106401edce
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun May 7 15:49:50 2023 -0600
+
+    [Coverage/ClassDef] Handle glyphID overflow in serialize
+
+ src/OT/Layout/Common/Coverage.hh | 7 +++++++
+ src/hb-ot-layout-common.hh       | 9 ++++++++-
+ 2 files changed, 15 insertions(+), 1 deletion(-)
+
+commit 6d7de2f8dd551920367017cf169750b611971d52
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun May 7 15:23:05 2023 -0600
+
+    [array] Implement FNV-1a hash function
+
+ src/hb-array.hh | 34 ++++++++++++++++++++++++++--------
+ 1 file changed, 26 insertions(+), 8 deletions(-)
+
+commit ebdeab8baaa0cd7a6d243bb1b2f2604bef167eea
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun May 7 14:18:36 2023 -0600
+
+    [array] Improve hash function
+    
+    Previously all arrays of 0 bytes were getting same hash.
+
+ src/hb-array.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit f772071f3e7241367d56c5a6f82d394bea2b829e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun May 7 13:42:00 2023 -0600
+
+    [subset-plan] Another error check
+
+ src/hb-subset-accelerator.hh | 2 ++
+ src/hb-subset-plan.cc        | 2 ++
+ 2 files changed, 4 insertions(+)
+
+commit 5ec0ccad638597fca929a84cfdf70ee3878308af
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat May 6 13:36:39 2023 -0600
+
+    Undef a macro after use
+
+ src/hb-subset-plan-member-list.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 4bb78e353031ade00eb4d486a1cf8073f23fee7d
+Author: denis rochette <8184192+denis-rochette@users.noreply.github.com>
+Date:   Sat May 6 16:27:46 2023 +0200
+
+    Typo in the documentation of hb-ot-math
+
+ src/hb-ot-math.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 86658df5d29308d66ddead03f1112442df04ec27
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 5 16:10:46 2023 -0600
+
+    [ClassDef] Fix a fuzzer issue
+    
+    Don't qsort an array that failed to allocate!
+    
+    Fixes https://oss-fuzz.com/testcase-detail/6512559172485120
+
+ src/hb-ot-layout-common.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit cda646a598207642721b753ef5abcebb2525f61b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 5 15:57:13 2023 -0600
+
+    [subset-plan] Check success of all object members
+
+ src/hb-subset-plan-member-list.hh | 8 ++++----
+ src/hb-subset-plan.cc             | 4 ++++
+ 2 files changed, 8 insertions(+), 4 deletions(-)
+
+commit 5f5660fc5d80a0ce84066206e8e9bad6e20a24d4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 5 15:52:17 2023 -0600
+
+    [subset] In glyf-closure always add current glyph
+    
+    Bad things can happen otherwise if one composite glyph depleted
+    the op count.
+
+ src/hb-subset-plan.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 5468b08c0238d16f1a0360f759b44af12fefbb99
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 5 15:49:38 2023 -0600
+
+    [subset-plan] Move all object members to a new file
+    
+    To automatically check for their errors.
+
+ src/Makefile.sources              |   1 +
+ src/hb-subset-plan-member-list.hh | 126 ++++++++++++++++++++++++++++++++++++++
+ src/hb-subset-plan.hh             |  90 ++-------------------------
+ src/meson.build                   |   1 +
+ 4 files changed, 132 insertions(+), 86 deletions(-)
+
+commit 71910fdf9128ca3068e9546a262f61cbf6e8c8f3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 5 15:37:07 2023 -0600
+
+    [Coverage] Remove unnecessary check
+
+ src/OT/Layout/Common/Coverage.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ee9b631d19d6e51825a7b2be4579b7394084a162
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 5 10:26:57 2023 -0600
+
+    [SingleSubst] Fix condition to upgrade to beyond-64k
+
+ src/OT/Layout/GSUB/SingleSubst.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 8eb9f31263746a8942fd5dbab90094930ac104bd
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri May 5 15:56:50 2023 +0000
+
+    [subset] s/Since/XSince/.
+
+ src/hb-subset-input.cc | 2 +-
+ src/hb-subset.h        | 6 +++---
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit 5d4f3ff690aa8358b214c90ae7942766d68c12f9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 5 07:10:02 2023 -0600
+
+    [TINY] Fix build
+
+ src/hb-ot-font.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 7e676cb4cf66c0a70d6b240ed124394fab14b3b8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 5 07:07:00 2023 -0600
+
+    [config] Add HB_NO_OT_FONT_ADVANCE_CACHE
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/4220
+
+ src/hb-config.hh  | 1 +
+ src/hb-ot-font.cc | 8 ++++----
+ 2 files changed, 5 insertions(+), 4 deletions(-)
+
+commit 8831ba7f5516038cf70f5fe34984170931387fdc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 5 07:03:25 2023 -0600
+
+    [config] Add HB_NO_OT_FONT_CMAP_CACHE
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/4220
+
+ src/hb-config.hh  |  1 +
+ src/hb-ot-font.cc | 22 +++++++++++++++++++---
+ 2 files changed, 20 insertions(+), 3 deletions(-)
+
+commit 0e9ebf1062af21605d02838f0de4842d1e902794
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 5 06:57:51 2023 -0600
+
+    [config] Add HB_OPTIMIZE_SIZE_MORE and enable in HB_TINY
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/4220
+
+ src/OT/Layout/GSUB/LigatureSet.hh | 2 ++
+ src/hb-config.hh                  | 9 ++++++---
+ 2 files changed, 8 insertions(+), 3 deletions(-)
+
+commit da175c69356929a04ca1688658b8fc846d7d4366
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 5 06:51:59 2023 -0600
+
+    [config] Add HB_MINIMIZE_MEMORY_USAGE
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/4220
+
+ src/hb-config.hh | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+commit bbf4cfa393d26c7cc7e91cc8c859009261847f24
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 5 06:51:10 2023 -0600
+
+    [config] Add missing HB_NO_BORING_EXPANSION options
+    
+    Those others are only HB_EXPERIMENTAL_API anyway, but still.
+
+ src/hb-config.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit d339298f371902e9a09ca7e0708893a15a739f0c
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri May 5 06:00:30 2023 +0000
+
+    [subset] fix hb_subset_input_old_to_new_gid_mapping method comment.
+
+ src/hb-subset-input.cc | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+commit 374a9a9f5eefd40822c48707bd2126df3505b595
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri May 5 05:58:15 2023 +0000
+
+    [subset] restore accidentally removed function doc.
+
+ docs/harfbuzz-sections.txt | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 3021b2dbe2a18724f345f881eba7299a8bf00499
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri May 5 05:57:05 2023 +0000
+
+    [subset] change glyph mapping api to return a mutable map.
+    
+    Maintains consistency with our other set based api methods.
+
+ docs/harfbuzz-sections.txt |  2 +-
+ src/hb-subset-input.cc     | 27 +++++++++++----------------
+ src/hb-subset-plan.cc      | 35 +++++++++++++++++++++++++++--------
+ src/hb-subset.h            |  6 ++----
+ util/hb-subset.cc          |  4 +---
+ 5 files changed, 42 insertions(+), 32 deletions(-)
+
+commit d4c13225477df6d137c08bdda247add6e66ec84c
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu May 4 23:04:35 2023 +0000
+
+    [subset] Add new glyph map method to docs.
+
+ docs/harfbuzz-sections.txt | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 77a815542588a257f44c9310961797717e435f64
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu May 4 23:01:56 2023 +0000
+
+    [subset] Add some basic tests for a provided glyph map.
+
+ src/hb-subset-input.cc                                   |   9 +++------
+ src/hb-subset-plan.cc                                    |  10 ++++++++--
+ .../Roboto-Regular.glyph_map_roboto.41,43,61,66,69.ttf   | Bin 0 -> 3996 bytes
+ ...gular.glyph_map_roboto_retain_gids.41,43,61,66,69.ttf | Bin 0 -> 7936 bytes
+ test/subset/data/profiles/glyph_map_roboto.txt           |   2 ++
+ .../data/profiles/glyph_map_roboto_retain_gids.txt       |   4 ++++
+ test/subset/data/tests/glyph_map.tests                   |   9 +++++++++
+ test/subset/generate-expected-outputs.py                 |   4 +++-
+ 8 files changed, 29 insertions(+), 9 deletions(-)
+
+commit 3194963657a3049961fb64c9be86c1629afcea4b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 4 16:29:48 2023 -0600
+
+    Revert "[layout] Cache subtable coverages in hb_map_t"
+    
+    This reverts commit 7a715d74e06720c17d28ba7b4c3da0b583f8d1d3.
+
+ src/OT/Layout/GPOS/CursivePosFormat1.hh            |  4 +-
+ src/OT/Layout/GPOS/MarkBasePosFormat1.hh           |  5 +-
+ src/OT/Layout/GPOS/MarkLigPosFormat1.hh            |  5 +-
+ src/OT/Layout/GPOS/MarkMarkPosFormat1.hh           |  5 +-
+ src/OT/Layout/GPOS/PairPosFormat1.hh               |  6 +-
+ src/OT/Layout/GPOS/PairPosFormat2.hh               |  4 +-
+ src/OT/Layout/GPOS/PosLookup.hh                    |  4 +-
+ src/OT/Layout/GPOS/SinglePosFormat1.hh             |  4 +-
+ src/OT/Layout/GPOS/SinglePosFormat2.hh             |  8 ++-
+ src/OT/Layout/GSUB/AlternateSubstFormat1.hh        |  8 ++-
+ src/OT/Layout/GSUB/LigatureSubstFormat1.hh         |  8 ++-
+ src/OT/Layout/GSUB/MultipleSubstFormat1.hh         |  8 ++-
+ .../Layout/GSUB/ReverseChainSingleSubstFormat1.hh  |  9 ++-
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh           |  4 +-
+ src/OT/Layout/GSUB/SingleSubstFormat2.hh           |  8 ++-
+ src/OT/Layout/GSUB/SubstLookup.hh                  |  4 +-
+ src/hb-ot-layout-gsubgpos.hh                       | 70 ++++++++++++----------
+ 17 files changed, 99 insertions(+), 65 deletions(-)
+
+commit 7a715d74e06720c17d28ba7b4c3da0b583f8d1d3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 4 16:28:11 2023 -0600
+
+    [layout] Cache subtable coverages in hb_map_t
+    
+    Proof-of-concept. Going to revert. Memory consumption is more
+    than I like. It does speed up Roboto shaping another 15% though.
+    Perhaps if we could add logic to choose which subtables to
+    cache, this might be a useful approach.
+
+ src/OT/Layout/GPOS/CursivePosFormat1.hh            |  4 +-
+ src/OT/Layout/GPOS/MarkBasePosFormat1.hh           |  5 +-
+ src/OT/Layout/GPOS/MarkLigPosFormat1.hh            |  5 +-
+ src/OT/Layout/GPOS/MarkMarkPosFormat1.hh           |  5 +-
+ src/OT/Layout/GPOS/PairPosFormat1.hh               |  6 +-
+ src/OT/Layout/GPOS/PairPosFormat2.hh               |  4 +-
+ src/OT/Layout/GPOS/PosLookup.hh                    |  4 +-
+ src/OT/Layout/GPOS/SinglePosFormat1.hh             |  4 +-
+ src/OT/Layout/GPOS/SinglePosFormat2.hh             |  8 +--
+ src/OT/Layout/GSUB/AlternateSubstFormat1.hh        |  8 +--
+ src/OT/Layout/GSUB/LigatureSubstFormat1.hh         |  8 +--
+ src/OT/Layout/GSUB/MultipleSubstFormat1.hh         |  8 +--
+ .../Layout/GSUB/ReverseChainSingleSubstFormat1.hh  |  9 +--
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh           |  4 +-
+ src/OT/Layout/GSUB/SingleSubstFormat2.hh           |  8 +--
+ src/OT/Layout/GSUB/SubstLookup.hh                  |  4 +-
+ src/hb-ot-layout-gsubgpos.hh                       | 70 ++++++++++------------
+ 17 files changed, 65 insertions(+), 99 deletions(-)
+
+commit 98e73192f4aac0419d275857993359676bd94f94
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu May 4 22:20:06 2023 +0000
+
+    [subset] Add command line flag to provide a gid mapping.
+
+ src/hb-subset-input.cc |  5 +++++
+ util/hb-subset.cc      | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 65 insertions(+)
+
+commit 975980d36867728da42908a9a3c95373a32b3d30
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 4 15:56:06 2023 -0600
+
+    [gsubgpos] Add apply_cached() as separate method
+    
+    In prep for some other work.
+
+ src/hb-ot-layout-gsubgpos.hh | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+commit 779e8297fa53f95db2efe1d0e9e734951e0e33ab
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu May 4 19:31:23 2023 +0000
+
+    [subset] fix requested_glyph_map presence check.
+
+ src/hb-subset-plan.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e14020b27ac71f44a46374ebdce9e0ac46160118
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu May 4 19:24:01 2023 +0000
+
+    [subset] remove return value from mapping setting function.
+
+ src/hb-subset-input.cc | 5 ++---
+ src/hb-subset.h        | 2 +-
+ 2 files changed, 3 insertions(+), 4 deletions(-)
+
+commit 6826634714de899f5f000a6897deb43825c8ba78
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu May 4 19:18:54 2023 +0000
+
+    [subset] apply the user supplied glyph map.
+
+ src/hb-subset-input.cc | 18 ++++++++++++++++++
+ src/hb-subset-plan.cc  | 31 ++++++++++++++++++++++++++++++-
+ 2 files changed, 48 insertions(+), 1 deletion(-)
+
+commit e711e305c8d59b9e381e9bf7aa7fd7f85d5008b7
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu May 4 18:47:55 2023 +0000
+
+    [subset] Add new subsetting API method to receive a user specified glyph mapping.
+
+ src/hb-subset-input.cc | 16 ++++++++++++++++
+ src/hb-subset-input.hh |  1 +
+ src/hb-subset.h        |  5 +++++
+ 3 files changed, 22 insertions(+)
+
+commit 1be39729140a6d726de164746e516c1fe5afcb19
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 4 13:18:34 2023 -0600
+
+    [subset] Support unordered glyphlist in Coverage/ClassDef serialize
+
+ src/OT/Layout/Common/Coverage.hh        |  9 +++++++--
+ src/OT/Layout/Common/CoverageFormat2.hh |  1 +
+ src/OT/Layout/Common/RangeRecord.hh     | 12 ++++++++++++
+ src/hb-ot-layout-common.hh              |  2 ++
+ 4 files changed, 22 insertions(+), 2 deletions(-)
+
+commit a10fad7cc233e70ac647081eaeb9e0c4ecbb1e1d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 4 11:32:07 2023 -0600
+
+    [config] Add HB_NO_GDEF_CACHE
+
+ src/OT/Layout/GDEF/GDEF.hh | 9 +++++++++
+ src/hb-config.hh           | 1 +
+ 2 files changed, 10 insertions(+)
+
+commit e138319fccd9168bbf94d0047e9b33e540f8a25d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 4 11:28:50 2023 -0600
+
+    [config] Allow overriding HB_OPTIMIZE_SIZE
+
+ src/hb-config.hh | 17 ++++++-----------
+ 1 file changed, 6 insertions(+), 11 deletions(-)
+
+commit 319a488b3903cf92c3b45d1772717168a10f94d7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 4 10:36:48 2023 -0600
+
+    [GDEF] Fix null check
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5920994267889664
+
+ src/OT/Layout/GDEF/GDEF.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3f2401e2f11e730050632982f286fe534a2881ad
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 3 16:56:52 2023 -0600
+
+    [layout] Don't init iters successively multiple times
+
+ src/hb-ot-layout-gsubgpos.hh | 8 ++++----
+ src/hb-ot-layout.cc          | 9 +++++----
+ 2 files changed, 9 insertions(+), 8 deletions(-)
+
+commit 959f16343b630216c74e2a2de70f783af45e8c5f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 3 16:27:41 2023 -0600
+
+    [gsubgpos] Minor reduce variable scope
+
+ src/hb-ot-layout-gsubgpos.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit fb795dc3c519a34222d32fff0a4309c6e20d77a8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 3 15:17:20 2023 -0600
+
+    [GPOS] Optimize iterator reset
+    
+    Speeds up Gulzar shaping 5%.
+
+ src/OT/Layout/GPOS/CursivePosFormat1.hh  |  2 +-
+ src/OT/Layout/GPOS/MarkMarkPosFormat1.hh |  2 +-
+ src/OT/Layout/GPOS/PairPosFormat1.hh     |  2 +-
+ src/OT/Layout/GPOS/PairPosFormat2.hh     |  2 +-
+ src/hb-ot-layout-gsubgpos.hh             | 10 ++++++++++
+ 5 files changed, 14 insertions(+), 4 deletions(-)
+
+commit 0c1637b60683bcbd11d2aa55cf0df05c3cefe573
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 3 15:04:57 2023 -0600
+
+    [aat] Fix HB_NO_OT_LAYOUT build
+
+ src/hb-aat-layout.cc | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+commit 8a8fc37c42135b3ed524e4179bcc4add854ae195
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 3 14:57:00 2023 -0600
+
+    [GDEF] Use a cache for glyph classes
+    
+    Shows 5% speedup for Roboto shaping.
+
+ src/OT/Layout/GDEF/GDEF.hh   | 15 +++++++++++++++
+ src/hb-null.hh               |  2 +-
+ src/hb-ot-layout-gsubgpos.hh | 10 +++++++++-
+ src/hb-ot-layout.cc          |  2 +-
+ 4 files changed, 26 insertions(+), 3 deletions(-)
+
+commit 323a1fe4968029fd036948533ead5c0ba69b9df2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 3 13:52:43 2023 -0600
+
+    [PairPos] Fix what I broke
+
+ src/OT/Layout/GPOS/PairPosFormat1.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a6f5f0dc4aa9b1551ccdb3a18a8b4c6589ee72cc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 3 13:45:39 2023 -0600
+
+    [PairSet] Micro-optimize
+
+ src/OT/Layout/GPOS/PairSet.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 4e495eb0a78cd2b51a09c4fdeaa9f1cd9d13116b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 3 13:40:46 2023 -0600
+
+    [PairPos] Add an unlikely
+
+ src/OT/Layout/GPOS/PairPosFormat1.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 5528bdd46fc0a1e6c34de1fbe0f79becc12f00ab
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 3 13:35:10 2023 -0600
+
+    [PairPos] Remove a likely
+
+ src/OT/Layout/GPOS/PairPosFormat2.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ae0fe02d13f1ecd1ede03d0523308cba4b88a738
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 3 13:24:08 2023 -0600
+
+    [Ligature] Use slow path if 2 or fewer ligatures
+
+ src/OT/Layout/GSUB/LigatureSet.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit ddd6c2e7a2d11b91d49681c1a8609010dafefad8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 3 13:16:39 2023 -0600
+
+    [Ligature] Micro-optimize more
+
+ src/OT/Layout/GSUB/LigatureSet.hh | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+commit 045ae4b0b5358503ddf445d2a5bfd6427a9ee4f2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 3 13:08:43 2023 -0600
+
+    [GPOS] Micro-optimize
+
+ src/OT/Layout/GPOS/CursivePosFormat1.hh  | 2 +-
+ src/OT/Layout/GPOS/MarkMarkPosFormat1.hh | 4 ++--
+ src/OT/Layout/GPOS/PairPosFormat2.hh     | 2 +-
+ 3 files changed, 4 insertions(+), 4 deletions(-)
+
+commit 0fe90ebc00d07a1a636ed0dfdd72f5586b51bcfa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 3 12:49:31 2023 -0600
+
+    [Ligature] Micro-optimize
+
+ src/OT/Layout/GSUB/LigatureSet.hh | 16 ++++++++++++----
+ 1 file changed, 12 insertions(+), 4 deletions(-)
+
+commit 51061d2854cbf55de422f46b31e1746b8657a4e1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 3 12:46:04 2023 -0600
+
+    [Ligature] Minor tweak to recent code
+
+ src/OT/Layout/GSUB/LigatureSet.hh | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+commit 7881eadffc6314e0da29b27125550a1c5d46819f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 2 14:56:18 2023 -0600
+
+    [Ligature] Speed up
+    
+    Match the first component of the ligature in the LigatureSet loop.
+    
+    Speeds up Roboto shaping by 25%. I don't think it breaks anything.
+    The test suite seems happy.
+
+ src/OT/Layout/GSUB/Ligature.hh    |  2 +-
+ src/OT/Layout/GSUB/LigatureSet.hh | 43 +++++++++++++++++++++++++++++++++++++--
+ 2 files changed, 42 insertions(+), 3 deletions(-)
+
+commit 95f155573c84dd3b74ae83183d23faac7f364f08
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 2 16:37:31 2023 -0600
+
+    [PairPosFormat2] Micro-optimize and don't kern if class2=0
+    
+    If class2=0 we expect no kerning to happen. Just bail out.
+
+ src/OT/Layout/GPOS/PairPosFormat2.hh | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+commit 5996715436cdd303138653c598acfe5974566c16
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 2 15:52:43 2023 -0600
+
+    [PairPos2] Micro-optimize
+
+ src/OT/Layout/GPOS/PairPosFormat2.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 49ac5e11ef6000de139f1e823d5fc43ae6f8f412
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 2 12:12:26 2023 -0600
+
+    [match_input] Micro-optimize
+
+ src/hb-ot-layout-gsubgpos.hh | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+commit 7e7f1d0414c9128ce2e09659711f45e6b0f74c39
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 2 12:06:00 2023 -0600
+
+    Drop a pair of parantheses from likely/unlikely
+    
+    Such that "if likely(...)" wouldn't compile.
+
+ src/hb.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit db730f46d093b69667ad430785ca50fc32f2172c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 2 11:55:10 2023 -0600
+
+    Simplify likely/unlikely
+    
+    This surprisingly saves bytes and speeds up.
+
+ src/hb.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 2f9945ca0191c316fa82c1fb5fa553bc4aa50b0c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 2 11:33:31 2023 -0600
+
+    [Glyph] Only treat numContours=-1 as Composite
+    
+    Leave the other negative numbers as empty glyph.
+
+ src/OT/glyf/Glyph.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit db23be642ff13706333069ef895f7b6559a9036b
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue May 2 00:06:08 2023 +0000
+
+    [subset] clamp head *Min/*Max values to fit within 16 bit signed int.
+    
+    Fixes fuzzer https://oss-fuzz.com/testcase-detail/4549472192692224.
+
+ src/OT/glyf/Glyph.hh                                     |  11 +++++++----
+ ...-testcase-minimized-hb-subset-fuzzer-4549472192692224 | Bin 0 -> 1634 bytes
+ 2 files changed, 7 insertions(+), 4 deletions(-)
+
+commit a8b8eb53c3de9830ccd8e1444a24eee430c2dc74
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 1 16:56:29 2023 -0600
+
+    [Coverage] Micro-optimize
+
+ src/OT/Layout/Common/Coverage.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit af21ea359c1463d4b1b0f78d43fa695788098277
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 1 16:34:50 2023 -0600
+
+    [Coverage/serialize] Micro-optimize
+
+ src/OT/Layout/Common/Coverage.hh        | 5 ++---
+ src/OT/Layout/Common/CoverageFormat2.hh | 6 +++---
+ 2 files changed, 5 insertions(+), 6 deletions(-)
+
+commit 491f2968cd964c14c86642c5c881be5e16f12d62
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 1 15:58:57 2023 -0600
+
+    [gvar] Micro-optimize
+    
+    We don't need the flag in the case of apply_to_all.
+
+ src/hb-ot-var-gvar-table.hh | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit 19d8328b639a7520f24dea0ada086cbff1ad90eb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 1 15:54:06 2023 -0600
+
+    [VarComposite] Minor use pad instead of StructAfter
+
+ src/OT/glyf/VarCompositeGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1b74cd7c2df711007b9bc252c891618d5250affd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 1 15:41:12 2023 -0600
+
+    [gvar] Micro-optimize
+
+ src/hb-ot-var-gvar-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 267ecd20c8995c146c45bf8e37fb25fa6e7b9b8b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 1 14:05:17 2023 -0600
+
+    [normalize] Micro-optimize
+
+ src/hb-ot-shape-normalize.cc | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+commit 577bc8a2391ad7bd727b0268ed711c1d10065a14
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 1 14:01:08 2023 -0600
+
+    [layout] Micro-optimize
+
+ src/hb-ot-layout.cc | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit 5b78e9a92443eea0aaf62228f6a93a62c7d39410
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 1 13:45:42 2023 -0600
+
+    [layout] Whitespace
+
+ src/hb-ot-layout.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3f9eb03b40251b7c27a2d9935db31091fc8a1586
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 1 12:49:40 2023 -0600
+
+    [graph] Micro-optimize
+
+ src/graph/graph.hh | 64 +++++++++++++++++++++++++++++++-----------------------
+ 1 file changed, 37 insertions(+), 27 deletions(-)
+
+commit 1cbb85dc84bf3f581556fcdb1eeca8822c8d3095
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Apr 30 11:31:46 2023 -0600
+
+    [Glyph] Protect against an underflow
+
+ src/OT/glyf/Glyph.hh | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+commit c7721f7df54a95701b1a4f0ce563aa8e3c0ba49d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Apr 30 11:28:40 2023 -0600
+
+    [Glyph] Reuse variables
+
+ src/OT/glyf/Glyph.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit e826d94afe1eab70817db7f32e9c5f9597a3da84
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Apr 30 11:11:19 2023 -0600
+
+    Call roundf() instead of _hb_roundf()
+    
+    The former is defined as a macro expanding to the latter.
+
+ src/OT/Color/COLR/COLR.hh  | 8 ++++----
+ src/OT/Layout/GPOS/GPOS.hh | 2 +-
+ src/hb-ot-metrics.cc       | 2 +-
+ 3 files changed, 6 insertions(+), 6 deletions(-)
+
+commit fbffd4e65e65843ab149c43df417882fe08683d9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Apr 30 10:45:19 2023 -0600
+
+    [SimpleGlyph] Handle cubic curves when instancing
+
+ src/OT/glyf/SimpleGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 85a0a123389a54ea8925a8f84030eb687f82bf47
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Apr 30 10:40:50 2023 -0600
+
+    [SimpleGlyph] Relax types
+
+ src/OT/glyf/SimpleGlyph.hh | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit 2e5e566504b67fa7495bf017aded25f771d5a690
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Apr 30 10:23:58 2023 -0600
+
+    [SimpleGlyph] Micro-optimize
+
+ src/OT/glyf/SimpleGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 7b9832deab83d406052a8a8fcd6440bd018ca064
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Apr 29 12:56:07 2023 -0600
+
+    [buffer] Whitespace
+
+ src/hb-buffer.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 700975f732be2eb9b31d538e43a4909311851f55
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Apr 29 11:23:56 2023 -0600
+
+    [gvar/glyf] Minor save a variable
+
+ src/OT/glyf/Glyph.hh        |  3 ++-
+ src/hb-ot-var-gvar-table.hh | 11 ++++++++---
+ 2 files changed, 10 insertions(+), 4 deletions(-)
+
+commit 07be0b6878a2e1948cbd32bbce111b44b53beda3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Apr 29 11:09:28 2023 -0600
+
+    [VarComposite] Minor micro-optimize
+
+ src/OT/glyf/VarCompositeGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ecd0f859bde42d7883746e8ea7f00bd56ef4cd35
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Apr 29 10:51:59 2023 -0600
+
+    [Composite] Minor micro-optimize
+
+ src/OT/glyf/CompositeGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e768754b0fa7153442280b393ff1136a6f8574a3
+Author: Han Seung Min - 한승민 <hanseungmin.ar@gmail.com>
+Date:   Sat Apr 29 17:51:04 2023 +0900
+
+    [buffer] fix `hb_buffer_t::similar` setting `replacement` to `src.invisible`
+    
+    ```cpp
+    void
+    hb_buffer_t::similar (const hb_buffer_t &src)
+    {
+      hb_unicode_funcs_destroy (unicode);
+      unicode = hb_unicode_funcs_reference (src.unicode);
+      flags = src.flags;
+      cluster_level = src.cluster_level;
+      replacement = src.invisible; // <- this should be src.replacement
+      invisible = src.invisible;
+      not_found = src.not_found;
+    }
+    ```
+
+ src/hb-buffer.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit afd432daf52f2df0897b47681230e45e970a8f06
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 28 14:55:37 2023 -0600
+
+    [VarComposite] Fix an #ifdef check
+
+ src/OT/glyf/VarCompositeGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b53f8c25ca49b6401fafbca5ad1f0f95863c323f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 28 14:49:22 2023 -0600
+
+    [path-builder] Simplify initialization
+
+ src/OT/glyf/path-builder.hh | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+commit 6a4b87d0034e2523d3e4b9a0bba63bc89edaebd0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 28 14:48:46 2023 -0600
+
+    [path-builder] Remove double-initialization
+
+ src/OT/glyf/path-builder.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 4a102effd00fac7a6a6b8c4be2aa7c711c6ba91c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 28 14:38:34 2023 -0600
+
+    [gvar] Minor always pass cache
+    
+    We now check for access in calculate_scalar(), so no need to
+    check fof error here.
+
+ src/hb-ot-var-gvar-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 06504cb0a26ff2bff1842b6049e28e427489ea5b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 28 13:13:18 2023 -0600
+
+    [PairPosFormat2] Minor use false instead of 0
+
+ src/OT/Layout/GPOS/PairPosFormat2.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 262f029e20a4e99bc977d767bebf9f03bf1da183
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 28 12:57:24 2023 -0600
+
+    [algs] Undo touching HACKMEM 169
+
+ src/hb-algs.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 9ed43dc50059ce1710fbf5104e210703f1f2f65f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 28 12:38:26 2023 -0600
+
+    [PairPosFormat2] Reuse a value
+
+ src/OT/Layout/GPOS/PairPosFormat2.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 859f7d41cba08731de9b45e87aa37c877454e801
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 28 12:22:11 2023 -0600
+
+    [set-digest] Comment
+
+ src/hb-set-digest.hh | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+commit bd62a91d03034f9f1600b6994b7f3cff2f76bc7d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 28 12:01:21 2023 -0600
+
+    [algs] 64bit popcount
+
+ src/hb-algs.hh | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+commit 5b0d818128163bf915a17e5b696a6805c14738c5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 28 11:40:42 2023 -0600
+
+    [Glyph] Add missing break
+
+ src/OT/glyf/Glyph.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit e5dfb6a4b6122d1e1cb6c3feea985ee68154c736
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 28 11:38:12 2023 -0600
+
+    [SimpleGlyph] Use hb_memset instead of memset
+
+ src/OT/glyf/SimpleGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1b0c5a3e6346dcc4efac7861ad38f64533a05bba
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 28 11:16:11 2023 -0600
+
+    [VarComposite] Comment
+
+ src/OT/glyf/VarCompositeGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b0e763f5ebb8ef9cc9134b1aebe96f41b526f1cf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 28 10:45:23 2023 -0600
+
+    [VarComposite] Micro-optimize get_num_points
+
+ src/OT/glyf/VarCompositeGlyph.hh | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+commit 29d576584d4a56502da8e16c9dcc2222ad94e7bb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 28 10:33:50 2023 -0600
+
+    [VarComposite] Micro-optimize
+
+ src/OT/glyf/Glyph.hh             | 1 +
+ src/OT/glyf/VarCompositeGlyph.hh | 9 ++++-----
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+commit bf97f880558f35cdd54f88c737164ff8efa807c3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 28 10:28:17 2023 -0600
+
+    [VarComposite] Minor notation
+
+ src/OT/glyf/VarCompositeGlyph.hh | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+commit e9738563ffe7d07c6245a19b9a9b94a310f31140
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 28 10:22:40 2023 -0600
+
+    [VarComposite] Speedup get_size()
+
+ src/OT/glyf/VarCompositeGlyph.hh | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+commit 21ba0b6868790f1586363c02aea90b3c449304f7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 19:15:41 2023 -0600
+
+    [cvt] Remove unneeded initialization
+
+ src/hb-ot-var-cvar-table.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit b3fed4fa6465151e740bdbf5cfffb13298a57803
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Apr 27 22:13:30 2023 +0000
+
+    [repacker] fix fuzzer found memory leak.
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5196242811748352
+
+ src/graph/markbasepos-graph.hh                         |   5 ++++-
+ ...tcase-minimized-hb-repacker-fuzzer-5196242811748352 | Bin 0 -> 358356 bytes
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+commit 247ffe389fb2e80a9d254860b7aa4a9ccd6c6558
+Merge: f90e3fc3f c800c0cfe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 16:28:47 2023 -0600
+
+    Merge pull request #4211 from harfbuzz/glyf-inplace
+    
+    Glyf inplace
+
+commit c800c0cfe1a09a4c5e11345b4870cab123cbfae8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 15:12:02 2023 -0600
+
+    [Glyph] Load composite glyphs in-place
+
+ src/OT/glyf/CompositeGlyph.hh    | 33 ++++++++++++++++++++++++-----
+ src/OT/glyf/Glyph.hh             | 45 ++++++++++++++++++++--------------------
+ src/OT/glyf/SimpleGlyph.hh       | 12 ++++++-----
+ src/OT/glyf/VarCompositeGlyph.hh | 15 +++++++++++---
+ src/hb-ot-var-gvar-table.hh      | 33 +++++++----------------------
+ 5 files changed, 77 insertions(+), 61 deletions(-)
+
+commit f90e3fc3f4ff9aca66742ee8843e0087ddc83872
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 14:39:33 2023 -0600
+
+    [Composites] Pre-alloc phantom-points space
+
+ src/OT/glyf/CompositeGlyph.hh    | 1 +
+ src/OT/glyf/VarCompositeGlyph.hh | 1 +
+ 2 files changed, 2 insertions(+)
+
+commit 0c7cb57539c39a29fa71d89c634f9173908da71f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 14:21:44 2023 -0600
+
+    [VarComposite] Micro-optimization for advance-only
+
+ src/OT/glyf/Glyph.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit bdce23a0c0faab35a11eef6c97c1ad6432157b31
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 14:07:57 2023 -0600
+
+    [Glyph] Don't load component glyphs is phantom_only
+    
+    Drastically speeds up variable advance calculation when HVAR
+    is missing. Let's see what I broke...
+
+ src/OT/glyf/Glyph.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit e2be7865f33640671e5bb342cd648ce944937fe8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 13:54:06 2023 -0600
+
+    [VarComposite] Minor rewrite
+
+ src/OT/glyf/VarCompositeGlyph.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit b9b85da3c9200f84d978edeb3e404e089ca69454
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Apr 27 11:17:24 2023 -0700
+
+    [instancer] no need to create hb_font_t object when fetching delta from varstore
+
+ src/hb-ot-layout-common.hh | 11 ++++++-----
+ src/hb-subset-plan.cc      | 12 ++----------
+ 2 files changed, 8 insertions(+), 15 deletions(-)
+
+commit 58f79063bbe5a9f2bbd438771a5f495d47208a95
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 13:35:32 2023 -0600
+
+    [VarComposite] Set min_size to 5
+
+ src/OT/glyf/VarCompositeGlyph.hh | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+commit 28b5a47d2b06bb85540c3ef6616b9d92a4fe93d7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 13:31:53 2023 -0600
+
+    [VarComposite] Reuse a variable
+
+ src/OT/glyf/VarCompositeGlyph.hh | 25 +++++++++++++------------
+ 1 file changed, 13 insertions(+), 12 deletions(-)
+
+commit 977c2f9c66363a369e91521d789ceacf0133621e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 13:25:30 2023 -0600
+
+    [glyf] Micro-optimize
+
+ src/OT/glyf/SimpleGlyph.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit a4b4536a17cd308fdc59639d67d64049d4964326
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 13:14:52 2023 -0600
+
+    Revert "[glyf] Micro-optimize"
+    
+    This reverts commit 2bbb605d08298047164a20a242f4cfcfbe68c309.
+    
+    In case of phantoms_only we were leaving array uninitialized.
+    This is why the fedora-valgrind bot broke.
+
+ src/OT/glyf/SimpleGlyph.hh | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+commit 1c4e7e4f7e8fa569885abc608aa52b979f966ea2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 13:05:54 2023 -0600
+
+    [VarComposite] Rewrite code with ?
+
+ src/OT/glyf/VarCompositeGlyph.hh | 27 +++++++++------------------
+ 1 file changed, 9 insertions(+), 18 deletions(-)
+
+commit 9491a3dd0b6d098073b4d89540fe227b84c07ebb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 13:01:27 2023 -0600
+
+    [VarComposite] Minor notation
+
+ src/OT/glyf/VarCompositeGlyph.hh | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+commit 644e0551a2f8736fa77fa19d7ccdfe07160cfab7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 13:00:24 2023 -0600
+
+    [VarComposite] Minor move code
+
+ src/OT/glyf/VarCompositeGlyph.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit 79aa9e93d366c9e016404faf12da68b56bd56c9d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 12:57:25 2023 -0600
+
+    [VarComposite] Optimize translate, second try
+
+ src/OT/glyf/VarCompositeGlyph.hh | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+commit 83bbeaca20f84b7a5af092209f5989986e6e2f9d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 12:49:56 2023 -0600
+
+    [VarComposite] Minor move code
+
+ src/OT/glyf/VarCompositeGlyph.hh | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+commit 9b5afad49392cd2b661c6517353e0da950d33029
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 12:38:44 2023 -0600
+
+    [var] Fix assertion
+    
+    Fixes https://oss-fuzz.com/testcase-detail/4861707188305920
+
+ src/hb-ot-var-common.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 7cb95c8ab7d29d9ccc265d74a98a63ee3b514b63
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 12:28:00 2023 -0600
+
+    Revert "[VarComposite] Optimize translate()"
+    
+    This reverts commit 6a55e73d6aa9a378789d4101849f1508ac6fff3d.
+    
+    This was wrong.
+
+ src/OT/glyf/VarCompositeGlyph.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit b79a49f1a0a5030ccb582ae7aa715ae9da3c2857
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 12:21:32 2023 -0600
+
+    [VarComposite] Optimize get_points()
+
+ src/OT/glyf/VarCompositeGlyph.hh | 43 +++++++++++++++++++---------------------
+ 1 file changed, 20 insertions(+), 23 deletions(-)
+
+commit 51891e8ff42200f0555669c1c8a71e73ddbe189b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 12:16:12 2023 -0600
+
+    [VarComposite] Micro-optimize
+
+ src/OT/glyf/VarCompositeGlyph.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 0f05ced13b5d4c80b2b3f5b145613b0acd24df74
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 11:59:28 2023 -0600
+
+    [VarComposite] Optimize transformation functions more
+
+ src/OT/glyf/VarCompositeGlyph.hh | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+commit 65ea95b9747e4863552a2a671000862c6ef14c6e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 11:52:56 2023 -0600
+
+    [VarComposite] Optimize skew()
+
+ src/OT/glyf/VarCompositeGlyph.hh | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit 070f837be6b3e928a333c388025a82d77dae92dc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 11:51:42 2023 -0600
+
+    [VarComposite] Optimize rotate()
+
+ configure.ac                     |  2 +-
+ meson.build                      |  1 +
+ src/OT/glyf/VarCompositeGlyph.hh | 10 ++++++++--
+ 3 files changed, 10 insertions(+), 3 deletions(-)
+
+commit 4e256f5a5754699c79d575dbf3026b11731ab926
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 11:47:52 2023 -0600
+
+    [VarComposite] Optimize scale()
+
+ src/OT/glyf/VarCompositeGlyph.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 6a55e73d6aa9a378789d4101849f1508ac6fff3d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 11:45:18 2023 -0600
+
+    [VarComposite] Optimize translate()
+
+ src/OT/glyf/VarCompositeGlyph.hh | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+commit cdc02acd3d0281b4791c129da9145ec184c73df6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 11:40:24 2023 -0600
+
+    [VarComposite] Minor adjust initialization values
+
+ src/OT/glyf/VarCompositeGlyph.hh | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+commit a257546de492e3dba05cb08aec936b0489023959
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 11:39:40 2023 -0600
+
+    [VarComposite] Minor micro-optimize / indent
+
+ src/OT/glyf/VarCompositeGlyph.hh | 17 ++++++++---------
+ 1 file changed, 8 insertions(+), 9 deletions(-)
+
+commit 18396b8e27888c2ecb3aec40cb488263f9a26d50
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 11:36:24 2023 -0600
+
+    [VarComposite] Micro-optimize
+
+ src/OT/glyf/VarCompositeGlyph.hh | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+commit 1e71a673e925dcce0acfb81c14f74404b92a1568
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 11:27:40 2023 -0600
+
+    [VarComposite] Micro-optimize
+
+ src/OT/glyf/VarCompositeGlyph.hh | 66 +++++++++++++++++++++-------------------
+ 1 file changed, 35 insertions(+), 31 deletions(-)
+
+commit dd860fad80b85f8bc03dd53373cff4f092c32447
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 11:24:48 2023 -0600
+
+    [VarComposite] Micro-optimize
+
+ src/OT/glyf/VarCompositeGlyph.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 6457847719a1e22bf1047c2b9e5debf843b5156d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 11:22:18 2023 -0600
+
+    [VarComposite] Minor change variable types
+
+ src/OT/glyf/VarCompositeGlyph.hh | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+commit 50e758e34534b963269f859274dff1d2a3812778
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 11:02:07 2023 -0600
+
+    [glyf] Tweak assertion
+
+ src/OT/glyf/SimpleGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1056590f00db7414a289d122f88f68d305c000a5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 10:41:36 2023 -0600
+
+    [config] Add HB_OPTIMIZE_SIZE_VAL
+
+ src/hb-config.hh            | 5 +++++
+ src/hb-ot-var-gvar-table.hh | 9 +--------
+ src/hb-vector.hh            | 4 +---
+ 3 files changed, 7 insertions(+), 11 deletions(-)
+
+commit 726590ed5f3ac23f8316ed3988bf24f87ff58360
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 27 10:13:39 2023 -0600
+
+    [gvar] Add optimize-size code path
+
+ src/hb-ot-var-gvar-table.hh | 100 ++++++++++++++++++++++++++++----------------
+ 1 file changed, 64 insertions(+), 36 deletions(-)
+
+commit 7c9ed76d0a272b97af48b75ce0e7ea001164d453
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Apr 27 03:26:57 2023 +0200
+
+    [doc] Use simpler markdown link syntax
+
+ src/hb-ot-layout.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit a200f0a3fe9ced04ad498fc9a1b480fbf1cce78d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 17:29:49 2023 -0600
+
+    [gvar] Micro-optimize
+
+ src/hb-ot-var-gvar-table.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit db86e977a091b084897ebbafff7f72a58e0e375a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 17:08:53 2023 -0600
+
+    [gvar] Micro-optimize
+
+ src/hb-ot-var-gvar-table.hh | 61 +++++++++++++++++++++++++++------------------
+ 1 file changed, 37 insertions(+), 24 deletions(-)
+
+commit 27b8a208ec93d9a2a4efd33682ce23ee3f4841d7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 16:54:58 2023 -0600
+
+    [gvar] Minor variable reuse
+
+ src/hb-ot-var-gvar-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 2bbb605d08298047164a20a242f4cfcfbe68c309
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 16:40:39 2023 -0600
+
+    [glyf] Micro-optimize
+    
+    No need to init the whole array.
+
+ src/OT/glyf/SimpleGlyph.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit c87f26018d53e5fdb4d6226919cb10a3c43a9c8e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 16:32:07 2023 -0600
+
+    [glyf] Micro-optimize
+
+ src/OT/glyf/SimpleGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a321c4fee56b15247c10f9aa3db7e7ccb3b8173b
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Apr 27 00:48:00 2023 +0200
+
+    7.2.0
+
+ NEWS                | 29 +++++++++++++++++++++++++++++
+ configure.ac        |  2 +-
+ meson.build         |  2 +-
+ src/hb-deprecated.h |  2 +-
+ src/hb-subset.h     |  2 +-
+ src/hb-unicode.h    |  2 +-
+ src/hb-version.h    |  4 ++--
+ 7 files changed, 36 insertions(+), 7 deletions(-)
+
+commit fd52c4cf7b97b7d16b442d369ae1d8ad18efa36e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 16:27:51 2023 -0600
+
+    [gvar] Comment
+
+ src/hb-ot-var-gvar-table.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 0c59c629c1d46067bca26e10e051eaabd87ff0b2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 16:20:16 2023 -0600
+
+    [gvar] Micro-optimize
+    
+    For cases where no deltaset applies.
+
+ src/hb-ot-var-gvar-table.hh | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit 5d1a603ad1556f8797180aea0f7201f3bad66441
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 16:25:15 2023 -0600
+
+    [var] Fix compiler warnings
+
+ src/hb-ot-var-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit af393e9652aa746c42652e3590dfb12724dd0877
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 16:02:06 2023 -0600
+
+    [gvar] Refactor a variable
+
+ src/hb-ot-var-common.hh | 16 +++++++++-------
+ 1 file changed, 9 insertions(+), 7 deletions(-)
+
+commit 2a3bf5a542aaefb72bac4708ca9ded99b2ec62cb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 15:58:55 2023 -0600
+
+    [gvar] Minor error-handling
+
+ src/hb-ot-var-gvar-table.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 57faabb78e030388dca2cd6b6ec7d94a484c0956
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 15:56:04 2023 -0600
+
+    [gvar] Micro-optimize
+
+ src/hb-ot-var-gvar-table.hh | 20 ++++++++++++++++----
+ 1 file changed, 16 insertions(+), 4 deletions(-)
+
+commit 76e269af9e87d95415564d75a3aabc2ecec262cd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 15:47:12 2023 -0600
+
+    [gvar] Micro-optimize
+
+ src/hb-ot-var-common.hh | 12 +++++-------
+ 1 file changed, 5 insertions(+), 7 deletions(-)
+
+commit 7349cea127599d4d164b3ef4b05aee80451bc26b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 14:27:24 2023 -0600
+
+    [gvar] Micro-optimization
+
+ src/hb-ot-var-common.hh | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+commit bc535870025dbb78e83ebad1e01aba8644825e87
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 13:57:11 2023 -0600
+
+    [deprecated] Add HB_UNICODE_COMBINING_CLASS_CCC133
+    
+    https://github.com/harfbuzz/harfbuzz/pull/4207
+
+ docs/harfbuzz-sections.txt |  1 +
+ src/hb-deprecated.h        | 11 +++++++++++
+ 2 files changed, 12 insertions(+)
+
+commit c5afe026bdf784d05f32d9be31a38c077746d210
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 13:44:03 2023 -0600
+
+    [gvar] Comment
+
+ src/hb-ot-var-gvar-table.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 87c6e68ec31260fb51d67d563c61adb61041bb41
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 13:20:51 2023 -0600
+
+    [gvar] Assertion
+
+ src/hb-ot-var-common.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 09386737312ddae4d850334cd55063de935cf6d5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 13:19:27 2023 -0600
+
+    [gvar] Error handling & micro-optimization
+
+ src/hb-ot-var-common.hh     | 2 +-
+ src/hb-ot-var-gvar-table.hh | 5 +++--
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+commit b6aa2d71f39473d1d927376a4959bb73398aa4ca
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 13:06:24 2023 -0600
+
+    [gvar] Speed up calculate_scalar more
+    
+    Use a gvar-wide cache of the one active peak index for shared-tuples
+    that have only one active peak. This speeds up the scalar calculation.
+    
+    This shows significant speedup for the CJK VarComposite font for
+    example since that has tens of axes with mostly only one active peak.
+
+ src/hb-ot-var-common.hh     | 18 ++++++++++++++++--
+ src/hb-ot-var-gvar-table.hh | 27 ++++++++++++++++++++++++++-
+ 2 files changed, 42 insertions(+), 3 deletions(-)
+
+commit ffbfab123f0966f4ee1c00b24fcb7158b1b3857d
+Author: Han Seung Min - 한승민 <hanseungmin.ar@gmail.com>
+Date:   Thu Apr 27 00:43:48 2023 +0900
+
+    oops docs
+
+ src/hb-unicode.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e428edc3714eebe68981c579bda9412f303f538d
+Author: Han Seung Min - 한승민 <hanseungmin.ar@gmail.com>
+Date:   Wed Apr 26 23:57:21 2023 +0900
+
+    [unicode] Fix typo
+    
+    I believe the `hb-unicode.h` has a typo where `HB_UNICODE_COMBINING_CLASS_CCC133        = 132,` is supposed to be `HB_UNICODE_COMBINING_CLASS_CCC132`
+
+ src/hb-unicode.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 63afb4f2e7cc6053fb884108b360f19d1103b065
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 10:29:25 2023 -0600
+
+    [syllabic] Better fix for previous issue
+    
+    With previous fix the GPOS application was still reading the syllable()
+    member, which was already freed.  This fix is more correct.
+
+ src/hb-ot-layout-gsubgpos.hh | 3 ++-
+ src/hb-ot-shaper-syllabic.cc | 4 ----
+ 2 files changed, 2 insertions(+), 5 deletions(-)
+
+commit c5f3b3feb1d2845b46e19f7e01605bbcf3e7f480
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 26 10:17:37 2023 -0600
+
+    [syllabic] Actually clear syllables
+    
+    Such that they don't affect GPOS.
+    
+    I broke this in 044d7a06db552e1564b8575f4d23798f009d9dde.
+
+ src/hb-ot-shaper-syllabic.cc | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 9ee7c2ea63416a6e7e98461d9b5480e7af22c427
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Apr 25 16:13:54 2023 -0600
+
+    [cmap] Minor remove magic number
+
+ src/hb-ot-cmap-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 580b0dc1c353c5cf2d2b6ba63f17043baf050d8d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Apr 25 16:11:01 2023 -0600
+
+    [cmap] Comment
+
+ src/hb-ot-cmap-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1d31da91ce02bf01947f1533d896dc4a4a5f6bcb
+Merge: f6803b06b e41f31719
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Apr 25 15:34:06 2023 -0600
+
+    Merge pull request #4205 from harfbuzz/gvar-optimize
+    
+    Gvar optimize
+
+commit e41f3171994a739ff966735b78e1777ab5933471
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Apr 25 20:54:27 2023 +0000
+
+    [subset] Update expectation files for full_instance tests.
+
+ ...fault.retain-all-codepoint.wght=300,wdth=90.ttf | Bin 114300 -> 114300 bytes
+ ...anges.retain-all-codepoint.wght=300,wdth=90.ttf | Bin 114300 -> 114300 bytes
+ test/subset/data/tests/full_instance.tests         |   3 +++
+ 3 files changed, 3 insertions(+)
+
+commit f6803b06bf7ef6b6a480e9dd489a8fa693d7b403
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Apr 25 14:46:44 2023 -0600
+
+    [VarRegionAxis] Micro-optimize
+    
+    peak==0 is common.
+
+ src/hb-ot-layout-common.hh | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+commit f91929d6da527e42b4f46c7738d40e118107163a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Apr 25 14:42:00 2023 -0600
+
+    Minor return floats instead of doubles from function
+    
+    Not that any compiler complained...
+
+ src/hb-ot-layout-common.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 808a21f8de7523b26ddad2316e55fafa6daf4fe2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Apr 25 14:03:52 2023 -0600
+
+    [gvar] Simplify ref_points logic
+
+ src/hb-ot-var-gvar-table.hh | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+commit 78a0216a031234fdcc14448f906649bd83bb7118
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Apr 25 13:52:00 2023 -0600
+
+    [gvar] Write a for loop as range loop
+
+ src/hb-ot-var-gvar-table.hh | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+commit f654823fe0639bf6c71d77f53c34b4b2f878eb2e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Apr 25 13:09:40 2023 -0600
+
+    [gvar] Handle an error case
+
+ src/hb-ot-var-gvar-table.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 30d08dc62cfab0f5f8d8d4491f91eb352eebfb3e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Apr 25 12:13:57 2023 -0600
+
+    [gvar] Populate end_points lazily
+    
+    Tiny micro-optimization...
+
+ src/hb-ot-var-gvar-table.hh | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+commit fe8c91707b5579f77505e37ebea8578e1282db38
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Apr 25 11:30:36 2023 -0600
+
+    [gvar] Micro-optimize has_intermediate() access
+
+ src/hb-ot-var-common.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit 2175f5d050743317c563ec9414e0f83a47f7fbc4
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Apr 24 21:13:18 2023 +0000
+
+    [subset] Fix inefficient ItemVariationStore subsetting w/ retain_gids.
+    
+    ItemVariationStore is relying on the assumption that the inner_map is populated for all output glyphs, this is not true for subsetting operations with retain gids enabled. Fixes fuzzer timeout: https://oss-fuzz.com/testcase-detail/4575222591520768.
+
+ src/hb-bimap.hh                                         |   9 +++++++++
+ src/hb-ot-layout-common.hh                              |  14 ++++++--------
+ src/hb-ot-var-hvar-table.hh                             |  10 ++++------
+ ...testcase-minimized-hb-subset-fuzzer-4575222591520768 | Bin 0 -> 91107 bytes
+ .../variable/Fraunces.retain-gids.26,66,69,124,125.ttf  | Bin 0 -> 21296 bytes
+ .../data/expected/variable/Fraunces.retain-gids.61.ttf  | Bin 0 -> 4508 bytes
+ test/subset/data/tests/variable.tests                   |   1 +
+ 7 files changed, 20 insertions(+), 14 deletions(-)
+
+commit 385e23762dc18659c4cc0c69e17549fe3e00d74e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Apr 24 17:51:07 2023 -0600
+
+    [var] Optimize calculate_scalar more
+    
+    This change alone is showing me 14% scalar in a benchmark.
+    The reason being that the array::operator[] is not being invoked
+    a lot of time, which was, many times, hitting the unlikely() path.
+    Weird!
+
+ src/hb-ot-var-common.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 7a3928e2b6099c5c334ca0b2469a567b529bcf34
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Apr 24 17:38:20 2023 -0600
+
+    [var] Optimize calculate_scalar
+    
+    For varfonts with lots of deltasets, the loop in this function is
+    *really* hot...
+
+ src/hb-ot-var-common.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 89296036317bf718c99fdd1dc0d1bf4f1c34323a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Apr 24 16:16:27 2023 -0600
+
+    [gvar] Another minor optimization
+    
+    Allocate orig_points lazily only when needed.
+
+ src/hb-ot-var-gvar-table.hh | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+commit 20454eaa399abe28db485b2ccb461c30861023e0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Apr 24 15:50:58 2023 -0600
+
+    [gvar] Optimize by applying deltas in batches
+    
+    Shows up to 7% speedup in one of my benchmarks.
+    
+    One test fails by one rounding issue. To be updated.
+
+ src/hb-ot-var-gvar-table.hh | 22 +++++++++++++++++-----
+ 1 file changed, 17 insertions(+), 5 deletions(-)
+
+commit 491aa572ce9c845afa40cfdcded4959add46fd5c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Apr 24 15:05:18 2023 -0600
+
+    [gvar] Minor call a function instead of handcoding
+
+ src/hb-ot-var-gvar-table.hh | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+commit cf95f3193bfb85ec4d14041e93df8a03909f40a1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Apr 24 14:45:52 2023 -0600
+
+    [VarComposite] Another minor resue of num_points
+
+ src/OT/glyf/Glyph.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit fc8dfe64d04e3d429f9c8c7f39e52c619c4bba13
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Apr 24 14:39:20 2023 -0600
+
+    [benchmark-font] Minor rename
+
+ perf/benchmark-font.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 0a5208422821471d2904e164cad651bd8dadcfb4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Apr 24 14:23:24 2023 -0600
+
+    [VarComposite] Minor resue of num_points
+
+ src/OT/glyf/VarCompositeGlyph.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit a9a9f278b81f6a855afce1bf668410d3ccceb682
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Apr 24 14:16:48 2023 -0600
+
+    [atomic] Remove incomplete comment
+
+ src/hb-atomic.hh | 4 ----
+ 1 file changed, 4 deletions(-)
+
+commit d1c00c047030226b6b5255cc4b7cdeb738ee0ccc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Apr 24 13:24:47 2023 -0600
+
+    [COLR] Respect HB_NO_PAINT
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4204
+
+ src/OT/Color/COLR/COLR.hh | 4 ++++
+ src/hb-ot-font.cc         | 2 +-
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+commit 4129061e37824433f9c81eaa99d1618af2f2d69a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Apr 24 13:04:05 2023 -0600
+
+    Revert "Move hb-ot-name-language-static.hh out of hb-static.cc"
+    
+    This reverts commit 7b5f0dd3a8b4a126b7952fea1c4c30b8b456083e.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4203
+
+ src/hb-ot-name.cc | 2 --
+ src/hb-static.cc  | 1 +
+ src/hb-subset.cc  | 5 -----
+ 3 files changed, 1 insertion(+), 7 deletions(-)
+
+commit e76a3649db4611ac0531cbb5fc8e555a039b93f3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Apr 22 10:20:25 2023 -0600
+
+    [atomic] Comment
+
+ src/hb-atomic.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 8e43e3a8ce72a3888e9bfbc9f2975fc56e139836
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Apr 22 10:16:43 2023 -0600
+
+    [priority-heap] Comment
+
+ src/hb-priority-queue.hh | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 48f8ed7e0205e1c0dcf0a19c1bfc9b515182563a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Apr 22 10:11:22 2023 -0600
+
+    Docs
+
+ src/hb-buffer.cc    | 5 +++++
+ src/hb-face.cc      | 6 ++++++
+ src/hb-font.cc      | 5 +++++
+ src/hb-ot-layout.cc | 2 ++
+ 4 files changed, 18 insertions(+)
+
+commit b31684dca478da09d9ae5063658d5663fa5cbce0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Apr 22 09:47:58 2023 -0600
+
+    [cache] Add some AI-generated comments
+
+ src/hb-cache.hh | 14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
+
+commit bffdca89f7977e7a4b84a69196ac48f1df6d3c6f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Apr 22 09:32:57 2023 -0600
+
+    [pool] Add funny Copilot comment
+
+ src/hb-pool.hh | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+commit a960571f24b0383dedd958df4f268fcb877fe94d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 21 16:45:08 2023 -0600
+
+    [glyf] Comments
+
+ src/OT/glyf/Glyph.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 2b042cc5c6e90736754acdbbd035fe4a230b9fd6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 21 16:43:47 2023 -0600
+
+    [VarComposite] Implement trim_padding()
+
+ src/OT/glyf/Glyph.hh             | 2 +-
+ src/OT/glyf/VarCompositeGlyph.hh | 7 +++++++
+ 2 files changed, 8 insertions(+), 1 deletion(-)
+
+commit 591c9460dc28967c5db11e9301d81d08c2773217
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Apr 21 14:12:27 2023 -0700
+
+    [instancer] compile composite glyphs directly with shifted component
+    points instead of deltas
+
+ src/OT/glyf/CompositeGlyph.hh | 25 ++++++++++++-------------
+ src/OT/glyf/Glyph.hh          | 27 +++++++++------------------
+ 2 files changed, 21 insertions(+), 31 deletions(-)
+
+commit 3520f528aaba200ab2e3f1edfe746c7963a7ce54
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 21 15:46:36 2023 -0600
+
+    [CompositeGlyph] Apply gvar deltas with component transform
+    
+    This was being done wrong for one of the scaled_offsets() cases.
+
+ src/OT/glyf/CompositeGlyph.hh | 37 ++++++++++++++++++++++---------------
+ src/OT/glyf/Glyph.hh          | 14 +++++++-------
+ 2 files changed, 29 insertions(+), 22 deletions(-)
+
+commit 33972b3bf6cd9a63424a2213e5b80bff474b7d10
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 21 12:37:51 2023 -0600
+
+    [glyf] Increase CompositeGlyf memory allocation
+    
+    The 50% wasn't justified by logic.
+
+ src/OT/glyf/CompositeGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 290cef39bed5fcc05e3a424ce05b1797507a0a03
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 21 12:22:30 2023 -0600
+
+    [glyf] When instancing, just spew empty VarComposites
+    
+    Before we were dropping the entire glyf table.
+
+ src/OT/glyf/Glyph.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 4353192d057fe3583a4ad234e478a407e9d1eb1a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 21 11:59:15 2023 -0600
+
+    [aat] Tweak a couple sanitize calls that are never called
+
+ src/hb-aat-layout-common.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 305012609bddba97a2fbc5080a146bc3d3feaa06
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 21 11:42:18 2023 -0600
+
+    [hdmx] Remove unused unsafe function
+
+ src/hb-ot-hdmx-table.hh | 10 +---------
+ 1 file changed, 1 insertion(+), 9 deletions(-)
+
+commit f74abc307d742f6f90b0012dc1cef66da149742e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 21 11:37:37 2023 -0600
+
+    [face] Comment
+
+ src/hb-face.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d1f49ba6d2dc7f8c316f055a9e4f9cdf4dafdcad
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 20 18:17:14 2023 -0600
+
+    [VarComposites] More ifdef guards
+
+ src/OT/glyf/Glyph.hh | 33 ++++++++++++++++++++++++++++-----
+ 1 file changed, 28 insertions(+), 5 deletions(-)
+
+commit 1e9a0511f33a851b27d6d0320b0d426bf95c97ce
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 20 17:47:04 2023 -0600
+
+    [subset] Fix HB_TINY build
+
+ src/hb-subset-plan.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 106a237e404b4942803a52a8ab4114b2f3034c77
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 20 17:44:59 2023 -0600
+
+    [subset/glyf] Close over VarComposite glyphs
+    
+    Subsetting VarComposite glyphs works now.
+
+ src/hb-subset-plan.cc | 14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
+
+commit f2d21425a353728fa69680eff24421cce22981de
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 20 17:31:58 2023 -0600
+
+    [VarC/subset] Support subsetting VarComposites
+    
+    By renumbering components.
+
+ src/OT/glyf/SubsetGlyph.hh       | 15 +++++++++++++--
+ src/OT/glyf/VarCompositeGlyph.hh |  8 ++++++++
+ 2 files changed, 21 insertions(+), 2 deletions(-)
+
+commit 15d0a1dcfd192fda87c4877da2029c14d0bd5bd2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 20 17:28:10 2023 -0600
+
+    [glyf] TODO
+
+ src/OT/glyf/SubsetGlyph.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 85d0c3b5f1158eedc7ead3cae55adb026456352b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 20 17:17:28 2023 -0600
+
+    [glyf] Comment
+
+ src/OT/glyf/CompositeGlyph.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 5d74b42b9e3e2a591071d196d9d2b2dd537a496b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 20 17:15:57 2023 -0600
+
+    [glyf] Change variable name
+
+ src/OT/glyf/SubsetGlyph.hh | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit c997e490c78f8e643f9d8ff8c712cc1856b4979f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 20 17:02:38 2023 -0600
+
+    Remove unnecessary return
+
+ src/OT/glyf/CompositeGlyph.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 781da13e99d1373b4e33a84b40e01923e6f64e49
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 20 16:59:25 2023 -0600
+
+    [glyf] Comment
+
+ src/OT/glyf/SubsetGlyph.hh | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit 0e4bcf908ca4bf394a326970490ae1943966a410
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 20 16:23:41 2023 -0600
+
+    [hmtx] Add TODO
+
+ src/hb-ot-hmtx-table.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 639f45ef9e9bcb9b3a4c380e41d4a574156f41c0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 20 16:21:08 2023 -0600
+
+    [beyond-64k/subset] Implement subsetting of hmtx beyond64k
+
+ src/hb-ot-hmtx-table.hh | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+commit b3da715b9c0a5d0354cabb8a7e9117622643c119
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 20 16:05:03 2023 -0600
+
+    Fix HB_TINY build
+
+ src/OT/glyf/glyf.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 32f145ff9cd87a97d5eb265e29689c304799ebf3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 20 15:58:26 2023 -0600
+
+    Fix build
+
+ src/OT/glyf/Glyph.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 000a3c5dca1deb811646cf94e705733f5e9ee422
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 20 15:53:10 2023 -0600
+
+    [beyond-64k/subset] Fetch lsb from glyph table if not available
+    
+    The beyond-64k hmtx table doesn't encode LSB. If subsetting brings
+    the glyph under 64k (which currently is the only mode we support),
+    then we need to encode the LSB, which wasn't available. We need to
+    fetch xMin from glyf table and set it as LSB.
+
+ src/OT/glyf/Glyph.hh    |  1 +
+ src/OT/glyf/glyf.hh     |  9 +++++++++
+ src/hb-ot-font.cc       | 16 ----------------
+ src/hb-ot-hmtx-table.hh |  6 +++++-
+ src/hb-static.cc        | 23 +++++++++++++++++++++++
+ 5 files changed, 38 insertions(+), 17 deletions(-)
+
+commit 1111c7578ed76f9b338c5cbc13792ff638e22783
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 20 15:17:23 2023 -0600
+
+    hb_memset
+
+ src/OT/glyf/SubsetGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 219e739c9f21a16942162a53935f1dfbaf0414fa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 20 15:10:29 2023 -0600
+
+    [beyond-64k/subset] Lower CompositeGlyph GID24's when possible
+
+ src/OT/glyf/CompositeGlyph.hh | 20 ++++++++++++++++++++
+ src/OT/glyf/SubsetGlyph.hh    | 41 +++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 61 insertions(+)
+
+commit a2e8ecf9969b0657221f7d0ad6e6aeca5c20cd11
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 20 13:59:49 2023 -0600
+
+    [Glyph] Minor change type of type to enum type
+    
+    Say that thrice.
+
+ src/OT/glyf/Glyph.hh | 30 +++++++++++++++++++++---------
+ 1 file changed, 21 insertions(+), 9 deletions(-)
+
+commit 317e3693da558087ab92d2c896be463311e737d6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 20 11:48:43 2023 -0600
+
+    [beyond-64k] Fail hmtx subsetting if subset too large
+
+ src/hb-ot-hmtx-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 64ecf8720c959617e0b0a5d10002089a05f28f98
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 20 11:42:45 2023 -0600
+
+    [beyond-64k] Fix subsetting of maxp
+
+ src/hb-ot-maxp-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 7f629c0df20a52fb9aabecb657552c0703b70c58
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 19 13:16:18 2023 -0600
+
+    [docs] clarify purpose of FreeType integration
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4200
+
+ docs/usermanual-integration.xml | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 19e1b698c59e56b6e3530220866be0cd0754d1bd
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Apr 18 18:49:26 2023 +0000
+
+    [subset] Fix ubsan failure.
+
+ src/OT/glyf/Glyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 647b024784e1346f6886565f570cdf940d7b82b4
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Apr 17 22:47:47 2023 +0000
+
+    [subset] Fix fuzzer issue https://oss-fuzz.com/testcase-detail/6521393809588224
+
+ src/OT/glyf/SimpleGlyph.hh                              |   6 ++++++
+ src/OT/glyf/SubsetGlyph.hh                              |   7 ++++++-
+ ...testcase-minimized-hb-subset-fuzzer-6521393809588224 | Bin 0 -> 15886 bytes
+ 3 files changed, 12 insertions(+), 1 deletion(-)
+
+commit 3db6baa20e0a4661f99654860000e74a2770c2e0
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Apr 17 20:01:17 2023 +0000
+
+    [subset] add test for lig glyph fix.
+
+ ...oboto-Regular.no-layout-closure-gids2.no-unicodes.ttf | Bin 0 -> 2800 bytes
+ test/subset/data/profiles/no-layout-closure-gids2.txt    |   3 +++
+ test/subset/data/tests/no_layout_closure.tests           |   1 +
+ 3 files changed, 4 insertions(+)
+
+commit 8658c257c45f11ed28a8fcd621b35261fadffcfa
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Apr 17 19:46:46 2023 +0000
+
+    [subset] In LigatureSubst subsetting, check if the ligature glyph is in glyphset.
+    
+    Otherwise coverage will not match the retained ligature sets.
+
+ src/OT/Layout/GSUB/Ligature.hh             |  3 +++
+ src/OT/Layout/GSUB/LigatureSet.hh          | 12 ++++++++++++
+ src/OT/Layout/GSUB/LigatureSubstFormat1.hh |  2 +-
+ 3 files changed, 16 insertions(+), 1 deletion(-)
+
+commit ac4c3b3e8552d401977bcbba668f45d4e4f2cdd6
+Author: Josef Friedrich <josef@friedrich.rocks>
+Date:   Mon Apr 17 20:13:43 2023 +0200
+
+    Fix typos in the source code docs
+
+ src/hb-face.cc                    | 2 +-
+ src/hb-subset-instancer-solver.cc | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit ef6adadba92d605d54cf344962206cfbf421193d
+Author: DeadSix27 <DeadSix27@users.noreply.github.com>
+Date:   Mon Apr 17 12:53:49 2023 +0200
+
+    meson: add an option to disable utilities building
+    
+    Adds the missing utilities option to meson builds for parity with CMake builds
+
+ meson.build       | 5 ++++-
+ meson_options.txt | 2 ++
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+commit 90356eb226f633c8a7c9250b2653da75eaf51cfb
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Apr 14 20:52:35 2023 +0000
+
+    [subset] Note --no-layout-closure is only for GSUB.
+
+ src/hb-subset.h   | 2 +-
+ util/hb-subset.cc | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 14b9d8d53432da0a53122ae62ac125f5a67f456a
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Apr 14 20:44:15 2023 +0000
+
+    [subset] add --no-layout-closure flag.
+    
+    Disables layout glyph closure. Fixes #4192.
+
+ src/hb-subset-plan.cc                                    |   2 +-
+ src/hb-subset.h                                          |   3 +++
+ test/subset/data/Makefile.am                             |   1 +
+ test/subset/data/Makefile.sources                        |   1 +
+ ...Roboto-Regular.no-layout-closure-gids.no-unicodes.ttf | Bin 0 -> 2612 bytes
+ test/subset/data/profiles/no-layout-closure-gids.txt     |   2 ++
+ test/subset/data/tests/no_layout_closure.tests           |   8 ++++++++
+ test/subset/generate-expected-outputs.py                 |   7 +++++--
+ test/subset/meson.build                                  |   1 +
+ test/subset/subset_test_suite.py                         |   7 +++++++
+ util/hb-subset.cc                                        |   1 +
+ 11 files changed, 30 insertions(+), 3 deletions(-)
+
+commit 9c258936e7638e9e39976ae6afdc0b05a3065e16
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 14 11:35:34 2023 -0600
+
+    [SECURITY] Update
+
+ SECURITY.md | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit feb1f6d39e186421cc309ca137852ecb5fb8f65e
+Author: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+Date:   Fri Apr 14 15:17:54 2023 +0000
+
+     Add security policy
+    
+    Signed-off-by: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+
+ SECURITY.md | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+commit 26c719e8cd767e984daec3656be10b8ceec7832c
+Author: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+Date:   Wed Apr 12 13:38:49 2023 +0000
+
+     Add read-only top-level permissions to cifuzz.yml
+    
+    Signed-off-by: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
+
+ .github/workflows/cifuzz.yml | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 96ed20725c99275f286a9a9cf461548731b6828c
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Apr 4 10:33:58 2023 -0700
+
+    [instancer] update bound metrics for CFF2 instancing
+
+ src/hb-ot-head-table.hh                            |  20 ++++-
+ src/hb-ot-var-hvar-table.hh                        |   3 +
+ src/hb-subset-plan.cc                              |  88 +++++++++++++++++++++
+ test/subset/data/Makefile.am                       |   1 +
+ test/subset/data/Makefile.sources                  |   1 +
+ ...fault.retain-all-codepoint.wght=650,CNTR=50.otf | Bin 41760 -> 41760 bytes
+ ...F-ABC.default.retain-all-codepoint.wght=800.otf | Bin 0 -> 1508 bytes
+ ...C.retain-gids.retain-all-codepoint.wght=800.otf | Bin 0 -> 1508 bytes
+ test/subset/data/fonts/Cantarell-VF-ABC.otf        | Bin 0 -> 2508 bytes
+ .../tests/instantiate_cff2_update_metrics.tests    |  15 ++++
+ test/subset/meson.build                            |   1 +
+ 11 files changed, 128 insertions(+), 1 deletion(-)
+
+commit 2663a9b6f98a4afebe43ee213c5c14af6c2c5ce5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Mar 31 17:38:23 2023 -0600
+
+    [wasm] Rename a couple APIs
+
+ src/hb-wasm-api-blob.hh | 20 --------------------
+ src/hb-wasm-api-face.hh | 27 ++++++++++++++++++---------
+ src/hb-wasm-api-font.hh | 11 +++++++++++
+ src/hb-wasm-api-list.hh |  4 ++--
+ src/hb-wasm-api.h       | 10 +++++-----
+ 5 files changed, 36 insertions(+), 36 deletions(-)
+
+commit d2fb583a5a2e7839a88a8a4b3c1832459223c732
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Mar 31 12:18:41 2023 -0600
+
+    [wasm-graphite] Fix advance signedness
+
+ src/wasm/graphite/shape.cc | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit f9dd402ef8c49bbb89d7c1311a6008a492f4182d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Mar 31 12:18:35 2023 -0600
+
+    [wasm] Fix header
+
+ src/hb-wasm-api.h | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+commit 85a1fdd93fcafbfdd91bec2d16cf0ce6f3a0cd79
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Mon Mar 27 14:42:21 2023 +0100
+
+    [wasm] get/set font variation parameters
+
+ src/hb-wasm-api-font.hh | 56 +++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-wasm-api-list.hh |  2 ++
+ src/hb-wasm-api.h       | 14 +++++++++++++
+ 3 files changed, 72 insertions(+)
+
+commit 0bfad127c3a907d5c50e59ab61a2beac69853cb1
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Sun Mar 26 17:44:55 2023 +0100
+
+    [wasm] Make _hb_wasm_module_reader conditional
+    
+    Or else uharfbuzz doesn't build.
+
+ src/hb-wasm-shape.cc | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit 3fc48d4ada4e4ed1535f7a38cba9b3f85d21ad9b
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Sun Mar 26 17:43:14 2023 +0100
+
+    [wasm] [experimental] wrap hb_face_create and hb_create_font
+
+ src/hb-wasm-api-blob.hh | 20 ++++++++++++++++++++
+ src/hb-wasm-api-face.hh |  9 +++++++++
+ src/hb-wasm-api-list.hh |  2 ++
+ src/hb-wasm-api.h       |  5 +++++
+ 4 files changed, 36 insertions(+)
+
+commit 0a16c60b42a03603d12affd9746da1d0a0e67adf
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Fri Mar 10 14:31:56 2023 +0000
+
+    [wasm-rust] Derive some friendly traits
+
+ src/wasm/rust/harfbuzz-wasm/src/lib.rs | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 6ff994f31d4dc0a929dffae2ff6772096a2e51fd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Mar 3 15:33:48 2023 -0700
+
+    [wasm-api-shape] Avoid a couple of crashes
+
+ src/hb-wasm-api-shape.hh | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+commit b6c18144106955f30ac9ec645b0c7eac860c6a7f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Mar 3 11:31:08 2023 -0700
+
+    [wasm] Comment
+
+ src/hb-wasm-api-list.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit e78d8653cebc1803f669c238b2e42300717af7c8
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Thu Mar 2 19:47:33 2023 +0000
+
+    [wasm-rust] panic if buffer_set_contents fails
+
+ src/wasm/rust/harfbuzz-wasm/src/lib.rs | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 74a2f338c67a8c3cd5220b19366f0331332dd69d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Mar 2 10:29:01 2023 -0700
+
+    [wasm-shape] Don't crash if font is bad
+
+ src/hb-wasm-shape.cc | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit 7df9b3dd892abfcb31be072ae47193cb0482b51e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 26 14:54:07 2023 -0700
+
+    [wasm-api-list] Add TODO
+
+ src/hb-wasm-api-list.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit f5a0bd223b2194203aa7435ac09fc73468544a46
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 26 14:05:26 2023 -0700
+
+    [wasm-shape] Comment re thread-safety
+
+ src/hb-wasm-shape.cc | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit 7e5064ac1b259f5f92a588fc42096337c2f37a1c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 26 14:01:56 2023 -0700
+
+    [wasm-shape] Comment re thread-safety
+
+ src/hb-wasm-shape.cc | 13 ++++++++++---
+ 1 file changed, 10 insertions(+), 3 deletions(-)
+
+commit 5235ee68adc1bec46fb7e0cb4f327f814961d595
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 26 13:15:39 2023 -0700
+
+    [wasm-shape] Remove explicit running-mode setting
+    
+    It does it automatically.
+
+ src/hb-wasm-shape.cc | 5 -----
+ 1 file changed, 5 deletions(-)
+
+commit e89415b5b9f82ae1893343496ec659a0947b7055
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 26 13:14:37 2023 -0700
+
+    [wasm-shape] Print another error message
+
+ src/hb-wasm-shape.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 6aea77c643777b7ed550edc63f65859c05430e53
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 26 12:28:25 2023 -0700
+
+    [wasm-shape] Add (disabled) module support
+
+ meson.build                |  1 +
+ src/hb-wasm-shape.cc       | 66 +++++++++++++++++++++++++++++++++++++++++++++-
+ src/wasm/graphite/Makefile |  2 +-
+ 3 files changed, 67 insertions(+), 2 deletions(-)
+
+commit 142ceaf2466b66fc868f125b4adc6e727b981f3b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 26 12:18:31 2023 -0700
+
+    [wasm-shape] Print module instantiation error
+
+ src/hb-wasm-shape.cc | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+commit 7e397d8695f32c91bddbf373cd19f4c6e61fa882
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Sun Feb 26 13:57:34 2023 +0000
+
+    [wasm-rust] Fix shape parameters
+
+ src/wasm/sample/rust/hello-wasm/src/lib.rs | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+commit d942f72c2a6325a25e213bbce5bc3a943be39861
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Sun Feb 26 13:57:07 2023 +0000
+
+    [wasm-rust] Fix path
+
+ src/wasm/sample/rust/hello-wasm/Cargo.toml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 52b11546c8b76206b97fd49d65ae2e850a7212d3
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Sun Feb 26 13:57:00 2023 +0000
+
+    [wasm-rust] Optional kurbo dependency
+
+ src/wasm/rust/harfbuzz-wasm/Cargo.toml |  1 +
+ src/wasm/rust/harfbuzz-wasm/src/lib.rs | 92 ++++++++++++++++++++++++++++++++--
+ 2 files changed, 88 insertions(+), 5 deletions(-)
+
+commit 0c90555e5932817f7c3d820c5883172dd86844a9
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Sun Feb 26 13:55:17 2023 +0000
+
+    [wasm] Fix Rust docs
+
+ docs/wasm-shaper.md | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 4f537df67de6d1475de5caf14d9cfd9886621dc1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 15:29:35 2023 -0700
+
+    [wasm] Disable check-libstdc++ test
+    
+    Since libiwasm.so links to it.
+
+ src/meson.build | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit 2482bb120b8f29c830fe1c05d9b6bc75a651eae1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 15:14:25 2023 -0700
+
+    [wasm-shape] Add XXX item
+
+ src/hb-wasm-shape.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit a53690a937bc7c4273e5f46a7f87ac8945ff282b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 15:10:10 2023 -0700
+
+    [wasm-shape] Minor rename
+
+ src/hb-wasm-shape.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 3226b4342b88e44764393a6a9e1af458d70fa5fe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 15:03:03 2023 -0700
+
+    [wasm-shape] Use hb allocators
+
+ src/hb-wasm-shape.cc | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit 4096115b48e88881a73218b15e4f83ea128abbad
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 14:22:03 2023 -0700
+
+    [wasm-graphite] Export malloc/free
+    
+    Makes the wasm-micro-runtime use these instead of internal heap.
+
+ src/wasm/graphite/Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 7b1c5e86aea4babcecb572a9b69f04cf95f5d102
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 14:18:09 2023 -0700
+
+    [wasm-shape] Minor conditionalize allocation
+
+ src/hb-wasm-shape.cc | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+commit 196c6b6c1f8f528c5fbdce540156fb6375e03a80
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 14:05:15 2023 -0700
+
+    [wasm-buffer] Fix buffer_contents_realloc
+
+ src/hb-wasm-api-buffer.hh | 30 +++++++++++++++++-------------
+ 1 file changed, 17 insertions(+), 13 deletions(-)
+
+commit b9d4758bf9679a1ad502f0beba7db75569fbf1a4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 13:07:56 2023 -0700
+
+    [wasm/graphite] Add commented out allocator export
+
+ src/wasm/graphite/Makefile | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 3c599434332ba806babf4f280e491b5560ff0778
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 13:04:54 2023 -0700
+
+    [wasm/graphite] Remove stale comment
+
+ src/wasm/graphite/shape.cc | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit 6311b72fcce18703eff35010bd20c05a748ae3e5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 12:57:57 2023 -0700
+
+    [wasm-shape] Shuffle code around
+
+ src/hb-wasm-shape.cc | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit 9b66e45481c81c9af43d3dd5c2babad2121a9f59
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 12:44:32 2023 -0700
+
+    [wasm/graphite] Remove unused variable
+    
+    Wasm cannot export those?
+
+ src/wasm/graphite/shape.cc | 3 ---
+ 1 file changed, 3 deletions(-)
+
+commit c5a88a068b933ab67ffa8c39c97ad11f2dfbd7d0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 12:43:22 2023 -0700
+
+    [wasm-api] Minor cleanup
+
+ src/hb-wasm-api.h | 21 +++++++++------------
+ 1 file changed, 9 insertions(+), 12 deletions(-)
+
+commit 8215e7063232ffe3ff262c9839f1841e6d9bd7a1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 12:37:11 2023 -0700
+
+    [wasm-graphite] Memory hygiene
+
+ src/wasm/graphite/shape.cc | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit faaae04359862e49d0750592d0fc1ddf8b6d4e37
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 12:36:57 2023 -0700
+
+    [wasm-shape] Minor
+
+ src/hb-wasm-shape.cc | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit d5d8fc046fbd7b758f2e31b74e1b86b06b3acf8d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 12:17:30 2023 -0700
+
+    [wasm/graphite] Include standard headers
+    
+    Since we use emcc here.
+
+ src/wasm/graphite/shape.cc | 9 ++-------
+ 1 file changed, 2 insertions(+), 7 deletions(-)
+
+commit 1f86890b7526821279c6bf2bd3ead189bf558459
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 11:55:34 2023 -0700
+
+    [wasm/graphite] Typo
+
+ src/wasm/graphite/Makefile | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit f95c2cc6d5ce9db646efde99768e2847016afc38
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 11:10:28 2023 -0700
+
+    [wasm] Infra for iwasm llvm build
+
+ meson.build     | 2 ++
+ src/meson.build | 1 +
+ 2 files changed, 3 insertions(+)
+
+commit 65f7bac73c774e3e75efc35566b2d9466726ffd2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 11:07:31 2023 -0700
+
+    Revert "[wasm-shape] No need to set default runnint mode"
+    
+    This reverts commit fa484fac08a868e885b3252522668824f0f0fe71.
+
+ src/hb-wasm-shape.cc | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit d894a10699c08ebf2f4854f28b6343a6b5ff7aea
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 10:48:41 2023 -0700
+
+    [wasm-shape] Debug message
+
+ src/hb-wasm-shape.cc | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 91eb2f49dbf1e84da5e64f20a2b3c5b6f37f3c83
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 10:44:45 2023 -0700
+
+    [wasm-api-buffer] Minor variable
+
+ src/hb-wasm-api-buffer.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit 4260de12c1bb271033d9cd3b0f47a4cf77190bf3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 10:43:27 2023 -0700
+
+    [wasm] Add HB_ARRAY_APP2NATIVE
+
+ src/hb-wasm-api-buffer.hh | 7 +++----
+ src/hb-wasm-api-face.hh   | 2 +-
+ src/hb-wasm-api-font.hh   | 4 ++--
+ src/hb-wasm-api.hh        | 5 +++++
+ 4 files changed, 11 insertions(+), 7 deletions(-)
+
+commit 1537e252bad82ea03b2a1550d2464bddc24e6e49
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 10:35:15 2023 -0700
+
+    [wasm] Minor blob validation
+
+ src/hb-wasm-api-face.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 918df8ccaf48041994e3b107ed7d2f32d643ff03
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 10:29:03 2023 -0700
+
+    [wasm-api] Add glyph_outline_free
+
+ src/hb-wasm-api-font.hh             | 16 ++++++++++++++++
+ src/hb-wasm-api-list.hh             |  3 +++
+ src/hb-wasm-api.h                   |  4 ++++
+ src/wasm/sample/c/shape-fallback.cc |  8 +++++++-
+ 4 files changed, 30 insertions(+), 1 deletion(-)
+
+commit 7fff4a19ad0dc598f9eae271d2314003b2e44df5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 10:25:19 2023 -0700
+
+    [wasm-api] Reuse allocation in font_copy_glyph_outline
+
+ src/hb-wasm-api-font.hh             | 19 +++++++++++++++++++
+ src/hb-wasm-api.h                   |  1 +
+ src/wasm/sample/c/shape-fallback.cc |  2 +-
+ 3 files changed, 21 insertions(+), 1 deletion(-)
+
+commit 41362cc339d2e6e547291cf73dcc147fe39966d1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 10:08:22 2023 -0700
+
+    [wasm] Simplify memory cleaning
+
+ src/hb-wasm-api-buffer.hh | 3 ++-
+ src/hb-wasm-api-face.hh   | 2 +-
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+commit 6746ca4ae2aa0623a56676eb77bb63975e1016b0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 09:41:20 2023 -0700
+
+    [wasm] Minor remove undefine function
+
+ src/wasm/sample/c/shape-fallback.cc | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+commit b08026187ab7fbec7f8d6d4adca0a8dc9d02d74b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 09:34:03 2023 -0700
+
+    [wasm-api] Memory house-keeping
+
+ src/hb-wasm-api-buffer.hh | 2 ++
+ src/hb-wasm-api-face.hh   | 2 ++
+ 2 files changed, 4 insertions(+)
+
+commit f2d227ad9f03038ddbdb70b5a45adb29a19f5fb0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 09:30:40 2023 -0700
+
+    [wasm-api] Respect existing blob allocation in face_copy_blob
+
+ src/hb-wasm-api-face.hh             | 19 +++++++++++++++++--
+ src/hb-wasm-api.h                   |  1 +
+ src/wasm/graphite/shape.cc          |  2 +-
+ src/wasm/sample/c/shape-fallback.cc |  2 +-
+ 4 files changed, 20 insertions(+), 4 deletions(-)
+
+commit e7540043de3f38c4f442e696b569bcc6af90587f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 09:18:40 2023 -0700
+
+    [wasm-api] Make buffer_copy_contents reuse contents
+
+ src/hb-wasm-api-buffer.hh           | 26 +++++++++++++++++++++++++-
+ src/hb-wasm-api.h                   |  1 +
+ src/wasm/graphite/shape.cc          |  2 +-
+ src/wasm/sample/c/shape-fallback.cc |  2 +-
+ 4 files changed, 28 insertions(+), 3 deletions(-)
+
+commit 65966e0c3da0fdb5a59abcc76533dfceccbc1425
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 08:59:03 2023 -0700
+
+    [wasm-api] Add font_copy_glyph_outline
+
+ src/hb-wasm-api-font.hh             | 46 +++++++++++++++++++++++++++++++++++++
+ src/hb-wasm-api-list.hh             |  1 +
+ src/hb-wasm-api.h                   | 36 +++++++++++++++++++++++++++--
+ src/wasm/sample/c/shape-fallback.cc |  4 ++++
+ 4 files changed, 85 insertions(+), 2 deletions(-)
+
+commit 92a57b4b4aa60620040dd5a31dcb764643da9496
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Sat Feb 25 15:38:08 2023 +0000
+
+    [wasm-rust] update font_copy_table API
+
+ src/wasm/rust/harfbuzz-wasm/src/lib.rs | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+commit db789eacb41ecd74ee3c32d245e7e15640c58198
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Sat Feb 25 15:35:37 2023 +0000
+
+    [wasm-rust] Docs and API update
+
+ docs/wasm-shaper.md                    |  8 ++++----
+ src/wasm/rust/harfbuzz-wasm/src/lib.rs | 12 ++++++++++--
+ 2 files changed, 14 insertions(+), 6 deletions(-)
+
+commit 0d237d062e0826138769c405bb1c04c9ed8da247
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 08:32:35 2023 -0700
+
+    [wasm-shape] No need to set default runnint mode
+    
+    It's detected automatically apparently.
+
+ src/hb-wasm-shape.cc | 5 -----
+ 1 file changed, 5 deletions(-)
+
+commit 2004528cf8375b82c687e8b9eb12d485d14427f1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 08:23:14 2023 -0700
+
+    [wasm-api] Change face_copy_table to return success
+
+ src/hb-wasm-api-face.hh             | 29 ++++++++++++++++++++---------
+ src/hb-wasm-api-list.hh             |  2 +-
+ src/hb-wasm-api.h                   |  7 ++++---
+ src/wasm/graphite/shape.cc          |  4 +++-
+ src/wasm/sample/c/shape-fallback.cc |  5 ++++-
+ 5 files changed, 32 insertions(+), 15 deletions(-)
+
+commit 83b9c34f0b5d9b6b6f65aae0e1bb92877972a5ed
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Sat Feb 25 15:23:22 2023 +0000
+
+    [wasm] Add rust example
+
+ src/wasm/sample/rust/hello-wasm/Cargo.toml | 13 +++++++++++++
+ src/wasm/sample/rust/hello-wasm/src/lib.rs | 18 ++++++++++++++++++
+ 2 files changed, 31 insertions(+)
+
+commit 840b5dff734e566b258fc3a1ee556739af31b45c
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Sat Feb 25 15:20:39 2023 +0000
+
+    [wasm] Improve Rust docs, refer to new crate
+
+ docs/wasm-shaper.md | 103 +++++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 69 insertions(+), 34 deletions(-)
+
+commit 28a7c1f93247d692475ded0ea4dd6d0b5dd94044
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 08:16:31 2023 -0700
+
+    [wasm-api] Rename face_reference_table to face_copy_table
+
+ src/hb-wasm-api-face.hh                | 6 +++---
+ src/hb-wasm-api-list.hh                | 2 +-
+ src/hb-wasm-api.h                      | 6 +++---
+ src/wasm/graphite/shape.cc             | 2 +-
+ src/wasm/rust/harfbuzz-wasm/src/lib.rs | 4 ++--
+ src/wasm/sample/c/shape-fallback.cc    | 2 +-
+ 6 files changed, 11 insertions(+), 11 deletions(-)
+
+commit b5b577f29fd20016fab21b454403510d1098f132
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 08:12:16 2023 -0700
+
+    [wasm-api] Make buffer_copy_contents return success
+
+ src/hb-wasm-api-buffer.hh           | 24 ++++++++++++++++--------
+ src/hb-wasm-api-list.hh             |  2 +-
+ src/hb-wasm-api.h                   |  5 +++--
+ src/wasm/graphite/shape.cc          |  4 ++--
+ src/wasm/sample/c/shape-fallback.cc |  4 +++-
+ 5 files changed, 25 insertions(+), 14 deletions(-)
+
+commit 1023a80d395318e444458d0eebccab363133d5ef
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 07:57:04 2023 -0700
+
+    [wasm] Fix up samples
+
+ src/{wasm/graphite => }/addTable.py |  0
+ src/wasm/graphite/Makefile          | 17 ++++++++++-------
+ src/wasm/sample/addTable.py         | 16 ----------------
+ src/wasm/sample/c/Makefile          | 14 ++++++++------
+ 4 files changed, 18 insertions(+), 29 deletions(-)
+
+commit 4ad659a6088d4b86599a3334a9c0f7ceeec8c79e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 25 07:48:35 2023 -0700
+
+    [wasm] Move wasm-graphite
+
+ src/{wasm-graphite => wasm/graphite}/Makefile    | 0
+ src/{wasm-graphite => wasm/graphite}/addTable.py | 0
+ src/{wasm-graphite => wasm/graphite}/shape.cc    | 0
+ 3 files changed, 0 insertions(+), 0 deletions(-)
+
+commit 514a8d58d8820b7b21e2f25933bc9b0d6ea70672
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Sat Feb 25 14:42:13 2023 +0000
+
+    [wasm-api] Add ergonomic Rust interface
+
+ src/wasm/rust/harfbuzz-wasm/Cargo.toml |   8 +
+ src/wasm/rust/harfbuzz-wasm/src/lib.rs | 364 +++++++++++++++++++++++++++++++++
+ 2 files changed, 372 insertions(+)
+
+commit 74deaa9e7888f1433c053802877911cb643221f9
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Sat Feb 25 13:33:49 2023 +0000
+
+    [wasm-api] Restructure samples/libraries
+
+ src/{wasm-sample => wasm/sample}/addTable.py         |   0
+ src/{wasm-sample => wasm/sample/c}/Makefile          |   0
+ src/{wasm-sample => wasm/sample/c}/shape-fallback.cc |   0
+ src/{wasm-sample => wasm/sample/c}/shape-ot.cc       |   0
+ src/{wasm-sample => wasm/sample/c}/test.ttf          | Bin
+ 5 files changed, 0 insertions(+), 0 deletions(-)
+
+commit 4bdfaeecefae4136b9ceb451138f8055c7b74d02
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 20:05:35 2023 -0700
+
+    [wasm-shape] Set glyph flags
+
+ src/hb-wasm-shape.cc | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 77f0f3c11a5b9e2d5bbf20a6e2840c19822bc134
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 20:01:22 2023 -0700
+
+    [wasm-api] Make buffer_copy_contents return zero length on mem fail
+
+ src/hb-wasm-api-buffer.hh  |  4 ++--
+ src/hb-wasm-shape.cc       | 15 ++-------------
+ src/wasm-graphite/shape.cc |  2 ++
+ 3 files changed, 6 insertions(+), 15 deletions(-)
+
+commit 16ecb96922e2f1389cd634a2b908df0a72f8ac1f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 19:53:47 2023 -0700
+
+    [wasm-api] Return success from buffer_contents_realloc
+
+ src/hb-wasm-api-buffer.hh  | 42 ++++++++++++++++++++++++++++--------------
+ src/hb-wasm-api-list.hh    |  2 +-
+ src/hb-wasm-api.h          |  6 +++---
+ src/wasm-graphite/shape.cc |  3 ++-
+ 4 files changed, 34 insertions(+), 19 deletions(-)
+
+commit 2568890d15f2a271738a2ef23ca73d173bf120df
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 19:04:39 2023 -0700
+
+    [wasm-shape] Retry shaping if out-of-memory
+
+ src/hb-wasm-shape.cc       | 26 +++++++++++++++++++++++---
+ src/wasm-graphite/shape.cc |  4 ++++
+ 2 files changed, 27 insertions(+), 3 deletions(-)
+
+commit cb382e489d656a3d955c15feb99ea887f6d8985a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 17:56:14 2023 -0700
+
+    [wasm-shape] Cache wasm-shape-plan
+
+ src/hb-wasm-api-buffer.hh |   3 +
+ src/hb-wasm-shape.cc      | 202 +++++++++++++++++++++++++++++++---------------
+ 2 files changed, 140 insertions(+), 65 deletions(-)
+
+commit 73de7d4d05ab2c78e56a4b6156b52ebd2f107c8f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 17:44:33 2023 -0700
+
+    [wasm-api] Add shape_plan
+
+ src/hb-wasm-api.h                 |  9 ++++-
+ src/hb-wasm-shape.cc              | 75 ++++++++++++++++++++++++++++++++-------
+ src/wasm-graphite/shape.cc        | 24 ++++++++++---
+ src/wasm-sample/shape-fallback.cc |  3 +-
+ src/wasm-sample/shape-ot.cc       |  3 +-
+ 5 files changed, 93 insertions(+), 21 deletions(-)
+
+commit a267249930503f99a2517cd35f90556cefdea854
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 17:22:22 2023 -0700
+
+    [wasm] Typo
+
+ src/harfbuzz.cc      | 2 ++
+ src/hb-wasm-shape.cc | 2 +-
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+commit 99d2dab30f317058075d5a82c0dfedc898d6912d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 17:04:05 2023 -0700
+
+    [wasm] Try at autotools build
+
+ configure.ac         | 23 +++++++++++++++++++++++
+ src/Makefile.am      | 10 ++++++++++
+ src/Makefile.sources | 15 +++++++++++++--
+ src/harfbuzz.cc      |  2 --
+ 4 files changed, 46 insertions(+), 4 deletions(-)
+
+commit ed39e0766194194e0fcdd4b45cd428c4c1abd43d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 16:20:06 2023 -0700
+
+    [wasm] Fix docs
+
+ docs/harfbuzz-sections.txt | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit c5af08c0dc7388198019eab3ff16eccd614fce94
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 15:57:10 2023 -0700
+
+    [wasm] Add to harfbuzz.cc and hb-features
+
+ src/Makefile.am      | 9 +++++----
+ src/harfbuzz.cc      | 2 ++
+ src/hb-features.h.in | 7 +++++++
+ src/hb-wasm-api.cc   | 6 ++++++
+ src/meson.build      | 3 ++-
+ 5 files changed, 22 insertions(+), 5 deletions(-)
+
+commit aa8f9eed63698ae5b40b7f3cca284a5535eaf661
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 15:20:37 2023 -0700
+
+    [wasm-shape] Use JIT running-modes if available
+    
+    Build wasm-micro-runtime with:
+    
+    $ cmake . -DWAMR_BUILD_REF_TYPES=1 -DWAMR_BUILD_FAST_JIT=1
+    
+    or:
+    
+    $ cmake . -DWAMR_BUILD_REF_TYPES=1 -DWAMR_BUILD_JIT=1
+    
+    The latter needs llvm and is harder to get working. Still trying.
+
+ src/hb-wasm-shape.cc | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit 8d960dfe68da0393eafd92a66fa4277b2e1d6e63
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 15:07:40 2023 -0700
+
+    [wasm-sample] Remove Wasm table from test.ttf again
+    
+    Was added by mistake.
+
+ src/wasm-sample/test.ttf | Bin 23468 -> 22116 bytes
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+
+commit 1c6d640e1fbf459b3cf2ef66ad48560e8469f72e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 15:01:36 2023 -0700
+
+    [wasm-shaper] Whitespace
+
+ src/hb-wasm-shape.cc       | 9 +++------
+ src/wasm-graphite/Makefile | 2 +-
+ 2 files changed, 4 insertions(+), 7 deletions(-)
+
+commit 9f8ad3928afeaf10a0dac8e7d0f3df6bd822c63d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 14:16:11 2023 -0700
+
+    [wasm-api] Bind shaper features
+
+ src/hb-wasm-api-blob.hh           |  2 +-
+ src/hb-wasm-api-buffer.hh         |  6 +++---
+ src/hb-wasm-api-font.hh           |  6 +++---
+ src/hb-wasm-api-list.hh           |  2 +-
+ src/hb-wasm-api-shape.hh          | 14 ++++++++++++--
+ src/hb-wasm-api.h                 | 18 +++++++++++++++---
+ src/hb-wasm-api.hh                | 11 ++++++++++-
+ src/hb-wasm-shape.cc              | 12 +++++++++++-
+ src/wasm-graphite/shape.cc        |  5 ++++-
+ src/wasm-sample/shape-fallback.cc |  5 ++++-
+ src/wasm-sample/shape-ot.cc       |  7 +++++--
+ 11 files changed, 69 insertions(+), 19 deletions(-)
+
+commit 2327fe9d8a77c930ec5e939060c714ef3008d325
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 13:35:47 2023 -0700
+
+    [hb-wasm] Remove TODO
+
+ src/hb-wasm-shape.cc | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit b130b2b3317d296f0120acf5f9aab4bab39f2506
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 13:34:16 2023 -0700
+
+    [graphite] Simplify direction handling
+
+ src/hb-graphite2.cc | 23 +++++++++++------------
+ 1 file changed, 11 insertions(+), 12 deletions(-)
+
+commit ec3270c7bb162a8e8996192922628502dab9d5a2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 13:31:10 2023 -0700
+
+    [wasm-graphite] Ensure native direction here too
+    
+    Binds buffer_get_script and script_get_horizontal_direction.
+
+ src/hb-wasm-api-buffer.hh  |  8 ++++++++
+ src/hb-wasm-api-common.hh  | 44 ++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-wasm-api-list.hh    |  3 +++
+ src/hb-wasm-api.cc         |  1 +
+ src/hb-wasm-api.h          | 11 +++++++++++
+ src/meson.build            |  1 +
+ src/wasm-graphite/shape.cc | 21 +++++++++++++++------
+ 7 files changed, 83 insertions(+), 6 deletions(-)
+
+commit cbc71c56bcc5eded3e2393a0b1d2b380fa5944a0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 13:15:11 2023 -0700
+
+    [graphite] Ensure native direction
+    
+    Mirrored characters come out wrong. Oh well. Better than before though.
+
+ src/hb-graphite2.cc | 18 ++++++++++++++++--
+ 1 file changed, 16 insertions(+), 2 deletions(-)
+
+commit 39f8703df17cc49b8630597fc250b13ef61870b8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 12:42:22 2023 -0700
+
+    [wasm-api] Match interface and implementation signatures
+
+ src/hb-wasm-api-blob.hh   |  5 ++--
+ src/hb-wasm-api-buffer.hh | 65 +++++++++++++++++++++--------------------------
+ src/hb-wasm-api-face.hh   | 12 ++++-----
+ src/hb-wasm-api-font.hh   | 55 +++++++++++++++++----------------------
+ src/hb-wasm-api-shape.hh  |  9 +++----
+ src/hb-wasm-api.hh        |  1 -
+ 6 files changed, 64 insertions(+), 83 deletions(-)
+
+commit fea3ffe03147c35180be09b42caee90a96c61a34
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 12:31:32 2023 -0700
+
+    [wasm-api] Beautify internal API
+
+ src/hb-wasm-api-blob.hh   |  2 +-
+ src/hb-wasm-api-buffer.hh | 16 +++++++-------
+ src/hb-wasm-api-face.hh   |  4 ++--
+ src/hb-wasm-api-font.hh   | 20 +++++++++---------
+ src/hb-wasm-api-shape.hh  |  4 ++--
+ src/hb-wasm-api.h         | 53 +++++++++++++++++++++++++----------------------
+ src/hb-wasm-api.hh        |  3 ++-
+ 7 files changed, 53 insertions(+), 49 deletions(-)
+
+commit fe557e2f21108181496b8f23c92595e0d24d7d20
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 12:20:31 2023 -0700
+
+    [wasm-api] Bind font_get_glyph_extents
+    
+    Untested.
+
+ src/hb-wasm-api-font.hh | 17 +++++++++++++++++
+ src/hb-wasm-api-list.hh |  1 +
+ src/hb-wasm-api.h       | 12 ++++++++++++
+ 3 files changed, 30 insertions(+)
+
+commit b3b6e8da86b8bda05311fe9524ac169040ba9cf3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 12:03:53 2023 -0700
+
+    [wasm-api] Bind buffer_reverse
+
+ src/hb-wasm-api-buffer.hh | 9 +++++++++
+ src/hb-wasm-api-list.hh   | 1 +
+ src/hb-wasm-api.h         | 3 +++
+ 3 files changed, 13 insertions(+)
+
+commit 863ec70e1240379875fe72baeada79c0d9f79fe4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 12:00:29 2023 -0700
+
+    [wasm-shape] Add TODO items
+
+ src/hb-wasm-shape.cc | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit 1acff90b0337d9a0158c4b8afddaf485a8037b67
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 11:53:47 2023 -0700
+
+    [wasm-api] Bind font_glyph_to_string
+
+ src/hb-wasm-api-font.hh           | 12 ++++++++++++
+ src/hb-wasm-api-list.hh           |  1 +
+ src/hb-wasm-api.h                 |  5 +++++
+ src/wasm-graphite/shape.cc        |  3 +++
+ src/wasm-sample/shape-fallback.cc |  8 +++++++-
+ 5 files changed, 28 insertions(+), 1 deletion(-)
+
+commit 7537d48f081f25e3bd78dcacf9218535a1e40c2f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 11:47:17 2023 -0700
+
+    [wasm] Remove a few lingering hb_
+
+ src/hb-wasm-api-font.hh    | 12 ++++++------
+ src/hb-wasm-api.h          | 32 ++++++++++++++++----------------
+ src/wasm-graphite/shape.cc |  2 +-
+ 3 files changed, 23 insertions(+), 23 deletions(-)
+
+commit d7f76f30b0dcfda3f4322b3e240be30b4a141cc7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 11:31:04 2023 -0700
+
+    [wasm-graphite] Memory cleanup
+
+ src/wasm-graphite/shape.cc | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+commit 5738851b1ca0471b4ac270b89549466202fddf10
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 11:05:59 2023 -0700
+
+    [wasm-api] Disallow "wasm" shaper in shape_with
+
+ src/hb-wasm-api-shape.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 2bde2f66f1391ca4d1c0e38142a6ea0f175173ab
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 11:03:13 2023 -0700
+
+    [wasm-api] Bind shape_with
+
+ src/hb-wasm-api-list.hh                        |  3 ++
+ src/hb-wasm-api-shape.hh                       | 50 ++++++++++++++++++++++++++
+ src/hb-wasm-api.cc                             |  1 +
+ src/hb-wasm-api.h                              |  8 +++++
+ src/meson.build                                |  1 +
+ src/wasm-sample/Makefile                       | 15 ++++----
+ src/wasm-sample/{shape.c => shape-fallback.cc} |  6 ++--
+ src/wasm-sample/shape-ot.cc                    | 14 ++++++++
+ 8 files changed, 90 insertions(+), 8 deletions(-)
+
+commit a08dbf41cd20bf36828b58a4e4b448671ee036c1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 10:13:21 2023 -0700
+
+    [wasm-api] Bind buffer_reverse_clusters
+
+ src/hb-wasm-api-buffer.hh  | 8 ++++++++
+ src/hb-wasm-api-list.hh    | 1 +
+ src/hb-wasm-api.h          | 2 ++
+ src/wasm-graphite/Makefile | 2 +-
+ src/wasm-graphite/shape.cc | 6 +++---
+ 5 files changed, 15 insertions(+), 4 deletions(-)
+
+commit 0a51ed31b0bba05727210f27548ebd3b55052fe3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 10:07:59 2023 -0700
+
+    [wasm-api] Bind buffer_get_direction
+
+ src/hb-wasm-api-buffer.hh  | 10 ++++++++++
+ src/hb-wasm-api-list.hh    |  1 +
+ src/hb-wasm-api.h          | 17 +++++++++++++++++
+ src/wasm-graphite/shape.cc | 11 ++++++-----
+ 4 files changed, 34 insertions(+), 5 deletions(-)
+
+commit a5c844a1de2a6f5c0acda723d4367c41d7a7b90c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 09:52:38 2023 -0700
+
+    [wasm] Rename macro
+
+ src/hb-wasm-api-blob.hh   | 2 +-
+ src/hb-wasm-api-buffer.hh | 6 +++---
+ src/hb-wasm-api-font.hh   | 4 ++--
+ src/hb-wasm-api.hh        | 2 +-
+ 4 files changed, 7 insertions(+), 7 deletions(-)
+
+commit 23b58b5667aa6ffe2780860e7a9202149e05eac3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 09:50:34 2023 -0700
+
+    [wasm-api] Bind font_get_scale
+
+ src/hb-wasm-api-buffer.hh  |  2 +-
+ src/hb-wasm-api-face.hh    |  2 +-
+ src/hb-wasm-api-font.hh    | 15 ++++++++++++++-
+ src/hb-wasm-api-list.hh    |  1 +
+ src/hb-wasm-api.h          |  5 +++++
+ src/hb-wasm-api.hh         |  2 +-
+ src/wasm-graphite/shape.cc |  6 ++++--
+ 7 files changed, 27 insertions(+), 6 deletions(-)
+
+commit 149199ee26cfac1ff211b2283f8c79b1c7b8cdd0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 09:39:25 2023 -0700
+
+    [wasm-api] Bind face_get_upem
+
+ src/hb-wasm-api-face.hh    | 9 +++++++++
+ src/hb-wasm-api-list.hh    | 1 +
+ src/hb-wasm-api.h          | 5 +++++
+ src/wasm-graphite/shape.cc | 4 ++--
+ 4 files changed, 17 insertions(+), 2 deletions(-)
+
+commit 2d295183b8ed47fa3efa4b83aff1d7781d97ab4f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 09:20:42 2023 -0700
+
+    [wasm-api] Add buffer_contents_realloc
+
+ src/hb-wasm-api-buffer.hh  | 33 ++++++++++++++++++++++++++++++++-
+ src/hb-wasm-api-list.hh    |  1 +
+ src/hb-wasm-api.h          |  4 ++++
+ src/wasm-graphite/shape.cc |  3 +--
+ 4 files changed, 38 insertions(+), 3 deletions(-)
+
+commit 07ece174954a3345f05be3c23766119e6554dbf5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 08:08:18 2023 -0700
+
+    [wasm-graphite] Initial code
+
+ src/hb-wasm-api-face.hh       |   2 +-
+ src/hb-wasm-shape.cc          |   2 +-
+ src/wasm-graphite/Makefile    |  22 +++++
+ src/wasm-graphite/addTable.py |  16 ++++
+ src/wasm-graphite/shape.cc    | 210 ++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 250 insertions(+), 2 deletions(-)
+
+commit ae981eec8e33abe7052176733c1ed84cdaeb082f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 21:36:17 2023 -0700
+
+    [graphite] Remove script handling
+    
+    https://github.com/harfbuzz/harfbuzz/issues/3439#issuecomment-1442650148
+
+ src/hb-graphite2.cc | 10 +---------
+ 1 file changed, 1 insertion(+), 9 deletions(-)
+
+commit 5ab7f7a7d41720bb8ea189df0c5c47db1a22d550
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 16:11:54 2023 -0700
+
+    [wasm-sample] Make addTable take args
+
+ src/wasm-sample/Makefile    |   2 +-
+ src/wasm-sample/addTable.py |  11 ++++++++---
+ src/wasm-sample/test.ttf    | Bin 22116 -> 23468 bytes
+ 3 files changed, 9 insertions(+), 4 deletions(-)
+
+commit 551528a6e6bef10b3bfbc254c949d7247fba8176
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 16:06:39 2023 -0700
+
+    [wasm-sample] Remove unused prototype
+
+ src/wasm-sample/shape.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit 926f8a326e42b557d2991bddf5e234289677c362
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 15:52:13 2023 -0700
+
+    [wasm-sample] Actually shape text!
+
+ src/wasm-sample/shape.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit c1dc112121e8ce7e3c75fae0c9e3589176bbc2f8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 15:47:56 2023 -0700
+
+    [wasm-api] Bind buffer_set_contents
+
+ src/hb-buffer.hh          |  7 +++++++
+ src/hb-wasm-api-buffer.hh | 34 +++++++++++++++++++++++++++++++---
+ src/hb-wasm-api-list.hh   |  7 ++++---
+ src/hb-wasm-api.h         |  4 ++++
+ src/wasm-sample/shape.c   |  8 +++++++-
+ 5 files changed, 53 insertions(+), 7 deletions(-)
+
+commit e0fec1dda01f1060dd474537dcbe5084ef46a88f
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Thu Feb 23 22:18:22 2023 +0000
+
+    [wasm-api] Wrap some of hb-font
+
+ src/hb-wasm-api-font.hh | 31 +++++++++++++++++++++++++++++++
+ src/hb-wasm-api-list.hh |  5 ++++-
+ src/hb-wasm-api.h       | 13 ++++++++++++-
+ 3 files changed, 47 insertions(+), 2 deletions(-)
+
+commit af1f41a43ee7b7bb06e43e7000101019ae24f66a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 15:17:18 2023 -0700
+
+    [wasm-api] Clear structs in _free()
+
+ src/hb-wasm-api-blob.hh   | 3 +++
+ src/hb-wasm-api-buffer.hh | 4 ++++
+ 2 files changed, 7 insertions(+)
+
+commit 099a0150e1ba3af96d52629a04fe5def489c4b34
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 15:15:06 2023 -0700
+
+    [wasm] Add HB_STRUCT_TYPE
+
+ src/hb-wasm-api-blob.hh   | 5 ++---
+ src/hb-wasm-api-buffer.hh | 5 ++---
+ src/hb-wasm-api.hh        | 9 +++++++++
+ 3 files changed, 13 insertions(+), 6 deletions(-)
+
+commit 851ef1380aec550e51a4d8055a9c8aef2b57aeeb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 15:06:18 2023 -0700
+
+    [wasm-api] Add buffer-contents-free
+
+ src/hb-wasm-api-buffer.hh | 13 +++++++++++++
+ src/hb-wasm-api-list.hh   |  1 +
+ src/hb-wasm-api.h         |  5 +++--
+ src/wasm-sample/shape.c   |  2 ++
+ 4 files changed, 19 insertions(+), 2 deletions(-)
+
+commit d38f02ab30e3696614c295f88beadb655110599a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 15:03:03 2023 -0700
+
+    [wasm-api] Make ref types actual pointers on the wasm side
+
+ src/hb-wasm-api-buffer.hh |  2 +-
+ src/hb-wasm-api-face.hh   |  2 +-
+ src/hb-wasm-api-font.hh   |  4 ++--
+ src/hb-wasm-api.h         | 25 ++++++++++++-------------
+ src/wasm-sample/shape.c   |  4 ++--
+ 5 files changed, 18 insertions(+), 19 deletions(-)
+
+commit cbd5c554fb28d3aa2ac834c28e6d89600e969f62
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 14:54:46 2023 -0700
+
+    [wasm-api] Add blob_free
+
+ src/hb-wasm-api-blob.hh  | 49 ++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-wasm-api-list.hh  |  3 +++
+ src/hb-wasm-api.cc       |  1 +
+ src/hb-wasm-api.h        |  3 ++-
+ src/meson.build          |  1 +
+ src/wasm-sample/Makefile |  2 ++
+ src/wasm-sample/shape.c  |  2 +-
+ 7 files changed, 59 insertions(+), 2 deletions(-)
+
+commit 3bec8dca1ca108a9c64af36c768eda58bdec2d95
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 14:35:01 2023 -0700
+
+    [wasm-sample] Free blob data for now
+
+ src/wasm-sample/shape.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit d45a13f1018a18a8ea797b717253cbf6f42f9fe8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 14:28:16 2023 -0700
+
+    [wasm] Add wasm-sample/
+
+ src/wasm-sample/Makefile    |  18 ++++++++++++++++++
+ src/wasm-sample/addTable.py |  11 +++++++++++
+ src/wasm-sample/shape.c     |  25 +++++++++++++++++++++++++
+ src/wasm-sample/test.ttf    | Bin 0 -> 22116 bytes
+ 4 files changed, 54 insertions(+)
+
+commit 5cecfe865919ff2c72a0409e34265d79f78750d0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 13:58:40 2023 -0700
+
+    [wasm-api] Bind buffer_copy_contents
+
+ src/hb-wasm-api-buffer.hh | 58 +++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-wasm-api-face.hh   |  8 +++----
+ src/hb-wasm-api-font.hh   |  8 +++----
+ src/hb-wasm-api-list.hh   |  3 +++
+ src/hb-wasm-api.cc        |  1 +
+ src/hb-wasm-api.h         | 43 ++++++++++++++++++++++++++++++++++-
+ src/meson.build           |  9 +++++++-
+ 7 files changed, 120 insertions(+), 10 deletions(-)
+
+commit 50b22368d04893afa9227ac2c3321ef43c5ae638
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 13:41:41 2023 -0700
+
+    Revert "Fix function signature"
+    
+    This reverts commit d70ebf98b0c696f3c66a20b1243cb347e3e3abc8.
+    
+    Nope. A struct return is not returned that way.
+
+ src/hb-wasm-api-list.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 743cd2c46ee0c81958e2c360d56391da679107f6
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Thu Feb 23 20:35:16 2023 +0000
+
+    Fix function signature
+
+ src/hb-wasm-api-list.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3b88bd9742b06e5f0ebd90b39f1fdce6b2129e91
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 13:27:46 2023 -0700
+
+    [wasm-api] Make ptr_t a pointer on the wasm side
+
+ src/hb-wasm-api.h  | 7 ++++---
+ src/hb-wasm-api.hh | 4 +++-
+ 2 files changed, 7 insertions(+), 4 deletions(-)
+
+commit d7a6671676f9ec5b6b2e8f3a964d1ef9f85f9e3a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 13:16:49 2023 -0700
+
+    [wasm-api] Add debugprint1/2/3/4
+
+ src/hb-wasm-api-list.hh | 22 ++++++++++++++++------
+ 1 file changed, 16 insertions(+), 6 deletions(-)
+
+commit 108995bbc67aa4a45657127eab6b9f89171355fd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 13:04:38 2023 -0700
+
+    [wasm-api] Finish face_reference_table
+
+ src/hb-wasm-api-face.hh | 13 ++++++++++---
+ 1 file changed, 10 insertions(+), 3 deletions(-)
+
+commit 69b1707d82b498eb88a097c72595a848c3e0007f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 13:00:06 2023 -0700
+
+    [wasm] Return empty object when ref2obj fails
+
+ src/hb-wasm-api-face.hh | 2 --
+ src/hb-wasm-api-font.hh | 3 ---
+ src/hb-wasm-api.hh      | 2 +-
+ 3 files changed, 1 insertion(+), 6 deletions(-)
+
+commit e87b1b3ec3a67bf42edac41236e1e70a56ff7072
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 12:23:52 2023 -0700
+
+    [wasm-api] Try to add face_reference_table
+
+ src/hb-wasm-api-face.hh | 51 +++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-wasm-api-list.hh |  3 +++
+ src/hb-wasm-api.cc      |  4 +---
+ src/hb-wasm-api.h       | 41 ++++++++++++++++++++++++++++++---------
+ src/hb-wasm-api.hh      | 19 ++++++++++++++++--
+ 5 files changed, 104 insertions(+), 14 deletions(-)
+
+commit e03726d26948b6f9cf2c64df75230c3e15433f44
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 12:00:42 2023 -0700
+
+    [wasm] Ignore API in the docs
+
+ docs/meson.build | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 747dcf561d710d324b02249806fa0b113178c3d2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 11:53:08 2023 -0700
+
+    [wasm] Strong typing for object references
+    
+    Such that wasm cannot crash us by passing wrong object refs.
+    
+    https://github.com/bytecodealliance/wasm-micro-runtime/discussions/1987
+    
+    It still is unsafe if some code in the process other than HarfBuzz
+    registers refs with wasm-micro-runtime, since wasm_externref_ref2obj()
+    takes no context variable and looks up refs globally :(.
+    
+    Maybe I fix that later by keeping a hash table of ref->obj-type instead.
+
+ src/hb-wasm-api.cc   | 11 ++---------
+ src/hb-wasm-api.hh   | 32 ++++++++++++++++++++++++++++++++
+ src/hb-wasm-shape.cc | 41 +++++++++++++++++++++--------------------
+ 3 files changed, 55 insertions(+), 29 deletions(-)
+
+commit 6b72a18c7b981ac0126ea3b585f16449ce3dd25b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 11:06:48 2023 -0700
+
+    [wasm-api] Rename file
+
+ src/{hb-wasm-font.hh => hb-wasm-api-font.hh} | 0
+ src/hb-wasm-api.cc                           | 2 +-
+ 2 files changed, 1 insertion(+), 1 deletion(-)
+
+commit 42d121ae79ce547f1bbe82b9fa771725604546d3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 11:05:19 2023 -0700
+
+    [wasm] Add hb-wasm-api.cc
+
+ src/hb-wasm-api-list.hh |  1 -
+ src/hb-wasm-api.cc      | 45 +++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-wasm-api.hh      | 20 --------------------
+ src/hb-wasm-shape.cc    |  1 +
+ src/meson.build         |  2 +-
+ 5 files changed, 47 insertions(+), 22 deletions(-)
+
+commit 980706441b58878cb168543eef70247eccc6abf6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 10:58:22 2023 -0700
+
+    [wasm] Add hb-wasm-api-list.hh
+
+ src/hb-wasm-api-list.hh | 61 +++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-wasm-api.hh      | 30 +-----------------------
+ 2 files changed, 62 insertions(+), 29 deletions(-)
+
+commit 65efad6b59f6252b2b314e5e16b958bf1b8f4e80
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 10:49:02 2023 -0700
+
+    [wasm] Make debugprint use debug API
+
+ src/hb-wasm-api.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit bb8a04cbadc16c8195b87e8fd307a2403d2212fa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 10:37:44 2023 -0700
+
+    [wasm] Remove the print(returnval) and use it to fail shaper
+
+ docs/wasm-shaper.md  | 2 --
+ src/hb-wasm-shape.cc | 8 +-------
+ 2 files changed, 1 insertion(+), 9 deletions(-)
+
+commit 11fc83c0ba349a6f376a8409971b5698bba39b19
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Thu Feb 23 17:34:02 2023 +0000
+
+    [Docs] Pass a C string from Rust to HB
+
+ docs/wasm-shaper.md | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+commit 36dd27bf3f4c35fde6041a91aeb275d4c8624624
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Thu Feb 23 17:33:50 2023 +0000
+
+    Just printf, don't take length
+
+ src/hb-wasm-api.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 3bc0ecf28c97a5891a9f2cfb371c41505640beef
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 10:30:35 2023 -0700
+
+    [wasm-api] Add ref_t
+
+ src/hb-wasm-api.h | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+commit 62f3c7cf67c8b468b49380346a0dbd22c0ad174e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 10:29:04 2023 -0700
+
+    [wasm-api] Add macros for ref handling
+
+ src/hb-wasm-api.hh  | 13 ++++++++++++-
+ src/hb-wasm-font.hh |  9 ++++-----
+ 2 files changed, 16 insertions(+), 6 deletions(-)
+
+commit 4c8a414a101c9657fda42d2fdb9789407b034c99
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 10:22:12 2023 -0700
+
+    [wasm-api] Clean up debugprint
+
+ src/hb-wasm-api.hh | 21 ++++++++++++---------
+ 1 file changed, 12 insertions(+), 9 deletions(-)
+
+commit 63904538c8215312489afd0277d78199c88a512a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 10:11:22 2023 -0700
+
+    [wasm-api] Use i32 instead of externref in API spec
+    
+    Oh well...
+
+ src/hb-wasm-api.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit bd28d01a6a1e562dc611e386544075f6caeacf21
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 09:49:46 2023 -0700
+
+    [wasm-api] Add HB_WASM_INTERFACE
+
+ src/hb-wasm-api.h | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+commit ed1a70c7e8ddf78ea3fd3e6208e683870ff7e893
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Thu Feb 23 16:41:17 2023 +0000
+
+    Only export debugprint when HB_DEBUG_WASM
+
+ src/hb-wasm-api.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 89c50b0ccb60fc0d73f2b9d65ccbdaebe6fef5b1
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Thu Feb 23 16:41:04 2023 +0000
+
+    Fix debugprint format string
+
+ src/hb-wasm-api.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f0200445d0606019cec868dfc92b1cde5015e6d5
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Thu Feb 23 16:38:39 2023 +0000
+
+    Initial WASM docs and Rust example
+
+ docs/wasm-shaper.md | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 116 insertions(+)
+
+commit fd1f7f46f46cd9dba29ad4975f09f6d4073edae4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 09:25:05 2023 -0700
+
+    [wasm-api] Implement font_get_face
+
+ src/hb-wasm-api.hh  |  7 ++++++-
+ src/hb-wasm-font.hh | 12 ++++++++++--
+ 2 files changed, 16 insertions(+), 3 deletions(-)
+
+commit 9f4dc2e103290cd7447ab24b2561c52d0f66344b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 09:18:25 2023 -0700
+
+    [wasm] Bind native API
+
+ src/hb-wasm-api.h    | 10 ++++++++--
+ src/hb-wasm-api.hh   | 27 +++++++++++++++++++++++++++
+ src/hb-wasm-font.hh  |  3 ++-
+ src/hb-wasm-shape.cc | 25 ++-----------------------
+ 4 files changed, 39 insertions(+), 26 deletions(-)
+
+commit e79a7318c4956fa9a8974812332480ccc5a13991
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 09:03:06 2023 -0700
+
+    [wasm] Start adding wasm-api
+
+ src/harfbuzz-subset.cc |  1 -
+ src/harfbuzz.cc        |  1 -
+ src/hb-wasm-api.h      | 29 +++++++++++++++++------------
+ src/hb-wasm-api.hh     | 45 +++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-wasm-font.hh    | 44 ++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-wasm-shape.cc   |  4 ++--
+ 6 files changed, 108 insertions(+), 16 deletions(-)
+
+commit 829ba7428476da0616d6b92b88189224acc36cf0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 08:32:14 2023 -0700
+
+    [wasm] Add hb-wasm-api.h
+
+ src/hb-wasm-api.h | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 70 insertions(+)
+
+commit 11c6d46086f5758a71df8e58059e087cd9c1766f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 23 08:16:49 2023 -0700
+
+    [wasm] Pass font & buff to shape() function
+
+ src/hb-wasm-shape.cc | 24 ++++++++++++++++++++----
+ 1 file changed, 20 insertions(+), 4 deletions(-)
+
+commit 05bf9842128376db20b1c1da91efe0257b23a351
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Thu Feb 23 14:55:49 2023 +0000
+
+    Add a simple callback native function
+
+ src/hb-wasm-shape.cc | 27 ++++++++++++---------------
+ 1 file changed, 12 insertions(+), 15 deletions(-)
+
+commit bdbc1568bac50371d4b552e179ecfc338f12fd43
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 22 23:30:28 2023 -0700
+
+    [wasm] Port from c_api to wasm-micro-runtime wasm_runtime API
+
+ src/hb-debug.hh      |   4 ++
+ src/hb-wasm-shape.cc | 190 +++++++++++++++++++++++++++++++--------------------
+ 2 files changed, 119 insertions(+), 75 deletions(-)
+
+commit db8e51e01b972aaf6d32309ef5aa381964950af4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 22 13:33:34 2023 -0700
+
+    [wasm] More boilerplate
+
+ src/hb-wasm-shape.cc | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 67 insertions(+), 2 deletions(-)
+
+commit fcc8be409b8a8034af54caa0ccd0a91206fdbf6b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 22 12:57:19 2023 -0700
+
+    [wasm] Add meson build option
+    
+    Autotools support missing.
+
+ meson.build          |  5 ++++-
+ meson_options.txt    |  2 ++
+ src/hb-wasm-shape.cc | 57 +++++++++++++++++++++++++++++++++++++++++++---------
+ src/meson.build      | 10 ++++++++-
+ 4 files changed, 63 insertions(+), 11 deletions(-)
+
+commit 425fc7f3ee257b7aee9a481a04d368c4ccf57c4d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 22 12:19:06 2023 -0700
+
+    [wasm] Add wasm shaper skeleton
+
+ meson.build            |   2 +
+ src/Makefile.sources   |   1 +
+ src/harfbuzz-subset.cc |   1 +
+ src/harfbuzz.cc        |   1 +
+ src/hb-shaper-list.hh  |   5 +++
+ src/hb-wasm-shape.cc   | 100 +++++++++++++++++++++++++++++++++++++++++++++++++
+ src/meson.build        |   1 +
+ 7 files changed, 111 insertions(+)
+
+commit 04a47932a3844f7e73e3af8b05fb98c8b54fb779
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Mar 31 11:44:08 2023 -0600
+
+    [paint] Remove enum trailing comma in C header
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/discussions/4188
+
+ src/hb-paint.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 2cd81fdfb6ccc6ba7ec63abe14e0126ece71f304
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Mar 30 22:11:43 2023 +0000
+
+    [subset] fix memory leak.
+    
+    Fixes fuzzer issue https://oss-fuzz.com/testcase-detail/6169920089227264
+
+ src/hb-subset-plan.cc                                    |   3 ++-
+ ...-testcase-minimized-hb-subset-fuzzer-6169920089227264 | Bin 0 -> 1214 bytes
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+commit 453ded05392af38bba9f89587edce465e86ffa6b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Mar 28 13:17:15 2023 -0600
+
+    [indic] Tighten up base-finding
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4185
+
+ src/hb-ot-shaper-indic.cc | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit c1acfe9966b1d2bd74c80de4aefcccc309664822
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Mar 22 19:06:58 2023 -0700
+
+    [instancer] bug fix in TupleVariationData get_size ()
+    
+    We need to iterate TupleVariationHeader when calculating the total size
+
+ src/hb-ot-var-common.hh                                  |   7 +++++--
+ .../Muli-ABC.default.retain-all-codepoint.wght=300.ttf   | Bin 0 -> 5808 bytes
+ .../Muli-ABC.default.retain-all-codepoint.wght=700.ttf   | Bin 0 -> 5804 bytes
+ test/subset/data/fonts/Muli-ABC.ttf                      | Bin 0 -> 6996 bytes
+ test/subset/data/tests/apply_cvar_delta.tests            |   1 +
+ 5 files changed, 6 insertions(+), 2 deletions(-)
+
+commit be872001063d263efe708c4db5af569cfaedd3fe
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Mar 24 17:30:53 2023 +0000
+
+    [subset] fix buffer overflow fuzzer reported issue.
+
+ src/hb-subset-plan.cc                                    |  14 ++++++++------
+ ...-testcase-minimized-hb-subset-fuzzer-5120246288875520 | Bin 0 -> 2501 bytes
+ 2 files changed, 8 insertions(+), 6 deletions(-)
+
+commit 79ae6b657f9c7bff8c97eb8ee7d2dbeb2217868e
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Mar 24 17:14:55 2023 +0000
+
+    [subset] Fix fuzzer found memory leaks.
+
+ src/hb-subset-plan.cc                                    |   9 +++++++--
+ ...-testcase-minimized-hb-subset-fuzzer-5793182905663488 | Bin 0 -> 803 bytes
+ ...-testcase-minimized-hb-subset-fuzzer-6742230974201856 | Bin 0 -> 1214 bytes
+ 3 files changed, 7 insertions(+), 2 deletions(-)
+
+commit ab87d7d22545f6774a12688708d21e6e18ae7fb4
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Mar 20 12:24:22 2023 -0700
+
+    [instance] add tests for colrv1 full instancing
+
+ test/subset/data/Makefile.am                             |   1 +
+ test/subset/data/Makefile.sources                        |   1 +
+ .../Foldit.default.retain-all-codepoint.wght=900.ttf     | Bin 0 -> 2508 bytes
+ test/subset/data/tests/instantiate_colrv1.tests          |  14 ++++++++++++++
+ test/subset/meson.build                                  |   1 +
+ 5 files changed, 17 insertions(+)
+
+commit fe671a5ac811e542071a7cd2151d6c045b77158a
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Mar 16 14:10:21 2023 -0700
+
+    [instancer] support COLRv1 full instancing
+
+ src/OT/Color/COLR/COLR.hh | 379 +++++++++++++++++++++++++++++++++++++---------
+ src/hb-ot-var-common.hh   |  14 +-
+ 2 files changed, 312 insertions(+), 81 deletions(-)
+
+commit f0f7f22525d20ba05e9b69ba40b352cb89b506ae
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Mar 20 18:39:49 2023 +0000
+
+    [subset] fix fuzzer found null deref.
+    
+    https://oss-fuzz.com/testcase-detail/5844352760152064
+
+ src/hb-subset-plan.cc                                    |   9 +++++++--
+ ...-testcase-minimized-hb-subset-fuzzer-5844352760152064 | Bin 0 -> 1214 bytes
+ 2 files changed, 7 insertions(+), 2 deletions(-)
+
+commit 79233a149209e3da199bb4e2f74271668502c574
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Mar 17 00:58:58 2023 +0000
+
+    [subset] fix incorrectly specified lock.
+    
+    Lock variable must have a name or it will immediately destruct.
+
+ src/hb-subset-plan.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 8d8bcde8cfe214855fdde15b5d9448e87d3ec734
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Mar 15 17:29:08 2023 +0000
+
+    [set] don't allow -1 (HB_SET_VALUE_INVALID) to be inserted into a hb_set_t.
+    
+    Add tests that check all of the addition methods.
+
+ src/hb-bit-set.hh |  4 ++--
+ src/test-set.cc   | 24 ++++++++++++++++++++++++
+ 2 files changed, 26 insertions(+), 2 deletions(-)
+
+commit a84cae424d7b315336a191d13a2bef8a9d3635d2
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Mar 15 02:39:57 2023 +0000
+
+    [subset] Don't add invalid gids (-1) to the glyphset when loading glyph map from the accelerator.
+
+ src/OT/Layout/GPOS/PairPosFormat1.hh                     |   2 +-
+ src/hb-subset-plan.cc                                    |   9 ++++++---
+ test/subset/data/Makefile.am                             |   1 +
+ test/subset/data/Makefile.sources                        |   1 +
+ .../preprocess/Roboto-Regular.gids.61,62,63,30D9.ttf     | Bin 0 -> 2680 bytes
+ test/subset/data/tests/preprocess.tests                  |   8 ++++++++
+ test/subset/meson.build                                  |   1 +
+ 7 files changed, 18 insertions(+), 4 deletions(-)
+
+commit 09a266236147497bd8149240062c31c16fbc81e3
+Merge: 75e6498d9 204e155ac
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Mar 14 12:48:12 2023 -0600
+
+    Merge pull request #4168 from googlefonts/subset_name_collect
+    
+    [subset] name_id closure
+
+commit 75e6498d9a8b600ab7f00b3d279f1054dd72feec
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Mar 14 12:41:46 2023 -0600
+
+    Don't use M_PI
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4166
+    
+    Happy Pi Day!
+
+ src/OT/Color/COLR/COLR.hh        |  4 ++--
+ src/OT/glyf/VarCompositeGlyph.hh |  6 +++---
+ src/hb-cairo-utils.cc            | 24 +++++++++++-------------
+ src/hb-ft-colr.hh                |  4 ++--
+ src/hb-paint.hh                  |  8 ++++----
+ src/hb-style.cc                  |  4 ++--
+ src/hb.hh                        |  6 ++++++
+ 7 files changed, 30 insertions(+), 26 deletions(-)
+
+commit 204e155acbf6a9311a13efd4400d2a7b52ca609a
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Mar 14 10:25:31 2023 -0700
+
+    [subset] Add tests for collecting name_ids from STAT and FeatureParams
+
+ test/subset/data/Makefile.am                            |   1 +
+ test/subset/data/Makefile.sources                       |   1 +
+ ...et.keep-all-layout-features.retain-all-codepoint.otf | Bin 0 -> 12796 bytes
+ .../data/fonts/SourceSerif4Variable-Roman_subset.otf    | Bin 0 -> 12784 bytes
+ test/subset/data/tests/collect_name_ids.tests           |  11 +++++++++++
+ test/subset/meson.build                                 |   1 +
+ 6 files changed, 14 insertions(+)
+
+commit 32c889f1d66e7a990c9e80e3c4cc0bd8f62da601
+Author: Jason Simmons <jsimmons@google.com>
+Date:   Mon Mar 13 18:24:39 2023 -0700
+
+    Remove extra blank line in hb-outline.cc
+
+ src/hb-outline.cc | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 0d65738633f84cfbf69325edb8189ee0184d50cf
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Mar 13 15:51:45 2023 -0700
+
+    [subset] collect elidedFallbackNameID in STAT table
+
+ src/hb-ot-stat-table.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 125450d2f220821e63fe748475611c66905904e8
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Mar 13 15:43:29 2023 -0700
+
+    [subset] collect name_ids for FeratureParams
+
+ src/hb-ot-layout-common.hh   | 39 +++++++++++++++++++++++++++++++++++++++
+ src/hb-ot-layout-gsubgpos.hh | 12 ++++++++++++
+ src/hb-subset-plan.cc        | 38 +++++++++++++++++++++++---------------
+ 3 files changed, 74 insertions(+), 15 deletions(-)
+
+commit 663ecc01d8cd32c3fcb8421ee157815ecab413db
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Mar 13 22:12:59 2023 +0000
+
+    [subset] don't free glyphs by range.
+    
+    The iterator in this loop is a map iterator so glyphs are not necessarily traveresed in order.
+
+ src/OT/glyf/glyf.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 3d05b96181b259593047f592df4df33a3658e472
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Mar 13 21:34:26 2023 +0000
+
+    [subset] track which glyphs have allocated memory so we can clean up correctly.
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5388270411579392
+
+ src/OT/glyf/CompositeGlyph.hh                            |   5 ++++-
+ src/OT/glyf/SubsetGlyph.hh                               |  13 ++++++++++---
+ src/OT/glyf/glyf.hh                                      |   6 ++----
+ ...-testcase-minimized-hb-subset-fuzzer-5388270411579392 | Bin 0 -> 4844 bytes
+ 4 files changed, 16 insertions(+), 8 deletions(-)
+
+commit 7a87b17742a0cec36ad21d9fddc1c605597eea14
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Mar 13 19:50:28 2023 +0000
+
+    Check for failed subset input creation in the fuzzer.
+
+ ...z-testcase-minimized-hb-subset-fuzzer-4801020053291008 | Bin 0 -> 311 bytes
+ test/fuzzing/hb-subset-fuzzer.cc                          |  12 ++++++++++++
+ 2 files changed, 12 insertions(+)
+
+commit de6533d8850944e71d5d69c6257ef85f1bf16b1f
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Mar 13 13:36:00 2023 -0700
+
+    [subset] collect name_ids from CPAL table
+
+ src/OT/Color/CPAL/CPAL.hh | 31 +++++++++++++++++++++++++++++++
+ src/hb-subset-plan.cc     | 41 +++++++++++++++++++++++++----------------
+ 2 files changed, 56 insertions(+), 16 deletions(-)
+
+commit 7b77cd198c0352b6ed2a0adbee68bb3e246b9658
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Mar 13 12:45:43 2023 -0700
+
+    [subset] fix bug in CPAL V1tail serialization
+    
+    We should serialize nameIDs rather than retained color index
+
+ src/OT/Color/CPAL/CPAL.hh | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+commit 6d2705a719222adaa4d56a5df589f0c1c81e9bfc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Mar 10 12:40:43 2023 -0700
+
+    [justify-demo] Help message
+
+ src/justify.py | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 2d8634624ccec268aaac097763f544aafcae8ba8
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Fri Mar 10 14:32:39 2023 +0000
+
+    Add Tifinagh to list of both-directions scripts
+
+ src/hb-common.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 905eeee4a4ebfbc8ed4f07d3ae0c730dd54eb334
+Author: Jean-Michaël Celerier <jeanmichael.celerier+github@gmail.com>
+Date:   Mon Mar 6 13:21:33 2023 -0500
+
+    harfbuzz-config.cmake: support static library build
+
+ src/harfbuzz-config.cmake.in | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+commit 28b05e1cb6116b07b95af799ff68b883c3f590d1
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Mar 8 23:59:04 2023 +0000
+
+    [subset] Fix memory leak in glyf subset.
+    
+    Fixes fuzzer issue: https://oss-fuzz.com/testcase-detail/6525813890875392.
+
+ src/OT/glyf/glyf.hh                                     |   9 +++++++++
+ ...testcase-minimized-hb-subset-fuzzer-6525813890875392 | Bin 0 -> 73882 bytes
+ 2 files changed, 9 insertions(+)
+
+commit 9286e125250c7724a5d7eece0fff4284f73341b6
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Mar 8 20:02:26 2023 +0000
+
+    Don't subset a glyf table with an unknown format.
+    
+    Fixes fuzzer issue: https://oss-fuzz.com/testcase-detail/4875306193518592
+
+ src/OT/glyf/glyf.hh                                      |  15 ++++++++++++++-
+ ...case-minimized-hb-subset-fuzzer-4875306193518592.fuzz | Bin 0 -> 1044 bytes
+ 2 files changed, 14 insertions(+), 1 deletion(-)
+
+commit cfa9541daa86c659ea935bbd4507cc620658c6d4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Mar 8 10:35:39 2023 -0700
+
+    [glyf] "Support" glyf version 1
+
+ src/OT/glyf/glyf.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 552290f60437ceaa5aa299a2db726046c0385f80
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Mar 8 10:25:26 2023 -0700
+
+    [gvar] Fix out-of-memory access issue
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5953342850596864
+
+ src/hb-ot-var-gvar-table.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit 7327006d686c149cefdc7ee6047d2b426ac1ac75
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Mar 7 21:06:01 2023 -0700
+
+    [GSUB] Support SingleSubst in get_glyph_alternates
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/discussions/4146
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 28 ++++++++++++++++++++++++++++
+ src/OT/Layout/GSUB/SingleSubstFormat2.hh | 25 +++++++++++++++++++++++++
+ 2 files changed, 53 insertions(+)
+
+commit 69183217dfbd6380f2c57e3a9a793559874667e5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Mar 7 20:56:56 2023 -0700
+
+    Add test-gsub-get-alternates.cc
+
+ src/Makefile.am                 |  5 +++
+ src/meson.build                 |  1 +
+ src/test-gsub-get-alternates.cc | 86 +++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 92 insertions(+)
+
+commit ea17c7a81a743d7e319da0ff4111bcf650d2011b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Mar 7 14:23:39 2023 -0700
+
+    [beyond-64k] Implement gvar support
+    
+    https://github.com/harfbuzz/boring-expansion-spec/issues/85
+
+ src/hb-ot-var-gvar-table.hh | 38 ++++++++++++++++++++++++--------------
+ 1 file changed, 24 insertions(+), 14 deletions(-)
+
+commit f325aba561335a4f0f3c71aa59e42f1a23c774f2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Mar 6 13:07:42 2023 -0700
+
+    [VarComposites] Minor rename
+
+ src/OT/glyf/VarCompositeGlyph.hh | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit b4b089c4278f041f69c3253f84901de226d38558
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Mar 6 04:40:04 2023 +0200
+
+    [docs] Disable gtdoc-check by default
+    
+    It slows build as it causes documentation to be always rebuilt. We now
+    disable it by default and enable it on relevant CI jobs.
+
+ .github/workflows/linux-ci.yml | 1 +
+ docs/meson.build               | 2 +-
+ meson_options.txt              | 2 ++
+ 3 files changed, 4 insertions(+), 1 deletion(-)
+
+commit d165afec1d301167754c4152f868a0110b3144a6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Mar 4 21:09:26 2023 -0700
+
+    [justify-demo] Create new fonts all the time
+    
+    The hb.shape_justify() call modifies the font. This was messing
+    up justification. Create new fonts all the time.
+
+ src/justify.py | 18 ++++++++++--------
+ 1 file changed, 10 insertions(+), 8 deletions(-)
+
+commit 690145fa009b4a705065549474a81113e609419f
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Mar 4 07:19:20 2023 +0200
+
+    [justify-demo] Rewrite in a simpler way
+    
+    No need to overthink it, append text words to the line and reshape, no
+    need to shape the whole text first and do complicated glyph/input
+    mapping. Much simpler code and as fast.
+
+ src/justify.py | 323 +++++++++++++++++++++------------------------------------
+ 1 file changed, 118 insertions(+), 205 deletions(-)
+
+commit e9d6f23b5d4779e08cd27f38fd92860cb9cbe1da
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Mar 3 17:15:18 2023 -0700
+
+    [justify-demo] Fix for LTR typesetting
+
+ src/justify.py | 24 +++++++++++++++---------
+ 1 file changed, 15 insertions(+), 9 deletions(-)
+
+commit 5cf54aeddec47aea380bfa39d543b8fe373c6873
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Mar 3 17:01:12 2023 -0700
+
+    [justify-demo] Guess segment properties
+
+ src/justify.py | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+commit 5c334b9686064aa0d1d41d8935e713c70c43589b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Mar 3 16:53:44 2023 -0700
+
+    [justify-demo] Fix crash if font has no variation axis
+
+ src/justify.py | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit ab249fd24b355ead23ab23f481bd219e0d95faaa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Mar 4 01:46:07 2023 +0200
+
+    [justify] Fix shrink/expand conditions
+
+ src/justify.py | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+commit 039ea9adda1ab9338165469982ae1be6dcce3ae7
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Mar 4 01:41:34 2023 +0200
+
+    [justify] Add demo GTK app
+
+ src/justify.py | 364 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 364 insertions(+)
+
+commit be47182d4897de6b875101a1d258877ed525a24b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Mar 3 11:10:16 2023 -0700
+
+    [hb-cairo] Add Black Foundry copyright
+
+ src/hb-cairo-utils.cc | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+commit ab4c32118025822094ef9197ad105e7460230be4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Mar 3 09:31:16 2023 -0700
+
+    [justify] Set out params in more cases
+
+ src/hb-shape.cc | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+commit e57defc07c83f1012fac0f213d636698d86a76c1
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Mar 3 13:05:30 2023 +0200
+
+    [justify] Set var_value when expanding/shrinking to max
+    
+    When expanding/shrinking the buffer to max (and still not fitting), we
+    need to also set var_value to the axis max/min otherwise client not have
+    the correct axis value to draw with.
+
+ src/hb-shape.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit a2efa5b4895bc90a89be43196e56de276a5fcf00
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Mar 3 09:15:46 2023 -0700
+
+    [map] Another try at fixing old Mac build
+    
+    https://github.com/harfbuzz/harfbuzz/issues/4138
+
+ src/hb-map.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit bfab56d3b5d2d11416375d03c7440f9d6e262f62
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Mar 3 13:14:05 2023 +0200
+
+    [font] Typo
+
+ src/hb-font.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 60841e26187576bff477c1a09ee2ffe544844abc
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Mar 3 01:01:49 2023 +0200
+
+    7.1.0
+
+ NEWS                   | 10 ++++++++++
+ configure.ac           |  2 +-
+ docs/harfbuzz-docs.xml |  1 +
+ meson.build            |  2 +-
+ src/hb-font.cc         |  2 +-
+ src/hb-version.h       |  6 +++---
+ 6 files changed, 17 insertions(+), 6 deletions(-)
+
+commit e471ef77f93eeafff2701a31e6c042054ea4f7e1
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Mar 2 12:40:16 2023 -0800
+
+    [instancer] fix a runtime error
+    
+    runtime error: -1 is outside the range of representable values of type 'unsigned int'
+
+ src/hb-ot-var-cvar-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 43dbdd9db6abda31d41d06f4c33a826e1b791bd2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Mar 2 13:42:52 2023 -0700
+
+    [justify] Document algorithm
+
+ src/hb-shape.cc | 26 ++++++++++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+commit c98bb4cf9c2d73a78773ea9547865fbeaa1ecaff
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Mar 2 13:18:06 2023 -0700
+
+    [justify] Fix up after recent changes
+    
+    Oops.
+
+ src/hb-shape.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit fb067390e422d79b092d9cfe8abb84f0ef8cae05
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Mar 2 11:40:45 2023 -0700
+
+    [docs] Fix a warning
+
+ docs/harfbuzz-sections.txt | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit fe83736e2608eb4697ce1194a69a55234561b620
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Mar 2 11:35:42 2023 -0700
+
+    [sanitize] Protect against an underflow
+
+ src/hb-sanitize.hh | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+commit 08784baf101aea472c133dcd67604b475ace3772
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Mar 2 10:48:30 2023 -0700
+
+    [GSUB/GPOS] Fix sanitization in Format1
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5120727025319936
+
+ src/OT/Layout/GPOS/SinglePosFormat1.hh   | 14 ++++++++------
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 14 ++++++++------
+ 2 files changed, 16 insertions(+), 12 deletions(-)
+
+commit 789717387042ae7855cb61af2ef4b91ee32866a4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Mar 2 10:38:12 2023 -0700
+
+    [justify] Fix compiler warnings
+
+ src/hb-shape.cc | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+commit be64cae16489406147848e4613d11de8303e1513
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Mar 2 09:50:38 2023 -0700
+
+    [map] Another try at fixing old Mac builds
+    
+    Maybe fixes https://github.com/harfbuzz/harfbuzz/issues/4138
+
+ src/hb-map.cc   |  4 ++--
+ src/hb-map.hh   | 12 ------------
+ src/test-map.cc |  4 ++--
+ 3 files changed, 4 insertions(+), 16 deletions(-)
+
+commit 67e01c1292821e7b6fc2ab13acddb84ab41b2187
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Mar 1 20:07:38 2023 -0700
+
+    [map] Try to work around old Mac compiler bug
+    
+    Maybe fixes https://github.com/harfbuzz/harfbuzz/issues/4138
+
+ src/hb-map.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit e359f46a202899e0ee6dab1fec3c4cc325b9509c
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Mar 2 03:06:53 2023 +0200
+
+    Fix build
+
+ src/hb-shape.cc | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit e8f94f9e1249fd1374fa282685ae93aba3b8fcdd
+Merge: c67c0086e 6de9d2b89
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Mar 1 16:34:01 2023 -0700
+
+    Merge pull request #4144 from harfbuzz/justify
+    
+    Justify
+
+commit 6de9d2b89fb10ce69ebf501b3e77bd95da5b1792
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Mar 1 14:32:06 2023 -0700
+
+    [justify] Rename hb-view --width to hb-view --justify-to
+
+ util/shape-options.hh | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+commit 25c66d633d58dcdd1e59095abf673a9ef08a612c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Mar 1 14:16:08 2023 -0700
+
+    [justify] Wrap in HB_EXPERIMENTAL_API
+
+ src/gen-def.py        | 3 ++-
+ src/hb-shape.cc       | 8 +++++++-
+ util/shape-options.hh | 4 ++++
+ 3 files changed, 13 insertions(+), 2 deletions(-)
+
+commit 96d4ed093123293114d65800e8629deb1fff2218
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Mar 1 14:08:16 2023 -0700
+
+    [justify] Document API
+
+ docs/harfbuzz-sections.txt |  1 +
+ src/hb-shape.cc            | 78 ++++++++++++++++++++++++++++++----------------
+ src/hb-shape.h             |  6 ++--
+ 3 files changed, 56 insertions(+), 29 deletions(-)
+
+commit d29d7b7a3dd2cfca151ce667a3290359d028911c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Mar 1 13:10:11 2023 -0700
+
+    [algs] Adjust solve_itp
+
+ src/hb-algs.hh  | 11 +++++++----
+ src/hb-shape.cc |  4 ----
+ 2 files changed, 7 insertions(+), 8 deletions(-)
+
+commit aa10deaf4283822f8c368ecbdebd01330dd76fe5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Mar 1 11:08:32 2023 -0700
+
+    [justify] Print default buffer width in hb-shape --width=-1
+
+ util/shape-options.hh | 25 ++++++++++++++++++++++---
+ 1 file changed, 22 insertions(+), 3 deletions(-)
+
+commit 93252c6fc3585f6c226514e9c476af82b7c55d86
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Mar 1 10:59:04 2023 -0700
+
+    [justify] Debug output
+
+ src/hb-debug.hh |  4 ++++
+ src/hb-shape.cc | 11 ++++++++---
+ 2 files changed, 12 insertions(+), 3 deletions(-)
+
+commit b937edfb148d28421f97db7c3c81e2253019e469
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Mar 1 10:44:57 2023 -0700
+
+    [justify] Add min/max target_width
+    
+    Speeds up solving when some slack available.
+
+ src/hb-algs.hh        |  8 +++++---
+ src/hb-shape.cc       | 32 ++++++++++++++++++--------------
+ src/hb-shape.h        |  3 ++-
+ util/shape-options.hh |  6 ++++--
+ 4 files changed, 29 insertions(+), 20 deletions(-)
+
+commit 6e483c4061b526c6c22db198194d4f8b2cfb3a86
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 28 12:25:32 2023 -0700
+
+    [shape] Add hb_shape_justify() and hb-view --width
+
+ src/hb-algs.hh        |   2 +-
+ src/hb-shape.cc       | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-shape.h        |  11 ++++
+ util/shape-options.hh |  30 +++++++--
+ 4 files changed, 210 insertions(+), 6 deletions(-)
+
+commit ee4822f9696d2a40351a26d73257667a77af78ca
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 28 09:39:32 2023 -0700
+
+    [algs] Add solve_itp method
+    
+    Port from kurbo.
+
+ src/hb-algs.hh | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 53 insertions(+)
+
+commit c67c0086ef66e05228f9cc1f4c169f690e130511
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Mar 1 13:32:44 2023 -0700
+
+    [GPOS] Fix indexing in MarkLigPos
+    
+    This was broken in 8708b9e081.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4142
+
+ src/OT/Layout/GPOS/MarkLigPosFormat1.hh | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+commit 01d34763f06f0c513406dc14db6d496a08ecf4fa
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Tue Feb 28 20:16:39 2023 -0500
+
+    Typo fix
+
+ src/hb-font.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 2d33a6b4dfdcd751eba242637c863d810a4a803c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 28 15:31:45 2023 -0700
+
+    [subset-fuzzer] Protect against overflow
+    
+    Fixes
+    https://github.com/harfbuzz/harfbuzz/issues/4137#issuecomment-1448994447
+
+ test/fuzzing/hb-subset-fuzzer.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 5226d697338756e661c951af28c19b9a69b4ff93
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 28 14:49:44 2023 -0700
+
+    [font] Make set_variation() respect currently-set variations
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4143
+
+ src/hb-font.cc | 27 ++++++++++++++++++---------
+ 1 file changed, 18 insertions(+), 9 deletions(-)
+
+commit 91627daee2970b26666d8d9d47161387511667d1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 28 14:31:25 2023 -0700
+
+    [outline] Rename internal function
+
+ src/hb-outline.cc | 4 ++--
+ src/hb-outline.hh | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+commit 5c462865920681246422a1d23d38cc62a94f1870
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 28 12:16:46 2023 -0700
+
+    Revert "."
+    
+    This reverts commit 59434578cd453d9dcdcaf5d010d5f5686c17717e.
+
+ src/hb-shape.cc | 84 ---------------------------------------------------------
+ src/hb-shape.h  |  9 -------
+ 2 files changed, 93 deletions(-)
+
+commit 59434578cd453d9dcdcaf5d010d5f5686c17717e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 28 12:13:55 2023 -0700
+
+    .
+
+ src/hb-shape.cc | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-shape.h  |  9 +++++++
+ 2 files changed, 93 insertions(+)
+
+commit bbb9d6d436b7fb5aba771c63378aa4daa231b8c5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 28 12:07:48 2023 -0700
+
+    [font] Add hb_font_set_variation()
+
+ docs/harfbuzz-sections.txt |  1 +
+ src/hb-font.cc             | 64 ++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-font.h              |  5 ++++
+ 3 files changed, 70 insertions(+)
+
+commit a975ec4842468e574484bdc310095fad780978fc
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Feb 14 13:26:59 2023 -0800
+
+    [instancer] apply cvar deltas
+
+ src/hb-ot-face-table-list.hh                       |   1 +
+ src/hb-ot-var-cvar-table.hh                        |  27 +++++++++++++--------
+ src/hb-subset-input.cc                             |   1 -
+ src/hb-subset.cc                                   |  11 +++++++++
+ test/subset/data/Makefile.am                       |   1 +
+ test/subset/data/Makefile.sources                  |   1 +
+ ...r-new.default.retain-all-codepoint.wght=300.ttf | Bin 0 -> 131712 bytes
+ ...r-new.default.retain-all-codepoint.wght=700.ttf | Bin 0 -> 131588 bytes
+ test/subset/data/tests/apply_cvar_delta.tests      |  12 +++++++++
+ test/subset/meson.build                            |   1 +
+ 10 files changed, 44 insertions(+), 11 deletions(-)
+
+commit 8b0c7b9554cc75d499bc0aa9c25f45e53a1f2ce9
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Feb 10 09:49:09 2023 -0800
+
+    [instance] Add struct definition for cvar table
+    
+    Also add functions to add cvt tables with cvar deltas applied
+
+ src/Makefile.sources        |   1 +
+ src/hb-ot-var-common.hh     |  19 ++++++
+ src/hb-ot-var-cvar-table.hh | 151 ++++++++++++++++++++++++++++++++++++++++++++
+ src/meson.build             |   1 +
+ 4 files changed, 172 insertions(+)
+
+commit 22cc73f3e9b941be47330a574599cddd79811168
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Feb 6 12:36:05 2023 -0800
+
+    Move common structs for TupleVariation from gvar to var-common.hh
+    
+    Also added a table_base in the iterator and related function to handle
+    different start address for dataoffset in cvar and gvar
+
+ src/hb-ot-var-common.hh     | 308 +++++++++++++++++++++++++++++++++++++++++++
+ src/hb-ot-var-gvar-table.hh | 309 +-------------------------------------------
+ 2 files changed, 312 insertions(+), 305 deletions(-)
+
+commit c0fac016dc017596e2d979e19e1eb8f88df38ea3
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Feb 22 20:54:20 2023 +0000
+
+    [subset] update the subset fuzzer to be able to reach instancing code.
+
+ test/fuzzing/fonts/AdobeVFPrototype.ABC.otf | Bin 0 -> 4724 bytes
+ test/fuzzing/fonts/Roboto-Variable.ABC.ttf  | Bin 0 -> 13480 bytes
+ test/fuzzing/hb-subset-fuzzer.cc            |  49 +++++++++++++++++++++++-----
+ 3 files changed, 41 insertions(+), 8 deletions(-)
+
+commit 62fc27f372779d363cb6ba46cfaca6433a42504b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 27 11:20:47 2023 -0700
+
+    [ft] Enlarge glyph-cache value-size again
+    
+    8bits just doesn't do it. It has caused cache-hammering and high
+    CPU usage when the font is hinted.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4139
+
+ src/hb-ft.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 921eca3e79df93af8ee16a47994150d1f4845bfc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 17:06:43 2023 -0700
+
+    [autotools] Fix hb-info chafa build
+
+ util/Makefile.am | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+commit 209f63b7850f836e5e3628523f6f740e25008409
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 24 16:03:23 2023 -0700
+
+    [TINY] Fix config issue
+
+ src/hb-config.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 605aed0544e51fa2534a3324262f3935d4dcfe99
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Feb 24 10:17:32 2023 -0800
+
+    [instancer] bug fix in post table applying mvar deltas
+
+ src/hb-ot-post-table.hh                                 |   8 ++++----
+ test/subset/data/Makefile.am                            |   1 +
+ test/subset/data/Makefile.sources                       |   1 +
+ ...l-codepoint.wght=400,CASL=0,CRSV=0,MONO=0,slnt=0.ttf | Bin 0 -> 1884 bytes
+ test/subset/data/fonts/Recursive-ABC.ttf                | Bin 0 -> 20332 bytes
+ test/subset/data/tests/post_apply_mvar_delta.tests      |  11 +++++++++++
+ test/subset/meson.build                                 |   1 +
+ 7 files changed, 18 insertions(+), 4 deletions(-)
+
+commit 918193ebf908d35c88bb71d02dfc14bc41ffc31d
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Feb 22 23:11:29 2023 +0000
+
+    [subset] fix a class of fuzzer timeouts caused by large shared coverage tables.
+    
+    More acurately estimates the op count for CoverageFormat2 tables as the population size instead of the size in bytes.
+
+ src/OT/Layout/GPOS/SinglePosFormat1.hh                  |   8 +++++++-
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh                |   8 +++++++-
+ src/hb-sanitize.hh                                      |   8 ++++++++
+ ...testcase-minimized-hb-subset-fuzzer-5192684970311680 | Bin 0 -> 67697 bytes
+ 4 files changed, 22 insertions(+), 2 deletions(-)
+
+commit ddd0f7f40b5cae71271fcfa7b6143066d8e465df
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Feb 22 20:23:34 2023 +0000
+
+    [subset] Add a test for CFF2 instancing.
+    
+    Adds option to disable the fonttools comparison check in the test. This is needed since CFF2 instancing is not yet supported in fonttools.
+
+ test/subset/data/Makefile.am                        |   1 +
+ test/subset/data/Makefile.sources                   |   1 +
+ ...efault.retain-all-codepoint.wght=650,CNTR=50.otf | Bin 0 -> 41760 bytes
+ test/subset/data/tests/instantiate_cff2.tests       |  14 ++++++++++++++
+ test/subset/generate-expected-outputs.py            |  20 +++++++++++---------
+ test/subset/meson.build                             |   1 +
+ test/subset/subset_test_suite.py                    |  13 ++++++++-----
+ 7 files changed, 36 insertions(+), 14 deletions(-)
+
+commit 33cc3121d457b415f3fac2374af7df5cd4fd704e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 22 12:03:30 2023 -0700
+
+    Comment
+
+ src/hb-shaper-list.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 5bc6ab006da7dbab993867c3d7d24cefaa81b51c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 22 08:08:11 2023 -0700
+
+    Use __has_builtin for builtin checks instead of compiler versions
+    
+    https://github.com/harfbuzz/harfbuzz/issues/4066#issuecomment-1439510188
+
+ src/hb-algs.hh | 30 ++++++++++++++++++++++--------
+ src/hb.hh      | 10 +++++++++-
+ 2 files changed, 31 insertions(+), 9 deletions(-)
+
+commit 6b286cfabf23c93ecec6d65f83d8c1291cd46cf6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 21 16:15:45 2023 -0700
+
+    [cubic-glyf] Remove stale comment
+
+ src/OT/glyf/path-builder.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 22b93156281dae8772b15e68b2553a2a9a5c8367
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 21 15:50:55 2023 -0700
+
+    [cubic-glyf] Handle wrap-around cubic off-curves
+
+ src/OT/glyf/path-builder.hh | 30 ++++++++++++++++++++----------
+ 1 file changed, 20 insertions(+), 10 deletions(-)
+
+commit 050f5a58fe182f8f2bf85c95fc2ddc13bc784699
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 21 15:25:59 2023 -0700
+
+    [cubic-glyf] Handle contour-initial cubic offcurves
+
+ src/OT/glyf/path-builder.hh | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+commit 9c27fe625f592fdb97dc94c4006f928877e7cb61
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Feb 21 23:25:14 2023 +0200
+
+    Revert "[doc] Fix a couple of gtk-doc warnings"
+    
+    This reverts commit ed42b2fcb556a1d47a620f77cc98069123d1670c.
+
+ docs/harfbuzz-sections.txt | 1 -
+ src/hb-gobject-structs.cc  | 2 +-
+ 2 files changed, 1 insertion(+), 2 deletions(-)
+
+commit ed42b2fcb556a1d47a620f77cc98069123d1670c
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Feb 21 23:08:15 2023 +0200
+
+    [doc] Fix a couple of gtk-doc warnings
+
+ docs/harfbuzz-sections.txt | 1 +
+ src/hb-gobject-structs.cc  | 2 +-
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+commit 0575229477006a51f85eee10c9490db92972d60a
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Feb 21 18:07:53 2023 +0200
+
+    [blob] Typo in documentation
+
+ src/hb-blob.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 424f5f2c0d10596abc79d98bc165cd9e86680597
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Feb 20 16:05:53 2023 +0200
+
+    [ci] Don’t build docs while building Windows binaries
+
+ .circleci/config.yml | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 1d1f93a612ed071b703abab7deb0951f46a12433
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Feb 20 15:54:12 2023 +0200
+
+    7.0.1
+
+ NEWS             | 6 ++++++
+ configure.ac     | 2 +-
+ meson.build      | 2 +-
+ src/hb-version.h | 4 ++--
+ 4 files changed, 10 insertions(+), 4 deletions(-)
+
+commit 6db871eb3aab5d4e47397b58025e678380a6fb34
+Merge: 8c1b47d7e 5b50b0771
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 19 21:08:14 2023 -0700
+
+    Merge pull request #4126 from harfbuzz/cff2-instancer
+    
+    CFF2 instancer make ots-sanitize happy
+
+commit 5b50b07717a0adf353e866c1f5502f1c5b374d22
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 19 20:30:38 2023 -0700
+
+    [subset-cff] Make BCD writing locale-independent
+
+ src/hb-common.cc            | 26 --------------------------
+ src/hb-subset-cff-common.hh | 10 ++++++++--
+ src/hb.hh                   | 31 +++++++++++++++++++++++++++++++
+ 3 files changed, 39 insertions(+), 28 deletions(-)
+
+commit 4a735b30c4e31489779a06722c66f8d820b9666d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 19 19:51:03 2023 -0700
+
+    [cff2-subset] Update test
+
+ test/api/fonts/AdobeVFPrototype.abc.static.otf | Bin 86112 -> 2576 bytes
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+
+commit 21ff66cbd4445899f37c6aa6827a2d349292119b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 19 20:00:39 2023 -0700
+
+    [subset-cff2] Round blended Private values when instancing
+    
+    Hopefully no one blends BlueScale...
+
+ src/hb-subset-cff2.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a4b7033d0159b6372e631927b98b1963838bcc54
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 19 17:48:02 2023 -0700
+
+    [cff2-subset] Blend Private values when instancing
+
+ src/hb-serialize.hh         |   7 ++
+ src/hb-subset-cff-common.hh |  80 ++++++++++++++++++++++
+ src/hb-subset-cff2.cc       | 159 ++++++++++++++++++++++++++++++++++++++++++--
+ 3 files changed, 239 insertions(+), 7 deletions(-)
+
+commit f10a4c9d6aebcc60b525a2342b0cdc6970ba32a3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 19 17:11:30 2023 -0700
+
+    [cff] Rename encode_num to encode_num_cs
+
+ src/hb-subset-cff-common.hh | 4 ++--
+ src/hb-subset-cff1.cc       | 4 ++--
+ src/hb-subset-cff2.cc       | 6 +++---
+ 3 files changed, 7 insertions(+), 7 deletions(-)
+
+commit c65eb5a82e4a9a0f3fe60b770741f3f4d3391bc2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 19 15:15:57 2023 -0700
+
+    [cff] Specialize cff_private_dict_op_serializer_t for CFF1/2
+
+ src/hb-subset-cff-common.hh | 33 ---------------------------------
+ src/hb-subset-cff1.cc       | 32 +++++++++++++++++++++++++++++++-
+ src/hb-subset-cff2.cc       | 36 +++++++++++++++++++++++++++++++++++-
+ 3 files changed, 66 insertions(+), 35 deletions(-)
+
+commit bf4b34e87e5d7428b7b206a38ce6d7948657a9cb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 19 11:16:51 2023 -0700
+
+    [subset-cff2] Don't encode vsindex in Private dict
+
+ src/hb-subset-cff-common.hh | 14 +++++++++-----
+ src/hb-subset-cff2.cc       |  2 +-
+ 2 files changed, 10 insertions(+), 6 deletions(-)
+
+commit 220caa7e095b62fef55b03f32b65ddc564d8dc63
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 19 11:01:27 2023 -0700
+
+    [subset-cff2] Only encode VarStore link if any varstore
+
+ src/hb-subset-cff2.cc | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit 82d9940a938d20bc2a4864a10e53bff4e34762ad
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 19 10:51:55 2023 -0700
+
+    [subset-cff2] Don't encode vsindex if pinned
+
+ src/hb-subset-cff-common.hh | 8 ++++----
+ src/hb-subset-cff2.cc       | 2 +-
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+commit a88f3e8d379b7fbb0e4374f8ce1feb48ae681911
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 19 10:47:36 2023 -0700
+
+    [subset-cff2] Don't serialize VarStore if pinned
+
+ src/hb-subset-cff2.cc | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+commit 8c1b47d7e23910c632993aa444df12cc2338d89a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 19 20:38:43 2023 -0700
+
+    [font] Fix compiler warnings
+
+ src/hb-font.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 7c74fc96319b57499e1e3defc3e346fd3cc6848e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 19 14:43:07 2023 -0700
+
+    [CFF] Remove unused member single_val
+
+ src/hb-cff-interp-dict-common.hh | 4 +---
+ src/hb-ot-cff1-table.hh          | 3 ---
+ src/hb-ot-cff2-table.hh          | 3 ---
+ 3 files changed, 1 insertion(+), 9 deletions(-)
+
+commit 2746597b69c10b7aa1c0df2a4d36a3d92fb0769f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 19 12:14:35 2023 -0700
+
+    [subset-cff2] Add flush_hintmask
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4125
+
+ src/hb-subset-cff2.cc | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+commit adccc5355b695cfaaf6403a3187c67c7fcae623d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 17 12:29:42 2023 -0700
+
+    [MarkBase] Adjust base-finding logic
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4124
+
+ src/OT/Layout/GPOS/MarkBasePosFormat1.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 946477fa5472bb93f6ac099a45ec13a34d87a732
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 16 15:03:50 2023 -0700
+
+    [font] Fix a MSVC "error"
+    
+    Oh well.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4122
+
+ src/hb-font.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b41efb6c4da9b1180b5178a55ceb31c68791dfdc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 13 21:16:16 2023 -0700
+
+    [atomic] Use no-op asm for compiler barrier
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/pull/4119
+
+ src/hb-atomic.hh | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+commit 2f1aa032b4c43a76953036c6a90d108fe9358711
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Feb 13 09:50:04 2023 +0200
+
+    [doc] Give this section a nice URL
+
+ docs/usermanual-fonts-and-faces.xml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 552f0714e854af0ed41d54fad710a2e4ce872af3
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Feb 13 09:21:05 2023 +0200
+
+    [meson] Fix test failure with experimental_api
+    
+    Pass --experimental-api to all gen-def.py when generating all .def
+    files, not only harfbuzz.def.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4117
+
+ src/meson.build | 17 ++++++++---------
+ 1 file changed, 8 insertions(+), 9 deletions(-)
+
+commit 40fa046cf311718665496d0516495e9c139221ba
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 12 10:54:07 2023 -0700
+
+    [hb-info] Declare a variable unused
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4115
+
+ util/hb-info.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 8bdaeddfcd86aa66f560ff1ae1ae71b1e1723463
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Feb 11 23:44:58 2023 +0200
+
+    7.0.0
+
+ NEWS                   | 130 +++++++++++++++++++++++++++++++++++++++++++++++++
+ configure.ac           |   2 +-
+ docs/harfbuzz-docs.xml |   1 +
+ meson.build            |   2 +-
+ src/hb-cairo.cc        |  18 +++----
+ src/hb-cairo.h         |   2 +-
+ src/hb-draw.cc         |   6 +--
+ src/hb-face.cc         |   2 +-
+ src/hb-font.cc         |  13 ++---
+ src/hb-font.h          |  16 +++---
+ src/hb-map.cc          |   8 +--
+ src/hb-ot-color.cc     |   4 +-
+ src/hb-ot-layout.cc    |   2 +-
+ src/hb-ot-name.h       |   2 +-
+ src/hb-paint.cc        |  46 ++++++++---------
+ src/hb-paint.h         |  72 +++++++++++++--------------
+ src/hb-set.cc          |   2 +-
+ src/hb-subset-input.cc |   2 +-
+ src/hb-version.h       |   4 +-
+ 19 files changed, 232 insertions(+), 102 deletions(-)
+
+commit df6324cbe7f1ebf43f243cbefe60902e0e0d6085
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Feb 11 22:35:09 2023 +0200
+
+    [ci] Build with default wrap mode
+    
+    Forcing fallback forces checking the subproject even if the option is
+    disabled.
+
+ .ci/build-win32.sh | 2 +-
+ .ci/build-win64.sh | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 5b82fa91c5b955ed5bea4b848e9afcda1f4a519b
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Feb 11 22:22:48 2023 +0200
+
+    [meson] Update Glib subproject
+
+ subprojects/glib.wrap | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit 31e099fd212491045b9743d5b3b4ed718f80902a
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Feb 11 22:21:53 2023 +0200
+
+    [meson] Update Cairo subproject
+
+ subprojects/cairo.wrap | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 8f0da5e5e6d6fb5b827ec090ece871bf13324c87
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Feb 11 22:20:41 2023 +0200
+
+    [meson] Update FreeType subproject
+
+ subprojects/freetype2.wrap |  9 ++++-----
+ subprojects/zlib.wrap      | 13 -------------
+ 2 files changed, 4 insertions(+), 18 deletions(-)
+
+commit 59cd1b17a96e6a8024f4fb5c1de1c1c8c3896633
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Feb 11 20:24:49 2023 +0200
+
+    [ci] Don’t build docs on macos-aat-fonts job
+    
+    It fails ninja test, but superfluous anyway.
+
+ .circleci/config.yml | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 7188c5643a45c11d82a04589d03a970fdffe8c0a
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Feb 11 20:02:34 2023 +0200
+
+    [doc] Enable gtkdoc-check
+    
+    Should catch the most blatant issues.
+
+ docs/meson.build | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 0ea8bbd91a5addd10d1c5e4c1f4098937840f1e8
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Feb 11 20:01:06 2023 +0200
+
+    [doc] Use XSince for REPLACEME/EXPERIMENTAL
+    
+    To hide them from gtk-doc so that we can finally enable gtkdoc-check.
+
+ RELEASING.md              |  2 +-
+ src/hb-cairo.cc           | 18 ++++++------
+ src/hb-cairo.h            |  2 +-
+ src/hb-draw.cc            |  6 ++--
+ src/hb-face.cc            |  2 +-
+ src/hb-font.cc            | 10 +++----
+ src/hb-font.h             | 10 +++----
+ src/hb-map.cc             |  8 +++---
+ src/hb-ot-color.cc        |  4 +--
+ src/hb-ot-layout.cc       |  2 +-
+ src/hb-ot-name.h          |  2 +-
+ src/hb-paint.cc           | 46 +++++++++++++++---------------
+ src/hb-paint.h            | 72 +++++++++++++++++++++++------------------------
+ src/hb-set.cc             |  2 +-
+ src/hb-subset-input.cc    |  4 +--
+ src/hb-subset-repacker.cc |  2 +-
+ 16 files changed, 96 insertions(+), 96 deletions(-)
+
+commit 16dfd263b143e343973bfda478975457841f225d
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Feb 11 19:31:29 2023 +0200
+
+    [subset] Remove docs for unimplemented flags
+    
+    GTK-Doc does not like this.
+
+ src/hb-subset.h | 10 ----------
+ 1 file changed, 10 deletions(-)
+
+commit 4d25941315b785f711562216241a674fbfa01509
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Feb 11 19:25:52 2023 +0200
+
+    [doc] Fix hb_ot_name_[id|predefined]_t
+    
+    Shuffle the docs around, so that the enum values appear in documentation
+    as they now belong to hb_ot_name_predefined_t. The Since field will be
+    misleading now, though.
+
+ src/hb-ot-name.h | 23 +++++++++++------------
+ 1 file changed, 11 insertions(+), 12 deletions(-)
+
+commit 13741e68f8db429e432677f12e227de6e014dec0
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Feb 11 19:17:37 2023 +0200
+
+    [doc] Minor
+
+ src/hb-font.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ab191d9dc7eb126759cd6224131db8df4b730b81
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 11 09:31:07 2023 -0700
+
+    [ot-font] Minor division rounding
+
+ src/hb-ot-font.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit c6c1c6ddf12e9e4f7fd343f0641288d62432962f
+Merge: af1e605be 6ddd49019
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 11 09:20:51 2023 -0700
+
+    Merge pull request #4107 from harfbuzz/cubic-glyf
+    
+    [glyf] Support cubic curves
+
+commit 6ddd490191b11ae7ac02f8d69486c771e0803a00
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 10 14:24:03 2023 -0700
+
+    [path-builder] Comment re cubic
+
+ src/OT/glyf/path-builder.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 91c2f098d09b36c25e4e849bf65483aa030c3f22
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 10 14:15:16 2023 -0700
+
+    [cubic-glyf] Add HB_NO_CUBIC_GLYF
+
+ src/OT/glyf/path-builder.hh | 4 ++++
+ src/hb-config.hh            | 1 +
+ 2 files changed, 5 insertions(+)
+
+commit af1e605be27afc79c293fdd0a45e6f6e2edd9054
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Feb 10 11:08:05 2023 -0800
+
+    [instancer] bug fix
+    
+    It's possible that length of all_points equals to 4 for non-empty
+    glyphs: a composite glyph which contains only one child glyph that is
+    empty.
+
+ src/OT/glyf/Glyph.hh                                     |   2 +-
+ test/subset/data/Makefile.am                             |   1 +
+ test/subset/data/Makefile.sources                        |   1 +
+ .../RobotoMono.default.retain-all-codepoint.wght=700.ttf | Bin 0 -> 1264 bytes
+ test/subset/data/fonts/RobotoMono.ttf                    | Bin 0 -> 1932 bytes
+ .../data/tests/instance_comp_glyph_empty_child.tests     |  11 +++++++++++
+ test/subset/meson.build                                  |   1 +
+ 7 files changed, 15 insertions(+), 1 deletion(-)
+
+commit 8302da86303f68b1c9308ce2984cca0d28f1716a
+Merge: 219e2f12f 737b15c5a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 10 12:50:45 2023 -0700
+
+    Merge pull request #4097 from harfbuzz/embolden
+    
+    Embolden
+
+commit 219e2f12f0d0ce02ef06351faa1ccb14fd69258c
+Author: Jens Kutilek <webmail@kutilek.de>
+Date:   Fri Feb 10 17:23:31 2023 +0100
+
+    Clarify that those two test fonts are CC0-licensed
+
+ .../fonts/TestGVAR-Composite-0.ttf                    | Bin 3136 -> 3592 bytes
+ .../fonts/TestGVAR-Composite-Missing.ttf              | Bin 2984 -> 3440 bytes
+ 2 files changed, 0 insertions(+), 0 deletions(-)
+
+commit b1680e914362000de04a494d7134efbabc5fb3bc
+Author: Pedro J. Estébanez <pedrojrulez@gmail.com>
+Date:   Fri Feb 10 14:14:43 2023 +0100
+
+    Use proper preprocessor checks for UWP
+
+ src/hb-blob.cc  | 6 +++---
+ src/hb-mutex.hh | 2 +-
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit 96d9e8624c410842ee3bf32bfc45f3240dc6d720
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 9 12:53:17 2023 -0700
+
+    [docs] Improve cluster-level docs
+
+ docs/usermanual-clusters.xml | 22 +++++++++++++---------
+ 1 file changed, 13 insertions(+), 9 deletions(-)
+
+commit 737b15c5a0251d1579bc4b6a41cb08bc8c66e275
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 8 17:45:59 2023 -0700
+
+    [embolden] Docs
+
+ src/hb-font.cc | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 00a6f8945c5c8c4174619c0703b4edf8a96db47d
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Feb 8 22:43:39 2023 +0200
+
+    [meson] Minor
+    
+    alias_target() is variadic function.
+
+ meson.build | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1d9dafbfd5a59143a009403798beae1e1ad1753a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 7 22:19:45 2023 -0700
+
+    [glyf] Support cubic curves
+    
+    https://github.com/harfbuzz/boring-expansion-spec/issues/41
+
+ src/OT/glyf/SimpleGlyph.hh  |  2 +-
+ src/OT/glyf/path-builder.hh | 55 ++++++++++++++++++++++++++++++++++++---------
+ 2 files changed, 45 insertions(+), 12 deletions(-)
+
+commit 64fa5cd482d0be2e215998aa1c2a05b978133e7c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 7 15:50:36 2023 -0700
+
+    [GPOS] Fix assert fail introduced recently
+    
+    Was introduced in 8708b9e081192786c027bb7f5f23d76dbe5c19e8.
+    
+    If these lookups are recursed to from (Chain)Context out-of-order,
+    it was possible that last_base > buffer->idx, in which case we
+    were attaching marks to a base after them... and an assertion
+    was failing fortunately.
+    
+    Fixes https://oss-fuzz.com/testcase-detail/6377756666757120
+
+ src/OT/Layout/GPOS/MarkBasePosFormat1.hh                  |   5 +++++
+ src/OT/Layout/GPOS/MarkLigPosFormat1.hh                   |   5 +++++
+ ...zz-testcase-minimized-hb-shape-fuzzer-6377756666757120 | Bin 0 -> 607 bytes
+ 3 files changed, 10 insertions(+)
+
+commit 840e1b6b84e8c421ab695f8fa99eae8cfc08e3e8
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Feb 7 13:49:19 2023 -0800
+
+    [instancer] bug fix
+
+ src/hb-subset-plan.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3fd9311649e2e0e5e2bfbe27c082e3f2dbc797f5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 7 14:16:24 2023 -0700
+
+    [indic] Use a hb_swap()
+
+ src/hb-ot-shaper-indic.cc | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+commit be1c14ee0ad7702250f2a8b1969387d8018d4012
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 7 13:52:53 2023 -0700
+
+    [embolden] Adjust font_h_extents
+
+ src/hb-ft.cc      |  2 +-
+ src/hb-ot-font.cc | 13 ++++++++++---
+ 2 files changed, 11 insertions(+), 4 deletions(-)
+
+commit b350122fb3af6d4eff9a2cf9c8fc3b7157601944
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 7 13:49:16 2023 -0700
+
+    [embolden] Fix glyph_extents in hb-ft
+
+ src/hb-ft.cc | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+commit 61a1a88940f808f0f1184c6afdfbf025f21c1527
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 7 13:47:04 2023 -0700
+
+    [hb-ft] Fix --font-grade
+
+ src/hb-ft.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 560a65e456275e927d64f650235bdaa10049ee50
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 7 13:46:13 2023 -0700
+
+    [embolden] Update glyph_extents in hb-ot-font
+
+ src/hb-font.hh | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+commit aef002e0d92caeed512ae1f40904d02ebcb8d506
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 7 11:29:49 2023 -0700
+
+    [embolden] Add in-place option
+    
+    Adds --font-grade to hb-view and hb-shape.
+
+ src/hb-font.cc       | 44 ++++++++++++++++++++++++++++++--------------
+ src/hb-font.h        |  8 ++++++--
+ src/hb-font.hh       |  9 +++++----
+ src/hb-ft.cc         | 43 +++++++++++++++++++++++++++++++++++++------
+ src/hb-ot-font.cc    | 22 ++++++++++++++--------
+ src/hb-outline.cc    |  7 ++++---
+ src/hb-outline.hh    |  3 ++-
+ util/font-options.hh | 37 ++++++++++++++++++++++++++++++++-----
+ 8 files changed, 130 insertions(+), 43 deletions(-)
+
+commit 0b92c579844a666e679c1741beded1edd0860611
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 7 10:20:46 2023 -0700
+
+    [meson] Add alias "libs" target
+    
+    Builds libharfbuzz and libharfbuzz-subset.
+
+ meson.build | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 434c98d4c672a95f380eed0b4c08b94f16426cf9
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Feb 7 10:06:13 2023 +0200
+
+    [meson] Add alias "lib" target
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4105
+
+ meson.build | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit ce6440fceb0c0213dd4a39cc999efc67fe5dfb41
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 6 16:12:03 2023 -0700
+
+    [buffer] Speed up merge_clusters_impl
+
+ src/hb-buffer.cc | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+commit 1930760bc2c2b4185a772e38b6ecc174a95a47b2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 6 15:54:09 2023 -0700
+
+    [buffer] Fix up previous commit
+    
+    https://github.com/harfbuzz/harfbuzz/commit/85be877925ddbf34f74a1229f3ca1716bb6170dc#commitcomment-99547060
+
+ src/hb-buffer.hh | 22 ++++++++++------------
+ 1 file changed, 10 insertions(+), 12 deletions(-)
+
+commit 30b84faba7811bed1b7c9828afd719f20e0086da
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 6 15:27:13 2023 -0700
+
+    [buffer] Optimize _infos_set_glyph_flags to avoid O(n^2) behavior
+    
+    https://github.com/harfbuzz/harfbuzz/commit/85be877925ddbf34f74a1229f3ca1716bb6170dc#commitcomment-99547060
+
+ src/hb-buffer.hh | 44 ++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 38 insertions(+), 6 deletions(-)
+
+commit 0b97ac39ac0bbe4d0027d1bb96668f456aaf634b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 6 15:17:09 2023 -0700
+
+    [buffer] Optimize _infos_find_min_cluster for monotone clusters
+
+ src/hb-buffer.hh | 16 ++++++++++++----
+ 1 file changed, 12 insertions(+), 4 deletions(-)
+
+commit 8708b9e081192786c027bb7f5f23d76dbe5c19e8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 6 14:51:25 2023 -0700
+
+    [GPOS] Avoid O(n^2) behavior in mark-attachment
+    
+    Better implementation; avoids arbitrary limit on look-back.
+
+ src/OT/Layout/GPOS/MarkBasePosFormat1.hh | 76 ++++++++++++++++++++------------
+ src/OT/Layout/GPOS/MarkLigPosFormat1.hh  | 24 +++++++---
+ src/hb-ot-layout-gsubgpos.hh             |  5 ++-
+ 3 files changed, 69 insertions(+), 36 deletions(-)
+
+commit 661050b4659ee490dfe622821bc7fde7d1c40510
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 6 12:38:17 2023 -0700
+
+    Revert "[layout] Limit how far we skip when looking back"
+    
+    This reverts commit 85be877925ddbf34f74a1229f3ca1716bb6170dc.
+
+ src/hb-ot-layout-gsubgpos.hh | 7 -------
+ 1 file changed, 7 deletions(-)
+
+commit b29fbd16fa82b82bdf0dcb2f13a63f7dc23cf324
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 6 13:08:52 2023 -0700
+
+    [gsubgpos] Refactor skippy_iter.match()
+
+ src/hb-ot-layout-gsubgpos.hh | 94 +++++++++++++++++++++++++-------------------
+ 1 file changed, 54 insertions(+), 40 deletions(-)
+
+commit ef2a8f722fc0ec12f5a59d44d4d60d376907fd31
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 6 12:04:16 2023 -0700
+
+    [VarComposite] Adjust for RESET_UNSPECIFIED_AXES semantic change
+    
+    https://github.com/harfbuzz/boring-expansion-spec/issues/81
+
+ src/OT/glyf/Glyph.hh | 2 +-
+ src/hb-array.hh      | 3 +++
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+commit 474b99d12238d4c401c970874688a2567c017534
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 4 10:16:11 2023 -0700
+
+    [test-paint] Fix build without FreeType
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4103
+
+ test/api/test-paint.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d250fd979b54d26b7f432c809a153c3f90f020a9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 2 10:57:30 2023 -0700
+
+    [font] Docs
+
+ docs/harfbuzz-sections.txt | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit cf39d316d86edb253873143596484baaeddce30e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 2 10:45:35 2023 -0700
+
+    [outline] Add FreeType authors copyrights
+
+ COPYING           | 4 ++--
+ src/hb-outline.cc | 8 +++++++-
+ 2 files changed, 9 insertions(+), 3 deletions(-)
+
+commit 061f995845f347a481e4ff6f66fd66c6b50bfcfb
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Feb 2 08:15:02 2023 +0100
+
+    [font] Document synthetic boldness APIs
+
+ src/hb-font.cc | 31 +++++++++++++++++++++++++++++++
+ 1 file changed, 31 insertions(+)
+
+commit 2119eab69f5e8c5323fa23ab6c7dc26c2ab5aab3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 1 17:37:10 2023 -0700
+
+    [embolden] Adjust advance values
+
+ src/hb-ft.cc      | 16 +++++++++++++++-
+ src/hb-ot-font.cc | 29 +++++++++++++++++++++++++++++
+ 2 files changed, 44 insertions(+), 1 deletion(-)
+
+commit b087266e511d21b5c63b02fa7eed45af4061e543
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 1 17:09:29 2023 -0700
+
+    [ot-font] Conditionalize emboldening
+
+ src/hb-ot-font.cc | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+commit 36dcc9a4327f824ccaa5751412707731504e1023
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 1 17:06:15 2023 -0700
+
+    [ot-font] Fix emboldening CFF
+
+ src/hb-ot-font.cc | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+commit 6b3fe8ac1beeb97194e5171b5fe3873236879fdd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 1 17:00:14 2023 -0700
+
+    [embolden] Semi-handle with negative scales
+
+ src/hb-font.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit e39104ba1920a1bd2f6b4a56ace6cb66f7fcab6e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 1 16:56:56 2023 -0700
+
+    [font/util] Add emboldening API, --font-bold
+    
+    Needs documentation.
+
+ src/hb-font.cc       | 34 ++++++++++++++++++++++++++++++++--
+ src/hb-font.h        |  6 ++++++
+ src/hb-font.hh       | 12 ++++++++++++
+ src/hb-ft.cc         |  4 +---
+ src/hb-ot-font.cc    |  4 +---
+ util/font-options.hh | 25 ++++++++++++++++++++++++-
+ 6 files changed, 76 insertions(+), 9 deletions(-)
+
+commit 4247b78e31e00d02d3a6951888d5cae89d4e9060
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 1 16:26:07 2023 -0700
+
+    [outline] Comment
+
+ src/hb-outline.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit ae522a1372c34bd013990de1b09d5cfa84433590
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 1 16:24:44 2023 -0700
+
+    [embolden] Rename to hb-outline
+
+ src/Makefile.sources                       |  2 +
+ src/harfbuzz-subset.cc                     |  1 +
+ src/harfbuzz.cc                            |  1 +
+ src/hb-ot-font.cc                          |  2 +-
+ src/{hb-draw-embolden.hh => hb-outline.cc} | 54 ++------------------
+ src/hb-outline.hh                          | 82 ++++++++++++++++++++++++++++++
+ src/meson.build                            |  2 +
+ 7 files changed, 94 insertions(+), 50 deletions(-)
+
+commit fda2f6f64e5033c824187b50fcdd07b1d65d1080
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 1 16:16:10 2023 -0700
+
+    [embolden] Shuffle under hb_outline_t
+
+ src/hb-draw-embolden.hh | 377 ++++++++++++++++++++++++------------------------
+ src/hb-ot-font.cc       |  10 +-
+ 2 files changed, 192 insertions(+), 195 deletions(-)
+
+commit 7774bccb48404f4b998d16b701463039bf0955da
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 1 16:12:10 2023 -0700
+
+    [embolden] Renames
+
+ src/hb-draw-embolden.hh | 134 ++++++++++++++++++++++++------------------------
+ 1 file changed, 66 insertions(+), 68 deletions(-)
+
+commit c06f95ebe18e7f6a093e28e8dcb322ca6e4d5a8d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 1 16:02:48 2023 -0700
+
+    [embolden] Move code
+
+ src/hb-draw-embolden.hh | 72 +++++++++++++++++++++++--------------------------
+ 1 file changed, 34 insertions(+), 38 deletions(-)
+
+commit 6b4a6fbedded342182cca5356707050696912753
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 1 15:59:37 2023 -0700
+
+    [embolden] Add orientation detection
+
+ src/hb-draw-embolden.hh | 24 ++++++++++++++++++++++--
+ 1 file changed, 22 insertions(+), 2 deletions(-)
+
+commit 1817f18085a7476759e794cfb0b4a627fc1487cc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 1 15:49:05 2023 -0700
+
+    [embolden] Simplify recording-pen
+
+ src/hb-draw-embolden.hh | 109 +++++++++++++++++++++++-------------------------
+ 1 file changed, 53 insertions(+), 56 deletions(-)
+
+commit 70149885a78017475ebedd732ca5d3b0d4d8c595
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 1 14:27:45 2023 -0700
+
+    [font] Towards implementing emboldening
+
+ src/hb-draw-embolden.hh | 349 ++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-ft.cc            |   6 +-
+ src/hb-ot-font.cc       |  20 ++-
+ src/hb-vector.hh        |   5 +-
+ 4 files changed, 373 insertions(+), 7 deletions(-)
+
+commit b5c68c1cf3a64b1be0708201bf433e7ae73c1f34
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 2 15:50:53 2023 -0700
+
+    [codecov] Enable information patch mode
+
+ .codecov.yml | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+commit fda200658e3d3e2db466c9eb81be349df94c6704
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Feb 2 22:03:36 2023 +0000
+
+    [subset] fix missing compiled glyph cleanup when serialization succeeds.
+
+ src/OT/glyf/glyf.hh | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+commit 9bd3259335322338e2181935dc031fb9d7805e10
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 2 13:36:23 2023 -0700
+
+    [cairo] Fix uninitialized value
+    
+    Ouch!
+
+ src/hb-cairo-utils.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 85be877925ddbf34f74a1229f3ca1716bb6170dc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 1 20:00:43 2023 -0700
+
+    [layout] Limit how far we skip when looking back
+    
+    See comments.
+
+ src/hb-ot-layout-gsubgpos.hh | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+commit d18fd3f7ebcd75e99c928c52fabfc51359000d26
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 31 16:28:49 2023 -0700
+
+    [layout] Comment
+
+ src/hb-ot-layout-gsubgpos.hh | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit 7a4bd97e4a3633429675a91df069b927ff3c580c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 31 14:59:39 2023 -0700
+
+    [layout] Build lookup accelerators lazily on-demand
+    
+    Reduces memory consumption for large multi-script fonts
+    drastically.
+
+ src/hb-ot-font.cc                   |  3 +-
+ src/hb-ot-layout-gpos-table.hh      |  7 ++--
+ src/hb-ot-layout-gsub-table.hh      |  7 ++--
+ src/hb-ot-layout-gsubgpos.hh        | 66 ++++++++++++++++++++++++-------------
+ src/hb-ot-layout.cc                 | 35 +++++++++++---------
+ src/hb-ot-shaper-arabic-fallback.hh | 15 +++++----
+ 6 files changed, 76 insertions(+), 57 deletions(-)
+
+commit 83353f13f45fefbf0ad1eb0d5388b2c8bf2f7702
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 31 14:32:14 2023 -0700
+
+    [layout] Reduce memory use slightly
+    
+    By using raw pointer instead of vector for subtable accelerator.
+    
+    To be used for more memory saving by making subtable accelerators
+    lazy-loaded by shape-plans for large fonts.
+
+ src/hb-ot-layout-gpos-table.hh |  2 +-
+ src/hb-ot-layout-gsub-table.hh |  2 +-
+ src/hb-ot-layout-gsubgpos.hh   | 37 +++++++++++++++++++++----------------
+ src/hb-ot-layout.cc            | 15 +++++++++------
+ 4 files changed, 32 insertions(+), 24 deletions(-)
+
+commit 2b6d74b42e2320f2caf8a99dcf98ef692819d689
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Jan 31 17:37:37 2023 +0000
+
+    [subset] for keep everything, don't drop any tables.
+
+ src/hb-subset-input.cc | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit 277003d553293c7af0b5b6d25be02fac0925e597
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 30 22:43:01 2023 -0700
+
+    [ft] Fit advance cache into short int
+
+ src/hb-ft.cc | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit a924bbcfce67fed3da4ad6cf92178f7135a3359a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 30 14:13:33 2023 -0700
+
+    [atomic/cache] Add hb_atomic_short_t
+
+ src/hb-atomic.hh | 30 +++++++++++++++++++++++++-----
+ src/hb-cache.hh  |  4 +++-
+ 2 files changed, 28 insertions(+), 6 deletions(-)
+
+commit e7a71ea15b1df6feb3ca9811eb3abe721a63e21f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 30 11:21:08 2023 -0700
+
+    [font] Docs
+
+ src/hb-font.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit cb47dca74cbf6d147aac9cf3067f249555aa68b1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 29 10:03:52 2023 -0700
+
+    [object] Handle mallocation error in set_user_data
+    
+    Should make bots happy.
+
+ src/hb-object.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 548bad221c6ba8a82fc3387923ca0382d183ab5e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 29 10:10:48 2023 -0700
+
+    [user-data] Move methods to header file
+    
+    No idea why they were in hb-static.
+
+ src/hb-object.hh | 32 ++++++++++++++++++++++++++------
+ src/hb-static.cc | 32 --------------------------------
+ 2 files changed, 26 insertions(+), 38 deletions(-)
+
+commit 02f79f60f26d800d55194be174210bf47968812e
+Merge: 6622e04aa 784fe9ac6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 29 09:36:46 2023 -0700
+
+    Merge pull request #4092 from harfbuzz/more-cmap-cache
+    
+    [ot-font] Use the cmap cache more
+
+commit 784fe9ac67f9c0a203367222671d431a85c98cfa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 29 09:26:52 2023 -0700
+
+    [cmap] Simplify caching
+
+ src/hb-ot-cmap-table.hh | 19 ++++++-------------
+ 1 file changed, 6 insertions(+), 13 deletions(-)
+
+commit a451aa5465ed80963f09c9f0290979608b1d675e
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Jan 29 11:25:28 2023 -0500
+
+    Add back a null check
+    
+    This was accidentally dropped in the previous commit.
+
+ src/hb-ot-cmap-table.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 6622e04aa1b9d8b38e53cbe3e71c0b7066fd7208
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 29 09:06:52 2023 -0700
+
+    [solver] Fix unused-variable error
+    
+    https://github.com/harfbuzz/harfbuzz/commit/223abd72b9f48c951ce1e99d89328edbcff43515
+
+ src/hb-subset-instancer-solver.cc | 13 +++----------
+ 1 file changed, 3 insertions(+), 10 deletions(-)
+
+commit 318aa107082cf4ab1c2fcc5f0bf2ead145216e1d
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Jan 29 09:17:17 2023 -0500
+
+    [ot-font] Use the cmap cache more
+    
+    Use the cmap cache for get_nominal_glyph and
+    get_variation_glyph as well. The first of these
+    is used a lot in pango.
+
+ src/hb-ot-cmap-table.hh | 21 +++++++++++++++------
+ src/hb-ot-font.cc       |  6 ++++--
+ 2 files changed, 19 insertions(+), 8 deletions(-)
+
+commit 5da829eaf534b78ee2fee7fbea86e8deb36bfef3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 28 22:18:53 2023 -0700
+
+    [font] Comments
+
+ src/hb-ot-font.cc | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+commit 544dd9678c51458c9a19a951a873a0a259cdfe7a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 28 22:06:46 2023 -0700
+
+    [font] Fix unlikely
+
+ src/hb-ot-font.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c1d0daf5f12caf2b13f267941d761fd9c37d4fd6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 28 22:05:24 2023 -0700
+
+    [font] unlikely
+
+ src/hb-ot-font.cc | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit 30ee7a21e174e56a2f9caf750e666d16f002247a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 28 21:48:16 2023 -0700
+
+    [font] Typo
+
+ src/hb-ot-font.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 04056d44e2265a44fe3090ff7eb5a7a493d3221c
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Jan 28 22:52:25 2023 -0500
+
+    [layout] Optimize more buffer message calls
+    
+    Continuation of da7b66c1f8bbf7147f8113.
+
+ src/hb-ot-layout.cc | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+commit f8a744d9d52d64f69778c2bfc2848ae2f2d1f63b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 28 13:37:43 2023 -0700
+
+    [ot-font] Add a cmap cache
+    
+    Speeds up Roboto shaping by 7%, for 1kb per face.
+
+ src/hb-ot-cmap-table.hh | 27 ++++++++++++++++++++++-----
+ src/hb-ot-font.cc       | 33 ++++++++++++++++++++++++++++++++-
+ 2 files changed, 54 insertions(+), 6 deletions(-)
+
+commit 1b53ed3c418298c760c42c612e2b6a2126237ee1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 28 13:22:52 2023 -0700
+
+    [cache] Remove empty fini()
+
+ src/hb-cache.hh   | 1 -
+ src/hb-ft.cc      | 2 --
+ src/hb-ot-font.cc | 3 ---
+ 3 files changed, 6 deletions(-)
+
+commit 115d572571fbd5fdb3bf677a0248dc8fdd29b31d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 28 13:22:08 2023 -0700
+
+    [cache] Add constructor
+
+ src/hb-cache.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit ae96295d6737a9e6f925ffb8043118d3e051cdaa
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Jan 28 22:12:33 2023 +0200
+
+    Delete commented out include
+
+ src/OT/Color/COLR/colrv1-closure.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 09b7fce857c4cde4f1a8e7925aa5c96052e5c050
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Jan 28 13:21:27 2023 -0500
+
+    Make includes relative
+
+ src/OT/Layout/GDEF/GDEF.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit e25e4c9a52233056bfda866fbbe635dc490726fc
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Jan 28 00:10:47 2023 -0500
+
+    Move GDEF table to src/OT/Layout/GDEF
+
+ src/Makefile.sources           |   1 +
+ src/OT/Layout/GDEF/GDEF.hh     | 918 +++++++++++++++++++++++++++++++++++++++++
+ src/hb-ot-layout-gdef-table.hh | 886 +--------------------------------------
+ src/meson.build                |   1 +
+ 4 files changed, 921 insertions(+), 885 deletions(-)
+
+commit f89fa6dcfe8fc9ea53c9502f51024ec1dfac9a39
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Jan 27 23:54:34 2023 -0500
+
+    Move name table to src/OT/name
+
+ src/Makefile.sources    |   1 +
+ src/OT/name/name.hh     | 589 ++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-ot-name-table.hh | 559 +--------------------------------------------
+ src/meson.build         |   1 +
+ 4 files changed, 592 insertions(+), 558 deletions(-)
+
+commit b8193357c1a0ce5013d074beaffda5cb6f6ae9c6
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Jan 28 00:00:30 2023 -0500
+
+    [OT::Color] Drop unused includes
+
+ src/OT/Color/COLR/COLR.hh           | 1 -
+ src/OT/Color/COLR/colrv1-closure.hh | 2 +-
+ src/OT/Color/sbix/sbix.hh           | 1 -
+ 3 files changed, 1 insertion(+), 3 deletions(-)
+
+commit da7b66c1f8bbf7147f8113922f81c02002af818c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 27 16:39:06 2023 -0700
+
+    [layout] Optimize buffer message calls
+    
+    Those aren't exactly free. They were showing up in profiles.
+
+ src/hb-ot-layout.cc | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+commit 49d75ef331a372fc6545fbf0643ce053dbe39341
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 27 15:37:11 2023 -0700
+
+    [gsubgpos] Fix bug in cached ChainContextFormat2 application
+
+ src/hb-ot-layout-gsubgpos.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d2279a204f4452ac88a08eec07958fea7a70e549
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 27 12:32:55 2023 -0700
+
+    [gsubgpos] Avoid a copy into the vector
+
+ src/hb-ot-layout-gsubgpos.hh | 14 ++++++--------
+ 1 file changed, 6 insertions(+), 8 deletions(-)
+
+commit 615595689c9b0e5ee8af3c689e78cbbca7d7c4be
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Jan 27 11:05:13 2023 -0800
+
+    [subset/COLR] add tests for copying varStore
+
+ test/subset/data/Makefile.am                            |   1 +
+ test/subset/data/Makefile.sources                       |   1 +
+ .../colrv1_copy_varstore/Foldit.default.41,42.ttf       | Bin 0 -> 43860 bytes
+ .../expected/colrv1_copy_varstore/Foldit.default.41.ttf | Bin 0 -> 43048 bytes
+ .../Foldit.default.retain-all-codepoint.ttf             | Bin 0 -> 44336 bytes
+ .../Foldit.drop-hints-retain-gids.41,42.ttf             | Bin 0 -> 43836 bytes
+ .../Foldit.drop-hints-retain-gids.41.ttf                | Bin 0 -> 43032 bytes
+ ...ldit.drop-hints-retain-gids.retain-all-codepoint.ttf | Bin 0 -> 44300 bytes
+ .../colrv1_copy_varstore/Foldit.drop-hints.41,42.ttf    | Bin 0 -> 43820 bytes
+ .../colrv1_copy_varstore/Foldit.drop-hints.41.ttf       | Bin 0 -> 43016 bytes
+ .../Foldit.drop-hints.retain-all-codepoint.ttf          | Bin 0 -> 44300 bytes
+ .../colrv1_copy_varstore/Foldit.retain-gids.41,42.ttf   | Bin 0 -> 43876 bytes
+ .../colrv1_copy_varstore/Foldit.retain-gids.41.ttf      | Bin 0 -> 43064 bytes
+ .../Foldit.retain-gids.retain-all-codepoint.ttf         | Bin 0 -> 44336 bytes
+ test/subset/data/fonts/Foldit.ttf                       | Bin 0 -> 44340 bytes
+ test/subset/data/tests/colrv1_copy_varstore.tests       |  13 +++++++++++++
+ test/subset/meson.build                                 |   1 +
+ 17 files changed, 16 insertions(+)
+
+commit 0f33ea8c4fe39ee1b39a2ce87f07a7522a99808c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 27 11:26:57 2023 -0700
+
+    [subset/COLR] Copy VarStore
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4085
+
+ src/OT/Color/COLR/COLR.hh  |  2 +-
+ src/hb-ot-layout-common.hh | 26 ++++++++++++++++++++++++++
+ 2 files changed, 27 insertions(+), 1 deletion(-)
+
+commit 6c46da7710616b7f085da789ce4131d1169fce5d
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Jan 27 10:34:50 2023 +0200
+
+    [test] Fix shell script quoting
+
+ test/shape/record-test.sh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit c03c8548f48c08434957ec4de4f59c2af422fe0a
+Merge: 950c7ab3f 7a714d1a8
+Author: Matthias Clasen <matthias.clasen@gmail.com>
+Date:   Thu Jan 26 23:17:11 2023 -0500
+
+    Merge pull request #4084 from harfbuzz/cairo-check-funcs
+    
+    [meson] Enable all checked for Cairo functions for internal Cairo
+
+commit 7a714d1a8d28f626efeb7e1785acda104ffce29f
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Jan 27 03:12:36 2023 +0200
+
+    [meson] Enable all checked for Cairo functions for internal Cairo
+    
+    Similar to what we do with FreeType ones.
+
+ meson.build | 16 +++++++++++-----
+ 1 file changed, 11 insertions(+), 5 deletions(-)
+
+commit 950c7ab3f0486b5baa0f602c7b12fc85cadd5428
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 26 15:26:05 2023 -0700
+
+    [gsubgpos] Use accelerator when recursing
+
+ src/hb-ot-layout-gpos-table.hh | 12 ++++++++++--
+ src/hb-ot-layout-gsub-table.hh | 12 ++++++++++--
+ 2 files changed, 20 insertions(+), 4 deletions(-)
+
+commit e377888990239dc6d108777c1be61a99bade6e01
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 26 13:26:47 2023 -0700
+
+    [ft-colr] Conditionalize on (unreleased0 FreeType 2.13.0
+    
+    That's the version that the color API is called stable, and
+    includes changes that we rely on.
+
+ src/hb-ft.cc          |  6 +++---
+ test/api/test-paint.c | 10 +++++-----
+ 2 files changed, 8 insertions(+), 8 deletions(-)
+
+commit 281db89a688f253ea91c780ebe2c0c9494d234f2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 26 13:05:12 2023 -0700
+
+    [cairo] Try to handle failure in set_user_data
+
+ src/hb-cairo.cc | 42 ++++++++++++++++++++++++++----------------
+ 1 file changed, 26 insertions(+), 16 deletions(-)
+
+commit 2fede3ef4a95184d831fae698c20d5616cccb89a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 26 12:23:12 2023 -0700
+
+    [layout] Fix a return_trace
+
+ src/hb-ot-layout-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 05a2f31592711e02c359d5f1d9955052df9455e2
+Merge: aea37bfd3 e484d6b99
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 26 12:56:02 2023 -0700
+
+    Merge pull request #4065 from harfbuzz/cairo-fix-foreground-color
+    
+    hb-cairo: Fix handling of foreground color
+
+commit e484d6b990171ba28e7ee8811f3a41d32b1d0418
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 26 12:55:25 2023 -0700
+
+    [cairo] Handle malloc failure
+
+ src/hb-cairo-utils.cc | 22 ++++++++++++++++++----
+ 1 file changed, 18 insertions(+), 4 deletions(-)
+
+commit 29a36010a1514c72c207fec8b5ab8361617a0078
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 17:26:33 2023 -0700
+
+    [cairo] Adapt to cairo foreground API change again
+
+ src/hb-cairo-utils.cc | 2 +-
+ src/hb-cairo.cc       | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 30d0d9c56c5f481b93141ca2742f6c992443ac46
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Tue Jan 24 15:43:17 2023 -0500
+
+    Adapt to cairo changes
+    
+    Adapt to the api in the cairo MR that will be used,
+    and make the code build with older cairo.
+
+ meson.build           | 1 +
+ src/hb-cairo-utils.cc | 4 +++-
+ src/hb-cairo.cc       | 4 +++-
+ 3 files changed, 7 insertions(+), 2 deletions(-)
+
+commit 034d4d26f2dc31b73db72b94ca265ee45da44ddd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 23 16:22:26 2023 -0700
+
+    [hb-cairo] Minor simplify
+
+ src/hb-cairo-utils.cc | 4 +---
+ src/hb-cairo.cc       | 4 +---
+ 2 files changed, 2 insertions(+), 6 deletions(-)
+
+commit 26d34392e2dd2ea0e9908c1d53e1223487f021cc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 23 16:21:13 2023 -0700
+
+    [hb-cairo] Fix condition
+
+ src/hb-cairo.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f9b3c79047aaedbffe4690b3bc6093c241ca5e90
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Jan 23 18:09:09 2023 -0500
+
+    Update to different cairo API
+    
+    The cairo will likely end up begin a getter for
+    a cairo_pattern_t instead of a color.
+
+ src/hb-cairo-utils.cc | 11 ++++++++---
+ src/hb-cairo.cc       | 12 +++++++-----
+ 2 files changed, 15 insertions(+), 8 deletions(-)
+
+commit 4afdbcbad55e5b5a4718c52398663cfd889a92ae
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 23 15:53:26 2023 -0700
+
+    [hb-cairo] Don't call get_foreground_color unnecessarily
+    
+    That would invalidate cairo cache on foreground change, even
+    if the glyph doesn't need that.
+
+ src/hb-cairo-utils.cc | 42 +++++++++++++++++++++++++++---------------
+ src/hb-cairo.cc       | 23 +++++++++++++++--------
+ 2 files changed, 42 insertions(+), 23 deletions(-)
+
+commit c37ea4f93ed726c37739325e3f181b3973182e29
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Jan 23 08:31:24 2023 -0500
+
+    hb-cairo: Fix handling of foreground color
+    
+    Use the new cairo_user_scaled_font_get_foreground_color
+    to obtain the foreground color, since the cr's source
+    can't be trusted.
+    
+    Requires https://gitlab.freedesktop.org/cairo/cairo/-/merge_requests/420
+
+ src/hb-cairo.cc | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+commit aea37bfd370b880c553c1b5c80b7ddba59a28be6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 26 12:18:50 2023 -0700
+
+    Fix c++20 build
+
+ src/hb-subset-instancer-solver.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e1dc4920eeb220b5cb3d5f20446748e63b158623
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 26 12:11:35 2023 -0700
+
+    [iter] Allow hb_len() to fetch c.len as non-function
+
+ src/hb-iter.hh | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+commit 8d29be39b2fa777f70a4481629ac0c29fb1813fe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 26 11:41:58 2023 -0700
+
+    [gsubgpos] Minor drop an unnecessary hb_iter
+
+ src/hb-ot-layout-gsubgpos.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 06b9b3b5b66b0883d2274c6a6522378df6f4859c
+Merge: c1a5d2095 4a632dec7
+Author: Matthias Clasen <matthias.clasen@gmail.com>
+Date:   Thu Jan 26 14:15:52 2023 -0500
+
+    Merge pull request #4083 from harfbuzz/bump-cairo
+    
+    build: Bump to newer cairo
+
+commit 4a632dec788fbb90d61d196e563f342440448240
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Jan 26 13:19:50 2023 -0500
+
+    build: Bump to newer cairo
+
+ subprojects/cairo.wrap | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c1a5d20951803f8619094b98bac76d474963e264
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Jan 25 21:52:05 2023 -0500
+
+    [doc] Add a missing comma
+
+ src/hb-paint.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 8d80d1dd184c06a94d07afe5f06b1513e1ccae3a
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Jan 25 19:06:51 2023 -0500
+
+    [paint] Update expected test results
+    
+    These tests were affected by recent fixes.
+
+ test/api/results/test-106   | 6 +++---
+ test/api/results/testvf-106 | 6 +++---
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+commit 570fe998c942e1042c66bbab2f848a9e05ad777a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 15:42:24 2023 -0700
+
+    [cairo] Another sweep_gradient fix
+    
+    k was -1 sometimes.
+    
+    Fixes the rest of https://roettsch.es/var_colrv1.html
+
+ src/hb-cairo-utils.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 13bfef9f01d2e11e5520c25d884ac51162d33cf2
+Author: Andres Salomon <dilinger@queued.net>
+Date:   Wed Jan 25 16:14:59 2023 -0500
+
+    [COPYING] Another update
+    
+    Adobe, Inc has copyright in src/hb-subset-cff*, test/api/test-subset*, and
+    misc other places.
+    
+    Ebrahim Byagowi has copyright as far back as 2015 in places like
+    src/hb-directwrite.cc.
+    
+    Google, Inc has newer copyright into 2022 in places like
+    src/graph/test-classdef-graph.cc. Also, listing every year was getting a bit
+    unwieldy, so just do 2010-2022.
+    
+    Igalia S.L. contributed the stuff in src/hb-ot-math*.
+    
+    The only references I could find to Martin Hosken & SIL were in
+    src/hb-graphite2*, and they were 2011, not 2009.
+    
+    Mozilla's got a bunch of 2015 code in src/hb-ot-shaper-*.
+    
+    Red Hat has copyright up to 2023 (eg, test/api/test-glyph-names.c).
+
+ COPYING | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+commit ea316b56a0ef1e84c29cd31b45b083bbe0120f83
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 15:31:29 2023 -0700
+
+    [cairo] Flip offsets when reversing
+    
+    Fixes many of the var_colrv1 first row tests.
+    
+    https://roettsch.es/var_colrv1.html
+
+ src/hb-cairo-utils.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 5b05e198cf047335ee9d421d60a0d57e6693424a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 15:24:14 2023 -0700
+
+    [cairo] More hb_malloc
+
+ src/hb-cairo-utils.cc | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 57352b8bd4cc35ca6f2e3db7127c266e1a6a938d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 15:22:27 2023 -0700
+
+    [cairo] Use hb_malloc / hb_free
+
+ src/hb-cairo-utils.cc | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit a9392c0cbb44111c2d5424257aafdebf2de8604c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 14:54:52 2023 -0700
+
+    [cairo] Use hb_swap()
+
+ src/hb-cairo-utils.cc | 10 ++--------
+ 1 file changed, 2 insertions(+), 8 deletions(-)
+
+commit 5e868703788057696eb062fc30de0898058fdc41
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Jan 25 12:27:16 2023 -0800
+
+    [instancer] compute head/maxp values using only non-empty glyphs
+
+ src/OT/glyf/Glyph.hh                                     |  14 +++++++++++++-
+ ...fault.retain-all-codepoint.wght=100,ELGR=1,ELSH=2.ttf | Bin 0 -> 2244 bytes
+ test/subset/data/tests/instance_no_double_free.tests     |   1 +
+ 3 files changed, 14 insertions(+), 1 deletion(-)
+
+commit d15551c6f394e8a7732f81fd51b8a0304e8e050c
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Jan 25 11:01:08 2023 -0800
+
+    [instancer] update head table flagbit: allXMinIsLsb
+
+ src/OT/glyf/Glyph.hh        | 3 +++
+ src/OT/glyf/glyf-helpers.hh | 7 +++++++
+ src/hb-ot-head-table.hh     | 2 ++
+ src/hb-subset-plan.hh       | 4 +++-
+ 4 files changed, 15 insertions(+), 1 deletion(-)
+
+commit 2c49eba044be55d81470ffaa9f854734c607e6e4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 14:52:39 2023 -0700
+
+    [cairo] Indent
+
+ src/hb-cairo-utils.cc | 398 +++++++++++++++++++++++++-------------------------
+ 1 file changed, 199 insertions(+), 199 deletions(-)
+
+commit 2accbdc0b6cbee4b6d9f581d8a890601881506fb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 14:40:04 2023 -0700
+
+    [paint] Minor skew
+
+ src/hb-paint.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit a4420479a8f2d4d9b11039f5b7862f7f5f684db1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 14:37:10 2023 -0700
+
+    Revert "[VarComposite] Fix skew"
+    
+    This reverts commit 8cf7076309da014e8e2af033b1c636785ae407cd.
+
+ src/OT/glyf/VarCompositeGlyph.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 8cf7076309da014e8e2af033b1c636785ae407cd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 14:35:35 2023 -0700
+
+    [VarComposite] Fix skew
+
+ src/OT/glyf/VarCompositeGlyph.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 626f8e4de3060376d12c77ac4967fd6fb908169a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 14:33:46 2023 -0700
+
+    [paint] Fix skew to match Chrome
+
+ src/hb-paint.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit b44ff062e1dcddb51c13d3df9e66b31339d7e4b5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 14:16:46 2023 -0700
+
+    [deserialize] Some more
+
+ src/hb-buffer-deserialize-text-glyphs.hh  | 9 ++++++++-
+ src/hb-buffer-deserialize-text-glyphs.rl  | 9 ++++++++-
+ src/hb-buffer-deserialize-text-unicode.hh | 9 ++++++++-
+ src/hb-buffer-deserialize-text-unicode.rl | 9 ++++++++-
+ src/test-buffer-serialize.cc              | 2 +-
+ 5 files changed, 33 insertions(+), 5 deletions(-)
+
+commit 57ff696430bf28072aa9b532250ea556f04d40e2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 14:09:22 2023 -0700
+
+    [deserialize] One more fix
+
+ src/hb-buffer-deserialize-text-unicode.hh | 128 +++++++++++++++++-------------
+ src/hb-buffer-deserialize-text-unicode.rl |   4 +-
+ 2 files changed, 77 insertions(+), 55 deletions(-)
+
+commit e973050986b298458ef95c77356b2cdfdbb0c227
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 14:07:01 2023 -0700
+
+    [hb-buffer-deserialize] Fixups
+
+ src/hb-buffer-deserialize-text-glyphs.hh  | 689 +++++++++++++++++-------------
+ src/hb-buffer-deserialize-text-glyphs.rl  |  20 +-
+ src/hb-buffer-deserialize-text-unicode.hh |  27 +-
+ src/hb-buffer-deserialize-text-unicode.rl |  19 +-
+ src/hb-buffer-serialize.cc                |   6 +-
+ src/test-buffer-serialize.cc              |  27 +-
+ 6 files changed, 480 insertions(+), 308 deletions(-)
+
+commit a1101f09ca896610cdb9361e3f924da74e9d043d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 13:10:57 2023 -0700
+
+    [test-buffer-serialize] Handle too-small out buffer
+    
+    Need to handle too-small in buffer still.
+
+ src/test-buffer-serialize.cc | 20 +++++++++++---------
+ 1 file changed, 11 insertions(+), 9 deletions(-)
+
+commit 39d50008f85d087c4ccb09b4954416c39c29cf1a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 12:53:50 2023 -0700
+
+    [hb-info] Format
+
+ util/hb-info.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4e2267b729e6f97f4697d5332d8f6b6e601cb516
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 12:51:53 2023 -0700
+
+    [hb-info] Add --get-meta
+
+ util/hb-info.cc | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+commit 42ed6abb6a9ee832025d29c96e77e5fcc10cc2fd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 12:47:16 2023 -0700
+
+    [hb-info] Add --list-meta
+
+ util/hb-info.cc | 37 +++++++++++++++++++++++++++++++++++++
+ 1 file changed, 37 insertions(+)
+
+commit 2fec4f1c3db4e3ab6f3cc6a7a6bff81b756614f2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 12:09:12 2023 -0700
+
+    [subset] Finish out hb-subset-instancer-solver.cc
+
+ src/hb-subset-instancer-solver.cc | 100 +++++++++++++++++++++++++++++++-------
+ 1 file changed, 83 insertions(+), 17 deletions(-)
+
+commit 90a98dd62a3b8e9eb416b6777f36951c7f5a56a4
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Jan 25 10:06:23 2023 -0800
+
+    [instancer] fix potential memory leak for compiled glyph bytes
+    
+    Also calculate max_offsets after glyph bytes are compiled, cause byte
+    length of a glyph might change after compile
+
+ src/OT/glyf/SubsetGlyph.hh | 10 +-----
+ src/OT/glyf/glyf.hh        | 81 ++++++++++++++++++++++++++++------------------
+ 2 files changed, 51 insertions(+), 40 deletions(-)
+
+commit 223abd72b9f48c951ce1e99d89328edbcff43515
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 11:36:47 2023 -0700
+
+    [subset] Add unfinished port of fonttools instancer solver
+
+ src/Makefile.sources              |   1 +
+ src/harfbuzz-subset.cc            |   1 +
+ src/hb-subset-instancer-solver.cc | 405 ++++++++++++++++++++++++++++++++++++++
+ src/meson.build                   |   1 +
+ 4 files changed, 408 insertions(+)
+
+commit 167443e9fc4f25b661ba7f17e7ea39691839297a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 10:32:01 2023 -0700
+
+    [hb-info] Respect HB_CHAFA=0
+
+ util/hb-info.cc | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 87df84c386d2c03e8df75507b680b02044ee8cdd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 10:20:48 2023 -0700
+
+    [hb-info] Fix copyright header
+
+ util/hb-info.cc | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 0bbc9d5256b3ba0f350b0d5136d2253113723c8b
+Author: Andres Salomon <dilinger@queued.net>
+Date:   Wed Jan 25 00:44:38 2023 -0500
+
+    [fonts] move OFL-1.1 license to a higher directory
+    
+    There's a bunch of font directories inside of test/ for which the vast
+    majority of fonts are licensed under the SIL open font license. We currently
+    have a COPYING file in test/shape/data/in-house/COPYING that says that most
+    of the fonts are OFL-1.1, but that doesn't apply to the fonts in, say,
+    test/api/fonts/ or test/fuzzing/fonts/. Since there are so many OFL-1.1
+    fonts all over test, let's move the COPYING file to the top-level test/
+    directory.
+
+ test/{shape/data/in-house => }/COPYING | 0
+ test/Makefile.am                       | 2 +-
+ test/shape/data/in-house/Makefile.am   | 1 -
+ 3 files changed, 1 insertion(+), 2 deletions(-)
+
+commit 44a9c4bf596ce5da51ab3844de6a685aa5e9e211
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 25 09:58:29 2023 -0700
+
+    [COPYING] Update
+
+ COPYING | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit c622c6b883f514982888a8a40be8223f672c21da
+Author: Andres Salomon <dilinger@queued.net>
+Date:   Tue Jan 24 23:52:10 2023 -0500
+
+    [font] update the license url for TestGVAREight.ttf
+    
+    The url in the exif data incorrectly links to a proprietary license. However,
+    permission was granted for distribution under Apache-2 as part of another project,
+    so link to that project's license instead.
+    
+    fixes #4062
+
+ test/api/fonts/TestGVAREight.ttf                      | Bin 4692 -> 4680 bytes
+ .../data/text-rendering-tests/fonts/TestGVAREight.ttf | Bin 4692 -> 4680 bytes
+ 2 files changed, 0 insertions(+), 0 deletions(-)
+
+commit eb0a025e491a6e2c600836b0a440cd782048b025
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Tue Jan 24 20:40:32 2023 -0500
+
+    Add a test for glyph names
+    
+    This verifies that hb_font_get_glyph_name
+    returns false for nonexisting glyphs.
+
+ test/api/Makefile.am        |   1 +
+ test/api/meson.build        |   1 +
+ test/api/test-glyph-names.c | 112 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 114 insertions(+)
+
+commit 1b143b0f0c1f0fbd1675f077d03c997a6b72b613
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 24 18:34:04 2023 -0700
+
+    [font] Docs
+
+ src/hb-font.cc | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 64ed03c9be0ddb0cba2674e22e8f377090ec5124
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 24 18:30:49 2023 -0700
+
+    [cff1] Return no name for out-of-range glyph IDs
+    
+    Was returning .notdef before.
+
+ src/hb-ot-cff1-table.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit c89aebc40b2c29ad6bcae8e5fff7189f70b35d55
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Tue Jan 24 20:24:27 2023 -0500
+
+    hb-font: Document length limit for glyph names
+    
+    This is useful information for users of the
+    hb_font_get_glyph_name() API.
+
+ src/hb-font.cc | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit dd64266ea444baa4507ce29d88f63d81132d9577
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Tue Jan 24 19:26:20 2023 -0500
+
+    Add a test for glyph extents
+    
+    This verifies a recent fix for COLRv1 returning
+    0,0,-1,1 for extents of non-painting glyphs.
+
+ test/api/Makefile.am       |   1 +
+ test/api/fonts/adwaita.ttf | Bin 0 -> 1332 bytes
+ test/api/meson.build       |   1 +
+ test/api/test-extents.c    | 104 +++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 106 insertions(+)
+
+commit 73e6f6cc88f6656e6061067fbd4170073c068975
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Jan 24 16:14:11 2023 -0800
+
+    [instancer] enable the missing test
+
+ test/subset/data/Makefile.am      | 1 +
+ test/subset/data/Makefile.sources | 1 +
+ test/subset/meson.build           | 1 +
+ 3 files changed, 3 insertions(+)
+
+commit 27f72f0deb12ac99868da28d77c8b60f37d8d893
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Jan 24 16:08:32 2023 -0800
+
+    [instancer] avoid double free for compiled glyph bytes
+    
+    also increase the HB_GLYF_MAX_POINTS limit to 20000 cause the test file has a
+    .notdef glyph which is a composite glyph and has 10176 points after
+    get_points() call
+
+ src/OT/glyf/glyf.hh                                     |   4 +++-
+ src/hb-limits.hh                                        |   2 +-
+ test/subset/data/Makefile.am                            |   1 +
+ test/subset/data/Makefile.sources                       |   1 +
+ ...line.retain-all-codepoint.wght=100,ELGR=1,ELSH=2.ttf | Bin 0 -> 2696 bytes
+ test/subset/data/fonts/Handjet.ttf                      | Bin 0 -> 58944 bytes
+ test/subset/data/tests/instance_no_double_free.tests    |  11 +++++++++++
+ test/subset/meson.build                                 |   1 +
+ 8 files changed, 18 insertions(+), 2 deletions(-)
+
+commit ac969fffa287dc67d3e3c78cbb28a34b48bafa05
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Tue Jan 24 19:06:15 2023 -0500
+
+    Update meson summary
+    
+    Include builtin font callbacks and Cairo integration
+    in the configuration summary.
+
+ meson.build | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 192361cb4dd6fa522a6871c6cbb11151bbc8e1b1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 24 17:05:38 2023 -0700
+
+    [hb-info] Show color swatch only if printing to terminal
+
+ util/hb-info.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 817ec182eb8bcd78de06947602e189aa09308660
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 24 17:02:08 2023 -0700
+
+    [hb-info] Format
+
+ util/hb-info.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 66ddeb0737df78a73c91f5cd32239ca2cfa435c9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 24 17:01:01 2023 -0700
+
+    [hb-info] Change Chafa repeat to 16
+
+ util/hb-info.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 7a29ded1691ba0f3bfcac74045f0c14c6e53b138
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 24 16:59:44 2023 -0700
+
+    [hb-info] Render colors in --list-palette
+    
+    Uses chafa if available
+
+ util/hb-info.cc  | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ util/meson.build |  2 +-
+ 2 files changed, 91 insertions(+), 2 deletions(-)
+
+commit b684c6edd4b024f0c3b7d237dd0c9a1308c28c4b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 23 15:44:22 2023 -0700
+
+    [hb-cairo] Add hb_cairo_context_t
+
+ src/hb-cairo-utils.cc | 16 +++++++++----
+ src/hb-cairo-utils.hh | 15 ++++++++----
+ src/hb-cairo.cc       | 63 ++++++++++++++++++++++++++++++---------------------
+ 3 files changed, 60 insertions(+), 34 deletions(-)
+
+commit 279f13c1870148c0b649d8c435b58d4edf2bade2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 24 11:50:59 2023 -0700
+
+    [hb-shape] Write trace output to stderr
+
+ util/shape-output.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 161d8f9d26ff2725a9965b2b36d2f6045373973d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 24 11:48:10 2023 -0700
+
+    [util] Rename a variable
+
+ util/shape-options.hh | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+commit 68a790261c75e35466952b231e4d2b9f3979cc6e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 24 11:44:32 2023 -0700
+
+    [util] If --glyphs doesn't have positions, use glyph advances
+    
+    Such that eg --glyphs=10 works.
+
+ util/shape-options.hh | 23 +++++++++++++++++++++--
+ 1 file changed, 21 insertions(+), 2 deletions(-)
+
+commit 91a174f151f20ede983eb879fc62631f83919098
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 24 11:27:35 2023 -0700
+
+    [hb-view] Hide --annotate and make it alias for --show-extents
+
+ util/helper-cairo.hh |  2 +-
+ util/view-cairo.hh   | 13 ++++---------
+ util/view-options.hh | 10 ++--------
+ 3 files changed, 7 insertions(+), 18 deletions(-)
+
+commit 8cfb0ed07289dc8982003e53277f064b65a7a1eb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 24 11:24:31 2023 -0700
+
+    [hb-view] --annotate enables --show-extents
+
+ util/view-options.hh | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 20fcf5c5b8c2c068dc4956b3100d4d9b150c2a41
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 24 11:22:55 2023 -0700
+
+    [hb-view] Add --show-extents
+
+ util/view-cairo.hh   | 25 ++++++++++++++++++++++++-
+ util/view-options.hh |  2 ++
+ 2 files changed, 26 insertions(+), 1 deletion(-)
+
+commit 72e13fff6537febcd4dd316954b52a2a0d3cf1a0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 24 11:05:38 2023 -0700
+
+    [COLRv1] Handle void extents
+
+ src/OT/Color/COLR/COLR.hh | 18 ++++++++++++++----
+ 1 file changed, 14 insertions(+), 4 deletions(-)
+
+commit 20318feddf71e5d275bb48ebee12829f2e113f70
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 24 11:04:10 2023 -0700
+
+    [COLRv1] Don't return extents if glyph has no paint
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4068
+
+ src/OT/Color/COLR/COLR.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 32afdcdb46dbb9e54272a142f4d6fa742ca724f4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 23 21:10:11 2023 -0700
+
+    [hb-buffer-deserialize-text-unicode] Relax parsing
+
+ src/hb-buffer-deserialize-text-unicode.hh | 88 ++++++++++++++++++-------------
+ src/hb-buffer-deserialize-text-unicode.rl |  2 +-
+ 2 files changed, 53 insertions(+), 37 deletions(-)
+
+commit 328ee9b4ad2fcdb5f78db0dfb6a9c168b1c9b918
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 23 21:06:27 2023 -0700
+
+    [hb-buffer-deserialize-text-unicodes] Rename
+
+ src/Makefile.sources                               |  4 +-
+ ...es.hh => hb-buffer-deserialize-text-unicode.hh} | 78 +++++++++++-----------
+ ...es.rl => hb-buffer-deserialize-text-unicode.rl} | 18 ++---
+ src/hb-buffer-serialize.cc                         |  8 +--
+ src/meson.build                                    |  4 +-
+ 5 files changed, 56 insertions(+), 56 deletions(-)
+
+commit bc596b8ccae15502f641cc88ddf5fa52e3c6473d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 23 21:03:59 2023 -0700
+
+    [buffer-deserialize-text-unicode] Simplify
+
+ src/hb-buffer-deserialize-text-unicodes.hh | 21 ++++++++++-----------
+ src/hb-buffer-deserialize-text-unicodes.rl |  3 +--
+ 2 files changed, 11 insertions(+), 13 deletions(-)
+
+commit 649973a316ef4616b26210a553727a3cdd33ed98
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 23 21:02:14 2023 -0700
+
+    Fix build
+
+ src/hb-buffer-deserialize-text-glyphs.hh   | 570 ++++++++++++++++++++
+ src/hb-buffer-deserialize-text-unicodes.hh | 275 ++++++++++
+ src/hb-buffer-deserialize-text.hh          | 801 -----------------------------
+ 3 files changed, 845 insertions(+), 801 deletions(-)
+
+commit f798cf225ec4dab7fa4683224e26f3df08c59189
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 23 20:57:30 2023 -0700
+
+    [util] Don't require final ']' in --glyphs
+
+ util/shape-options.hh | 17 ++++++++++++++++-
+ 1 file changed, 16 insertions(+), 1 deletion(-)
+
+commit 4268283e5463f72cc93a8c66f6b0537b991017a1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 23 20:53:17 2023 -0700
+
+    [buffer-deserialize-text] Accept initial comma
+
+ src/hb-buffer-deserialize-json.hh          | 10 ++++------
+ src/hb-buffer-deserialize-json.rl          |  2 --
+ src/hb-buffer-deserialize-text-glyphs.rl   |  4 +++-
+ src/hb-buffer-deserialize-text-unicodes.rl |  4 +++-
+ 4 files changed, 10 insertions(+), 10 deletions(-)
+
+commit 2c29b81e7f36cf56e92f5b5eb406cc46e6394178
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 23 20:49:19 2023 -0700
+
+    [buffer-deserialize-text] Separate glyphs / unicodes machines
+
+ src/Makefile.sources                               |   6 +-
+ ...ext.rl => hb-buffer-deserialize-text-glyphs.rl} |  31 ++----
+ src/hb-buffer-deserialize-text-unicodes.rl         | 108 +++++++++++++++++++++
+ src/hb-buffer-serialize.cc                         |  15 +--
+ src/meson.build                                    |   6 +-
+ 5 files changed, 130 insertions(+), 36 deletions(-)
+
+commit d0355eb4bd778adae86d9e0e3c17ceea29a115bd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 23 20:37:53 2023 -0700
+
+    [buffer-deserialize] Parse whole items at a time
+    
+    Previous logic would fail if char buffer was partial.
+
+ src/hb-buffer-deserialize-json.hh | 362 +++++++++++------------
+ src/hb-buffer-deserialize-json.rl |   2 +-
+ src/hb-buffer-deserialize-text.hh | 586 +++++++++++++++-----------------------
+ src/hb-buffer-deserialize-text.rl |   6 +-
+ 4 files changed, 420 insertions(+), 536 deletions(-)
+
+commit f65b04c17c45587f4500c8af52418b4f0ca39886
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Jan 23 21:57:05 2023 -0500
+
+    Tweak wording
+
+ src/hb-paint.h | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 7e01976bcc573a1cdd40649be3e2d8d68ca0af01
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Jan 23 20:44:22 2023 -0500
+
+    [hb-paint] Add some details to the docs
+
+ src/hb-paint.h | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+commit e4fff64ce31902674a5b8c667c6a7b61e5429381
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Jan 24 00:52:26 2023 +0000
+
+    [repacker] check duplicate() for success.
+    
+    Fixes fuzzer testcase https://oss-fuzz.com/testcase-detail/5475787333828608.
+
+ src/graph/graph.hh                                     |   9 ++++++++-
+ ...tcase-minimized-hb-repacker-fuzzer-5475787333828608 | Bin 0 -> 127193 bytes
+ 2 files changed, 8 insertions(+), 1 deletion(-)
+
+commit 6b72a4ddb05c7226d58d0f156db13153dec4a0e8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 23 18:36:04 2023 -0700
+
+    Revert "[sanitize] Simplify(?) check_range"
+    
+    This reverts commit af0b1ef8a72d4f6b778dbba3606ebe7df39d5288.
+
+ src/hb-sanitize.hh | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+commit 00cf322e237eaf81086130e989b8bf88402b959e
+Merge: af0b1ef8a 699485b34
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 23 16:06:26 2023 -0700
+
+    Merge pull request #4046 from harfbuzz/hb-features-docs
+    
+    [doc] Try to fix generating hb-features docs
+
+commit 699485b349030b1b8fdbb742758718b88bee1212
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Jan 24 00:07:45 2023 +0200
+
+    [meson] Further simplify generating hb-features.h
+
+ src/meson.build | 38 +++++++++++++++++---------------------
+ 1 file changed, 17 insertions(+), 21 deletions(-)
+
+commit 2486d6d22fcbdeb2ec89bb33265665e60dc8461a
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Jan 23 23:57:16 2023 +0200
+
+    [meson] Reduce repetitions
+
+ src/meson.build | 46 +++++++++++++++++++++-------------------------
+ 1 file changed, 21 insertions(+), 25 deletions(-)
+
+commit 12f2ecbddb65328a6e3312921ccb6946a76a665e
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Jan 23 23:41:11 2023 +0200
+
+    [doc] Generate hb-supported-features.h
+    
+    See inline comment.
+
+ docs/meson.build |  1 +
+ src/meson.build  | 19 +++++++++++++++++++
+ 2 files changed, 20 insertions(+)
+
+commit 0bbd3360eeb00fbbb9544524a330e405450f44e5
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Jan 19 20:11:35 2023 +0200
+
+    [doc] Try to fix generating hb-features docs
+    
+    Move it to a separate section, since hb-common says include hb.h, while
+    we want to include hb-features.h here.
+    
+    This still does not fix generating documentation of undefined macros
+    (e.g. HB_HAS_GDI since we build docs on Linux).
+
+ docs/harfbuzz-docs.xml     |  1 +
+ docs/harfbuzz-sections.txt | 24 ++++++++++++++----------
+ src/hb-features.h.in       |  8 ++++++++
+ 3 files changed, 23 insertions(+), 10 deletions(-)
+
+commit af0b1ef8a72d4f6b778dbba3606ebe7df39d5288
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 23 14:31:10 2023 -0700
+
+    [sanitize] Simplify(?) check_range
+
+ src/hb-sanitize.hh | 16 +++-------------
+ 1 file changed, 3 insertions(+), 13 deletions(-)
+
+commit fe94c760e1cc9a5f3824c48accd4d1cfd86ebcb0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 23 14:05:28 2023 -0700
+
+    [algs] Build fix for clang and __builtin_mul_overflow
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4066
+
+ src/hb-algs.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1cf61f3053e2c0a5c4df3623ac08f68834ccf7b4
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Jan 23 13:43:35 2023 +0200
+
+    [meson] Fix build with -Dgobject=disabled
+
+ src/meson.build  | 14 ++++++++------
+ util/meson.build |  2 +-
+ 2 files changed, 9 insertions(+), 7 deletions(-)
+
+commit 2b87af808bb55c0635b16ecc39331b2e6ab7ae6b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 17:37:51 2023 -0700
+
+    [hb-info] Typo
+
+ util/hb-info.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit fe22afe7f9ba4440ddb19dc2b262358555374f07
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 16:47:50 2023 -0700
+
+    [hb-info] Simplify
+
+ util/hb-info.cc | 129 ++++++++++++++++++++++++++------------------------------
+ 1 file changed, 59 insertions(+), 70 deletions(-)
+
+commit eba5762919ab02f5dd9b2b9dd319d106ddaf9de9
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Jan 23 01:10:56 2023 +0200
+
+    Another try
+
+ util/meson.build | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 37ab12a372a74c25b34cae909ac89c79aef8c376
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Jan 23 01:02:51 2023 +0200
+
+    [util] Try to fix hb-info build
+
+ util/meson.build | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 5880ab06030dd7e3f77711319480cd908ca19195
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 16:20:23 2023 -0700
+
+    [hb-info] More build fix try
+
+ util/Makefile.am | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+commit d76ef46d0a25ee8d0093afde3424dc9589bcc6d9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 16:17:39 2023 -0700
+
+    Try to fix autotools build
+
+ util/Makefile.am | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit 6e58598520069ab144f0705c6960fc3109858b5d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 15:22:30 2023 -0700
+
+    [hb-info] Subfamily
+
+ util/hb-info.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4142a460af34cdbca705b5a2309dda03dcd2deb3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 15:11:50 2023 -0700
+
+    [hb-info] Add --list-baselines
+
+ util/hb-info.cc | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 67 insertions(+), 1 deletion(-)
+
+commit 9c62022dedfecf5bc423ff142a8181d6b829595b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 15:02:21 2023 -0700
+
+    [hb-info] Format
+
+ util/hb-info.cc | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+commit 0b7d3952bade88c066fbdde78f461613c89a1eea
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 15:00:10 2023 -0700
+
+    [hb-info] Add --list-style
+
+ util/hb-info.cc | 29 ++++++++++++++++++++++++++++-
+ 1 file changed, 28 insertions(+), 1 deletion(-)
+
+commit 090a6d0dde90bc1ee393e70f7064e13f8fea86fe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 14:56:25 2023 -0700
+
+    [hb-info] Add --get-style
+
+ util/hb-info.cc | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+commit 5b291d49e80f4e2b79e91e046f4858a45eb2f0ad
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 14:51:17 2023 -0700
+
+    [hb-info] Rename style to subfamily
+
+ util/hb-info.cc | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit c300bf00f0c1297516658917f1e001be8259c569
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 14:46:20 2023 -0700
+
+    [hb-info] Move include around
+
+ util/hb-info.cc | 4 ++++
+ util/options.hh | 3 ---
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+commit b839f53cdecee5b0c7fed1bd543753ece9e10e86
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 14:39:26 2023 -0700
+
+    [hb-info] Write fallback metrics in --list-metrics
+
+ util/hb-info.cc | 21 +++++++++++++++++++--
+ 1 file changed, 19 insertions(+), 2 deletions(-)
+
+commit 7ba3d0c419b61ddb07b9f38fb5fa0bb36ecb4fd6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 14:27:31 2023 -0700
+
+    [hb-info] Add --list-metrics
+    
+    Requires hb-gobject
+
+ util/hb-info.cc | 39 ++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 38 insertions(+), 1 deletion(-)
+
+commit 4ec3d2e32ac0ec805518137ef887805377ee4143
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 14:12:44 2023 -0700
+
+    [hb-info List enum nicks in --list-names
+
+ util/hb-info.cc  | 16 ++++++++++++++--
+ util/meson.build |  4 ++--
+ util/options.hh  |  6 ++++++
+ 3 files changed, 22 insertions(+), 4 deletions(-)
+
+commit def94aa8c5575f1bbaa8c3ea07356e78c0af6067
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 14:01:34 2023 -0700
+
+    [features] Add HB_HAS_GOBJECT
+
+ docs/harfbuzz-sections.txt | 1 +
+ src/Makefile.am            | 4 ++++
+ src/hb-features.h.in       | 7 +++++++
+ src/meson.build            | 4 ++++
+ 4 files changed, 16 insertions(+)
+
+commit b3006ba9cbc1fdb8cc2a8c7600b0fc0aa975fd2d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 13:46:35 2023 -0700
+
+    Docs
+
+ docs/harfbuzz-sections.txt | 1 +
+ src/hb-ot-name.h           | 7 +++++++
+ 2 files changed, 8 insertions(+)
+
+commit e3e4d1ecdcd0c07be352e9d19775bbd9a207cbd5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 13:41:43 2023 -0700
+
+    [name] Add hb_ot_name_id_predefined_t
+    
+    Not sure what to do about its docs.
+
+ src/hb-ot-name.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 3feac1a408429c78f1470164976b266d0095d96d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 10:15:14 2023 -0700
+
+    [hb-info] Use tab in --list-palettes
+
+ util/hb-info.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 752ad51cce0c3e6033ed6de6d8257f46129fac06
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 10:07:24 2023 -0700
+
+    [hb-info] Move some initialization to post_parse
+
+ util/hb-info.cc | 19 ++++++++++++-------
+ 1 file changed, 12 insertions(+), 7 deletions(-)
+
+commit 334f59c955088e840004e85cb0c4bd10e4175b41
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 10:06:05 2023 -0700
+
+    [hb-info] If name not found, fall back to English
+
+ util/hb-info.cc | 69 +++++++++++++++++++++++++++++++++++++--------------------
+ 1 file changed, 45 insertions(+), 24 deletions(-)
+
+commit 7cae55359220da8310dc1257b3fd7177359e2235
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 09:33:25 2023 -0700
+
+    [hb-info] Rename --dump-table to --get-table
+
+ util/hb-info.cc | 30 +++++++++++++-----------------
+ 1 file changed, 13 insertions(+), 17 deletions(-)
+
+commit 9b499a48bbcb7a1bc8b95e5c23df2eae29549e02
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 09:27:05 2023 -0700
+
+    [hb-info] Add --get-name
+
+ util/hb-info.cc | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+commit 7a47a369d3a15716fa4d9c5ccd5681c72a155a99
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 09:09:45 2023 -0700
+
+    [hmtx] Fix typo
+
+ src/hb-ot-hmtx-table.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit b9879181254b94a38f9a478d8fcae7daed0dd6c6
+Merge: e4cdaa1d3 89d332559
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 09:08:51 2023 -0700
+
+    Merge pull request #4052 from googlefonts/instancer_recalc_bounds
+    
+    [instancer] recalc bounds by default when --instance option is enabled
+
+commit e4cdaa1d3f7aa9725ba1d2beed4096287a8d59ce
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 08:36:51 2023 -0700
+
+    [test] Fix build
+
+ test/shape/data/in-house/Makefile.sources | 1 -
+ test/shape/data/in-house/meson.build      | 1 -
+ 2 files changed, 2 deletions(-)
+
+commit 9ba1e400d6831d5cd08f104b460f05346234a1d7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 22 08:31:39 2023 -0700
+
+    [test] Remove non-free font and its test
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4059
+
+ .../fonts/641ca9d7808b01cafa9a666c13811c9b56eb9c52.ttf  | Bin 11492 -> 0 bytes
+ test/shape/data/in-house/tests/arabic-mark-attach.tests |   1 -
+ 2 files changed, 1 deletion(-)
+
+commit 749df4ee8449107b39d76df353785a6f96b1cfa0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 21 16:00:54 2023 -0700
+
+    [PairPosFormat1] One more
+
+ src/OT/Layout/GPOS/PairPosFormat1.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b648ceb72f281e739ec8bd73cbc243624854238d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 21 15:58:59 2023 -0700
+
+    [PairSet] Optimize last commit
+
+ src/OT/Layout/GPOS/PairSet.hh | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+commit 891623243c167217fcbd9480b111b110cc004c9c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 21 15:57:18 2023 -0700
+
+    [PairSet] Unify get_size()
+
+ src/OT/Layout/GPOS/PairPosFormat1.hh |  4 +---
+ src/OT/Layout/GPOS/PairSet.hh        | 24 ++++++++++++------------
+ 2 files changed, 13 insertions(+), 15 deletions(-)
+
+commit b63159e8bf579345a6f56d04ad1b2c28eee66bac
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 21 15:50:48 2023 -0700
+
+    [PairPosFormat1] Fix stride
+    
+    Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=55287
+    and generally the lookup with MediumTypes.
+
+ src/OT/Layout/GPOS/PairPosFormat1.hh                     |   4 ++--
+ src/OT/Layout/GPOS/PairPosFormat2.hh                     |   2 +-
+ src/OT/Layout/GPOS/PairSet.hh                            |  13 ++++++-------
+ src/OT/Layout/GPOS/ValueFormat.hh                        |   2 +-
+ ...z-testcase-minimized-hb-shape-fuzzer-5965759719538688 | Bin 0 -> 1154 bytes
+ 5 files changed, 10 insertions(+), 11 deletions(-)
+
+commit be8a87c453473b4ac0d1895f89fdf4e50bcf5e52
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 21 15:00:41 2023 -0700
+
+    Move TRACE_DISPATCH after may_recurse()
+    
+    Such that we don't get memory access issues if DEBUG_SANITIZE is
+    on and may_recurse() returns false.
+
+ src/OT/Color/COLR/COLR.hh                     | 4 ++--
+ src/OT/Layout/GPOS/CursivePos.hh              | 2 +-
+ src/OT/Layout/GPOS/MarkBasePos.hh             | 2 +-
+ src/OT/Layout/GPOS/MarkLigPos.hh              | 2 +-
+ src/OT/Layout/GPOS/MarkMarkPos.hh             | 2 +-
+ src/OT/Layout/GPOS/PairPos.hh                 | 2 +-
+ src/OT/Layout/GPOS/SinglePos.hh               | 2 +-
+ src/OT/Layout/GSUB/AlternateSubst.hh          | 2 +-
+ src/OT/Layout/GSUB/LigatureSubst.hh           | 2 +-
+ src/OT/Layout/GSUB/MultipleSubst.hh           | 2 +-
+ src/OT/Layout/GSUB/ReverseChainSingleSubst.hh | 2 +-
+ src/OT/Layout/GSUB/SingleSubst.hh             | 2 +-
+ src/hb-ot-layout-common.hh                    | 2 +-
+ src/hb-ot-layout-gdef-table.hh                | 2 +-
+ src/hb-ot-layout-gsubgpos.hh                  | 8 ++++----
+ src/hb-ot-stat-table.hh                       | 2 +-
+ 16 files changed, 20 insertions(+), 20 deletions(-)
+
+commit 84b9a632ed6d9cf0a5eb00722c6409025cb839a6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 21 14:36:26 2023 -0700
+
+    [debug] Fix printf signness warnings
+
+ src/hb-debug.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit c54a7022feeb42aa89c0e9aeb80fd3c959d02c97
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 21 14:07:41 2023 -0700
+
+    [hb-view] Require cairo 1.17.5 for HB_DRAW=1 default again
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4051
+
+ util/helper-cairo.hh | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+commit 67e652cd5d875f2c78ee97885039c180cacab39d
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Jan 21 15:57:13 2023 +0200
+
+    [meson] Update Cairo subproject
+
+ meson.build            | 1 +
+ subprojects/cairo.wrap | 2 +-
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+commit ed68db2c010a14c0613becd1685586836d4099aa
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Jan 21 03:54:57 2023 +0200
+
+    [util] Fix MSVC warning
+    
+    Apparently \e is non-standard extension not supported by MSVC. Use \033
+    instead.
+    
+    Fixes:
+    
+    warning C4129: 'e': unrecognized character escape sequence
+
+ util/ansi-print.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit c08e5d094a3bd7e6c3b9d6475a30aa8883429a89
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Jan 21 03:40:09 2023 +0200
+
+    [hb-draw] Fix MSVC warning
+    
+    warning C4305: 'initializing': truncation from 'double' to 'float'
+
+ src/hb-cairo-utils.cc | 4 ++--
+ test/api/test-paint.c | 6 +++---
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+commit e1a0705128c2e6fd068374c47c13220ede9ee5a2
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Jan 21 03:16:20 2023 +0200
+
+    [meson] Enabled needlessly disabled MSVC warnings
+    
+    We don’t seem to hot any of these warnings currently.
+
+ meson.build | 3 ---
+ 1 file changed, 3 deletions(-)
+
+commit f96e32a0aad4092f3f551ed390f3e3b884a8e4fe
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Jan 21 00:39:00 2023 +0200
+
+    [meson] Try to make MSVC build less spammy
+    
+    Enable exceptions in ragel subproject, and revert the exceptions part of:
+    
+    commit 22cbd038d3578c344e265a098fc98ef168f8d18b
+    Author: Khaled Hosny <khaled@aliftype.com>
+    Date:   Tue Sep 14 12:34:25 2021 +0200
+    
+        [meson] Add ragel subproject
+    
+    To get ride of the following warnings:
+    
+    cl : Command line warning D9025 : overriding '/EHs' with '/EHs-'
+
+ meson.build                                |  5 ++---
+ subprojects/packagefiles/ragel/meson.build | 10 +++++++++-
+ 2 files changed, 11 insertions(+), 4 deletions(-)
+
+commit 32f9b467d6265498dc4d8023bc4b6dc947896576
+Merge: 179c93c5c 7f59bed52
+Author: Matthias Clasen <matthias.clasen@gmail.com>
+Date:   Sat Jan 21 02:20:39 2023 -0500
+
+    Merge pull request #4045 from harfbuzz/custom-palette-cairo
+    
+    Custom palette cairo
+
+commit 179c93c5c21dc7dda7840d2bfc1ef27bcebdad71
+Merge: 54d5321d1 c574eda74
+Author: Matthias Clasen <matthias.clasen@gmail.com>
+Date:   Sat Jan 21 02:20:00 2023 -0500
+
+    Merge pull request #4054 from harfbuzz/hb-info-color-format
+    
+    [hb-info] Fix output for CPAL
+
+commit 54d5321d136ebd4be799d8c3dcf4e433b1c3778f
+Merge: fcb5111cc 47baa1da6
+Author: Matthias Clasen <matthias.clasen@gmail.com>
+Date:   Sat Jan 21 02:19:43 2023 -0500
+
+    Merge pull request #4056 from harfbuzz/fix-sweep-gradient-hang
+    
+    [hb-cairo] Fixes for sweep gradients
+
+commit 47baa1da6bbf386d7be73ca4a79d2c819ca2a3c9
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Jan 20 23:38:22 2023 -0500
+
+    [hb-cairo] Fixes for sweep gradients
+    
+    Make reversed angles not infloop, and
+    cap the number of interval repetitions
+    at 1000.
+    
+    Fixes: https://github.com/harfbuzz/harfbuzz/issues/4055
+
+ src/hb-cairo-utils.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit c574eda74b027b514665c978d32cef0aa284bee5
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Jan 20 22:06:47 2023 -0500
+
+    [hb-info] Fix output for CPAL
+    
+    The output for palette names was mangled.
+    This commit makes things come out ok.
+    
+    For flags, we use "Both" when both LIGHT
+    and DARK are set.
+
+ util/hb-info.cc | 19 +++++++++++++------
+ 1 file changed, 13 insertions(+), 6 deletions(-)
+
+commit 7f59bed528e75e5336ace1d9cdbee20932e3e211
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 16:42:55 2023 -0700
+
+    [hb-cairo] Round foreground color
+
+ src/hb-cairo.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 76b059cadb805df3df860be6a130ab5480cb8846
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 16:41:47 2023 -0700
+
+    [hb-cairo] Simplify foreground color fetching
+
+ src/hb-cairo.cc | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+commit f70f7194de5f24625d12d40cf639a7a0e7ef48b9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 16:30:59 2023 -0700
+
+    [hb-cairo] Remove unused prototype
+
+ src/hb-cairo.cc | 6 ------
+ 1 file changed, 6 deletions(-)
+
+commit 61719a835089ea2c2cda36702f630c9343b029c7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 15:52:09 2023 -0700
+
+    [hb-view] Support specifying color indices again
+
+ src/hb-number.cc     |  1 -
+ util/helper-cairo.hh | 16 ++++++++++++++--
+ 2 files changed, 14 insertions(+), 3 deletions(-)
+
+commit 89d332559ee4d5349315b35e64b34c27116ba441
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Jan 20 14:15:19 2023 -0800
+
+    [instancer] add tests
+
+ ...fault.retain-all-codepoint.wght=150,wdth=80.ttf | Bin 114200 -> 114200 bytes
+ ...fault.retain-all-codepoint.wght=300,wdth=90.ttf | Bin 114300 -> 114300 bytes
+ ...anges.retain-all-codepoint.wght=150,wdth=80.ttf | Bin 114200 -> 114200 bytes
+ ...anges.retain-all-codepoint.wght=300,wdth=90.ttf | Bin 114300 -> 114300 bytes
+ .../MPLUS1-Variable.default.30DD.wght=100.ttf      | Bin 1460 -> 1460 bytes
+ .../MPLUS1-Variable.default.30DD.wght=400.ttf      | Bin 1712 -> 1712 bytes
+ ...fault.retain-all-codepoint.wght=200,wdth=90.ttf | Bin 6760 -> 6760 bytes
+ ...fault.retain-all-codepoint.wght=650,wdth=85.ttf | Bin 6712 -> 6712 bytes
+ ...fault.retain-all-codepoint.wght=200,wdth=90.ttf | Bin 6440 -> 6440 bytes
+ ...fault.retain-all-codepoint.wght=650,wdth=85.ttf | Bin 6392 -> 6392 bytes
+ ...etain-all-codepoint.wght=150,wdth=80,CTGR=0.ttf | Bin 1396 -> 1396 bytes
+ ...etain-all-codepoint.wght=300,wdth=90,CTGR=0.ttf | Bin 1432 -> 1432 bytes
+ ...lt.retain-all-codepoint.wght=400,wdth=100.0.ttf | Bin 6804 -> 6804 bytes
+ ...ult.retain-all-codepoint.wght=drop,wdth=100.ttf | Bin 6804 -> 6804 bytes
+ test/subset/generate-expected-outputs.py           |   3 ++-
+ 15 files changed, 2 insertions(+), 1 deletion(-)
+
+commit 30058f489a43c39b7bd9278c1e04baf1952bba48
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Jan 18 15:23:24 2023 -0800
+
+    [instancer] trim .notdef outline data after recalc bounds
+    
+    If outline data present, we use it to recalc bounds and then trim it
+    accordingly
+
+ src/OT/glyf/Glyph.hh | 4 ++++
+ src/OT/glyf/glyf.hh  | 2 +-
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+commit 0de7f83a9fe2054ad2d63c3f8e08dc61e1397c62
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Jan 18 13:33:34 2023 -0800
+
+    [instancer] update maxp table
+
+ src/hb-ot-maxp-table.hh | 13 +++++++++++++
+ src/hb-subset.cc        |  1 +
+ 2 files changed, 14 insertions(+)
+
+commit 94c390d07835727c201bfdbe0b4d208dc3fe3fc2
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Jan 18 10:15:47 2023 -0800
+
+    [instancer] update head table
+
+ src/OT/glyf/glyf-helpers.hh | 7 +++++++
+ src/hb-ot-head-table.hh     | 2 ++
+ src/hb-subset.cc            | 2 +-
+ 3 files changed, 10 insertions(+), 1 deletion(-)
+
+commit 2ecb1c31e90657a5a264f4b84907bad6f07673c1
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Jan 18 09:52:00 2023 -0800
+
+    [instancer] always recalculate bounds when --instance option enabled
+    
+    But don't recompile glyph bytes if pinned at default
+
+ src/OT/glyf/Glyph.hh | 48 ++++++++++++++++++++++++++----------------------
+ src/OT/glyf/glyf.hh  |  5 +++--
+ 2 files changed, 29 insertions(+), 24 deletions(-)
+
+commit 1f948e7fd55ff6a65aa3a6b038284db3d211493e
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Jan 17 15:16:17 2023 -0800
+
+    [instancer] store recalculated head/maxp info in subset plan
+
+ src/OT/glyf/Glyph.hh  | 50 ++++++++++++++++++++++++++++++++++++++++++++------
+ src/OT/glyf/glyf.hh   |  2 +-
+ src/hb-subset-plan.hh | 27 +++++++++++++++++++++++++++
+ 3 files changed, 72 insertions(+), 7 deletions(-)
+
+commit 92122421c951f6f126eff902f917b403bdf027a5
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Jan 13 11:42:58 2023 -0800
+
+    [instancer] update vhea/hhea tables
+
+ src/OT/glyf/Glyph.hh    | 11 +++++++++--
+ src/hb-ot-hmtx-table.hh | 43 +++++++++++++++++++++++++++++++++++++------
+ src/hb-subset-plan.hh   |  4 ++++
+ 3 files changed, 50 insertions(+), 8 deletions(-)
+
+commit ab7c91442536086f0baebe2d419827bb9e4cce06
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 15:43:01 2023 -0700
+
+    [hb-cairo] Macro shuffle again
+
+ src/hb-cairo.cc | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 4759932bcfb5af5f576868cc96dfe2755361fe9d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 15:33:38 2023 -0700
+
+    [hb-cairo] Round colors
+
+ src/hb-cairo.cc | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit 876675e090e2b55fdb5f3e8b187022184145b2f3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 15:31:43 2023 -0700
+
+    [hb-cairo] Macro shuffling
+
+ src/hb-cairo.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 68a73e436a37851465b1b8b59e3b7a2c552d28f2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 15:30:07 2023 -0700
+
+    [hb-cairo] Macro hygiene
+
+ src/hb-cairo.cc | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+commit fcb5111cc6db8e310d62e27d93980a0f67ee936a
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Jan 21 00:24:50 2023 +0200
+
+    [doc] Fix gtk-doc warning
+
+ src/hb-cairo.cc | 6 +++---
+ src/hb-face.cc  | 2 +-
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit 574d9344dccdd7c79a02070dac48bf825c8095de
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 15:22:50 2023 -0700
+
+    [hb-cairo] Fix build with old cairo
+
+ src/hb-cairo.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 4f19c3b3be07b75235684b969677725fe50494f3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 15:15:52 2023 -0700
+
+    [hb-cairo] Move color-cache to scaled-font
+
+ src/hb-cairo.cc | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+commit beba43eebe235dac402a66ffd58fa29a9689fe15
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 15:02:24 2023 -0700
+
+    [hb-cairo] Fix color cache on not-found
+
+ src/hb-cairo.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit cc9b55c79469b93583f21f8a45cd3cb0759aa789
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 14:57:57 2023 -0700
+
+    [hb-cairo] Add a color cache
+
+ src/hb-cairo.cc | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+commit 10def9b3df1241eec912b94ba82d43cd8f93caa4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 14:06:18 2023 -0700
+
+    meson fix
+
+ meson.build | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit eb00088bcfea640d2d1d591d08cdcdd01d5acf91
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 13:55:13 2023 -0700
+
+    [paint] Docs
+
+ docs/harfbuzz-sections.txt | 2 --
+ src/hb-paint.cc            | 3 ++-
+ src/hb-paint.h             | 4 +++-
+ 3 files changed, 5 insertions(+), 4 deletions(-)
+
+commit f21b15dcc318aa62d256443be3ccec7953a64242
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 13:38:22 2023 -0700
+
+    [hb-view] Update to alternative cairo custom-palette API
+
+ meson.build          | 1 +
+ src/hb-cairo.cc      | 5 +++--
+ util/helper-cairo.hh | 2 +-
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+
+commit 638e0ed4fdd06a6215f2d7c74786b6436074d564
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 13:01:22 2023 -0700
+
+    [paint] Overlay custom-palette on top of chosen palette
+    
+    Got to agree this is more ergonomic.
+
+ src/OT/Color/COLR/COLR.hh |  4 +---
+ src/hb-cairo.cc           |  8 +++++---
+ src/hb-font.cc            |  3 +--
+ src/hb-ft-colr.hh         |  7 +++----
+ src/hb-paint.cc           | 12 +++++++-----
+ src/hb-paint.h            | 25 ++++++++-----------------
+ src/hb-paint.hh           |  6 ++++--
+ util/helper-cairo.hh      | 10 ++++------
+ 8 files changed, 33 insertions(+), 42 deletions(-)
+
+commit 03e2e586423ada331ae433db7dea705a8b6ad3fe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 11:24:35 2023 -0700
+
+    [hb-view] Improve color parsing
+    
+    Now supports 3, 4, 6, 8 digit colors.
+
+ util/helper-cairo.hh | 13 +++++++------
+ util/options.hh      | 40 ++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 47 insertions(+), 6 deletions(-)
+
+commit dc4af478d14ca5d0270e317a87d60dfba111381d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 11:11:02 2023 -0700
+
+    [hb-view] Default background to white when parsing
+
+ util/helper-cairo.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b81db8d3d82af7a369a2b26ec35dcec81060a965
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Jan 19 08:19:04 2023 -0500
+
+    Avoid a compiler warning
+
+ src/hb-cairo.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e998cec1d94f32ac44ff0dca42941b28a4fdd546
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 23:33:21 2023 -0700
+
+    [hb-view] Move palette options to --help-view
+
+ util/font-options.hh | 5 -----
+ util/helper-cairo.hh | 9 +++++----
+ util/view-cairo.hh   | 3 ++-
+ util/view-options.hh | 5 +++++
+ 4 files changed, 12 insertions(+), 10 deletions(-)
+
+commit 253b4cecae0729330ec04fab93972db86ee1b203
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 23:28:25 2023 -0700
+
+    [hb-view] Simplify palette format
+
+ util/font-options.hh | 2 +-
+ util/helper-cairo.hh | 6 +++---
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit 52b78d526b522f95897bfcb4d9652ea328fbdb6a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 23:06:08 2023 -0700
+
+    [hb-view] Fix leak
+
+ util/helper-cairo.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 5847ec24ff65d7f7c59d105b2cca86ac235ac7eb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 22:37:54 2023 -0700
+
+    Fix bots
+
+ util/helper-cairo.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4fe6ece425c19e8fd63e346179de5bd14415d732
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 22:33:56 2023 -0700
+
+    [cairo] Don't fallback to CPAL if cairo doesn't support custom palette
+
+ src/hb-cairo.cc | 11 +----------
+ 1 file changed, 1 insertion(+), 10 deletions(-)
+
+commit 0bff5704912fb99789ca7e09d3fafb640c2ccfed
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 22:33:32 2023 -0700
+
+    [hb-view] Use custom palette if any set
+
+ util/helper-cairo.hh | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+commit c41892a01229404d4d0c31b8056fd7b72ac3a58a
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Jan 18 23:45:53 2023 -0500
+
+    hb-view: Add a --custom-palette option
+
+ util/font-options.hh |  3 +++
+ util/helper-cairo.hh | 12 ++++++++++++
+ 2 files changed, 15 insertions(+)
+
+commit ab37ade7e46ac00152113c275dd8cd7fc9d1a11c
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Jan 18 23:29:37 2023 -0500
+
+    Hook up custom palettes for cairo
+
+ src/hb-cairo.cc | 36 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+commit cce7c441eb0bd097f63016aa7e5962aa6615951b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 13:57:05 2023 -0700
+
+    [name] Fix doc
+    
+    That's part of an enum now.
+
+ docs/harfbuzz-sections.txt | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 3711455154373d0400bad77221cb02a785882623
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 12:32:41 2023 -0700
+
+    [hb-info] Minor set parse hooks
+    
+    Unused.
+
+ util/hb-info.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 89371419a91f88ae503dbbb99fb9ebbb5c1239ab
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 12:20:38 2023 -0700
+
+    [hb-info] Move code around
+
+ util/hb-info.cc | 28 ++++++++++++++--------------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+commit 32b42eb5687bf0bc4fd27545e19753066620af60
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 12:18:04 2023 -0700
+
+    [hb-info] Add --show-face-count
+
+ util/hb-info.cc | 16 +++++++++++++++-
+ 1 file changed, 15 insertions(+), 1 deletion(-)
+
+commit fd84605b5898e6cb9738c4d821e2893edd0a2cf6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 12:10:03 2023 -0700
+
+    [hb-info] Add --show-technology
+
+ util/hb-info.cc | 44 ++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 44 insertions(+)
+
+commit c05230256d52e8c62135e8133cd2a6b75296e54a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 12:08:31 2023 -0700
+
+    [util] Add -y for --face-index
+    
+    Ala ttx.
+
+ util/face-options.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 6bf9237e5f467073021483cd06251955ef28c84f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 11:54:08 2023 -0700
+
+    [hb-info] Format --list-palettes
+
+ util/hb-info.cc | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit 64625ed85d27102fcd4b499e007b88229c4b0221
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 11:48:01 2023 -0700
+
+    [hb-info] Write palette flags
+
+ util/hb-info.cc | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+commit d811dcdbde935cd8ec897d84332a572b76e772a3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 11:42:51 2023 -0700
+
+    [hb-info] Add --list-palettes
+
+ util/hb-info.cc | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 58 insertions(+), 1 deletion(-)
+
+commit 2590578162692e24afe4a333f9c6b1c9423d6937
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 11:04:22 2023 -0700
+
+    [hb-info] Add --get-baseline
+
+ util/hb-info.cc | 50 +++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 49 insertions(+), 1 deletion(-)
+
+commit b77baa31c36d4b8375ebb3fe97a7bbe36b71b463
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 10:13:21 2023 -0700
+
+    [hb-info] Show whether --get-metric value is fallback
+
+ util/hb-info.cc | 26 +++++++++++++++++++-------
+ 1 file changed, 19 insertions(+), 7 deletions(-)
+
+commit 2a8df82aca15df45c5abfd6d8e18e294a8d6dadf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 09:57:28 2023 -0700
+
+    [hb-info] Add --get-metric
+
+ util/hb-info.cc | 31 ++++++++++++++++++++++++++-----
+ 1 file changed, 26 insertions(+), 5 deletions(-)
+
+commit ba4f5e9f220b7e33c5ea0438c824a99f433f41d9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 09:29:39 2023 -0700
+
+    [hb-info] Add --ot-script and --ot-language
+
+ util/hb-info.cc | 46 ++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 40 insertions(+), 6 deletions(-)
+
+commit edec8946ed376c2888f9444b038b80dad57c162e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 09:28:59 2023 -0700
+
+    New API: hb_ot_layout_script_select_language2()
+    
+    Variant that outputs chosen_language.
+    
+    Not sure why the original API didn't have this. The script
+    counterpart has.
+
+ docs/harfbuzz-sections.txt |  1 +
+ src/hb-ot-layout.cc        | 66 +++++++++++++++++++++++++++++++++++++++-------
+ src/hb-ot-layout.h         |  9 +++++++
+ 3 files changed, 66 insertions(+), 10 deletions(-)
+
+commit 2fd8e36ea5891f462f4bff8b6657c4421943a4f8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 09:09:14 2023 -0700
+
+    [layout] Fix return value of chosen_script when matching fails
+
+ src/hb-ot-layout.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d06976e68fd475eb12fcec538b207354ddcffd92
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 08:21:43 2023 -0700
+
+    [glyf] Add an edge-count limit
+    
+    Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=55246
+
+ src/OT/glyf/Glyph.hh | 13 ++++++++++---
+ src/hb-limits.hh     |  4 ++++
+ 2 files changed, 14 insertions(+), 3 deletions(-)
+
+commit 2cfd4133fb7e42237fbe47f09e448285fdbd1975
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 20 07:11:16 2023 -0700
+
+    [hb-info] Print Zyyy for DFLT script
+
+ util/hb-info.cc | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit 178c5bed39c66595ca4198c2e377fd5bee719351
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Jan 20 00:42:29 2023 +0200
+
+    [ci] Use unique ccache cache keys per job
+
+ .github/workflows/linux-ci.yml | 2 ++
+ .github/workflows/macos-ci.yml | 2 ++
+ 2 files changed, 4 insertions(+)
+
+commit a0afde70c53a6e7b64dbbc932236a8d9b124b9e6
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Jan 19 22:55:11 2023 +0200
+
+    [ci] Re-enable coverage reporting on macOS
+
+ .github/workflows/macos-ci.yml | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+commit 8785d515d073679fa15db97ed01f2f6525ae6566
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Jan 19 22:43:16 2023 +0200
+
+    [ci] Don’t install glib-utils on macOS
+    
+    Homebrew can’t make up their mind, they seem to have merged the glib
+    packages again.
+
+ .github/workflows/macos-ci.yml | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 5ddb5fb847c741201bca382780e4cde9d627f2bb
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Jan 19 22:41:49 2023 +0200
+
+    [ci] Don’t install gtk-doc on macOS
+    
+    We are not building the documentation here.
+
+ .github/workflows/macos-ci.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 48df846a413a3734a18bfe13e661e41a1bafed88
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Jan 19 22:38:36 2023 +0200
+
+    [ci] Make homebrew do less work
+
+ .github/workflows/macos-ci.yml | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 35f0184bfd260f08eab869a7911453c8e612a122
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Jan 17 20:48:11 2023 +0200
+
+    [ci] Clean a bit and add some consistency
+
+ .github/workflows/linux-ci.yml | 70 ++++++++++++++++++++-----------------
+ .github/workflows/macos-ci.yml | 39 ++++++++++++++++-----
+ .github/workflows/msvc-ci.yml  | 64 +++++++++++++++++-----------------
+ .github/workflows/msys2-ci.yml | 79 +++++++++++++++++++++---------------------
+ 4 files changed, 141 insertions(+), 111 deletions(-)
+
+commit edd5a37e791569ed1df9291d95e6c8ee0839987e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 18:39:32 2023 -0700
+
+    [hb-info] Implement script/language-sensitive --list-features
+    
+    I'm not very confident in the implementation.
+
+ util/hb-info.cc | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 97 insertions(+), 9 deletions(-)
+
+commit a67b6aad925e31aace8d81647ce341e448af22b5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 18:07:05 2023 -0700
+
+    [hb-info] Format
+
+ util/hb-info.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4927e215a4065045d64786fd0cf74be38656b708
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 18:03:31 2023 -0700
+
+    [hb-info] Format
+
+ util/hb-info.cc | 18 +++++++++++++-----
+ 1 file changed, 13 insertions(+), 5 deletions(-)
+
+commit 9ca320d69ee99025977d76a4228bc4e786ade6e9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 17:54:46 2023 -0700
+
+    [hb-info] Format
+
+ util/hb-info.cc | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit b24c7add808bae277bd2b3246d7efdb72f7387ad
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 17:53:07 2023 -0700
+
+    [hb-info] Write ISO/BCP script/language in --scripts
+
+ util/hb-info.cc | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+commit b8dacd46f5558b4d6313392a536309ddd49bfbeb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 17:46:24 2023 -0700
+
+    [hb-info] Format
+
+ util/hb-info.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b9a2917c2ea4b81bcbf7510c054369a8edbc170b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 17:34:10 2023 -0700
+
+    [hb-info] Simplify direction/script/language handling
+
+ util/hb-info.cc | 30 ++++++++++--------------------
+ 1 file changed, 10 insertions(+), 20 deletions(-)
+
+commit e6544148b590c2d846eee608b39501de6826a9a0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 17:28:41 2023 -0700
+
+    [hb-info] Enlarge name buffer
+
+ util/hb-info.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit d759918d181b1e8b53ae618dc476506a49b913e1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 17:26:00 2023 -0700
+
+    [hb-info] TODO
+
+ util/hb-info.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 4baf0ada694602f63a6fd34bafc5a75f74872ad4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 17:24:05 2023 -0700
+
+    [hb-info] Add --direction, --script, --language
+
+ util/hb-info.cc | 46 +++++++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 39 insertions(+), 7 deletions(-)
+
+commit 66692c82e925b2ca8d9e6fc567b1f0abbc32d331
+Merge: f43ba351e e52a23c5f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 16:26:15 2023 -0700
+
+    Merge pull request #4048 from harfbuzz/hb-info
+    
+    hb-info
+
+commit e52a23c5f8d25441bf164b4e63b28aae8082acfb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 16:01:29 2023 -0700
+
+    [hb-info] Add --show-extents
+
+ util/hb-info.cc | 29 +++++++++++++++++++++++++----
+ 1 file changed, 25 insertions(+), 4 deletions(-)
+
+commit 1302a88b25f38dfb0cf463ed0cbb3bb21811f590
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 15:51:46 2023 -0700
+
+    [hb-info] Add --dump-table
+
+ util/hb-info.cc | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+commit 148ee3e0c73dd9c00988ad46b01fcd18ef5f5cc4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 15:41:13 2023 -0700
+
+    [hb-info] Make --show-style and --show-postscript-name show named-instance
+
+ util/hb-info.cc | 23 +++++++++++++++++++++--
+ 1 file changed, 21 insertions(+), 2 deletions(-)
+
+commit 2a3903b37fbfdf49e56ba6a343f98b4f60a0196e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 15:34:14 2023 -0700
+
+    [hb-info] TODO items
+
+ util/hb-info.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 5540367ee2e0be55b782bb6ff33df48613c4d904
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 15:30:27 2023 -0700
+
+    [hb-info] Add --show-version
+
+ util/hb-info.cc | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit 3c734f4479068c0b9a6a768ff55d9ecd0d73d6f7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 15:27:13 2023 -0700
+
+    [hb-info] Add --show-postscript-name
+
+ util/hb-info.cc | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit 895d3f9e3e146e0f185000962f0897c1fc693dac
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 15:24:32 2023 -0700
+
+    [hb-info] Mark --show-all as default
+
+ util/hb-info.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit dec320a4630a1d71f94d6e81ea95b5c855dfe01a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 15:18:06 2023 -0700
+
+    [hb-info] Put back -l for --list-tables
+
+ util/hb-info.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9395bbaa6710ad3b7c8415340d068c467cc31f8f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 15:17:33 2023 -0700
+
+    [hb-info] Format
+
+ util/hb-info.cc | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit d7cf69ede2fe9ad7f1eb9559a4f8638b11c550f2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 15:15:56 2023 -0700
+
+    [hb-info] Format
+
+ util/hb-info.cc | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit 7af0624bdf9d2c8d712eacb5dd46787deeb5cfd6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 15:11:55 2023 -0700
+
+    [hb-info] Remove unintended short option
+
+ util/hb-info.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 21151401219a4f6b4a907f14b783bc61d397136f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 15:10:00 2023 -0700
+
+    [hb-info] Add --show-unique-name and --show-full-name
+
+ util/hb-info.cc | 22 ++++++++++++----------
+ 1 file changed, 12 insertions(+), 10 deletions(-)
+
+commit 2d9ba17a535d2c466dce1f09064dfba73a92e387
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 15:06:21 2023 -0700
+
+    [hb-info] Add --show-style
+
+ util/hb-info.cc | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+commit fecb2eeca0120e4cf9d06f3164e38d4daa983bd0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 15:05:00 2023 -0700
+
+    [hb-info] Add --show-family
+
+ util/hb-info.cc | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+commit f25c03162b2b6132199712bdd165faee0075b2f6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 14:57:45 2023 -0700
+
+    [hb-info] Change separator to ===
+
+ util/hb-info.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 5b05edd221d85b9d6c83dfc2d8e0aa32781b8b1f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 14:57:30 2023 -0700
+
+    [hb-info] Add --list-names
+
+ util/hb-info.cc | 31 ++++++++++++++++++++++++++++++-
+ 1 file changed, 30 insertions(+), 1 deletion(-)
+
+commit 67c9845301a317dae5a33ba0de003ec060427ee4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 14:45:04 2023 -0700
+
+    [hb-info] Make -l list tables ala ttx
+
+ util/hb-info.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 972e3b76da8330faec20883f978c40d701908d98
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 14:42:18 2023 -0700
+
+    [hb-info] Minor formatting
+
+ util/hb-info.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c1679e02662d1589dfcdc8802a8ae7889807405b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 14:41:13 2023 -0700
+
+    [hb-info] Default to --show-all
+
+ util/hb-info.cc | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 1eca2c88a29c2a29c6f7687c79f567598ecae869
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 14:38:12 2023 -0700
+
+    [hb-info] Add a few short option forms
+
+ util/hb-info.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit e5a07c883c90ad8c0108c967f664e7468b4ca14a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 14:34:32 2023 -0700
+
+    [hb-info] --help format
+
+ util/hb-info.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b215f6a84f38725a628248ea25cbb88e57f2c464
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 14:31:45 2023 -0700
+
+    [hb-info] Add --show-unicode-count
+
+ util/hb-info.cc | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+commit 3189b614b1d3ac3343c17b1b67acadb8d4f4e6e1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 14:24:26 2023 -0700
+
+    [hb-info] Format
+
+ util/hb-info.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit fd20a7e143e2e2dfa4c13ab255570200510cd508
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 14:23:36 2023 -0700
+
+    [hb-info] Add --show-glyph-count
+
+ util/hb-info.cc | 22 ++++++++++++++++++----
+ 1 file changed, 18 insertions(+), 4 deletions(-)
+
+commit 38c71cebd070ee0e1e25836ab1fb485bebfd066e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 14:19:05 2023 -0700
+
+    [hb-info] Add --show-upem --show-all --all
+
+ util/hb-info.cc | 38 +++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 37 insertions(+), 1 deletion(-)
+
+commit aee7454d05256b206a4aa5892d9ca6211c7d3189
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 14:09:45 2023 -0700
+
+    [hb-info] Add --list-scripts
+
+ util/hb-info.cc | 31 +++++++++++++++++++++++++++----
+ 1 file changed, 27 insertions(+), 4 deletions(-)
+
+commit 9ca2f86fe0807c7abf8e967130734be76a25f52d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 14:04:37 2023 -0700
+
+    [hb-info] Minor verbose print
+
+ util/hb-info.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9a94c06052e6dd6e752aaac7ce5924f205b73072
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 13:56:36 2023 -0700
+
+    [hb-info] Minor we have face available
+
+ util/hb-info.cc | 4 ----
+ 1 file changed, 4 deletions(-)
+
+commit 8921f593f953947760ab97bd844b20b0c9edc1be
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 13:49:22 2023 -0700
+
+    [hb-info] Print "---" separator
+
+ util/hb-info.cc | 38 +++++++++++++++++++++++++++-----------
+ 1 file changed, 27 insertions(+), 11 deletions(-)
+
+commit f514f697246bd9a19429c5e42038532b48bbab4f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 13:35:15 2023 -0700
+
+    [hb-info] Add --quiet
+
+ util/hb-info.cc | 60 +++++++++++++++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 52 insertions(+), 8 deletions(-)
+
+commit dc717ced8d378aa455a3ca749b8b932bf2b53b97
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 13:16:34 2023 -0700
+
+    [hb-info] Simplify
+
+ util/hb-info.cc | 42 ++++++++++++++++++++++++++----------------
+ 1 file changed, 26 insertions(+), 16 deletions(-)
+
+commit 1816d3664d52b94547a6f0882173a8d5d7f93d19
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 12:59:26 2023 -0700
+
+    [hb-info] Flesh out
+
+ util/face-options.hh |  29 -----
+ util/font-options.hh | 281 ---------------------------------------------
+ util/hb-info.cc      | 318 ++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 3 files changed, 316 insertions(+), 312 deletions(-)
+
+commit ca903f7531f71a81c06a4e9fc4f7166af3f04968
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 12:40:27 2023 -0700
+
+    [hb-info] Start adding
+
+ util/Makefile.am      |   3 ++
+ util/Makefile.sources |   8 ++++
+ util/hb-info.cc       | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ util/meson.build      |  13 ++++++
+ 4 files changed, 132 insertions(+)
+
+commit f43ba351e87e6abc084c4c67ab0cdb093689d415
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 12:17:30 2023 -0700
+
+    [util] Limit chafa to one thread
+
+ util/helper-cairo-ansi.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 2b010d8017c18375d16e897eee22a092f65d80c4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 12:14:50 2023 -0700
+
+    [util] Minor hide --font-ptem sometimes
+
+ util/font-options.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 06c064a351bca485cc7d1245b57835b413459e32
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 19 11:17:49 2023 -0700
+
+    [util] Use hb_font_glyph_to_string
+
+ util/font-options.hh | 15 ++++++---------
+ 1 file changed, 6 insertions(+), 9 deletions(-)
+
+commit 0c7d386748e7cf0bfb09598f82b84b8927d78190
+Merge: ea291493d 0b32cf902
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 21:50:10 2023 -0700
+
+    Merge pull request #4044 from harfbuzz/custom-palette
+    
+    Custom palette
+
+commit 0b32cf902322a38b067ef7748380d91430dd4151
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 21:16:38 2023 -0700
+
+    [COLR] Rename a variable
+
+ src/OT/Color/COLR/COLR.hh | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+commit 1d58c8fb0ec78ee92e3274e9cb07d56c1f5b342f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 21:14:24 2023 -0700
+
+    [paint] Typo
+
+ src/hb-paint.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 7aca3b509039b3a522cfd03e3aaaca9fe7017dba
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 20:49:06 2023 -0700
+
+    [COLRv1] Hook up custom palette colors
+
+ src/OT/Color/COLR/COLR.hh | 12 +++++++++---
+ src/hb-ft-colr.hh         | 50 +++++++++++++++++++++++++++++++++++------------
+ 2 files changed, 46 insertions(+), 16 deletions(-)
+
+commit d695cc87353f59f1647351e2194d513b42ae55ce
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 20:45:19 2023 -0700
+
+    [paint] Docs
+
+ docs/harfbuzz-sections.txt | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit 53bd9039e77d822d2d258dc5b056509cb758ad24
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 20:44:05 2023 -0700
+
+    [paint] Doc
+
+ src/hb-font.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 8afd3ccb106196c230741417d8364722df7f6e32
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 20:43:10 2023 -0700
+
+    [paint] Add HB_PAINT_PALETTE_INDEX_CUSTOM
+
+ src/hb-font.cc |  3 ++-
+ src/hb-paint.h | 12 ++++++++++++
+ 2 files changed, 14 insertions(+), 1 deletion(-)
+
+commit 9a2f2b593eca24fc5e4a412d7ab2d776d28953e1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 20:39:36 2023 -0700
+
+    [font] Rename palette to palette_index
+
+ src/hb-font.cc | 8 ++++----
+ src/hb-font.h  | 6 +++---
+ 2 files changed, 7 insertions(+), 7 deletions(-)
+
+commit bd733146168bce4cb0ea6dd6dc314d5366d85f0a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 20:37:21 2023 -0700
+
+    [paint] Add API for custom palettes
+
+ src/hb-paint.cc | 23 +++++++++++++++++++++++
+ src/hb-paint.h  | 39 +++++++++++++++++++++++++++++++++++++++
+ src/hb-paint.hh |  6 ++++++
+ 3 files changed, 68 insertions(+)
+
+commit ea291493d2d52480accfb2402946b19ef00ce74b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 19:51:22 2023 -0700
+
+    [hb-shape/view] List variation sequences in --list-unicodes
+
+ util/font-options.hh | 36 ++++++++++++++++++++++++++++++++----
+ 1 file changed, 32 insertions(+), 4 deletions(-)
+
+commit 8564d2266bc7988b6744e20bfb188d9328ef56e8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 19:43:33 2023 -0700
+
+    [hb-shape/view] Add --list-glyphs
+
+ util/font-options.hh | 28 +++++++++++++++++++++++++++-
+ 1 file changed, 27 insertions(+), 1 deletion(-)
+
+commit bf8bb9fb83575e99484f953d078fe0328d3dc344
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 19:39:30 2023 -0700
+
+    [hb-shape/view] Add --list-unicodes
+
+ util/font-options.hh | 37 +++++++++++++++++++++++++++++++++++++
+ 1 file changed, 37 insertions(+)
+
+commit 13c70066de00b46a0c30a32daa9e10647fd2e531
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 17:29:26 2023 -0700
+
+    Shut up gcc 13 -Wdangling-reference
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4043
+
+ src/hb.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 1abcc32137be9cce13bd8dc63b11a2759e5f8679
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Jan 18 18:22:00 2023 +0200
+
+    Revert "[ci] Use sccache with msys2"
+    
+    This reverts commit b9646dfd6290dbf7819cc042bb6f541b80ef8b68.
+    
+    For some reason using sccache re-introduces the random CI crashes that
+    was previously fixed in 80dd751564e8a9153f7466e687b8699a5e7e27c6.
+
+ .github/workflows/msys2-ci.yml | 6 ------
+ 1 file changed, 6 deletions(-)
+
+commit eed5d5efdd37bfbf06f52b67a5dd9d170576d2ee
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 14:13:12 2023 -0700
+
+    [VarComposite] Implement RESET_UNSPECIFIED_AXES
+    
+    Fixes https://github.com/harfbuzz/boring-expansion-spec/issues/79
+
+ src/OT/glyf/Glyph.hh             | 6 +++++-
+ src/OT/glyf/VarCompositeGlyph.hh | 2 ++
+ 2 files changed, 7 insertions(+), 1 deletion(-)
+
+commit 4300a18b852f67ad2b45fb9c1c04474c9f234eb2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 18 10:44:13 2023 -0700
+
+    [arabic-fallback] Fix ligature code
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4042
+    
+    This was broken in 20e9f0b.
+
+ src/hb-ot-shaper-arabic-fallback.hh | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+commit b9646dfd6290dbf7819cc042bb6f541b80ef8b68
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Jan 17 20:46:33 2023 +0200
+
+    [ci] Use sccache with msys2
+
+ .github/workflows/msys2-ci.yml | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 22a4fca375e54c5b3fabb56559ef2400cc5807a3
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Jan 17 18:10:36 2023 +0200
+
+    [ci] Use sccache for msvc jobs
+    
+    Meson will not use ccache with MSVC, so we use sccache here.
+
+ .github/workflows/msvc-ci.yml | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit 582636bce035e655392d82c400a2953ccb815a2c
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Jan 17 18:09:41 2023 +0200
+
+    [ci] Use ccache for linux and macos jobs
+
+ .github/workflows/linux-ci.yml | 5 ++++-
+ .github/workflows/macos-ci.yml | 6 +++++-
+ 2 files changed, 9 insertions(+), 2 deletions(-)
+
+commit 99146e76090787fd3e2f39289556da9bcf911e60
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Jan 17 17:20:19 2023 +0200
+
+    [ci] We don’t need to install ragel on msys2
+
+ .github/workflows/msys2-ci.yml | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 842e26d32ca42ed7715eb3f1018be6fd86f3d036
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Jan 17 17:02:56 2023 +0200
+
+    [ci] Remove no longer needed workaround
+    
+    Meson seems to take care of this itself now.
+
+ .github/workflows/msvc-ci.yml | 3 ---
+ 1 file changed, 3 deletions(-)
+
+commit 4d86c65c7ab544fe614c1c8f49d6154ea7b1ee04
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 17 07:34:45 2023 -0700
+
+    [hb-cairo] Fix linear-gradient reduce_anchors
+
+ src/hb-cairo-utils.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 910adc7e9263fb6f8456e282c5d5b62faa0bc923
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Jan 17 14:23:46 2023 +0200
+
+    [test-paint] Update expectations
+
+ test/api/results/bad-154    | 622 ++++++++++++++++++++++++--------------------
+ test/api/results/test-154   |  28 +-
+ test/api/results/testvf-154 |  28 +-
+ 3 files changed, 375 insertions(+), 303 deletions(-)
+
+commit 4f4b6e03f43e651bc18d8c9b724d779855e62e03
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Jan 17 14:08:58 2023 +0200
+
+    [wrap] Add fallback source URL for zlib
+    
+    Hopefully this fixes the intermittent CI failures due to download
+    failures.
+
+ subprojects/zlib.wrap | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit c86bab3fb4d2a52d6970d1fffd00e1b112b0b3c9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 17 06:29:17 2023 -0700
+
+    [test-paint] Use G_GNUC_PRINTF
+
+ test/api/test-paint.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+commit 92d5ec2f1618c3b899c74216f7f05ea85f815b8e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 17 05:59:19 2023 -0700
+
+    [bit-page] Mark len() function static
+
+ src/hb-bit-page.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 0a3e4c12ac770f36e52a1934862c1f98429d9b1b
+Author: Amir Masoud Abdol <amirmasoudabdol@icloud.com>
+Date:   Tue Jan 17 09:36:03 2023 +0100
+
+    Replace the deprecated $<CONFIGURATION> with $<CONFIG>
+
+ CMakeLists.txt | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit f38e35ebc317eaf311a334af40488a607c693194
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 16 18:07:39 2023 -0700
+
+    [cairo] Internal function renames
+
+ src/hb-cairo-utils.cc | 42 +++++++++++++++++++++---------------------
+ src/hb-cairo-utils.hh | 42 +++++++++++++++++++++---------------------
+ src/hb-cairo.cc       | 10 +++++-----
+ 3 files changed, 47 insertions(+), 47 deletions(-)
+
+commit e4a41f5e16b56a7c84055960dcac34e7b5ac94df
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 16 16:27:04 2023 -0700
+
+    [COLRv1] Implement recursive clip boxes
+    
+    Tests need update.
+    
+    hb-view test_glyphs-glyf_colr_1_variable.ttf -u f0c00
+
+ src/OT/Color/COLR/COLR.hh | 31 ++++++++++++++++++++++++-------
+ src/hb-ft-colr.hh         | 24 ++++++++++++++++--------
+ 2 files changed, 40 insertions(+), 15 deletions(-)
+
+commit f02c4ebb409befa41857d4df9465c5944f25e87b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 16 14:17:16 2023 -0700
+
+    [test-paint] Adjust condition for enabling ft backend
+
+ test/api/test-paint.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 7dfa672dac958bdbc7703ab0920e167eaa126754
+Author: Sergei Trofimovich <slyich@gmail.com>
+Date:   Mon Jan 16 19:49:53 2023 +0000
+
+    test/threads/hb-subset-threads.cc: add missing <cstdio> include
+    
+    This week's `gcc-13` snapshot cleaned further up it's standard headers
+    and exposed missing declaration as a build failure:
+    
+        ../test/threads/hb-subset-threads.cc: In function 'void test_operation(operation_t, const char*, const test_input_t&)':
+        ../test/threads/hb-subset-threads.cc:127:3: error: 'printf' was not declared in this scope
+    
+        ../test/threads/hb-subset-threads.cc: In function 'int main(int, char**)':
+        ../test/threads/hb-subset-threads.cc:157:19: error: 'atoi' was not declared in this scope
+
+ test/threads/hb-subset-threads.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit f11271cc036ae6ecee5e75a93da13078a6b97d11
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 16 13:14:58 2023 -0700
+
+    [cairo] Version-check the variations code
+
+ src/hb-cairo.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit a180ae43ce0ae8bccc45913a6443c0d109ce7ee9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 16 13:06:30 2023 -0700
+
+    [bit-set] Use for loop instead of memset for page clear
+    
+    Produces faster code.
+
+ src/hb-bit-page.hh | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+commit 8e8ca03b2a970f816e024d21ad9ab7dcd4ed76ad
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 16 12:38:53 2023 -0700
+
+    [hb-fc] Minor remove unused variable
+
+ util/hb-fc.cc | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+commit e903397bc33a202410255b56abdbe05aa4963b78
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 16 12:33:17 2023 -0700
+
+    Whitespace
+
+ util/ansi-print.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit ca1de29e0a85508b9938defd5e7a4b08e3134c7b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 16 12:08:11 2023 -0700
+
+    [set] Adjust hb_set_copy()
+
+ src/hb-set.cc | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit b7f1c30c2062837932d70bd7fbd5fb69289e4f36
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 16 12:07:15 2023 -0700
+
+    [map] Adjust hb_map_copy()
+
+ src/hb-map.cc | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+commit e0883d60e4203e9a01e6276c7c56dc5d427c60b6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 16 12:02:21 2023 -0700
+
+    Whitespace
+
+ src/hb-paint-extents.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 82a3b2dbb5fa65c2dba8f2ec81796f45e4ffe9a1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 16 11:18:22 2023 -0700
+
+    [util] Fix --named-instance
+
+ util/font-options.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ad6b9c417d240b82ed4e03f6cd9a1b4bec993064
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 16 11:07:03 2023 -0700
+
+    [util] Format --list-features
+
+ util/font-options.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 0f4da85074a0de1c0221d8af1d100eba4e78e3b9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 16 11:04:38 2023 -0700
+
+    [util] Minor in --list-features clear feature set between GSUB/GPOS
+
+ util/font-options.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit f25e3696eb315e3bccc24b9d4b89ce22c9f05c5f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 16 10:54:23 2023 -0700
+
+    [hb-shape/hb-view] Better --list-features
+
+ util/font-options.hh | 111 +++++++++++++++++++++++++++++++++------------------
+ 1 file changed, 72 insertions(+), 39 deletions(-)
+
+commit 32d439596d8d6157f4b621570f120afea6b3ca38
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 15 22:34:14 2023 -0700
+
+    [hb-shape/view] Print feature names in --list-features
+
+ util/font-options.hh | 41 ++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 38 insertions(+), 3 deletions(-)
+
+commit cc6a9bfa6f4eca07b8dec693acfc557cd21c073c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 15 18:16:19 2023 -0700
+
+    [hb-shape/view] Print table length in --list-tables
+
+ util/face-options.hh | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+commit 880d65c9056dc029140af0084693189dbab5fb71
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 15 18:14:14 2023 -0700
+
+    [hb-shape/view] Add --list-tables
+
+ util/face-options.hh | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+commit 3d5a922bcac06a47a589070b49f58b44d0c7ba2d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 15 16:15:52 2023 -0700
+
+    Fix really
+
+ util/font-options.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 484831be3dd1e113c92370cc5df781432b770ccd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 15 16:14:53 2023 -0700
+
+    [util] Fix build
+
+ util/font-options.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 8a6ecc5c89c524bf0a2d985dc39eaf793bfe5a01
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 15 13:54:27 2023 -0700
+
+    [hb-view/shape] Add --list-features
+
+ util/font-options.hh | 39 +++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 39 insertions(+)
+
+commit 40a8145acc7e90535c0089e393216a5602f7f9e4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 15 11:30:24 2023 -0700
+
+    [util] Don't use hb_vector_t
+
+ util/font-options.hh | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+commit d769e8ae7c125cf2ed0686f3c9e99e9525ecbbd4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 15 10:58:15 2023 -0700
+
+    [hb-shape/view] Add --named-instance
+
+ src/hb-font.cc       | 11 ++++++-----
+ util/font-options.hh |  3 +++
+ 2 files changed, 9 insertions(+), 5 deletions(-)
+
+commit 99838770abbd810caf63db7957d524537cb34290
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 15 10:54:01 2023 -0700
+
+    [font] Add hb_font_get_var_named_instance()
+    
+    Two new API:
+    +HB_FONT_NO_VAR_NAMED_INSTANCE
+    +hb_font_get_var_named_instance
+
+ docs/harfbuzz-sections.txt |  2 ++
+ src/hb-font.cc             | 28 ++++++++++++++++++++++------
+ src/hb-font.h              | 15 ++++++++++++++-
+ 3 files changed, 38 insertions(+), 7 deletions(-)
+
+commit 40bf30bfeb5cda9a8e147313f7b3a7ba8f671275
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 15 10:45:47 2023 -0700
+
+    [util] Print named-instance index in --list-variations
+
+ util/font-options.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d195e077e9ba22c2c54c2efc1677a4ded6ff250b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 15 10:44:04 2023 -0700
+
+    [font] Remember named_instance index
+    
+    Specially, in hb_font_set_variations() default to the named_instance
+    for unspecified axes.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/1883
+
+ src/hb-font.cc | 36 ++++++++++++++++++++----------------
+ src/hb-font.hh |  1 +
+ 2 files changed, 21 insertions(+), 16 deletions(-)
+
+commit 14a83d6cc7c6da9f82d1d048ad930d9654c3e479
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 15 10:11:54 2023 -0700
+
+    [hb-shape/view] --list-variations cleanup
+
+ util/font-options.hh | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+commit e1a5448306a555a66cb337a419e275bb5d98d461
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 15 10:00:26 2023 -0700
+
+    [hb-shape/view] Print named-instances in --list-variations
+    
+    Might remove the coordinates.
+
+ util/font-options.hh | 30 +++++++++++++++++++++++++++++-
+ 1 file changed, 29 insertions(+), 1 deletion(-)
+
+commit 9abc21072b34b4170fbc73bdec7e6b7dcd70d123
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 15 09:46:19 2023 -0700
+
+    [hb-shape/view] Add --list-variations
+
+ util/font-options.hh | 46 ++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 46 insertions(+)
+
+commit d015e9016c4c4028996ba6ea2be11756963d2a2c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 18:50:16 2023 -0700
+
+    [ms-features] Comment
+
+ src/hb-ms-feature-ranges.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit ea1ee0d4b6e283b025cf37cee9f8359c8b848ac1
+Author: Garret Rieger <grieger@google.com>
+Date:   Sat Jan 14 00:23:53 2023 +0000
+
+    [instance] drop and don't collect lookups from feature variations when fully instancing.
+    
+    This previously incorrectly collected lookups that could be reached via feature variations that are dropped and not activated by the current instance position.
+
+ src/hb-ot-layout-gsubgpos.hh                       |  23 ++++++++++++++++++---
+ src/hb-subset-plan.cc                              |  12 ++++++++++-
+ .../MPLUS1-Variable.default.30DD.wght=100.ttf      | Bin 0 -> 1460 bytes
+ .../MPLUS1-Variable.default.30DD.wght=400.ttf      | Bin 0 -> 1712 bytes
+ ...iable.default.retain-all-codepoint.wght=400.ttf | Bin 1660624 -> 0 bytes
+ ...otdef-outline.retain-all-codepoint.wght=400.ttf | Bin 1660668 -> 0 bytes
+ ...ototype.layout-test-retain-gids.41,42,43,57.otf | Bin 5924 -> 5920 bytes
+ ...FPrototype.layout-test-retain-gids.41,42,43.otf | Bin 5212 -> 5208 bytes
+ ...beVFPrototype.layout-test-retain-gids.41,42.otf | Bin 4732 -> 4728 bytes
+ ...FPrototype.layout-test-retain-gids.41,56,57.otf | Bin 5048 -> 5044 bytes
+ ...AdobeVFPrototype.layout-test-retain-gids.41.otf | Bin 3996 -> 3992 bytes
+ ...beVFPrototype.layout-test-retain-gids.42,57.otf | Bin 5040 -> 5036 bytes
+ .../AdobeVFPrototype.layout-test.41,42,43,57.otf   | Bin 5480 -> 5476 bytes
+ .../AdobeVFPrototype.layout-test.41,42,43.otf      | Bin 4952 -> 4948 bytes
+ .../AdobeVFPrototype.layout-test.41,42.otf         | Bin 4468 -> 4464 bytes
+ .../AdobeVFPrototype.layout-test.41,56,57.otf      | Bin 4620 -> 4616 bytes
+ .../AdobeVFPrototype.layout-test.41.otf            | Bin 3768 -> 3764 bytes
+ .../AdobeVFPrototype.layout-test.42,57.otf         | Bin 4600 -> 4596 bytes
+ .../data/expected/variable/Fraunces.default.61.ttf | Bin 4232 -> 4228 bytes
+ .../data/tests/instance_feature_variations.tests   |   4 ++--
+ 20 files changed, 33 insertions(+), 6 deletions(-)
+
+commit d250148db08f620022092487578f36474f35b127
+Merge: 81b942e36 60a4f2e6f
+Author: Matthias Clasen <matthias.clasen@gmail.com>
+Date:   Thu Jan 12 21:26:24 2023 -0500
+
+    Merge pull request #4024 from harfbuzz/test-paint-variable
+    
+    test-paint: Add variable font tests
+
+commit 60a4f2e6f5fd8896cd09a1274a4e772c987d695d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 19:12:46 2023 -0700
+
+    [test-paint] Detect FreeType COLRv1 from struct size
+
+ test/api/test-paint.c | 55 +++++++++++++++++++++++++++++----------------------
+ 1 file changed, 31 insertions(+), 24 deletions(-)
+
+commit b783967242cce70e814fc817c49f08e4ec0599ce
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 18:58:07 2023 -0700
+
+    [test] Minor save glyph_count
+
+ test/api/test-paint.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit cca0ed9bcd91fbdb4611cfba51ebf068d50081ed
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Jan 11 06:44:25 2023 -0500
+
+    test-paint: Add variable font tests
+    
+    These needs freetype master to work.
+
+ .../api/fonts/test_glyphs-glyf_colr_1_variable.ttf | Bin 0 -> 70336 bytes
+ test/api/results/testvf-10                         |  22 +++++++++
+ test/api/results/testvf-106                        |  30 ++++++++++++
+ test/api/results/testvf-116                        |  26 +++++++++++
+ test/api/results/testvf-123                        |  47 +++++++++++++++++++
+ test/api/results/testvf-154                        |  30 ++++++++++++
+ test/api/results/testvf-165                        |  22 +++++++++
+ test/api/results/testvf-175                        |  36 +++++++++++++++
+ test/api/results/testvf-6                          |  21 +++++++++
+ test/api/results/testvf-92                         |  21 +++++++++
+ test/api/test-paint.c                              |  51 +++++++++++++++++----
+ 11 files changed, 296 insertions(+), 10 deletions(-)
+
+commit 81b942e363f3ca7b156e2a1ba21f74c1f3de8848
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 18:42:22 2023 -0700
+
+    [os2] Comment
+
+ src/hb-ot-os2-table.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 9fb9be8d43262f46c8a639d80fa049dcb0e440f0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 18:37:45 2023 -0700
+
+    [os2] Rewrite a loop
+
+ src/hb-ot-os2-table.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 082e5c5defec424856fdc82c94a388eac1c409c2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 18:37:07 2023 -0700
+
+    [os2] Minor add a cast
+
+ src/hb-ot-os2-unicode-ranges.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 45fe897e89f348bc16db538d2da7583e5fa4808a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 18:36:16 2023 -0700
+
+    [os2] Rename a couple of variables
+
+ src/hb-ot-os2-unicode-ranges.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 2dcbf3bd07ea10bf81548f4407afead2cc1ea2b0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 18:29:16 2023 -0700
+
+    [os2] Inline a trivial function
+
+ src/hb-ot-os2-table.hh | 16 ++--------------
+ 1 file changed, 2 insertions(+), 14 deletions(-)
+
+commit 075fe33446aa66ee36004f23a309b41e18991d49
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 17:14:42 2023 -0700
+
+    Enable -Wunsafe-loop-optimizations
+    
+    I don't get any.
+
+ src/hb.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ed023f66df642b58e486da855e871c7dbc0a9576
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 17:04:24 2023 -0700
+
+    Enable -Wformat-signedness
+    
+    And fix the codebase.
+
+ src/OT/Layout/GPOS/CursivePosFormat1.hh            |  4 +--
+ src/OT/Layout/GPOS/MarkArray.hh                    |  4 +--
+ src/OT/Layout/GPOS/PairPosFormat2.hh               |  6 ++--
+ src/OT/Layout/GPOS/PairSet.hh                      |  6 ++--
+ src/OT/Layout/GPOS/SinglePosFormat1.hh             |  4 +--
+ src/OT/Layout/GPOS/SinglePosFormat2.hh             |  4 +--
+ src/OT/Layout/GSUB/AlternateSet.hh                 |  6 ++--
+ src/OT/Layout/GSUB/Ligature.hh                     |  8 ++---
+ .../Layout/GSUB/ReverseChainSingleSubstFormat1.hh  |  4 +--
+ src/OT/Layout/GSUB/Sequence.hh                     | 12 ++++----
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh           |  6 ++--
+ src/OT/Layout/GSUB/SingleSubstFormat2.hh           |  6 ++--
+ src/OT/glyf/SubsetGlyph.hh                         |  2 +-
+ src/OT/glyf/glyf-helpers.hh                        |  4 +--
+ src/graph/graph.hh                                 |  8 ++---
+ src/graph/serialize.hh                             |  6 ++--
+ src/hb-aat-layout-kerx-table.hh                    |  4 +--
+ src/hb-aat-layout-morx-table.hh                    |  6 ++--
+ src/hb-buffer-verify.cc                            |  4 +--
+ src/hb-debug.hh                                    |  2 +-
+ src/hb-ot-layout-gsubgpos.hh                       |  2 +-
+ src/hb-ot-layout.cc                                |  6 ++--
+ src/hb-ot-shaper-arabic.cc                         | 16 +++++-----
+ src/hb-ot-shaper-indic-machine.hh                  |  2 +-
+ src/hb-ot-shaper-indic-machine.rl                  |  2 +-
+ src/hb-ot-shaper-khmer-machine.hh                  |  2 +-
+ src/hb-ot-shaper-khmer-machine.rl                  |  2 +-
+ src/hb-ot-shaper-myanmar-machine.hh                |  2 +-
+ src/hb-ot-shaper-myanmar-machine.rl                |  2 +-
+ src/hb-ot-shaper-use-machine.hh                    |  2 +-
+ src/hb-ot-shaper-use-machine.rl                    |  2 +-
+ src/hb-ot-tag.cc                                   |  4 +--
+ src/hb-repacker.hh                                 |  4 +--
+ src/hb-sanitize.hh                                 |  8 ++---
+ src/hb-shape-plan.cc                               |  6 ++--
+ src/hb-subset-plan.hh                              |  2 +-
+ src/hb.hh                                          |  2 +-
+ src/main.cc                                        | 36 +++++++++++-----------
+ src/test-ot-meta.cc                                |  4 +--
+ src/test-unicode-ranges.cc                         |  2 +-
+ src/test.cc                                        |  2 +-
+ util/font-options.hh                               |  2 +-
+ util/shape-format.hh                               |  2 +-
+ 43 files changed, 110 insertions(+), 110 deletions(-)
+
+commit 7b5f0dd3a8b4a126b7952fea1c4c30b8b456083e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 15:05:19 2023 -0700
+
+    Move hb-ot-name-language-static.hh out of hb-static.cc
+    
+    Since hb-static.cc is used by libharfbuzz-cairo as well.
+
+ src/hb-ot-name.cc | 2 ++
+ src/hb-static.cc  | 1 -
+ src/hb-subset.cc  | 5 +++++
+ 3 files changed, 7 insertions(+), 1 deletion(-)
+
+commit 449f6df7622c2e363841823c92ca5fd4faee9d62
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 14:52:00 2023 -0700
+
+    [mutex] Add constructor/destructor
+    
+    Use in one place.
+
+ src/hb-mutex.hh              | 3 +++
+ src/hb-subset-accelerator.hh | 7 +------
+ 2 files changed, 4 insertions(+), 6 deletions(-)
+
+commit 8e71f7e8eda4ab4c664ee5c073db56f223bf6b20
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 14:46:44 2023 -0700
+
+    [subset-accelerator] Streamline constructor/destructor
+
+ src/hb-subset-accelerator.hh | 52 +++++++++++++++++++++++++++++---------------
+ 1 file changed, 34 insertions(+), 18 deletions(-)
+
+commit c4c646280fd2b6e3141ecc0f45d477c8f2b43bc7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 13:58:46 2023 -0700
+
+    [unicode] Adjust error message
+
+ src/hb-unicode.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 0d665291358f2648725e605e7deb88cbe4ee0490
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 13:14:24 2023 -0700
+
+    [bit-page] Minor simplify bit-page specification
+
+ src/hb-bit-page.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 32866a331e49da465812f329d494bb8612dc14db
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 13:02:30 2023 -0700
+
+    [subset-input] Simplify destruction
+
+ src/hb-subset-input.hh | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+commit d5b826fd0910f68dcdc4c6f6e990c7b188a95255
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 12:55:47 2023 -0700
+
+    [subset-input] Fix leak
+
+ src/hb-subset-input.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit c52810529e8eae366b0d7d94b8077b5e2ab5f06b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 12:53:46 2023 -0700
+
+    [subset-plan] Move construction to constructor
+
+ src/hb-subset-plan.cc | 157 ++++++++++++++++++++++++++------------------------
+ src/hb-subset-plan.hh |   3 +
+ 2 files changed, 84 insertions(+), 76 deletions(-)
+
+commit 26d69e059dc2fbf03ae28e52a08c1bd38f7ce2bf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 12:46:44 2023 -0700
+
+    [subset-input] Move constructor to .cc file
+
+ src/hb-subset-input.cc | 160 +++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-subset-input.hh | 158 +-----------------------------------------------
+ 2 files changed, 161 insertions(+), 157 deletions(-)
+
+commit a916ad9ea9b8cfc1cc34608fd4a3e608a4ef76f0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 12:44:16 2023 -0700
+
+    [subset-input] Move initialization to constructor
+
+ src/hb-subset-input.cc | 157 ------------------------------------------------
+ src/hb-subset-input.hh | 158 ++++++++++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 157 insertions(+), 158 deletions(-)
+
+commit 875f9f6f22451f1cc02782a8269f7e1e4bce0ca0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 12:37:48 2023 -0700
+
+    [subset-input] Use shared_ptr for sets
+
+ src/hb-subset-input.cc |  2 +-
+ src/hb-subset-input.hh | 29 ++++++++++++++---------------
+ 2 files changed, 15 insertions(+), 16 deletions(-)
+
+commit ef005bc82a48d8ee0acd073a17c7d3481ecb702e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 12:09:14 2023 -0700
+
+    [subset-input] Fix destruction
+    
+    Ouch! Object was already destroyed at that point before.
+
+ src/hb-subset-input.cc |  8 --------
+ src/hb-subset-input.hh | 11 +++++++++++
+ src/hb-subset-plan.hh  |  3 ---
+ 3 files changed, 11 insertions(+), 11 deletions(-)
+
+commit c60c5995bb36a4796c747243d1e43bca04b1332f
+Merge: 8c83de139 cfb672f1e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 11:59:51 2023 -0700
+
+    Merge pull request #4028 from harfbuzz/mvar-instancing
+    
+    [instancer] Add MVAR values to OS/2
+
+commit cfb672f1e5cb0e855cec3e5baacee1507e973ce3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 10:36:39 2023 -0700
+
+    [glyf] Revert sign of advance widths back
+
+ src/OT/glyf/Glyph.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit c324d999521d3886af4560a810dcd34ef779125f
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jan 12 18:15:07 2023 +0000
+
+    [instancing] Add tests for MVAR instancing.
+
+ ...out.retain-all-codepoint.wght=150,wdth=80,CTGR=0.ttf | Bin 0 -> 1396 bytes
+ ...out.retain-all-codepoint.wght=300,wdth=90,CTGR=0.ttf | Bin 0 -> 1432 bytes
+ test/subset/data/fonts/NotoSans-VF.abc.ttf              | Bin 0 -> 11156 bytes
+ test/subset/data/profiles/no-layout.txt                 |   1 +
+ test/subset/data/tests/mvar_full_instance.tests         |  12 ++++++++++++
+ 5 files changed, 13 insertions(+)
+
+commit 8c83de1396c7b51acfd1ba1482e2dbe816048363
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 12 10:44:08 2023 -0700
+
+    [aat] Initialize values
+
+ src/hb-aat-map.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit ca1909154938084be149bf84e1f38edec5bb682b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 14:36:02 2023 -0700
+
+    [hhea/vhea] Add MVAR during instancing
+
+ src/hb-ot-hmtx-table.hh | 28 ++++++++++++++++++++++++----
+ 1 file changed, 24 insertions(+), 4 deletions(-)
+
+commit f4550001380bf1c8f70119908d83538d4bafb918
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 14:25:37 2023 -0700
+
+    [post] Add MVAR to subsetting
+
+ src/hb-ot-post-table.hh | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+commit 9dc3e785aad419c832b69fb6d8ad53258dc8273a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 14:09:47 2023 -0700
+
+    [instancer] Add MVAR values to OS/2
+
+ src/hb-ot-os2-table.hh      | 33 +++++++++++++++++++++++++++++++++
+ src/hb-ot-var-mvar-table.hh |  9 +++++++++
+ 2 files changed, 42 insertions(+)
+
+commit e78a68bf467b86daa17377dc08f382cadb8d748c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 15:34:11 2023 -0700
+
+    [subset-input] Don't RETAIN_GIDs in keep-everything
+
+ src/hb-subset-input.cc | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit d675f0d4f2d6269ac1dd92fa0ea0db79ce5ee3a1
+Merge: 52c8c5a05 bfd7548e2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 15:06:31 2023 -0700
+
+    Merge pull request #4023 from harfbuzz/aat-features2
+    
+    [aat] Support feature ranges
+
+commit 52c8c5a058dbbfe9373d786718b69568a25b41e0
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Jan 11 18:50:24 2023 +0200
+
+    [doc] Fix API indices generation
+    
+    For whatever reason, GTK-Doc 1.33.1 will not generate HTML files for
+    indices that has these role attributes.
+
+ docs/harfbuzz-docs.xml | 128 ++++++++++++++++++++++++-------------------------
+ 1 file changed, 64 insertions(+), 64 deletions(-)
+
+commit 1135f0b8cc9fc00129012f7022986c75732ffd60
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 13:45:16 2023 -0700
+
+    Another try at fixing arm build
+
+ src/hb-ot-hmtx-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 527e2d7ce2a2659c69f90c6bc86b5bb8838ed682
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 13:41:44 2023 -0700
+
+    [gobject] Add another value type hb_ot_var_axis_info
+
+ src/hb-gobject-structs.cc | 1 +
+ src/hb-gobject-structs.h  | 4 ++++
+ 2 files changed, 5 insertions(+)
+
+commit 8206569d6373a0fe97602788c7a43a0cf1f0345a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 13:24:50 2023 -0700
+
+    [map] Remove hashmap create/destroy/vtable
+    
+    Unused now.
+
+ src/hb-map.hh   | 32 --------------------------------
+ src/test-map.cc | 10 ----------
+ 2 files changed, 42 deletions(-)
+
+commit 1426f1c8ea29a6b71ab0f1ce9d9c79b41f407eb0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 13:23:34 2023 -0700
+
+    [subset-plan] Simplify name_table_overrides allocation
+
+ src/hb-subset-input.cc | 20 ++++----------------
+ src/hb-subset-input.hh |  4 ++--
+ src/hb-subset-plan.cc  | 21 +++++++++------------
+ 3 files changed, 15 insertions(+), 30 deletions(-)
+
+commit 5cab4a55d28ec51abe1cf4a7bd09c1814378fc67
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 13:21:57 2023 -0700
+
+    [subset-input] Simplify axes_location allocation
+
+ src/hb-subset-input.cc | 9 +++------
+ src/hb-subset-input.hh | 4 ++--
+ src/hb-subset-plan.cc  | 3 +--
+ 3 files changed, 6 insertions(+), 10 deletions(-)
+
+commit df721e05628daa0d5dd9998ff22dec98db9433e7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 12:50:52 2023 -0700
+
+    [gobject] Add draw/paint value types
+
+ src/hb-gobject-structs.cc |  3 +++
+ src/hb-gobject-structs.h  | 12 ++++++++++++
+ 2 files changed, 15 insertions(+)
+
+commit 41352c08b8baa2a731331126a64978df80371b0f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 12:42:14 2023 -0700
+
+    [hmtx] Fix types
+
+ src/hb-ot-hmtx-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 4e7c80396928aef328a31b84f1d8df479e31d340
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 12:38:26 2023 -0700
+
+    [subset-plan] Simplify name_table_overrides allocation
+
+ src/hb-ot-name-table.hh |  2 +-
+ src/hb-subset-plan.cc   |  5 ++---
+ src/hb-subset-plan.hh   | 10 +++-------
+ 3 files changed, 6 insertions(+), 11 deletions(-)
+
+commit 65d3db375cb51204ac971dcd2d978684ab8a9422
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 12:36:54 2023 -0700
+
+    [subset-plan] Simplify user_axes_location allocation
+
+ src/OT/glyf/glyf.hh         |  6 +++---
+ src/hb-ot-layout-common.hh  |  4 ++--
+ src/hb-ot-os2-table.hh      |  8 ++++----
+ src/hb-ot-post-table.hh     |  4 ++--
+ src/hb-ot-stat-table.hh     |  8 ++++----
+ src/hb-ot-var-fvar-table.hh |  2 +-
+ src/hb-subset-plan.cc       | 23 +++++++++++------------
+ src/hb-subset-plan.hh       |  4 +---
+ src/hb-subset.cc            |  2 +-
+ 9 files changed, 29 insertions(+), 32 deletions(-)
+
+commit 60418fcb95519013d1cf7ef57d9e63431401dc6a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 12:33:25 2023 -0700
+
+    [subset-plan] Simplify axes_index_map allocation
+
+ src/hb-ot-layout-common.hh  | 2 +-
+ src/hb-ot-var-fvar-table.hh | 6 +++---
+ src/hb-subset-plan.cc       | 3 +--
+ src/hb-subset-plan.hh       | 3 +--
+ 4 files changed, 6 insertions(+), 8 deletions(-)
+
+commit 8265277c2ee60c6d9f4e6b87f86bc2b3b296338a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 12:32:04 2023 -0700
+
+    [subset-plan] Simplify axes_location allocation
+
+ src/hb-subset-plan.cc | 5 ++---
+ src/hb-subset-plan.hh | 3 +--
+ 2 files changed, 3 insertions(+), 5 deletions(-)
+
+commit d54902c6598045112374f1f51e1775677dd77d94
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 12:29:25 2023 -0700
+
+    [subset-plan] Simplify axes_old_index_tag_map allocation
+
+ src/hb-ot-var-fvar-table.hh | 2 +-
+ src/hb-subset-plan.cc       | 5 ++---
+ src/hb-subset-plan.hh       | 3 +--
+ 3 files changed, 4 insertions(+), 6 deletions(-)
+
+commit 9f4c8fb7004bfce2bcc29f3be900a5f907e92fb3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 12:28:18 2023 -0700
+
+    [subset-plan] Minor move code around
+
+ src/hb-subset-plan.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit a34a204bf74ee0c08a67c97444ce803d6f0a0b6d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 12:27:19 2023 -0700
+
+    [subset-plan] Simplify unicodes allocation
+
+ src/hb-ot-cmap-table.hh | 2 +-
+ src/hb-ot-os2-table.hh  | 4 ++--
+ src/hb-subset-plan.cc   | 9 ++++-----
+ src/hb-subset-plan.hh   | 3 +--
+ 4 files changed, 8 insertions(+), 10 deletions(-)
+
+commit 75b33cb04b783f9f8473df46b603b6e94dc226b3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 12:24:35 2023 -0700
+
+    [subset-plan] Simplify hmtx_map / vmtx_map allocation
+
+ src/OT/glyf/Glyph.hh    | 4 ++--
+ src/hb-ot-hmtx-table.hh | 2 +-
+ src/hb-subset-plan.cc   | 3 ---
+ src/hb-subset-plan.hh   | 6 ++----
+ 4 files changed, 5 insertions(+), 10 deletions(-)
+
+commit 33ce3a0d446bef5b26fb11032849115ad948d76b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 12:21:26 2023 -0700
+
+    [subset] Minor adjust a couple types
+
+ src/OT/glyf/Glyph.hh  | 4 ++--
+ src/hb-subset-plan.cc | 4 ++--
+ src/hb-subset-plan.hh | 4 ++--
+ 3 files changed, 6 insertions(+), 6 deletions(-)
+
+commit 865d1747066a4dc91bf99cff182ae4504a53aa4f
+Merge: 5f51dd276 67eefebf8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 12:14:17 2023 -0700
+
+    Merge pull request #4027 from harfbuzz/plan-simplify
+    
+    Plan simplify
+
+commit 67eefebf8d61796a63e6e8e7c79a40564c45d723
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 11:44:09 2023 -0700
+
+    [subset-plan] Simplify user_axes_location destruction
+
+ src/hb-subset-plan.hh | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+commit b2007abff75f0d5d8b472e66e3b84947c9d06a70
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 11:27:22 2023 -0700
+
+    [subset-plan] Simplify glyph_map_gsub allocation
+
+ src/hb-ot-layout-common.hh | 4 ++--
+ src/hb-subset-plan.cc      | 3 +--
+ src/hb-subset-plan.hh      | 3 +--
+ 3 files changed, 4 insertions(+), 6 deletions(-)
+
+commit bd4b040e7f6c34afd811d5b8d37e967f18ffe728
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 11:23:48 2023 -0700
+
+    [shape-plan] Simplify glyphs_requested allocation
+
+ src/hb-ot-cmap-table.hh | 2 +-
+ src/hb-subset-plan.cc   | 2 +-
+ src/hb-subset-plan.hh   | 3 +--
+ 3 files changed, 3 insertions(+), 4 deletions(-)
+
+commit c51d33685db7a85243260585f2e8f0aba904f982
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 11:22:22 2023 -0700
+
+    [subset-plan] Simplify no_subset_tables allocation
+
+ src/hb-subset-plan.cc | 2 +-
+ src/hb-subset-plan.hh | 3 +--
+ src/hb-subset.cc      | 6 +++---
+ 3 files changed, 5 insertions(+), 6 deletions(-)
+
+commit 999be72135a45f1e1e36b32d1944a6d6b7335f17
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 11:21:17 2023 -0700
+
+    [subset-plan] Simplify drop_tables allocation
+
+ src/hb-subset-plan.cc | 2 +-
+ src/hb-subset-plan.hh | 3 +--
+ src/hb-subset.cc      | 2 +-
+ 3 files changed, 3 insertions(+), 4 deletions(-)
+
+commit b33eb9ecfc255f43006ccd422f0f6807f4f7a100
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 11:20:04 2023 -0700
+
+    [subset-plan] Simplify layout_variation_idx_delta_map allocation
+
+ src/OT/Layout/GPOS/AnchorFormat3.hh    | 12 ++++++------
+ src/OT/Layout/GPOS/PairPosFormat2.hh   |  4 ++--
+ src/OT/Layout/GPOS/PairSet.hh          |  2 +-
+ src/OT/Layout/GPOS/SinglePosFormat1.hh |  2 +-
+ src/OT/Layout/GPOS/SinglePosFormat2.hh |  2 +-
+ src/hb-ot-layout-gdef-table.hh         |  6 +++---
+ src/hb-subset-plan.cc                  |  5 ++---
+ src/hb-subset-plan.hh                  |  3 +--
+ 8 files changed, 17 insertions(+), 19 deletions(-)
+
+commit 9c45d98f732304e59ec2f81b3c7bb3c1f55fa78c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 11:16:18 2023 -0700
+
+    [subset-plan] Simplify colr_palettes allocation
+
+ src/OT/Color/COLR/COLR.hh | 6 +++---
+ src/OT/Color/CPAL/CPAL.hh | 2 +-
+ src/hb-subset-plan.cc     | 3 +--
+ src/hb-subset-plan.hh     | 3 +--
+ 4 files changed, 6 insertions(+), 8 deletions(-)
+
+commit b74a26519614c816a92bdcc8f6cd920647da90d0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 11:15:15 2023 -0700
+
+    [subset-plan] Simplify colrv1_layers allocation
+
+ src/OT/Color/COLR/COLR.hh | 2 +-
+ src/hb-subset-plan.cc     | 3 +--
+ src/hb-subset-plan.hh     | 3 +--
+ 3 files changed, 3 insertions(+), 5 deletions(-)
+
+commit 89905368ca75496fac663710ea03f1bb90cd33cb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 11:13:49 2023 -0700
+
+    [subset-plan] Simplify sanitized_table_cache allocation
+
+ src/hb-subset-plan.cc | 1 -
+ src/hb-subset-plan.hh | 5 ++---
+ 2 files changed, 2 insertions(+), 4 deletions(-)
+
+commit 9e24873c1e2459a78bb97ef31e0c42779aa88ae8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 11:12:07 2023 -0700
+
+    [subset-plan] Simplify gsub/gpos_feature_substitutes_map allocation
+
+ src/hb-ot-layout-common.hh | 4 ++--
+ src/hb-subset-plan.cc      | 7 ++-----
+ src/hb-subset-plan.hh      | 6 ++----
+ 3 files changed, 6 insertions(+), 11 deletions(-)
+
+commit 01208c7c02b779fb816391eb4a7ea6b76bd91cdc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 11:10:28 2023 -0700
+
+    [subset-plan] Simplify gsub/gpos_feature_record_cond_idx_map allocation
+
+ src/hb-ot-layout-common.hh | 4 ++--
+ src/hb-subset-plan.cc      | 7 ++-----
+ src/hb-subset-plan.hh      | 6 ++----
+ 3 files changed, 6 insertions(+), 11 deletions(-)
+
+commit 06039db0801f68bfe93dcff1c733595d77a1580e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 11:07:31 2023 -0700
+
+    [subset-plan] Simplify gsub_langsys and gpos_langsys allocation
+
+ src/hb-ot-layout-common.hh | 4 ++--
+ src/hb-subset-plan.cc      | 7 ++-----
+ src/hb-subset-plan.hh      | 6 ++----
+ 3 files changed, 6 insertions(+), 11 deletions(-)
+
+commit 5fc91de2c0f32f0e067950ce004f498a378690e9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 11:04:17 2023 -0700
+
+    [shape-plan] Simplify _glyphset_colred allocation
+
+ src/OT/Color/COLR/COLR.hh | 6 +++---
+ src/hb-subset-plan.cc     | 3 +--
+ src/hb-subset-plan.hh     | 3 +--
+ 3 files changed, 5 insertions(+), 7 deletions(-)
+
+commit efafe7aa3bef6d4367ca10caefb24802f809b299
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 11:03:19 2023 -0700
+
+    [subset-plan] Simplify _glyphset_mathed allocation
+
+ src/hb-ot-math-table.hh | 10 +++++-----
+ src/hb-subset-plan.cc   |  9 ++++-----
+ src/hb-subset-plan.hh   |  3 +--
+ 3 files changed, 10 insertions(+), 12 deletions(-)
+
+commit 113a1700df64b4ade259fac37bf434925664b050
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 11:01:11 2023 -0700
+
+    [subset-plan] Simplify _glyphset_gsub allocation
+
+ src/hb-subset-plan.cc | 21 ++++++++++-----------
+ src/hb-subset-plan.hh |  5 ++---
+ 2 files changed, 12 insertions(+), 14 deletions(-)
+
+commit 4a9268f2807db09f3b6480b7a1deb544d99b6f87
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 11:00:02 2023 -0700
+
+    [subset-plan] Simplify _glyphset allocation
+
+ src/hb-subset-plan.cc | 11 +++++------
+ src/hb-subset-plan.hh |  7 +++----
+ 2 files changed, 8 insertions(+), 10 deletions(-)
+
+commit 1a00ab69ec012e296f9ec11a9c5619d637012b3b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 10:56:16 2023 -0700
+
+    [subset-plan] Simplify gsub_lookups and gpos_lookups allocation
+
+ src/hb-ot-layout-common.hh   |  4 ++--
+ src/hb-ot-layout-gsubgpos.hh | 12 ++++++------
+ src/hb-subset-plan.cc        |  8 +++-----
+ src/hb-subset-plan.hh        |  6 ++----
+ 4 files changed, 13 insertions(+), 17 deletions(-)
+
+commit 1a716bad03a9d628a97d8212f37cd83b7ad3e76f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 10:51:48 2023 -0700
+
+    [subset-plan] Simplify gsub_features and gpos_features allocation
+
+ src/hb-ot-layout-common.hh | 4 ++--
+ src/hb-subset-plan.cc      | 7 ++-----
+ src/hb-subset-plan.hh      | 6 ++----
+ 3 files changed, 6 insertions(+), 11 deletions(-)
+
+commit 78aa9f1e9c5f68249628746178c4088c2eb3e8d5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 10:47:40 2023 -0700
+
+    [subset-plan] Simplify name_ids allocation
+
+ src/hb-subset-plan.cc | 4 ++--
+ src/hb-subset-plan.hh | 3 +--
+ 2 files changed, 3 insertions(+), 4 deletions(-)
+
+commit cfb48f91da9089c8f9ea0069c4e001562980b7e9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 10:45:02 2023 -0700
+
+    [subset-plan] Simplify name_languages allocation
+
+ src/hb-subset-plan.cc | 2 +-
+ src/hb-subset-plan.hh | 3 +--
+ 2 files changed, 2 insertions(+), 3 deletions(-)
+
+commit e4ca0fe436b691bba3f405a722cb178c3e62a828
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 10:43:01 2023 -0700
+
+    [subset-plan] Simplify layout_features allocation
+
+ src/hb-subset-plan.cc | 4 ++--
+ src/hb-subset-plan.hh | 3 +--
+ 2 files changed, 3 insertions(+), 4 deletions(-)
+
+commit 4de66eec5751e57eee64730aec271313b2f3ea2f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 11 10:40:54 2023 -0700
+
+    [subset-plan] Simplify layout_scripts allocation
+
+ src/hb-ot-layout-common.hh | 2 +-
+ src/hb-subset-plan.cc      | 6 +++---
+ src/hb-subset-plan.hh      | 3 +--
+ 3 files changed, 5 insertions(+), 6 deletions(-)
+
+commit 5f51dd276b5636d541d4a6b94314f48432b08ff2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 22:57:07 2023 -0700
+
+    [ft-colr] Minor use false instead of 0
+
+ src/hb-ft-colr.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f84a8e3289212b261fa9d9847c4628a1dd4b2153
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 22:43:30 2023 -0700
+
+    [ft-colr] Comment
+
+ src/hb-ft-colr.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 1cb5a87febb84dd3c8323e82da1db33d539310be
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Tue Jan 10 22:13:44 2023 -0500
+
+    test-pain: Print out extend for color lines
+    
+    Update all expected results to include this value.
+
+ test/api/results/bad-154   |  2 +-
+ test/api/results/hand-10   | 10 +++++-----
+ test/api/results/hand-10.2 | 10 +++++-----
+ test/api/results/rocher-1  |  2 +-
+ test/api/results/rocher-2  |  2 +-
+ test/api/results/rocher-3  |  2 +-
+ test/api/results/test-10   |  4 ++--
+ test/api/results/test-106  |  2 +-
+ test/api/results/test-116  |  2 +-
+ test/api/results/test-123  |  2 +-
+ test/api/results/test-154  |  4 ++--
+ test/api/results/test-165  |  4 ++--
+ test/api/results/test-175  |  4 ++--
+ test/api/results/test-6    |  4 ++--
+ test/api/results/test-92   |  4 ++--
+ test/api/test-paint.c      |  2 +-
+ 16 files changed, 30 insertions(+), 30 deletions(-)
+
+commit 6648e6e3e5b0d93dee8fcc3cbe7fd886ba324ee3
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Tue Jan 10 22:07:44 2023 -0500
+
+    Add one more paint test
+    
+    Add a test for the clip_box_top_left_glyph,
+    since we've seen broken rendering with it.
+
+ test/api/results/test-154 | 30 ++++++++++++++++++++++++++++++
+ test/api/test-paint.c     |  1 +
+ 2 files changed, 31 insertions(+)
+
+commit bf16dad55aac9225a7b857a392267959600568e0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 17:29:25 2023 -0700
+
+    [paint-extents] Return unbounded on memory allocation failure
+
+ src/hb-paint-extents.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 3e1c524e64c9829234f9c89f99a31af3aabe3ab8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 17:18:34 2023 -0700
+
+    [bit-page] Comment
+
+ src/hb-bit-page.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 626def03f8abbc818661a4178b2463ce6b108093
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 17:12:50 2023 -0700
+
+    [hmtx] Remove TODO items
+
+ src/hb-ot-hmtx-table.hh | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+commit adf0bd6dcd20b684dc3a64bcb219fced5918a1be
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 17:04:58 2023 -0700
+
+    [test-map] Add a test
+
+ src/test-map.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 4fd03540679b3630cd023825ed2ee2a5ecc60457
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 14:32:08 2023 -0700
+
+    [font] Docs
+
+ src/hb-font.cc | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit bfd7548e243ab92ed02e66c95d244c78dd6e622b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 13:31:58 2023 -0700
+
+    [aat] Optimize feature-range application
+
+ src/hb-aat-layout-morx-table.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit dd42939e318c90f2c0f7d0efc1c4354182552f72
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 13:23:19 2023 -0700
+
+    [aat] Reduce unsafe_to_concat calls
+
+ src/hb-aat-layout-common.hh     | 2 --
+ src/hb-aat-layout-kerx-table.hh | 2 ++
+ src/hb-aat-layout-morx-table.hh | 3 +++
+ 3 files changed, 5 insertions(+), 2 deletions(-)
+
+commit fecce62a45d996fbca11cea6c34bdbadec283ba4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 13:13:43 2023 -0700
+
+    [ft] Docs
+
+ src/hb-ft.cc | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit cb509d9c894a8b9aa586eebf896526578fdd8822
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 13:11:48 2023 -0700
+
+    [face] Docs
+
+ src/hb-face.cc | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 8a2efbd8a113ec885b3a437c014912ca9ee22460
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 13:10:36 2023 -0700
+
+    [upem] More docs
+
+ src/hb-face.cc | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit ccffce58cc5bcb07d82b2085a3ebb42ea04b2579
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 13:09:30 2023 -0700
+
+    [scale] More docs
+
+ src/hb-font.cc | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+commit c4580d8670218c750e9c8e058b4e10841526acd0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 12:56:02 2023 -0700
+
+    [scale] More docs
+
+ src/hb-font.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit f0e695a3a96cc2396c47a2a29966a8e0f9f682cb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 12:55:17 2023 -0700
+
+    [scale] Comment
+
+ src/hb-font.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 8c47580ac85b3eed0b932d50236d589e8c8747cf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 12:53:54 2023 -0700
+
+    [scale] Document
+
+ src/hb-font.cc | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+commit 8b17c6ca302e969ab285e0ea7da067cfe6a1a27d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 12:17:38 2023 -0700
+
+    [aat] Comment
+
+ src/hb-aat-layout-common.hh     | 1 +
+ src/hb-aat-layout-morx-table.hh | 1 +
+ 2 files changed, 2 insertions(+)
+
+commit 0e11d317ee329f1c6afd8473e0f8a2daa6b91e25
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 12:16:04 2023 -0700
+
+    [aat] Optimize feature application
+
+ src/hb-aat-layout-common.hh     | 3 ++-
+ src/hb-aat-layout-morx-table.hh | 3 ++-
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+commit 4ee60941140924f7247bf8dc7720fa1bf43a5bff
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 11:52:12 2023 -0700
+
+    [aat] Add test for feature range
+
+ test/shape/data/in-house/tests/macos.tests | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+commit a70543daf3f5f88c0bb4d1fc1515a9c0803297fc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 11:49:48 2023 -0700
+
+    [aat] Always unsafe-to-concat in state machine
+
+ src/hb-aat-layout-common.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 62383315fafd973415fa9ea9454f7a1db34b2d4c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 11:29:04 2023 -0700
+
+    [aat] Try fix leak on memory allocation failure
+
+ src/hb-aat-layout-morx-table.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit e122fe2acfde26b8b95ee96ebd7a33f20c02c77c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 11:06:20 2023 -0700
+
+    [aat] Adjust last range
+    
+    Otherwise a user cluster value of -1 would have tripped us.
+
+ src/hb-aat-map.cc | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit e28c158c35081c1f412f8d2dd10471fae360a574
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 11:03:38 2023 -0700
+
+    [aat] Run subtable across ranges if flags match
+
+ src/hb-aat-layout-common.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 2c9c49fd3289b7c27135f8379b92f413c6f5f1f0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 10:53:21 2023 -0700
+
+    [aat] Support ranges in NonContextual subtable as well
+
+ src/hb-aat-layout-common.hh     |  1 -
+ src/hb-aat-layout-morx-table.hh | 17 +++++++++++++++++
+ 2 files changed, 17 insertions(+), 1 deletion(-)
+
+commit c08308a83ca3c1c24a7013df976c3d753c633d56
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 9 21:42:19 2023 -0700
+
+    [aat] Always generate a feature range
+
+ src/hb-aat-map.cc | 127 +++++++++++++++++++++++++++---------------------------
+ 1 file changed, 64 insertions(+), 63 deletions(-)
+
+commit db4c87475867bea79069132544b736c19895cfe2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 9 21:32:15 2023 -0700
+
+    Revert "Revert "[aat] Support feature ranges""
+    
+    This reverts commit 6a7a38521f940216f1e9e2fa2bf22f7b45ce2aef.
+
+ src/hb-aat-layout-common.hh     | 105 +++++++++++++++++++++------------
+ src/hb-aat-layout-kerx-table.hh |   4 +-
+ src/hb-aat-layout-morx-table.hh |  27 +++++----
+ src/hb-aat-layout.cc            |  14 ++++-
+ src/hb-aat-layout.hh            |   4 +-
+ src/hb-aat-map.cc               | 125 ++++++++++++++++++++++++++++++----------
+ src/hb-aat-map.hh               |  45 +++++++++++----
+ src/hb-ot-shape.cc              |  43 +++-----------
+ src/hb-ot-shape.hh              |   2 -
+ 9 files changed, 239 insertions(+), 130 deletions(-)
+
+commit 0728098e454bb4adfb2fa9a3dc824c75a653d0d6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 10 10:18:29 2023 -0700
+
+    [Coverage] Speed up subset for too-large Coverage tables
+    
+    Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=54980
+
+ src/OT/Layout/Common/Coverage.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 8460909e0c8e6d045550fd50206946ee15ad48bd
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Jan 10 17:43:10 2023 +0200
+
+    [build] Fix make dist
+
+ test/api/Makefile.am | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 6a7a38521f940216f1e9e2fa2bf22f7b45ce2aef
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 9 21:29:19 2023 -0700
+
+    Revert "[aat] Support feature ranges"
+    
+    This reverts commit 1b7994cb3a3c35f3618d7f40c7289496bdab6f06.
+    
+    Broke Zapfino with partial ligature disabling. Debugging.
+
+ src/hb-aat-layout-common.hh     | 105 ++++++++++++---------------------
+ src/hb-aat-layout-kerx-table.hh |   4 +-
+ src/hb-aat-layout-morx-table.hh |  27 ++++-----
+ src/hb-aat-layout.cc            |  14 +----
+ src/hb-aat-layout.hh            |   4 +-
+ src/hb-aat-map.cc               | 125 ++++++++++------------------------------
+ src/hb-aat-map.hh               |  45 ++++-----------
+ src/hb-ot-shape.cc              |  43 +++++++++++---
+ src/hb-ot-shape.hh              |   2 +
+ 9 files changed, 130 insertions(+), 239 deletions(-)
+
+commit adfd5dd7a9df70f76e777627c7a0f44e89f5b0c4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 9 21:18:12 2023 -0700
+
+    Fix TINY build
+
+ src/hb-ot-shape.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 1b7994cb3a3c35f3618d7f40c7289496bdab6f06
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 9 19:38:50 2023 -0700
+
+    [aat] Support feature ranges
+    
+    The hard way...
+    
+    A bit uglier than I liked it to be, but is proper at least.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4020
+
+ src/hb-aat-layout-common.hh     | 105 +++++++++++++++++++++------------
+ src/hb-aat-layout-kerx-table.hh |   4 +-
+ src/hb-aat-layout-morx-table.hh |  27 +++++----
+ src/hb-aat-layout.cc            |  14 ++++-
+ src/hb-aat-layout.hh            |   4 +-
+ src/hb-aat-map.cc               | 125 ++++++++++++++++++++++++++++++----------
+ src/hb-aat-map.hh               |  45 +++++++++++----
+ src/hb-ot-shape.cc              |  43 +++-----------
+ src/hb-ot-shape.hh              |   2 -
+ 9 files changed, 239 insertions(+), 130 deletions(-)
+
+commit 622a68695256d8505517ed58885b94b8520efe07
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 9 18:14:40 2023 -0700
+
+    Revert "Revert "Revert "[aat] Allow disable feature ranges"""
+    
+    This reverts commit 5202053c2c5fb2c8af9704e690b25a26bf2a0295.
+
+ src/hb-aat-layout-common.hh     | 12 +++---------
+ src/hb-aat-layout-kerx-table.hh |  4 ++--
+ src/hb-aat-layout-morx-table.hh | 38 ++++++++++++++------------------------
+ src/hb-aat-layout.cc            |  8 +++-----
+ src/hb-aat-layout.hh            |  3 +--
+ src/hb-aat-map.cc               |  8 +++-----
+ src/hb-aat-map.hh               | 17 ++++-------------
+ src/hb-ot-shape.cc              | 12 +++---------
+ 8 files changed, 33 insertions(+), 69 deletions(-)
+
+commit 0f01a8362221129729553b3b0f87bff812b32d14
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Jan 10 01:09:44 2023 +0000
+
+    [subset] add basic test for CFF2 subsetting.
+    
+    FontTools does not yet support CFF2 subsetting so we can't add a comparison test. Instead add a golden file test.
+
+ test/api/fonts/AdobeVFPrototype.abc.static.otf | Bin 0 -> 86112 bytes
+ test/api/meson.build                           |   9 ++-
+ test/api/test-instance-cff2.c                  |  75 +++++++++++++++++++++++++
+ 3 files changed, 83 insertions(+), 1 deletion(-)
+
+commit 5202053c2c5fb2c8af9704e690b25a26bf2a0295
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 9 17:29:43 2023 -0700
+
+    Revert "Revert "[aat] Allow disable feature ranges""
+    
+    This reverts commit 82b3e8af69b09fd908d1cd27b669234328d4a500.
+    
+    Another try.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4020
+
+ src/hb-aat-layout-common.hh     | 12 +++++++++---
+ src/hb-aat-layout-kerx-table.hh |  4 ++--
+ src/hb-aat-layout-morx-table.hh | 38 ++++++++++++++++++++++++--------------
+ src/hb-aat-layout.cc            |  8 +++++---
+ src/hb-aat-layout.hh            |  3 ++-
+ src/hb-aat-map.cc               |  8 +++++---
+ src/hb-aat-map.hh               | 17 +++++++++++++----
+ src/hb-ot-shape.cc              | 12 +++++++++---
+ 8 files changed, 69 insertions(+), 33 deletions(-)
+
+commit 82b3e8af69b09fd908d1cd27b669234328d4a500
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 9 17:28:52 2023 -0700
+
+    Revert "[aat] Allow disable feature ranges"
+    
+    This reverts commit 24a4d397bae6b614215086c85a714dc789af3e7f.
+    
+    This was broken.
+
+ src/hb-aat-layout-common.hh     | 12 +++---------
+ src/hb-aat-layout-kerx-table.hh |  4 ++--
+ src/hb-aat-layout-morx-table.hh | 40 +++++++++++++++-------------------------
+ src/hb-aat-layout.cc            |  7 +++----
+ src/hb-aat-layout.hh            |  3 +--
+ src/hb-aat-map.cc               |  8 +++-----
+ src/hb-aat-map.hh               | 17 ++++-------------
+ src/hb-ot-shape.cc              | 12 +++---------
+ 8 files changed, 34 insertions(+), 69 deletions(-)
+
+commit 24a4d397bae6b614215086c85a714dc789af3e7f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 9 17:26:08 2023 -0700
+
+    [aat] Allow disable feature ranges
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4020
+    
+    This is a hack.
+    
+    To implement this properly we need to treat runs with different features
+    as independent runs for running the state machine, as the subtable flags
+    might be different. That would be a significant change to our internal
+    implementation.
+
+ src/hb-aat-layout-common.hh     | 12 +++++++++---
+ src/hb-aat-layout-kerx-table.hh |  4 ++--
+ src/hb-aat-layout-morx-table.hh | 40 +++++++++++++++++++++++++---------------
+ src/hb-aat-layout.cc            |  7 ++++---
+ src/hb-aat-layout.hh            |  3 ++-
+ src/hb-aat-map.cc               |  8 +++++---
+ src/hb-aat-map.hh               | 17 +++++++++++++----
+ src/hb-ot-shape.cc              | 12 +++++++++---
+ 8 files changed, 69 insertions(+), 34 deletions(-)
+
+commit b20871322f02415e5d336ee1807d2c2175c7c07b
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Jan 9 16:30:25 2023 -0500
+
+    test-paint: Fix use of g_test_skip
+
+ test/api/test-paint.c | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+commit 3ff713ab80a4fd8c8de168863eaffae9cd410c81
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 9 13:59:50 2023 -0700
+
+    [coretext] Remove unused variable
+
+ src/hb-coretext.cc | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 414848755696ff47e65b614f5201cbf9f5de15eb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 9 13:47:59 2023 -0700
+
+    [ft] Comment
+
+ src/hb-ft.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit d2aa2397bae6a6550060686da4cad1426eb2ad1f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 9 13:43:56 2023 -0700
+
+    Optimize non-slant extents code
+
+ src/hb-font.hh | 7 +++++--
+ src/hb-ft.cc   | 7 +++++--
+ 2 files changed, 10 insertions(+), 4 deletions(-)
+
+commit 73dab7f784856b44f9f8f97f354e4286ac2e03e9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 9 13:36:55 2023 -0700
+
+    [ft] Fix slanting code
+
+ src/hb-ft.cc | 18 ++++++++++++------
+ 1 file changed, 12 insertions(+), 6 deletions(-)
+
+commit eb0f0279d2bd31045e58711b75dc70fe0946d2bc
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Jan 9 15:33:34 2023 -0500
+
+    test-paint: Avoid g_test_skip_printf
+    
+    This is relatively recent api we don't need.
+
+ test/api/test-paint.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+commit e61c2be41cadd2ef304d1d47777618d2da2e1726
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Jan 9 15:25:29 2023 -0500
+
+    test-paint: Skip tests if ft COLRv1 is missing
+
+ test/api/test-paint.c | 17 ++++++++++++-----
+ 1 file changed, 12 insertions(+), 5 deletions(-)
+
+commit 1d662632d961ab588b35ad8a33d4ff85b5c465a1
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Jan 9 15:01:59 2023 -0500
+
+    test-paint: More output for failures
+
+ test/api/test-paint.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 64e3f53fc238443cbbf96f0ba16941093757a76c
+Merge: 027515149 d0108d31a
+Author: Matthias Clasen <matthias.clasen@gmail.com>
+Date:   Mon Jan 9 14:43:33 2023 -0500
+
+    Merge pull request #4015 from harfbuzz/more-paint-tests
+    
+    Add more paint tests
+
+commit d0108d31a283a8bb3a4dd61696b416059346050b
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Jan 8 11:20:21 2023 -0500
+
+    Add more paint tests
+    
+    These tests compare the output of the ft and ot
+    implementations for all the glyphs in the test_glyphs
+    font.
+
+ test/api/results/bad-154   |  10 ++++
+ test/api/results/hand-10   |   2 +-
+ test/api/results/hand-10.2 |   2 +-
+ test/api/results/rocher-1  |   2 +-
+ test/api/results/rocher-2  |   2 +-
+ test/api/results/rocher-3  |   2 +-
+ test/api/results/test-10   |   2 +-
+ test/api/results/test-106  |   2 +-
+ test/api/results/test-116  |   2 +-
+ test/api/results/test-123  |   2 +-
+ test/api/results/test-165  |   2 +-
+ test/api/results/test-175  |   2 +-
+ test/api/results/test-6    |   2 +-
+ test/api/results/test-92   |   2 +-
+ test/api/test-paint.c      | 124 +++++++++++++++++++++++++++++++++++----------
+ 15 files changed, 121 insertions(+), 39 deletions(-)
+
+commit 0275151490902461d2680056820b766c7d39c208
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 9 12:26:39 2023 -0700
+
+    [paint] Align deptch/edge count conditions across two backends
+
+ src/OT/Color/COLR/COLR.hh | 4 ++--
+ src/hb-ft-colr.hh         | 3 +--
+ 2 files changed, 3 insertions(+), 4 deletions(-)
+
+commit 5f976d86a7a24cfe186129294d4779cd1fe67d8c
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Jan 9 13:42:22 2023 -0500
+
+    test-paint: Use %.3g for results
+    
+    This produces more readable output.
+
+ test/api/results/bad-154   | 132 ++++++++++++++++++++++-----------------------
+ test/api/results/hand-10   |  90 +++++++++++++++----------------
+ test/api/results/hand-10.2 |  90 +++++++++++++++----------------
+ test/api/results/rocher-1  |   2 +-
+ test/api/results/rocher-2  |   2 +-
+ test/api/results/rocher-3  |   2 +-
+ test/api/results/test-10   |  22 ++++----
+ test/api/results/test-106  |  20 +++----
+ test/api/results/test-116  |  16 +++---
+ test/api/results/test-123  |  30 +++++------
+ test/api/results/test-165  |  22 ++++----
+ test/api/results/test-175  |  28 +++++-----
+ test/api/results/test-6    |  20 +++----
+ test/api/results/test-92   |  20 +++----
+ test/api/test-paint.c      |  52 +++++++++---------
+ 15 files changed, 271 insertions(+), 277 deletions(-)
+
+commit ec78a486bf4f81ce3bacf1f10558443c64483344
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Jan 9 13:38:19 2023 -0500
+
+    Run paint tests at upem scale
+    
+    This avoids problems with rouding.
+
+ test/api/results/bad-154   |  2 +-
+ test/api/results/hand-10   | 44 ++++++++++++++++++++++++--------------------
+ test/api/results/hand-10.2 | 42 +++++++++++++++++++++---------------------
+ test/api/results/rocher-1  |  2 +-
+ test/api/results/rocher-2  |  2 +-
+ test/api/results/rocher-3  |  2 +-
+ test/api/results/test-10   |  2 +-
+ test/api/results/test-106  |  2 +-
+ test/api/results/test-116  |  2 +-
+ test/api/results/test-123  |  2 +-
+ test/api/results/test-165  |  2 +-
+ test/api/results/test-175  |  2 +-
+ test/api/results/test-6    |  2 +-
+ test/api/results/test-92   |  2 +-
+ 14 files changed, 57 insertions(+), 53 deletions(-)
+
+commit 839f4b64941be2e4a6f1ec5325fe5ee8def11277
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 9 12:01:46 2023 -0700
+
+    [ft] Fix slanting clip box
+
+ src/hb-ft-colr.hh | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+commit 30adbc22d9a93d825ff9418eacf16737379a6987
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 9 11:54:44 2023 -0700
+
+    hb-font: Fix scale_glyph_extents() again
+    
+    And better fix this time.
+
+ src/hb-font.hh | 18 ++++++++++++------
+ 1 file changed, 12 insertions(+), 6 deletions(-)
+
+commit 6c1a4bed4a94619898052bfe3bd03e1dfb71806f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 9 11:37:39 2023 -0700
+
+    Better rounding clip boxes
+
+ src/hb-font.hh    | 4 ++--
+ src/hb-ft-colr.hh | 4 ++--
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit a085efa69922784850ef4ae68e6b43bf933d3d6d
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Jan 9 13:11:16 2023 -0500
+
+    test-paint: Fix font setup for ft
+    
+    We must call hb_ft_font_set_funcs after
+    setting the font scale.
+
+ test/api/test-paint.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 26f713a7f5bed1c0543e070473008bd6ff065233
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Jan 9 12:54:06 2023 -0500
+
+    paint-test: Use larger scales
+    
+    A scale of 20 is noise, so use 1000.
+
+ test/api/results/{bad-20-0-154 => bad-154}      | 134 ++++++++++++------------
+ test/api/results/{hand-20-0.2-10 => hand-10}    |  48 ++++-----
+ test/api/results/{hand-20-0-10 => hand-10.2}    |  46 ++++----
+ test/api/results/{rocher-120-0.3-1 => rocher-1} |   4 +
+ test/api/results/{rocher-120-0.3-2 => rocher-2} |   4 +
+ test/api/results/{rocher-120-0-3 => rocher-3}   |   4 +
+ test/api/results/{test-20-0-10 => test-10}      |  14 +--
+ test/api/results/{test-20-0-106 => test-106}    |  18 ++--
+ test/api/results/test-116                       |  26 +++++
+ test/api/results/{test-20-0-123 => test-123}    |  22 ++--
+ test/api/results/{test-20-0-165 => test-165}    |  14 +--
+ test/api/results/{test-20-0-175 => test-175}    |  18 ++--
+ test/api/results/test-20-0-116                  |  26 -----
+ test/api/results/{test-20-0-6 => test-6}        |  14 +--
+ test/api/results/{test-20-0-92 => test-92}      |  14 +--
+ test/api/test-paint.c                           |  28 ++---
+ 16 files changed, 221 insertions(+), 213 deletions(-)
+
+commit e886b6b8a6f165c57498760e3e8a3e40dfcec4b7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 9 10:26:01 2023 -0700
+
+    [test-draw] Use a larger scale
+    
+    A scale of 20 is in the noise category for us. Using a larger
+    scale makes the test pass.
+
+ test/api/test-draw.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 347910fd4c7fe9327e45d3cef02a184b486eb710
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Jan 8 20:06:24 2023 -0500
+
+    Add a draw test
+    
+    This test compares output between ft and ot
+    font funcs.
+
+ test/api/test-draw.c | 36 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+commit f46dcf147b0bc8be6e8d78093a049aaec01089b8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 8 14:33:54 2023 -0700
+
+    [paint/COLR] Fix clip transform
+    
+    Sigh. So complicated.
+
+ src/OT/Color/COLR/COLR.hh | 13 +++----------
+ 1 file changed, 3 insertions(+), 10 deletions(-)
+
+commit 42047070ddec3d8182fd7591d3a97e2b16aef4b3
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Jan 8 16:08:16 2023 -0500
+
+    test-paint: More helpful output
+    
+    No need to print ASCII chars as hex.
+
+ test/api/test-paint.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f283d4d366e1c10ec7e7a89b468911b00d948b9d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 8 12:42:34 2023 -0700
+
+    [paint] Try to adjust both renderers to use same clip order
+
+ src/OT/Color/COLR/COLR.hh | 20 ++++++++++++++------
+ src/hb-ft-colr.hh         |  1 -
+ 2 files changed, 14 insertions(+), 7 deletions(-)
+
+commit 3fd6c0d97aa33758005a45a3c8d8bd98f8e79df8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 8 12:30:26 2023 -0700
+
+    [test-paint] Remove unused FT_Library
+
+ test/api/test-paint.c | 8 --------
+ 1 file changed, 8 deletions(-)
+
+commit 28be4f8805f2f69167930f30b9e4c27fc84429ea
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 8 12:19:41 2023 -0700
+
+    [test-paint] Actually run against hb-ft
+
+ test/api/test-paint.c | 49 ++++++++-----------------------------------------
+ 1 file changed, 8 insertions(+), 41 deletions(-)
+
+commit ed7d0234e12aa82f60b9e37a823d55cfc8805c3d
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Jan 8 11:47:19 2023 -0500
+
+    test-paint: Limit the precision of clip boxes
+    
+    Update expected test results.
+
+ test/api/results/bad-20-0-154   | 6 +++++-
+ test/api/results/hand-20-0-10   | 6 +++++-
+ test/api/results/hand-20-0.2-10 | 6 +++++-
+ test/api/results/test-20-0-10   | 6 +++++-
+ test/api/results/test-20-0-106  | 4 ++--
+ test/api/results/test-20-0-116  | 4 ++--
+ test/api/results/test-20-0-123  | 6 +++++-
+ test/api/results/test-20-0-165  | 6 +++++-
+ test/api/results/test-20-0-175  | 6 +++++-
+ test/api/results/test-20-0-6    | 6 +++++-
+ test/api/results/test-20-0-92   | 6 +++++-
+ test/api/test-paint.c           | 2 +-
+ 12 files changed, 50 insertions(+), 14 deletions(-)
+
+commit 5d94eb61b883eb194bd952d6d5c552a614c68c19
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 8 11:55:13 2023 -0700
+
+    [hb-cairo] Fix hb_cairo_glyphs_from_buffer() when utf8 missing
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4016
+
+ src/hb-cairo.cc | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 10390ec5c6b6a133f5dcf3a2908249f6c7b40ef6
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Jan 8 09:06:03 2023 -0500
+
+    Update expected test results
+
+ test/api/results/test-20-0-106 | 12 ++++++++----
+ test/api/results/test-20-0-116 | 12 ++++++++----
+ 2 files changed, 16 insertions(+), 8 deletions(-)
+
+commit f3ce137420721cb689179afadae812011739a129
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Jan 8 09:01:31 2023 -0500
+
+    test-paint: Be more flexible for expected results
+    
+    When generating the expected output with GENERATE_DATA=1,
+    Glib's test framework puts out some comments at the top
+    of the file. Ignore them when comparing the expected
+    output. This makes it possible to directly use the output
+    of
+    
+    GENERATE_DATA=1 ./test-paint -p TESTCASE
+    
+    as expected result for TESTCASE.
+
+ test/api/test-paint.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+commit 5bd6fc1acedfc17b65262f6a96ab3aa282852df7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 7 16:32:50 2023 -0700
+
+    Comment
+
+ src/OT/Color/COLR/COLR.hh | 4 ++--
+ src/hb-ft-colr.hh         | 1 +
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+commit 432afa9dffd17df382b17c473e5c4d8199cdf8a4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 7 16:25:30 2023 -0700
+
+    [paint] Fix paint_extents usage
+    
+    It was broken all this time :(.
+    
+    The two backends do this slightly differently...
+
+ src/OT/Color/COLR/COLR.hh | 13 +++----------
+ src/hb-ft-colr.hh         |  3 +++
+ 2 files changed, 6 insertions(+), 10 deletions(-)
+
+commit a63d329261b552126f1bae67ef175bb9a7e0cd90
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 7 16:05:24 2023 -0700
+
+    [paint-extents] Simplify transform_extents
+
+ src/hb-paint-extents.hh | 13 +++----------
+ 1 file changed, 3 insertions(+), 10 deletions(-)
+
+commit e062f982600c8e275931c7666f9658c78ea67b4e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 7 16:02:21 2023 -0700
+
+    [paint-extents] Fix transform_extents
+    
+    Ouch!
+
+ src/hb-paint-extents.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 70ca146033dd513b91468c53ff3f89d03b277f09
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 7 15:48:57 2023 -0700
+
+    [chafa] Re-enable truecolor mode
+    
+    See 42bf8e3d49
+    https://github.com/harfbuzz/harfbuzz/pull/2959#issuecomment-827056111
+
+ util/helper-cairo-ansi.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 823a9b18d93cb8a7520d175da7834de1bcd62891
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 7 14:49:02 2023 -0700
+
+    [cairo] Return COMPOSITE mode CLEAR for unknown values
+    
+    As per the spec.
+
+ src/hb-cairo-utils.hh | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+commit d0aaea2319a3c32e129c58bf5b3464409ab83df7
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Jan 7 16:27:13 2023 -0500
+
+    Update test results for paint-test
+    
+    These were affected by the PaintComposite optimization.
+
+ test/api/results/bad-20-0-154  | 620 ++++++++++++++++++-----------------------
+ test/api/results/test-20-0-106 |  38 ++-
+ test/api/results/test-20-0-116 |  34 ++-
+ test/api/results/test-20-0-123 |  38 ++-
+ 4 files changed, 330 insertions(+), 400 deletions(-)
+
+commit 65c3cde5dac3c64f24dd1837daad494d63b78960
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 7 14:29:18 2023 -0700
+
+    [COLRv1] Fix scale variation
+
+ src/OT/Color/COLR/COLR.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 004cdc10f87d7259a7192706c2996f9a9d0a26ed
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 7 14:27:15 2023 -0700
+
+    [open-type] More tweaks to fixed types
+    
+    Add set_int().
+
+ src/hb-open-type.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit c8486b63019e77257a9d30361a9fdc5f2eaaa837
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 7 14:15:17 2023 -0700
+
+    [open-type] Add to_int to fixed types
+    
+    To make sure we don't accidentally forget to_float().
+    As we did recently in COLRv1 code.
+
+ src/OT/glyf/VarCompositeGlyph.hh | 14 +++++++-------
+ src/hb-open-type.hh              |  3 +++
+ src/hb-ot-layout-common.hh       | 10 +++++-----
+ src/hb-ot-var-avar-table.hh      |  4 ++--
+ src/hb-ot-var-fvar-table.hh      |  8 ++++----
+ src/hb-ot-var-gvar-table.hh      |  6 +++---
+ 6 files changed, 24 insertions(+), 21 deletions(-)
+
+commit dfd9bf8a50f9597e55e7811dc0c6c237546e6aef
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 7 14:05:02 2023 -0700
+
+    [COLRv1] Fix a couple of missing to_float() calls
+    
+    Ouch!
+
+ src/OT/Color/COLR/COLR.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit d045de78c1ff7b32f3d7082591f4112d1f8f796a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 7 13:55:17 2023 -0700
+
+    [paint] Optimize PAINT_COMPOSITE
+    
+    At the start of each paint call the current group is clear.
+    So we don't need to start a new group for the backdrop paint.
+    
+    A paint composite really needs one group push, not two.
+
+ src/OT/Color/COLR/COLR.hh | 2 --
+ src/hb-ft-colr.hh         | 2 --
+ 2 files changed, 4 deletions(-)
+
+commit 5ea5aacda9d14833a66e9d9869c69eda0bb4034a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jan 7 13:24:41 2023 -0700
+
+    [ft-colr] Adjust for FreeType master color-stop change
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/4013
+
+ src/hb-ft-colr.hh | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit 1eb5445e7575c828c552a914708ca1650f146377
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Jan 6 15:19:16 2023 -0800
+
+    [subset] Fix issue in hb_subset_input_override_name_table()
+    
+    If a nameRecord with provided name_id/platform_id/encoding_id/lang_id
+    is not retained after subsetting, create it and insert it to
+    the name table. So we need to check against retained name_records
+    rather than name_record in the original name table.
+
+ src/hb-ot-name-table.hh        | 28 +++++++++++-----------------
+ test/api/test-subset-nameids.c |  2 +-
+ 2 files changed, 12 insertions(+), 18 deletions(-)
+
+commit 30d4a7347387a1e3e0bd7db3f5159ba42c89e642
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 6 16:00:53 2023 -0700
+
+    [hb-subset] Adjust help for instancing
+
+ util/hb-subset.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3bcf153ad8dba1dc518b61ac3f19b865d8508b80
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 6 15:51:13 2023 -0700
+
+    Change library numbering scheme
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/1431
+
+ configure.ac | 2 +-
+ meson.build  | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 02948263f9a9ab8ef28078e69ed349e2d89b301d
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Jan 6 22:53:19 2023 +0200
+
+    [subset] Document that CFF2 instancing is now supported
+
+ src/hb-subset-input.cc | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit aba6cbe867ce1bf23673d44baef820e35001f487
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 6 13:09:10 2023 -0700
+
+    [hb-subset] Adjust --help-all formatting
+    
+    Meh.
+
+ util/hb-subset.cc | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+commit 82c863a50b9de8df7094b7267b50b4e191c03de8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 6 12:51:58 2023 -0700
+
+    Whitespace
+
+ src/hb-ot-os2-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 76879c5763643bf83680efbc610fede3d9faab00
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 6 11:47:04 2023 -0700
+
+    [subset-cff] Minor hide num_coords again
+
+ src/hb-cff2-interp-cs.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 576b36a31b6623092e5ff36f632390198a57d1b5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 6 11:40:21 2023 -0700
+
+    [cff2] Undo rounding change in draw() codepath
+
+ src/hb-cff2-interp-cs.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4867e0b192b1efcc28e12bfd8f997ca9377d65ce
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 6 11:39:13 2023 -0700
+
+    [subset-cff2] Faster instancing
+    
+    Instantiate blends during parsing. Dedups code as well.
+
+ src/hb-cff2-interp-cs.hh | 12 +++++++-----
+ src/hb-subset-cff2.cc    | 37 +------------------------------------
+ 2 files changed, 8 insertions(+), 41 deletions(-)
+
+commit 3757baab2c039d1cad959ffc4ead4e746cc52960
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 6 11:23:37 2023 -0700
+
+    [subset-cff2] Better condition
+    
+    Previous condition wasn't working for dropping axes.
+
+ src/hb-subset-cff2.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit acc6c13f05c0c43ffa3e3e1053626ca4186428a5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 6 11:20:41 2023 -0700
+
+    [subset-cff] Round numbers when instancing
+
+ src/hb-subset-cff2.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 2f174f23c38f5a14ec4c0535249b8b7ce247322f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 6 11:11:14 2023 -0700
+
+    Rename
+
+ src/hb-subset-cff2.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit a59116cd8f20e34a8cd7f5d1179ab7ba96aa4113
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 6 11:09:09 2023 -0700
+
+    Oops
+
+ src/hb-subset-plan.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c632a164b98de695b5cd3366689df8dd45021b6f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jan 6 11:01:25 2023 -0700
+
+    [subset/cff] Support instancing
+
+ src/hb-cff1-interp-cs.hh    |  3 ++-
+ src/hb-cff2-interp-cs.hh    |  2 ++
+ src/hb-subset-cff-common.hh |  9 +++++++--
+ src/hb-subset-cff2.cc       | 38 +++++++++++++++++++++++++++++++++++++-
+ src/hb-subset-plan.cc       |  6 ++++++
+ src/hb-subset-plan.hh       |  1 +
+ 6 files changed, 55 insertions(+), 4 deletions(-)
+
+commit 5153218b41a5984673900d080daf4e3273e1d117
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 16:26:41 2023 -0700
+
+    [set] Add hb_set_is_inverted()
+
+ docs/harfbuzz-sections.txt   |  1 +
+ src/hb-bit-set-invertible.hh |  5 +++++
+ src/hb-set.cc                | 16 ++++++++++++++++
+ src/hb-set.h                 |  3 +++
+ src/hb-set.hh                |  1 +
+ src/test-set.cc              |  3 ++-
+ 6 files changed, 28 insertions(+), 1 deletion(-)
+
+commit e8ac0ef2fd3cacccaf3bd5dec8a9cab324d13467
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 16:20:43 2023 -0700
+
+    [face] Minor rename a variable
+
+ src/hb-face.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 14ff7470248c4ed1bfddb846237514c56b7b59bb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 16:19:41 2023 -0700
+
+    [set] Add tests for inverted set range iteration
+
+ src/test-set.cc | 29 +++++++++++++++++++++++++++++
+ 1 file changed, 29 insertions(+)
+
+commit 381ac2fd78220b0ab521cfb0cc5b5f850e5c3964
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Jan 5 17:48:09 2023 -0500
+
+    docs: Fix a typo
+
+ src/hb-face.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 2764a6169141a09f354abedee39c3430179e90e6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 15:14:54 2023 -0700
+
+    Revert "[gsubgpos] Use swap instead of move"
+    
+    This reverts commit 8a17cc4ecf21f6754e2d90562d0ced7496870f74.
+
+ src/hb-ot-layout-gsubgpos.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 167b7c604603d8a70e15c89714fa601e59248f08
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 14:48:20 2023 -0700
+
+    Revert "[gsubgpos] Reduce hb_set_t allocations"
+    
+    This reverts commit 0b7f6d6cf0e2deba637783ab3880fdfb90ca8ac3.
+    
+    Not much benefit as the main allocations come from other places.
+
+ src/hb-ot-layout-gsubgpos.hh | 9 +--------
+ 1 file changed, 1 insertion(+), 8 deletions(-)
+
+commit 3947cedd09a2386be5774400ac0b582d8173d078
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 14:47:47 2023 -0700
+
+    Revert "[gsubgpos] Cache pos_glyphs allocation in closure"
+    
+    This reverts commit 3961cc46bf438947b19063cb7e735247358f1d4f.
+    
+    This was wrong...
+
+ src/hb-ot-layout-gsubgpos.hh | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+commit 097fb8b8aa220e209c7673a5713def137c91924c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 14:38:10 2023 -0700
+
+    [priority-queue] Use resize instead of shrink
+    
+    To avoid reallocation of smaller array. Not desirable here.
+
+ src/hb-priority-queue.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 8a17cc4ecf21f6754e2d90562d0ced7496870f74
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 14:15:38 2023 -0700
+
+    [gsubgpos] Use swap instead of move
+    
+    Move is wrong when we want to reuse the object.
+
+ src/hb-ot-layout-gsubgpos.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4401dd24822a07332b271d700fbab8612da5de45
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 14:13:57 2023 -0700
+
+    [gsubgpos] Minor use ->clear() directly
+
+ src/hb-ot-layout-gsubgpos.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 207ae11ab9f539272cd1969461a1023658b6e4b7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 14:08:47 2023 -0700
+
+    [set] Allocate first page exact
+
+ src/hb-bit-set.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 0b7f6d6cf0e2deba637783ab3880fdfb90ca8ac3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 13:58:57 2023 -0700
+
+    [gsubgpos] Reduce hb_set_t allocations
+
+ src/hb-ot-layout-gsubgpos.hh | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+commit 3961cc46bf438947b19063cb7e735247358f1d4f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 13:58:57 2023 -0700
+
+    [gsubgpos] Cache pos_glyphs allocation in closure
+    
+    Saves some 3% in Gulzar-Regular subsetting.
+
+ src/hb-ot-layout-gsubgpos.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit a90f149e1b9ce1dfb1295465ddc3d49bda175383
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 13:52:11 2023 -0700
+
+    [gsubgpos] Minor drop an allocation
+
+ src/hb-ot-layout-gsubgpos.hh | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+commit c54debc76dc120a696f24e9fd3dc9a9c4829b928
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 11:54:06 2023 -0700
+
+    [face] Add hb_face_collect_nominal_glyph_mapping
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3973
+
+ docs/harfbuzz-sections.txt       |  1 +
+ src/hb-face.cc                   | 27 ++++++++++++++++++++++++---
+ src/hb-face.h                    |  6 ++++++
+ test/api/test-collect-unicodes.c | 12 ++++++++++++
+ 4 files changed, 43 insertions(+), 3 deletions(-)
+
+commit ec70a3f7975907a4fc413255eec3b645f0a67c81
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 11:52:12 2023 -0700
+
+    [map] Include
+
+ src/hb-map.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 8b12c195738024107d5a8308ac29170d3f716f1d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 11:42:21 2023 -0700
+
+    [face] Split hb-face-builder.cc
+
+ src/Makefile.sources   |   1 +
+ src/harfbuzz-subset.cc |   1 +
+ src/harfbuzz.cc        |   1 +
+ src/hb-face-builder.cc | 246 +++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-face.cc         | 212 ------------------------------------------
+ src/meson.build        |   1 +
+ 6 files changed, 250 insertions(+), 212 deletions(-)
+
+commit b0d9421b1100ca00ac66ff83297affd3e9926529
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 11:21:46 2023 -0700
+
+    [docs] Remove reference to 2.x.x
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4006
+
+ docs/harfbuzz-docs.xml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit dc7b3a627db66afe948610a46d0c4a9e7201464b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 10:49:10 2023 -0700
+
+    [test-map] Another test
+
+ src/test-map.cc | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit a8df5cb07ddb4b5c0054564858e063a8c35c9a15
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 10:47:31 2023 -0700
+
+    [test-map] Test keys() / values()
+
+ src/test-map.cc | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+commit a349eef6a6da1064368ab5c0c09123ed1b748c59
+Author: Konstantin Käfer <mail@kkaefer.com>
+Date:   Thu Jan 5 10:54:21 2023 +0100
+
+    Disable hb_paint_extents_* functions if HB_NO_PAINT is defined
+
+ src/hb-paint-extents.cc | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 9420966f5b8df976c4c1514fbd1346556980c907
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jan 5 10:17:24 2023 -0700
+
+    [map] Fix next()
+
+ src/hb-map.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 35f46e74d1126b3db6dd342399e90874171f7ac8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 4 17:12:08 2023 -0700
+
+    [map] Add hb_map_keys() and hb_map_values()
+
+ docs/harfbuzz-sections.txt |  2 ++
+ src/hb-machinery.hh        |  1 -
+ src/hb-map.cc              | 32 ++++++++++++++++++++++++++++++++
+ src/hb-map.h               |  8 ++++++++
+ src/hb-map.hh              | 12 ++++++++++++
+ src/hb-set.hh              |  5 +++++
+ src/hb-subset.hh           |  1 +
+ 7 files changed, 60 insertions(+), 1 deletion(-)
+
+commit 07f2d8d5384943445ca00c0e127de81d37539e65
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 4 15:42:56 2023 -0700
+
+    Comment
+
+ src/hb-buffer.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4f6079138d74c1958c6345de28a08a8816e0c4af
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 4 13:58:46 2023 -0700
+
+    [map] Add hb_map_update()
+
+ docs/harfbuzz-sections.txt |  1 +
+ src/hb-map.cc              | 16 ++++++++++++++++
+ src/hb-map.h               |  4 ++++
+ src/hb-map.hh              |  7 +++++++
+ src/test-map.cc            | 16 ++++++++++++++--
+ 5 files changed, 42 insertions(+), 2 deletions(-)
+
+commit c350458539ee16bb06fde317ad440cd3c8159471
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 4 13:25:03 2023 -0700
+
+    [subset-plan] Relax const return type of a few functions
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4003
+
+ src/hb-subset-plan.cc | 6 +++---
+ src/hb-subset.h       | 6 +++---
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+commit dbf0964a0ff2fd36730c4179ab7ec7e8f0bd11cb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 4 13:17:14 2023 -0700
+
+    [map] Doc
+
+ src/hb-map.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 0875a420f7e04a27971b6b69a3364ba3eff9ed0b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 4 13:11:37 2023 -0700
+
+    [map] Doc
+
+ src/hb-map.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit ffafcf9633eae1c679b8835a31e9b00dca740dde
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 4 12:55:59 2023 -0700
+
+    [map] Add hb_map_next()
+
+ docs/harfbuzz-sections.txt |  1 +
+ src/hb-map.cc              | 25 ++++++++++++++++++++++++-
+ src/hb-map.h               |  6 ++++++
+ src/hb-map.hh              | 24 ++++++++++++++++++++++++
+ src/test-map.cc            | 27 +++++++++++++++++++++++++++
+ 5 files changed, 82 insertions(+), 1 deletion(-)
+
+commit 3e471bbc0801d8fc0093d4e536633e6a89d4d32b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 4 11:53:49 2023 -0700
+
+    [vector] Better test
+
+ src/hb-vector.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 45fc919a10dc7d13ea386904bddb601512ba2f28
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 4 11:35:44 2023 -0700
+
+    [bit-set] Minor setting length on allocation failure
+
+ src/hb-bit-set.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d8509061e6167a7132c7d4aa414df65d95703ee6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 4 11:33:54 2023 -0700
+
+    [vector] It's okay if shrinking fails
+
+ src/hb-vector.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 6c272b920d14f34494a8415bad15e794be313fc5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 3 13:00:41 2023 -0700
+
+    [set] Don't discard allocation in operator=
+    
+    That had caused memory thrashing.
+    
+    Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=54789
+
+ src/hb-bit-set.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit e6bbf112ea05482e48136f910518f57b2b153256
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jan 3 12:35:48 2023 -0700
+
+    [buffer] Better document set_content_type
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/4000
+
+ src/hb-buffer.cc | 26 ++++++++++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+commit 8f2345ca365de26d3d4888c9087181ebccde29d4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 2 18:08:45 2023 -0700
+
+    Use more vector resize_exact
+
+ src/hb-bit-set.hh        | 7 ++-----
+ src/hb-cff2-interp-cs.hh | 6 ++----
+ 2 files changed, 4 insertions(+), 9 deletions(-)
+
+commit b6be4550209af5cf33f3d0a35602ca8edeafcc5d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 2 18:05:43 2023 -0700
+
+    [vector] Add resize_exact()
+
+ src/hb-subset-cff-common.hh | 21 +++++++--------------
+ src/hb-vector.hh            |  8 ++++++--
+ 2 files changed, 13 insertions(+), 16 deletions(-)
+
+commit a516ce97e03877389bdb60a62234302e19266894
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 2 17:58:51 2023 -0700
+
+    [subset-cff] Add a few exact-allocation calls
+
+ src/hb-subset-cff-common.hh | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+commit 4a435dc0243329a409d4c23ca0ec07ca19fea9cb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 2 17:41:31 2023 -0700
+
+    [subset-cff] Remove an unlikely
+
+ src/hb-subset-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f8c578fd93b22a144f5a28e504e629b8adcb3f5c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 2 17:33:04 2023 -0700
+
+    [subset-cff] Remove commented-out line
+
+ src/hb-subset-cff-common.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit d5e1748f31231d5283e6c006d4114c139f9d261b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 2 12:26:43 2023 -0700
+
+    [cff] Simplify add_op()
+
+ src/hb-cff-interp-common.hh | 12 +-----------
+ 1 file changed, 1 insertion(+), 11 deletions(-)
+
+commit 27531d853e36ba1050da6158d7349bdf85b0f9e2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 2 12:05:11 2023 -0700
+
+    [subset-cff] Move code around
+
+ src/hb-subset-cff-common.hh | 64 ++++++++++++++++++++++-----------------------
+ 1 file changed, 32 insertions(+), 32 deletions(-)
+
+commit 9afe5f973ea62957542830662f4c61d3ce795678
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 2 11:44:29 2023 -0700
+
+    [vector] Fix leak
+    
+    Discovered by https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=54767
+
+ src/hb-vector.hh | 21 ++++++++++++++++++---
+ 1 file changed, 18 insertions(+), 3 deletions(-)
+
+commit 4f013c42f0c0d87b068ff349fd96cb3dcff1831d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jan 2 10:38:30 2023 -0700
+
+    [subset-cff] Always compact charstrings
+    
+    Reduces non-preprocessed subsetting memory footprint significantly.
+
+ src/hb-subset-cff-common.hh | 19 ++++++++++++-------
+ 1 file changed, 12 insertions(+), 7 deletions(-)
+
+commit d3ed6eed437d3123195d436a43babfaab6266edf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 1 23:29:35 2023 -0700
+
+    [cff] Initialize a member variable
+    
+    For good hygiene.
+
+ src/hb-cff-interp-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 8ccc704c9af497cfeca5d58d80e42e043203c738
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Jan 2 18:14:55 2023 +0200
+
+    [ci/win32] Disable Cairo tests as well
+
+ .ci/build-win32.sh | 2 +-
+ .ci/build-win64.sh | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 5d81fc0f1cec0ddece4e083e9befa4c4b429c546
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Mar 23 06:07:15 2022 +0200
+
+    [meson] Update Cairo subproject
+    
+    Update to the latest master to get color fonts working. Disable dwrite
+    on Windows builds as it does not compile and we don’t need it.
+
+ .ci/build-win32.sh     | 1 +
+ .ci/build-win64.sh     | 1 +
+ subprojects/cairo.wrap | 4 ++--
+ 3 files changed, 4 insertions(+), 2 deletions(-)
+
+commit 55a7d81740fd4e932ac101cb0c869eaa384fedc3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 1 23:07:42 2023 -0700
+
+    [vector] Allocate exact size in operator=
+
+ src/hb-vector.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 449910d43118b6f935fa1231531cc16c072cd455
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 1 19:27:10 2023 -0700
+
+    [vector] Allocate exact size in constructor
+
+ src/hb-vector.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 4dda1f7881d7584598467efb641927b56230250b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 1 19:00:04 2023 -0700
+
+    [cff-subset] Compact charstrings just after parsing
+    
+    Massive peak-memory saving when processing face.
+
+ src/hb-subset-cff-common.hh | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+commit a7617c3cf194dfd5d2b96095f43915b60b41fb44
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 1 18:58:08 2023 -0700
+
+    [cff-subset] Drop hints just after parsing charstring
+    
+    In prep for next commit.
+
+ src/hb-subset-cff-common.hh | 36 ++++++++++++------------------------
+ 1 file changed, 12 insertions(+), 24 deletions(-)
+
+commit b1c4cb0caeae6c750c0cfd42fabb7fcb79ea30fd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 1 18:41:19 2023 -0700
+
+    [cff2] Use a shrink instead of resize
+    
+    Such that we can free the allocation.
+
+ src/hb-cff2-interp-cs.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b87360763ece0494951071793140c1e4336cf19b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 1 18:38:28 2023 -0700
+
+    [vector] Support shrinking storage if exact size provided
+    
+    Only do it if requested size is less than quarter of allocated size.
+    
+    This has massive benefit during CFF subset preprocessing.
+
+ src/hb-vector.hh | 33 +++++++++++++++++++++++++--------
+ 1 file changed, 25 insertions(+), 8 deletions(-)
+
+commit 1119e6029609e31cc7548ddfb7ac5ba2c3001f0c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 1 18:31:32 2023 -0700
+
+    [subset-cff] Tweak another storage allocation
+
+ src/hb-subset-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 85e8f2b53ff373abf108053201d31742f6b24a79
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 1 18:26:08 2023 -0700
+
+    [hb-subset] Initialize preprocess variable
+
+ util/hb-subset.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f0b5286b36fb9eb45bf53ee3a6e2d8b5ee807471
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 1 17:04:59 2023 -0700
+
+    [features] Sort
+
+ src/hb-features.h.in | 48 ++++++++++++++++++++++++------------------------
+ 1 file changed, 24 insertions(+), 24 deletions(-)
+
+commit 4a5bd7a9267973c134c3fe1198d8cf8cf94cb4f1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 1 16:53:28 2023 -0700
+
+    [subset] Add hb_subset_input_keep_everything()
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3998
+    
+    New API:
+    + hb_subset_input_keep_everything()
+
+ docs/harfbuzz-sections.txt |  1 +
+ src/hb-subset-input.cc     | 56 ++++++++++++++++++++++++++++++----------------
+ src/hb-subset.h            |  3 +++
+ util/hb-subset.cc          | 15 +++++++++++++
+ 4 files changed, 56 insertions(+), 19 deletions(-)
+
+commit d87add41b3ff6ce19cf387cf20542525e8237b14
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 1 16:27:26 2023 -0700
+
+    [hb-subset] Rename --preprocess-face to --preprocess
+    
+    Keep old name working but hidden.
+
+ util/hb-subset.cc | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 52110f13b02678c24daa3c1b588683a8fb13e125
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 1 16:22:02 2023 -0700
+
+    [subset-input] Refactor copy-pasta code
+
+ src/hb-subset-input.cc | 39 ++++++++++++++-------------------------
+ 1 file changed, 14 insertions(+), 25 deletions(-)
+
+commit 4adc748b13c3fdcb60162a269982590925750ce3
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Jan 1 09:46:11 2023 -0500
+
+    Move Color tables to src/OT/Color/
+
+ src/Makefile.sources                                   | 12 ++++++------
+ .../Color/CBDT/CBDT.hh}                                | 10 +++++-----
+ .../Color/COLR/COLR.hh}                                | 18 +++++++++---------
+ .../Color/COLR/colrv1-closure.hh}                      | 12 ++++++------
+ .../Color/CPAL/CPAL.hh}                                | 12 ++++++------
+ .../Color/sbix/sbix.hh}                                | 12 ++++++------
+ src/{hb-ot-color-svg-table.hh => OT/Color/svg/svg.hh}  | 12 ++++++------
+ src/hb-ot-color.cc                                     | 10 +++++-----
+ src/hb-ot-face.cc                                      |  6 +++---
+ src/hb-ot-font.cc                                      |  8 ++++----
+ src/hb-static.cc                                       |  2 +-
+ src/hb-subset-plan.cc                                  |  4 ++--
+ src/hb-subset.cc                                       |  8 ++++----
+ src/meson.build                                        | 10 +++++-----
+ 14 files changed, 68 insertions(+), 68 deletions(-)
+
+commit a5f1f3a05cc72a127ac29aa78c3b775ed4d63adc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jan 1 13:14:04 2023 -0700
+
+    [ft] Conditionalize all COLOR code on >= 2.11.1
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3994
+
+ src/hb-ft-colr.hh | 9 ---------
+ src/hb-ft.cc      | 6 ++++++
+ 2 files changed, 6 insertions(+), 9 deletions(-)
+
+commit dc5179d465e5d39a60897a4c8cf14da6c2f6fefa
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Jan 1 09:23:07 2023 -0500
+
+    Drop hb-ot-color-colr-table.cc
+    
+    Move everything into the .hh file.
+
+ src/Makefile.sources          |  1 -
+ src/harfbuzz-subset.cc        |  1 -
+ src/harfbuzz.cc               |  1 -
+ src/hb-ot-color-colr-table.cc | 27 ---------------------------
+ src/hb-ot-color-colr-table.hh | 26 ++++++++++++++++++++++++--
+ src/meson.build               |  1 -
+ 6 files changed, 24 insertions(+), 33 deletions(-)
+
+commit 27684f14be2a72b8aab863844931a980ace76db5
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sun Jan 1 00:41:55 2023 +0200
+
+    [introspection] Skip sources not usable with GObject Introspection
+    
+    There is no point in generating GIR for code interfacing with libraries
+    without introspection integration. This fixes spurious warnings on macOS
+    when g-ir-scanner mistakenly tries to scan system headers.
+
+ src/meson.build | 21 +++++++++++++--------
+ 1 file changed, 13 insertions(+), 8 deletions(-)
+
+commit 2bd09a99c1b1e84fe69c854f2b42cf9a55a006d8
+Merge: 3ff91c449 f60e7e3f8
+Author: Matthias Clasen <matthias.clasen@gmail.com>
+Date:   Sun Jan 1 10:30:40 2023 -0500
+
+    Merge pull request #3996 from harfbuzz/drop-unused-file
+    
+    Drop an unused file
+
+commit f60e7e3f8c91c81c21f401e654389767e182db41
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Jan 1 09:50:27 2023 -0500
+
+    Drop an unused file
+
+ src/hb-ot-color-colrv1-paint.hh | 286 ----------------------------------------
+ 1 file changed, 286 deletions(-)
+
+commit 3ff91c449f52d5cccdc24639a836d30878a62188
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 14:49:41 2022 -0700
+
+    [paint] Optimize transform operations again
+
+ src/hb-ft-colr.hh             | 46 +++++++++++-----------
+ src/hb-ot-color-colr-table.hh | 74 +++++++++++++++++------------------
+ src/hb-paint.hh               | 90 ++++++++++++++++---------------------------
+ 3 files changed, 94 insertions(+), 116 deletions(-)
+
+commit 1a0dd49f1ef09af11235645b65f32c65704bcae6
+Merge: edb812345 9f3b59fe6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 14:38:06 2022 -0700
+
+    Merge pull request #3991 from harfbuzz/paint-optimize-transform
+    
+    Paint optimize transform
+
+commit 9f3b59fe6b27e3f8c2a32a89263264ceaceaa5be
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 31 16:19:20 2022 -0500
+
+    Update expected test results
+    
+    These need updates, because they record
+    every callback, and we've changed what
+    callbacks are happening.
+
+ test/api/results/test-20-0-106 | 4 ++--
+ test/api/results/test-20-0-123 | 8 ++++----
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+commit edb812345a10a4eb737e2ab96578a49b533cddd7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 13:55:41 2022 -0700
+
+    [subset-cff] Another exact allocation
+
+ src/hb-subset-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 54dd01b86538f91dbbb75dab937bff01266fa4f8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 13:33:25 2022 -0700
+
+    [set] Use exact-allocation in copying
+    
+    Significantly reduces memory consumption.
+
+ src/hb-bit-set.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 2c64048bc4b91cc45427faa437ae8368a5443c5f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 13:26:00 2022 -0700
+
+    [subset] Another exact-allocation
+
+ src/hb-subset.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 0ec0214f10ee17786531d54416d4f006ff9c818b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 13:18:32 2022 -0700
+
+    [cff-subset] Adjust pre-allocation
+    
+    Reduces memory use significantly.
+
+ src/hb-cff-interp-common.hh | 2 +-
+ src/hb-subset-cff-common.hh | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit b88ca81814059c71c0361d741c70b71b652240b7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 12:51:28 2022 -0700
+
+    [paint-extents] Minor reorder
+
+ src/hb-paint-extents.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit 0c6a72133766240c13649a69e783e12ad30ae08d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 12:42:29 2022 -0700
+
+    [set] Another exact-size allocation
+
+ src/hb-bit-set.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit b803024cafc76a5f23c88b8f248e4d19125d7933
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 12:40:07 2022 -0700
+
+    [cff2] Another exact-size allocation
+
+ src/hb-cff2-interp-cs.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 3d4659beaad042fe0b3f0a750ced96e8ca361cb9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 12:38:58 2022 -0700
+
+    [cff2] Use exact-size vector allocation for blends
+
+ src/hb-cff2-interp-cs.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 92e5933ee6c6382ea168ee5fdd30d80cece131d1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 12:35:30 2022 -0700
+
+    [vector] A couple more exact-size allocations
+
+ src/hb-ot-name-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 2eacc37e08a07c2e79139056ae09c1047cbff5cd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 12:27:13 2022 -0700
+
+    [vector] Add internal API for exact-size allocation
+    
+    Use it from a couple of places.
+
+ src/OT/glyf/SimpleGlyph.hh   | 8 ++++----
+ src/OT/glyf/glyf.hh          | 2 +-
+ src/hb-ot-layout-gsubgpos.hh | 2 +-
+ src/hb-repacker.hh           | 2 +-
+ src/hb-serialize.hh          | 4 ++--
+ src/hb-vector.hh             | 6 +++---
+ 6 files changed, 12 insertions(+), 12 deletions(-)
+
+commit a0b46f3f6bd4be906cde1f8a7fab765690c13f2f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 12:15:14 2022 -0700
+
+    [machinery] Refactor shared code into a macro
+
+ src/hb-machinery.hh | 48 ++++++++++++++++--------------------------------
+ 1 file changed, 16 insertions(+), 32 deletions(-)
+
+commit ebb475bae7b8e7af300251e4fd2d14a56e292b90
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 12:11:14 2022 -0700
+
+    [multimap] Add consts
+
+ src/hb-multimap.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 9e3ff0e9f0078aa17d616ae9670a3843949a212d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 11:55:45 2022 -0700
+
+    [paint] Fixup
+
+ src/hb-ft-colr.hh             |  4 ++++
+ src/hb-ot-color-colr-table.hh | 13 +++++++++++--
+ 2 files changed, 15 insertions(+), 2 deletions(-)
+
+commit 6b47fcb17aa138d1c60e07516ce4323c9fe594cc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 11:40:12 2022 -0700
+
+    [paint] Add internal push_skew/pop_skew API
+
+ src/hb-ft-colr.hh             |  8 ++++----
+ src/hb-ot-color-colr-table.hh | 16 ++++++++--------
+ src/hb-paint.hh               | 17 +++++++++++++++++
+ 3 files changed, 29 insertions(+), 12 deletions(-)
+
+commit 46adf31b4c6ac45c213c7ac492f27a18de8e1af5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 11:35:39 2022 -0700
+
+    [paint] Add internal push_rotate/pop_rotate API
+
+ src/hb-ft-colr.hh             |  6 ++----
+ src/hb-ot-color-colr-table.hh | 12 ++++--------
+ src/hb-paint.hh               | 17 +++++++++++++++++
+ 3 files changed, 23 insertions(+), 12 deletions(-)
+
+commit ce7835124a741a75748b941ef1ff228e70437dfe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 11:32:15 2022 -0700
+
+    [paint] Add internal push_scale/pop_scale API
+
+ src/hb-ft-colr.hh             | 10 ++++------
+ src/hb-ot-color-colr-table.hh | 28 ++++++++++++----------------
+ src/hb-paint.hh               | 14 ++++++++++++++
+ 3 files changed, 30 insertions(+), 22 deletions(-)
+
+commit 7363eb373a14310a3d15b5a5889e4c158a55e533
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 11:24:42 2022 -0700
+
+    [paint] Add internal push_translate/pop_translate
+
+ src/hb-ft-colr.hh             | 63 +++++++++++++++----------------------------
+ src/hb-ot-color-colr-table.hh | 41 ++++++++++++++--------------
+ src/hb-paint.hh               | 14 ++++++++++
+ 3 files changed, 56 insertions(+), 62 deletions(-)
+
+commit df91677997c42cf5639718755267488af1389140
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 11:12:02 2022 -0700
+
+    [paint] Call internal API internally
+
+ src/hb-paint.hh | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+commit 99da0e6cc3433a86710c9ce6fec662afa677f03f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 11:04:40 2022 -0700
+
+    [paint] Avoid div-by-zero
+
+ src/hb-paint.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit 4e94b65cffe4b2308c2c74fc113a93d597602b0b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 10:53:40 2022 -0700
+
+    [paint-extents] Const-correctness
+
+ src/hb-paint-extents.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit f6dc4698ef4ea042dd4858fd32fd0916b779b954
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 10:52:32 2022 -0700
+
+    [paint-extents] Minor move variable
+
+ src/hb-paint-extents.hh | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+commit 4e7807a09028a27f0240e6b8cee879a848c96f99
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 10:50:30 2022 -0700
+
+    [paint-extents] Rename variable
+
+ src/hb-paint-extents.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit c86d1892ad32a6ef07ae0e67fe6e5deaaababc00
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 10:46:46 2022 -0700
+
+    [paint-extents] Move code around
+
+ src/hb-paint-extents.cc | 32 +++++++-------------------------
+ src/hb-paint-extents.hh | 18 ++++++++++++++++++
+ 2 files changed, 25 insertions(+), 25 deletions(-)
+
+commit d9a9bd8fa8feda041ef39f78085d314677842159
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 31 10:41:30 2022 -0700
+
+    [paint-extents] Add HB_UNUSED
+
+ src/hb-paint-extents.cc | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+commit 956ccb11a8e29289302ff85f76713ceb31cfecc7
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 31 10:14:37 2022 -0500
+
+    [docs] Add a section about rendering
+
+ docs/usermanual-fonts-and-faces.xml | 42 +++++++++++++++++++++++++++++++++++++
+ 1 file changed, 42 insertions(+)
+
+commit 63cd1cce67c8459696cf49c53aad5e4f1830ccb7
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 31 08:56:12 2022 -0500
+
+    [docs] Drop stale commented-out section
+    
+    Freetype integration is documented elsewhere now.
+
+ docs/usermanual-fonts-and-faces.xml | 14 --------------
+ 1 file changed, 14 deletions(-)
+
+commit a390590451ef75e069ea5c67c3843b526f01fcde
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 31 08:51:19 2022 -0500
+
+    Mention named instances in the var-fonts section
+
+ docs/usermanual-fonts-and-faces.xml | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+commit 37e90c64c17656e74f83e932ae750aed347855a7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 30 15:41:40 2022 -0700
+
+    [cairo] Fix warnings
+
+ src/hb-cairo-utils.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 04464c55b2644de67a9599a72c3c9126a8718a18
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 30 14:55:32 2022 -0700
+
+    [pool] Change chunk-len from 16 to 32
+
+ src/hb-pool.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d7941e04df605549f97c9a48469c5c204609610a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 30 14:47:47 2022 -0700
+
+    [paint-extents] Unlikely
+
+ src/hb-paint-extents.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ca844b69759c0d7b6c7511267c935330392dab00
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 30 14:47:24 2022 -0700
+
+    [paint-extents] Whitespace
+
+ src/hb-paint-extents.cc | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 62ca2be39dd1bb03a99417ba57e0d8a18e407534
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 30 14:41:36 2022 -0700
+
+    [paint-extents] Implement quadratic callback
+
+ src/hb-paint-extents.cc | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+commit 7389efd8e0d5ee18b5139932214d326c7901ab15
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 30 13:58:34 2022 -0700
+
+    [post] Pre-alloc name index array
+
+ src/hb-ot-post-table.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 36bef5dccf0ba3b437fdf4246e39e7e1c5219ce8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 30 13:17:23 2022 -0700
+
+    [gsubgpos] Prealloc subtables vector
+
+ src/hb-ot-layout-gsubgpos.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 00060d99f300575dab95b255e31f75787f34078e
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Dec 30 22:55:56 2022 +0200
+
+    [hb-cairo] Silence warning when building with FreeType
+    
+    In file included from ../util/hb-view.cc:33:
+    In file included from ../util/view-cairo.hh:32:
+    ../util/helper-cairo.hh:102:7: warning: variable 'cairo_face' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
+      if (use_hb_draw)
+          ^~~~~~~~~~~
+    ../util/helper-cairo.hh:129:64: note: uninitialized use occurs here
+      cairo_scaled_font_t *scaled_font = cairo_scaled_font_create (cairo_face,
+                                                                   ^~~~~~~~~~
+    ../util/helper-cairo.hh:102:3: note: remove the 'if' if its condition is always true
+      if (use_hb_draw)
+      ^~~~~~~~~~~~~~~~
+    ../util/helper-cairo.hh:101:32: note: initialize the variable 'cairo_face' to silence this warning
+      cairo_font_face_t *cairo_face;
+                                   ^
+                                    = nullptr
+    
+    We know that cairo_face will always be assigned since use_hb_draw will
+    always be true, but the compiler does not know that.
+
+ util/helper-cairo.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a45bf5b04c907c7071a41bac3235459f02eb1f8f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 30 11:19:36 2022 -0700
+
+    [ft-colr] Require FreeType >= 2.11.1
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3989
+
+ src/hb-ft-colr.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ceba6c9a90751fa82264889d31b0d8d6794bd2d9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 30 10:44:34 2022 -0700
+
+    [config] Sort
+
+ src/hb-config.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 0d98c79b103a5bb2dfb684549077096853e08c55
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 29 21:07:38 2022 -0700
+
+    [util] Centralize includes again
+
+ util/helper-cairo.hh | 5 -----
+ util/options.hh      | 4 ++++
+ 2 files changed, 4 insertions(+), 5 deletions(-)
+
+commit d90ccc1c5c28eb0480c10d57a53daea2c17c0384
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 29 21:02:06 2022 -0700
+
+    [view] More includes
+
+ util/helper-cairo.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 969914b2b526a8017dfc85efa6a23a8453d17666
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 29 21:01:16 2022 -0700
+
+    [view] Clean up includes
+
+ util/ansi-print.hh   | 5 -----
+ util/helper-cairo.hh | 4 ++++
+ util/options.hh      | 3 ---
+ 3 files changed, 4 insertions(+), 8 deletions(-)
+
+commit 2bbc57c3c4ed4c54cd9f0fcab48b17a1d57a5823
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 29 20:41:55 2022 -0700
+
+    [chafa] Residual
+
+ util/helper-cairo-ansi.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 962d4925b27a3adf3805b98e5b8d221161ded421
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 29 20:39:02 2022 -0700
+
+    [ansi] Optimize write
+
+ util/ansi-print.hh | 21 ++++++++++++---------
+ 1 file changed, 12 insertions(+), 9 deletions(-)
+
+commit a35f8e340baee34d5b31df425b3044e520626c96
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 29 20:34:23 2022 -0700
+
+    [ansi] Whitespace
+
+ util/ansi-print.hh | 25 +++++++++++++++++--------
+ 1 file changed, 17 insertions(+), 8 deletions(-)
+
+commit 0004ec13a6334f6a279922c4f7111277bec20a60
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 29 20:26:42 2022 -0700
+
+    [view] Write ansi output to --output-file
+    
+    Was writing to stdout all this time!
+
+ util/ansi-print.hh        | 23 ++++++++++++++++-------
+ util/helper-cairo-ansi.hh | 12 ++++++++----
+ 2 files changed, 24 insertions(+), 11 deletions(-)
+
+commit 3a319b59bd4e52a20dbe7cd34ab85efe71a4831d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 29 20:26:09 2022 -0700
+
+    [ansi] Write \e directly
+
+ util/ansi-print.hh | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+commit ab8b9b444305dc01f5205ef0b7398a78184511b2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 29 18:33:12 2022 -0700
+
+    [view] Streamline cairo-ft face lifecycle management
+
+ util/helper-cairo-ft.hh | 10 ++++++++++
+ util/helper-cairo.hh    |  7 -------
+ 2 files changed, 10 insertions(+), 7 deletions(-)
+
+commit 228a415470dec6c58b5543d00ca1fd7f72980be3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 29 18:19:06 2022 -0700
+
+    [view-cairo] Minor subpixel-bits
+
+ util/helper-cairo.hh |  4 ++--
+ util/view-cairo.hh   | 12 ++++++------
+ 2 files changed, 8 insertions(+), 8 deletions(-)
+
+commit 74d29cd16890b013302626bf566dabe26e3300e2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 29 18:11:41 2022 -0700
+
+    [helper-cairo] Remove a method
+
+ util/helper-cairo.hh | 66 ++++++++++++++++++++++++----------------------------
+ util/view-cairo.hh   |  3 +--
+ 2 files changed, 32 insertions(+), 37 deletions(-)
+
+commit f2a6643fc15da58c5aec60a90b3eeea6af4d0ea2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 29 18:00:39 2022 -0700
+
+    [cairo] Docs
+
+ src/hb-cairo.cc | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit bfce4a60465e47f8c5f2cb916972e07242bbadc5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 29 10:43:37 2022 -0700
+
+    [cairo] Remove error path
+    
+    Assume cairo API always returns non-NULL.
+
+ src/hb-cairo.cc | 19 -------------------
+ 1 file changed, 19 deletions(-)
+
+commit b1de87b7f1ebe62fc9325679489718494ec1d3a2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 29 10:34:47 2022 -0700
+
+    [cairo] Document get_glyphs() arguments as inout
+
+ src/hb-cairo.cc      | 41 ++++++++++++++++++++++++++++++++++-------
+ util/helper-cairo.hh |  2 ++
+ 2 files changed, 36 insertions(+), 7 deletions(-)
+
+commit 3be9fa07f65130b3b534095d0c6cb2b36b85acdd
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Dec 29 10:14:51 2022 -0500
+
+    [docs] Mention new font-funcs in the user manual
+
+ docs/usermanual-fonts-and-faces.xml | 14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
+
+commit 2c2121784a6b162b2cdbb31b1388e8abc15691b8
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Dec 29 09:57:56 2022 -0500
+
+    [docs] Add a Cairo integration section
+
+ docs/usermanual-integration.xml | 44 ++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 43 insertions(+), 1 deletion(-)
+
+commit 89bd7f64ae91d9dfe2cf498233f38ecf054ec484
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Dec 29 08:05:16 2022 -0500
+
+    [hb-cairo] Small docs fixes
+
+ src/hb-cairo.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit c9206df1667101fa4fa5c54ac6e0d9750a0d2d1f
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Dec 29 16:05:19 2022 +0200
+
+    [hb-cairo] Fix warnings
+
+ src/hb-cairo-utils.cc | 58 +++++++++++++++++++++++++--------------------------
+ 1 file changed, 29 insertions(+), 29 deletions(-)
+
+commit 723e7a48e213ad9216f49762d6881745c36f6678
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Dec 29 15:49:21 2022 +0200
+
+    [docs] Small fixes
+
+ src/hb-cairo.cc | 6 +++---
+ src/hb-font.h   | 2 +-
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit 313f74a6931eef76d3d35a09c38c90851342a88f
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Jun 29 07:32:58 2022 -0400
+
+    Add a basic test for hb-coretext api
+    
+    This tests what would be my minimum assumption
+    about this api. It was written blindly.
+
+ test/api/Makefile.am     |  6 ++++
+ test/api/meson.build     |  6 ++++
+ test/api/test-coretext.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 91 insertions(+)
+
+commit 661baf403c9c6e8a8c7562adaf8cf39e21185101
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Jun 29 07:31:46 2022 -0400
+
+    Add a basic test for hb-ft api
+    
+    This tests what would be my minimum assumption
+    about this api.
+
+ test/api/Makefile.am |   4 ++
+ test/api/meson.build |   5 ++-
+ test/api/test-ft.c   | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 128 insertions(+), 1 deletion(-)
+
+commit 67456a7a02feee7bf9644f01402cbfade85bcac2
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 28 13:07:54 2022 -0500
+
+    [ft] Some more docs clarifications
+
+ src/hb-ft.cc | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit c612d068e8a5b90675c4e27a8ca2bd90ba8798eb
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 28 10:42:59 2022 -0500
+
+    [ft] Clarify docs around faces too
+
+ src/hb-ft.cc | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+commit 4dc955bb46f9f945e2cf0d79c0a12b15d200e3f7
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 28 10:04:21 2022 -0500
+
+    [ft] Clarify docs
+    
+    Add some clarifications on what fonts these apis
+    work with.
+
+ src/hb-ft.cc | 20 +++++++++++++++++---
+ 1 file changed, 17 insertions(+), 3 deletions(-)
+
+commit ef20b5e66f3e693b2c9e08f0e03802d2b8c2456c
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 28 08:51:27 2022 -0500
+
+    Typo fix
+
+ src/meson.build | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit dc9ca63763234d5082db5e88944d1fccb65ed565
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Dec 27 17:49:02 2022 -0700
+
+    [hb-view] Remove stale disabled code path
+    
+    With color rendering that code path is wrong anyway.
+    And cairo now supports subpixel text positioning.
+
+ util/view-cairo.hh | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+commit 5efb3bc6919f771f68780e3879e4be0d5121e99e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Dec 27 17:47:46 2022 -0700
+
+    [hb-view] Set hb-cairo scale-factor
+    
+    Unused.
+
+ util/helper-cairo.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 81c04b0c2176b6dce850a76ace059b74d59bbee5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Dec 27 17:46:25 2022 -0700
+
+    [cairo] Add separate x/y scale factors
+
+ src/hb-cairo.cc      | 43 ++++++++++++++++++++++---------------------
+ src/hb-cairo.h       |  3 ++-
+ util/helper-cairo.hh |  2 +-
+ 3 files changed, 25 insertions(+), 23 deletions(-)
+
+commit 50b7fff0c6f38819a66735d66ebd670655b4e961
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Dec 27 17:37:42 2022 -0700
+
+    [cairo] Fix text_to_glyphs scale factor
+
+ src/hb-cairo.cc | 8 +-------
+ 1 file changed, 1 insertion(+), 7 deletions(-)
+
+commit 8f62b8c6bb1ecf1ef5abcdf88798076d48ef28b5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Dec 27 17:26:39 2022 -0700
+
+    [cairo] Fix cluster conversion
+
+ src/hb-cairo.cc | 13 +++----------
+ 1 file changed, 3 insertions(+), 10 deletions(-)
+
+commit 326db329f84793152838ff8c45d284f4766c0a7a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Dec 27 14:38:17 2022 -0700
+
+    [directwrite] Simplify delete
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3981
+
+ src/hb-directwrite.cc | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+commit 7b0f9abc897f656addc55ad875bd4737cbb17128
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Dec 27 12:37:53 2022 -0700
+
+    [paint] Add back "remote-control" API
+    
+    This reverts commit f146299a405b8338542a245b85e664de29f0c972.
+
+ docs/harfbuzz-sections.txt |  13 +++
+ src/hb-paint.cc            | 246 +++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-paint.h             |  67 ++++++++++++
+ 3 files changed, 326 insertions(+)
+
+commit 43b0364edacaa487ea18bc0261d72e3e45e42197
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Dec 27 12:29:53 2022 -0700
+
+    [paint] Document composition modes
+
+ src/hb-paint.h | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 60 insertions(+)
+
+commit ec9e8a5993727174c765572cd71eba6fd3b38f90
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Dec 27 12:22:56 2022 -0700
+
+    [paint] Document extend modes.
+
+ src/hb-paint.h | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+commit fa3fa9422deb7bf9330f62412bbe24fe11eb7c4d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Dec 27 11:54:23 2022 -0700
+
+    [cairo] Doc
+
+ src/hb-cairo.cc | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit bbf6f42d3b3b7d5310255013eb1bb17528565121
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Dec 27 11:50:06 2022 -0700
+
+    [cairo] TODO
+
+ src/hb-cairo.cc | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit f9fc13287b5b384cb3485687c150d284a9fe53b2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Dec 27 11:08:34 2022 -0700
+
+    [hb-cairo] Return hb_font_t* from init-func
+
+ src/hb-cairo.cc | 2 +-
+ src/hb-cairo.h  | 8 +++++---
+ 2 files changed, 6 insertions(+), 4 deletions(-)
+
+commit d18903e44334d198e1d5445a4316da17887a75dc
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Tue Dec 27 09:25:05 2022 -0500
+
+    Add def files for libharfbuzz-cairo
+
+ src/Makefile.am | 7 ++++++-
+ src/meson.build | 6 ++++++
+ 2 files changed, 12 insertions(+), 1 deletion(-)
+
+commit d88787b6cab610ab961648e9f6c000a69c25d43b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Dec 27 10:59:17 2022 -0700
+
+    [cairo] Add func to init fonts on creation
+    
+    To set, for example, font-funcs.
+
+ docs/harfbuzz-sections.txt |   6 +-
+ src/hb-cairo.cc            | 138 ++++++++++++++++++++++++++++++---------------
+ src/hb-cairo.h             |  30 ++++++++--
+ 3 files changed, 121 insertions(+), 53 deletions(-)
+
+commit c52bff2d6132c5716825f45bf7e0a64e48e83a51
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Dec 27 10:42:13 2022 -0700
+
+    [cairo] Hide internal symbols
+
+ src/hb-cairo-utils.hh | 44 ++++++++++++++++++++++++--------------------
+ 1 file changed, 24 insertions(+), 20 deletions(-)
+
+commit 7d3b3739253a901b88cd4da9916007ae7166c9de
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Tue Dec 27 08:37:46 2022 -0500
+
+    Fix the autotools build
+
+ util/Makefile.sources | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 34aa8b0148dc03fcaff7dfe09ca7dab7f3c91a97
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 16:54:31 2022 -0700
+
+    [cairo] Add to library tests
+
+ src/check-libstdc++.py | 2 +-
+ src/check-symbols.py   | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 5fdfe6ae5d8118d7e2c0f90a8a7014e4d60a3a28
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 16:52:53 2022 -0700
+
+    [cairo] Use hb_qsort
+
+ src/hb-cairo-utils.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 21573265e92006eedac5bd5a3d43dc5b28e108b4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 16:52:13 2022 -0700
+
+    [cairo] More namespacing
+
+ src/hb-cairo-utils.cc | 196 +++++++++++++++++++++++++-------------------------
+ 1 file changed, 98 insertions(+), 98 deletions(-)
+
+commit 84d1b00cd4e29d428d60b45610231b9b93967693
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 16:45:23 2022 -0700
+
+    [cairo] More namespacing
+
+ src/hb-cairo-utils.cc | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+commit 8f16e98c1b645d7374f0e61388d8e6a427a53c63
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 16:44:07 2022 -0700
+
+    [cairo] Namespace types
+
+ src/hb-cairo-utils.cc | 84 +++++++++++++++++++++++++--------------------------
+ 1 file changed, 42 insertions(+), 42 deletions(-)
+
+commit 488be5246778b8e4f7177b84bb452f48e4217b41
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 16:42:22 2022 -0700
+
+    [cairo] Try fix msvc build
+
+ src/hb-cairo-utils.cc | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+commit c652e8e1b7a2a92d898b08941dc081546a26c101
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 16:25:22 2022 -0700
+
+    [cairo] Docs
+
+ src/hb-cairo.cc | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+commit 23980d3cb2e0d374933f28e58ff0631b4a59e1e0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 16:22:35 2022 -0700
+
+    [cairo] Docs
+
+ src/hb-cairo.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit f5fd46aa3d905a7c69c12fa35c48d8c3b64f0cf2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 16:18:27 2022 -0700
+
+    [cairo] Docs
+
+ src/hb-cairo.cc | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 36482b684b16f752965485b41c39558c1f144504
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 16:15:06 2022 -0700
+
+    [cairo] Err, utf8_clusters
+
+ src/hb-cairo.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 48cb25dd36a83f48748b295eebdfd74de170dc41
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 16:13:57 2022 -0700
+
+    [cairo] Implement (untested) text_to_glyphs callback
+
+ src/hb-cairo.cc | 41 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 41 insertions(+)
+
+commit c38abcb3fbe30d835988f2a0920c5eb80cf42266
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 16:03:25 2022 -0700
+
+    [cairo] Add x,y args to get_glyphs
+
+ src/hb-cairo.cc      | 18 +++++++++++-------
+ src/hb-cairo.h       |  2 ++
+ util/helper-cairo.hh | 10 ++++------
+ 3 files changed, 17 insertions(+), 13 deletions(-)
+
+commit 847ed695473306e76c3084df893e2c24bf79c440
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 15:59:57 2022 -0700
+
+    [cairo] Reorder arguments of a call
+
+ src/hb-cairo.cc      | 22 +++++++++++-----------
+ src/hb-cairo.h       |  4 ++--
+ util/helper-cairo.hh |  4 ++--
+ 3 files changed, 15 insertions(+), 15 deletions(-)
+
+commit 726cfffc0d37c0bb5aa4bd98403e369c829cbbed
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 15:55:56 2022 -0700
+
+    [cairo] Doc fix
+
+ src/hb-cairo.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 0fe0cdf066791b8805826a149cd438d56ba7e2f3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 15:52:55 2022 -0700
+
+    [cairo] Document scale-factor business
+
+ src/hb-cairo.cc | 32 ++++++++++++++++++++++++++++++++
+ 1 file changed, 32 insertions(+)
+
+commit 4e3e879c1cb25eb87bf0c0076067024184f875b7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 15:33:04 2022 -0700
+
+    [cairo] Add [sg]et_scale_factor
+
+ docs/harfbuzz-sections.txt |  2 ++
+ src/hb-cairo.cc            | 58 +++++++++++++++++++++++++++++++++++++++++++---
+ src/hb-cairo.h             |  7 ++++++
+ 3 files changed, 64 insertions(+), 3 deletions(-)
+
+commit 186bfa99f54747698bcebea35cb52fff680b3807
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 15:15:40 2022 -0700
+
+    [cairo] Make scale_factor a double
+
+ src/hb-cairo.cc | 4 ++--
+ src/hb-cairo.h  | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+commit 120419e180843b1183345d50d73585bc55805a17
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 15:10:26 2022 -0700
+
+    [hb-view] Fix autotools build
+
+ src/Makefile.am       | 1 +
+ util/Makefile.am      | 1 +
+ util/Makefile.sources | 2 --
+ 3 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 650a46d919dec6f55cbeb21685ab064086b5bf92
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 15:02:01 2022 -0700
+
+    [cairo] Fix autotools build
+
+ src/Makefile.am      |  4 ++--
+ src/Makefile.sources | 11 +++++++++--
+ 2 files changed, 11 insertions(+), 4 deletions(-)
+
+commit b417ac8a19ed09df3702722a9af4e74296d4bee2
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 26 08:43:52 2022 -0500
+
+    Try to fix autotools build
+
+ src/Makefile.am          | 10 ++++++++++
+ src/Makefile.sources     |  3 +++
+ src/harfbuzz-cairo.pc.in | 12 ++++++++++++
+ 3 files changed, 25 insertions(+)
+
+commit 8d0e18b51d37c7f7e4d49e42e612d82e40f88656
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Dec 25 22:12:29 2022 -0500
+
+    [cairo] More details in the docs
+    
+    Mention slant as well.
+
+ src/hb-cairo.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 30605e09b9e9be7469bd4b6989af3c99da36a691
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Dec 25 22:04:22 2022 -0500
+
+    [cairo] Mention variations in the docs
+
+ src/hb-cairo.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit c4f7563f8178eee8ec1dbf9de5a3198efc1a9e18
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 19:40:44 2022 -0700
+
+    [cairo] Fix build
+
+ src/meson.build | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 7a52ac4bbe5951626756ccd3cb8e50e382bbbe44
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 19:39:02 2022 -0700
+
+    [cairo] Set variations
+
+ src/hb-cairo.cc | 20 +++++++++++++++++++-
+ 1 file changed, 19 insertions(+), 1 deletion(-)
+
+commit 4be4e017fc0685745e6e9d3d44c40d191f26ff5a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 19:27:53 2022 -0700
+
+    [cairo] Make font immutable
+
+ src/hb-cairo.cc | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit ea993af8e7819826b98573a98b4b11363fed0e57
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 19:17:18 2022 -0700
+
+    [view] Don't double-slant
+
+ util/helper-cairo.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 70babda6adcadeac883b1ba14ed2b8c46d09cd99
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 19:10:11 2022 -0700
+
+    [cairo] docs
+
+ docs/harfbuzz-sections.txt |  5 ++++-
+ src/hb-cairo.cc            | 31 +++++++++++++++++++++++++++++++
+ 2 files changed, 35 insertions(+), 1 deletion(-)
+
+commit 1c67180d6dd7be650c47eddfcaa1ea1b73220fe2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 19:07:02 2022 -0700
+
+    [cairo] Add typed destroy funcs
+
+ src/hb-cairo.cc | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+commit 43da222e6dca2117fd2bbd4cd428dfe3cf056d23
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 19:05:24 2022 -0700
+
+    [cairo] Rename
+
+ src/hb-cairo.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit cf001f6ec777e40bd01c2087d8f9c5a4575e33f3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 19:01:28 2022 -0700
+
+    [cairo] Add constructor from hb_face_t
+
+ src/hb-cairo.cc      | 70 +++++++++++++++++++++++++++++++++++++++++-----------
+ src/hb-cairo.h       | 11 ++++++++-
+ util/helper-cairo.hh |  2 +-
+ 3 files changed, 67 insertions(+), 16 deletions(-)
+
+commit 2e897cc90b754e67240cba2589e7e28027b436cc
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Dec 25 20:03:59 2022 -0500
+
+    Add a pc file for harfbuzz-cairo
+
+ src/meson.build | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+commit ddb52e4a30375c2455f6c019c355d3bcf1adc196
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Dec 25 19:52:39 2022 -0500
+
+    [cairo] Add docs
+
+ docs/harfbuzz-docs.xml     |  1 +
+ docs/harfbuzz-sections.txt |  7 ++++++
+ src/hb-cairo.cc            | 53 +++++++++++++++++++++++++++++++++++++++++++++-
+ 3 files changed, 60 insertions(+), 1 deletion(-)
+
+commit dc2bf2664deb7700dd32b82612a49f363a51c443
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 18:02:34 2022 -0700
+
+    [cairo] Set scaled-font extents
+
+ src/hb-cairo.cc | 46 +++++++++++++++++++++++++++++++---------------
+ 1 file changed, 31 insertions(+), 15 deletions(-)
+
+commit d6ecda36bf43aad91de016771e2176b990225eea
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 17:39:26 2022 -0700
+
+    [cairo] Renames
+
+ src/hb-cairo.cc | 28 ++++++++++++++--------------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+commit ffa45f243c6ae9977b67340cad7beaa8ce7110b4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 17:14:45 2022 -0700
+
+    [cairo] #ifdef HAVE_CAIRO
+
+ src/hb-cairo-utils.cc | 4 ++++
+ src/hb-cairo.cc       | 4 ++++
+ src/hb-ft.cc          | 1 -
+ 3 files changed, 8 insertions(+), 1 deletion(-)
+
+commit 9e61fd770562967c7ac9fa4f7ddfa64a04167cfd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 17:09:43 2022 -0700
+
+    [hb-cairo] Lazy-load funcs thread-safe
+
+ src/hb-cairo.cc         | 68 ++++++++++++++++++++++++++++++++++++-------------
+ src/hb-paint-extents.cc |  3 +++
+ 2 files changed, 54 insertions(+), 17 deletions(-)
+
+commit 49a6aa97d97ccbd8d17deefbbdadb1edd2227e42
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Dec 25 19:09:19 2022 -0500
+
+    [docs] Add missing HB_HAS macros
+
+ docs/harfbuzz-sections.txt | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit 306645503d1d019b4ec011e9bacec43bb7a46a9a
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Dec 25 19:03:50 2022 -0500
+
+    Work on proper build integration
+    
+    Install hb-cairo.h and define HB_HAS_CAIRO.
+
+ docs/harfbuzz-sections.txt |  1 +
+ src/hb-features.h.in       |  7 +++++++
+ src/meson.build            | 51 +++++++++++++++++++++++++++++++---------------
+ 3 files changed, 43 insertions(+), 16 deletions(-)
+
+commit a7c2e839e1850c875aab2d563be2fd9f89530430
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 16:59:58 2022 -0700
+
+    [hb-cairo] Prefix internal methods
+
+ src/hb-cairo.cc | 224 +++++++++++++++++++++++++++++---------------------------
+ 1 file changed, 116 insertions(+), 108 deletions(-)
+
+commit bb640d403141c7f2b32e2d1f080d155d23c33e52
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 16:55:27 2022 -0700
+
+    [hb-cairo] Use nullptr instead of NULL
+
+ src/hb-cairo.cc | 32 ++++++++++++++++----------------
+ 1 file changed, 16 insertions(+), 16 deletions(-)
+
+commit b3a3656683fedabbe8f5e5e1e7d71fee6b61a91b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 16:53:54 2022 -0700
+
+    [hb-cairo] Minor
+
+ src/hb-cairo-utils.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3a11a09f542715aa92d956614089050a7b83d318
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 16:53:21 2022 -0700
+
+    [hb-cairo] Rename cairo_extend
+
+ src/hb-cairo-utils.cc | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 20a50acc91946f1ae3421dd7dd5657b81e1ffd24
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 16:09:26 2022 -0700
+
+    [hb-cairo] Make hb_cairo_glyphs_from_buffer public
+
+ src/hb-cairo.cc      | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-cairo.h       |  12 +++++
+ src/hb-utf.hh        |  30 ++++++++++++-
+ util/helper-cairo.hh | 121 -------------------------------------------------
+ 4 files changed, 166 insertions(+), 122 deletions(-)
+
+commit bf52386cfa6ca0c41750e40950b48727d67c7441
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 16:10:31 2022 -0700
+
+    [cairo] Silence warning
+
+ src/hb-cairo.cc | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit e594780e2893ca3b5c0e4c252225258964a7ffd6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 16:05:33 2022 -0700
+
+    [hb-cairo] Some header tweaks
+
+ src/hb-cairo-utils.hh | 11 ++++++-----
+ src/hb-cairo.h        |  1 +
+ 2 files changed, 7 insertions(+), 5 deletions(-)
+
+commit 1ad24421a67ec4ce2d62587586aaf0eace71d866
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 15:55:14 2022 -0700
+
+    [hb-cairo] Rename files to C++
+
+ src/{hb-cairo-utils.c => hb-cairo-utils.cc} | 78 +++++++++++------------------
+ src/{hb-cairo-utils.h => hb-cairo-utils.hh} |  0
+ src/{hb-cairo.c => hb-cairo.cc}             | 11 ++--
+ src/meson.build                             |  4 +-
+ 4 files changed, 36 insertions(+), 57 deletions(-)
+
+commit a230eb8cf587cd00140f5361e119967524125438
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 15:49:14 2022 -0700
+
+    [hb-cairo] Factorize hb_cairo_glyphs_from_buffer
+    
+    To be made public.
+
+ util/helper-cairo.hh | 146 +++++++++++++++++++++++++++++++++++----------------
+ 1 file changed, 100 insertions(+), 46 deletions(-)
+
+commit 5c3da76a439cb00d3cb45eacd51de40959c73cc1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 15:04:13 2022 -0700
+
+    [hb-cairo] Change API again
+    
+    We need to work with a hb-font for variations and font-funcs
+    to be fetched properly.
+
+ src/hb-cairo.c       | 21 ++++++---------------
+ src/hb-cairo.h       |  6 +++---
+ util/helper-cairo.hh |  8 +++++---
+ 3 files changed, 14 insertions(+), 21 deletions(-)
+
+commit 9f7538c2606d330f64bed5e71d7676195bb74975
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 25 13:46:37 2022 -0700
+
+    [hb-cairo] Change API
+
+ src/hb-cairo.c       | 46 ++++++++++++----------------------------------
+ src/hb-cairo.h       |  9 ++++-----
+ util/helper-cairo.hh | 23 ++++++++++-------------
+ 3 files changed, 26 insertions(+), 52 deletions(-)
+
+commit 0d6ee4621e7cc20f273430d4a041e31355cf716d
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Dec 25 10:50:56 2022 -0500
+
+    wip: Make hb-view use hb-cairo
+    
+    This is a quick hack to prove that the
+    hb-cairo apis work
+
+ util/hb-cairo-utils.c     | 847 ----------------------------------------------
+ util/hb-cairo-utils.h     |  97 ------
+ util/helper-cairo-user.hh | 541 -----------------------------
+ util/helper-cairo.hh      |  43 +--
+ util/meson.build          |   3 +-
+ 5 files changed, 25 insertions(+), 1506 deletions(-)
+
+commit 767bdd43a63cf50a9b0339cea8bb1a7a3311410a
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Dec 25 10:32:33 2022 -0500
+
+    wip: Add libharfbuzz-cairo
+    
+    This library will provide integration with cairo
+    for font rendering.
+
+ src/hb-cairo-utils.c | 847 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-cairo-utils.h |  97 ++++++
+ src/hb-cairo.c       | 432 ++++++++++++++++++++++++++
+ src/hb-cairo.h       |  44 +++
+ src/meson.build      |  19 ++
+ 5 files changed, 1439 insertions(+)
+
+commit 2a515679251116e3058fc43bf7ff54e08e14e3e4
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 26 16:50:32 2022 -0500
+
+    [paint] Add a test for recursion
+
+ test/api/fonts/bad_colrv1.ttf | Bin 0 -> 16708 bytes
+ test/api/results/bad-20-0-154 | 349 ++++++++++++++++++++++++++++++++++++++++++
+ test/api/test-paint.c         |   2 +
+ 3 files changed, 351 insertions(+)
+
+commit c3a8c6bb8b0a44fb338b85014bd88615ecf5c79f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 15:38:24 2022 -0700
+
+    [paint] More docs
+
+ src/hb-paint.cc |  4 +++-
+ src/hb-paint.h  | 28 ++++++++++++++++++++++++++++
+ 2 files changed, 31 insertions(+), 1 deletion(-)
+
+commit 5f168db884d2db7321cfbc251a98819a6ba0e4a4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 15:12:27 2022 -0700
+
+    [hb-view] Build with autotools if cairo-ft is not available
+    
+    Like with meson.
+
+ util/Makefile.am | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+commit ae208963dfd9bf3354b2eaa194bf2f4b5ec60c99
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 26 12:30:39 2022 -0700
+
+    Add hb-limits.hh
+
+ src/Makefile.sources           |   1 +
+ src/OT/glyf/Glyph.hh           |   5 --
+ src/hb-buffer.hh               |  20 --------
+ src/hb-cff-interp-cs-common.hh |   3 +-
+ src/hb-ft-colr.hh              |   9 +---
+ src/hb-limits.hh               | 105 +++++++++++++++++++++++++++++++++++++++++
+ src/hb-ot-color-colr-table.hh  |  14 ++----
+ src/hb-ot-layout-common.hh     |  36 --------------
+ src/hb.hh                      |   1 +
+ src/meson.build                |   1 +
+ 10 files changed, 113 insertions(+), 82 deletions(-)
+
+commit 5f5fa4b219320461a39c2d5c30a413574db6f628
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 26 13:47:35 2022 -0500
+
+    [ft-colr] Limit the size of the graph we follow
+    
+    This adds the same check that we already do in
+    the native implementation.
+
+ src/hb-ft-colr.hh | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+commit ea2892c30e6be7f073d2fc70237b7f6a77efff82
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 26 10:10:39 2022 -0500
+
+    [paint] Limit the size of the graph we follow
+    
+    In addition to checking the depth, also count
+    the number of edges in the graph we've followed,
+    and give up after 1024.
+
+ src/hb-ot-color-colr-table.hh | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+commit 1eb4d002f21354216c2fc7df973c7ca671e2af34
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 26 12:56:33 2022 -0500
+
+    Try to fix the build with msvc
+
+ test/api/test-paint.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 00e93102a63058aac9354edd87cdc16611e51168
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 26 08:31:22 2022 -0500
+
+    Add a test for hb_ot_color_glyph_has_paint
+
+ test/api/test-ot-color.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+commit e7b0947afd7caddbd865788f96af71a282eefdbc
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 26 08:24:39 2022 -0500
+
+    Add a test for hb_ot_color_has_paint
+
+ test/api/test-ot-color.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+commit 5dd69d81b0d2a1e2323dd780a684c041ffb310ed
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 26 08:23:55 2022 -0500
+
+    Fix hb_ot_color_has_paint
+    
+    We must no access v1 data without checking that
+    version is 1. A bit of a trap.
+
+ src/hb-ot-color-colr-table.hh | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+commit b8f2281c6c1546853821d9b26bdb61f9fe5acd0a
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 26 07:59:01 2022 -0500
+
+    Add hb_ot_color_glyph_has_paint
+
+ docs/harfbuzz-sections.txt    |  1 +
+ src/hb-ot-color-colr-table.hh | 13 +++++++++++++
+ src/hb-ot-color.cc            | 19 +++++++++++++++++++
+ src/hb-ot-color.h             |  4 ++++
+ 4 files changed, 37 insertions(+)
+
+commit 79c5bb92ce0609af093f23d8bfa5b092cfe09111
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 12:57:33 2022 -0700
+
+    [ft] Work around a freetype bug
+
+ src/hb-ft.cc | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit a7a93b85e655dd947db23fd7350c2209729ab140
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 24 14:05:12 2022 -0500
+
+    Drop accidentally added ttx files
+
+ test/api/fonts/RocherColorGX.abc.ttx       | 2714 ---------
+ test/api/fonts/test_glyphs-glyf_colr_1.ttx | 8458 ----------------------------
+ 2 files changed, 11172 deletions(-)
+
+commit fa1cf15e5d53b3c7bd7e75c21ef3e9225f5b8b7d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 11:56:23 2022 -0700
+
+    [ft-colr] Whitespace
+
+ src/hb-ft-colr.hh | 102 +++++++++++++++++++++++++++---------------------------
+ 1 file changed, 51 insertions(+), 51 deletions(-)
+
+commit 5343eac16188e0cee6b50e452ea5590bc6cce2d2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 11:53:43 2022 -0700
+
+    [ft-colr] Minor use context instead of direct access
+
+ src/hb-ft-colr.hh | 45 ++++++++++++++++++++++++---------------------
+ 1 file changed, 24 insertions(+), 21 deletions(-)
+
+commit 0b6468b820d5f65259fc900e97e9e796cadbbd38
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 11:50:57 2022 -0700
+
+    [ft-colr] Minor
+
+ src/hb-ft-colr.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 1c595ec17fe11288dd133db243ba5c5c75ed808d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 11:40:44 2022 -0700
+
+    [paint-extents] Lazy-load paint_extents funcs
+
+ src/hb-ft-colr.hh             |  2 --
+ src/hb-ot-color-colr-table.hh |  4 ----
+ src/hb-paint-extents.cc       | 53 ++++++++++++++++++++++++++++++-------------
+ 3 files changed, 37 insertions(+), 22 deletions(-)
+
+commit 4280ed290d4b773f94228f746688bde7be33971e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 11:38:32 2022 -0700
+
+    [paint-extents] Add missing file
+
+ src/hb-paint-extents.hh | 282 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 282 insertions(+)
+
+commit 2c0ab34d03477a5ad15bf8cddd4c99e61572efee
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 11:37:59 2022 -0700
+
+    [paint-extents] Lazy-load draw-funcs
+
+ src/hb-machinery.hh     | 16 ++++++++++++++++
+ src/hb-paint-extents.cc | 37 +++++++++++++++++++++++++++++--------
+ 2 files changed, 45 insertions(+), 8 deletions(-)
+
+commit 11036ed71ed4fb6b7eb1cc365100be8628161727
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 11:30:45 2022 -0700
+
+    [paint] Add hb-paint-extents.cc
+
+ src/Makefile.sources                             |   1 +
+ src/harfbuzz-subset.cc                           |   1 +
+ src/harfbuzz.cc                                  |   1 +
+ src/{hb-paint-extents.hh => hb-paint-extents.cc} | 255 +----------------------
+ src/meson.build                                  |   1 +
+ 5 files changed, 6 insertions(+), 253 deletions(-)
+
+commit 959996d709dad7ce4a8087b2eef9dd4d6169493f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 11:22:16 2022 -0700
+
+    [paint-extents] Namespace
+
+ src/hb-paint-extents.hh | 52 ++++++++++++++++++++++---------------------------
+ 1 file changed, 23 insertions(+), 29 deletions(-)
+
+commit 62bd26dda3950bb879c1cf9907bb7e6f1b8a7b2c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 11:01:32 2022 -0700
+
+    [ft] Pick largest bitmap size
+
+ src/hb-ft.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit d35dff020f7852d4b3d48966b4bcb69b2452330b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 10:59:17 2022 -0700
+
+    [cbdt] Remove extra clip
+
+ src/hb-ot-color-cbdt-table.hh | 7 -------
+ 1 file changed, 7 deletions(-)
+
+commit f70c5d6f0da2cca2c2df4765ba45dbe5fee0cc79
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 10:56:06 2022 -0700
+
+    [paint] Continue returning bool from paint_image()
+    
+    https://github.com/harfbuzz/harfbuzz/commit/6ccbfabd4fcc5d4cca99be10552c270205fd7792#commitcomment-94127307
+
+ src/hb-ft.cc                  | 17 ++++++++++-------
+ src/hb-ot-color-cbdt-table.hh | 14 +++++++-------
+ src/hb-ot-color-sbix-table.hh | 14 +++++++-------
+ src/hb-paint.hh               |  8 ++++----
+ 4 files changed, 28 insertions(+), 25 deletions(-)
+
+commit 6ccbfabd4fcc5d4cca99be10552c270205fd7792
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 10:44:25 2022 -0700
+
+    [paint] Return bool from paint_image()
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3974
+
+ src/hb-paint-extents.hh   |  4 +++-
+ src/hb-paint.cc           |  4 ++--
+ src/hb-paint.h            | 20 +++++++++++---------
+ test/api/test-paint.c     |  8 ++++++--
+ util/hb-cairo-utils.c     | 12 +++++++-----
+ util/hb-cairo-utils.h     | 14 +++++++-------
+ util/helper-cairo-user.hh |  4 ++--
+ 7 files changed, 38 insertions(+), 28 deletions(-)
+
+commit 346331d37518f6de411f28bc09917fee475cad15
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 10:35:26 2022 -0700
+
+    [ft] Fix negative xscale
+
+ src/hb-ft.cc | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 9376e7a93096b6eff1872063823278a569dbfdb0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 10:31:30 2022 -0700
+
+    [ft] Remove stale TODO
+
+ src/hb-ft.cc | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+commit a7fd48c408e13a0979a418739e73d5e196be1252
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 10:28:41 2022 -0700
+
+    [ft] Comment
+
+ src/hb-ft.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit bb45ba2f9f4469b8bf326118ffe8003fb487f1f9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 10:25:43 2022 -0700
+
+    [ft] Fix negative y-scale
+
+ src/hb-ft.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit aba2063c22629308fac59bf91e3b4c9a8eaa2fa1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 10:15:47 2022 -0700
+
+    [paint-extents] Comments
+
+ src/hb-paint-extents.hh | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+commit 988ca459f33f1ac1b580d935fa0612ed985ae987
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 10:12:35 2022 -0700
+
+    [paint-extents] Minor refactor
+
+ src/hb-paint-extents.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit f8bf98798d8cba184c2a623c35d0b1202ded48bd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 10:04:48 2022 -0700
+
+    [paint-extents] Refactor code
+
+ src/hb-paint-extents.hh | 111 ++++++++++++++++++++++--------------------------
+ 1 file changed, 51 insertions(+), 60 deletions(-)
+
+commit f9081fc358f6673ce289992b6cdfb0b63068142c
+Merge: 1f3c042ff dfd371e97
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 24 09:51:11 2022 -0700
+
+    Merge pull request #3938 from harfbuzz/wip/matthiasc/paint-api
+    
+    hb-paint API
+
+commit 1f3c042ff50ca231441b006825aa089e3a54fab1
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Dec 24 17:03:57 2022 +0200
+
+    [doc] Don’t automatically skip building docs on Windows
+    
+    Respect the option setting.
+
+ .github/workflows/msys2-ci.yml | 1 +
+ docs/meson.build               | 5 -----
+ 2 files changed, 1 insertion(+), 5 deletions(-)
+
+commit dfd371e97653b704326e04c2436ee3edab6c9d64
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 24 09:57:48 2022 -0500
+
+    Cosmetics
+
+ util/helper-cairo-user.hh | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+commit d00e97f16cb72ce12ef8c93ccc34fb1be2023a10
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 24 06:58:44 2022 -0500
+
+    Add test-paint to the autotools build
+
+ test/api/Makefile.am                       |    7 +
+ test/api/fonts/RocherColorGX.abc.ttx       | 2714 +++++++++
+ test/api/fonts/test_glyphs-glyf_colr_1.ttx | 8458 ++++++++++++++++++++++++++++
+ 3 files changed, 11179 insertions(+)
+
+commit 3478728edb32787bcc52cf262563c140a958031e
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 24 08:51:23 2022 -0500
+
+    Fix test-paint build without freetype
+
+ test/api/test-paint.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+commit 4816be9ab5c0afdc7019728620c6761838236bd3
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 24 07:37:04 2022 -0500
+
+    Work around cairo limitations
+    
+    If we just draw an image, cairos recording surface
+    complains that it is unbounded. Its not true of course.
+    
+    To make things work, clip to the extents.
+
+ src/hb-ot-color-cbdt-table.hh |  7 +++++++
+ util/hb-cairo-utils.c         | 11 +++++++++++
+ 2 files changed, 18 insertions(+)
+
+commit 9b9d7c7b8eac99116eeb9cead68c9f926881841c
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 24 05:34:47 2022 -0500
+
+    Plug a memory lek in paint tests
+
+ test/api/test-paint.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 76c16095fa9a15d719ce78e3adc6d890439e62e1
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 24 05:30:11 2022 -0500
+
+    Fix the build on Windows
+    
+    No __BYTE_ORDER there.
+
+ util/hb-cairo-utils.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit f9c865a8998d6d41b756526f1053b7f55e3c2218
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 20:20:33 2022 -0500
+
+    Update test results
+    
+    These were changed by the introduction of
+    clip boxes.
+
+ test/api/results/hand-20-0-10   | 188 ++++++++++++++++++++--------------------
+ test/api/results/hand-20-0.2-10 | 188 ++++++++++++++++++++--------------------
+ test/api/results/test-20-0-10   |  30 ++++---
+ test/api/results/test-20-0-106  |  46 +++++-----
+ test/api/results/test-20-0-116  |  42 ++++-----
+ test/api/results/test-20-0-123  |  54 ++++++------
+ test/api/results/test-20-0-165  |  30 ++++---
+ test/api/results/test-20-0-175  |  54 ++++++------
+ test/api/results/test-20-0-6    |  28 +++---
+ test/api/results/test-20-0-92   |  28 +++---
+ 10 files changed, 354 insertions(+), 334 deletions(-)
+
+commit f7eebc397c87d4e8c14c5c0e9f892c0dc8b2e269
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 18:52:46 2022 -0700
+
+    [paint-extents] Shorten enum addressing
+
+ src/hb-paint-extents.hh | 42 +++++++++++++++++++++---------------------
+ 1 file changed, 21 insertions(+), 21 deletions(-)
+
+commit 0110bdb3eaa46a6a60f2d5bc0f9cd2f782c6d446
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 18:17:05 2022 -0700
+
+    [paint-extents] Streamline extents_t more
+
+ src/hb-paint-extents.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 9f3e050b990e7006a34648faa62a1fd912b8e3c1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 18:15:21 2022 -0700
+
+    [paint-extents] Streamline extents_t
+
+ src/hb-paint-extents.hh | 13 ++++++++++---
+ 1 file changed, 10 insertions(+), 3 deletions(-)
+
+commit 0d129ae308d7ac8d0d676b302118229e5add655d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 18:00:38 2022 -0700
+
+    Fix warning
+
+ src/hb-ot-color-colr-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 73e48b9357ae8efb1526d64f6978efa8f22d80e3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 17:55:09 2022 -0700
+
+    [colr] Push clipbox or computed clip
+
+ src/hb-ot-color-colr-table.hh | 59 ++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 56 insertions(+), 3 deletions(-)
+
+commit 02684751bd6c4f76e6377862136611cf12f66762
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 17:33:13 2022 -0700
+
+    [paint-extents] Clean up
+
+ src/hb-ft-colr.hh             | 15 ++++++++++-----
+ src/hb-ot-color-colr-table.hh |  9 +++++----
+ src/hb-paint-extents.hh       | 10 ++++++++++
+ 3 files changed, 25 insertions(+), 9 deletions(-)
+
+commit dbea503a38878d8cab0d2106d5b7e44d6550ff5b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 17:28:46 2022 -0700
+
+    [colr] Return true extents
+
+ src/hb-ot-color-colr-table.hh | 14 +++++---------
+ 1 file changed, 5 insertions(+), 9 deletions(-)
+
+commit f9c2e30e0173f29ce5c05b3163561b1dab3889f7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 17:13:35 2022 -0700
+
+    [paint-extents] Better handle empty glyphs
+
+ src/hb-paint-extents.hh | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+commit 885dbcfba0e1bbc22255ab54f8f76096cb35fdeb
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 19:07:32 2022 -0500
+
+    Skip empty outlines
+
+ src/hb-paint-extents.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit bd61e645ffea3fdc421f7dc17c0ac0c5fb0d2357
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 16:59:12 2022 -0700
+
+    [paint-extents] Use hb_min/hb_max
+
+ src/hb-paint-extents.hh | 16 ++++------------
+ 1 file changed, 4 insertions(+), 12 deletions(-)
+
+commit 56a48f8b0a881dd0c211f76668a36b477f22e100
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 16:44:06 2022 -0700
+
+    [paint] Don't use extents in hb-view
+    
+    Let the clipbox do its magic. Currently works for ft backend only.
+
+ src/hb-ft-colr.hh         | 1 -
+ util/helper-cairo-user.hh | 7 -------
+ 2 files changed, 8 deletions(-)
+
+commit 79229cea1743acaf12c5736f8d7d0e2a8308a961
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 18:33:53 2022 -0500
+
+    Get outline extents manually
+
+ src/hb-paint-extents.hh | 96 +++++++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 89 insertions(+), 7 deletions(-)
+
+commit 55b7af6b621daf2b02d49d4b43d54c67298865fd
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 18:01:45 2022 -0500
+
+    Tweak paint-tests
+
+ test/api/test-paint.c | 26 +++++++++++++-------------
+ 1 file changed, 13 insertions(+), 13 deletions(-)
+
+commit 47c896f0040c4fd6b6c91cdbc0f4f0fa2e9f6582
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 16:20:44 2022 -0700
+
+    [paint-extents] Hook it up, kinda
+
+ src/hb-ft-colr.hh             | 25 +++++++++++++++++++------
+ src/hb-ot-color-colr-table.hh | 16 ++++++++++++++++
+ 2 files changed, 35 insertions(+), 6 deletions(-)
+
+commit 7fbaaebe8bf61523f1c69ba50c4c29c5e5230fa1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 15:37:16 2022 -0700
+
+    [paint-extents] Finish off
+    
+    Untested and unused.
+
+ src/hb-paint-extents.hh | 61 +++++++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 56 insertions(+), 5 deletions(-)
+
+commit 8ca78d1520cf9c4ee1720ed80abc3167cdf6f963
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 15:21:48 2022 -0700
+
+    [paint-extend] More
+
+ src/hb-paint-extents.hh | 56 +++++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 50 insertions(+), 6 deletions(-)
+
+commit 23a2d4dbabf812c75dec6bfe7ceb3a4fbf0b039e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 15:10:26 2022 -0700
+
+    [paint-extents] More
+
+ src/hb-paint-extents.hh | 30 +++++++++++++++++++++++++++++-
+ 1 file changed, 29 insertions(+), 1 deletion(-)
+
+commit d7435b10095bf035f41539de5e1ddd39c14719ce
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 15:05:30 2022 -0700
+
+    [paint-extents] Flesh out more
+
+ src/hb-paint-extents.hh | 23 ++++++++++++++---------
+ 1 file changed, 14 insertions(+), 9 deletions(-)
+
+commit c37a1eadef4c99d7c95cefb8341c40c7b3159246
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 14:57:12 2022 -0700
+
+    [paint-extents] Flesh out some more
+
+ src/hb-paint-extents.hh | 64 ++++++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 48 insertions(+), 16 deletions(-)
+
+commit 268d8b7dedf35b8c097075c2726753fb1462a04d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 14:45:56 2022 -0700
+
+    [paint-extents] Start out
+
+ src/Makefile.sources    |   1 +
+ src/hb-ft-colr.hh       |   2 +
+ src/hb-paint-extents.hh | 288 ++++++++++++++++++++++++++++++++++++++++++++++++
+ src/meson.build         |   1 +
+ 4 files changed, 292 insertions(+)
+
+commit 44b48845b7200a74f4ea01711f30a7c3ebe6fee4
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 16:26:05 2022 -0500
+
+    Add tests for hb_color_line_t
+    
+    Test a few things that were broken with the
+    ft implementation before.
+
+ test/api/test-paint.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 108 insertions(+)
+
+commit a4a86c0ec281e0e5ce0cd90822d6b6d633457342
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 13:52:22 2022 -0700
+
+    [test-paint] g_test_message
+
+ test/api/test-paint.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit dcab5679889ff47db6765e1ea853963cf9ee4286
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 13:47:37 2022 -0700
+
+    [test-paint] Don't use g_test_fail_print() for older glib
+
+ test/api/test-paint.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 8e197f50daf6d89a1e6f14cbd9836160d5d3d8c7
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 15:31:16 2022 -0500
+
+    Add missing paint test results
+
+ test/api/results/rocher-120-0-3   | 12 ++++++++++++
+ test/api/results/rocher-120-0.3-1 | 12 ++++++++++++
+ test/api/results/rocher-120-0.3-2 | 12 ++++++++++++
+ 3 files changed, 36 insertions(+)
+
+commit d9875ddc9d7a6b7078906929d98e0606a49f5da4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 12:37:42 2022 -0700
+
+    [ft-colr] Add depth counter
+
+ src/hb-ft-colr.hh | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+commit 3b021c5568bf8fe26b9691075211dad2408ae3b9
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 14:30:29 2022 -0500
+
+    Run paint tests with ft font funcs
+
+ test/api/test-paint.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 56 insertions(+), 3 deletions(-)
+
+commit ca190aaba4878b00bfeda39ae4f8ba6b669e90d3
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 14:03:03 2022 -0500
+
+    Split off the hb-paint tests
+    
+    They belong in their own file.
+
+ test/api/meson.build     |   1 +
+ test/api/test-ot-color.c | 370 -------------------------------------------
+ test/api/test-paint.c    | 400 +++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 401 insertions(+), 370 deletions(-)
+
+commit ecd7420456619dcfffd51b943468ed828c07d5a1
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 13:32:31 2022 -0500
+
+    Debug spew
+    
+    To get a dump of the hb-paint callbacks,
+    set HB_PAINT_DEBUG=1 when running hb-view.
+    
+    For now, leave this code in place, since it
+    comes in handy for various debugging.
+
+ util/helper-cairo-user.hh | 131 ++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 126 insertions(+), 5 deletions(-)
+
+commit 583f010b0506cec061e5a6849da649fe3d2cb22e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 12:10:22 2022 -0700
+
+    [ft] Move lock only around clip_glyph
+
+ src/hb-ft.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 276290390952d0ad26f77247675ad023e0651856
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 12:09:17 2022 -0700
+
+    [ft-colr] Minor
+
+ src/hb-ft-colr.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 3a1385f019082575e93bb92be870e1b5d9c76134
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 12:06:18 2022 -0700
+
+    [ft-colr] Simplify color-stop callback
+
+ src/hb-ft-colr.hh | 98 +++++++++++++++++++++++++------------------------------
+ 1 file changed, 44 insertions(+), 54 deletions(-)
+
+commit 1cc3b10008a2ae52b83466bb0039e2b8d99f7a28
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 11:55:55 2022 -0700
+
+    [ft-colr] Ifdef build for older freetype
+
+ src/hb-ft-colr.hh | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+commit 882c2bca2dcc898b6aa884605013c2609dd775ba
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 11:48:41 2022 -0700
+
+    [ft-colr] Add a paint context
+
+ src/hb-ft-colr.hh | 167 +++++++++++++++++++++++++++++++-----------------------
+ 1 file changed, 95 insertions(+), 72 deletions(-)
+
+commit 7a4b4c64f2f71e3b66833222a153a3f7b56300b3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 11:36:04 2022 -0700
+
+    [ft-colr] Minor macro
+
+ src/hb-ft-colr.hh | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+commit c453c2fce990b066155ccb72d8a39eba55e42a2d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 11:33:23 2022 -0700
+
+    [ft-colr] Fix color-stop iteration
+
+ src/hb-ft-colr.hh | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+commit bbb89e62aa5f876dc0b9348f11ce6a24ab032e47
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 13:30:26 2022 -0500
+
+    [paint] Document color lines as transient
+    
+    Just so people don't get ideas.
+
+ src/hb-paint.h | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+commit 15582d5fc164f8e0a4b5f2df5ef246e213cd85d2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 11:14:16 2022 -0700
+
+    [ft-colr] Apply slant to clipbox
+
+ src/hb-ft-colr.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 7abd5dcf10ea06fb5ba48077734222e7acc41065
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 11:49:06 2022 -0500
+
+    [ft-paint] Fix handling of colorstop iters
+
+ src/hb-ft-colr.hh | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit 393bab4ba1e5938843f83cc824e4a4142b42ff56
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 11:02:38 2022 -0500
+
+    [ft-paint] Apply ClipBox to all glyphs
+
+ src/hb-ft-colr.hh | 41 +++++++++++++++++++++++++++--------------
+ 1 file changed, 27 insertions(+), 14 deletions(-)
+
+commit c11ae85cbfa7b7a13577a058544a39146fc81bbf
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 09:20:45 2022 -0500
+
+    [ft-paint] Apply root transform
+
+ src/hb-ft-colr.hh | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+commit 7fc3fdac761670d9c223768c128f5225a87b47df
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 09:16:26 2022 -0500
+
+    [ft-paint] Optimize away some transforms
+
+ src/hb-ft-colr.hh | 26 ++++++++++++++++----------
+ 1 file changed, 16 insertions(+), 10 deletions(-)
+
+commit 586d1758c1aecf995de85020cb608f3fe5d859cf
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 09:21:14 2022 -0500
+
+    [ft-paint] Fix an oversight
+
+ src/hb-ft-colr.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 092637f94c60bc56ba135bbce1905275bde0925d
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 09:14:11 2022 -0500
+
+    [ft-paint] Fix rounding
+
+ src/hb-ft-colr.hh | 28 ++++++++++++++--------------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+commit fe08e956e0eb89ca26547b00d0a3191db9011af9
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 09:08:10 2022 -0500
+
+    [ft-paint] Fix a case of x/y confusion
+
+ src/hb-ft-colr.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 0d5256e5a729552a6c9b292c42928fc3734a95a7
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 02:41:08 2022 -0500
+
+    [ft-paint] Fix some fixed->float conversions
+
+ src/hb-ft-colr.hh | 30 +++++++++++++++---------------
+ 1 file changed, 15 insertions(+), 15 deletions(-)
+
+commit 07ba5be393f43ea8584074c61a463717ef33d72f
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 01:10:35 2022 -0500
+
+    [paint] Documentation tweaks
+
+ src/hb-paint.cc |  9 +++++----
+ src/hb-paint.h  | 15 +++++----------
+ 2 files changed, 10 insertions(+), 14 deletions(-)
+
+commit 13e0cb64f47f54c54651a239c8633f6d836ea9eb
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 00:54:05 2022 -0500
+
+    hb-view: Interpolate gradients premultiplied
+    
+    This is what the specs demand.
+
+ util/hb-cairo-utils.c | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+commit 21f78c87744c8a119f999f4b02c50009f681db33
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 00:30:40 2022 -0500
+
+    [paint] Document that colors are unpremultiplied
+    
+    And mention that gradient interpolation must happen
+    in premultiplied space.
+
+ src/hb-paint.h | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+commit b6e98cf758b8f38c14dee28b57d63514ace1a97d
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 00:18:40 2022 -0500
+
+    [colr] Add more docs
+    
+    State explicitly that palette entries are
+    unpremultipled, and link to the spec.
+
+ src/hb-font.cc | 15 ++++++++-------
+ 1 file changed, 8 insertions(+), 7 deletions(-)
+
+commit 7a2dc5cf5b41058c6d598cd89f714d81ea325632
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 22:29:52 2022 -0700
+
+    [docs] Hook up a couple
+
+ docs/harfbuzz-sections.txt | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit a634f6b48699b72b3f5bc57aad0c88c713e138f8
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 00:18:40 2022 -0500
+
+    [colr] Add more docs
+    
+    State explicitly that palette entries are
+    unpremultipled, and link to the spec.
+
+ src/hb-ot-color.cc | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit a02c2a911cc59985db00b86b09ed77b755238291
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 22:05:09 2022 -0700
+
+    [ft-paint] Apply alpha correctly
+
+ src/hb-ft-colr.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit ee7bbdf372833a5705a0ba9e012d9665f5731726
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 00:01:20 2022 -0500
+
+    tests: Update expected results
+    
+    These were changed by fixes for glyph transforms.
+
+ test/api/results/hand-20-0-10    | 92 ++++++++++++++++++++++++----------------
+ test/api/results/hand-20-0.2-10  | 92 ++++++++++++++++++++++++----------------
+ test/api/results/rocher-20-0-2   | 12 ------
+ test/api/results/rocher-20-0-3   | 12 ------
+ test/api/results/rocher-20-0.3-1 | 12 ------
+ test/api/results/test-20-0-10    | 18 ++++----
+ test/api/results/test-20-0-106   |  8 +++-
+ test/api/results/test-20-0-116   |  8 +++-
+ test/api/results/test-20-0-123   | 12 ++++--
+ test/api/results/test-20-0-165   | 18 ++++----
+ test/api/results/test-20-0-175   | 20 +++++----
+ test/api/results/test-20-0-6     | 16 ++++---
+ test/api/results/test-20-0-92    | 16 ++++---
+ test/api/test-ot-color.c         |  6 +--
+ 14 files changed, 184 insertions(+), 158 deletions(-)
+
+commit 3993a407037477e384650a1394c27c15596c9a45
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Dec 22 23:55:27 2022 -0500
+
+    test: Add some verification hints
+
+ test/api/test-ot-color.c | 16 +++++++++++-----
+ 1 file changed, 11 insertions(+), 5 deletions(-)
+
+commit 6ebcc9d2e16ca4d7eaad2002ea8209dce5e9ed90
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 21:23:45 2022 -0700
+
+    [ft-paint] Hook up gradients
+
+ src/hb-ft-colr.hh | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 122 insertions(+), 3 deletions(-)
+
+commit fe4e9bd93070daa2b8ac3bb8201e3736faab752b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 20:14:19 2022 -0700
+
+    [colr] Add public vtable for hb_color_line_t
+
+ src/hb-ot-color-colr-table.cc | 47 ---------------------------------
+ src/hb-ot-color-colr-table.hh | 44 ++++++++++++++++++++++++-------
+ src/hb-paint.cc               | 49 +++++++++++++++++++++++++++++++++++
+ src/hb-paint.h                | 60 ++++++++++++++++++++++++++++++++-----------
+ 4 files changed, 129 insertions(+), 71 deletions(-)
+
+commit 7c9e42ed924d7e286b666e9206532cf1dac76955
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 19:49:06 2022 -0700
+
+    [colr] Fix transform hell
+
+ src/hb-ot-color-colr-table.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 569d5b436cff95fbd7753aebb443ecc682d248c8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 18:00:02 2022 -0700
+
+    [ft-paint] Remove dead code
+
+ src/hb-ft-colr.hh | 6 ------
+ 1 file changed, 6 deletions(-)
+
+commit cfdc34b44d97bedfe482612f885f52641452390f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 17:58:36 2022 -0700
+
+    [ft-paint] Implement FT_COLR_PAINTFORMAT_SKEW
+
+ src/hb-ft-colr.hh | 21 ++++++++++++++++++++-
+ 1 file changed, 20 insertions(+), 1 deletion(-)
+
+commit 64cf17ec8b616dcf0a6254c56498b3b53cd4b933
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 17:55:25 2022 -0700
+
+    [ft-paint] Fix center translation
+
+ src/hb-ft-colr.hh | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+commit ddbe4e52ec05bca0c284192af41df7479edd2ecd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 17:54:01 2022 -0700
+
+    [ft-paint] Implement FT_COLR_PAINTFORMAT_ROTATE
+
+ src/hb-ft-colr.hh | 20 +++++++++++++++++++-
+ 1 file changed, 19 insertions(+), 1 deletion(-)
+
+commit 16598e024bd79796878650b9e723b02269e8f9d4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 17:51:35 2022 -0700
+
+    [ft-paint] Default
+
+ src/hb-ft-colr.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit a0f7f9e61cca50dfbf6969c1dfd088301ac89318
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 17:50:35 2022 -0700
+
+    [ft-paint] Implement FT_COLR_PAINTFORMAT_COMPOSITE
+
+ src/hb-ft-colr.hh | 67 ++++++++++++++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 57 insertions(+), 10 deletions(-)
+
+commit 0ec201446bf0f8b776a8820e97d76b4357036e2f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 17:40:53 2022 -0700
+
+    [ft] Implement FT_COLR_PAINTFORMAT_COLR_GLYPH
+
+ src/hb-ft-colr.hh | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+commit ac2682c610e64d47d9de0f5c742779a3b8f48f80
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 17:36:54 2022 -0700
+
+    [ft] Start of a COLRv1 renderer
+
+ src/hb-ft-colr.hh | 164 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 161 insertions(+), 3 deletions(-)
+
+commit e2546f5ab0fa440206ef501b382c19e8409ada61
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 15:50:43 2022 -0700
+
+    [ft] Add hb-ft-colr.hh
+
+ src/Makefile.sources |   2 +-
+ src/hb-ft-colr.hh    | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-ft.cc         |  60 ++++--------------------------
+ src/meson.build      |   2 +-
+ 4 files changed, 112 insertions(+), 54 deletions(-)
+
+commit 5bd3c07b5475dac69e33403f8c33b137cf9281d2
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Dec 22 16:23:50 2022 -0500
+
+    [colr] Don't access baseGlyphList unless v1
+    
+    This was showing up sporadic crashes due to
+    invalid reads.
+
+ src/hb-ot-color-colr-table.hh | 22 ++++++++++++----------
+ 1 file changed, 12 insertions(+), 10 deletions(-)
+
+commit 47dbebff393dcb121f058b43977bf8d931b19b1e
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Dec 22 16:06:51 2022 -0500
+
+    [paint] Add COLRv0 tests
+
+ test/api/fonts/RocherColorGX.abc.ttf | Bin 0 -> 7588 bytes
+ test/api/results/rocher-20-0-2       |  12 ++++++++++++
+ test/api/results/rocher-20-0-3       |  12 ++++++++++++
+ test/api/results/rocher-20-0.3-1     |  12 ++++++++++++
+ test/api/test-ot-color.c             |  35 +++++++++++++++++++++++------------
+ 5 files changed, 59 insertions(+), 12 deletions(-)
+
+commit 6909701b36e989a9bd0f581bf4959f8c706116a7
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Dec 22 15:32:09 2022 -0500
+
+    [paint] Update docs
+
+ src/hb-paint.h | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit 381d410b1eae1a292741a78920ff2e0fb436df55
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 13:21:48 2022 -0700
+
+    [paint] Add HB_PAINT_IMAGE_FORMAT_BGRA and use it in hb-ft
+    
+    Now hb-ft can render color emoji as well.
+    
+    Just left COLRv2.
+
+ docs/harfbuzz-sections.txt |  4 +++
+ src/hb-ft.cc               | 39 ++++++++++++++++++++++-
+ src/hb-paint.h             | 18 +++++++++--
+ util/hb-cairo-utils.c      | 78 +++++++++++++++++++++++++++++++++++++++-------
+ 4 files changed, 125 insertions(+), 14 deletions(-)
+
+commit 63db0d2aed3cda83470bae5c2c8128d1bc54ac46
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 12:19:33 2022 -0700
+
+    [util] Speculatively fix build against non-PNG builds
+
+ util/hb-cairo-utils.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit c5f903872fdb9d7221acd6910a9c5c5acabf99a9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 12:16:55 2022 -0700
+
+    [paint] Add bitmap width/height to paint_image callback
+    
+    Such that we can add raw data as well.
+
+ src/hb-ot-color-cbdt-table.hh | 45 ++++++++++++++++++++++++++++---------------
+ src/hb-ot-color-sbix-table.hh | 31 ++++++++++++++++-------------
+ src/hb-ot-color-svg-table.hh  |  7 ++++++-
+ src/hb-paint.cc               |  2 ++
+ src/hb-paint.h                |  8 ++++++--
+ src/hb-paint.hh               |  3 ++-
+ util/hb-cairo-utils.c         |  9 +++++++--
+ util/hb-cairo-utils.h         |  2 ++
+ util/helper-cairo-user.hh     |  4 +++-
+ 9 files changed, 75 insertions(+), 36 deletions(-)
+
+commit eef47f2379a3509a2f306fb3e6207f4541b96b73
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Dec 22 14:16:02 2022 -0500
+
+    [paint] Fix the docs
+
+ src/hb-paint.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 3c972867b97a0fbca5bef25ebfd7cbdab008a102
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 11:40:06 2022 -0700
+
+    More s/hb_font_get_glyph_shape/hb_font_draw_glyph/
+
+ perf/benchmark-font.cc         |  2 +-
+ src/hb-draw.h                  | 10 ++---
+ test/api/test-draw.c           | 88 +++++++++++++++++++++---------------------
+ test/fuzzing/hb-draw-fuzzer.cc |  2 +-
+ 4 files changed, 51 insertions(+), 51 deletions(-)
+
+commit 72a169c846c9be92d5ac5d0b2bc051d6ef5e8e6f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 11:26:10 2022 -0700
+
+    [ft] Paint COLRv0 glyphs
+
+ src/hb-ft.cc | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 64 insertions(+), 13 deletions(-)
+
+commit bb807f47d22f23a2da348f0498282c9ae7b81ab9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 10:51:26 2022 -0700
+
+    [ft] Implement paint_glyph() for outline glyphs
+
+ src/hb-ft.cc | 46 +++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 45 insertions(+), 1 deletion(-)
+
+commit 91c880503e7b194c9fc15cfe43eae4c70b1b19f9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 10:42:27 2022 -0700
+
+    [ft] Use new name for draw API
+
+ src/hb-ft.cc | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit c27eefec1df85d1648106c3d0ae7d2e740c5cedc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 10:41:13 2022 -0700
+
+    Revert "Drop the deprecation"
+    
+    This reverts commit 3904e66777339a3d420ece1c2b7d550949aa3946.
+
+ src/hb-font.h | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit f3985d948279c00518d5f3dea925a71a8e2be23f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 10:11:28 2022 -0700
+
+    [paint] Fix drawing non-color glyphs
+
+ src/OT/glyf/glyf.hh     | 6 +-----
+ src/hb-ot-cff1-table.cc | 6 +-----
+ src/hb-ot-cff2-table.cc | 6 +-----
+ 3 files changed, 3 insertions(+), 15 deletions(-)
+
+commit 237955dffca19bc320ca1b94808b52265ef653ed
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 08:12:47 2022 -0700
+
+    [paint] Add slant to image() callback
+    
+    And slant images in hb-view.
+
+ src/hb-ot-color-cbdt-table.hh | 2 +-
+ src/hb-ot-color-sbix-table.hh | 2 +-
+ src/hb-ot-color-svg-table.hh  | 2 +-
+ src/hb-paint.cc               | 1 +
+ src/hb-paint.h                | 1 +
+ src/hb-paint.hh               | 3 ++-
+ util/hb-cairo-utils.c         | 7 +++++++
+ util/hb-cairo-utils.h         | 1 +
+ util/helper-cairo-user.hh     | 3 ++-
+ 9 files changed, 17 insertions(+), 5 deletions(-)
+
+commit c221933977bdcf272fd9f2ded5e1182de8ae1939
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 21 18:39:27 2022 -0500
+
+    [paint] Preserve foreground information
+
+ src/OT/glyf/glyf.hh           |  2 +-
+ src/hb-ot-cff1-table.cc       |  2 +-
+ src/hb-ot-cff2-table.cc       |  2 +-
+ src/hb-ot-color-colr-table.hh | 23 +++++++++++++++++------
+ src/hb-paint.cc               |  1 +
+ src/hb-paint.h                |  4 ++++
+ src/hb-paint.hh               |  3 ++-
+ test/api/test-ot-color.c      |  1 +
+ util/helper-cairo-user.hh     |  1 +
+ 9 files changed, 29 insertions(+), 10 deletions(-)
+
+commit f146299a405b8338542a245b85e664de29f0c972
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 21 17:24:02 2022 -0500
+
+    [paint] Drop unnecessary api
+
+ docs/harfbuzz-sections.txt |  13 ---
+ src/hb-paint.cc            | 237 ---------------------------------------------
+ src/hb-paint.h             |  59 -----------
+ 3 files changed, 309 deletions(-)
+
+commit 6387004cadd8f5bc755f5b14c95fd71153bcc48b
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 21 16:43:19 2022 -0500
+
+    [paint] Simplify api
+    
+    Drop the hb_paint_context_t struct from the API, and
+    only pass the font where we need it.
+
+ docs/harfbuzz-sections.txt    |   1 -
+ src/OT/glyf/glyf.hh           |  16 +--
+ src/hb-font.cc                |  12 +--
+ src/hb-ot-cff1-table.cc       |  16 +--
+ src/hb-ot-cff2-table.cc       |  16 +--
+ src/hb-ot-color-cbdt-table.hh |   7 +-
+ src/hb-ot-color-colr-table.cc |  12 +--
+ src/hb-ot-color-colr-table.hh | 242 +++++++++++++++++++++---------------------
+ src/hb-ot-color-sbix-table.hh |   3 +-
+ src/hb-ot-color-svg-table.hh  |   4 +-
+ src/hb-paint.cc               |  85 +++++----------
+ src/hb-paint.h                |  84 +++------------
+ src/hb-paint.hh               |  90 ++++------------
+ test/api/test-ot-color.c      |  13 +--
+ util/hb-cairo-utils.c         |  31 +-----
+ util/hb-cairo-utils.h         |   9 --
+ util/helper-cairo-user.hh     |  23 ++--
+ 17 files changed, 216 insertions(+), 448 deletions(-)
+
+commit 71bd5a0dfc34efdf61a641b8ba98303524adeb9a
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 21 16:18:46 2022 -0500
+
+    [paint] Resolve colors
+    
+    We don't need to pass the index/alpha pairs to
+    client callbacks, and can just resolve the colors
+    internally.
+    
+    Update test results.
+
+ src/OT/glyf/glyf.hh             |  2 +-
+ src/hb-ot-cff1-table.cc         |  3 ++-
+ src/hb-ot-cff2-table.cc         |  2 +-
+ src/hb-ot-color-colr-table.cc   |  4 ++--
+ src/hb-ot-color-colr-table.hh   | 31 ++++++++++++++++++-------------
+ src/hb-paint.cc                 | 11 ++++-------
+ src/hb-paint.h                  | 33 +++++++--------------------------
+ src/hb-paint.hh                 | 27 ++++++++++++++++++++++++---
+ test/api/results/hand-20-0-10   | 34 +++++++++++++++++-----------------
+ test/api/results/hand-20-0.2-10 | 34 +++++++++++++++++-----------------
+ test/api/results/test-20-0-10   |  8 ++++----
+ test/api/results/test-20-0-106  |  4 ++--
+ test/api/results/test-20-0-116  |  4 ++--
+ test/api/results/test-20-0-123  |  6 +++---
+ test/api/results/test-20-0-165  |  6 +++---
+ test/api/results/test-20-0-175  |  6 +++---
+ test/api/results/test-20-0-6    |  4 ++--
+ test/api/results/test-20-0-92   |  6 +++---
+ test/api/test-ot-color.c        | 18 +++++++++++++-----
+ util/hb-cairo-utils.c           | 29 ++++++++++++++++++++++-------
+ util/helper-cairo-user.hh       | 11 ++++++-----
+ 21 files changed, 156 insertions(+), 127 deletions(-)
+
+commit bd1389bedf891311177b3aa9804aa4474c6758d0
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 21 15:23:43 2022 -0500
+
+    [paint] Add hb_paint_context_t to docs
+
+ docs/harfbuzz-sections.txt | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 5d7553d38f178c1c071f356f98bbf43d21b4ce29
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 21 15:18:02 2022 -0500
+
+    view: Add a --font-palette option
+
+ util/font-options.hh      |  2 ++
+ util/helper-cairo-user.hh | 10 +++++++++-
+ util/helper-cairo.hh      |  3 +++
+ 3 files changed, 14 insertions(+), 1 deletion(-)
+
+commit d094e76cbc84dc13de35e2837ffe6d1a8aa51fab
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 21 15:02:41 2022 -0500
+
+    hb-view: Pass fg color to hb_font_paint_glyph
+
+ util/helper-cairo-user.hh | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+commit 9be01b6bff054e3edb516ca680a1e33b05a74e9b
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 21 14:04:32 2022 -0500
+
+    [paint] Pass hb_paint_context_t along
+    
+    Replace the font argument with a hb_paint_context_t
+    that carries the font, the palette index and the
+    foreground color.
+    
+    The hb_font_paint_glyph() api now takes the palette
+    index and the foreground color as extra arguments.
+    
+    Update all callers and regenerate test results.
+
+ src/OT/glyf/glyf.hh             |  18 ++++--
+ src/hb-font.cc                  |  24 ++++++--
+ src/hb-font.h                   |   9 ++-
+ src/hb-font.hh                  |   5 +-
+ src/hb-ot-cff1-table.cc         |  19 ++++---
+ src/hb-ot-cff1-table.hh         |   2 +-
+ src/hb-ot-cff2-table.cc         |  20 ++++---
+ src/hb-ot-cff2-table.hh         |   2 +-
+ src/hb-ot-color-cbdt-table.hh   |   8 ++-
+ src/hb-ot-color-colr-table.cc   |   4 +-
+ src/hb-ot-color-colr-table.hh   | 119 ++++++++++++++++++++--------------------
+ src/hb-ot-color-sbix-table.hh   |   3 +-
+ src/hb-ot-color-svg-table.hh    |   4 +-
+ src/hb-ot-font.cc               |  10 ++--
+ src/hb-paint.cc                 |  98 ++++++++++++++++-----------------
+ src/hb-paint.h                  |  95 ++++++++++++++++++++------------
+ src/hb-paint.hh                 |  66 +++++++++++-----------
+ test/api/results/hand-20-0-10   |  18 +++---
+ test/api/results/hand-20-0.2-10 |  18 +++---
+ test/api/results/test-20-0-10   |   2 +-
+ test/api/results/test-20-0-106  |   4 +-
+ test/api/results/test-20-0-116  |   4 +-
+ test/api/results/test-20-0-123  |   6 +-
+ test/api/results/test-20-0-165  |   2 +-
+ test/api/results/test-20-0-175  |   4 +-
+ test/api/results/test-20-0-6    |   2 +-
+ test/api/results/test-20-0-92   |   2 +-
+ test/api/test-ot-color.c        |  26 ++++-----
+ util/hb-cairo-utils.c           |  51 +++++++----------
+ util/hb-cairo-utils.h           |  17 +++---
+ util/helper-cairo-user.hh       |  38 ++++++-------
+ 31 files changed, 384 insertions(+), 316 deletions(-)
+
+commit 6c71c530caaa40c0038ac1f33549a5a7f96266c3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Dec 21 10:54:22 2022 -0700
+
+    [paint] Rename hb_paint_context_t to hb_ot_paint_context_t
+
+ src/hb-ot-color-colr-table.cc |  4 ++--
+ src/hb-ot-color-colr-table.hh | 56 +++++++++++++++++++++----------------------
+ 2 files changed, 30 insertions(+), 30 deletions(-)
+
+commit 8495395397e5a26dacad0cad689a41b06ef5314c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Dec 21 09:03:13 2022 -0700
+
+    [paint] Fix slant
+
+ src/hb-paint.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b1500babaae38cb6d81bc4287adeb4678dfde1b3
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 21 09:49:42 2022 -0500
+
+    utils: Some cairo helper tweaks
+
+ util/hb-cairo-utils.c     | 64 +++++++++++++++++++++++------------------------
+ util/hb-cairo-utils.h     | 10 ++++----
+ util/helper-cairo-user.hh | 19 ++++++++------
+ 3 files changed, 48 insertions(+), 45 deletions(-)
+
+commit 97224f3b63e7d8ec74acabc1270ebf021c19afd6
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 21 02:11:36 2022 -0500
+
+    [paint] Pass font to all callbacks
+    
+    This will lead to easier implementations.
+    
+    At the same time, we change the push_clip_glyph
+    callback to use the font as-is, no unscaling needed.
+    
+    Update all callers and expected test results.
+
+ src/OT/glyf/glyf.hh                                |   8 +-
+ src/hb-font.cc                                     |   5 +-
+ src/hb-ot-cff1-table.cc                            |   8 +-
+ src/hb-ot-cff2-table.cc                            |   8 +-
+ src/hb-ot-color-cbdt-table.hh                      |   2 +-
+ src/hb-ot-color-colr-table.cc                      |   4 +-
+ src/hb-ot-color-colr-table.hh                      | 137 ++++++++++++---------
+ src/hb-ot-color-sbix-table.hh                      |   2 +-
+ src/hb-ot-color-svg-table.hh                       |   2 +-
+ src/hb-paint.cc                                    |  84 +++++++++----
+ src/hb-paint.h                                     |  65 +++++++---
+ src/hb-paint.hh                                    |  79 +++++++++---
+ src/hb.h                                           |   2 +-
+ test/api/results/hand-20-0-10                      |  97 +++++++++++++++
+ test/api/results/hand-20-0-10.txt                  |  79 ------------
+ test/api/results/hand-20-0.2-10                    |  97 +++++++++++++++
+ test/api/results/hand-20-0.2-10.txt                |  79 ------------
+ test/api/results/test-20-0-10                      |  14 +++
+ test/api/results/test-20-0-10.txt                  |  12 --
+ .../results/{test-20-0-106.txt => test-20-0-106}   |  16 ++-
+ test/api/results/test-20-0-116                     |  18 +++
+ test/api/results/test-20-0-116.txt                 |  14 ---
+ .../results/{test-20-0-123.txt => test-20-0-123}   |  24 ++--
+ test/api/results/test-20-0-165                     |  14 +++
+ test/api/results/test-20-0-165.txt                 |  12 --
+ test/api/results/test-20-0-175                     |  26 ++++
+ test/api/results/test-20-0-175.txt                 |  22 ----
+ test/api/results/test-20-0-6                       |  13 ++
+ test/api/results/test-20-0-6.txt                   |  11 --
+ test/api/results/test-20-0-92                      |  13 ++
+ test/api/results/test-20-0-92.txt                  |  11 --
+ test/api/test-ot-color.c                           |  40 +++---
+ util/helper-cairo-user.hh                          |  78 +++++-------
+ 33 files changed, 639 insertions(+), 457 deletions(-)
+
+commit 32ce29f99ea7387ce32de1114b1ce1c876fb6fbe
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 21 07:42:36 2022 -0500
+
+    [font] Move hb_font_t typedef
+    
+    This is needed to avoid circular header dependencies.
+
+ src/hb-common.h | 8 ++++++++
+ src/hb-font.h   | 9 ---------
+ src/hb-paint.h  | 3 +--
+ 3 files changed, 9 insertions(+), 11 deletions(-)
+
+commit 8364d9130f72a80802153efc7e22ac85bb38fe8f
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 21 00:59:13 2022 -0500
+
+    Document hb_font_set_draw_glyph_func
+
+ src/hb-font.h | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+commit a20999b9df313702643f012845cee4e266236985
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 21 00:20:37 2022 -0500
+
+    [font] Fix a few documentation mistakes
+
+ src/hb-font.cc | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+commit 754528914d98db1e30192cc07de4e3df879d5d8a
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 21 00:09:25 2022 -0500
+
+    [docs] Reorder paint section
+
+ docs/harfbuzz-sections.txt | 23 +++++++++++------------
+ 1 file changed, 11 insertions(+), 12 deletions(-)
+
+commit 2333a566edbe99402d66086dd820a02335f56899
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Tue Dec 20 22:43:04 2022 -0500
+
+    Drop the deprecation
+    
+    No need to drop hb_font_get_glyph_shape, just
+    because hb_font_draw_glyph does the same.
+    
+    Its fine to keep both around.
+
+ src/hb-font.h | 4 ----
+ 1 file changed, 4 deletions(-)
+
+commit cf02d13302941b964e2c3b63485eeb023698d26b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Dec 20 11:52:39 2022 -0700
+
+    [cairo] Remove unused struct
+
+ util/hb-cairo-utils.c | 7 -------
+ 1 file changed, 7 deletions(-)
+
+commit 14b026ff86f55436897702e268cf6c7eddbb0859
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 19 13:53:49 2022 -0500
+
+    [draw] Add hb_font_draw_glyph
+    
+    hb_font_draw_glyph(), hb_font_draw_glyph_func_t and
+    hb_font_funcs_set_draw_glyph_func() are just alternative
+    names for hb_font_get_glyph_shape and friends, to better
+    align with hb_font_paint_glyph.
+
+ src/hb-draw.cc    |  2 ++
+ src/hb-font.cc    | 76 +++++++++++++++++++++++++++++++++++++++----------------
+ src/hb-font.h     | 46 ++++++++++++++++++++++++++++++++-
+ src/hb-font.hh    | 14 +++++-----
+ src/hb-ot-font.cc | 12 ++++-----
+ 5 files changed, 114 insertions(+), 36 deletions(-)
+
+commit 08da126523d1cdfdcd527f7bdf10c2d3525196e4
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 19 14:36:29 2022 -0500
+
+    [docs] Linkify links
+
+ src/hb-paint.h | 26 +++++++++++++-------------
+ 1 file changed, 13 insertions(+), 13 deletions(-)
+
+commit 9437f719a7217ddb2231709ead03c4b62cbdb42f
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 19 14:29:39 2022 -0500
+
+    [paint] Document hb_paint_extend_t
+
+ src/hb-paint.h | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+commit 3a2634e27cf6f1df164aacb70b2e107eab2a15e6
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 19 13:48:08 2022 -0500
+
+    [paint] Document hb_font_paint_glyph_func_t
+
+ docs/harfbuzz-sections.txt |  2 ++
+ src/hb-font.h              | 13 +++++++++++++
+ 2 files changed, 15 insertions(+)
+
+commit 0f287e75ece6364bc3fcdd752de837f8ef51529d
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 19 13:45:45 2022 -0500
+
+    [paint] Rename hb_font_get_glyph_paint_func_t
+    
+    The 'get' was just there due to implementation
+    choices. Work around that and call the vfunc
+    what it should be: hb_font_paint_glyph_func_t.
+
+ src/hb-font.cc    | 40 ++++++++++++++++++++--------------------
+ src/hb-font.h     | 16 ++++++++--------
+ src/hb-font.hh    | 54 +++++++++++++++++++++++++++---------------------------
+ src/hb-ot-font.cc | 12 ++++++------
+ 4 files changed, 61 insertions(+), 61 deletions(-)
+
+commit b0fa40b2ece482818bfc9e71b2f173e43b9dd6dd
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 19 13:16:10 2022 -0500
+
+    tests: More diagnostics
+
+ test/api/test-ot-color.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit ddd2039265e3bf20bb4809d57905f83c42e61b97
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 19 12:20:07 2022 -0500
+
+    [paint] Improve the docs
+
+ src/hb-paint.cc | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+commit 3a219cfa6a2bef8eb79dd86c2210485a71aece1d
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 19 11:15:37 2022 -0500
+
+    [config] Make HB_LEAN imply HB_NO_PAINT
+
+ src/hb-config.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 0ef2dc9be557cc247621019933ca5151a4bd80cd
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 19 10:02:17 2022 -0500
+
+    Drop a TODO
+    
+    This was addressed in 61bd602791d801
+
+ src/hb-font.cc | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 96cda3886ceffc4264587576100d56f16c150ad0
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 19 09:59:33 2022 -0500
+
+    [paint] Clarify docs
+    
+    Spell out where the different datas originate.
+
+ src/hb-paint.h | 50 +++++++++++++++++++++++++-------------------------
+ 1 file changed, 25 insertions(+), 25 deletions(-)
+
+commit 290bb338bf9a881e38899cd0391146ef7a52b2b1
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 19 02:39:14 2022 -0500
+
+    Dist test result files
+
+ test/api/Makefile.am | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit a3ba723876d4da299cd13d70a3accab1b0672ffb
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 19 02:22:34 2022 -0500
+
+    Drop an unneeded include
+
+ util/hb-cairo-utils.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 74ccc1e76df3dafbc48e02818403d0f0688cf8ca
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 19 00:49:02 2022 -0500
+
+    tests: Produce useful output on failure
+
+ test/api/test-ot-color.c | 32 ++++++++++++++++++++++++++++++--
+ 1 file changed, 30 insertions(+), 2 deletions(-)
+
+commit 084291108ac59a0a99b2cde58073ad4377dfdd82
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 19 01:08:41 2022 -0500
+
+    Tests: Fix memleak pointed out by valgrind
+
+ test/api/test-ot-color.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 0800d1879c7aafb038e47793c9f3495da0221969
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 19 00:59:40 2022 -0500
+
+    Try to fix autotools build
+
+ src/Makefile.sources  | 3 +++
+ util/Makefile.sources | 2 ++
+ 2 files changed, 5 insertions(+)
+
+commit 5ac218865ad7df1643c8b70e527cc792415c28d0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 19 10:26:54 2022 -0700
+
+    [paint] A doc fix
+
+ src/hb-font.h   | 4 ++++
+ src/hb-paint.cc | 2 +-
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+commit 5451b78f4a4d97277d3a411762844e97adda62cd
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 19 00:07:18 2022 -0500
+
+    Don't use alloca
+    
+    It complicates things on Windows, for no
+    big win. Just preallocate a reasonable amount.
+
+ util/hb-cairo-utils.c | 58 +++++++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 45 insertions(+), 13 deletions(-)
+
+commit 7c12db46ff3fd771db4cc2d2cc6fea8937b34532
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Dec 18 23:36:05 2022 -0500
+
+    Try to fix msvc build
+
+ src/hb-ot-color-colr-table.hh | 2 +-
+ util/hb-cairo-utils.c         | 5 +++++
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+commit d2b420589bb65e92385383966cf2a8c9865abc49
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Dec 18 16:43:19 2022 -0500
+
+    [docs] Add hb-paint apis
+
+ docs/harfbuzz-docs.xml     |  1 +
+ docs/harfbuzz-sections.txt | 62 ++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 63 insertions(+)
+
+commit d8cb7ceefb31600b288da05c2c09476953dafc91
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 18 14:35:36 2022 -0700
+
+    [test] Try fixing bots with old glib
+
+ test/api/test-ot-color.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 5d1fc9ee9dcec13a45bfc19f53894ad83f42a2a0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 18 14:25:39 2022 -0700
+
+    [paint] Fix annotations
+
+ src/hb-paint.cc | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit 3590ee74f49fa571af145f788f2db6e122021116
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 18 13:59:56 2022 -0700
+
+    [util] Fix bot
+
+ util/helper-cairo-user.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit ee2204469ebfe3a3e9c76e856a7e0c8aab1dd946
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 18 13:50:34 2022 -0700
+
+    [paint] Add get_empty / [sg]et_user_data
+
+ src/hb-cplusplus.hh |  2 +-
+ src/hb-draw.cc      |  1 -
+ src/hb-paint.cc     | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-paint.h      | 15 ++++++++++++++
+ 4 files changed, 74 insertions(+), 2 deletions(-)
+
+commit 21a9db875ed9204ac45093e97354158012b4b35f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 18 13:47:22 2022 -0700
+
+    [draw] Add get_empty / [sg]et_user_data
+
+ docs/harfbuzz-sections.txt |  3 +++
+ src/hb-cplusplus.hh        |  2 ++
+ src/hb-draw.cc             | 58 ++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-draw.h              | 15 ++++++++++++
+ 4 files changed, 78 insertions(+)
+
+commit 9a7422c5fb9eefa3c73cde387512e1de4adaa946
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 18 13:46:32 2022 -0700
+
+    [font] Minor doc fix
+
+ src/hb-font.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit a9b37206eb1e254b24226b5115932aa40f20f7d9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 18 13:37:32 2022 -0700
+
+    [font] Minor rename
+
+ src/hb-font.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 815544a1f7ce0cd9da6cb632e7309ba31ed53faf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 18 13:33:54 2022 -0700
+
+    [font] Adapt paint_glyph to parent transform
+
+ src/hb-font.cc | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+commit 81bf08927361ae57563b02774523f7ce83903ea1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 18 13:15:49 2022 -0700
+
+    [hb-view] Use color render callback if HB_DRAW >= 2
+
+ util/helper-cairo-user.hh | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+commit c65f580b932daf7492d09c30462bf470247f794d
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Dec 18 15:13:55 2022 -0500
+
+    Drop hb-test
+    
+    This was a test binary to assist in developing
+    the hb-paint code. Not needed anymore, now that
+    hb-view has the same code in the cairo userfont
+    backend.
+
+ util/hb-test.c   | 350 -------------------------------------------------------
+ util/meson.build |   7 --
+ 2 files changed, 357 deletions(-)
+
+commit 85917e5b2143e212224e7950d8ee97ccd14b9ee0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 18 13:08:45 2022 -0700
+
+    [paint] Fix docs
+
+ src/hb-paint.h | 24 ++++++++++++------------
+ 1 file changed, 12 insertions(+), 12 deletions(-)
+
+commit 14bf3aaa8d276470c826f095bc0f8d57ff930b38
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 18 12:59:35 2022 -0700
+
+    [colr] Make paint_image work again
+
+ src/hb-ot-color-cbdt-table.hh | 4 ----
+ src/hb-ot-color-sbix-table.hh | 4 ----
+ 2 files changed, 8 deletions(-)
+
+commit 9672aa8610d605617fc2465b0c5d5dc2fc33079f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 18 12:57:42 2022 -0700
+
+    [util] Fix compiler warning
+
+ util/hb-cairo-utils.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 955bd30365d8bb7998515e0714c3aec94e284440
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Dec 18 14:55:56 2022 -0500
+
+    Fix hb-cairo-utils
+    
+    This was a stupid mistake, and hard to track down.
+
+ util/hb-cairo-utils.c | 2 ++
+ util/hb-cairo-utils.h | 1 +
+ 2 files changed, 3 insertions(+)
+
+commit 35739567058b61a4545228ea5b832576f2824f63
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 18 12:56:01 2022 -0700
+
+    [util] Include stdio.h
+
+ util/hb-cairo-utils.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 7accbe97d8dd0e55484fd4d1e76acea1c89c8ae1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 18 12:51:26 2022 -0700
+
+    [util] Fix argument order and root transform PNGs
+
+ src/hb-ot-color-cbdt-table.hh | 6 +++++-
+ src/hb-ot-color-sbix-table.hh | 6 +++++-
+ util/hb-cairo-utils.c         | 9 +++------
+ 3 files changed, 13 insertions(+), 8 deletions(-)
+
+commit 529dc40d7db9bee1075fc16ba0971ad265ffac11
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 18 12:35:50 2022 -0700
+
+    [util] Adjust scaling
+    
+    Still doesn't render PNGs.
+    
+    Fix a few compiler warnings
+
+ util/hb-cairo-utils.c | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+commit bcc9ab27fcf02d57333a9bfc06261eede85c0746
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 18 11:59:54 2022 -0700
+
+    [hb-view] Fix transformation
+    
+    No need for cairo patch; that patch was wrong.
+
+ util/helper-cairo-user.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c996fc58ec8997242d853b8bfac4f4f9c3d96605
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 18 11:36:58 2022 -0700
+
+    [hb-view] Remove redundant check
+
+ util/helper-cairo-user.hh | 3 ---
+ 1 file changed, 3 deletions(-)
+
+commit bec5354030e003e17aff2c0394c0b706d69cda73
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 18 11:26:46 2022 -0700
+
+    [hb-view] Fix render_color_glyph extents coordinate system
+    
+    Needs cairo fix:
+    https://gitlab.freedesktop.org/cairo/cairo/-/merge_requests/371
+
+ util/helper-cairo-user.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 95ccd66481768d443ac7aaeb1588823a79948944
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 18 11:08:25 2022 -0700
+
+    [hb-view] Set glyph extents in render_color_glyph
+    
+    Works around limitation in cairo-recording-surface unboundedness.
+    
+    Extents are wrong but at least renders something now.
+
+ util/helper-cairo-user.hh | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+commit 6cadf280f286f5ad59466d71fd2b7f8c2fd5d267
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Dec 18 09:42:18 2022 -0500
+
+    Use hb-cairo-utils in hb-test
+    
+    Just to prove that it works.
+
+ util/hb-test.c   | 1029 ++++++++----------------------------------------------
+ util/meson.build |    2 +-
+ 2 files changed, 144 insertions(+), 887 deletions(-)
+
+commit 8bcd13dd91916a436fa357fa73f9d4477d8a02ff
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Dec 18 09:41:00 2022 -0500
+
+    small fixup to hb-cairo-utils
+
+ util/hb-cairo-utils.h | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+commit f1f8d1e855a4628a59bfc9b8b55d94a9e35e31de
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Dec 18 02:43:25 2022 -0500
+
+    Small documentation addition
+
+ src/hb-font.cc | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 6c49822cad38b071212823a303059e0917aeedfa
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Dec 18 01:52:39 2022 -0500
+
+    wip: Use hb-paint in hb-view
+    
+    This doesn't paint anything yet.
+
+ util/hb-cairo-utils.c     | 727 ++++++++++++++++++++++++++++++++++++++++++++++
+ util/hb-cairo-utils.h     | 104 +++++++
+ util/helper-cairo-user.hh | 362 ++++++++++++++---------
+ util/meson.build          |   1 +
+ 4 files changed, 1061 insertions(+), 133 deletions(-)
+
+commit 021618e91ae26ef7af1fae4eb0693258e48a7d2a
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Dec 18 00:12:32 2022 -0500
+
+    [colr] Add hb_ot_color_has_paint
+    
+    This is a counterpart to hb_ot_color_has_layers
+    for COLRv1 data.
+
+ src/hb-ot-color-colr-table.hh |  3 ++-
+ src/hb-ot-color.cc            | 30 ++++++++++++++++++++----------
+ src/hb-ot-color.h             |  5 +++++
+ 3 files changed, 27 insertions(+), 11 deletions(-)
+
+commit 63fcb26c9b771f6ab492dad896a4da911fb0427e
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 22:41:34 2022 -0500
+
+    Add some more docs
+
+ src/hb-ot-color.cc | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+commit 2d4678b6478874288312cfe773d735c351d04b0f
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 22:30:31 2022 -0500
+
+    Add a comment
+
+ test/api/test-ot-color.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 3b32eab38e3212464239f32ad294d30d943a3ae2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 17 17:13:30 2022 -0700
+
+    [colr] Fix compiler warning
+
+ util/hb-test.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 30a6fd04d00624129b13b20fb755d6c1c4982637
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 18:20:00 2022 -0500
+
+    [colr] Add some tests
+
+ test/api/fonts/noto_handwriting-cff2_colr_1.otf | Bin 0 -> 4172 bytes
+ test/api/fonts/test_glyphs-glyf_colr_1.ttf      | Bin 0 -> 16704 bytes
+ test/api/results/hand-20-0-10.txt               |  79 ++++++
+ test/api/results/hand-20-0.2-10.txt             |  79 ++++++
+ test/api/results/test-20-0-10.txt               |  12 +
+ test/api/results/test-20-0-106.txt              |  18 ++
+ test/api/results/test-20-0-116.txt              |  14 ++
+ test/api/results/test-20-0-123.txt              |  31 +++
+ test/api/results/test-20-0-165.txt              |  12 +
+ test/api/results/test-20-0-175.txt              |  22 ++
+ test/api/results/test-20-0-6.txt                |  11 +
+ test/api/results/test-20-0-92.txt               |  11 +
+ test/api/test-ot-color.c                        | 312 ++++++++++++++++++++++++
+ 13 files changed, 601 insertions(+)
+
+commit 451414a27eeee7b47bed7cd8c5bb88b81f7f5cca
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 18:14:31 2022 -0500
+
+    [paint] Documentation fixes
+
+ src/hb-ot-color-colr-table.cc | 42 ++++++++++++++++++++++++++++++++++--------
+ src/hb-paint.cc               |  4 +++-
+ 2 files changed, 37 insertions(+), 9 deletions(-)
+
+commit e3153654cbb5132a9b06231fb4402a3849a0fb68
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 17 13:56:22 2022 -0700
+
+    [colr] Fix PNG placement
+
+ util/hb-test.c | 17 ++++++++++-------
+ 1 file changed, 10 insertions(+), 7 deletions(-)
+
+commit f07ce68f9cf8d5fd4eb37141a16e89cb0ec2bbae
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 17 13:48:05 2022 -0700
+
+    Remove unused function
+
+ util/hb-test.c | 7 -------
+ 1 file changed, 7 deletions(-)
+
+commit 0c77f1d9abf5f8dcd931ca1ae5856039daf3e3fc
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 14:10:28 2022 -0500
+
+    [paint] Documentation tweaks
+
+ src/hb-paint.cc | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ src/hb-paint.h  |  25 ++++++++--
+ 2 files changed, 168 insertions(+), 6 deletions(-)
+
+commit 0a2f3673b9cbe340cdf329f3b303832b16f7d2ee
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 13:51:23 2022 -0500
+
+    [paint] Use tags for image formats
+    
+    This fits better with the rest of the
+    HarfBuzz API.
+
+ src/hb-ot-color-cbdt-table.hh |  2 +-
+ src/hb-ot-color-sbix-table.hh |  2 +-
+ src/hb-ot-color-svg-table.hh  |  2 +-
+ src/hb-paint.cc               |  6 +++---
+ src/hb-paint.h                | 30 +++++++++++++++++++++++-------
+ src/hb-paint.hh               |  4 ++--
+ util/hb-test.c                |  4 ++--
+ 7 files changed, 33 insertions(+), 17 deletions(-)
+
+commit 4c728e952b5f7fa29b6da6c674ac289fddaf875b
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 13:33:56 2022 -0500
+
+    [colr] Add a todo
+
+ src/hb-ot-color-colr-table.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 4b0285bae60554c914f0b572fdaa5586be9f0611
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 17 11:18:42 2022 -0700
+
+    [colr] Use slant_xy
+
+ src/hb-paint.hh | 20 ++++++++++++--------
+ 1 file changed, 12 insertions(+), 8 deletions(-)
+
+commit b9314400eccb2dadce788f6af5d843d5341f2c11
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 17 10:58:52 2022 -0700
+
+    [colr] Hook up color-line variation
+
+ src/hb-ot-color-colr-table.cc |  4 ++--
+ src/hb-ot-color-colr-table.hh | 37 ++++++++++++++++++++++++-------------
+ 2 files changed, 26 insertions(+), 15 deletions(-)
+
+commit a935e4b0c256451f50b2c0886f4fed5152735b62
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 12:59:58 2022 -0500
+
+    [paint] Add synthetic slant to root transform
+
+ src/hb-paint.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit edf27382630a30070a33d9f65f005741fb15d95b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 17 10:47:55 2022 -0700
+
+    [colr] Try fixing bot build
+    
+    I don't get the error. Let's see.
+    
+    ../../src/harfbuzz/src/hb-ot-color-colr-table.hh:574:66: error: incomplete definition of type 'OT::NoVariable<OT::ColorLine<OT::NoVariable>>'
+
+ src/hb-ot-color-colr-table.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 686e627bdf1ef28f0ced44c146d0b3cd7f2def33
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 12:44:16 2022 -0500
+
+    [paint] Set up root transform in one place
+    
+    Instead of spreading this in all the tables,
+    make hb_paint_funcs_t provide a push/pop_root_transform
+    that does all the setup.
+
+ src/OT/glyf/glyf.hh           | 12 ++----------
+ src/hb-ot-cff1-table.cc       | 12 ++----------
+ src/hb-ot-cff2-table.cc       | 12 ++----------
+ src/hb-ot-color-colr-table.hh | 20 ++++----------------
+ src/hb-paint.hh               | 12 ++++++++++++
+ 5 files changed, 22 insertions(+), 46 deletions(-)
+
+commit c6dd56cc64d08defd661b3152a1ecd9b4b786db4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 17 10:38:23 2022 -0700
+
+    [colr] Simplify color-stop handling
+
+ src/hb-ot-color-colr-table.cc | 42 +++++++------------------------------
+ src/hb-ot-color-colr-table.hh | 49 ++++++++-----------------------------------
+ 2 files changed, 17 insertions(+), 74 deletions(-)
+
+commit 485ba9beb36d16f91330f50fa6f403cdb192f294
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 12:25:04 2022 -0500
+
+    [paint] Spell out rectangle in the API
+    
+    No need to abbreviate this.
+
+ src/hb-paint.cc | 12 ++++++------
+ src/hb-paint.h  | 32 ++++++++++++++++----------------
+ src/hb-paint.hh | 12 ++++++------
+ util/hb-test.c  | 12 ++++++------
+ 4 files changed, 34 insertions(+), 34 deletions(-)
+
+commit 37f3f0fcc25ed5cc0ea822b1a780705ab842d7bd
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 11:49:18 2022 -0500
+
+    [paint] Change the image callback
+    
+    Instead of passing the glyph ID, give
+    it the image blob, a mimetype, and
+    glyph extents (if available).
+    
+    Update all callers.
+
+ src/hb-ot-color-cbdt-table.hh |  6 +++++-
+ src/hb-ot-color-sbix-table.hh |  6 +++++-
+ src/hb-ot-color-svg-table.hh  |  2 +-
+ src/hb-paint.cc               | 10 +++++++---
+ src/hb-paint.h                | 18 ++++++++++++++----
+ src/hb-paint.hh               |  6 ++++--
+ util/hb-test.c                | 16 ++++++++++------
+ 7 files changed, 46 insertions(+), 18 deletions(-)
+
+commit ea48d6c292bd248a6607a0cfe1d17f05fc4f018f
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 11:51:37 2022 -0500
+
+    Move hb_glyph_extents_t definition
+
+ src/hb-common.h | 18 ++++++++++++++++++
+ src/hb-font.h   | 20 +-------------------
+ 2 files changed, 19 insertions(+), 19 deletions(-)
+
+commit b722039c48b41c1e96c7a1bcbad072a2332d4e46
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 17 10:22:32 2022 -0700
+
+    [colr] Simplify
+
+ src/hb-ot-color-colr-table.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 452cfb95997cbc0a81f5533e1fa365cbf6888157
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 17 10:04:55 2022 -0700
+
+    [colr] Simplify loop using iterators
+    
+    Or complexify?!
+
+ src/hb-ot-color-colr-table.hh | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+commit 601a596ca0837e36b45e117f70a5b7072c30d4e8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 17 09:22:55 2022 -0700
+
+    [paint] Fix include path
+
+ src/OT/glyf/glyf.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 8a9069d55fdfe738103a2fea83317a7fd1857727
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 17 09:21:08 2022 -0700
+
+    [colr] Fix radial gradient
+    
+    Broke it when adding variations.
+
+ src/hb-ot-color-colr-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e799c33bb59b8699a6c6b0f43e7e5854515c5075
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 17 09:00:20 2022 -0700
+
+    [paint] Fix function prototype
+
+ src/hb-paint.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1953d26a8a9cc0e70055c8cf5e8e876d7b6ac664
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 17 08:59:33 2022 -0700
+
+    [colr] Limit recursion depth
+
+ src/hb-ot-color-colr-table.hh | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit 378bbeea015f492756cbe7ffc39e6144a0ffe5ee
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 10:02:30 2022 -0500
+
+    Add more docs
+
+ src/hb-font.cc | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+commit 9876e30c6ee8fc53ae4d26692b9482e6011d04a5
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 02:46:37 2022 -0500
+
+    test: Support png images via paint_image
+
+ util/hb-test.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 59 insertions(+)
+
+commit 6079173a5229b8f51a0ee15f4e4ea957f1e2e722
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 01:04:35 2022 -0500
+
+    Try paint_glyph for more tables
+    
+    If the COLR table does not paint the glyph,
+    try SVG, CBDT and sbix too, before giving up
+    on color.
+
+ src/hb-ot-font.cc | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit e6c5a616aaf081d0603a6f6e74be66d89c2b1832
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 02:13:38 2022 -0500
+
+    SVG Implement paint-glyph
+
+ src/hb-ot-color-svg-table.hh | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+commit 23c60fd9b293f09461926f47cdd0779af766aff8
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 01:04:23 2022 -0500
+
+    sbix: Implement paint_glyph
+
+ src/hb-ot-color-sbix-table.hh | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+commit 7996ae4c3d4d99066efa738a8ddca3851ff94ec5
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 01:04:00 2022 -0500
+
+    CBDT: Implement paint glyph
+
+ src/hb-ot-color-cbdt-table.hh | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+commit 82e23f322a5e58e8fe7e74069f90507c09694c93
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 00:33:59 2022 -0500
+
+    paint: Add a paint-image callback
+    
+    This will be used for image blobs like pngs and svgs.
+    
+    FIXME: nail down and document sizing.
+
+ src/hb-paint.cc | 12 ++++++++++++
+ src/hb-paint.h  | 43 +++++++++++++++++++++++++++++++++++++++++++
+ src/hb-paint.hh |  6 ++++++
+ 3 files changed, 61 insertions(+)
+
+commit 56b02b6599168aec8743145021fbc9cec0163113
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 16 23:58:37 2022 -0500
+
+    Update the docs
+    
+    Mention that the color index will always be 0xFFFF
+    when using hb_paint API with fonts that don't have
+    color palettes.
+    
+    And add an outline about which kinds of glyphs
+    require which callbacks.
+
+ src/hb-paint.h | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+commit 9461ab70883c4fa0492f5f71c902cdabba627d4f
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 16 23:46:45 2022 -0500
+
+    Try paint_glyph for more tables
+    
+    If the COLR table can't paint the glyph,
+    try glyf, cff1 and cff2 too.
+
+ src/hb-ot-font.cc | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit 3e39dd492bd566e55183ff4e2b136288dfd5458c
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 16 23:46:15 2022 -0500
+
+    cff2: Implement paint_glyph
+
+ src/hb-ot-cff2-table.cc | 21 +++++++++++++++++++++
+ src/hb-ot-cff2-table.hh |  2 ++
+ 2 files changed, 23 insertions(+)
+
+commit df89b52130ce85ed481f8672f051744b947df6a5
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 16 23:46:05 2022 -0500
+
+    cff1: Implement paint_glyph
+
+ src/hb-ot-cff1-table.cc | 21 +++++++++++++++++++++
+ src/hb-ot-cff1-table.hh |  2 ++
+ 2 files changed, 23 insertions(+)
+
+commit 2edd771cf58de4348d6c760e4fbe77ea0f1ba16a
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 16 23:32:15 2022 -0500
+
+    glyf: Implement paint_glyph
+
+ src/OT/glyf/glyf.hh | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+commit 0b33b35eb0fc50045adc614dc60567fad837762b
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 16 23:22:15 2022 -0500
+
+    COLRv1: Return bool from paint_glyph
+    
+    This will let hb_ot_font_paint_glyph() try
+    multiple tables in turn.
+
+ src/hb-ot-color-colr-table.hh | 41 ++++++++++++++++++++++++++++-------------
+ 1 file changed, 28 insertions(+), 13 deletions(-)
+
+commit 0d890061d139a9a8b59d8aef7e73a02bec1489ee
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 17 00:07:30 2022 -0500
+
+    Rename 'solid' to 'color'
+    
+    'solid' does not really describe well what
+    the function does, and there is no strong
+    reason to stick 1:1 to the terminology used
+    in the spec.
+
+ src/hb-ot-color-colr-table.hh   |   4 +-
+ src/hb-ot-color-colrv1-paint.hh | 286 ++++++++++++++++++++++++++++++++++++++++
+ src/hb-paint.cc                 |   6 +-
+ src/hb-paint.h                  |  18 +--
+ src/hb-paint.hh                 |   8 +-
+ util/hb-test.c                  |  58 ++++----
+ 6 files changed, 333 insertions(+), 47 deletions(-)
+
+commit 2c07828603847892fe2759d2397530910f3f42e2
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 16 23:23:51 2022 -0500
+
+    test: More debug spew
+
+ util/hb-test.c | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+commit 46286275f7f49149ef9e1db45d703880f094c1ee
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 16 15:27:18 2022 -0700
+
+    [colr] More dispatch functionality
+
+ src/hb-ot-color-colr-table.cc |  4 ++--
+ src/hb-ot-color-colr-table.hh | 39 ++++++++++++++++++---------------------
+ 2 files changed, 20 insertions(+), 23 deletions(-)
+
+commit 81f232afb509bf94d8d909236c5bc1f507b08b5e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 16 15:17:35 2022 -0700
+
+    [colr] Use dispatch machinery for paint_glyph context
+
+ src/hb-ot-color-colr-table.hh | 48 +++++++------------------------------------
+ 1 file changed, 7 insertions(+), 41 deletions(-)
+
+commit a96300d42cf0a85ba6fa84eacfe583d8faf9c906
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 16 15:11:35 2022 -0700
+
+    [colr] Hide internal symbols
+
+ src/harfbuzz-subset.cc        | 1 +
+ src/harfbuzz.cc               | 1 +
+ src/hb-ot-color-colr-table.hh | 4 ++--
+ 3 files changed, 4 insertions(+), 2 deletions(-)
+
+commit fdf17dbf34666918979cb53c89e85b0c92fcf12b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 16 15:00:06 2022 -0700
+
+    Try fixing bots
+
+ util/hb-test.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b4cab86d94affa5b610154623a393afffac9728c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 16 14:58:39 2022 -0700
+
+    Fix autotools build
+
+ src/Makefile.sources   | 1 +
+ src/harfbuzz-subset.cc | 1 -
+ src/harfbuzz.cc        | 1 -
+ 3 files changed, 1 insertion(+), 2 deletions(-)
+
+commit 07575190928ff7bcb72885943d9b7073a27e4e3c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 16 12:45:02 2022 -0700
+
+    [colr] Add variation to rest of the paints
+
+ src/hb-ot-color-colr-table.hh | 80 +++++++++++++++++++++++++++++--------------
+ 1 file changed, 54 insertions(+), 26 deletions(-)
+
+commit 5bce0053463ff29386f1442f3720fd847d972263
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 16 12:31:08 2022 -0700
+
+    [colr] Flesh out variations for a few paints
+
+ src/hb-ot-color-colr-table.hh | 22 +++++++++++++++-------
+ 1 file changed, 15 insertions(+), 7 deletions(-)
+
+commit 9d3440b74299da8beb59c55e88aaf61fec39c507
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 16 12:12:21 2022 -0700
+
+    [colr] Add variation infrastructure to paint_glyph
+    
+    No paint applies variations yet.
+
+ src/hb-ot-color-colr-table.hh | 80 ++++++++++++++++++++++++-------------------
+ 1 file changed, 45 insertions(+), 35 deletions(-)
+
+commit 5c6329555e6171e82cdf151a119166666a08426b
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 16 12:04:17 2022 -0500
+
+    Apply root transform
+    
+    This commit applies scale, slant is still missing.
+
+ src/hb-ot-color-colr-table.hh | 15 +++++++++++++--
+ util/hb-test.c                | 22 +++++++++++++---------
+ 2 files changed, 26 insertions(+), 11 deletions(-)
+
+commit 5afca91ff22c76fbe65da1f2084b5029a66bee14
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 16 06:43:43 2022 -0500
+
+    Add some docs
+
+ src/hb-paint.cc |  48 +++++++++++-
+ src/hb-paint.h  | 226 +++++++++++++++++++++++++++++++++++++-------------------
+ 2 files changed, 196 insertions(+), 78 deletions(-)
+
+commit 44c68594f197f325fd9c50c3ca3d8ca1dca0be01
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 16 00:48:28 2022 -0500
+
+    Some docs
+
+ src/hb-paint.cc |   9 +++
+ src/hb-paint.h  | 230 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 239 insertions(+)
+
+commit d7c2eacf454e1345c15978bae9fff791d23effde
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Dec 15 23:42:40 2022 -0500
+
+    Handle COLRv0 layers in paint_glyph
+
+ src/hb-ot-color-colr-table.hh | 26 ++++++++++++++++++++------
+ 1 file changed, 20 insertions(+), 6 deletions(-)
+
+commit 55ca6ed230b74f84345258217e51d4865e763f2c
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Dec 15 23:16:54 2022 -0500
+
+    minor fixes
+
+ src/hb-ot-color-colr-table.cc | 73 +++++++++++++++++++++++++++++++++++++++++++
+ src/hb-ot-color-colr-table.hh |  9 ++++--
+ 2 files changed, 80 insertions(+), 2 deletions(-)
+
+commit 794fa4c3c1d6564477a0885b95f80409f9272090
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Dec 15 22:22:31 2022 -0500
+
+    sweep gradients etc
+
+ util/hb-test.c | 819 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 817 insertions(+), 2 deletions(-)
+
+commit 1880e547531a8f137564e9c5bf7421005e8cffbd
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Dec 15 01:06:00 2022 -0500
+
+    Assorted fixes
+
+ src/hb-ot-color-colr-table.hh | 62 ++++++++++++++++++++++++++-----------------
+ 1 file changed, 37 insertions(+), 25 deletions(-)
+
+commit 684df8a82a81e01412dc951c251abab77165ae66
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Dec 15 00:32:48 2022 -0500
+
+    add some todos
+
+ src/hb-font.cc                | 1 +
+ src/hb-ot-color-colr-table.hh | 2 ++
+ 2 files changed, 3 insertions(+)
+
+commit a6f813b68009325f9b5cc478ed83b312b06ad996
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Dec 15 00:05:27 2022 -0500
+
+    Implement hb_color_line_get_extend
+
+ src/hb-ot-color-colr-table.hh | 30 ++++++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+
+commit d07fdc69dd66ad520f9ce24438fbef5c7c41f28e
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 14 23:58:59 2022 -0500
+
+    test: dump color lines
+
+ util/hb-test.c | 26 +++++++++++++++++++++-----
+ 1 file changed, 21 insertions(+), 5 deletions(-)
+
+commit 3937d6b0aaff5b5937bb513430e7df30f3517315
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 14 23:58:47 2022 -0500
+
+    Implement hb_color_line_t
+
+ src/hb-ot-color-colr-table.hh | 139 +++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 123 insertions(+), 16 deletions(-)
+
+commit 64f1b55d01afa0a8424b0336fcaad626d9814126
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 14 23:58:25 2022 -0500
+
+    api fixes: use floats consistently
+
+ src/hb-paint.cc | 14 +++++++-------
+ src/hb-paint.h  | 11 ++++++-----
+ src/hb-paint.hh |  8 ++++----
+ 3 files changed, 17 insertions(+), 16 deletions(-)
+
+commit 627c857f8b8ea5c5efab1525daef2d7e5ec04401
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 14 22:36:54 2022 -0500
+
+    rename pop_group_and_composite
+
+ src/hb-ot-color-colr-table.hh |  4 ++--
+ src/hb-paint.cc               | 12 ++++++------
+ src/hb-paint.h                | 28 ++++++++++++++--------------
+ src/hb-paint.hh               | 12 ++++++------
+ util/hb-test.c                | 10 +++++-----
+ 5 files changed, 33 insertions(+), 33 deletions(-)
+
+commit c9350838c7a039b87408ff2686759d0bd0c05377
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 14 22:32:40 2022 -0500
+
+    assorted fixes and changes
+
+ src/hb-ot-color-colr-table.hh |   4 +-
+ src/hb-paint.cc               | 112 +++++++++++++++++++++++-------------------
+ src/hb-paint.h                |  73 +++++++++++++++++----------
+ src/hb-paint.hh               |  37 ++++++++------
+ util/hb-test.c                |  43 ++++++++++------
+ 5 files changed, 158 insertions(+), 111 deletions(-)
+
+commit 5a123e8691ae839e6409fdcd51edab0c62c0e9a4
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 14 22:05:02 2022 -0500
+
+    quick testcase
+
+ util/hb-test.c   | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ util/meson.build |   7 +++
+ 2 files changed, 175 insertions(+)
+
+commit 42324aef2b18728d6318ffd4de08a21b54126c92
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 14 22:04:46 2022 -0500
+
+    hb-paint: annotation fix
+
+ src/hb-paint.h | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+commit 8377341b289f47a8e63d448b5a3376dfdd464734
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 14 22:03:52 2022 -0500
+
+    wip: implement paint_glyph
+
+ src/harfbuzz-subset.cc        |   1 +
+ src/harfbuzz.cc               |   1 +
+ src/hb-ot-color-colr-table.hh | 204 ++++++++++++++++++++++++++++++++++++++++--
+ src/meson.build               |   1 +
+ 4 files changed, 199 insertions(+), 8 deletions(-)
+
+commit efe13a191df504df4a38f633c35a73477cf93b01
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 14 09:50:52 2022 -0500
+
+    fix introspection
+
+ src/hb-font.h             |  8 +++++-
+ src/hb-gobject-structs.cc |  1 +
+ src/hb-gobject-structs.h  |  4 +++
+ src/hb-paint.cc           |  5 ++++
+ src/hb-paint.h            | 70 +++++++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 87 insertions(+), 1 deletion(-)
+
+commit 6a48ac42f4f8404ecf64fda876141a0d1c48a56c
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 14 06:55:01 2022 -0500
+
+    COLR implementation
+
+ src/hb-ot-color-colr-table.hh |  5 +++++
+ src/hb-ot-font.cc             | 18 ++++++++++++++++++
+ 2 files changed, 23 insertions(+)
+
+commit 71efa0dcf12eb3924697f96d3a4ed203bb71962b
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Dec 14 06:22:00 2022 -0500
+
+    wip: hb_font_paint_glyph
+
+ src/hb-font.cc | 30 ++++++++++++++++++++++++++++++
+ src/hb-font.h  | 16 ++++++++++++++++
+ src/hb-font.hh |  9 +++++++++
+ 3 files changed, 55 insertions(+)
+
+commit 83d0a49f7100008937fcf7e69e31fe9625365259
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Tue Dec 13 21:14:25 2022 -0500
+
+    wip: hb-paint
+
+ src/harfbuzz-subset.cc        |   1 +
+ src/harfbuzz.cc               |   1 +
+ src/hb-ot-color-colr-table.hh |   5 +
+ src/hb-paint.cc               | 311 ++++++++++++++++++++++++++++++++++++++++++
+ src/hb-paint.h                | 276 +++++++++++++++++++++++++++++++++++++
+ src/hb-paint.hh               | 125 +++++++++++++++++
+ src/hb.h                      |   1 +
+ src/meson.build               |   3 +
+ 8 files changed, 723 insertions(+)
+
+commit 0066e824f02efce79e026f60391f3fd95214e1ac
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 13:37:38 2022 -0700
+
+    [util] Fix vertical positioning with --glyphs
+
+ util/shape-options.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 265b699fbd3c74c1c4324d5f7044e7236d3b0b89
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 13:31:48 2022 -0700
+
+    [util] Improve --glyphs
+
+ util/shape-consumer.hh | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit d45f7265e9dfbb053ae3ed88575136d75979c02b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 23 13:13:29 2022 -0700
+
+    [hb-view/hb-shape] Add --glyphs
+    
+    This makes hb-view take output of hb-shape and render it.
+
+ util/shape-consumer.hh |  2 +-
+ util/shape-options.hh  | 44 +++++++++++++++++++++++++++++++++++++++-----
+ 2 files changed, 40 insertions(+), 6 deletions(-)
+
+commit 30c5402e3d0cc156fd5f04560864a88723173cf2
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 23 14:29:25 2022 -0500
+
+    Make hb-features.h usable standalone
+    
+    The intended use for hb-features.h is to
+    be included standalone, so we can't put
+    the single-include guards in here.
+
+ src/hb-features.h.in | 6 ------
+ 1 file changed, 6 deletions(-)
+
+commit d628aff9db826671b1612ed1865f5cdbd763c9f8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 10:53:24 2022 -0700
+
+    [ft] Apply slant in get_glyph_extents
+
+ src/hb-ft.cc | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 9a0ebd2b2ab4b7fa5e1463c0ac4549cb24b21896
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 10:21:07 2022 -0700
+
+    [glyf] Fix slant-scaling in GlyphHeader too
+
+ src/OT/glyf/GlyphHeader.hh | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+commit 392463bff591fd0cec2ea2476b30427251f7c9f4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 08:34:01 2022 -0700
+
+    [cff] Fix extent rounding
+    
+    I broke it in b0abbfd8684e9970ed2cac78781643edb7cce0ae.
+
+ src/hb-ot-cff1-table.cc | 8 ++++----
+ src/hb-ot-cff2-table.cc | 8 ++++----
+ 2 files changed, 8 insertions(+), 8 deletions(-)
+
+commit 897c102703e482f8ed0842e63c6fb96f15dface3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 08:14:13 2022 -0700
+
+    [font] Fix scale_glyph_extents
+
+ src/hb-font.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 9194e13e25563f7170c68b0126f5852925c526ff
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 07:31:16 2022 -0700
+
+    [font] Apply slant to glyph extents
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3952
+    
+    hb-ft not fixed since doesn't use this code.
+
+ src/hb-font.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit b0abbfd8684e9970ed2cac78781643edb7cce0ae
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 22 07:26:14 2022 -0700
+
+    [font] Centralize glyph-extents scaling
+    
+    Needs more testing...
+    
+    Some rounding was removed, namely in cff1 and cff2.
+
+ src/OT/glyf/glyf.hh           | 11 +++--------
+ src/hb-font.hh                |  8 ++++++++
+ src/hb-ot-cff1-table.cc       | 10 ++++++----
+ src/hb-ot-cff2-table.cc       | 10 ++++++----
+ src/hb-ot-color-cbdt-table.hh | 10 ++++++----
+ src/hb-ot-color-colr-table.hh |  5 +----
+ src/hb-ot-color-sbix-table.hh | 18 ++++++++++--------
+ 7 files changed, 40 insertions(+), 32 deletions(-)
+
+commit 4622be7f84b22ad3fb1c7141c0e4ec88dd5672c8
+Author: Chun-wei Fan <fanc999@yahoo.com.tw>
+Date:   Thu Dec 22 12:05:11 2022 +0800
+
+    test/fuzzing: Fix dist
+    
+    We need to dist the repacker fuzzer test items into the tarball, along
+    with the items in graphs/ and sets/.
+
+ test/fuzzing/Makefile.am | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+commit 97b8ada8652ef7ca7e33f6fe927ab8bf3c18396e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Dec 21 19:52:20 2022 -0700
+
+    [varc] Reset component coordinates to that of the font
+    
+    Fixes https://github.com/harfbuzz/boring-expansion-spec/issues/78
+
+ src/OT/glyf/Glyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 40342c9437712cd51e37dc54f1f535bb24ae7529
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Dec 21 21:52:28 2022 +0000
+
+    [subset] check for addition overflow in hdmx size calculation.
+    
+    Fixes https://oss-fuzz.com/testcase-detail/4877336988483584.
+
+ src/hb-ot-hdmx-table.hh                                   |   1 +
+ ...z-testcase-minimized-hb-subset-fuzzer-4877336988483584 | Bin 0 -> 738 bytes
+ 2 files changed, 1 insertion(+)
+
+commit d77fca997ed0e9526e98eb78be2e469886123da0
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Dec 21 21:18:20 2022 +0000
+
+    [subset] when subsetting preprocessor fails, reference the returned face.
+    
+    The caller of the method is expected to destroy the returned result.
+
+ src/hb-subset-input.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit fc8fa184183d7eaa49d789963d6ae9456e32680c
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Dec 20 19:04:41 2022 +0200
+
+    Revert "[doc] Don’t skip building on Windows"
+    
+    This reverts commit 196e739cf28456cd8b7989377c3df6a5fe468dd7.
+
+ docs/meson.build | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit 6d80aba49e20f5915545dcc4116f5e68eab8c57f
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Dec 20 19:01:04 2022 +0200
+
+    Revert "[doc] Remove redundant check for gtkdoc-scan"
+    
+    This reverts commit 0409363f77cab416b34aab66d647a3d61f46d9d8.
+    
+    Broke lots of bots.
+
+ docs/meson.build | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit 9b5b4da0e471a16be46ddc60b0e2a233a84abd8d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Dec 20 09:57:32 2022 -0700
+
+    [varc] Set coordinates as absolute values
+
+ src/OT/glyf/VarCompositeGlyph.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 0409363f77cab416b34aab66d647a3d61f46d9d8
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Dec 20 18:42:13 2022 +0200
+
+    [doc] Remove redundant check for gtkdoc-scan
+    
+    If docs are enabled, meson will fail earlier of gtkdoc-scan is missing.
+
+ docs/meson.build | 5 -----
+ 1 file changed, 5 deletions(-)
+
+commit 196e739cf28456cd8b7989377c3df6a5fe468dd7
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Dec 20 18:41:01 2022 +0200
+
+    [doc] Don’t skip building on Windows
+    
+    We don’t enable building docs by default, so if one asked explicitly for
+    it we shouldn’t be overriding that.
+
+ docs/meson.build | 5 -----
+ 1 file changed, 5 deletions(-)
+
+commit 80e68f09c5daef0c3dfef4fb44ebfbd22899bf8a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 19 19:15:44 2022 -0700
+
+    [VarC] Change rotation/skew representation
+    
+    Fixes https://github.com/harfbuzz/boring-expansion-spec/issues/77
+
+ src/OT/glyf/VarCompositeGlyph.hh | 12 ++++++------
+ src/hb-open-type.hh              |  3 +--
+ 2 files changed, 7 insertions(+), 8 deletions(-)
+
+commit 1840b02e6a61d030cf485ea6c36126cd6dbd984e
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Dec 19 20:06:32 2022 +0000
+
+    [subset] Don't gate access to the table repacker.
+    
+    Any table with an object graph should repack correctly.
+
+ src/hb-subset.cc | 7 -------
+ 1 file changed, 7 deletions(-)
+
+commit 03a1685693e59f0c31803daf6647a80b4a111e9b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 19 17:11:34 2022 -0700
+
+    [VarC] Change representation of scale from 4.12 to 6.10
+    
+    Fixes https://github.com/harfbuzz/boring-expansion-spec/issues/76
+
+ src/OT/glyf/VarCompositeGlyph.hh | 12 ++++++------
+ src/hb-open-type.hh              |  4 ++--
+ 2 files changed, 8 insertions(+), 8 deletions(-)
+
+commit 1a51f71afd794a52a24cbcb7547000e0c563b0f6
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Dec 19 22:40:11 2022 +0000
+
+    [subset] don't segfault when --help-all is specified w/ instancing options.
+
+ util/hb-subset.cc | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit c292e577ff7d6b6b9d98e95dabd7ed71a02021fc
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 19 12:40:11 2022 -0500
+
+    Fix a typo
+
+ src/hb-draw.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b795246fff2246266287a728475b97e8873f3f14
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 19 06:30:28 2022 -0500
+
+    [draw] Clarify the docs
+    
+    Disambiguate the origin of draw_data and user_data,
+    this had me confused a few times.
+    
+    Fixes: https://github.com/harfbuzz/harfbuzz/issues/3955
+
+ src/hb-draw.h | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+commit eddb408f9c9c42991c8b8427ca81e33a03fc9060
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Dec 19 12:19:48 2022 -0500
+
+    [draw] Small doc fix
+
+ src/hb-draw.cc | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit bc4c290b7581bbcb7632d74a2ebebc24bd5df9f1
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Dec 19 00:39:35 2022 +0200
+
+    [doc] Workaround gtk-doc limitation with HB_DEPRECATED_FOR
+    
+    See https://github.com/harfbuzz/harfbuzz/issues/3957#issuecomment-1356890525
+
+ src/hb-deprecated.h    |  3 ++-
+ src/hb-graphite2.h     |  3 ++-
+ src/hb-ot-deprecated.h | 18 ++++++++++++------
+ 3 files changed, 16 insertions(+), 8 deletions(-)
+
+commit 734e5f7cf412e421568963e5a5fe3ee51365163e
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Dec 19 00:15:04 2022 +0200
+
+    [doc] Add HB_DEPRECATED_FOR to --ignore-decorators
+    
+    Does not make a difference, though.
+
+ docs/Makefile.am | 2 +-
+ docs/meson.build | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit f9e1192d58e54f6719993a1694aee0a73198d63d
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sun Dec 18 23:58:36 2022 +0200
+
+    [ot-tag] Document two deprecated symbols
+    
+    See https://github.com/harfbuzz/harfbuzz/issues/3957
+
+ src/hb-ot-tag.cc | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+commit 947e01a7c1bc7eede4077ced24923acd8f45e0f5
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sun Dec 18 23:40:01 2022 +0200
+
+    [subset] Suppress gtk-doc warning
+
+ src/hb-subset-input.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 9ca8e7564b52ae889961144d6533e8143a0f3771
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sun Dec 18 17:44:41 2022 +0200
+
+    Revert "[circleci] Make dist tarball with meson"
+    
+    This reverts commit 80157cc60baf0f1b26c442c336dc1854216468be.
+    
+    That was a thinko, meson generated dist tarballs are not usable for
+    autotools build as they will miss generated autotools files.
+
+ .circleci/config.yml | 33 +++++++++++----------------------
+ 1 file changed, 11 insertions(+), 22 deletions(-)
+
+commit c7dd63d1a04e797f21ba3fd7bb5aa5d08524c9dd
+Author: Nirbheek Chauhan <nirbheek@centricular.com>
+Date:   Sun Dec 18 09:28:47 2022 +0530
+
+    meson: Provide binaries when built as a subproject
+
+ util/meson.build | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 7be06f63779e3221333d3162f2025b1c497c5c8c
+Author: Nirbheek Chauhan <nirbheek@centricular.com>
+Date:   Sun Dec 18 07:10:32 2022 +0530
+
+    meson: Override dependencies to improve usage as a subproject
+    
+    With this change, harfbuzz can be consumed as a subproject without
+    making any changes to the build files of a project. All you need to do
+    is provide a wrap file with a `[provide]` section:
+    
+    https://mesonbuild.com/Wrap-dependency-system-manual.html#provide-section
+    
+    This is also necessary because otherwise projects need to hard-code
+    the subproject name, which might be `harfbuzz` when using `wrap-git` or
+    `harfbuzz-6.0.0` when using `wrap-file` (to build from a release
+    tarball). This can cause conflicts between different subprojects that
+    consume harfbuzz differently.
+    
+    Other projects like glib, cairo, pango, etc already do this.
+
+ src/meson.build | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 206957aee4a4479ca19a4065b2c5603e99379fcf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 17 08:57:40 2022 -0700
+
+    [COLR] Change recursion limit back to 128
+
+ src/hb-ot-color-colr-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 31ba950b71acbcb8d71a82bde0675785d24ff791
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Dec 17 01:11:20 2022 +0200
+
+    [circleci] Don’t run tests in dist
+
+ .circleci/config.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f22e42d7376f980fbb32e35a194f1dc1bfc3af0e
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Dec 17 00:57:26 2022 +0200
+
+    [circleci] Remove cruft
+
+ .circleci/config.yml | 16 ----------------
+ 1 file changed, 16 deletions(-)
+
+commit 21e866b8b5006ee99f40077fe1c494faf9ccb014
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Dec 17 00:34:46 2022 +0200
+
+    [circleci] Unify meson commands a bit
+
+ .circleci/config.yml | 33 ++++++++++++++++++---------------
+ 1 file changed, 18 insertions(+), 15 deletions(-)
+
+commit 80157cc60baf0f1b26c442c336dc1854216468be
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Dec 17 00:19:27 2022 +0200
+
+    [circleci] Make dist tarball with meson
+
+ .circleci/config.yml | 33 ++++++++++++++++++++++-----------
+ 1 file changed, 22 insertions(+), 11 deletions(-)
+
+commit afcae83a064843d71d47624bc162e121cc56c08b
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Dec 16 23:14:57 2022 +0200
+
+    6.0.0
+
+ NEWS                   | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ configure.ac           |  2 +-
+ docs/harfbuzz-docs.xml |  1 +
+ meson.build            |  2 +-
+ src/hb-subset-input.cc |  6 ++---
+ src/hb-version.h       |  8 +++----
+ 6 files changed, 72 insertions(+), 9 deletions(-)
+
+commit 27ff90d7b8c65017334f15f45b5552d4f6fdb128
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Dec 16 22:08:33 2022 +0200
+
+    [meson] Update freetype2 wrap
+    
+    Use the one from WrapDB and add zlib wrap because current FreeType
+    tarball misses it.
+
+ subprojects/freetype2.wrap | 10 ++++++----
+ subprojects/zlib.wrap      | 12 ++++++++++++
+ 2 files changed, 18 insertions(+), 4 deletions(-)
+
+commit a98c6fdd92f35c2d176f5c808287a0b568aede48
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 16 14:04:54 2022 -0500
+
+    Mark an argument as unused
+
+ src/hb-ot-color-colr-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 601d3806c93309ec47c2dc0c53fb36c3b95a3d9d
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 16 13:34:15 2022 -0500
+
+    COLRv1: Revamp extents variation
+    
+    Try to do this a cleaner way.
+
+ src/hb-ot-color-colr-table.hh | 60 ++++++++++++++++++++++++++++---------------
+ 1 file changed, 39 insertions(+), 21 deletions(-)
+
+commit 318df8a706b2cd9b8323d8368f2f7d96117c7348
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Dec 16 21:27:37 2022 +0200
+
+    [meson] Update google-benchmark wrap
+    
+    Use the one from WrapDB.
+
+ subprojects/google-benchmark.wrap | 15 ++++++++-------
+ 1 file changed, 8 insertions(+), 7 deletions(-)
+
+commit bd7c458028e1dde0cdeb9099279d17bf63f5b3ff
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Dec 16 21:01:26 2022 +0200
+
+    [meson] Update glib wrap
+    
+    Use the one from WrapDB.
+
+ .circleci/config.yml  |  4 ++--
+ subprojects/glib.wrap | 17 +++++++++--------
+ 2 files changed, 11 insertions(+), 10 deletions(-)
+
+commit 51a17201a734616640e8c46bccaa0b26e1caaa27
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 16 12:28:30 2022 -0700
+
+    [open-type] In to_float() take offset as float
+
+ src/hb-open-type.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9e3bfd9aa169f1ca77d6b1e6227905ee585a4255
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Dec 16 20:10:51 2022 +0200
+
+    [ci] Build Windows binaries without cairo-ft
+
+ .ci/build-win32.sh | 3 ++-
+ .ci/build-win64.sh | 3 ++-
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+commit 6add69a6ec422406727186fdc5a7fcde289cbfbe
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Dec 16 19:54:00 2022 +0200
+
+    [hb-view] Allow building without cairo-ft
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3925
+
+ meson.build          |  3 ++-
+ util/helper-cairo.hh | 16 ++++++++++++++--
+ util/meson.build     |  3 +--
+ 3 files changed, 17 insertions(+), 5 deletions(-)
+
+commit f252cf80e194130d26ae3057227dc86dc60f8cb8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 16 12:03:51 2022 -0700
+
+    [open-type] Allow passing an offset to to_float()
+
+ src/hb-open-type.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 6ae35365f89e31dfc6ceeafdc47f302d040ffbf8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 16 11:43:38 2022 -0700
+
+    Fix build
+
+ src/hb-ot-color-colr-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e957391efe2c00946ddf0586a710a4a4877981df
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 16 11:33:04 2022 -0700
+
+    [colr] Add NoVariable::varIdxBase
+
+ src/hb-ot-color-colr-table.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit e06de98c36200f7c6ff8939bb094960079521820
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 16 11:31:00 2022 -0700
+
+    [var-common] Make VarInstancer take an offset
+
+ src/hb-ot-color-colr-table.hh | 8 ++++----
+ src/hb-ot-var-common.hh       | 4 ++--
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+commit 251f9f62134bf2b7050a4156dad9b0bb0968879f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 16 11:29:51 2022 -0700
+
+    [open-type] Add VarIdx::add()
+
+ src/hb-open-type.hh           |  5 +++++
+ src/hb-ot-color-colr-table.hh | 10 +++++-----
+ 2 files changed, 10 insertions(+), 5 deletions(-)
+
+commit bf2ae3f0ca19c0e18741c39ca19fc2a88d2e972b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 16 11:26:24 2022 -0700
+
+    [open-type] Add static_assert for NO_VARIATION
+
+ src/hb-open-type.hh           | 1 +
+ src/hb-ot-color-colr-table.hh | 2 +-
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+commit d4496e640594ac26cef6f46a6f15f9ee55386eff
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Dec 16 12:19:39 2022 -0500
+
+    COLRv1: Apply variations correctly
+    
+    The variations are for xMin, yMin, xMAx, yMax.
+    Apply them before converting to extents..
+
+ src/hb-ot-color-colr-table.hh | 26 +++++++++++++++-----------
+ 1 file changed, 15 insertions(+), 11 deletions(-)
+
+commit 193e0e3e8efc86215990d4e450ea90b723fda9b0
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Dec 15 00:32:11 2022 -0500
+
+    Cosmetic: typo fix
+
+ src/hb-font.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b5acde43ed81f7c212b4a37aa06c3988bce168a1
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Dec 13 22:04:19 2022 +0000
+
+    [subset] check pending/subsetted tag sets for alloc failure.
+
+ src/hb-subset.cc                                          |   7 ++++++-
+ ...z-testcase-minimized-hb-subset-fuzzer-6164014466203648 | Bin 0 -> 191 bytes
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+commit 79285a9983983840d60d45220abb4d50cf08be05
+Author: Jordan Petridis <16531710+alatiera@users.noreply.github.com>
+Date:   Tue Dec 13 20:14:20 2022 +0200
+
+    VarC: cast ints (#3934)
+    
+    msvc is rightfully complaining that the types on the sides of
+    the ternary are not matching:
+    
+    ```
+    C:\pango\subprojects\harfbuzz\src\OT\glyf\VarCompositeGlyph.hh(317): error C2446: ':': no conversion from 'const OT::HBUINT16' to 'const OT::HBUINT8'
+    ```
+
+ src/OT/glyf/VarCompositeGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 300d82ce2ef1f30d8c9cd839801fe3b429c78d45
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Dec 13 10:48:56 2022 -0700
+
+    Fix compiler warning
+
+ src/hb-ot-layout-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 199345eb29ed821fed300b53000ced1d245c6ef2
+Merge: bd7cb384c 4e9a6cfb4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 12 18:37:10 2022 -0700
+
+    Merge pull request #3928 from harfbuzz/colrv1-extents
+    
+    COLRv1: use ClipBoxes for extents
+
+commit bd7cb384cf73cb88e3121f3b7ab89ce50a64e5bd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 12 14:10:13 2022 -0700
+
+    [VarC] Remove unused variable
+
+ src/OT/glyf/VarCompositeGlyph.hh | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit 51d3ce39bab6270568706ef92d0f55d6d171ab2e
+Merge: 1b278c765 64cbe8b96
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 12 14:07:44 2022 -0700
+
+    Merge pull request #3933 from googlefonts/cff
+    
+    [subset] Fix infinite loop when instancing CFF fonts
+
+commit 1b278c76580351e52c98b7c8ffa22933cd25a59c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 12 13:57:05 2022 -0700
+
+    [VarC] Update for new format
+    
+    https://github.com/harfbuzz/boring-expansion-spec/issues/71
+
+ src/OT/glyf/VarCompositeGlyph.hh | 134 ++++++++++++++++++++++++++++++---------
+ 1 file changed, 103 insertions(+), 31 deletions(-)
+
+commit 64cbe8b96273ef2268111c03950610efe3f6e5e5
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Dec 12 20:41:40 2022 +0000
+
+    [subset] Also note that only full instancing works.
+
+ src/hb-subset-input.cc | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 0da59f86a8b33672a3da31e3e2c4bf62fd4cac24
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Dec 12 20:26:11 2022 +0000
+
+    [subset] note that CFF/CFF2 instancing is not yet supported.
+
+ src/hb-subset-input.cc | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 9fbe52b88d07557197191b8080bdd591de4318b6
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Dec 12 20:24:24 2022 +0000
+
+    [subset] enable instancing tests by default.
+
+ test/subset/data/Makefile.sources        |  8 ++++----
+ test/subset/generate-expected-outputs.py |  1 -
+ test/subset/meson.build                  | 15 ++++-----------
+ util/hb-subset.cc                        |  4 ----
+ 4 files changed, 8 insertions(+), 20 deletions(-)
+
+commit 38a962888512da088eb35ddee4f58c2a06392b73
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Dec 12 20:13:17 2022 +0000
+
+    [subset] simplify handling of table subsetting depedencies.
+    
+    Allow the dependency checker to see all tables that will be subset. Use this to fix the HMTX/VMTX dep check against glyf. Don't delay hmtx/vmtx subsetting if no glyf table is present.
+
+ src/hb-subset.cc | 75 ++++++++++++++++++++++++++++++--------------------------
+ 1 file changed, 40 insertions(+), 35 deletions(-)
+
+commit 0853e5d9d7bd15fc7782b111dcf9815d25c6d031
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Dec 12 19:43:31 2022 +0000
+
+    [subset] if table dependencies can't be resolved fail the subset.
+    
+    Avoids getting stuck in an infinite loop.
+
+ src/hb-subset.cc | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 6bb478eeeb665ddb1801a424679644b5b2b6c9e1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 12 11:39:06 2022 -0700
+
+    [VarC] Clamp after addition
+
+ src/OT/glyf/VarCompositeGlyph.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 80a5011eb654275920aed8c08731b75e1a9a7bc9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 12 11:37:59 2022 -0700
+
+    [VarC] Fix coord setting
+    
+    Those are additive.
+
+ src/OT/glyf/VarCompositeGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4e9a6cfb49841d2293883a08e0aaae8481fbc27b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 12 10:20:51 2022 -0700
+
+    [COLR] Use VarStoreInstancer
+
+ src/hb-ot-color-colr-table.hh | 35 ++++++++++++++++-------------------
+ src/hb-ot-var-common.hh       |  2 ++
+ 2 files changed, 18 insertions(+), 19 deletions(-)
+
+commit a3a3d37b952201265b9f17e1ef58d1127f617210
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 12 10:17:20 2022 -0700
+
+    [var] Add VarStoreInstancer
+
+ src/hb-ot-var-common.hh | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+commit c64661b2f856341c399eea5bff10fca35db57f6b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 12 10:11:02 2022 -0700
+
+    [COLR] Fix variation code
+
+ src/hb-ot-color-colr-table.hh | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+commit ff332b14eae0ac122d7cfea90fb7d98e107dea92
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 11 21:05:14 2022 -0700
+
+    [COLR] Handle HB_OT_LAYOUT_NO_VARIATIONS_INDEX
+
+ src/hb-ot-color-colr-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9a3f0be2911388e65e1e037e1c40ccfddc8b10bf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 11 13:40:53 2022 -0700
+
+    [COLR] Apply variations in get_extent
+
+ src/hb-ot-color-colr-table.hh | 36 +++++++++++++++++++++++++++++-------
+ src/hb-ot-layout-common.hh    |  8 ++++++++
+ 2 files changed, 37 insertions(+), 7 deletions(-)
+
+commit 68964efa553e77e0867777f4c4bfa5e962a9bda6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 11 13:21:01 2022 -0700
+
+    [COLR] Use bsearch in get_extents
+
+ src/hb-ot-color-colr-table.hh | 11 ++++++++---
+ src/hb-static.cc              |  2 ++
+ 2 files changed, 10 insertions(+), 3 deletions(-)
+
+commit d0ee5a452f057386d5dbffef1e8f7912fec8537c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 11 13:13:35 2022 -0700
+
+    [COLR] Return false from get_extents if table version not 1
+
+ src/hb-ot-color-colr-table.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit b3d6a5ef8644f7531e320fcfb98971ae56718c9a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 11 13:04:24 2022 -0700
+
+    [colr] Minor no behavior change
+
+ src/hb-ot-color-colr-table.hh | 21 +++++++++------------
+ 1 file changed, 9 insertions(+), 12 deletions(-)
+
+commit 7a748ad4acacd76b8c6285eab013a68813027997
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Dec 10 19:59:03 2022 -0500
+
+    COLRv1: use ClipBoxes for extents
+    
+    This is a first step; ultimatively, we
+    should compute the extents is ClipBoxes
+    are missing.
+
+ src/hb-ot-color-colr-table.hh | 49 +++++++++++++++++++++++++++++++++++++++++++
+ src/hb-ot-font.cc             |  4 ++++
+ 2 files changed, 53 insertions(+)
+
+commit d36a0f8c422cdabd5bb931a048a4c8515cd8b33d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 11 13:12:19 2022 -0700
+
+    [COLR] Add TODO
+
+ src/hb-ot-color-colr-table.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit a3068206817c7df57dc13b7c7b48a3e1c538fada
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 11 13:03:55 2022 -0700
+
+    [colr] Use SortedArray instead of Array
+
+ src/hb-ot-color-colr-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b9d5e7a8bbc15ffdffd2a00c2ca8497cbed4d85a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 11 12:54:19 2022 -0700
+
+    [colr] Set HB_COLRV1_MAX_NESTING_LEVEL to 16
+    
+    Was 100. That seemed excessive.
+
+ src/hb-ot-color-colr-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c17afa48deb932650cb6748328cbfe3b95c7126d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 11 12:53:55 2022 -0700
+
+    [colr] Remove COLRV1_ENABLE_SUBSETTING
+
+ src/hb-ot-color-colr-table.hh | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+commit 9ab2c8034ee137e84749b9aa2c197b2acec206aa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 11 12:00:54 2022 -0700
+
+    Revert "[glyf] Use component phantom points after transformation"
+    
+    This reverts commit a756bd1944404da6e53173c4061a2aef262e60f3.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3929
+
+ src/OT/glyf/Glyph.hh | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+commit 7f73b57bc1a64438b9a57e866a9ad055b7ef7f23
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 10 17:35:52 2022 -0700
+
+    [subset] Graduate L1 instancing API from experimental
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3926
+
+ docs/harfbuzz-sections.txt | 4 ++--
+ perf/benchmark-subset.cc   | 4 ----
+ src/gen-def.py             | 2 --
+ src/hb-subset-input.cc     | 6 ++----
+ src/hb-subset.h            | 4 ----
+ 5 files changed, 4 insertions(+), 16 deletions(-)
+
+commit 0f4e38cd865afedcb03ebc955f7c6e072415a09c
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Dec 10 16:39:26 2022 +0200
+
+    [subset] Small doc fixes
+
+ src/hb-subset-input.cc | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit bf2e8175491126f7b7f471fb9739e84c623c8d2d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 9 23:15:26 2022 -0700
+
+    [VarComposites] Support GID24
+
+ src/OT/glyf/VarCompositeGlyph.hh | 36 ++++++++++++++++++++++--------------
+ 1 file changed, 22 insertions(+), 14 deletions(-)
+
+commit 8c641eeefb88659bf88a28dcd9cd7cf52aeb1d35
+Merge: e66d02126 10d38dcdf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 9 19:43:47 2022 -0700
+
+    Merge pull request #3841 from harfbuzz/varc
+    
+    [glyf] VariableComposites
+
+commit 10d38dcdfd7e0b62f35ac5ff1d6cdf9ce1a78cc2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 9 19:19:57 2022 -0700
+
+    [varc] Change format slightly
+    
+    Fixes https://github.com/harfbuzz/boring-expansion-spec/issues/70
+
+ src/OT/glyf/VarCompositeGlyph.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit af450a757d8471e55b71d1f3eb3c1e1fd3390d7b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 9 19:05:16 2022 -0700
+
+    [config] Use HB_EXPERIMENTAL_API instead of adhoc HB_EXPERIMENTAL
+
+ src/hb-config.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 5cf0b9ae7d21cdce0c822ac1f6fb8de1e922aed8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 9 18:59:43 2022 -0700
+
+    [varc] Mark as experimental feature with HB_NO_VAR_COMPOSITES
+
+ src/OT/glyf/Glyph.hh | 4 ++++
+ src/hb-config.hh     | 1 +
+ 2 files changed, 5 insertions(+)
+
+commit 82b4f3791e1348273ebc8c13d410638842eef833
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 9 18:45:37 2022 -0700
+
+    [coord-setter] Don't modify font coords
+
+ src/OT/glyf/Glyph.hh        |  4 ++--
+ src/OT/glyf/coord-setter.hh | 33 +++++++++------------------------
+ 2 files changed, 11 insertions(+), 26 deletions(-)
+
+commit e9e503b80bba01d42b0987bab4dc240db6368e8f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 9 18:42:46 2022 -0700
+
+    [Glyph] Pass down coords to get_points
+
+ src/OT/glyf/Glyph.hh | 29 ++++++++++++++++++++++++-----
+ 1 file changed, 24 insertions(+), 5 deletions(-)
+
+commit 8e46870093fe9c214679370bdf34dbd67f388d18
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 9 18:35:30 2022 -0700
+
+    [gvar] Take coords in instead of font in apply_deltas_to_points
+
+ src/OT/glyf/Glyph.hh        | 4 +++-
+ src/hb-ot-var-gvar-table.hh | 6 +++---
+ 2 files changed, 6 insertions(+), 4 deletions(-)
+
+commit 3caa42a4a7b4879162d19273441c2cc8b44e3142
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 9 14:48:41 2022 -0700
+
+    Fix build after rebase
+
+ src/OT/glyf/Glyph.hh             | 2 +-
+ src/OT/glyf/VarCompositeGlyph.hh | 4 ++--
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+commit bbe59e4211c6dbff929320c7a4332289353cf666
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 8 16:04:19 2022 -0700
+
+    Whitespace
+
+ src/OT/glyf/Glyph.hh | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit 13deea7cbd5becb0746585177b9d67e0a52516e7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Oct 18 13:38:12 2022 -0600
+
+    [glyf/VarComposite] Clamp axis coordinates
+
+ src/OT/glyf/VarCompositeGlyph.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit a975be4c072b4370ee5efad5409b0b88e818259d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Oct 18 11:00:35 2022 -0600
+
+    [glyf/VarComposite] Minor rename
+
+ src/OT/glyf/Glyph.hh             | 2 +-
+ src/OT/glyf/VarCompositeGlyph.hh | 4 ++--
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+commit 1e71db2d264ebf9d86a43dc3378b653b8e5907ea
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Oct 18 10:47:32 2022 -0600
+
+    [glyf/VarComposite] Fix transformation
+
+ src/OT/glyf/VarCompositeGlyph.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 1233be61d89b876dee6901137a02b4d7ee7a0e13
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Oct 17 14:06:44 2022 -0600
+
+    [glyf/VarComposite] Remove unneeded resize
+
+ src/OT/glyf/Glyph.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 1a906162cb5d2445975cc571bc808e025f31b5d1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Oct 17 14:01:34 2022 -0600
+
+    [glyf/coord-setter] Fix memory issue
+
+ src/OT/glyf/coord-setter.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 7efd68da390f5cd125a1dd3a187ae28bbfb282e0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Oct 17 13:05:22 2022 -0600
+
+    [glyf/VarComposite] Set coordinates
+    
+    Code is untested but complete!
+
+ src/OT/glyf/Glyph.hh             |  3 ++-
+ src/OT/glyf/VarCompositeGlyph.hh | 16 ++++++++++++++++
+ 2 files changed, 18 insertions(+), 1 deletion(-)
+
+commit 4ec77814978b675d0aa74e869c24abc8b5270678
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Oct 17 12:53:58 2022 -0600
+
+    [glyf] Move coord-setter to its own file
+
+ src/Makefile.sources             |  1 +
+ src/OT/glyf/Glyph.hh             | 29 +-------------------------
+ src/OT/glyf/VarCompositeGlyph.hh |  1 +
+ src/OT/glyf/coord-setter.hh      | 45 ++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 48 insertions(+), 28 deletions(-)
+
+commit dadb4ed71de2da768ee4f07a3b595181813fb0f4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Oct 17 12:48:24 2022 -0600
+
+    [glyf/VarComposite] More, almost there
+
+ src/OT/glyf/Glyph.hh             | 18 ++++++++-----
+ src/OT/glyf/VarCompositeGlyph.hh | 58 +++++++++++++++++++++++++++++++++-------
+ 2 files changed, 60 insertions(+), 16 deletions(-)
+
+commit 0a939b48a60bc5b5cae0d3a5774218f1143b6759
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Oct 17 12:12:40 2022 -0600
+
+    [glyf/VarComposite] Implement more
+
+ src/OT/glyf/Glyph.hh             | 49 +++++++++++++++++++++++++++++++++++++---
+ src/OT/glyf/VarCompositeGlyph.hh |  8 +++++--
+ 2 files changed, 52 insertions(+), 5 deletions(-)
+
+commit 65cc3b5e2b2181e82836c85ea060b2bd8c59ff49
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Oct 13 17:11:12 2022 -0600
+
+    [glyf/VarComposite] More
+
+ src/OT/glyf/VarCompositeGlyph.hh | 24 ++++++++++++++++++------
+ 1 file changed, 18 insertions(+), 6 deletions(-)
+
+commit 12688ed3865fcbfcd34dd5c1c4ab3ca3bfc63e42
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Oct 13 17:06:07 2022 -0600
+
+    [glyf] Fix distcheck
+
+ src/Makefile.sources | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 60d959a6e7b73ce6492fb1b49b91aefe81ad99a5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Oct 13 14:15:36 2022 -0600
+
+    [glyf/VarComposite] Add use_my_metrics()
+
+ src/OT/glyf/VarCompositeGlyph.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 575d99406a5e40eab04b9d6c5c3a970b674b1753
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Oct 13 13:12:26 2022 -0600
+
+    [glyf] Flesh out VarCompositeGlyph
+
+ src/OT/glyf/VarCompositeGlyph.hh | 218 +++++++++++++++++++++++----------------
+ src/hb-open-type.hh              |   3 +
+ 2 files changed, 132 insertions(+), 89 deletions(-)
+
+commit 21f671bc453ba42b03402774a7e07fa0d3733099
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Oct 13 11:25:29 2022 -0600
+
+    [glyf] Add stub VarCompositeGlyph
+
+ src/OT/glyf/Glyph.hh             |   1 +
+ src/OT/glyf/VarCompositeGlyph.hh | 157 +++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 158 insertions(+)
+
+commit 435c5eeffec54fe48e190699532ec063c0a12c3a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Oct 13 10:54:58 2022 -0600
+
+    [glyf] Split composite-iter
+
+ src/OT/glyf/CompositeGlyph.hh | 51 ++------------------------------
+ src/OT/glyf/composite-iter.hh | 68 +++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 70 insertions(+), 49 deletions(-)
+
+commit 1024a013fd62eddc65c092f6fb2ff2fae176a618
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Aug 22 09:49:30 2022 -0600
+
+    [glyf] Add CoordSetter
+
+ src/OT/glyf/Glyph.hh | 32 +++++++++++++++++++++++++++++++-
+ 1 file changed, 31 insertions(+), 1 deletion(-)
+
+commit e66d02126e876ab01d0dacd1f22540106a27d7ec
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Dec 8 22:56:07 2022 +0000
+
+    [subset] replace subset-processing.md reference with link to it on github.
+
+ src/hb-subset-input.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 27201ed32b37d3956b15859e76db1be4ab32d7d5
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Dec 8 22:48:27 2022 +0000
+
+    [subset] fix up hb_subset_preprocess api comment.
+
+ docs/harfbuzz-sections.txt   | 2 +-
+ docs/subset-preprocessing.md | 2 +-
+ src/hb-subset-input.cc       | 8 +++++---
+ 3 files changed, 7 insertions(+), 5 deletions(-)
+
+commit 13b038835122c6eba53db15d33a02f898ce369a3
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Dec 7 22:53:44 2022 +0000
+
+    [subset] link to preprocessing doc from api comment.
+
+ docs/subset-preprocessing.md | 6 ++++--
+ src/hb-subset-input.cc       | 2 ++
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+commit c097abab52c51568f40b443576dbe030ff3cae89
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Dec 7 22:50:09 2022 +0000
+
+    [subset] set no prune unicode ranges flag in preprocessor.
+    
+    To avoid modifying the original unicode range values in the source font.
+
+ src/hb-subset-input.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 8c021462e6a7c52beb20906b595be52d526d5976
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Dec 7 22:44:50 2022 +0000
+
+    [subset] Add short document on subset preprocessing.
+
+ docs/subset-preprocessing.md | 226 +++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 226 insertions(+)
+
+commit bc87fe952e62624464933913bcba5874b49379a9
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Dec 7 21:43:14 2022 +0000
+
+    [subset] add note about memory management with preprocessed faces.
+
+ src/hb-subset-input.cc | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit 5e713e99bf5121a7d0cd2341c40db3d79bd09879
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Dec 5 23:57:57 2022 +0000
+
+    Revert "[map] Speed up is_real()"
+    
+    This reverts commit f5307c3ba8401fbaf9008705d7f8dfa7d28e944c.
+    
+    Found to slow down the benchmarks in some cases.
+
+ src/hb-map.hh | 15 ++++++---------
+ 1 file changed, 6 insertions(+), 9 deletions(-)
+
+commit eda02c2ebd6527f9072e3488ef8c675e4d85a720
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Dec 5 20:18:41 2022 +0000
+
+    [subset] Move hb_subset_preprocess to be non-experimental.
+
+ perf/benchmark-subset.cc |  4 ----
+ src/gen-def.py           |  1 -
+ src/hb-subset-input.cc   |  6 ++----
+ src/hb-subset.h          |  7 +++----
+ test/subset/run-tests.py | 11 ++++++++---
+ util/hb-subset.cc        |  4 ----
+ 6 files changed, 13 insertions(+), 20 deletions(-)
+
+commit 76d5482a7c6bfc1b10de0b925c229a9cdd220977
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Dec 5 19:40:49 2022 +0000
+
+    [subset] always return a valid face from hb_subset_preprocess.
+
+ src/hb-subset-input.cc | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+commit a80cae445369ad7feafbca2398601238df8e7e65
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Dec 8 11:17:47 2022 +0200
+
+    [doc] Add missing symbols to harfbuzz-sections.txt
+
+ docs/harfbuzz-sections.txt | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit 41edf95893f616c8a518f4853aba6f28c423d056
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Dec 8 11:01:04 2022 +0200
+
+    [doc] Fix sorting
+    
+    * Keep setters and getters together, with setters first.
+    * Keep common functions at the top and in a predictable order.
+    * Put callback functions right above their setters.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3352
+
+ docs/harfbuzz-sections.txt | 411 ++++++++++++++++++++++-----------------------
+ 1 file changed, 205 insertions(+), 206 deletions(-)
+
+commit 35233d2514cc202e9e2f8f94b3102cb620a0d403
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Dec 7 00:47:28 2022 +0000
+
+    [repacker] fix fuzzer reported stack overflow.
+    
+    Fixes https://oss-fuzz.com/testcase-detail/6014493291577344.
+
+ src/graph/graph.hh                                        |   5 +++++
+ src/hb-repacker.hh                                        |   8 ++++++++
+ ...testcase-minimized-hb-repacker-fuzzer-6014493291577344 | Bin 0 -> 921 bytes
+ 3 files changed, 13 insertions(+)
+
+commit b17fbc200bee7b1898862bdb13e46387d0057b38
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Dec 5 20:34:51 2022 +0000
+
+    [repacker] use memcpy to avoid alignment issues.
+
+ test/fuzzing/hb-repacker-fuzzer.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f1d3489388a48a2dcde35bb1872abd1d7aafa192
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Dec 5 19:33:15 2022 +0000
+
+    [repacker] bail on failure  to alloc assigned_bytes set.
+    
+    Fixes fuzzer issue https://oss-fuzz.com/testcase-detail/5390364397928448.
+
+ src/graph/graph.hh                                        |   3 ++-
+ ...testcase-minimized-hb-repacker-fuzzer-5390364397928448 | Bin 0 -> 423 bytes
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+commit 239a5aca022926d89291701ad9547ac4477c86d6
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Dec 5 19:15:36 2022 +0000
+
+    [repacker] don't allow references to the null object in graph.
+    
+    Fixes fuzzer issue https://oss-fuzz.com/testcase-detail/6714085985353728
+
+ src/graph/graph.hh                                     |   7 ++++---
+ ...tcase-minimized-hb-repacker-fuzzer-6714085985353728 | Bin 0 -> 358596 bytes
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+commit 4ce0f088978b20b8ef431426faa16dee253a5ea0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Oct 31 12:20:19 2022 -0600
+
+    [coretext] Clamp variation settings to min/max
+    
+    Like our native implementation does; CoreText doesn't itself.
+    
+    Also fix leak of CFNumber's.
+
+ src/hb-coretext.cc | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+commit 1b867530314e8efe3a67377ac25b04ca2e71e90e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 5 11:44:52 2022 -0700
+
+    [hb-subset] Support -u, -g, -t
+    
+    For --unicodes, --gids, --text.
+
+ util/hb-subset.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 22b0390e2dcefcf737d70f8d965d99b902831a29
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Dec 5 09:43:36 2022 -0700
+
+    Revert "[VarData] Don't clear memory we are going to fill in completely"
+    
+    This reverts commit e28e2dad03a453c5e5c4c5a9d6fd276182c5f80b.
+    
+    This made fuzzer unhappy. I'm not sure how.
+    
+    https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=54044
+
+ src/hb-ot-layout-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3c497e2458d358748d0e85f5e3afb9d9e33e717c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 4 15:35:01 2022 -0700
+
+    [harfbuzz-subset.cc] Revert accidental change
+    
+    These extra files are unnecessary, but our generator currently
+    isn't smart enough to know that. Will fix some time.
+
+ src/harfbuzz-subset.cc | 40 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 40 insertions(+)
+
+commit aa7f5e3742bc737f727a3c62a9884ed12cdb87fa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 4 15:31:47 2022 -0700
+
+    [subset] Conditionalize call to hb_font_set_variations
+
+ src/OT/glyf/glyf.hh    |  2 ++
+ src/harfbuzz-subset.cc | 40 ----------------------------------------
+ src/hb-subset-plan.cc  |  2 ++
+ 3 files changed, 4 insertions(+), 40 deletions(-)
+
+commit ad5588e80046ea2f5108d21c583a1ecf12efeb82
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 4 15:27:59 2022 -0700
+
+    [config] If HB_NO_SHAPER then HB_NO_OT_SHAPE
+
+ src/hb-config.hh | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit 1a5c749581a9d7d19ab94250599c6e2700660fee
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 4 15:20:51 2022 -0700
+
+    [config] Flesh out HB_NO_SHAPER a bit more
+
+ src/hb-face.cc       | 2 ++
+ src/hb-face.hh       | 2 ++
+ src/hb-shape-plan.cc | 5 +++++
+ src/hb-shape.cc      | 5 +++++
+ 4 files changed, 14 insertions(+)
+
+commit 2c0abf02580ba109abcd6fb1da890f8b7500a9b1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 4 15:03:36 2022 -0700
+
+    Revert "[harfbuzz-subset.cc] Trim down!"
+    
+    This reverts commit a335458d5776135f8672bfc98681b8862f657d5c.
+    
+    While this can be vastly trimmed down, what I did is not right.
+    It still depends on hb-face, hb-font, hb-blob, hb-set, and hb-map.
+
+ src/harfbuzz-subset.cc | 45 +++++++++++++++++++++++++++++++++++++++++++++
+ src/meson.build        |  2 +-
+ 2 files changed, 46 insertions(+), 1 deletion(-)
+
+commit a335458d5776135f8672bfc98681b8862f657d5c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 4 14:56:20 2022 -0700
+
+    [harfbuzz-subset.cc] Trim down!
+
+ src/harfbuzz-subset.cc | 45 ---------------------------------------------
+ src/meson.build        |  2 +-
+ 2 files changed, 1 insertion(+), 46 deletions(-)
+
+commit 765a3551da9c05ad6b2868a703ddf50fd84630cd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 4 14:48:32 2022 -0700
+
+    [face-builder] Minor cast
+
+ src/hb-face.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3fff6d9084e92642f4e13e54e9720c682d5d2bc5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 4 14:47:38 2022 -0700
+
+    [face-builder] Initialize face orders to -1
+
+ src/hb-face.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 805ce9ad3d3254e4b8dde113cdf914aebb533482
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 4 14:43:17 2022 -0700
+
+    [face-builer] Protect against wrong face
+    
+    In hb_face_builder_sort_tables.
+
+ src/hb-face.cc | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+commit 0acfd2b714ad15167c882c1c5be3a650db24e748
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 4 14:01:05 2022 -0700
+
+    [indic-machine] Regenerate line numbers
+
+ src/hb-ot-shaper-indic-machine.hh | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+commit 9704f8354e92c86aaaec7dc736463091e421b03c
+Merge: 0545949f0 c1aae14a6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 4 13:58:52 2022 -0700
+
+    Merge branch 'config-header'
+
+commit c1aae14a68eaea92c4de20e372cfca05c66c50b1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 4 13:53:55 2022 -0700
+
+    [features.h] Fix autotools build rules
+
+ src/Makefile.am | 18 ++++++++++--------
+ 1 file changed, 10 insertions(+), 8 deletions(-)
+
+commit 0545949f018cf48743052de878bfabbb95b4d1d6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 4 12:44:09 2022 -0700
+
+    [gvar] Minor use array get_size()
+
+ src/hb-ot-var-gvar-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1bd386515c603a1e77291f77e50dc7cb3437dbcd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 4 12:29:23 2022 -0700
+
+    [bit-set] Micro-optimize page_for
+
+ src/hb-bit-set.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit b182e2808af51a04b72951781fe21c3e2301e827
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 4 12:22:17 2022 -0700
+
+    [bit-set] Don't clear pages when copying set
+
+ src/hb-bit-set.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit f5307c3ba8401fbaf9008705d7f8dfa7d28e944c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 4 11:54:16 2022 -0700
+
+    [map] Speed up is_real()
+
+ src/hb-map.hh | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+commit 301f6e4b47f0ce40758a773cc351f98564eda02c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 4 11:46:10 2022 -0700
+
+    [Coverage] Remove TODO
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit dbbb8e8006ea71519546105f229ce635105bf855
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 4 11:13:39 2022 -0700
+
+    Revert "[map] Add hb_map_filter_invalid"
+    
+    This reverts commit 8d7e92111786b21906157127c24b72b1e444e6e7.
+    
+    Surprisingly this slowed NotoNastaliqUrdu benchmark down by a couple
+    percent instead of speeding it up.
+
+ src/OT/Layout/Common/Coverage.hh | 2 +-
+ src/hb-map.hh                    | 2 --
+ 2 files changed, 1 insertion(+), 3 deletions(-)
+
+commit 8d7e92111786b21906157127c24b72b1e444e6e7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Dec 4 11:01:45 2022 -0700
+
+    [map] Add hb_map_filter_invalid
+    
+    Use it in one place.
+
+ src/OT/Layout/Common/Coverage.hh | 2 +-
+ src/hb-map.hh                    | 2 ++
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+commit 260df1fa326c6c19d35e030f78d24e2342cb7370
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sun Dec 4 12:25:22 2022 -0500
+
+    [indic] Support <U+0A02, U+0A40>
+
+ src/gen-indic-table.py                             |  11 +-
+ src/hb-ot-shaper-indic-machine.hh                  | 610 +++++++++++----------
+ src/hb-ot-shaper-indic-machine.rl                  |   3 +-
+ src/hb-ot-shaper-indic-table.cc                    |   7 +-
+ src/hb-ot-shaper-indic.cc                          |  14 +-
+ .../5f73fff1ffc07b5a99a90c0909609f2b09fef274.ttf   | Bin 0 -> 1028 bytes
+ .../data/in-house/tests/indic-special-cases.tests  |   2 +
+ 7 files changed, 349 insertions(+), 298 deletions(-)
+
+commit 8b533763c07f565c1b31505351bf3b51088a62a3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 15:58:12 2022 -0700
+
+    Use hb_len() instead of .len()
+
+ src/hb-open-type.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit e28e2dad03a453c5e5c4c5a9d6fd276182c5f80b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 15:56:43 2022 -0700
+
+    [VarData] Don't clear memory we are going to fill in completely
+
+ src/hb-ot-layout-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 0e13b4abbc90574fb3a2c7c87070fc3908b7d4ea
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 15:50:24 2022 -0700
+
+    [VarData] Optimize main loop slightly
+
+ src/hb-ot-layout-common.hh | 19 ++++++++++---------
+ 1 file changed, 10 insertions(+), 9 deletions(-)
+
+commit ad17c0acce14995bcbd67ff18532c6c4283ff9d0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 14:56:57 2022 -0700
+
+    [VarData] Whitespace
+
+ src/hb-ot-layout-common.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit e7eb445d29076f4d5cf9d7d7d09d40288eaf9186
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 14:56:00 2022 -0700
+
+    [VarData] Optimize longWord calculation
+
+ src/hb-ot-layout-common.hh | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+commit f2c980be2998a909486a4a40515763a57b03846b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 14:49:38 2022 -0700
+
+    [VarData] Optimize wordCount calculation
+    
+    6% speedup in RobotoFlex-Variable/900 benchmark.
+
+ src/hb-ot-layout-common.hh | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 3641b0e01ec46a06cd684c48262680ac74194393
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 14:26:21 2022 -0700
+
+    [VarData] Optimize serialize()
+
+ src/hb-ot-layout-common.hh | 39 +++++++++++++++++++++++++++++++--------
+ 1 file changed, 31 insertions(+), 8 deletions(-)
+
+commit e155f1230702afb6b81b2c2901087945e5d4d249
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 14:14:39 2022 -0700
+
+    [VarData] Minor save a variable
+
+ src/hb-ot-layout-common.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit 5596a7308752b619d9417735c8f8718b09ec9a34
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 13:33:48 2022 -0700
+
+    [layout] Speed up ClassDefFormat2 intersects
+
+ src/hb-ot-layout-common.hh | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+commit 85e7263b38db4a42c56cb7e7d81564576e5607a5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 13:28:02 2022 -0700
+
+    [VariationStore] Minor access array directly
+
+ src/hb-ot-layout-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 41a8597f38b7ebcad3c599105f12104e106d5873
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 13:23:26 2022 -0700
+
+    [layout] Simplify CoverageFormat2 intersects_coverage()
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 18 +++---------------
+ 1 file changed, 3 insertions(+), 15 deletions(-)
+
+commit 1f4d8ccaedfce035567f43fbb47597151bdf89a6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 13:17:15 2022 -0700
+
+    [CoverageFormat2] Optimize intersects()
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+commit c482b061081a77e8ca085ade01c951406c5d554d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 13:14:31 2022 -0700
+
+    [gpos] Optimize PairPosFormat1::intersects
+
+ src/OT/Layout/GPOS/PairPosFormat1.hh | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+commit 58e9df132fd5db88667bb71a7538358d4109ce33
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 13:04:00 2022 -0700
+
+    [Device] Serialize VariationDevice zerocopy
+
+ src/hb-ot-layout-common.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 071a2bb4f7e433eabb21e38cd560cc4dcfacab7d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 13:03:38 2022 -0700
+
+    [serialize] Support zerocopy while sharing
+
+ src/hb-serialize.hh | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+commit 44a5de3a97c6092547d4994c7b10922fbdce15b8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 12:50:32 2022 -0700
+
+    [Device] Save a snap/revert
+
+ src/hb-ot-layout-common.hh | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+commit 93328cedfc6e55e78f86db1026f4f1b98dd84501
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 12:49:26 2022 -0700
+
+    [Device] Save a map get()
+
+ src/hb-ot-layout-common.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 630b874ae6f54d7c1705ec1c16599d476b8c1c69
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 12:13:15 2022 -0700
+
+    [gsubgpos] Add a cache to intersected_class_glyphs
+    
+    30% gain on subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/1400.
+
+ src/hb-ot-layout-gsubgpos.hh | 72 +++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 54 insertions(+), 18 deletions(-)
+
+commit c044f4af3e3e513e42ffd1b48b7b0b4af7633953
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 11:58:04 2022 -0700
+
+    [gsubgpos] Remove wrong const
+
+ src/hb-ot-layout-gsubgpos.hh | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+commit 2680be1f22e7446fb6da04e99716dc08a112d0c2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 11:53:14 2022 -0700
+
+    [gsubgpos] Don't set unnecessary funcs
+
+ src/hb-ot-layout-gsubgpos.hh | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+commit 023f595dec2b9c0cbc91a6b63a594e9041f1006e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 11:18:05 2022 -0700
+
+    [cmap] Speed up DefaultUVS::copy even more
+    
+    Another 14% on SourceHanSerifVF/10 benchmark.
+
+ src/hb-ot-cmap-table.hh | 81 +++++++++++++++++++++++++++++++++++--------------
+ 1 file changed, 59 insertions(+), 22 deletions(-)
+
+commit 4ca610510805764433eea47a4f991aaf059bd9ce
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 11:15:06 2022 -0700
+
+    [cmap] Remove double-min
+
+ src/hb-ot-cmap-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit cd29147e30df819850b9f257bc1bd69470741ed4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 10:41:42 2022 -0700
+
+    [cmap] Minor cast
+
+ src/hb-ot-cmap-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4cdb5cc69b6110fe28b9e01d9c3e4e8f4a8b3272
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 10:40:24 2022 -0700
+
+    [cmap] Minor change iterator
+
+ src/hb-ot-cmap-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 2cdaedaf543375a54f0810cf5b2b2a535fd85d3b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 10:16:35 2022 -0700
+
+    Use hb_enumerate in more places
+
+ src/graph/markbasepos-graph.hh |  4 ++--
+ src/hb-ot-var-fvar-table.hh    | 10 +++++-----
+ src/hb-subset-plan.cc          |  6 ++----
+ 3 files changed, 9 insertions(+), 11 deletions(-)
+
+commit 02bc4dd69bc5dc8d11de1404e6531b35e233dd39
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 10:07:16 2022 -0700
+
+    Use hb_enumerate instead of hand-coding
+
+ src/hb-ot-layout-common.hh | 46 ++++++++++++++++++++--------------------------
+ 1 file changed, 20 insertions(+), 26 deletions(-)
+
+commit 4d19c724c0423892810eefe8b9d9c6efcf274ddd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 09:57:29 2022 -0700
+
+    [CoverageFormat1] Speed up intersects()
+    
+    Speeds up SourceHanSerif/10000 benchmark (not in test suite) by
+    32%!
+
+ src/OT/Layout/Common/CoverageFormat1.hh | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+commit a2d33779e1f582e06c89549090ba95251c04be13
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 09:49:00 2022 -0700
+
+    Fix arm bot build
+
+ src/hb-ot-cmap-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit dabbf13d402620e605ad497b58dbfb61aed28a3d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Dec 3 09:46:11 2022 -0700
+
+    [cmap] Speed up DefaultUVS::copy
+
+ src/hb-ot-cmap-table.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 8eadb83640b0f027639d80a10071ad4ae3ab6c47
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Nov 10 10:33:26 2022 -0800
+
+    [subset] Update hb_subset_input_override_name_table API
+    
+    Override the name string for the NameRecord identified by name_id,
+    platform_id, encoding_id and language_ids specified by the user.
+    If a record with specified name_id does not exist, this API will create
+    a new NameRecord with provided info and insert it to the name table.
+
+ src/hb-ot-name-table.hh                     | 154 ++++++++++++++++++++++------
+ src/hb-subset-input.cc                      |  69 +++++++++----
+ src/hb-subset-input.hh                      |  44 +++++++-
+ src/hb-subset-plan.cc                       |  10 +-
+ src/hb-subset-plan.hh                       |  10 +-
+ src/hb-subset.h                             |   5 +-
+ test/api/fonts/nameID.override.expected.ttf | Bin 167936 -> 168012 bytes
+ test/api/test-subset-nameids.c              |  14 ++-
+ 8 files changed, 237 insertions(+), 69 deletions(-)
+
+commit 29903f46b92db764ba8e6b6422c2128c011c7223
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 2 17:45:01 2022 -0700
+
+    [benchmark-subset] Cache (preprocessed) face amongst runs
+
+ perf/benchmark-subset.cc | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+commit 3fb4ea29cd5a40e76760668e694133fa095e8d55
+Merge: a42fc8ec4 ddeac3658
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 2 17:08:31 2022 -0700
+
+    Merge pull request #3914 from harfbuzz/multimap
+    
+    [multimap] Add a multimap datastructure & use for gid-to-unicodes subset accelerator
+
+commit ddeac3658b46a6536a67b06b8bc8f3efd9ce5f6f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 2 16:51:07 2022 -0700
+
+    [test-multimap] More tests
+
+ src/test-multimap.cc | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+commit ff419789efb2a7b8f997fbd8d87bea738f2a6c59
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 2 16:25:26 2022 -0700
+
+    [subset-plan] Sort unicode_to_new_gid_list when needed
+
+ src/hb-algs.hh        | 12 ++++++++++++
+ src/hb-subset-plan.cc |  7 ++++++-
+ src/hb-subset-plan.hh |  2 +-
+ 3 files changed, 19 insertions(+), 2 deletions(-)
+
+commit 1a40da4ad1a8896f65a99838d5251613ecc8e350
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 2 16:13:37 2022 -0700
+
+    [subset-plan] Use add_array instead of add_sorted_array
+    
+    That vector is not declared as sorted.
+
+ src/hb-subset-plan.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 32e049a315a1f1d6e2f751f1f93472134fec8f00
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 2 16:09:10 2022 -0700
+
+    [subset-plan] Use gid-to-unicodes multimap
+    
+    One test fails. Need investigation.
+
+ src/hb-subset-plan.cc | 37 +++++++++++++++++++++++++++++++------
+ 1 file changed, 31 insertions(+), 6 deletions(-)
+
+commit da7961b2e879aab88fedda7cd0c9e2de4c3240a1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 2 16:08:40 2022 -0700
+
+    .
+
+ src/hb-multimap.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 7d6893a8034230458ba22f677d54e67c68b1508a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 2 15:50:52 2022 -0700
+
+    [subset-accelerator] Cache gid-to-unicodes
+
+ src/hb-subset-accelerator.hh | 15 +++++++++++----
+ src/hb-subset-plan.cc        | 12 ++++++++++++
+ 2 files changed, 23 insertions(+), 4 deletions(-)
+
+commit 10c8fc55535e679a75f6f3012273f256e0416d90
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 2 15:34:34 2022 -0700
+
+    [multimap] Add a multimap datastructure
+
+ src/Makefile.am      |  5 +++
+ src/Makefile.sources |  1 +
+ src/hb-multimap.hh   | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/meson.build      |  2 ++
+ src/test-multimap.cc | 50 ++++++++++++++++++++++++++++
+ 5 files changed, 150 insertions(+)
+
+commit a42fc8ec4a55adce3a935fb40183f388ff376f8a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 2 15:41:18 2022 -0700
+
+    [subset-accelerator] Adjust in_error()
+
+ src/hb-subset-accelerator.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 65d9630312e277dc464122ae60ce877634ad1820
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 2 14:59:26 2022 -0700
+
+    [subset-cff2] Whitespace
+
+ src/hb-subset-cff2.cc | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit b33297ee26a3965e172ec13d1297eef11783c0c2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 2 14:43:37 2022 -0700
+
+    [cff2] Remove unused typedef
+
+ src/hb-cff2-interp-cs.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 3ade2ffaa58d639bc825dbeee8aa1d0033ed668b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 2 14:26:36 2022 -0700
+
+    [serialize] Adjust pop_discard for zerocopy
+
+ src/hb-serialize.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 043eeb29a3913ff92879c35d410669da3574af18
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 2 13:58:36 2022 -0700
+
+    [subset-cff] Optimize encode_subrs
+    
+    Don't loop over all original subrs. Just walk over closure subrs.
+
+ src/hb-subset-cff-common.hh | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+commit 0ad5977cd6679f7d0f19e255d78eaf14ecc4e116
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 2 13:41:06 2022 -0700
+
+    [subset-cff] Simplify hinting processing
+    
+    We already have drop_hints in the params.
+
+ src/hb-subset-cff-common.hh | 26 ++++++++++----------------
+ 1 file changed, 10 insertions(+), 16 deletions(-)
+
+commit 16cbe41bcaefb9ba1634f781adb7357f8006f645
+Merge: 2a7a1d5a7 16f61a1c8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 2 12:43:13 2022 -0700
+
+    Merge pull request #3910 from googlefonts/repacker_fuzz
+    
+    [repacker] Add a fuzzer for the hb-subset-repacker api.
+
+commit 2a7a1d5a73f2bd337c69a381d8592a7633113793
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 2 12:33:24 2022 -0700
+
+    [Coverage] Avoid timeout on broken ranges
+    
+    Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=53929
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit c9476527689bd5f061584ba83e1298dd8be3549f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 21:48:35 2022 -0700
+
+    [subset-cff] Micro-optimize
+
+ src/hb-subset-cff-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit a24d4e9261ccd280e874177e6d21bdf40dd6d76d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 20:27:56 2022 -0700
+
+    [array] Oops. Fix memcpy copy()!
+
+ src/hb-array.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 5e41766bb92d7b58ededf40e1e031b4690464f48
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 20:19:04 2022 -0700
+
+    [array] Fix hb_bytes_t memcpy copy
+    
+    Wasn't being used!
+
+ src/hb-array.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit a5616227caf44c5fdcdea3c8f8336808d5b0087b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 20:11:34 2022 -0700
+
+    [subset-cff] Fix buffer size calculation
+
+ src/hb-subset-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 015af5a8e5bbcfbc63328a1196318621ed21e1e7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 20:08:59 2022 -0700
+
+    [subset-cff] Write a couple loops as range-based for
+
+ src/hb-subset-cff-common.hh | 24 +++++++++---------------
+ 1 file changed, 9 insertions(+), 15 deletions(-)
+
+commit bfbbd4af253a2ac58bb8bcdcde650fcba9636038
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 20:05:20 2022 -0700
+
+    [subset-cff] Copy str for call ops
+
+ src/hb-subset-cff-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit c755b3884f40595340fe3de615faf8c17842c667
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 20:02:38 2022 -0700
+
+    [subset-cff] Pre-alloc enough for check-less copy
+
+ src/hb-subset-cff-common.hh | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+commit 062e59ae673d645c4b072938a40af7f3931ccaca
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 19:43:48 2022 -0700
+
+    [subset-cff] Optimize vector allocation for preprocessed input
+
+ src/hb-subset-cff-common.hh | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit 8e9e94dba971e3b09d4a9853a8abcf68d5c6dc62
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 19:40:21 2022 -0700
+
+    Revert "[vector] Optimize grow_vector() for size"
+    
+    This reverts commit 1dd9396c7a4c24fe9d578551fab735bdd699e52a.
+    
+    Is faster indeed.
+    
+    15% on SourceHanSans/10000 benchmark.
+
+ src/hb-vector.hh | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+commit 2644540a74c19a32fbe3fe904b1266163b8ff2a1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 18:49:09 2022 -0700
+
+    [subset-cff] Compact parsed strings if using accelerator
+    
+    Saves 32% on SourceHanSans/10000 benchmark!
+    
+    Also, use memcmp now for writing out strings since now that our
+    ops are not super short, that's faster.
+    
+    This makes cff-japanese test takes super long though; that needs
+    inspection.
+
+ src/hb-subset-cff-common.hh | 55 ++++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 45 insertions(+), 10 deletions(-)
+
+commit 6012d3b228bc30397ab46eda48776fb414043315
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 17:33:53 2022 -0700
+
+    [subset-cff] Write out charstrings zerocopy to serializer
+
+ src/hb-serialize.hh   | 21 +++++++++++++++++----
+ src/hb-subset-cff1.cc |  8 +++++++-
+ src/hb-subset-cff2.cc |  8 +++++++-
+ 3 files changed, 31 insertions(+), 6 deletions(-)
+
+commit 16f61a1c87f83ac750bdf529917519593a9ef58e
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Dec 1 23:57:30 2022 +0000
+
+    [repacker] only build repacker fuzzer when experimental api is enabled.
+
+ test/fuzzing/meson.build | 35 +++++++++++++++++++++--------------
+ 1 file changed, 21 insertions(+), 14 deletions(-)
+
+commit 36e1a6339cb0a9bd9ec6e76b64ae83ec871d2f8f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 16:52:29 2022 -0700
+
+    [cff] Add total_size to INDEX
+
+ src/hb-ot-cff-common.hh | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+commit 3843000660d587d81d3f71bfd8a1e76939847b86
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 16:48:22 2022 -0700
+
+    [serialize] Add start_zerocopy()
+
+ src/hb-serialize.hh | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+commit de5a621322a749e96333656a86137a6ee42490b3
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Dec 1 23:37:16 2022 +0000
+
+    [repacker] enforce root node having no incoming edges.
+
+ src/graph/graph.hh                                     |   8 ++++++++
+ .../crash-3bf72494aa4c9f8cbbcbf887fdc2a2858c87feb4     | Bin 0 -> 358596 bytes
+ 2 files changed, 8 insertions(+)
+
+commit a2681c37c171143858ade2f91c9eff876c0aa586
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 16:09:03 2022 -0700
+
+    [cff-subset] Simplify INDEX serialize() more
+
+ src/hb-ot-cff-common.hh | 21 ++++++---------------
+ src/hb-ot-cff1-table.hh |  2 --
+ 2 files changed, 6 insertions(+), 17 deletions(-)
+
+commit c4b05878cbca0b710485c5ea749d8e5e69166aef
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 15:56:37 2022 -0700
+
+    [subset-cff] Remove INDEX unused serialize() methods
+
+ src/hb-ot-cff-common.hh | 61 -------------------------------------------------
+ 1 file changed, 61 deletions(-)
+
+commit b3ad4d72cced348ff5a169ef59b28c13b5f09741
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 15:46:00 2022 -0700
+
+    [cff] Another no-memset in INDEX
+
+ src/hb-ot-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 5fd2f255fc4bd749d583cf98dc1788e69f40acd6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 15:18:59 2022 -0700
+
+    [open-type] Don't memset 0 in serialize for ArrayOf family
+    
+    Not necessary.
+
+ src/hb-open-type.hh | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+commit 30e405e470f002693b353db5a1bb90504ba01b2a
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Dec 1 22:12:59 2022 +0000
+
+    [repacker] ensure link obj indices are valid.
+
+ src/graph/graph.hh                                     |  11 +++++++++--
+ .../leak-a77f29b25edb873729f3ab120148fdb213cfa527      | Bin 0 -> 358596 bytes
+ 2 files changed, 9 insertions(+), 2 deletions(-)
+
+commit 70ac6dfb28e7ec921ab03467dd84e7c9103d87c5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 14:56:28 2022 -0700
+
+    [subset-cff] Don't memset 0 INDEX and other serialize methods
+    
+    Not necessary.
+
+ src/hb-ot-cff-common.hh | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit 554ed06fac759508ad959482f784bf02e4839a66
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Dec 1 21:51:17 2022 +0000
+
+    [repacker] add cycle detection to the graph sort.
+    
+    This allows us to bail early if the graph is not acyclic.
+
+ src/graph/graph.hh                 | 14 ++++++++++----
+ src/hb-repacker.hh                 |  5 +++++
+ src/test-repacker.cc               |  1 +
+ test/fuzzing/hb-repacker-fuzzer.cc | 17 +++++++++++++++--
+ 4 files changed, 31 insertions(+), 6 deletions(-)
+
+commit a66de336fb6c98f9946830194e6b28d0f3aaaef8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 14:32:13 2022 -0700
+
+    [vector] Minor use get_size() in as_bytes()
+
+ src/hb-vector.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 0b826368fd122691e6d9095a42e8ad3023baa4bb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 14:23:25 2022 -0700
+
+    [serializer] Don't memset memory in embed
+    
+    Not necessary.
+
+ src/hb-serialize.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3b68c7146f0722f6ae54f3bee9afa8112dc8dba4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 14:19:27 2022 -0700
+
+    [array] Don't clear serializer buffer when copying out
+    
+    Not needed.
+
+ src/hb-array.hh     |  4 ++--
+ src/hb-serialize.hh | 13 +++++++------
+ 2 files changed, 9 insertions(+), 8 deletions(-)
+
+commit 57808609c98ff037e03c2c1be0c7d9dbffe3f62f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Dec 1 14:03:56 2022 -0700
+
+    [VarData] Move an unlikely
+
+ src/hb-ot-layout-common.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 9e99d08470c455d3ea8fc73e01a244d492fff989
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Sep 8 23:19:02 2022 +0000
+
+    [repacker] validate link widths during repacker setup.
+
+ src/graph/graph.hh                 | 7 +++++++
+ test/fuzzing/hb-repacker-fuzzer.cc | 2 --
+ 2 files changed, 7 insertions(+), 2 deletions(-)
+
+commit edf7a29595f01bf5548587476b37efdc24c500f1
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Sep 8 22:59:34 2022 +0000
+
+    [repacker] Validate link positions before running the repacker.
+
+ src/graph/graph.hh                                 |  30 +++++++++++++++++++++
+ src/hb-repacker.hh                                 |   6 +++++
+ .../crash-442bfac994a3d9929cf06262ae9fb00f6ee1f774 | Bin 0 -> 358596 bytes
+ test/fuzzing/hb-repacker-fuzzer.cc                 |   1 +
+ 4 files changed, 37 insertions(+)
+
+commit 88d437525ffc25c5f9ee3d81b828aedd234b521c
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Sep 8 21:19:25 2022 +0000
+
+    [repacker] add test for repacker fuzzer.
+
+ test/fuzzing/meson.build                  | 12 ++++++
+ test/fuzzing/run-repacker-fuzzer-tests.py | 68 +++++++++++++++++++++++++++++++
+ 2 files changed, 80 insertions(+)
+
+commit 6627a1ab450066bfda9c064dc48a0e4ea7fa45c8
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Sep 8 21:11:39 2022 +0000
+
+    [repacker] Add a initial seed for the fuzzer repacker.
+
+ test/fuzzing/graphs/noto_nastaliq_urdu | Bin 0 -> 358596 bytes
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+
+commit deca30b2684f5580606ad614bc3ffb6c35e887a5
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Sep 8 21:10:06 2022 +0000
+
+    [repacker] get repacker fuzzer working.
+    
+    Additionally add helper method that allows a graph to be saved as a fuzzer seed.
+
+ src/graph/graph.hh                 | 50 ++++++++++++++++++++++++++++++++++++++
+ src/hb-repacker.hh                 |  2 +-
+ test/fuzzing/hb-repacker-fuzzer.cc | 13 +++++++---
+ 3 files changed, 60 insertions(+), 5 deletions(-)
+
+commit 261a605f9c75d65570ee70abbc46a03e4ce99f7b
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Sep 7 22:43:06 2022 +0000
+
+    [repacker] verify graph is a dag before using the fuzzer input.
+
+ test/fuzzing/hb-repacker-fuzzer.cc | 12 +++---------
+ 1 file changed, 3 insertions(+), 9 deletions(-)
+
+commit 985b19f678cbccc57853796d2ee0e6885b9e7244
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Sep 7 22:21:16 2022 +0000
+
+    [repacker] begin implementing a fuzzer for the repacker api.
+
+ src/graph/graph.hh                 |  12 ++++
+ src/hb-repacker.hh                 |   6 ++
+ test/fuzzing/hb-repacker-fuzzer.cc | 134 +++++++++++++++++++++++++++++++++++++
+ test/fuzzing/meson.build           |   3 +
+ 4 files changed, 155 insertions(+)
+
+commit c6d616cc41561cc0029050e579b36cb5084a05ed
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Oct 17 22:41:51 2022 -0400
+
+    Generate and install hb-features.h
+    
+    This header has defines for all the optional
+    dependendencies that come with their own Harfbuzz
+    headers, so you can do:
+    
+      #include <hb-features.h>
+      #ifdef HB_HAS_DIRECTWRITE
+      #include <hb-directwrite.h>
+      #endif
+
+ src/Makefile.am      | 42 ++++++++++++++++++++++-
+ src/hb-features.h.in | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/meson.build      | 18 ++++++++++
+ 3 files changed, 155 insertions(+), 1 deletion(-)
+
+commit 8805a866b52526e41acd1e7ffe2c9e7bbee5a3b6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 30 17:15:00 2022 -0700
+
+    [ClassDef2] Write a few loops as range-based for
+
+ src/hb-ot-layout-common.hh | 34 ++++++++++++++--------------------
+ 1 file changed, 14 insertions(+), 20 deletions(-)
+
+commit ac8b232a2d94dcde2cdf00a4cc1db856009edb2a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 30 16:42:15 2022 -0700
+
+    [gsub] Cache intersects_class results for closure
+    
+    Benchmark                                                                                 Time             CPU      Time Old      Time New       CPU Old       CPU New
+    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
+    BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/10                  +0.0246         +0.0240             0             0             0             0
+    BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/64                  -0.5541         -0.5544             4             2             4             2
+    BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/512                 -0.1120         -0.1123            43            38            43            38
+    BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/1400                -0.1154         -0.1159            43            38            43            38
+
+ src/hb-ot-layout-gsubgpos.hh | 58 +++++++++++++++++++++++++++++++-------------
+ 1 file changed, 41 insertions(+), 17 deletions(-)
+
+commit 20a0a467299964b0095295247f455835e63ed009
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 30 15:59:54 2022 -0700
+
+    [perf] Remove stale run.sh
+
+ perf/run.sh | 25 -------------------------
+ 1 file changed, 25 deletions(-)
+
+commit 38e7bc345c5a55fa910b3af967c4713da2dbcb6a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 30 15:01:38 2022 -0700
+
+    [benchmark-subset] Support testing arbitrary fonts from cmdline
+
+ perf/benchmark-subset.cc | 38 +++++++++++++++++++++++++++++++-------
+ 1 file changed, 31 insertions(+), 7 deletions(-)
+
+commit c6a4b60116a528afb4f1bb28880326cf80ceafc8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 30 14:09:59 2022 -0700
+
+    [gsubgpos] Add an unlikely
+
+ src/hb-ot-layout-gsubgpos.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit d4dec54c3adec19875f3b29b773b282390e1f1ef
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 30 13:51:14 2022 -0700
+
+    [ci] Switch configs build to Ubuntu 20.04
+    
+    https://github.com/actions/runner-images/issues/6002
+
+ .github/workflows/configs-build.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 52d8346d993ed5ad96356216958323abc89cd514
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 30 13:50:16 2022 -0700
+
+    [ci] Change Linux runner to Ubuntu 20.04
+    
+    https://github.com/actions/runner-images/issues/6002
+
+ .github/workflows/linux-ci.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 32dd9810cf156b7710bc849030d69b902e58077b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 30 13:15:58 2022 -0700
+
+    [subset-cff1] Cache glyph-to-sid-map in the accelerator
+    
+    Benchmark                                                                                      Time             CPU      Time Old      Time New       CPU Old       CPU New
+    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+    BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/10                   -0.0841         -0.0843             0             0             0             0
+    BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/64                   -0.1305         -0.1305             0             0             0             0
+    BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/512                  -0.1398         -0.1401             1             1             1             1
+    BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/4096                 +0.0382         +0.0380             9             9             9             9
+    BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/10000                +0.0213         +0.0211            11            11            11            11
+
+ src/hb-ot-cff2-table.hh     |  5 +++++
+ src/hb-subset-cff-common.hh |  2 ++
+ src/hb-subset-cff1.cc       | 21 +++++++++++++++++----
+ 3 files changed, 24 insertions(+), 4 deletions(-)
+
+commit 72fabef0a46435152ec620b88245d32391858634
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 30 11:37:49 2022 -0700
+
+    [SingleSubstFormat2] Speed up closure
+
+ src/OT/Layout/GSUB/SingleSubstFormat2.hh | 20 ++++++++++++++++++--
+ 1 file changed, 18 insertions(+), 2 deletions(-)
+
+commit 2dc2e016d4bc47a37857eebf64d8d0b8378b32db
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 30 11:25:50 2022 -0700
+
+    [cff] Enable an unlikely
+
+ src/hb-ot-cff-common.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 582a87ef0a320061b991662f081e6b247f7f38f2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 30 11:20:19 2022 -0700
+
+    [cff] Speed up FDSelect0 sanitize
+
+ src/hb-ot-cff-common.hh | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+commit 2658370f00981ac95c7031e9acaf8163f2e0f526
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Nov 30 00:19:10 2022 +0000
+
+    [subset] make the cmap cache in accelerator const.
+
+ src/hb-ot-cmap-table.hh      | 30 +++++++++++++++++++++++-------
+ src/hb-subset-accelerator.hh |  4 +---
+ 2 files changed, 24 insertions(+), 10 deletions(-)
+
+commit 7551a668e38248a5c1df3f1315e7a05bc5909ab6
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Nov 30 00:04:16 2022 +0000
+
+    [subset] Make cff_accelerator const.
+    
+    This gives more confidence that it won't be accidentally modified by the subset operation using it.
+
+ src/hb-subset-accelerator.hh |  2 +-
+ src/hb-subset-cff-common.hh  | 34 ++++++++++++++++------------------
+ 2 files changed, 17 insertions(+), 19 deletions(-)
+
+commit d8d0e0669405c5efbd07bcc24ad97b467534ff39
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 29 21:35:54 2022 -0700
+
+    [array] Comment
+
+ src/hb-array.hh | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit 2fecf2aa1997b5f914a9fa545c95929afc79714a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 29 21:25:01 2022 -0700
+
+    [ClassDef] Minor rename
+
+ src/hb-ot-layout-common.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 8f632ca8843427cefd9e2f7f76e1453c93c33913
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 29 21:23:35 2022 -0700
+
+    [ClassDef] Write another loop as range for
+
+ src/hb-ot-layout-common.hh | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+commit 87b12aee13778065bbacc601cfec61fac5f62268
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 29 21:18:48 2022 -0700
+
+    [ClassDef] Write a couple loops as range for
+
+ src/hb-ot-layout-common.hh | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+commit ccd40c842ccaef4923bd4ed3981e7332d73aed4c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 29 21:14:44 2022 -0700
+
+    [ClassDef] Optimize intersected_class_glyphs
+
+ src/hb-ot-layout-common.hh | 14 ++++++--------
+ 1 file changed, 6 insertions(+), 8 deletions(-)
+
+commit 44c585a6df139665a953c1f85e6e3adcc204e71f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 29 20:51:58 2022 -0700
+
+    [ClassDef] Fix disabled codeblock
+
+ src/hb-ot-layout-common.hh | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+commit 9b7617d433158eeef45461715dd416bce34328a5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 29 20:29:58 2022 -0700
+
+    [ClassDef2] Use a faster algorithm in subset()
+    
+    Speedup across the board; up to 40% for MPlus1 at small sizes.
+
+ src/hb-ot-layout-common.hh | 66 ++++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 55 insertions(+), 11 deletions(-)
+
+commit ae5e6d562bd49eed1438ecafc1c0b37ba77e0da3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 29 15:48:38 2022 -0700
+
+    [ClassDef2] Micro-optimize
+
+ src/hb-ot-layout-common.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 7129b79406fbbf53e08fa55623b5d8e2fa34e649
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 29 15:33:07 2022 -0700
+
+    [open-type] Add faster range-based loop to array types
+
+ src/hb-open-type.hh | 12 ++++++++++++
+ src/hb-vector.hh    |  2 +-
+ 2 files changed, 13 insertions(+), 1 deletion(-)
+
+commit dc823340612196ee360b5fb5a32bd1d9e143b256
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 29 15:26:55 2022 -0700
+
+    Remove a couple of unneeded .iter() invocations
+
+ src/hb-ot-layout-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 00f2657bb8fea82613d67a059dd4c3a5550683f1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 29 13:49:15 2022 -0700
+
+    [subset] Accelerate sanitize-table-cache
+    
+    Big wins all across small subsets
+    
+    BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/10                              -0.1140         -0.1129             0             0             0             0
+    BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/10                               -0.4717         -0.4714             0             0             0             0
+    BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/10                    -0.8147         -0.8146             0             0             0             0
+    BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/10                  -0.3248         -0.3242             0             0             0             0
+    BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/10                             -0.1262         -0.1260             0             0             0             0
+    BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/10                -0.0308         -0.0309             0             0             0             0
+    BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/10                       -0.1374         -0.1373             0             0             0             0
+    BM_subset/subset_codepoints/AdobeVFPrototype.otf/nohinting/10                            -0.4555         -0.4555             0             0             0             0
+    BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/10                             -0.4175         -0.4174             0             0             0             0
+    BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/10                         -0.4214         -0.4214             0             0             0
+
+ src/hb-mutex.hh              |  7 ++++---
+ src/hb-subset-accelerator.hh | 12 ++++++++++--
+ src/hb-subset-plan.hh        | 16 +++++++++-------
+ 3 files changed, 23 insertions(+), 12 deletions(-)
+
+commit 33165f4848608ddd813404602877bcf907e1e683
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 29 15:14:15 2022 -0700
+
+    [bit-page] Remove ELT_BITS_LOG_2
+    
+    My compiler is smart enough to take care of it.
+
+ src/hb-bit-page.hh | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+commit 58925ed9a0bf0dc7b3e8dff34d296bf50759e2b7
+Author: Satadru Pramanik <satadru@gmail.com>
+Date:   Tue Nov 29 13:14:10 2022 -0500
+
+    Update freetype subproject to 2.12.1
+
+ subprojects/freetype2.wrap | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 80dd751564e8a9153f7466e687b8699a5e7e27c6
+Author: Christoph Reiter <reiter.christoph@gmail.com>
+Date:   Tue Nov 29 19:15:31 2022 +0100
+
+    CI: work around flaky 64bit MSYS2 builds
+    
+    MSYS2 Python+meson has some random crashes in CI which we haven't been
+    able to reproduce yet. Naturally enabling debugging fixes them.. :)
+
+ .github/workflows/msys2-ci.yml | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 8f41b6a13918968476b9b2e917798daca3394352
+Author: Christoph Reiter <reiter.christoph@gmail.com>
+Date:   Tue Nov 29 18:29:46 2022 +0100
+
+    CI: fix msvc build
+    
+    The Windows image for some reason now contains a zlib and freetype build
+    which meson finds and tries to use. Force meson to use the subprojects always
+    to avoid picking up system libs.
+
+ .github/workflows/msvc-ci.yml | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 7a004a7ac27da776b623c0892ebced3d12213c39
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Nov 29 00:47:55 2022 +0000
+
+    [subset] Cache per subtable cmap unicode mappings.
+
+ src/hb-ot-cmap-table.hh      | 108 +++++++++++++++++++++++++++++++++++--------
+ src/hb-subset-accelerator.hh |  15 +++++-
+ src/hb-subset.cc             |   5 ++
+ 3 files changed, 109 insertions(+), 19 deletions(-)
+
+commit d2a2670e54d545db2e5200eeeba0f08191a09f74
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 28 19:42:27 2022 -0700
+
+    [iter] Simplify has() interface implementations
+
+ src/OT/Layout/Common/Coverage.hh | 6 ++----
+ src/hb-bit-set-invertible.hh     | 6 ++----
+ src/hb-bit-set.hh                | 6 ++----
+ src/hb-map.hh                    | 3 +--
+ src/hb-ot-layout-common.hh       | 6 ++----
+ src/hb-set.hh                    | 6 ++----
+ 6 files changed, 11 insertions(+), 22 deletions(-)
+
+commit cba82829baa1e5344e31095932c383f412a409a6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 28 16:19:54 2022 -0700
+
+    [subset-cff1] Share subrs object
+    
+    Multiple FDs might share the same subrs...
+
+ src/hb-subset-cff1.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c7b998b355f3815d4b288c457aa120770580f3c6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 28 16:18:21 2022 -0700
+
+    [cff2] Don't share fd-array link
+    
+    No point.
+
+ src/hb-subset-cff2.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3d9e3c2dc7a5cfa2831a30903419a1c98f571757
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 28 16:17:09 2022 -0700
+
+    [subset-cff2] Don't share varstore object
+
+ src/hb-subset-cff2.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c503cf003e75191f3b3f9200c8dc4e90fdc1c67b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 28 15:53:35 2022 -0700
+
+    [cmap] Store offset, not pointer, in cmap cache
+
+ src/hb-ot-cmap-table.hh | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit 3e151139a8987a13cdd8cc2ddc025534c51c607f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 28 14:23:49 2022 -0700
+
+    [PairPos] Optimize get_effective_value_format
+    
+    Speeds up BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/512
+    12%.
+
+ src/OT/Layout/GPOS/PairPosFormat1.hh | 3 +++
+ src/OT/Layout/GPOS/PairPosFormat2.hh | 6 +++++-
+ 2 files changed, 8 insertions(+), 1 deletion(-)
+
+commit 3131aecf9fc8b34a22ebf797412496c4baf18c68
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 28 14:12:55 2022 -0700
+
+    [array/hash] Fix asan issue
+    
+    ../src/hb-algs.hh:240:43: runtime error: reference binding to misaligned address 0x7ffe91a08b0e for type 'const unsigned int', which requires 4 byte alignment
+
+ src/hb-array.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 26ad7a6022533e3497e7fa94d67808830b9915b3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 28 14:09:21 2022 -0700
+
+    [gpos] Minor micro-optimize
+
+ src/OT/Layout/GPOS/PairPosFormat1.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit c769d7e1810cbb30210d0fbcc21e04909e270cf8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 28 14:03:58 2022 -0700
+
+    [gpos] Whitespace
+
+ src/OT/Layout/GPOS/PairPosFormat1.hh | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit 3ea0f37c30aaf354e256ad1374fd2e0956df8120
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 28 13:58:44 2022 -0700
+
+    [subset-cff] Move an init to constructor
+    
+    The init was not called anyway.
+
+ src/hb-subset-cff-common.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit 6c92c3e0cf4e7c09c13e2e2c59cc5467605ad165
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 28 13:54:24 2022 -0700
+
+    [subset-cff] Remove unnecessary check
+
+ src/hb-subset-cff-common.hh | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+commit 7fd300dd9a7e38973ee9eda0197e973bc88b043f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 28 13:51:16 2022 -0700
+
+    [subset-cff] Use constructor for parsed_cs_op_t
+
+ src/hb-subset-cff-common.hh | 13 ++++---------
+ 1 file changed, 4 insertions(+), 9 deletions(-)
+
+commit bd37900e0da9c5b9dbfabccb8af64e97cbe8c956
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Nov 28 20:35:34 2022 +0000
+
+    [subset] use a reference to cached global/loca subrs.
+    
+    Previously they were being copied in. Copying is no longer necessary now that hint dropping doesn't mutate the arrays.
+
+ src/hb-subset-cff-common.hh | 91 +++++++++++++++++----------------------------
+ 1 file changed, 35 insertions(+), 56 deletions(-)
+
+commit ded9de9cd82aa33a5ffbf8e23c473c6ff2c186c9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 28 13:31:40 2022 -0700
+
+    [cff] bsearch in fdselect
+    
+    Saves 8% in NotoSansCJK / 10000 subset benchmark.
+
+ src/hb-ot-cff-common.hh     | 18 ++++++++++++------
+ src/hb-subset-cff-common.hh |  9 ++++-----
+ 2 files changed, 16 insertions(+), 11 deletions(-)
+
+commit 0c33aba30cb06f2798088573efb7880315d94029
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 28 12:28:13 2022 -0700
+
+    [subset-cff] Rename drop flag to hinting flag
+
+ src/hb-subset-cff-common.hh | 28 ++++++++++++++--------------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+commit 6f5b531986c5084da7b85d12551018650ac63d5d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 28 11:39:24 2022 -0700
+
+    [subset-cff] Make no-hinting use accelerator as well
+
+ src/hb-subset-cff-common.hh | 43 +++++++++++++++++++++++++++----------------
+ 1 file changed, 27 insertions(+), 16 deletions(-)
+
+commit fad8322b3f126281ff662eb7b1a6d1747f5fc193
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Nov 27 15:09:48 2022 -0700
+
+    [benchmark-subset] Add no-hinting ops
+
+ perf/benchmark-subset.cc | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+commit f51a624e6752441ea081052620129714135559a8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Nov 27 14:54:39 2022 -0700
+
+    [subset-cff] Micro-optimize drop_hints_in_str
+
+ src/hb-subset-cff-common.hh | 22 ++++++++++++----------
+ 1 file changed, 12 insertions(+), 10 deletions(-)
+
+commit 38603266881499db8c7925ab7fc909158b462308
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Nov 27 13:23:13 2022 -0700
+
+    [subset-cff] Write loop more idiomatic
+
+ src/hb-number-parser.hh     |  8 ++++----
+ src/hb-subset-cff-common.hh | 15 ++++++++-------
+ 2 files changed, 12 insertions(+), 11 deletions(-)
+
+commit 3ff502d3aef4cdd1ac4dee29fbcb5af16f43b2cf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Nov 27 12:58:04 2022 -0700
+
+    [subset-cff] Remove unnecessary initialization
+
+ src/hb-subset-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 6af4985bf9013cef85bc5cdf3c8b8150fc72c967
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 18:20:20 2022 -0700
+
+    [subset-cff] No need for bitflag here anymore
+
+ src/hb-subset-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 69ce606d1467dbfdd3c01070a5126e141c5c3047
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 18:18:35 2022 -0700
+
+    [subset-cff] Immediately drop subr numbers instead of marking for skip
+    
+    Seems to work and saves ~2% time.
+
+ src/hb-subset-cff-common.hh | 17 ++---------------
+ 1 file changed, 2 insertions(+), 15 deletions(-)
+
+commit 1cf4f3e0830eb45bd9d96fdfcdea15d2fb1af8f2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 18:15:28 2022 -0700
+
+    [subset-cff] More comment
+
+ src/hb-subset-cff-common.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit f68221ff43df990f10ddcf91f6a71d4c72a82e82
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 18:12:14 2022 -0700
+
+    [subset-cff] Add comment
+
+ src/hb-subset-cff-common.hh | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 048ab8a066afd5c472e4a436f5e95016ac0d3649
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 18:00:43 2022 -0700
+
+    [subset-cff] Remove unused bits
+
+ src/hb-subset-cff-common.hh | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+commit 37cbfc0c7ee82ee6f781b2b1df6a8c8555a15c16
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 17:57:44 2022 -0700
+
+    [subset-cff] Remove unneeded member
+
+ src/hb-subset-cff-common.hh | 11 ++++-------
+ 1 file changed, 4 insertions(+), 7 deletions(-)
+
+commit 46ab15137b0ee04b76e22cb5964969aa9f2e6e7c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 17:49:21 2022 -0700
+
+    [subset-cff] Add has_calls to parsed charstrings
+    
+    Optimize closure based on it.
+
+ src/hb-subset-cff-common.hh | 17 +++++++++++++----
+ 1 file changed, 13 insertions(+), 4 deletions(-)
+
+commit 6d53074e6375c1680f40b647a1b4ad88dd3cc1c6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 17:23:09 2022 -0700
+
+    [subset-cff] Drop another unused parameter
+
+ src/hb-subset-cff-common.hh | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+commit 42615561b545f2bb7c29618884fa2d63d8dd97a8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 17:10:58 2022 -0700
+
+    Optimize a couple array references
+
+ src/hb-ot-map.cc            | 2 +-
+ src/hb-subset-cff-common.hh | 4 ++--
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+commit 04d23b7ca802cde23b04c8570d8d166c1b543ac3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 17:08:00 2022 -0700
+
+    [subset-cff] Micro-optimize collect_subr_refs_in_str
+
+ src/hb-subset-cff-common.hh | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+commit 9d18180c3c77ed73188d5eda14b9602c5f6d073b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 15:38:21 2022 -0700
+
+    [array] Use hb_hash instead of handrolling
+
+ src/hb-array.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 1e6f77c250825a7f6ef7e550289f67253a469b05
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 15:31:56 2022 -0700
+
+    [benchmark-subset] Adjust num glyphs more
+
+ perf/benchmark-subset.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 0382defa5196a28e3e0fcad5d91bcee14f303bad
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 15:27:07 2022 -0700
+
+    [benchmark-subset] Adjust number of glyphs of fonts
+
+ perf/benchmark-subset.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 4cb441dfd11221bdd423622a4c57f87e723fc129
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 15:23:07 2022 -0700
+
+    [benchmark-subset] Add AdobeVFPrototype
+
+ perf/benchmark-subset.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit e302b9d5da0641ab9c3e1d20cfab19282649f839
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 15:18:16 2022 -0700
+
+    Fix build
+
+ src/hb-coretext.cc          | 2 +-
+ src/hb-ms-feature-ranges.hh | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 70d97d079b73cc39d457dcb18ffae4eca3b5f5b0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 15:16:11 2022 -0700
+
+    [subset-cff] Remove unused argument
+
+ src/hb-cff2-interp-cs.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit 4167e93a1507d8fdefa37dba2044d9015f87ad78
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 15:14:52 2022 -0700
+
+    [subset-cff2] Micro-optimize blend operator
+
+ src/hb-cff2-interp-cs.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit f159bf075bb7050eebf307a5a90e1110fc526573
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 15:11:32 2022 -0700
+
+    [cff2] Micro-optimize blend operator
+
+ src/hb-cff2-interp-cs.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit a331e913dc99cba1e5994b06cffa2c5cc007f7ff
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 14:59:37 2022 -0700
+
+    [bit-page] Hand-code equality
+    
+    Faster than memcmp() because of alignment.
+
+ src/hb-bit-page.hh | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit 9df06a26950ced1017395c771e25be56f20fba5c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 14:56:45 2022 -0700
+
+    [bit-set] Fix is_subset() short-circut criteria
+    
+    Ouch!
+
+ src/hb-bit-set.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 915c1a00cfde01cc153582df31031361ded28b20
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 14:48:57 2022 -0700
+
+    [vector] Add remove_unordered
+    
+    Saves 5% in NotoNastaliq/1000 subset benchmark.
+
+ src/graph/graph.hh             |  4 ++--
+ src/graph/markbasepos-graph.hh |  2 +-
+ src/hb-vector.hh               | 14 +++++++++++++-
+ src/test-vector.cc             |  3 ++-
+ 4 files changed, 18 insertions(+), 5 deletions(-)
+
+commit 4b8d8fbee4dc5fb96d298ea8ea8c5871b7ffbc26
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 14:31:15 2022 -0700
+
+    [ot-map] Micro-optimize for size
+
+ src/hb-ot-map.hh | 6 +++---
+ src/hb-vector.hh | 3 +++
+ 2 files changed, 6 insertions(+), 3 deletions(-)
+
+commit 93f3a9dbc677ae51e5b0a754c995963207ca97b8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 14:19:00 2022 -0700
+
+    [ot-map] Micro-optimize more
+    
+    Another 500 bytes.
+
+ src/hb-ot-map.cc | 33 ++++++++++++++++++---------------
+ 1 file changed, 18 insertions(+), 15 deletions(-)
+
+commit f39f049870ebad20b76e3f56194568e89fa45aac
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 14:16:15 2022 -0700
+
+    [ot-map] Micro-optimize
+    
+    Weird that shrinks size by 500 bytes.
+
+ src/hb-ot-map.cc | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit 60bb32c45470f8ea3d30baf67980c699dfb9b801
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 14:12:57 2022 -0700
+
+    [ot-map] Minor refactor
+
+ src/hb-ot-map.cc | 21 +++++++++++----------
+ 1 file changed, 11 insertions(+), 10 deletions(-)
+
+commit e3cc61838fe331167d8074b55271039fbe2d2cb2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 13:58:04 2022 -0700
+
+    [PairPos] Adjust kerning buffer messages
+
+ src/OT/Layout/GPOS/PairPosFormat2.hh | 12 ++++++++++--
+ src/OT/Layout/GPOS/PairSet.hh        | 12 ++++++++++--
+ 2 files changed, 20 insertions(+), 4 deletions(-)
+
+commit a81dd1053dcdd1e26a0516d3a5b84e0b904e2c96
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 13:43:15 2022 -0700
+
+    [layout] Adjust printing feature tags
+    
+    For required-feature, print spaces, not nul bytes.
+
+ src/hb-ot-layout.cc | 6 +++---
+ src/hb-ot-map.hh    | 2 +-
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit 56e3868b52ef6e85d6495d28bae57dcc5746d1db
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 26 13:14:23 2022 -0700
+
+    [layout/buffer-message] Print feature name in lookup buffer messages
+
+ src/hb-ot-layout.cc | 6 +++---
+ src/hb-ot-map.cc    | 7 +++++--
+ src/hb-ot-map.hh    | 4 +++-
+ 3 files changed, 11 insertions(+), 6 deletions(-)
+
+commit a5d35fd80a26cb62c4c9030894f94c0785d183e7
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Nov 25 23:17:05 2022 +0000
+
+    [subset] use charstrings directly from accelerator cache if mutability isn't needed.
+
+ src/hb-subset-cff-common.hh | 70 ++++++++++++++++++++++++++++++---------------
+ 1 file changed, 47 insertions(+), 23 deletions(-)
+
+commit 026b64ef76e12f87ec4740c26eeda724193f810e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 25 14:57:40 2022 -0700
+
+    [subset-cff] Avoid set mallocation in hb_plan_subset_cff_fdselect
+
+ src/hb-subset-cff-common.cc | 11 ++++-------
+ 1 file changed, 4 insertions(+), 7 deletions(-)
+
+commit 74acf52f3321d3aeeb4b96f5b36040727634efd0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 25 14:43:44 2022 -0700
+
+    [subset-cff] Micro-optimize copy_str more
+
+ src/hb-subset-cff-common.hh | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit d2f3cde7ef20a7e7d58c3301ac32da6d38a65712
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 25 14:38:30 2022 -0700
+
+    [subset-cff] Micro-optimize copy_str
+
+ src/hb-subset-cff-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit e333223f269a090732ae3a9d468bb93c35bbeb62
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 25 14:23:57 2022 -0700
+
+    [array] Optimize serializing copy()
+
+ src/hb-array.hh  | 16 +++++++++++++++-
+ src/hb-vector.hh | 11 ++++++-----
+ 2 files changed, 21 insertions(+), 6 deletions(-)
+
+commit 22990fca1d78680a4f24fc29a109a115fe0660d0
+Merge: 7b197446a 8d5c899b0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 25 14:12:58 2022 -0700
+
+    Merge pull request #3894 from googlefonts/cff_accel
+    
+    [subset] Cache parsed char strings in CFF accelerator
+
+commit 8d5c899b0ff43b4b8aeb767623627cf55168c8fb
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Nov 25 20:33:39 2022 +0000
+
+    [subset] In cff accelerator hold reference to CFF table instead of the whole font.
+
+ src/hb-ot-cff1-table.hh     |  2 +-
+ src/hb-ot-cff2-table.hh     |  2 +-
+ src/hb-subset-cff-common.hh | 19 ++++++++++---------
+ 3 files changed, 12 insertions(+), 11 deletions(-)
+
+commit 7b197446acc8b4876d3d193b56ee5ab605424ef3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 25 13:28:53 2022 -0700
+
+    [vector] Adjust for HB_OPTIMIZE_SIZE
+
+ src/hb-vector.hh | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit 75a99f28abbb6d82e51f49dcda95c0d61b225e98
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Nov 25 18:38:13 2022 +0000
+
+    [subset] destruct cff accelerator if present.
+
+ src/hb-subset-accelerator.hh | 7 ++++++-
+ src/hb-subset-cff-common.hh  | 6 ++++--
+ 2 files changed, 10 insertions(+), 3 deletions(-)
+
+commit 1d474194f0a5c164ce629c4e291051ee12979e25
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 25 13:21:35 2022 -0700
+
+    [subset-cff] Micro-optimize encode_str
+
+ src/hb-subset-cff-common.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 3c4a610b59857665c73e771a4d2448fcd1acaae1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 25 13:16:30 2022 -0700
+
+    [subset-cff] Micro-optimize copy_str some more
+
+ src/hb-subset-cff-common.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 535aadb309f51dbb243042230c5fef09885c7499
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 25 13:07:42 2022 -0700
+
+    [subset-cff] Micro-optimize collect_subr_refs_in_str more
+
+ src/hb-subset-cff-common.hh | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+commit 00a9df3a43484f81d02baf9e726993ff67bb523f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 25 13:05:05 2022 -0700
+
+    [subset-cff] Micro-optimize collect_subr_refs_in_str
+
+ src/hb-subset-cff-common.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit d2a2f5bf4ed66979b17332f35b52c3395b02ed2d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 25 12:44:02 2022 -0700
+
+    [vector] Handroll copy
+
+ src/hb-vector.hh | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit 1fed366d5bb5020948b8d6d033ad886fec7e8be8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 25 12:37:24 2022 -0700
+
+    [serialize] Shut compiler warning off
+
+ src/hb-serialize.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f2297e6978087cefd27a947e044adf9e89eab5f6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 25 11:33:00 2022 -0700
+
+    [buffer] Documentation
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3889
+
+ src/hb-buffer.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 71c23c1c079cbd992ee3c9e92435ee2b1374c227
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Nov 25 18:04:44 2022 +0000
+
+    [subset] don't copy the entire global/loca subr lists from the accelerator.
+    
+    Instead run a closure on the retained charstrings and copy only the referenced subrs. This significantly speeds up cases with small character sets.
+
+ src/hb-subset-cff-common.hh | 80 ++++++++++++++++++++++++++++++---------------
+ 1 file changed, 53 insertions(+), 27 deletions(-)
+
+commit 4ff09274a86102a69c6e7abebc59d694bc90bbcd
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Nov 24 22:47:29 2022 +0000
+
+    [subset] In CFF accelerator keep a reference to original face.
+    
+    The charstring objects reference memory from the original face so we need to maintain a reference to prevent it from being destroyed.
+
+ src/hb-subset-cff-common.hh | 17 +++++++++++++++--
+ 1 file changed, 15 insertions(+), 2 deletions(-)
+
+commit 6aaa16627c3d6c77da32e6b2019724385103581d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 14:58:42 2022 -0700
+
+    [Coverage] Comment
+
+ src/OT/Layout/Common/CoverageFormat1.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 06e2147a483a1244b6978c0f7c4ca3fbe3bad227
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 14:56:04 2022 -0700
+
+    More call set->next() directly
+
+ src/hb-ot-layout-common.hh | 29 ++++++++++++++---------------
+ 1 file changed, 14 insertions(+), 15 deletions(-)
+
+commit 196c9db06fc627a4709886e49ff0823dba3bbdbc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 14:51:52 2022 -0700
+
+    Call ->next() directly
+
+ src/hb-ot-layout-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 03d64b7469d12d10b498fbf942afb7b87810012f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 14:33:18 2022 -0700
+
+    [bit-set] Remove TODO that would never happen
+
+ src/hb-bit-set.hh | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit 690df8a36955390cfd7251a50a2629e64b52bb82
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 14:32:51 2022 -0700
+
+    [bit-set] Micro-optimize prev()
+
+ src/hb-bit-set.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit fe5d9176aed02c0d3388d5a5cf3881e6437db71f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 14:30:18 2022 -0700
+
+    [bit-set] Micro-optimize size
+    
+    It's silly that this saves size at all. :(
+
+ src/hb-bit-set.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit cf9b9929df088570c18ea8b55e61ba7f31374532
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 14:26:28 2022 -0700
+
+    [bit-set] Micro-optimize process()
+
+ src/hb-bit-set.hh | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+commit d77903db7b165dbb6327141e1949984a09756de7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 14:22:32 2022 -0700
+
+    [bit-set] Micro-optimize
+
+ src/hb-bit-set.hh | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+commit 13dd4b464b7bf7bfaff790d242b6baeec2edffa9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 14:20:42 2022 -0700
+
+    [bit-set] Micro-optimize access
+
+ src/hb-bit-set.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit a3afa61ce8d01784d88de4af3647ebd5b3e71fe6
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Nov 23 22:24:39 2022 +0000
+
+    [subset] use cached parsed char strings if available.
+
+ src/hb-subset-cff-common.hh | 67 ++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 51 insertions(+), 16 deletions(-)
+
+commit 47c125845caf1c24f538679ffdc32c04b2f0920b
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Nov 23 21:02:39 2022 +0000
+
+    [subset] Cache parsed charstrings in the cff accelerator.
+
+ src/hb-subset-cff-common.hh | 36 ++++++++++++++++++++++++++++++++----
+ 1 file changed, 32 insertions(+), 4 deletions(-)
+
+commit 48b68370743264f900457e4b463e9ced5325ceae
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Nov 23 20:51:51 2022 +0000
+
+    [subset] add a CFF specific accelerator object.
+    
+    This allows CFF specific accelerator structures to be isolated to the CFF code.
+
+ src/hb-subset-accelerator.hh | 12 +++++++++++-
+ src/hb-subset-cff-common.hh  | 22 ++++++++++++++++++++++
+ 2 files changed, 33 insertions(+), 1 deletion(-)
+
+commit d77f346d1a822c7209192f55218fe707e6295183
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 14:02:46 2022 -0700
+
+    [subset-cff] Minor rename
+
+ src/hb-subset-cff-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 29a0fa089a6c0bf390a02ddaa1757d8894c1a0a7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 14:00:59 2022 -0700
+
+    [subset-cff] Micro-optimize
+
+ src/hb-subset-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d480ae1fac8c2d32fb9df851629b877248331416
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 13:53:43 2022 -0700
+
+    [cff] Remove unused function
+
+ src/hb-cff-interp-common.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 73046d53e5e769ec8c4eff2a1b8306bb15ce0cce
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 13:49:29 2022 -0700
+
+    [shaper] Disable dumber shaper if no AAT
+
+ src/hb-ot-shape.cc          | 2 ++
+ src/hb-ot-shaper-default.cc | 2 ++
+ 2 files changed, 4 insertions(+)
+
+commit e9f964c01a4d1273f5632d34f8f3827608cab735
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 13:38:53 2022 -0700
+
+    [ot-face] Declare more tables as core
+
+ src/hb-machinery.hh          |  2 +-
+ src/hb-ot-face-table-list.hh | 28 ++++++++++++++--------------
+ 2 files changed, 15 insertions(+), 15 deletions(-)
+
+commit 5bc27a128dc5fb6ec65591c0f0632973ce9e8116
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 13:30:12 2022 -0700
+
+    [machinery] Comment
+
+ src/hb-machinery.hh | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+commit d21bfb08615f44ffd60737295b45da5e1a5fca7e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 13:14:05 2022 -0700
+
+    [normalize] Remove an unlikely
+    
+    Keep unlikely for truely unlikely scenarios.
+
+ src/hb-ot-shape-normalize.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9e1239f443bce69200d7203cd3a89b921a382531
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 13:00:47 2022 -0700
+
+    [config] Define HB_NO_VERTICAL in HB_LEAN and as such in HB_TINY
+
+ src/hb-config.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 6f133ccfde9c96ab6de8e18ddbbac4b7509eed0c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 12:59:55 2022 -0700
+
+    [glyf] Fix build with HB_NO_VERTICAL
+
+ src/OT/glyf/Glyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 76420ef769e828db3633578e814409c4ddc7b938
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 12:52:15 2022 -0700
+
+    [machine.rl] Remove unlikely from what happens 1/16 of the time
+
+ src/hb-ot-shaper-indic-machine.hh   | 16 ++++++++--------
+ src/hb-ot-shaper-indic-machine.rl   |  2 +-
+ src/hb-ot-shaper-khmer-machine.hh   | 16 ++++++++--------
+ src/hb-ot-shaper-khmer-machine.rl   |  2 +-
+ src/hb-ot-shaper-myanmar-machine.hh | 16 ++++++++--------
+ src/hb-ot-shaper-myanmar-machine.rl |  2 +-
+ src/hb-ot-shaper-use-machine.hh     | 16 ++++++++--------
+ src/hb-ot-shaper-use-machine.rl     |  2 +-
+ 8 files changed, 36 insertions(+), 36 deletions(-)
+
+commit 1248574454facabe15a96d7670243c7959f4a065
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 12:46:04 2022 -0700
+
+    [config] Disable Zawgyi shaper in HB_MINI/HB_TINY
+
+ src/hb-config.hh            | 1 +
+ src/hb-ot-shaper-myanmar.cc | 2 ++
+ src/hb-ot-shaper.hh         | 2 ++
+ 3 files changed, 5 insertions(+)
+
+commit 05aa084e67705285941c9acd13151e2a38da8b0f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 12:13:31 2022 -0700
+
+    [PairPos] Another attempt at fixing unsafe-to-break with ValueFormat2
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116
+    
+    Test:
+    $ hb-shape XBRoya34.ttf  ' الأ' --show-flags --script=arab
+
+ src/OT/Layout/GPOS/PairPosFormat2.hh | 9 +++++----
+ src/OT/Layout/GPOS/PairSet.hh        | 5 +++--
+ 2 files changed, 8 insertions(+), 6 deletions(-)
+
+commit 54ae3345b225151d9f77189f1dec071c1f075ce9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 11:59:50 2022 -0700
+
+    [buffer] Improve documentation of hb_buffer_add_codepoints()
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3889
+
+ src/hb-buffer.cc | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit a4a40786326cef97fe25eee2232852c9173347e7
+Merge: 0c70bc7f3 64e8707ec
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 11:56:58 2022 -0700
+
+    Merge pull request #3893 from googlefonts/preprocess_test
+    
+    [subset] Fix testing of preprocess
+
+commit 0c70bc7f3286ea0c04164f110a6d2caac805812c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 24 11:48:48 2022 -0700
+
+    [skippy-iter] Fix two logic errors
+    
+    First, a signed underflow.
+    
+    Second, a wrong condition.
+    
+    Both were introduced in 42681bdb55a75520d4ac194302fe936d1ce3cb34
+
+ src/hb-ot-layout-gsubgpos.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 64e8707ecac726a4e78772875d069db3f5c0ad6a
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Nov 24 18:24:50 2022 +0000
+
+    [subset] don't use hb repacker when generating test files from fonttools.
+
+ ...astaliqUrdu-Regular.default.627,644,62D,628.ttf | Bin 24564 -> 24532 bytes
+ .../NotoNastaliqUrdu-Regular.default.633,6D2.ttf   | Bin 14296 -> 14292 bytes
+ ...otoNastaliqUrdu-Regular.default.63A,64A,631.ttf | Bin 26152 -> 26124 bytes
+ ...iqUrdu-Regular.default.retain-all-codepoint.ttf | Bin 542388 -> 542328 bytes
+ ...liqUrdu-Regular.retain-gids.627,644,62D,628.ttf | Bin 30464 -> 30432 bytes
+ ...otoNastaliqUrdu-Regular.retain-gids.633,6D2.ttf | Bin 20140 -> 20132 bytes
+ ...astaliqUrdu-Regular.retain-gids.63A,64A,631.ttf | Bin 32012 -> 31984 bytes
+ ...du-Regular.retain-gids.retain-all-codepoint.ttf | Bin 542424 -> 542360 bytes
+ test/subset/generate-expected-outputs.py           |   2 ++
+ 9 files changed, 2 insertions(+)
+
+commit 3b43096ef336cf3ba149518c82541c0079ef0f92
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 23 22:04:02 2022 -0700
+
+    [buffer] Whitespace
+
+ src/hb-buffer.cc | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 094f80738a57a99a9f541f55bbf8aa796235756c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 23 22:03:26 2022 -0700
+
+    [buffer] Handle null buffer in set_message_func
+
+ src/hb-buffer.cc | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+commit 1fa64c0c23ed86d60117198420587aee81fdc8d8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 23 21:38:51 2022 -0700
+
+    [gsubgpos] Conditionalize skippy on unsafe-to-concat
+
+ src/hb-ot-layout-gsubgpos.hh | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+commit 42681bdb55a75520d4ac194302fe936d1ce3cb34
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 23 21:36:43 2022 -0700
+
+    [gsubgpos] No logic-change minor rewrite
+
+ src/hb-ot-layout-gsubgpos.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit c15efdec496aae23f9e15d08b69d61f77bf6dee0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 23 21:14:28 2022 -0700
+
+    [gsubgpos] Comment
+
+ src/hb-ot-layout-gsubgpos.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 7ec1c41a55729808d61cb85fb2d632e0b488f53f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 23 21:12:41 2022 -0700
+
+    [gsubgpos] Skippy-iter: Prefer correctness to performance
+    
+    Prefer unsafe-to-concat correctness, over performance.
+
+ src/hb-ot-layout-gsubgpos.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit b6df3471379bfe66e9360cf1d6625c705e179018
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 23 20:15:16 2022 -0700
+
+    [perf] Add Hindi test to benchmark-shape
+
+ perf/benchmark-shape.cc |     4 +
+ perf/texts/hi-words.txt | 10000 ++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 10004 insertions(+)
+
+commit dce3502e10af6f52bffad94c2f772b3cae12fd5e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 23 18:34:54 2022 -0700
+
+    [array] Add commented-out static asserts
+    
+    They don't work.
+
+ src/hb-array.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit a7fee43cefce95097ba46591090395a3c882741c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 23 17:46:32 2022 -0700
+
+    [priority-queue] Minor micro-optimize
+
+ src/hb-priority-queue.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ff3cac0ccd0633a7715945e4c9f1e7243f75d1cb
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Nov 23 23:50:49 2022 +0000
+
+    [subset] Fix unecessary trailing 0 bytes left by ContextFormat2 pruning.
+    
+    Uneeded rules where beind removed from the count by the bytes for them was being left in the font.
+
+ src/hb-ot-layout-gsubgpos.hh                        |   6 +++++-
+ ...subrules_f1.layout-test-retain-gids.41,42,43.otf | Bin 2152 -> 2148 bytes
+ ...le_subrules_f1.layout-test-retain-gids.41,42.otf | Bin 2028 -> 2024 bytes
+ ...layout-test-retain-gids.retain-all-codepoint.otf | Bin 4012 -> 4008 bytes
+ ...t2_multiple_subrules_f1.layout-test.41,42,43.otf | Bin 1440 -> 1436 bytes
+ ...text2_multiple_subrules_f1.layout-test.41,42.otf | Bin 1320 -> 1316 bytes
+ ...subrules_f1.layout-test.retain-all-codepoint.otf | Bin 4012 -> 4008 bytes
+ ...landhar-Regular.default.retain-all-codepoint.ttf | Bin 49248 -> 49244 bytes
+ ...dhar-Regular.drop-hints.retain-all-codepoint.ttf | Bin 29468 -> 29464 bytes
+ ...ndhar-Regular.keep-gdef.retain-all-codepoint.ttf | Bin 49248 -> 49244 bytes
+ ...subrules_f2.layout-test-retain-gids.41,42,43.otf | Bin 2256 -> 2252 bytes
+ ...le_subrules_f2.layout-test-retain-gids.41,42.otf | Bin 2224 -> 2220 bytes
+ ...layout-test-retain-gids.retain-all-codepoint.otf | Bin 4008 -> 4004 bytes
+ ...t2_multiple_subrules_f2.layout-test.41,42,43.otf | Bin 1460 -> 1456 bytes
+ ...text2_multiple_subrules_f2.layout-test.41,42.otf | Bin 1416 -> 1412 bytes
+ ...subrules_f2.layout-test.retain-all-codepoint.otf | Bin 4008 -> 4004 bytes
+ 16 files changed, 5 insertions(+), 1 deletion(-)
+
+commit f2851e4157e302d9932ef0582da6c36cade4f085
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 23 16:50:30 2022 -0700
+
+    [test-map] Test has() getter with unique-ptr
+
+ src/test-map.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 5f3a780614ee76347fd0692439fe37a7fc02602e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 23 16:45:46 2022 -0700
+
+    [font] Protect against div-by-zero
+
+ src/hb-font.cc | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 060ecac949dca29a75538ddeedf015441296334b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 23 16:31:37 2022 -0700
+
+    [font] Respect subfont slant setting in hb-draw
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3890
+
+ src/hb-font.cc | 34 ++++++++++++++++++++--------------
+ 1 file changed, 20 insertions(+), 14 deletions(-)
+
+commit 2e9b270a496de14d3eee9d8b7e1372293bf13888
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 23 16:17:50 2022 -0700
+
+    [hb-view] Fix cairo slanting condition
+    
+    hb-draw already does slanting. If NOT hb-draw, we should slant
+    through cairo path.  Donno why this was untested before.
+    
+    This was double-slanting with hb-draw, and not slanting without it.
+
+ util/helper-cairo.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 51028e63e68b2e06f969da9e4e727d5c2f912bf4
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Nov 23 22:51:16 2022 +0000
+
+    [subset] Retain all glyphs in preprocessed face.
+
+ src/hb-subset-input.cc | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 404cb99d86c2d639b4ce2fc59f00f5e66468af34
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 23 15:35:14 2022 -0700
+
+    [buffer-diff] Fix check for glyph flag equality
+    
+    I'm not sure if the old behavior was intentional, but it was checking
+    that the glyph flags were a subset of the reference buffer's glyph
+    flags.  I don't see why that is useful.  Fix that.
+    
+    Then make the buffer-verify code ignore flag differences when verifying
+    buffers, since our unsafe-to-concat flag at least, is conservative and
+    not guaranteed to be produced the same in fragments.  See:
+    
+    https://github.com/harfbuzz/harfbuzz/issues/3888
+
+ src/hb-buffer-verify.cc | 5 ++---
+ src/hb-buffer.cc        | 2 +-
+ 2 files changed, 3 insertions(+), 4 deletions(-)
+
+commit 4c49daf7cd961fb47126baf04240243736cae606
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Nov 23 22:33:57 2022 +0000
+
+    [subset] actually use the preprocessed face in hb-subset.
+    
+    Tests weren't actually using the preprocessed face due to this typo in util/hb-subset.
+
+ src/hb-subset-input.cc | 5 +++++
+ util/hb-subset.cc      | 2 +-
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+commit 2c0afde7370a27d1aa26983751a422f61924580c
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Nov 23 20:24:40 2022 +0000
+
+    [subset] add an inprogress accelerator to plan.
+    
+    This allows subset code to cache information into the accelerator during preprocess subset. Previously the accelerator was created at the end of subsetting.
+
+ src/hb-subset-plan.cc | 11 +++++++++++
+ src/hb-subset-plan.hh |  4 ++++
+ src/hb-subset.cc      | 11 ++++++-----
+ 3 files changed, 21 insertions(+), 5 deletions(-)
+
+commit 81640fdffe5a57191b392eda2d93fcf39183dbcf
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Nov 23 20:22:36 2022 +0000
+
+    [subset] fix leaked font in glyf::subset(...)
+
+ src/OT/glyf/glyf.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit dcce53ddcb52d10dca1ff1d3e118297175892c26
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 23 13:19:38 2022 -0700
+
+    [cff] Micro-optimize fetch_op
+
+ src/hb-cff-interp-common.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 0bf7d9eb4dd1b706a139e56638d2e8db0ccab933
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 23 13:00:23 2022 -0700
+
+    [subset-cff] Micro-optimize encode_byte
+
+ src/hb-subset-cff-common.hh | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit a23f820427a7ae7be5b24d66265bd46fb0d4d6df
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 23 12:56:13 2022 -0700
+
+    [subset-cff] Micro-optimize array access
+
+ src/hb-subset-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1e8f1ac6774226a12cb6d9794f300a103a590ea4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 23 12:28:29 2022 -0700
+
+    [subset-glyf] Micro-optimize array access
+
+ src/OT/glyf/SimpleGlyph.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 356d135ed698042f6337486e5c8cb2fe6206c44a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 23 12:20:51 2022 -0700
+
+    [subset-glyf] Reduce roundf calls
+    
+    Saves 7% on MPLUS1-Variable/6000 benchmark.
+
+ src/OT/glyf/Glyph.hh | 30 +++++++++++++++---------------
+ 1 file changed, 15 insertions(+), 15 deletions(-)
+
+commit 463ae07e9982e337b9340cb24598db57d008e33c
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Nov 23 18:41:23 2022 +0000
+
+    [subset] In the preprocess subset call always use long loca.
+    
+    Long loca is needed so that we can store the trimmed glyph bytes to allow us to safely skip trimming in the later subset.
+
+ src/OT/glyf/glyf.hh    | 9 ++++++---
+ src/hb-subset-input.cc | 5 +++++
+ src/hb-subset-input.hh | 4 ++++
+ src/hb-subset-plan.cc  | 1 +
+ src/hb-subset-plan.hh  | 1 +
+ 5 files changed, 17 insertions(+), 3 deletions(-)
+
+commit 299ec902eb3f657b71517ac1cd1f477ceec6b409
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 16:03:02 2022 -0700
+
+    [glyf] Move instanciation to serialize()
+
+ src/OT/glyf/SubsetGlyph.hh | 10 +++++++++-
+ src/OT/glyf/glyf.hh        | 46 ++++++++++++++--------------------------------
+ 2 files changed, 23 insertions(+), 33 deletions(-)
+
+commit d8d881f22d634573afd4860415e9dda29ce44492
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 15:24:16 2022 -0700
+
+    [subset-glyf] Don't create a second glyf accelerator
+
+ src/OT/glyf/glyf.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 75609300707fedc45d7a2bc6d9b62793ad212aa4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 15:22:25 2022 -0700
+
+    [glyf] Add _create_font_for_instancing
+
+ src/OT/glyf/glyf.hh | 24 ++++++++++++++++++------
+ 1 file changed, 18 insertions(+), 6 deletions(-)
+
+commit 40634ceeb0bf1bdb6c2b12e90ecac9e45c2e4671
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 15:07:16 2022 -0700
+
+    [glyf] Adjust data types
+
+ src/OT/glyf/SimpleGlyph.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit ba0d28ea3647fe5d8108ba4f2ca60be7f267c043
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 15:01:48 2022 -0700
+
+    [glyf] Fix font error check
+
+ src/OT/glyf/glyf.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 04c525019c84e4683e99674624e199c0598e38e2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 14:54:55 2022 -0700
+
+    [glyf] Use a malloc instead of calloc
+
+ src/OT/glyf/SimpleGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 024aa818051712a5ea14e8d1ad7603a5ab9ca4ef
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 14:51:42 2022 -0700
+
+    [glyf] Micro-optimize encode_coord
+
+ src/OT/glyf/SimpleGlyph.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit b6694597f9b80d37fd8361723ae34861019a46ba
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 14:49:01 2022 -0700
+
+    [glyf] Micro-optimize encode_flag()
+
+ src/OT/glyf/SimpleGlyph.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit d47cfe79364391bd10ceb8588f4cdb55ff6e47e8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 14:45:04 2022 -0700
+
+    [glyf] Minor use operator ++
+
+ src/OT/glyf/SimpleGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 03e6bde79035a5d3e25c9a571fab8b1d916c069c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 14:40:36 2022 -0700
+
+    [glyf] Minor adjustment to lastflag handling
+    
+    No logic change.
+
+ src/OT/glyf/SimpleGlyph.hh | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+commit 0ca9fda889a97febac66bcc86bda9211628bd7ba
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 14:39:10 2022 -0700
+
+    [glyf] Remove misplaced comment
+
+ src/OT/glyf/SimpleGlyph.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 44be8ef4ce883f6ce9680f6f489d37722711fa8e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 14:21:25 2022 -0700
+
+    [gvar] Skip degenerate all-untouched delta-sets
+
+ src/hb-ot-var-gvar-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 656bb223f17343d68dcd6118d6afdb85b7298345
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 14:16:40 2022 -0700
+
+    [gvar] Micro-optimize unpack_points
+
+ src/hb-ot-var-gvar-table.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit a383027262d5d073da29e4bc45ef2b99c734a1de
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 14:15:17 2022 -0700
+
+    [gvar] Cosmetic
+
+ src/hb-ot-var-gvar-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit be89919a7097d6ba1fa4e3042627d13fac545e53
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 13:56:20 2022 -0700
+
+    [gvar] is_valid() remove a check
+    
+    I don't know why this check was there, but it doesn't make sense
+    because that function never returns 0 / false.
+
+ src/hb-ot-var-gvar-table.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit e8ddf107d0f3ecd66db901c748028bf642210ae8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 13:29:32 2022 -0700
+
+    [gvar] Optimize a loop
+
+ src/hb-ot-var-gvar-table.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit dd6fcec92ccc609435312dd42b9ae3c98c88af40
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 13:27:40 2022 -0700
+
+    [gvar] Remove a conditional
+
+ src/hb-ot-var-gvar-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a02317238af994b15f280b33d20a0eb8e75ae711
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 13:24:39 2022 -0700
+
+    [gvar] Refactor deltas array access
+
+ src/hb-ot-var-gvar-table.hh | 18 ++++++++++--------
+ 1 file changed, 10 insertions(+), 8 deletions(-)
+
+commit c34c77698c473cdaa85a703a75db85ee5f328d7f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 13:21:01 2022 -0700
+
+    [gvar] Don't try IUP if all points are specified
+
+ src/hb-ot-var-gvar-table.hh | 84 ++++++++++++++++++++++++---------------------
+ 1 file changed, 45 insertions(+), 39 deletions(-)
+
+commit 27c4037e5988d41b92c7c3904d4ceeea8c31586c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 13:12:22 2022 -0700
+
+    [gvar] Micro-optimize boundary-checking
+
+ src/hb-ot-var-gvar-table.hh | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+commit ab8346fb6fee2fd64204cc880c5f75f3b1b33ff9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 13:07:39 2022 -0700
+
+    [gvar] Add an unlikely
+
+ src/hb-ot-var-gvar-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1e8a342ea2769f368be6dbf0bf6b0aaf99af1db7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 13:02:38 2022 -0700
+
+    [gvar] Micro-optimize int types
+
+ src/hb-ot-var-gvar-table.hh | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+commit 4afcdf675ba9b134a92659090aa4bf0b7a39d5f7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 12:56:48 2022 -0700
+
+    More hb_memcpy
+
+ src/OT/glyf/CompositeGlyph.hh | 16 ++++++++--------
+ src/OT/glyf/SimpleGlyph.hh    | 10 +++++-----
+ src/graph/gsubgpos-graph.hh   |  2 +-
+ src/graph/pairpos-graph.hh    |  2 +-
+ src/graph/serialize.hh        |  2 +-
+ 5 files changed, 16 insertions(+), 16 deletions(-)
+
+commit 58a696d80ed3158c88e8e95345642cbd4db75eaa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 12:56:05 2022 -0700
+
+    More hb_memset
+
+ src/OT/Layout/Common/Coverage.hh  | 2 +-
+ src/hb-buffer-deserialize-json.rl | 4 ++--
+ src/hb-buffer-deserialize-text.rl | 4 ++--
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+commit 59c45f6debd8e266286ba7b34314a3b625d8a307
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 12:54:50 2022 -0700
+
+    Use hb_memcpy instead of memcpy consistently
+
+ src/hb-aat-layout-morx-table.hh |  8 ++++----
+ src/hb-blob.cc                  |  2 +-
+ src/hb-buffer-serialize.cc      |  8 ++++----
+ src/hb-buffer.cc                |  6 +++---
+ src/hb-cff-interp-common.hh     |  2 +-
+ src/hb-common.cc                |  8 ++++----
+ src/hb-font.cc                  | 10 +++++-----
+ src/hb-open-file.hh             |  2 +-
+ src/hb-ot-cff-common.hh         |  6 +++---
+ src/hb-ot-cff1-table.hh         |  4 ++--
+ src/hb-ot-cff2-table.hh         |  4 ++--
+ src/hb-ot-color-cbdt-table.hh   |  2 +-
+ src/hb-ot-layout-common.hh      |  2 +-
+ src/hb-ot-math-table.hh         |  4 ++--
+ src/hb-ot-name-table.hh         |  2 +-
+ src/hb-ot-post-table.hh         |  2 +-
+ src/hb-ot-stat-table.hh         |  2 +-
+ src/hb-ot-tag.cc                |  2 +-
+ src/hb-ot-var-common.hh         |  2 +-
+ src/hb-ot-var-gvar-table.hh     |  4 ++--
+ src/hb-serialize.hh             |  8 ++++----
+ src/hb-shape-plan.cc            |  2 +-
+ src/hb-shaper.cc                |  2 +-
+ src/hb-subset-cff-common.hh     |  4 ++--
+ src/hb-uniscribe.cc             |  4 ++--
+ src/test-repacker.cc            |  2 +-
+ 26 files changed, 52 insertions(+), 52 deletions(-)
+
+commit ac0efaf8181636fdecbffa79c629547e072f5287
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 12:50:36 2022 -0700
+
+    Use hb_memset instead of memset consistently
+
+ src/hb-aat-map.hh                 |  2 +-
+ src/hb-bit-page.hh                |  6 +++---
+ src/hb-buffer-deserialize-json.hh |  4 ++--
+ src/hb-buffer-deserialize-text.hh | 28 ++++++++++++++--------------
+ src/hb-buffer.cc                  | 12 ++++++------
+ src/hb-common.cc                  |  4 ++--
+ src/hb-font.cc                    |  6 +++---
+ src/hb-font.hh                    |  6 +++---
+ src/hb-graphite2.cc               |  2 +-
+ src/hb-ot-map.cc                  |  2 +-
+ src/hb-ot-map.hh                  |  2 +-
+ src/hb-pool.hh                    |  2 +-
+ src/hb-uniscribe.cc               |  2 +-
+ 13 files changed, 39 insertions(+), 39 deletions(-)
+
+commit 44a892a233e0441a0bac84a680aebf2362f2c227
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 12:48:52 2022 -0700
+
+    [shape] Use hb_memcmp instead of memcmp
+
+ src/hb-ot-shape.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c53c64812724762b91ff397c56f6701d42d000b5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 12:46:25 2022 -0700
+
+    [subset-cff] Another handrolled memcpy
+
+ src/hb-subset-cff-common.hh | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+commit ae578705c2ac7f8d520ff5f6646c2efe57469902
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 12:23:17 2022 -0700
+
+    [array] Write hash as range for loop again
+    
+    Now that our range loop is faster than our own iter.
+
+ src/hb-array.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 13e1ca9eb520d7a5ca1092d2bf8566669d8b5580
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 12:19:28 2022 -0700
+
+    [cff] Micro-optimize memcpy
+
+ src/hb-cff-interp-common.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 2968dd7844c71734e0e052bb1a9eb7875e214961
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 11:57:29 2022 -0700
+
+    [gvar] Optimize as_array() access
+
+ src/hb-ot-var-gvar-table.hh | 16 +++++++++-------
+ 1 file changed, 9 insertions(+), 7 deletions(-)
+
+commit bb3bb76450c575321aecf33b74e5b51d0c5c75e3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 11:53:35 2022 -0700
+
+    [gvar] Optimize scalar = 1.0 case
+
+ src/hb-ot-var-gvar-table.hh | 26 ++++++++++++++++++--------
+ 1 file changed, 18 insertions(+), 8 deletions(-)
+
+commit 2d098d5d7f223d587abe4e8926a911cfbb5eef62
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 11:51:04 2022 -0700
+
+    [gvar] Use memset
+
+ src/hb-ot-var-gvar-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit e630a65e604ea4d1fc4fb4818c456c3d450fede4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 11:27:05 2022 -0700
+
+    [gvar] Micro-optize vector extend
+
+ src/hb-ot-var-gvar-table.hh | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+commit 49d4f62135f34983ea1e47828f6f549d4f581f9a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 11:14:56 2022 -0700
+
+    [gvar] Micro-optimize
+
+ src/hb-ot-var-gvar-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 1758ee6646f69f80bbcd79d93fc4992aeaf6c2bc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 10:45:49 2022 -0700
+
+    [glyf] Minor write loop more idiomatically
+
+ src/OT/glyf/SimpleGlyph.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 16ec9dcc1bb7f4e710d4c4b83f3900dc15b29c3b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 10:43:46 2022 -0700
+
+    [gvar] Whitespace
+
+ src/hb-ot-var-gvar-table.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit b567ce51d3724c6dc89cce72257dd5baf245fc9a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 20:08:54 2022 -0700
+
+    [subset] Don't trim glyf's again if preprocessed
+    
+    Speeds up M1/10000 benchmark by 30%!
+
+ src/OT/glyf/glyf.hh | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit 72059a47891d2ecf875dcf36836a2cabe599502a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 10:41:37 2022 -0700
+
+    [gvar] Optimize IUP alg
+
+ src/hb-ot-var-gvar-table.hh | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+commit ee9873b5ede5ee14a542dd1d4bc470695487c5f4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 10:23:17 2022 -0700
+
+    [gvar] Disable initializing vectors when not necessary
+
+ src/hb-ot-var-gvar-table.hh | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+commit b0d2641186e269da1f1556bf7d1c8b8c7763ccb3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 10:20:11 2022 -0700
+
+    [vector] Add "initialize" argument to resize()
+
+ src/hb-vector.hh | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+commit a2059f8f55ebbc8cbc6adf7df0d1886ee130f2dd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 10:16:21 2022 -0700
+
+    [gvar] Optimize unpack_points
+
+ src/hb-ot-var-gvar-table.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 6d7206b68bbb4cd99f2a53ff8ac61114d272a958
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 22 10:13:14 2022 -0700
+
+    [gvar] Optimize unpack_deltas
+
+ src/hb-ot-var-gvar-table.hh | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+commit bca569ae535e4fb7a38f9ec9514e667fc15a29d2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 23:19:42 2022 -0700
+
+    [array] Speed up hash() for byte arrays
+
+ src/hb-array.hh | 32 ++++++++++++++++++++++++++++----
+ 1 file changed, 28 insertions(+), 4 deletions(-)
+
+commit d7b492e3f589f8ba0d034a818a83a1d14a86b443
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 23:08:51 2022 -0700
+
+    Revert "[array] Remove hash specializations for bytes"
+    
+    This reverts commit 213117317cefeb4e75d21c5c21e383309f116bb0.
+
+ src/hb-array.hh | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+commit 1572ba281acb7fb3510d97e0f52bea83a1d6050d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 22:26:44 2022 -0700
+
+    [subset-cff] Return in subr closure if already seen subr
+    
+    Not sure why this was not done before.
+
+ src/hb-subset-cff-common.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit a29ca6efbc7ee4a7832fdf66bdda07654e28496a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 22:02:17 2022 -0700
+
+    [subset-cff] Comment
+
+ src/hb-subset-cff-common.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 28e767ddea3acea744fad3f8e44f1f8f3b4d198d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 21:59:51 2022 -0700
+
+    [subset-cff] Really optimize op_str_t / parsed_cs_op_t layout
+    
+    Now parsed_cs_op_t and op_str_t are both 16 bytes.
+    
+    Saves another 7% in SourceHanSans/10000 benchmark.
+
+ src/hb-cff-interp-common.hh | 9 ++++++---
+ src/hb-subset-cff-common.hh | 5 +++--
+ 2 files changed, 9 insertions(+), 5 deletions(-)
+
+commit 2d5ee23731ecbd779a36142cd32f8d50eae88ff2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 21:37:38 2022 -0700
+
+    [subset-cff] Readjust parsed_cs_op_t
+    
+    Now it doesn't matter anymore since op_str_t is adjusted and
+    is 16 bytes with 8byte alignment.
+
+ src/hb-subset-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4f056b923a99236b70d52236a4e3c293242c3216
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 21:37:38 2022 -0700
+
+    [subset-cff] Optimize op_str_t layout
+
+ src/hb-cff-interp-common.hh | 18 +++++++++++++-----
+ src/hb-subset-cff-common.hh | 20 ++++++++++----------
+ src/hb-subset-cff1.cc       |  5 +++--
+ 3 files changed, 26 insertions(+), 17 deletions(-)
+
+commit a750cb012855558e137c8eb483af1c94ea7d3e00
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 21:03:32 2022 -0700
+
+    Simplify rvalue creation
+
+ src/hb-subset-plan.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 86a763c651090094f35f1995cba7a923aaa9e0d3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 20:53:44 2022 -0700
+
+    [map] Make keys moveable
+
+ src/hb-map.hh   | 10 ++++++----
+ src/test-map.cc |  6 ++----
+ 2 files changed, 8 insertions(+), 8 deletions(-)
+
+commit cf20d2ec5d609a5a9319b5b1f6cdf5616d41d13d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 20:46:01 2022 -0700
+
+    [map] Take const key
+
+ src/hb-map.hh         | 10 +++++-----
+ src/hb-subset-plan.hh |  6 +++---
+ src/test-map.cc       |  2 +-
+ 3 files changed, 9 insertions(+), 9 deletions(-)
+
+commit 3d1c76f713844f192aa11af956e9ee84f097b071
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 19:40:32 2022 -0700
+
+    [serializer] Don't hash objects twice
+
+ src/hb-map.hh       | 78 ++++++++++++++++++++++++++---------------------------
+ src/hb-serialize.hh |  6 +++--
+ src/test-map.cc     |  2 +-
+ 3 files changed, 43 insertions(+), 43 deletions(-)
+
+commit 35878df2155f38e981acde5888141bb61bd9ab63
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 19:14:03 2022 -0700
+
+    [algs] Implement swap() for pair_t
+    
+    Helps priority_queue::pop_minimum and friends, which help subsetter
+    repacker. Shows a few percentage improvement on NotoNastaliq benchmark.
+
+ src/hb-algs.hh | 29 ++++++++++++++++++-----------
+ 1 file changed, 18 insertions(+), 11 deletions(-)
+
+commit a2984a2932c94312d75dfc64485c8afaa97a34b0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 18:40:01 2022 -0700
+
+    [cff] Remove unnecessary namespacing
+
+ src/hb-ot-cff-common.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit dc3bb5e0ed4f44e3a11474656ecf2cd8b7d86a68
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 18:18:48 2022 -0700
+
+    [subset-cff] Pre-allocate values array for subroutines as well
+
+ src/hb-cff-interp-common.hh | 2 ++
+ src/hb-subset-cff-common.hh | 4 ++++
+ 2 files changed, 6 insertions(+)
+
+commit c6279224dbe5b2b8d3895cd91429178fc408e23a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 18:01:50 2022 -0700
+
+    [cff] Adjust pre-allocation
+    
+    This better matches actual usage, given that ops are one or two
+    bytes, and vector also allocates 50% extra.
+
+ src/hb-subset-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit bab8ec58b044272d45d584e8f16c6715ca21ee89
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 17:46:32 2022 -0700
+
+    [subset-cff] Disable sharing when packing charstring INDEXes
+    
+    Saves another 8%ish.
+
+ src/hb-subset-cff1.cc | 6 +++---
+ src/hb-subset-cff2.cc | 4 ++--
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+commit 2cadacad6c1da254fc778db3300aa6c53d0de420
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 17:17:15 2022 -0700
+
+    [cff] Simplify str_encoder_t error handling
+
+ src/hb-subset-cff-common.hh | 16 ++++------------
+ 1 file changed, 4 insertions(+), 12 deletions(-)
+
+commit f263e3fe2e11810a517925d580640a21402ae36b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 17:04:55 2022 -0700
+
+    [cff] Manually copy short strings instead of memcpy()
+
+ src/hb-subset-cff-common.hh | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit 38efd1862fd42e8323aa93da9c6f9685ea4919fc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 17:02:11 2022 -0700
+
+    [cff] Add a likely()
+
+ src/hb-subset-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 191025cc96b2f72dd893619b7d296001609c168d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 16:58:19 2022 -0700
+
+    [cff] Adjust buffer pre-allocation
+    
+    Most ops take one or two bytes, so allocate count*2, not count*3.
+    Shows minor speedup in subsetting benchmark (around 2%).
+
+ src/hb-subset-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4b2caafea2cd2902b866a94c965f20d1caabad5e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 16:46:20 2022 -0700
+
+    [subset-cff] Optimize parsed_cs_op_t size
+    
+    Shows 5% speedup on SourceHanSans-Regular/10000 benchmark.
+
+ src/hb-subset-cff-common.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit e0b06bd1b1daaac4d8e020db9ac3ec1fcaad38b6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 16:09:39 2022 -0700
+
+    [subset] Cache has_seac in accelerator
+    
+    Speeds up SourceHanSans-Regular/10000 benchmark by %25.
+
+ src/hb-subset-accelerator.hh |  5 ++++-
+ src/hb-subset-plan.cc        | 16 ++++++++++++----
+ src/hb-subset-plan.hh        |  1 +
+ src/hb-subset.cc             |  3 ++-
+ 4 files changed, 19 insertions(+), 6 deletions(-)
+
+commit dd1ba328a8d49ff43633eda43013fd5dd1fe2ada
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Nov 21 23:20:59 2022 +0000
+
+    [repacker] fix fuzzer timeout.
+    
+    For https://oss-fuzz.com/testcase-detail/5845846876356608. Only process the set of unique overflows.
+
+ src/graph/serialize.hh                             |  21 +++++++++++++++++++++
+ ...ase-minimized-hb-subset-fuzzer-5845846876356608 | Bin 0 -> 427854 bytes
+ 2 files changed, 21 insertions(+)
+
+commit 59451502e99ff0dd73361a53fc576cb8b0057d75
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 15:23:16 2022 -0700
+
+    [cff] Optimize env error checking
+
+ src/hb-cff-interp-common.hh | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+commit b238578a9c9255282b7634bcbf751f03001ceda6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 14:36:57 2022 -0700
+
+    [cff] Optimize INDEX operator[]
+
+ src/hb-ot-cff-common.hh | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+commit d9de515a382c169f50a56fc7292aa96f62366ce8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 14:23:07 2022 -0700
+
+    [cff] Optimize byte_str_ref_t array access
+
+ src/hb-cff-interp-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a81ec9b2b6734e66c0d532ae4da1b6788dd59f0c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 14:03:28 2022 -0700
+
+    [cff] Optimize byte_str_ref_t inc()
+    
+    Shows a couple percent speedup.
+
+ src/hb-cff-interp-common.hh | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+commit 3ff75411bdc29094c4664f834703dc5c4cf117c7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 13:08:55 2022 -0700
+
+    [algs] Fix bot fail
+
+ src/hb-algs.hh           | 2 +-
+ src/hb-ot-shaper-thai.cc | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit b81e3989f83da88e387e04b54bdb85d1f26ed5e4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 13:02:40 2022 -0700
+
+    Try fixing arm-eabi build after a10cfe3f32861c13578dc21476b2fe4d2e0af43c
+
+ src/hb-ot-shaper-thai.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4c14043b06cb28cef5a8a6ebfc39a0c83902d423
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 12:56:33 2022 -0700
+
+    [algs] Add output argument to hb_unsigned_mul_overflows()
+
+ src/hb-algs.hh     | 10 +++++++---
+ src/hb-buffer.cc   | 20 ++++++++++----------
+ src/hb-sanitize.hh | 15 +++++++++------
+ 3 files changed, 26 insertions(+), 19 deletions(-)
+
+commit 25adbb382535de2c981755df211295249a93c4e2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 12:47:53 2022 -0700
+
+    [algs] Use __builtin_mul_overflow
+    
+    Compiles to smaller binary.
+
+ src/hb-algs.hh | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit a10cfe3f32861c13578dc21476b2fe4d2e0af43c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 12:37:59 2022 -0700
+
+    [algs] Write hb_in_ranges() recursively
+
+ src/hb-algs.hh | 15 +++++----------
+ 1 file changed, 5 insertions(+), 10 deletions(-)
+
+commit 2e86700e30265e839f7b00e4bdaf43b5fe04bde2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 12:28:10 2022 -0700
+
+    [gvar] Add memory-barrier as in ArrayOf
+
+ src/hb-ot-var-gvar-table.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit b00a911fa721598b1b7c44943790671506091542
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 12:11:30 2022 -0700
+
+    [sorted-array] Add faster iterator implementation here as well
+
+ src/hb-array.hh | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit 7cc79a8a86835bc641bf56c0b82e36063f44e22f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 12:09:24 2022 -0700
+
+    [vector] Adjust comment
+
+ src/hb-vector.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e82a3c69dd5155b7bcd41fe2131514fa780da24a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 12:00:10 2022 -0700
+
+    [array/vector] Optimize range-based for-loop
+    
+    Avoid bounds-checking.
+
+ src/hb-array.hh  |  5 +++++
+ src/hb-iter.hh   | 16 ++++++++++------
+ src/hb-ot-map.cc |  3 +--
+ src/hb-vector.hh |  5 +++++
+ 4 files changed, 21 insertions(+), 8 deletions(-)
+
+commit 0387182c2a198c69f2313bc8627762477bae4bde
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 11:05:47 2022 -0700
+
+    [ot-map] Minor refactor features[i] access
+
+ src/hb-ot-map.cc | 17 ++++++++++-------
+ 1 file changed, 10 insertions(+), 7 deletions(-)
+
+commit 5ee6d5d77e373314e007d736f04b3686723d1cfd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 11:00:29 2022 -0700
+
+    [cff] Add memory-barrier to INDEX
+    
+    Like we do for ArrayOf.
+
+ src/hb-ot-cff-common.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 6905d36d73f7b33243aaa8507ded49272462d3f8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 10:51:33 2022 -0700
+
+    [cff] Fix fetch_op() bounds-checking
+
+ src/hb-cff-interp-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit b51ab1a9e515f10ed6906b9e1149120854c48260
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 10:27:07 2022 -0700
+
+    [cff] Optimize byte_str_ref_t
+    
+    Make it 16 bytes instead of 24.  This struct is used in the subroutine
+    call stack heavily.
+    
+    This change makes the HB AdobeVFPrototype benchmark to become faster
+    than FT one, with about 6% speedup as a result of this change.
+
+ src/hb-cff-interp-common.hh | 36 ++++++++++++++++--------------------
+ 1 file changed, 16 insertions(+), 20 deletions(-)
+
+commit 7a39464b1883dd4e04608427522d545e049c8389
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 09:48:54 2022 -0700
+
+    [cff] Hide members of byte_str_ref_t
+
+ src/hb-cff-interp-common.hh | 13 +++++++------
+ src/hb-ot-cff1-table.hh     |  2 +-
+ 2 files changed, 8 insertions(+), 7 deletions(-)
+
+commit 18141f00070d2134fb45a68edad026cc83b0f2ea
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 09:47:03 2022 -0700
+
+    [cff] Move a sub_array call
+    
+    No logic change.... I hope?!
+
+ src/hb-cff-interp-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f66415cdd17009463cbc79e6fe3af1edc08a3649
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 09:39:27 2022 -0700
+
+    [cff] Move initialization of a type to constructor
+
+ src/hb-cff-interp-common.hh | 12 ++----------
+ 1 file changed, 2 insertions(+), 10 deletions(-)
+
+commit 70a5cd53f645ff70f6dbcb306fbde3bc778abece
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 21 08:52:33 2022 -0700
+
+    [algs] Assert trivial copy assignable in stable_sort
+
+ src/hb-algs.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 9bb39423f5c46fb2f69ac8975de1433020e46411
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Nov 20 17:40:54 2022 -0700
+
+    [algs] Simplify stable_sort signatures
+
+ src/hb-algs.hh | 10 ++--------
+ 1 file changed, 2 insertions(+), 8 deletions(-)
+
+commit d119568df6bb1691bb9f8146a020811ded5c8dfd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Nov 20 14:11:51 2022 -0700
+
+    [cbdt] Use vector tail()
+
+ src/hb-ot-color-cbdt-table.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 87a88117c8fe819eccce98c71e5f912a756ade96
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Nov 20 14:10:39 2022 -0700
+
+    [object] Use vector tail()
+
+ src/hb-object.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 76ce390b5ae15004ff8abf8c6360a377c0656dd6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Nov 20 13:54:56 2022 -0700
+
+    [ucd] Document algorithms
+
+ src/gen-ucd-table.py | 33 ++++++++++++++++++++++++++++++---
+ src/hb-ucd.cc        | 16 ++++++++++++++++
+ 2 files changed, 46 insertions(+), 3 deletions(-)
+
+commit ed43bc5118edb0cdcbbfac4d31f514d7aa86ebe4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Nov 20 13:10:19 2022 -0700
+
+    [buffer] Move delete_glyphs_inplace() here
+
+ src/hb-aat-layout.cc |  2 +-
+ src/hb-buffer.cc     | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-buffer.hh     |  2 ++
+ src/hb-ot-layout.cc  | 50 --------------------------------------------------
+ src/hb-ot-layout.hh  |  4 ----
+ src/hb-ot-shape.cc   |  2 +-
+ 6 files changed, 51 insertions(+), 56 deletions(-)
+
+commit dd88dae8a9f140c6bbc44d3efd44a37acc71c0c4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 19 15:22:39 2022 -0700
+
+    [unicode] Simplify set_funcs a bit more
+
+ src/hb-unicode.cc | 13 +++++--------
+ 1 file changed, 5 insertions(+), 8 deletions(-)
+
+commit 2d8ff3bcbe69f9d573f2075ef0e3c3d061f1133f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 19 15:23:44 2022 -0700
+
+    [unicode] Destroy user_data in set_funcs fail paths
+    
+    This is what the font_funcs / draw_funcs do.
+
+ src/hb-unicode.cc | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit 527823ccacf2b1e9807ea5b15e8ea15c1f4ddeb1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 19 15:19:08 2022 -0700
+
+    [unicode] Destroy user_data in set_funcs fail paths
+    
+    This is what the font_funcs / draw_funcs do.
+
+ src/hb-unicode.cc       | 14 +++++++++++++-
+ test/api/test-unicode.c |  4 ++--
+ 2 files changed, 15 insertions(+), 3 deletions(-)
+
+commit 56d6b6992b630ea81b681b2876dbcee97164b617
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 19 15:08:50 2022 -0700
+
+    [font/draw] Remove unneeded branch
+    
+    The preamble sets user_data/destroy to nullptr if func is nullptr.
+
+ src/hb-draw.cc | 19 +++++++------------
+ src/hb-font.cc | 18 +++++++-----------
+ 2 files changed, 14 insertions(+), 23 deletions(-)
+
+commit 976bb26cc14909273959695691c65b099349666b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 19 15:06:23 2022 -0700
+
+    [draw] Optimize set_func functions
+
+ src/hb-draw.cc | 72 +++++++++++++++++++++++++++++++++++++++++++---------------
+ src/hb-font.cc | 18 +++++++--------
+ 2 files changed, 63 insertions(+), 27 deletions(-)
+
+commit 114167a9333ebd492832ed45fcf86484def1d909
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 19 14:47:45 2022 -0700
+
+    [font] Optimize set_func functions
+
+ src/hb-font.cc | 81 ++++++++++++++++++++++++++++++++++++++--------------------
+ 1 file changed, 54 insertions(+), 27 deletions(-)
+
+commit f9d7b303ede471a58393d730c4ca3cf935ac7f8b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 19 14:20:36 2022 -0700
+
+    [thai] Use smaller type for arrays
+    
+    No logic change.
+
+ src/hb-ot-shaper-thai.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 72c4e431af13a2c5108998b6d23d3f36d0f97b25
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 19 13:40:33 2022 -0700
+
+    [use-table] Add a OPTIMIZE_SIZE version
+
+ src/gen-use-table.py          |  28 ++++-
+ src/hb-ot-shaper-use-table.hh | 270 ++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 293 insertions(+), 5 deletions(-)
+
+commit 83c3a91dc6a1e666383987e37e2ef934ffb245bc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 19 13:34:58 2022 -0700
+
+    [gen-use-table] Report fullCost
+
+ src/gen-use-table.py | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit ba08de624ef42229933061ae9837512196b5c53e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Nov 19 13:14:18 2022 -0700
+
+    [ucd] Change OPTIMIZE_SIZE to compression level 9
+    
+    Also changes default compression level from 3 to 5, but that shows
+    no change in the generated table size.
+
+ src/gen-ucd-table.py |   24 +-
+ src/hb-ucd-table.hh  | 3892 ++++++++++++++++++++++++--------------------------
+ 2 files changed, 1871 insertions(+), 2045 deletions(-)
+
+commit b68f9f3cfecc23c7f1af128256e652cdb2c04a80
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 21:35:35 2022 -0700
+
+    [machinery] Adjust comment
+
+ src/hb-machinery.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit a47ba1dc0eafa93af0b390f8cc61a8d0573cbf1a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 21:14:07 2022 -0700
+
+    [lazy-pointer] Hide instance
+
+ src/hb-machinery.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 281b4705b43503e0a377a6ac251f4b48ae00542f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 20:25:05 2022 -0700
+
+    [pool] Rewrite a loop as dagger
+
+ src/hb-pool.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit 3ff8abf27287da410883b0f4305cb9426206a60f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 19:35:49 2022 -0700
+
+    Revert "[map] Allow std::move-ing keys into the map"
+    
+    This reverts commit f657ef7e57c889309c2d9d37934368ca255f9d5b.
+    
+    This breaks many compilers with messages like this:
+    
+    hb-subset-plan.hh:226: undefined reference to `OT::head::tableTag'
+    
+    I'm out of my depth re how to fix it.
+
+ src/hb-map.hh   | 15 ++++++---------
+ src/test-map.cc |  6 ++++--
+ 2 files changed, 10 insertions(+), 11 deletions(-)
+
+commit 039e476baccd87786e79e3b483c526d784f5631c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 19:26:02 2022 -0700
+
+    [test-vector] Test sink-move'ing
+
+ src/test-vector.cc | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit a3a218edb57e63f49b49ef847b258b641609a1d7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 19:24:41 2022 -0700
+
+    [map] Add a couple more sink interfaces
+
+ src/hb-map.hh   | 4 ++++
+ src/test-map.cc | 2 ++
+ 2 files changed, 6 insertions(+)
+
+commit 90226eab8933975cb5a6f4e7f7f8067c0a24a68a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 19:21:58 2022 -0700
+
+    [test-map] Test inserting shared_ptr key
+
+ src/test-map.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit f657ef7e57c889309c2d9d37934368ca255f9d5b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 19:17:03 2022 -0700
+
+    [map] Allow std::move-ing keys into the map
+
+ src/hb-map.hh   | 15 +++++++++------
+ src/test-map.cc |  2 ++
+ 2 files changed, 11 insertions(+), 6 deletions(-)
+
+commit a1768ad82938922cda34603371af86ff8035beac
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 19:08:34 2022 -0700
+
+    [map] Fix use of !=
+
+ src/hb-map.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e74b372b59db623f246499db12e8e9707648ccce
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 18:41:39 2022 -0700
+
+    [test-map] Test moving values
+
+ src/test-map.cc | 17 +++++++++++++++--
+ 1 file changed, 15 insertions(+), 2 deletions(-)
+
+commit a9c6a20b193bfa26a43b0d5a1021038dfe4c8ba4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 18:29:12 2022 -0700
+
+    [map] Support moving value in sink interface
+
+ src/hb-algs.hh  |  2 +-
+ src/hb-map.hh   |  2 ++
+ src/test-map.cc | 10 +++++++++-
+ 3 files changed, 12 insertions(+), 2 deletions(-)
+
+commit 1bf9afaad0c7b05d6fbd97805449561b4cc4c5fe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 18:20:50 2022 -0700
+
+    [test-vector] Test sink interface
+
+ src/test-vector.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit fa0e4b041d8d3525a84f838a27b84d2a100025cf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 18:20:14 2022 -0700
+
+    [test-map] Test sink interface
+
+ src/test-map.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1c612a85415ed3b0aec4907817f5ed7211dd1c3c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 18:18:42 2022 -0700
+
+    [test-set] Test sinking range
+
+ src/test-set.cc | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+commit 356708e34a52bbf22cafa44771ee6eeaefc8a80b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 18:17:34 2022 -0700
+
+    [test-set] Test length of iterator
+
+ src/test-set.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 2892fc71e8733890db666afe0ccbd491c0c0bbd2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 18:03:59 2022 -0700
+
+    [vector] Add std::move to pop()
+    
+    This was removed in 76fc27713f52cc338f0325650c2c7798f5cfa2ce,
+    but I believe that was faultly. It was because of a bad move
+    implementation in the set.
+
+ src/hb-vector.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 921f45f46d2f973113d79fd68adb59ae8c0141af
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 17:26:58 2022 -0700
+
+    [array] Rewrite hash() as dagger
+
+ src/hb-array.hh | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit 213117317cefeb4e75d21c5c21e383309f116bb0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 17:24:23 2022 -0700
+
+    [array] Remove hash specializations for bytes
+    
+    Not needed.
+
+ src/hb-array.hh | 15 ---------------
+ 1 file changed, 15 deletions(-)
+
+commit bef5a1c8dc5fd2930e2fd395ad6c1ec4a6a0c2c3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 17:22:17 2022 -0700
+
+    [vector] Comment
+
+ src/hb-vector.hh | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit 69b41f92ec97e3c6822541a96daea66258eba637
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 17:04:34 2022 -0700
+
+    [vector] Simplify shift_down_vector()
+    
+    Compiler is smarter than I am.
+
+ src/hb-vector.hh | 11 -----------
+ 1 file changed, 11 deletions(-)
+
+commit 1dd9396c7a4c24fe9d578551fab735bdd699e52a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 17:01:14 2022 -0700
+
+    [vector] Optimize grow_vector() for size
+    
+    Again, compiler is smarter than I am.
+
+ src/hb-vector.hh | 10 ----------
+ 1 file changed, 10 deletions(-)
+
+commit d36f688131070308c222ebb54fbb188c6cbe278f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 17:00:07 2022 -0700
+
+    [vector] Optimize shrink_vector for size
+    
+    Compiler is smarter than I am.
+
+ src/hb-vector.hh | 13 +------------
+ 1 file changed, 1 insertion(+), 12 deletions(-)
+
+commit bc8eded2963376901be02f9d0f563c980b0a67b0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 16:51:24 2022 -0700
+
+    [vector] Remove a for loop
+
+ src/hb-vector.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit afd9a58bd76032f98fa1daf579c780121ddcdfb6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 16:46:01 2022 -0700
+
+    [vector] Save a couple hb_iter() invocations
+
+ src/hb-vector.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 3ead9863d2fc6ab64984ae5ba49c6c3005679138
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 16:43:47 2022 -0700
+
+    [map] Add size()
+
+ src/hb-map.hh | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+commit 42db8be1897862d0545471b48a8da765496c7aa0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 16:41:50 2022 -0700
+
+    [map] Minor remove if condition
+
+ src/hb-map.hh | 19 +++++++++----------
+ 1 file changed, 9 insertions(+), 10 deletions(-)
+
+commit 4ec706980c9f5583b9c6db2862b9603bba284055
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 16:39:30 2022 -0700
+
+    [map] Rewrite hash() as dagger
+    
+    Somehow our daggers instead of for loop save size. I cannot
+    pinpoint why, other than maybe not inlining.
+
+ src/hb-map.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 025a68cb074cde6b150f7edaf9fa87cb11773b56
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 16:33:04 2022 -0700
+
+    [map] Optimize copy resizing logic
+
+ src/hb-map.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f1d716871d64641136f2f7f17b0731bed59f3a12
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 16:31:27 2022 -0700
+
+    [map] Change bucket_for_hash() to item_for_hash()
+
+ src/hb-map.hh | 26 +++++++++++++-------------
+ 1 file changed, 13 insertions(+), 13 deletions(-)
+
+commit d012f9a9b3a38cc313a07780b68e6494cc8c97c0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 16:29:06 2022 -0700
+
+    [map] Change bucket_for() to item_for()
+
+ src/hb-map.hh | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+commit 68a29020c586a17bcefead7041cf64033a0c3cea
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 16:02:45 2022 -0700
+
+    [bit-page] Write hash() as dagger
+
+ src/hb-bit-page.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit 87271e1b2e3e313ab21ee78f947d7470b01fac72
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 16:01:23 2022 -0700
+
+    [bit-page] Write get_population as dagger
+
+ src/hb-bit-page.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 744eb6baf9ff060af52a6457c012e0f6f4c0a0ce
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 15:56:06 2022 -0700
+
+    [bit-page] Write is_empty() as dagger
+
+ src/hb-bit-page.hh | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+commit 43a4028f0e22c70a979164ddf037c1f6709a3524
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 15:54:34 2022 -0700
+
+    [algs] Move hb_vector_size_t to bit-page as only user
+
+ src/hb-algs.hh     | 43 -------------------------------------------
+ src/hb-bit-page.hh | 44 ++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 44 insertions(+), 43 deletions(-)
+
+commit 01f961ac3a1fdfb31c184e66a5b772239a579764
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 15:47:17 2022 -0700
+
+    [gsubgpos] Minor call hb_iter() instead of ->iter() directly
+
+ src/hb-ot-layout-gsubgpos.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit bba5765583c5857622512c8c99a40cecc7b38839
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 14:52:17 2022 -0700
+
+    [gsubgpos] Remove a few unnecessary namespace invocations
+
+ src/hb-ot-layout-gsubgpos.hh | 34 +++++++++++++++++-----------------
+ 1 file changed, 17 insertions(+), 17 deletions(-)
+
+commit b4d0d1608d5b86ae5b3021fbf98db0472911c578
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 14:47:33 2022 -0700
+
+    [gsubgpos] Rewrite a couple apply() functions as daggers
+
+ src/hb-ot-layout-gsubgpos.hh | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+commit 76c8214eb51fada2d99c460b59307c7acc4ad074
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 18 12:30:46 2022 -0700
+
+    [gsubgpos] Move member around
+
+ src/hb-ot-layout-gsubgpos.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 81a573008e407a67b9c0ea22d4a9a2d9c22222ac
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 17 16:59:36 2022 -0700
+
+    [map] Optimize storage
+
+ src/hb-map.hh | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+commit ae080bf202e08f3b9748a2d752ee5a1cc8a522f1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 17 16:34:58 2022 -0700
+
+    [map] Initialize key and value explicitly
+    
+    If they are of int time they won't be initialized otherwise.
+
+ src/hb-map.hh | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+commit 1d41b9cb3c5078f4d0dd5b693e611ac8724ec91d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 17 16:26:48 2022 -0700
+
+    [user-data] std::move item
+
+ src/hb-object.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ff0bb74895ad6b43792cdc2e3add9cbe9c712a15
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 17 16:17:37 2022 -0700
+
+    [map] Call item_t constructor/destructor directly
+
+ src/hb-map.hh | 34 ++++++++++++++--------------------
+ 1 file changed, 14 insertions(+), 20 deletions(-)
+
+commit 5c8871594955133a5652d4fad07bec20805bfbcf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 17 16:14:16 2022 -0700
+
+    [map] Add item_t.destruct()
+
+ src/hb-map.hh | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+commit 7f83040836e77c13e5a704ee76b83840389876d4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 17 16:10:37 2022 -0700
+
+    [map] Simplify (de)construction of item_t
+
+ src/hb-map.hh | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+commit 99103bd9768fbb2063542c60ecdae317df0ce155
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 17 15:57:06 2022 -0700
+
+    [map] Destruct objects when clearing
+
+ src/hb-map.hh | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+commit 4caad5720cecbf28bb9b11aceba4ab8bf79f611e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 17 15:51:39 2022 -0700
+
+    [test-map] Add test for reset
+    
+    I expect this to leak now, since we don't destruct items.
+
+ src/test-map.cc | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit e93c01c3ae4e7ed019455dd9098034b506b8c49a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 17 15:50:00 2022 -0700
+
+    [map] Rename item clear() to construct()
+
+ src/hb-map.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit fc22d706fe1f72212ad1fba61435a1484b75ffe6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 17 15:46:48 2022 -0700
+
+    [test-map] Don't insert null smart-pointers in map
+    
+    Dereferencing them is not supported anymore after
+    3aad7c2ddffc3f882bf33504dbac31be491c4d72
+    
+    We don't support that for regular pointers, so don't supporting
+    them for smart-pointers sounds right to me.
+
+ src/test-map.cc | 4 ----
+ 1 file changed, 4 deletions(-)
+
+commit 896377463f880fa653e49184f81ce1190d05e082
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 17 15:25:45 2022 -0700
+
+    [map] Don't resize map if not necessary
+
+ src/hb-map.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 7595fa2d9a15518a9ca41f6892a17fd36858e5af
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 17 15:19:29 2022 -0700
+
+    [map] Fix copy-assignment operator
+    
+    Ouch!
+
+ src/hb-map.hh   |  2 +-
+ src/test-map.cc | 13 ++++++++++++-
+ 2 files changed, 13 insertions(+), 2 deletions(-)
+
+commit 41f4bdac357a8b4e4a04a470e7afd11f9d416beb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 17 15:16:00 2022 -0700
+
+    [map] Fix resize during copy-construction/assignment
+
+ src/hb-map.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 3aad7c2ddffc3f882bf33504dbac31be491c4d72
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 17 15:10:47 2022 -0700
+
+    [algs] Remove smart-pointers from hb_hash()
+    
+    hb_deref() handles them. I think this code predated that.
+
+ src/hb-algs.hh | 11 -----------
+ 1 file changed, 11 deletions(-)
+
+commit 7bd101728ac1c0223f9f4cda50d37e006bb069da
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 17 15:01:55 2022 -0700
+
+    [map] Minor use hb_iter instead of hb_array
+
+ src/hb-map.hh | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+commit 238fc14716bc976c1e2891668e79d177a805b8c0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 17 14:58:50 2022 -0700
+
+    [map] Simplify iterators
+
+ src/hb-map.hh | 35 ++++++++++++++++-------------------
+ 1 file changed, 16 insertions(+), 19 deletions(-)
+
+commit 410c14bfa2c5584d785ac1865a1cd273dfba8c50
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Nov 17 14:53:00 2022 -0700
+
+    [map] Fix equality
+    
+    Ouch!
+
+ src/hb-map.hh   |  2 +-
+ src/test-map.cc | 12 +++++++++++-
+ 2 files changed, 12 insertions(+), 2 deletions(-)
+
+commit 6dfd4a16e7dd18944c506764983e87f0098bf338
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 22:44:22 2022 -0700
+
+    [ot-font] Remove stale TODO
+
+ src/hb-ot-font.cc | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit a0bde1e1ea5b6496c84424d47461ee48c4517bdc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 21:27:12 2022 -0700
+
+    [open-type] Remove (Sorted)ArrayOf.sub_array()
+
+ src/OT/Layout/GSUB/AlternateSet.hh |  2 +-
+ src/hb-open-file.hh                |  2 +-
+ src/hb-open-type.hh                | 18 ------------------
+ src/hb-ot-layout-common.hh         |  6 +++---
+ src/hb-ot-layout-gdef-table.hh     |  4 ++--
+ src/hb-ot-math-table.hh            |  4 ++--
+ src/hb-ot-meta-table.hh            |  2 +-
+ 7 files changed, 10 insertions(+), 28 deletions(-)
+
+commit f2b5db700f1674e96f7bbf1face89507351e103c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 21:22:43 2022 -0700
+
+    [vector] Remove .sub_array ()
+
+ src/OT/glyf/Glyph.hh | 4 ++--
+ src/hb-ot-map.cc     | 2 +-
+ src/hb-vector.hh     | 9 ---------
+ 3 files changed, 3 insertions(+), 12 deletions(-)
+
+commit c7d57dcf260288818fc0b74852a588d8e5611a12
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 21:21:31 2022 -0700
+
+    [vector/array] Simplify qsort()
+
+ src/hb-array.hh     | 7 -------
+ src/hb-open-type.hh | 4 ++--
+ src/hb-ot-map.cc    | 2 +-
+ src/hb-vector.hh    | 4 +---
+ 4 files changed, 4 insertions(+), 13 deletions(-)
+
+commit 1610008e623ad7cf60b20c28fb02808cdf709aef
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 20:02:36 2022 -0700
+
+    [gsubgpos] Minor remove call to hb_iter
+
+ src/hb-ot-layout-gsubgpos.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 19ec01d25c68f90bb78150b81363f6744089aa22
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 19:14:42 2022 -0700
+
+    [gsubgpos] Sprinkle const around
+
+ src/hb-ot-layout-gsubgpos.hh | 27 +++++++++++++++------------
+ 1 file changed, 15 insertions(+), 12 deletions(-)
+
+commit 561946c7d57ce2370835236182f475946d646406
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 17:58:59 2022 -0700
+
+    [layout] Comment
+
+ src/hb-ot-layout.cc | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 2268207c19b417e07da4b808b3df257811158c25
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 17:51:22 2022 -0700
+
+    [layout] Update comment
+
+ src/hb-ot-map.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 658f8f4391d768ce87fe7213e7443e79e0982c04
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 17:50:35 2022 -0700
+
+    [layout] Comment
+
+ src/hb-ot-map.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 27a8fe7d58d5bf361ce829ddd9916f8042e129ae
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 17:49:44 2022 -0700
+
+    [layout] Only update buffer digest if buffer changed by a pause
+
+ src/hb-ot-layout.cc          |  9 +++++----
+ src/hb-ot-layout.hh          |  3 ++-
+ src/hb-ot-map.hh             |  2 +-
+ src/hb-ot-shaper-arabic.cc   | 19 +++++++++++--------
+ src/hb-ot-shaper-indic.cc    | 33 ++++++++++++++++++++-------------
+ src/hb-ot-shaper-khmer.cc    | 21 +++++++++++++--------
+ src/hb-ot-shaper-myanmar.cc  | 19 ++++++++++++-------
+ src/hb-ot-shaper-syllabic.cc | 12 +++++++-----
+ src/hb-ot-shaper-syllabic.hh |  4 ++--
+ src/hb-ot-shaper-use.cc      | 33 ++++++++++++++++++++-------------
+ 10 files changed, 93 insertions(+), 62 deletions(-)
+
+commit 8b2a2111235af22ca969898737835e904badf92f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 16:57:44 2022 -0700
+
+    [layout] Keep digest updated in the context
+    
+    Don't recompute digest after every (applied) GSUB lookup.
+
+ src/hb-ot-layout-gsubgpos.hh | 16 ++++++++++------
+ src/hb-ot-layout.cc          | 19 +++++++++----------
+ 2 files changed, 19 insertions(+), 16 deletions(-)
+
+commit a5964a2d2a064941b7090f49f1da2b55938fa95a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 16:45:23 2022 -0700
+
+    [layout] Minor simplify
+
+ src/hb-ot-layout.cc | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+commit 443961971adcfd1a8a2c1d3e8a3aeb8a49297bed
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 16:35:00 2022 -0700
+
+    [perf] Add fa-words.txt and use in shape benchmark
+
+ perf/benchmark-shape.cc |     4 +
+ perf/texts/fa-words.txt | 10000 ++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 10004 insertions(+)
+
+commit 80b87588815bee1be0d083665425caed176ad09e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 16:26:41 2022 -0700
+
+    [layout] Add a buffer message for digest-skipped lookups
+
+ src/hb-ot-layout.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit afa71ee8effa697888daa4e89e4547fa634c42ba
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 16:22:45 2022 -0700
+
+    Fix alignment error
+
+ src/hb-set-digest.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit dff1b809a0535d3c32cf7e8f10cbd5fb8926bca9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 16:19:05 2022 -0700
+
+    [buffer] Add .digest() and use
+
+ src/hb-buffer.hh    |  9 +++++++++
+ src/hb-ot-layout.cc | 11 ++---------
+ 2 files changed, 11 insertions(+), 9 deletions(-)
+
+commit 654a2eafc8a0710b2c2edcb4b7d8098bf801cd50
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 16:09:04 2022 -0700
+
+    [layout] Use buffer-digest for GSUB as well
+    
+    Combined with previous commit, this shows up to 12% speed up with
+    Roboto and the en-words (ie. short strings) benchmark, about 5%
+    for longer English tests, and no adverse effect on heavier fonts.
+
+ src/hb-ot-layout.cc | 34 +++++++++++++++++++++-------------
+ 1 file changed, 21 insertions(+), 13 deletions(-)
+
+commit 15b6c3259957f9bbfab848530aa4ff8ece89780e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 15:59:13 2022 -0700
+
+    [layout] Use a buffer digest for GPOS to skip whole lookups
+
+ src/hb-ot-layout-gsubgpos.hh |  2 +-
+ src/hb-ot-layout.cc          | 37 +++++++++++++++++++++++++------------
+ src/hb-set-digest.hh         |  8 ++++++++
+ 3 files changed, 34 insertions(+), 13 deletions(-)
+
+commit a053b84cb92bb8624ae407265377475f45b9f095
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 14:39:25 2022 -0700
+
+    [gsubgpos] Optimize set-digest initialization
+    
+    Previously we were once collecting set-digest for each subtable,
+    and another time for each lookup.
+    
+    Now we compute the one for each lookup simply from the ones for
+    its subtables.
+
+ src/hb-ot-layout-gsubgpos.hh | 7 ++++---
+ src/hb-set-digest.hh         | 8 ++++++++
+ 2 files changed, 12 insertions(+), 3 deletions(-)
+
+commit 20654cd8891a75e6e44f3f0a467a6d53d65ab3f9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 14:15:58 2022 -0700
+
+    [set-digest] Minor no logic change
+
+ src/hb-set-digest.hh | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+commit 95b9763dbc011e5aa32b8a9faf2146aa552d6eef
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 14:15:01 2022 -0700
+
+    [set-digest] Minor simplify
+
+ src/hb-set-digest.hh | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+commit 9855b678f218ca89376dad44032cd3fc73aadbba
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 13:37:34 2022 -0700
+
+    [cache] Minor rewrite assertion
+
+ src/hb-cache.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a10ff20562f9a77b2f1510bdb70a70f3d2699f1c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 13:34:37 2022 -0700
+
+    [ft] Comment
+
+ src/hb-ft.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 557be9502a49b6a2ed736fed8937b77f6afdd5af
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 12:47:05 2022 -0700
+
+    [test-vector] Fix test
+
+ src/test-vector.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9027d15410a889a903839aba12b08280d53551ea
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 12:39:30 2022 -0700
+
+    [test-iter] Fix leak
+
+ src/test-iter.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit afd716d4cdaa7ac314bc806b4ac4f761d51fbc2e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 12:28:56 2022 -0700
+
+    [serialize] Don't free object-pool in reset()
+
+ src/hb-pool.hh      | 9 +++------
+ src/hb-serialize.hh | 1 -
+ 2 files changed, 3 insertions(+), 7 deletions(-)
+
+commit 02949cf64f6bc9fb9faf5d143519cf50126347f5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 12:06:44 2022 -0700
+
+    [priority-queue] More assert adjustment
+
+ src/hb-priority-queue.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 620ddd762d586d8189212715b56d270ccc6db683
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 12:04:35 2022 -0700
+
+    [priority-queue] Fix asserts
+
+ src/hb-priority-queue.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 57de568aad32ea2f1be894536d695a6aa6b4a12a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 11:50:05 2022 -0700
+
+    [indic-table] Minor adjust empty lines
+
+ src/gen-indic-table.py          |  6 +++---
+ src/hb-ot-shaper-indic-table.cc | 14 ++++++--------
+ 2 files changed, 9 insertions(+), 11 deletions(-)
+
+commit 281a2602cc1c5974814d9eb639e17e1dfd3d112c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 16 11:36:33 2022 -0700
+
+    Update generated file
+
+ src/hb-buffer-deserialize-json.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit f734c26c5c78f56e2d1875f5ce262b6a06093d70
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 15 16:27:56 2022 -0700
+
+    [test-vector] Test inserting set and map
+
+ src/test-vector.cc | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+commit 0a97d27c2b80554d58a51a2f5037a341c18ac993
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 15 16:23:48 2022 -0700
+
+    [test-iter] Add another test
+
+ src/test-iter.cc | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+commit e9e985682af41a8aa106cb0252592a64b536a6db
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 15 16:11:57 2022 -0700
+
+    [fallback-shape] Remove TODO
+
+ src/hb-fallback-shape.cc | 10 ----------
+ 1 file changed, 10 deletions(-)
+
+commit 6df8498da2662cf949770d580d0744817c8acfb8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 15 15:52:04 2022 -0700
+
+    [sample.py] Fix warning
+
+ src/sample.py | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 49fe5c1e5a329d033e55ce87ceff7fae1bf28f4b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 15 15:37:23 2022 -0700
+
+    [glib] Remove old cruft from pre-2011
+
+ src/hb-glib.cc | 77 +++-------------------------------------------------------
+ 1 file changed, 4 insertions(+), 73 deletions(-)
+
+commit 1bd1a37837c1a57fc8a440a6a75b7e6c2778b810
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 15 15:18:36 2022 -0700
+
+    [test] Minor
+
+ src/test-map.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 35aa492eb71def762ecb24c924c1b65c6abb340c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 15 15:05:15 2022 -0700
+
+    [main] sprintf -> snprintf
+
+ src/main.cc | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+commit 72c6962012fab7a4bfe345687d10f8d08c672151
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 14 21:34:16 2022 -0700
+
+    [buffer-deserialize-text] Fix glyph name for glyph flags
+    
+    Skip "#" in glyph names.
+
+ src/hb-buffer-deserialize-text.hh | 462 +++++++++++++-------------------------
+ src/hb-buffer-deserialize-text.rl |   2 +-
+ 2 files changed, 160 insertions(+), 304 deletions(-)
+
+commit dee26de76fc3fdfa2dbfc780c62120206229f1f2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 14 16:24:25 2022 -0700
+
+    [test-buffer-serialize] Allow no font
+
+ src/test-buffer-serialize.cc | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+commit f6076890c5103f7078196d14cfc15323a4781b17
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 14 16:06:39 2022 -0700
+
+    Hide all mentions of name_table_overrides behind EXPERIMENTAL_API
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3872
+
+ src/hb-ot-name-table.hh | 39 ++++++++++++++++++++++++++++++---------
+ src/hb-subset-input.cc  | 13 +++++++++++--
+ src/hb-subset-input.hh  |  8 +++++++-
+ src/hb-subset-plan.cc   |  3 ++-
+ src/hb-subset-plan.hh   |  4 ++++
+ 5 files changed, 54 insertions(+), 13 deletions(-)
+
+commit ebc382a8474af5a8829750db8f641b384f6f47ec
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 14 15:59:46 2022 -0700
+
+    Revert "Avoid use values () in hb-hashmap if value_t has an overriden operator &"
+    
+    This reverts commit b92e4cc0091e093f6941019e1a53cc04a137017a.
+
+ src/hb-subset-input.cc | 7 +++----
+ src/hb-subset-plan.cc  | 7 +++----
+ src/hb-subset-plan.hh  | 6 ++----
+ 3 files changed, 8 insertions(+), 12 deletions(-)
+
+commit ff0d0d020e0fcf7be4e45d6791eb5c7155f5c84b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 14 14:34:20 2022 -0700
+
+    [meta] Use std::decay
+
+ src/hb-meta.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 9650f34a84006c714ac81c72ee59b249bf4e9788
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 14 14:16:11 2022 -0700
+
+    [CI] Remove coverage testing from macos-ci
+
+ .github/workflows/macos-ci.yml | 10 ++--------
+ 1 file changed, 2 insertions(+), 8 deletions(-)
+
+commit 3a9ca6aa698d112c8c7d6733dbbc438b701fd917
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 14 13:57:02 2022 -0700
+
+    [CI] Try fixing macos-ci
+
+ .github/workflows/macos-ci.yml | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 24cf86b0099ada427936b3113c5b48c3537b3425
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 14 13:33:06 2022 -0700
+
+    [array] Fix MSVC fail
+
+ src/test-array.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit a87843be3dea86a5893e1fa64667df872408549e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 14 13:43:58 2022 -0700
+
+    [array] Another try at sizeof sorted_array
+
+ src/hb-array.hh   | 8 ++++----
+ src/test-array.cc | 3 +--
+ 2 files changed, 5 insertions(+), 6 deletions(-)
+
+commit 72ba0b2aa2bd65ea1bfdbca75fe4127264590e00
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Nov 14 13:33:06 2022 -0700
+
+    [array] Fix MSVC fail
+
+ src/test-array.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit b92e4cc0091e093f6941019e1a53cc04a137017a
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Nov 14 08:54:24 2022 -0800
+
+    Avoid use values () in hb-hashmap if value_t has an overriden operator &
+
+ src/hb-subset-input.cc | 7 ++++---
+ src/hb-subset-plan.cc  | 7 ++++---
+ src/hb-subset-plan.hh  | 6 ++++--
+ 3 files changed, 12 insertions(+), 8 deletions(-)
+
+commit ea63e95e4cc287d8efbad6fd215a0b4c541a9e15
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 11 12:45:12 2022 -0700
+
+    [GPOS.PairPos] Adjust unsafe-to-break for non-zero ValueFormat2
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3824
+
+ src/OT/Layout/GPOS/PairPosFormat2.hh | 4 ++++
+ src/OT/Layout/GPOS/PairSet.hh        | 7 ++++++-
+ 2 files changed, 10 insertions(+), 1 deletion(-)
+
+commit 85e0be13575d1342645867bc1a788e13e196594f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Nov 13 17:28:09 2022 -0700
+
+    [vector/array] Add simple test for sorted size
+
+ src/test-array.cc  | 2 ++
+ src/test-vector.cc | 1 +
+ 2 files changed, 3 insertions(+)
+
+commit 4e618557a67f6ce49f93d5c10686500628bede30
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Nov 13 17:23:25 2022 -0700
+
+    [vector] Don't subclass sorted vector from unsorted
+    
+    Was doubling the size unnecessarily.
+
+ src/hb-vector.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 8f15fb125247de8b19e8b5a9396f40a83114a64a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Nov 13 17:06:58 2022 -0700
+
+    [util] Move variable closer to use
+
+ util/shape-consumer.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 630f09c8b6022184f7a414bb5e07c01898fae60c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 9 11:32:30 2022 -0700
+
+    Another hb_memcpy instead of strncpy use
+
+ src/hb-subset-plan.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit cd011ceadfa443767fd818cfe1af8a87150291a2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 9 11:30:44 2022 -0700
+
+    Use hb_memcpy instead of strncpy
+    
+    Nul-termination is not intended.
+
+ src/hb-subset-input.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 604fe807078ce41d0ac7742547e90b17c066709f
+Author: Eli Schwartz <eschwartz93@gmail.com>
+Date:   Tue Nov 8 16:24:08 2022 -0500
+
+    meson: fix regression in detecting freetype2/icu-uc when explicitly disabled
+    
+    In #3811 / commit 53a194aa3f5f7de0b40e879e41fcbe0de6e9fefe a broken and
+    half-implemented approach to kind of sort of handling the detection of
+    both pkg-config and cmake names for dependencies, was implemented. It
+    just checked for both versions with required: false, but when the build
+    was configured with *disabled* options, it was still found because it
+    was treated as auto.
+    
+    Really, the problem here is trying to outsmart Meson, which handles a
+    lot of edge cases correctly. But it's possible, albeit very wordy, to
+    manually implement Meson's internal logic via if/else fallbacks. Do so
+    here.
+
+ meson.build | 79 +++++++++++++++++++++++++++++++++++++++++++------------------
+ 1 file changed, 56 insertions(+), 23 deletions(-)
+
+commit c158b626c3033036321180d4ac90c129206b0ad2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 8 14:15:56 2022 -0700
+
+    [name] Simplify buffer-length calculation
+
+ src/hb-ot-name-table.hh | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+commit 55edf59d521d06a981b16af44a9d6f217093d73b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 8 14:53:27 2022 -0700
+
+    [name] Typo
+
+ src/hb-ot-name-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 27c8bbcb04d506670dad8bbe3b9e9d1bde466aa8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 8 14:48:38 2022 -0700
+
+    Revert "[name] Simplify buffer-length calculation"
+    
+    This reverts commit d70595657e8d56b52d5714d082092d8eb104093e.
+
+ src/hb-ot-name-table.hh | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+commit d70595657e8d56b52d5714d082092d8eb104093e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 8 14:15:56 2022 -0700
+
+    [name] Simplify buffer-length calculation
+
+ src/hb-ot-name-table.hh | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+commit 6314aa7da4204379cd3ebeeaa447a51fbd7ef7bc
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Oct 28 10:44:48 2022 -0700
+
+    [subset] add an experimental API that can override name strings for specified name_id
+
+ src/gen-def.py                              |   1 +
+ src/hb-ot-name-table.hh                     |  83 ++++++++++++++++++++++++++--
+ src/hb-ot-name.cc                           |  51 +----------------
+ src/hb-subset-input.cc                      |  50 ++++++++++++++++-
+ src/hb-subset-input.hh                      |   3 +-
+ src/hb-subset-plan.cc                       |  23 ++++++++
+ src/hb-subset-plan.hh                       |  11 ++++
+ src/hb-subset.h                             |   7 +++
+ test/api/fonts/nameID.override.expected.ttf | Bin 0 -> 167936 bytes
+ test/api/test-subset-nameids.c              |  35 ++++++++++++
+ 10 files changed, 208 insertions(+), 56 deletions(-)
+
+commit f53ef69d5941514b06f5afbcd83709cf724eb74d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Nov 4 16:00:34 2022 -0600
+
+    [indic] Order left-matras inside-out
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3863
+
+ src/hb-ot-shaper-indic.cc                          |  28 ++++++++++++++++++++-
+ src/hb-ot-shaper-myanmar.cc                        |  27 ++++++++++++++++++++
+ .../9d8c53cb64b8747abdd2b70755cce2ee0eb42ef7.ttf   | Bin 0 -> 3000 bytes
+ .../a232bb734d4c6c898a44506547d19768f0eba6a6.ttf   | Bin 0 -> 2512 bytes
+ .../data/in-house/tests/indic-special-cases.tests  |   2 ++
+ test/shape/data/in-house/tests/myanmar-misc.tests  |   1 +
+ 6 files changed, 57 insertions(+), 1 deletion(-)
+
+commit 2822b589bc837fae6f66233e2cf2eef0f6ce8470
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Nov 3 19:49:49 2022 +0000
+
+    [subset] Include instancing tests in distribution.
+    
+    Automatically enable them when the experimental api is enabled.
+
+ test/subset/data/Makefile.am      |  5 +++++
+ test/subset/data/Makefile.sources |  5 +++++
+ test/subset/meson.build           | 19 ++++++++++++-------
+ 3 files changed, 22 insertions(+), 7 deletions(-)
+
+commit dbb7f47b19e60551ef4707f6a2cb60f1bd8334dd
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Nov 3 11:55:41 2022 -0700
+
+    fix bug in hb_hashmap_t has() interface
+    
+    It was not working when the value type is hb_bytes_t because hb_array_t
+    overloaded operator &
+
+ src/hb-map.hh   |  2 +-
+ src/test-map.cc | 10 ++++++++++
+ 2 files changed, 11 insertions(+), 1 deletion(-)
+
+commit d1f445ec1e6518d2d135eca13e791a79a824025a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 2 12:24:04 2022 -0600
+
+    [name] Typo
+
+ src/hb-ot-name.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit fc935fb81b04cce3753b0502897944792be47a19
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Nov 1 14:39:33 2022 -0600
+
+    Fix snprintf use
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3495#issuecomment-1299107964
+
+ src/OT/Layout/GSUB/Ligature.hh | 2 +-
+ src/OT/Layout/GSUB/Sequence.hh | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 2ee42bbac2e2c85e946db525a8241d32d6b01459
+Author: Lorenz Wildberg <lorenz@wild-fisch.de>
+Date:   Tue Nov 1 13:00:18 2022 +0100
+
+    hb_variation_to_string: Fix GIR annotation
+
+ src/hb-common.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 0e4f579493c42e34931277dc32aec75d0044af14
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Oct 31 13:51:24 2022 -0600
+
+    [util/hb-view] Default HB_DRAW to 1
+    
+    See comments.
+
+ util/helper-cairo.hh | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+commit 02b76393efa4ca9a335cc08473bdb744be721bda
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Oct 29 11:15:03 2022 -0600
+
+    [config] Re-enable BORING_EXPANSION
+    
+    Only the non-experimental parts (currently avar2) are
+    enabled by default.
+
+ src/OT/Layout/Common/Coverage.hh     | 34 +++++++++++++++++-----------------
+ src/OT/Layout/GPOS/MarkBasePos.hh    |  4 ++--
+ src/OT/Layout/GPOS/MarkLigPos.hh     |  4 ++--
+ src/OT/Layout/GPOS/MarkMarkPos.hh    |  4 ++--
+ src/OT/Layout/GPOS/PairPos.hh        |  4 ++--
+ src/OT/Layout/GSUB/AlternateSubst.hh |  4 ++--
+ src/OT/Layout/GSUB/LigatureSubst.hh  |  4 ++--
+ src/OT/Layout/GSUB/MultipleSubst.hh  |  4 ++--
+ src/OT/Layout/GSUB/SingleSubst.hh    |  8 ++++----
+ src/graph/classdef-graph.hh          |  2 +-
+ src/graph/coverage-graph.hh          |  2 +-
+ src/graph/gsubgpos-graph.hh          |  4 ++--
+ src/graph/markbasepos-graph.hh       |  4 ++--
+ src/graph/pairpos-graph.hh           |  4 ++--
+ src/hb-config.hh                     |  4 ----
+ 15 files changed, 43 insertions(+), 47 deletions(-)
+
+commit 6a47ef34b1ac5c1afc94a37dc7d2bcbe2013975e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Oct 29 11:14:27 2022 -0600
+
+    [config] If not HB_EXPERIMENTAL, then HB_NO_BEYOND_64K
+
+ src/hb-config.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit a0f999cd95834dce7f98f34890aaccb44c3179d5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Oct 29 11:13:40 2022 -0600
+
+    [config] Rename HB_NO_VARIATIONS2 to HB_NO_AVAR2
+
+ src/hb-config.hh            | 2 +-
+ src/hb-ot-var-avar-table.hh | 6 +++---
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit 60c6b7786d9f4651ae2803bfc4ff4435b38a5bc6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Oct 28 14:19:39 2022 -0600
+
+    Disable -Wcast-function-type-strict
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3859#issuecomment-1295409126
+
+ src/hb.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit d88269c827895b38f99f7cf741fa60210d4d5169
+Author: Martin Storsjö <martin@martin.st>
+Date:   Fri Oct 28 22:17:15 2022 +0300
+
+    freetype: Fix function signatures to match without casts
+    
+    Clang 16 has got a new stricter warning for casts of function types
+    (see https://github.com/llvm/llvm-project/commit/1aad641c793090b4d036c03e737df2ebe2c32c57).
+    
+    This new warning gets included as part of the existing error
+    diagnostic setting of -Wcast-function-type.
+    
+    This fixes errors like these:
+    
+    ../src/hb-ft.cc:1011:34: error: cast from 'void (*)(FT_Face)' (aka 'void (*)(FT_FaceRec_ *)') to 'FT_Generic_Finalizer' (aka 'void (*)(void *)') converts to incompatible function type [-Werror,-Wcast-function-type-strict]
+        ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
+                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ src/hb-ft.cc | 30 ++++++++++++++++++------------
+ 1 file changed, 18 insertions(+), 12 deletions(-)
+
+commit 8a5524833ce78484ed38eeacffc476c462a384d8
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Oct 27 09:43:07 2022 -0700
+
+    [instance] update OS2/.usWeightClass and .usWidthClass when
+    no-prune-unicode-ranges option is enabled
+
+ src/hb-ot-os2-table.hh                             |  23 +++++++++++----------
+ ...anges.retain-all-codepoint.wght=150,wdth=80.ttf | Bin 0 -> 114200 bytes
+ ...anges.retain-all-codepoint.wght=300,wdth=90.ttf | Bin 0 -> 114300 bytes
+ test/subset/data/tests/full_instance.tests         |   1 +
+ 4 files changed, 13 insertions(+), 11 deletions(-)
+
+commit fddeba26e4a0363f7b9ae260ddff2daad6939b34
+Merge: e854739b2 db292f6f0
+Author: خالد حسني (Khaled Hosny) <khaled@aliftype.com>
+Date:   Wed Oct 26 22:34:02 2022 +0200
+
+    Merge pull request #3857 from 2xsaiko/outgoing/cmake-abs-path
+    
+    Pass through absolute paths to cmake config directly
+
+commit db292f6f0238581a489aa8cddc585129b6e920cd
+Author: Marco Rebhan <me@dblsaiko.net>
+Date:   Wed Oct 26 20:49:52 2022 +0200
+
+    Pass through absolute paths to cmake config directly
+    
+    The previous code concatenates includedir to _harfbuzz_prefix verbatim,
+    which results in a wrong final include path in case includedir is an absolute
+    path. Instead, we can let meson determine the absolute include and lib paths
+    in advance and save them in the cmake config.
+    
+    This is an issue in nixpkgs, where includedir is set to the final (absolute)
+    path of the built library in the Nix store, which causes CMake projects
+    depending on harfbuzz to not configure.
+    
+    See https://github.com/NixOS/nixpkgs/issues/180054.
+
+ src/harfbuzz-config.cmake.in | 44 ++++++++------------------------------------
+ src/meson.build              |  4 ++--
+ 2 files changed, 10 insertions(+), 38 deletions(-)
+
+commit e854739b2d905a98082dd37344e75beddf795e1a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Oct 26 13:12:56 2022 -0600
+
+    [fuzzing] Add test font for previous commit
+
+ ...testcase-minimized-hb-shape-fuzzer-6635625931735040 | Bin 0 -> 175945 bytes
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+
+commit 477d71724c945c9f1b4ca8a569be1cc5c5f93dcb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Oct 26 13:11:47 2022 -0600
+
+    [glyf] Limit points in a glyf to 10000 roughly
+    
+    Only enforced when components are being expanded.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3838
+
+ src/OT/glyf/Glyph.hh | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+commit 9aad3dba8f6cc91c8039ebfc2c6c6c5fd179a74b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Oct 26 13:04:02 2022 -0600
+
+    [SingleSubst] Fix degenerate-lookup test
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/3853
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 83769b9cb1bc44511c05f89dfeaa96cfec9749a8
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Oct 21 22:37:32 2022 +0000
+
+    [subset] add comment for why we retain empty lookups.
+
+ src/hb-ot-layout-common.hh | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 70e2de2bd440bccbb5e896ca1a08202da7ed0b4d
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Oct 21 22:33:17 2022 +0000
+
+    [subset] Always output Lookup's even if they are empty.
+    
+    The rest of layout subsetting depends on lookup indices being consistent with those computed during planning. So if an empty lookup is discarded during the subset phase it will invalidate all subsequent lookup indices. Generally we shouldn't end up with an empty lookup as we pre-prune them during the planning phase, but it can happen in rare cases such as when a subtable is considered degenerate (eg. #3853)
+
+ src/hb-ot-layout-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 3377ddf69e0be9ddacf0330c45c0649eade8ba3e
+Author: Joel Auterson <joel@emitwise.com>
+Date:   Thu Oct 20 21:07:05 2022 +0100
+
+    Add missing underscore
+
+ .github/workflows/arm-ci.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 28cb1b39545aa7ab6a2ec5e9110098fd848a30fa
+Author: Joel Auterson <joel@emitwise.com>
+Date:   Thu Oct 20 21:01:53 2022 +0100
+
+    Fix working-directory
+
+ .github/workflows/arm-ci.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit dbbbf02d77a415a3c1c14f01365b348526e01b8a
+Author: Joel Auterson <joel@emitwise.com>
+Date:   Thu Oct 20 20:59:12 2022 +0100
+
+    Fix GHA workflow
+
+ .github/workflows/arm-ci.yml | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 756b5000188a5ca60ba78333aa29d20de8d14320
+Author: Joel Auterson <joel@emitwise.com>
+Date:   Thu Oct 20 20:16:58 2022 +0100
+
+    Add ARM CI workflow
+
+ .github/workflows/arm-ci.yml | 25 +++++++++++++++++++++++++
+ 1 file changed, 25 insertions(+)
+
+commit c813f84235b16994c293d2ffa4584056a97c8e73
+Author: Joel Auterson <joel@emitwise.com>
+Date:   Thu Oct 20 19:45:23 2022 +0100
+
+    Make build work for arm-none-eabi
+
+ src/graph/graph.hh               | 14 +++++++-------
+ src/hb-ot-layout-common.hh       |  8 ++++----
+ src/hb-ot-post-table-v2subset.hh |  4 ++--
+ src/hb-ot-var-fvar-table.hh      |  2 +-
+ src/hb-repacker.hh               |  2 +-
+ 5 files changed, 15 insertions(+), 15 deletions(-)
+
+commit b0b7a65388da25ae3fa01e969ad6abc67eed4f49
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Oct 20 17:13:26 2022 -0600
+
+    [subset] Fix check-symbols failure
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3850
+
+ src/check-symbols.py         | 2 +-
+ src/hb-subset-accelerator.hh | 5 +++--
+ src/hb-subset.cc             | 4 ++++
+ 3 files changed, 8 insertions(+), 3 deletions(-)
+
+commit 970321db7bddbe8c579b73751fc655a924ea3ce6
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Oct 19 22:06:46 2022 +0200
+
+    5.3.1
+
+ NEWS             | 8 ++++++++
+ configure.ac     | 2 +-
+ meson.build      | 2 +-
+ src/hb-version.h | 4 ++--
+ 4 files changed, 12 insertions(+), 4 deletions(-)
+
+commit 7c8be866c981b0fcadc9603c1aac7feefc6c9747
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Oct 19 22:04:31 2022 +0200
+
+    [doc] Hide another experimental symbol
+
+ docs/harfbuzz-sections.txt | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit d1bf6c0c26aa4bb28f107548fcda262b057dfbee
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Oct 17 20:14:02 2022 +0000
+
+    [subset] only preprocess in benchmark when experimental api is enabled.
+
+ perf/benchmark-subset.cc | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit db22bfb3ccc36643d00cc5d6e0cc367a0136ef35
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Oct 17 18:37:07 2022 +0000
+
+    [subset] Remove Franklin from the tests which is not an open source font.
+
+ test/subset/data/Makefile.am                            |   1 -
+ test/subset/data/Makefile.sources                       |   1 -
+ .../FranklinGothic-Regular.default.61,63,68,69.ttf      | Bin 6856 -> 0 bytes
+ ...nklinGothic-Regular.default.retain-all-codepoint.ttf | Bin 44544 -> 0 bytes
+ .../FranklinGothic-Regular.layout-test.61,63,68,69.ttf  | Bin 7928 -> 0 bytes
+ ...nGothic-Regular.layout-test.retain-all-codepoint.ttf | Bin 46524 -> 0 bytes
+ .../FranklinGothic-Regular.retain-gids.61,63,68,69.ttf  | Bin 7288 -> 0 bytes
+ ...nGothic-Regular.retain-gids.retain-all-codepoint.ttf | Bin 44552 -> 0 bytes
+ test/subset/data/fonts/FranklinGothic-Regular.ttf       | Bin 71856 -> 0 bytes
+ test/subset/data/tests/layout.default_features.tests    |  11 -----------
+ test/subset/meson.build                                 |   1 -
+ 11 files changed, 14 deletions(-)
+
+commit a73137d101e5ce03d6691908bb1bb09c1e440cd4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Oct 17 12:18:16 2022 -0600
+
+    [face] Fix annotation
+
+ src/hb-face.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d65af60213e46c2d213d797af48d92b352ee4f55
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Oct 15 14:26:02 2022 -0600
+
+    [shape] Adjust Grapheme clusters for Katakana voiced sound marks
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3844
+
+ src/hb-ot-shape.cc | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+commit bda42fc34a34c0c320784e4f8cba541ddc4573ca
+Merge: a756bd194 f53ebf558
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Oct 14 15:08:22 2022 -0600
+
+    Merge pull request #3842 from harfbuzz/patch_mode
+    
+    [subset] Begin implementing a subset accelerator
+
+commit f53ebf55849bccd9cb8c3f49fa0af6d5eff0570f
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Oct 14 19:38:19 2022 +0000
+
+    [subset] Add hb_subset_preprocess to experimental symbol list for check-symbols.
+
+ src/gen-def.py         | 4 +++-
+ src/hb-subset-input.cc | 8 ++++----
+ src/hb-subset.h        | 3 +++
+ 3 files changed, 10 insertions(+), 5 deletions(-)
+
+commit fdb98ed88e9e3d865736eb27894a2018db236eb8
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Oct 14 18:30:39 2022 +0000
+
+    [subset] add missing HB_EXTERN.
+
+ src/hb-subset-input.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 515863e57c1d682e1a06373cf3dcd053602ed3b0
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Oct 13 23:42:00 2022 +0000
+
+    [subset] Remove add accelerator flag, replace with new api method.
+    
+    Adds hb_subset_preprocess() which preprocesses the face and attaches accelerator data.
+
+ perf/benchmark-subset.cc | 34 +++-----------------------------
+ src/hb-subset-input.cc   | 50 +++++++++++++++++++++++++++++++++++++++++++++++-
+ src/hb-subset-input.hh   |  1 +
+ src/hb-subset-plan.cc    |  2 ++
+ src/hb-subset-plan.hh    |  1 +
+ src/hb-subset.cc         |  2 +-
+ src/hb-subset.h          | 12 ++++++------
+ util/hb-subset.cc        | 35 +++++----------------------------
+ 8 files changed, 68 insertions(+), 69 deletions(-)
+
+commit 573640c99fbff98fe7bb4b672a99eb397165a7cc
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Oct 13 23:21:35 2022 +0000
+
+    [subset] Add hb-subset-accelerator.hh to Make soure list.
+
+ src/Makefile.sources | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit a756bd1944404da6e53173c4061a2aef262e60f3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Oct 13 17:18:19 2022 -0600
+
+    [glyf] Use component phantom points after transformation
+
+ src/OT/glyf/Glyph.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit 82d19c08fc5f2b083d3769d2e6bd818368d6ac40
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Oct 13 17:17:03 2022 -0600
+
+    Revert "[glyf/Composite] Remove phantom points when not needed anymore"
+    
+    This reverts commit 527e63a3bd8487d21e423a8a358eee30672eddb6.
+
+ src/OT/glyf/Glyph.hh | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+commit 527e63a3bd8487d21e423a8a358eee30672eddb6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Oct 13 17:13:40 2022 -0600
+
+    [glyf/Composite] Remove phantom points when not needed anymore
+
+ src/OT/glyf/Glyph.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 3394ec7048ce7c61e39e7d1f176e5d260e3273d1
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Oct 13 23:02:54 2022 +0000
+
+    [subset] use subset accelerator in tests.
+    
+    This ensures it produces equivalent subsets as without the accelerator.
+
+ perf/benchmark-subset.cc |  3 +++
+ test/subset/run-tests.py |  1 +
+ util/hb-subset.cc        | 45 ++++++++++++++++++++++++++++++++++++++++++++-
+ 3 files changed, 48 insertions(+), 1 deletion(-)
+
+commit f4903defc4ed3575f6671087dcecf24c8a37b5f2
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Oct 13 21:38:54 2022 +0000
+
+    [subset] use the accelerator in the subsetting benchmark.
+
+ perf/benchmark-subset.cc | 36 ++++++++++++++++++++++++++++++++++++
+ src/hb-subset.h          |  4 ++--
+ 2 files changed, 38 insertions(+), 2 deletions(-)
+
+commit 01481db5822a7990d60ceba383123040d3009b7b
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Oct 13 21:12:22 2022 +0000
+
+    [subset] use accelerator unicode to gid map if available.
+
+ src/hb-subset-accelerator.hh |  5 +--
+ src/hb-subset-plan.cc        | 78 ++++++++++++++++++++++++++++++++------------
+ src/hb-subset-plan.hh        |  3 ++
+ src/hb-subset.cc             |  2 +-
+ 4 files changed, 65 insertions(+), 23 deletions(-)
+
+commit 4ec5eb955f466a7d4f4a167c7f84e66210ea4851
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Oct 13 19:40:31 2022 +0000
+
+    [subset] add a subset accelerator.
+    
+    Can be optionally attached to the face during subsetting. Contains data which can accelerate future subsets.
+
+ src/hb-subset-accelerator.hh | 75 ++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-subset.cc             | 26 +++++++++++++++
+ src/meson.build              |  1 +
+ 3 files changed, 102 insertions(+)
+
+commit f105c28749b94b5f5a093f2278fe9fc0cb5c73dd
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Oct 13 18:53:41 2022 +0000
+
+    [subset] Suggested flags to enable more performant subset production for use in incxfer.
+
+ src/hb-subset.h | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+commit 5769d422c5d824386d19ddc6bb2d85b96233c357
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Oct 13 12:12:24 2022 -0600
+
+    [type] Add HBFixed template
+
+ src/hb-open-type.hh | 29 +++++++++++++----------------
+ 1 file changed, 13 insertions(+), 16 deletions(-)
+
+commit 8c29dcaee4393e6e52dbe7081bc01ca83512bb7e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Oct 13 12:04:32 2022 -0600
+
+    s/HBFixed/F16DOT16/g
+
+ src/hb-aat-layout-just-table.hh | 20 ++++++++++----------
+ src/hb-aat-layout-trak-table.hh |  8 ++++----
+ src/hb-open-type.hh             |  4 ++--
+ src/hb-ot-color-colr-table.hh   | 14 +++++++-------
+ src/hb-ot-post-table.hh         |  2 +-
+ src/hb-ot-stat-table.hh         | 14 +++++++-------
+ src/hb-ot-var-fvar-table.hh     | 20 ++++++++++----------
+ 7 files changed, 41 insertions(+), 41 deletions(-)
+
+commit 294b1c9f6eda839d22c1509199887e9650b377fe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Oct 13 11:30:02 2022 -0600
+
+    Use snprintf instead of sprintf
+
+ src/OT/Layout/GSUB/Ligature.hh | 2 +-
+ src/OT/Layout/GSUB/Sequence.hh | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 9559d3c1c16812ed202852977ab11f10e3ebe804
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Oct 11 19:49:01 2022 +0000
+
+    [repacker] fix incorrect coverage table size estimation.
+    
+    During splitting of PairPosFormat2 the code was assuming the maximum size of the generated coverage table would be equal too the current size. This is incorrect size the new coverage table may not preserve the ranges found in the original coverage table (since we are splitting based on class, not coverage) and in the worst case may convert from format2 to format1. So use the size of a format1 table as the max size.
+
+ src/graph/pairpos-graph.hh | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+commit dcd8fe2c3b2b76588ce692e44afd290f054451de
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Oct 8 19:33:38 2022 +0200
+
+    Revert "[ci] Mark automatic releases as draft"
+    
+    This reverts commit 9a28df411e75a39c2e4973a589ad0db99f2c5306.
+    
+    It creates a new draft release for each upload, which is not what we are
+    after.
+
+ .ci/publish_release_artifact.sh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 3ce4b8f5c94fe351165243b209ccb9759917f5cb
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Oct 8 19:10:07 2022 +0200
+
+    5.3.0
+
+ NEWS                   | 17 +++++++++++++++++
+ configure.ac           |  2 +-
+ docs/harfbuzz-docs.xml |  1 +
+ meson.build            |  2 +-
+ src/hb-face.cc         |  2 +-
+ src/hb-ot-layout.cc    |  2 +-
+ src/hb-version.h       |  4 ++--
+ 7 files changed, 24 insertions(+), 6 deletions(-)
+
+commit 90eee512a07819c50d32b44e6e660fecd05828b0
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Oct 8 19:02:28 2022 +0200
+
+    [doc] Add symbols to harfbuzz-sections.txt
+
+ docs/harfbuzz-sections.txt | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 9a28df411e75a39c2e4973a589ad0db99f2c5306
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Oct 8 18:22:13 2022 +0200
+
+    [ci] Mark automatic releases as draft
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/2780
+
+ .ci/publish_release_artifact.sh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 99f4668e1969a0a688044433803b3e7797391688
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Sep 29 19:39:59 2022 +0000
+
+    [repacker] use mutable copies of Coverage/ClassDef in MarkBasePos shrink operation.
+    
+    Also make mutable copies (when needed) of the top level subtables during a split operation.
+
+ src/graph/graph.hh             | 25 ++++++++++++++--
+ src/graph/gsubgpos-graph.hh    |  9 ++++--
+ src/graph/markbasepos-graph.hh | 23 ++++++++-------
+ src/graph/pairpos-graph.hh     | 66 ++++++++++++++++++++----------------------
+ src/hb-repacker.hh             |  2 +-
+ 5 files changed, 73 insertions(+), 52 deletions(-)
+
+commit 8f1bf23cc9a8912c452f7571e2a3f35a192a8120
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Sep 27 22:50:54 2022 +0000
+
+    [subset] optimize glyf subsetting w/ retain gids.
+    
+    When retain gids is enabled the subset plan may require the output of many empty glyphs. This change optimizes the glyf subsetting code when the number of retained glyphs << number of output glyphs. Unnessecary lookups to the glyph map are reduced by iterating through the glyph map instead of the output glyph set.
+
+ src/OT/glyf/Glyph.hh       | 14 +++++++++----
+ src/OT/glyf/SubsetGlyph.hh |  1 -
+ src/OT/glyf/glyf.hh        | 52 +++++++++++++++++++++-------------------------
+ 3 files changed, 34 insertions(+), 33 deletions(-)
+
+commit e94fe2adf379b1a802e1ecdd393858474a02970b
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Sep 20 13:14:26 2022 -0700
+
+    [instance] minor optimizations to glyf instancing
+
+ src/OT/glyf/Glyph.hh       | 13 +++++++++----
+ src/OT/glyf/SimpleGlyph.hh | 26 ++++++++++++--------------
+ src/OT/glyf/glyf.hh        | 22 +++++++++++++++++-----
+ 3 files changed, 38 insertions(+), 23 deletions(-)
+
+commit d5fc4a73c08c218b16513464a2e880f65531313b
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Sep 14 14:43:20 2022 -0700
+
+    [instance] add tests for featureVariations
+    
+    Also updated the script that is used to generate tests.With fonttools,
+    we now do instancing first and then subsetting.
+    
+    With different order of subsetting and instancing operations on the same
+    VF file, fonttools seems to generate 2 different font files with different
+    glyph set.
+    1. do subsetting and then instancing: this seems result in a larger glyph
+       set in the font file. Lookups are collected from both retained features
+       and all possible alternate featurevariations, this leads to a larger
+       glyph set after glyph closurei. And instancer doesn't redo glyph
+       closure, it does lookups pruning only.
+    
+    2. do instancing and then subsetting: lookups are collected from
+       features that are replaced already and possible alternate feature
+       variations
+
+ ...fault.retain-all-codepoint.wght=150,wdth=80.ttf | Bin 114200 -> 114200 bytes
+ ...fault.retain-all-codepoint.wght=300,wdth=90.ttf | Bin 114300 -> 114300 bytes
+ ...iable.default.retain-all-codepoint.wght=400.ttf | Bin 0 -> 1660624 bytes
+ ...otdef-outline.retain-all-codepoint.wght=400.ttf | Bin 0 -> 1660668 bytes
+ test/subset/data/fonts/Roboto-Variable.ttf         | Bin 0 -> 477420 bytes
+ .../data/tests/instance_feature_variations.tests   |  12 +++++++++++
+ test/subset/generate-expected-outputs.py           |  23 +++++++++++----------
+ test/subset/meson.build                            |   1 +
+ 8 files changed, 25 insertions(+), 11 deletions(-)
+
+commit b90ce34a25538b1377f69be2bae8b2cf8230ac06
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Sep 14 11:26:32 2022 -0700
+
+    [instance] fix for non-empty .notdef glyph metrics update
+    
+    we need pass in source glyph's outline data to calculate boundaries, and
+    then drop the outline data if notdef-outline is specified.
+    
+    Also disable shifting points for instancing in get_points () API
+
+ src/OT/glyf/Glyph.hh | 31 ++++++++++++++++++++-----------
+ src/OT/glyf/glyf.hh  |  5 +++--
+ 2 files changed, 23 insertions(+), 13 deletions(-)
+
+commit b706c6f77eaeb4fc17e03c0c8c6cee2fe5dc85fc
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Sep 12 13:58:55 2022 -0700
+
+    [instance] update FeatureList with variations
+
+ src/hb-ot-layout-common.hh | 234 ++++++++++++++++++++++++++++-----------------
+ 1 file changed, 144 insertions(+), 90 deletions(-)
+
+commit 8f3a7017c38a713759a324f755f4042b3e533ac2
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Sep 9 15:00:37 2022 -0700
+
+    [instance] support FeatureVariations table
+
+ src/OT/Layout/GPOS/GPOS.hh |  2 +-
+ src/OT/Layout/GSUB/GSUB.hh |  2 +-
+ src/hb-ot-layout-common.hh | 72 +++++++++++++++++++++++++++++++++++-----------
+ 3 files changed, 58 insertions(+), 18 deletions(-)
+
+commit f4813e3b7f3bd15ab0ba94bbf8176b6ec2a9ecea
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Sep 9 10:34:09 2022 -0700
+
+    [instance] update collect_lookups/prune_features()/closure_features() with variations
+    
+    Some features will be substituted with variations, so we do not collect
+    lookups from the original feature tables.
+
+ src/hb-ot-layout-common.hh   | 23 ++++++++++++---
+ src/hb-ot-layout-gsubgpos.hh | 17 +++++++----
+ src/hb-ot-layout.cc          |  2 +-
+ src/hb-subset-plan.cc        | 69 +++++++++++++++++++++++++++++++++-----------
+ src/hb-subset-plan.hh        |  4 +--
+ 5 files changed, 86 insertions(+), 29 deletions(-)
+
+commit 64e2f2fc581c7a301919265b9bf6a6519e9c8586
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Sep 9 09:36:19 2022 -0700
+
+    [instance] store active featurevariation record/condition idxes in the plan
+
+ src/hb-ot-layout-common.hh   | 140 +++++++++++++++++++++++++++++++++++++++++++
+ src/hb-ot-layout-gsubgpos.hh |   5 ++
+ src/hb-subset-plan.cc        |  19 +++++-
+ src/hb-subset-plan.hh        |  17 ++++++
+ 4 files changed, 178 insertions(+), 3 deletions(-)
+
+commit 0a6c16a313443eb4130aca4e39e2a9a792f8ba03
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Aug 8 13:47:39 2022 -0700
+
+    [instance] instantiate fvar table
+    
+    Added an old->new axes_indices mapping in the subset plan
+
+ src/hb-ot-var-fvar-table.hh | 80 +++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-subset-input.cc      |  1 -
+ src/hb-subset-plan.cc       | 14 +++++---
+ src/hb-subset-plan.hh       |  6 ++++
+ src/hb-subset.cc            |  4 +++
+ 5 files changed, 100 insertions(+), 5 deletions(-)
+
+commit 486fc2271a804f8143f44476d55237f8a7755955
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Sep 28 15:11:23 2022 -0600
+
+    [cplusplus] Add missing const
+
+ src/hb-cplusplus.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit c335bf469f5f1103d5ddf76716f356d026cc30c0
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Sep 26 13:01:20 2022 -0700
+
+    support dereferencing shared_ptrs and unique_ptrs
+
+ src/hb-meta.hh  | 12 ++++++++++++
+ src/test-map.cc | 17 +++++++++++++++++
+ 2 files changed, 29 insertions(+)
+
+commit d5829b3ce2a3a989f7f69e5184b7802e71402cf8
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Sep 23 20:06:57 2022 +0000
+
+    [repacker] update the repacker doc to reflect the current state.
+
+ docs/repacker.md | 97 ++++++++++++++++++++++++++++++++++++--------------------
+ 1 file changed, 63 insertions(+), 34 deletions(-)
+
+commit 8cd7d1c3fe4e632a205b538b5ba46c2abe861a56
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Sep 20 22:04:39 2022 +0000
+
+    [subset] Allow table ordering on the face builder to be overriden.
+
+ docs/harfbuzz-sections.txt |  1 +
+ src/hb-face.cc             | 76 +++++++++++++++++++++++++++++++++++++---------
+ src/hb-face.h              |  4 +++
+ 3 files changed, 67 insertions(+), 14 deletions(-)
+
+commit b70032eddadb5488514d60c54f6254834f3d750d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Sep 22 15:59:16 2022 -0600
+
+    [layout] Fix typo in docs
+
+ src/hb-ot-layout.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d2966d39197090a29c35b635831496e6e5a64cf3
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Sep 22 23:30:50 2022 +0200
+
+    [ot-font] Try CBDT extents before outline tables
+    
+    Like we do for sbix table.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3827
+
+ src/hb-ot-font.cc | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+commit 1fdf04642773251bb7899df1e2d6b50ec9a6acff
+Merge: 3ca5fbda7 752060a49
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Sep 22 12:03:17 2022 -0600
+
+    Merge pull request #3799 from harfbuzz/optical-bounds
+    
+    Optical bounds
+
+commit 3ca5fbda76098cf74a9ba0c55feea611e48b0b5c
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Wed Sep 21 18:13:17 2022 -0400
+
+    [USE] Update the data files
+    
+    This uses the data files from
+    <https://github.com/microsoft/font-tools/tree/3254c94606d1d6737370deedae0ee3e08d1e100d/USE>
+    and closes #3817.
+
+ src/gen-use-table.py                              |  23 +--
+ src/hb-ot-shaper-use-table.hh                     | 120 ++++++-------
+ src/hb-ot-shaper-vowel-constraints.cc             |  34 ++++
+ src/ms-use/IndicPositionalCategory-Additional.txt |  15 +-
+ src/ms-use/IndicShapingInvalidCluster.txt         | 198 +++++++++++-----------
+ src/ms-use/IndicSyllabicCategory-Additional.txt   |  91 +++++++---
+ 6 files changed, 284 insertions(+), 197 deletions(-)
+
+commit b78d4b1e58a6c358b4c5034549deba7dea59934c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Sep 21 13:27:12 2022 -0600
+
+    [color] Fix documentation re UPEM vs PPEM
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3826
+
+ src/hb-ot-color.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 56c467093598ec559a7148b61e112e9de52b7076
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Sep 20 17:39:54 2022 -0600
+
+    [subset] Fix compiler warning
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3823
+
+ src/graph/graph.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit c02a1a4adc3d3c02b3573a13d47e8381e3534c22
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Sep 10 10:44:16 2022 -0600
+
+    [ot-font] Remove unused include
+
+ src/hb-ot-font.cc | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit d7cc82ad48981b5d321e848a26618443e28f1b2b
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Tue Sep 20 11:22:54 2022 -0400
+
+    Update the language system tag registry URL
+
+ src/update-unicode-tables.make | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 21b0e594141a386a616f0497c171339f4f47552f
+Author: Jonathan Kew <jfkthame@gmail.com>
+Date:   Tue Sep 20 12:03:08 2022 +0100
+
+    [aat] Add test for rlig-to-aat feature mapping in Geeza Pro.
+
+ test/shape/data/in-house/tests/macos.tests | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit f54d2b3e2c7a51586011f15e439f203a5295fc4e
+Author: Jonathan Kew <jfkthame@gmail.com>
+Date:   Tue Sep 20 11:42:00 2022 +0100
+
+    [aat] Map 'rlig' to AAT required-ligatures setting.
+    
+    Fixes #3819.
+
+ src/hb-aat-layout.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit d827a5ee4031d7db1a0cd3265764140a1210fb12
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Sep 19 10:40:49 2022 +0200
+
+    [subset] Skip glyph closure for any dropped table
+    
+    If COLR or MATH tables are being dropped, there is no point in closing
+    glyphs over them, just like it is done for GSUB.
+
+ src/hb-subset-plan.cc | 29 +++++++++++++++--------------
+ 1 file changed, 15 insertions(+), 14 deletions(-)
+
+commit 4a1d891c6317d2c83e5f3c2607ec5f5ccedffcde
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Sep 17 03:15:51 2022 +0200
+
+    5.2.0
+
+ NEWS                   | 22 ++++++++++++++++++++++
+ configure.ac           |  2 +-
+ meson.build            |  2 +-
+ src/hb-common.h        |  6 +++---
+ src/hb-subset-input.cc |  4 ++--
+ src/hb-version.h       |  4 ++--
+ 6 files changed, 31 insertions(+), 9 deletions(-)
+
+commit 53a194aa3f5f7de0b40e879e41fcbe0de6e9fefe
+Author: Xavier Claessens <xavier.claessens@collabora.com>
+Date:   Wed Sep 7 17:35:03 2022 -0400
+
+    meson: Fix freetype and icu dependency lookup
+    
+    It is wrong to search for a different name depending on the compiler. If
+    anything, cmake name could be available on systems that uses GCC too.
+    
+    This also fix regression in the usage of freetype subproject fallback as
+    its name is "freetype2" and was previously used even when the
+    "freetype" option was set to "auto".
+
+ meson.build | 34 ++++++++++++++++++++++++----------
+ 1 file changed, 24 insertions(+), 10 deletions(-)
+
+commit 7c0791d61afaeec3e0871d2835e22cad018a6a1e
+Merge: 2b766e8ad a120b01ab
+Author: خالد حسني (Khaled Hosny) <khaled@aliftype.com>
+Date:   Wed Sep 7 10:31:17 2022 +0200
+
+    Merge pull request #3810 from ankith26/main
+    
+    [cmake] Generate pkg-config .pc files
+
+commit 2b766e8ade84107261def2a7f8588a6973a4f9b5
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Sep 2 11:34:31 2022 -0700
+
+    [subset] No need to collect_features twice
+
+ src/hb-subset-plan.cc | 43 +++++++++++++++++++++++--------------------
+ 1 file changed, 23 insertions(+), 20 deletions(-)
+
+commit 09b9a1ffddd473ede52b0481c5cb056dd91d648c
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Thu Sep 1 20:20:44 2022 -0400
+
+    [USE] Allow ZWNJ at the end of a cluster
+
+ src/hb-ot-shaper-use-machine.hh                    | 1229 +++++++++++---------
+ src/hb-ot-shaper-use-machine.rl                    |   16 +-
+ .../a56745bac8449d0ad94918b2bb5930716ba02fe3.ttf   |  Bin 0 -> 1292 bytes
+ test/shape/data/in-house/tests/use-syllable.tests  |    1 +
+ 4 files changed, 698 insertions(+), 548 deletions(-)
+
+commit a3e6dbbb43264c7c290897328e8a9fbae2537a0e
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Sep 2 13:53:10 2022 -0700
+
+    [subset] skip the script if it's not included in the final subset
+
+ src/hb-ot-layout-gsubgpos.hh | 3 +++
+ src/hb-subset-plan.cc        | 2 +-
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+commit a120b01ab3894ca14f8b069c1505d0cca8b31e5c
+Author: Ankith <46915066+ankith26@users.noreply.github.com>
+Date:   Tue Sep 6 15:32:04 2022 +0530
+
+    [cmake] Generate pkg-config .pc files
+
+ CMakeLists.txt | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 63 insertions(+), 2 deletions(-)
+
+commit e3548c206990f23caba4fa31fed1aaf3fceeb04f
+Author: Wez Furlong <wez@wezfurlong.org>
+Date:   Sat Sep 3 08:15:03 2022 -0700
+
+    hb-view: Detect WezTerm and use iterm2 image protocol
+    
+    Similar to the logic that detects iterm2, but look for
+    TERM_PROGRAM=WezTerm which identifies wezterm is present.
+    
+    This allows hb-view to output an image directly to the terminal.
+
+ util/helper-cairo.hh | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 752060a49c533c84249707d5a2f026a5b5a4ea33
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Sep 1 13:47:12 2022 -0600
+
+    [layout] Document hb_ot_layout_lookup_get_optical_bound()
+
+ src/hb-ot-layout.cc | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+commit 71c6cba097852831bfb296702e8727e88d14d04a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Sep 1 13:43:19 2022 -0600
+
+    [layout] Rename API:
+    
+    -hb_ot_layout_get_optical_bound()
+    +hb_ot_layout_lookup_get_optical_bound()
+
+ src/hb-config.hh    |  2 +-
+ src/hb-ot-layout.cc | 10 +++++-----
+ src/hb-ot-layout.h  | 13 +++++++++----
+ 3 files changed, 15 insertions(+), 10 deletions(-)
+
+commit 3892128a1fe1d04365cb91b71babd01b331c1893
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Sep 1 13:40:53 2022 -0600
+
+    [layout] Add HB_NO_LAYOUT_RARELY_USED
+
+ src/hb-config.hh    | 1 +
+ src/hb-ot-layout.cc | 2 ++
+ 2 files changed, 3 insertions(+)
+
+commit 8e88653f05daa3f78462ba4949b6713115b26aa9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Sep 1 13:39:26 2022 -0600
+
+    [layout] Move code around
+
+ src/hb-ot-layout.cc | 104 ++++++++++++++++++++++++++--------------------------
+ 1 file changed, 53 insertions(+), 51 deletions(-)
+
+commit 4bf9621113441a509565697c146492eee872c6fa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Aug 31 09:18:18 2022 -0600
+
+    [optical-bounds] Optimize
+
+ src/OT/Layout/GPOS/SinglePosFormat1.hh | 15 +++++++++++----
+ src/OT/Layout/GPOS/SinglePosFormat2.hh | 15 +++++++++++----
+ src/hb-ot-layout.cc                    |  6 +-----
+ 3 files changed, 23 insertions(+), 13 deletions(-)
+
+commit 5d6f1a88e48b57cd28f529643c2c0ff7809e3eea
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Aug 31 08:31:24 2022 -0600
+
+    [layout] Add hb_ot_layout_get_optical_bound()
+
+ src/OT/Layout/GPOS/SinglePosFormat1.hh | 11 +++++++
+ src/OT/Layout/GPOS/SinglePosFormat2.hh | 17 +++++++++-
+ src/hb-ot-layout.cc                    | 57 ++++++++++++++++++++++++++++++++++
+ src/hb-ot-layout.h                     |  6 ++++
+ 4 files changed, 90 insertions(+), 1 deletion(-)
+
+commit 238e7dd2b646b061ffb5c748e280c1e805d6fd00
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Sep 1 13:24:01 2022 -0600
+
+    Fix build
+
+ perf/benchmark-subset.cc | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 470944901f63dfe4ba74e65906be8fe94d620143
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Aug 31 12:01:32 2022 -0700
+
+    [instance] add benchmarks for instancing
+
+ perf/benchmark-subset.cc                       |  84 +++++++++++++++++++++----
+ test/subset/data/fonts/MPLUS1-Variable.ttf     | Bin 0 -> 4133100 bytes
+ test/subset/data/fonts/RobotoFlex-Variable.ttf | Bin 0 -> 1755856 bytes
+ 3 files changed, 73 insertions(+), 11 deletions(-)
+
+commit 14eb3d37ad91e22b88af516850b1ca1ac2603f84
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Sep 1 13:18:42 2022 -0600
+
+    [layout] Improve annotations
+
+ src/hb-ot-layout.cc | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit fd107bddb0362ab4eff70da307124c3603525fbf
+Merge: 29d5c7f67 f8ddb9998
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Sep 1 13:12:25 2022 -0600
+
+    Merge pull request #3795 from googlefonts/instance_GDEF_GPOS
+    
+    [instancing] update GDEF/GPOS tables and a few fixes for glyf instancing
+
+commit f8ddb9998b1b6390b415bcfa549156baeef48b65
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Aug 30 09:08:09 2022 -0700
+
+    [instance] Fix os/2 table width to widthclass mapping
+
+ src/hb-ot-os2-table.hh | 28 +++++++++++++++++++++++++++-
+ 1 file changed, 27 insertions(+), 1 deletion(-)
+
+commit 88c02e00248227ba3434e6b09a58d86c0a779144
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Aug 26 08:34:12 2022 -0700
+
+    [instance] add tests for full instancing
+    
+    Also update previous tests with GDEF/GPOS tables
+
+ ...ifVariable-Roman.drop-hints.1FC,21,41,20,62,63.ttf | Bin 3876 -> 3864 bytes
+ ....default.retain-all-codepoint.wght=150,wdth=80.ttf | Bin 0 -> 114200 bytes
+ ....default.retain-all-codepoint.wght=300,wdth=90.ttf | Bin 0 -> 114300 bytes
+ ....default.retain-all-codepoint.wght=200,wdth=90.ttf | Bin 6540 -> 6760 bytes
+ ....default.retain-all-codepoint.wght=650,wdth=85.ttf | Bin 6492 -> 6712 bytes
+ ....default.retain-all-codepoint.wght=200,wdth=90.ttf | Bin 6332 -> 6440 bytes
+ ....default.retain-all-codepoint.wght=650,wdth=85.ttf | Bin 6284 -> 6392 bytes
+ ...fault.retain-all-codepoint.wght=400,wdth=100.0.ttf | Bin 6584 -> 6804 bytes
+ ...efault.retain-all-codepoint.wght=drop,wdth=100.ttf | Bin 6584 -> 6804 bytes
+ test/subset/data/tests/full_instance.tests            |  12 ++++++++++++
+ test/subset/generate-expected-outputs.py              |   7 +------
+ test/subset/meson.build                               |   1 +
+ test/subset/run-tests.py                              |   3 +--
+ 13 files changed, 15 insertions(+), 8 deletions(-)
+
+commit 8f84c58a34e07254d89eb539ff4dd5ec8089281e
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Aug 26 08:24:19 2022 -0700
+
+    [instance] don't copy phantom points from component
+    
+    No need to consider USE_MY_METRICS for instancing
+
+ src/OT/glyf/Glyph.hh | 7 ++++---
+ src/OT/glyf/glyf.hh  | 2 +-
+ 2 files changed, 5 insertions(+), 4 deletions(-)
+
+commit 58dbc00162fba5a694f4a1dffdc2d3521ebc24f1
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Aug 25 11:05:15 2022 -0700
+
+    [instance] Fix compiling Composite glyph bytes
+    
+    The x/y offset encoded with int8 originally might overflow after deltas
+    are applied. So we cannot just copy and update old values.
+
+ src/OT/glyf/CompositeGlyph.hh | 102 +++++++++++++++++++++++++++++++++---------
+ 1 file changed, 82 insertions(+), 20 deletions(-)
+
+commit 8b7e2a137346c42168acbc7841b3aa77f849edcb
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Aug 24 14:16:55 2022 -0700
+
+    [instance] we need to update hmtx/vmtx values even for empty glyphs
+    
+    Update metrics using the 4 phantom points
+
+ src/OT/glyf/Glyph.hh | 22 ++++++++++++++--------
+ 1 file changed, 14 insertions(+), 8 deletions(-)
+
+commit 7d7b49234441144692a69577b7c7ed70611c9ebc
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Aug 24 11:49:50 2022 -0700
+
+    [instance] move _normalize_axes_location to the beginning of
+    subset_plan_create
+    
+    pinned_at_default flag decides whether delta will be collected as well
+    when collecting layout variation indices
+
+ src/hb-subset-plan.cc | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 6de0a6f0b7cdb32e7a7b63c6fe87933b085f229b
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Aug 3 11:18:00 2022 -0700
+
+    [instance] update GPOS ValueRecord table
+
+ src/OT/Layout/GPOS/Common.hh           |  3 +-
+ src/OT/Layout/GPOS/PairPosFormat1.hh   |  6 +++
+ src/OT/Layout/GPOS/PairPosFormat2.hh   | 10 ++++-
+ src/OT/Layout/GPOS/PairSet.hh          |  2 +-
+ src/OT/Layout/GPOS/PairValueRecord.hh  |  6 +--
+ src/OT/Layout/GPOS/SinglePos.hh        | 15 ++++---
+ src/OT/Layout/GPOS/SinglePosFormat1.hh |  6 +--
+ src/OT/Layout/GPOS/SinglePosFormat2.hh |  6 +--
+ src/OT/Layout/GPOS/ValueFormat.hh      | 81 +++++++++++++++++++++++++++-------
+ 9 files changed, 100 insertions(+), 35 deletions(-)
+
+commit 61636d4efec1e6bbb3754de469212734d75489fb
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Aug 2 10:52:31 2022 -0700
+
+    [instance] update GPOS AnchorFormat3 table
+
+ src/OT/Layout/GPOS/Anchor.hh        |  3 +--
+ src/OT/Layout/GPOS/AnchorFormat3.hh | 46 ++++++++++++++++++++++++++++++-------
+ 2 files changed, 39 insertions(+), 10 deletions(-)
+
+commit 9ab6605f205159b0b16be11a4b36f022ccb8274d
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Aug 2 09:54:29 2022 -0700
+
+    [instance] update GDEF table
+
+ src/hb-ot-layout-common.hh     | 26 ++++++++++++++++++++------
+ src/hb-ot-layout-gdef-table.hh | 28 +++++++++++++++++++++++++---
+ 2 files changed, 45 insertions(+), 9 deletions(-)
+
+commit b72995ff162c6318a84b6ae9d43a9a247f2ad01d
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Aug 1 14:48:01 2022 -0700
+
+    [instance] GDEF table: collect both varidxes and deltas
+
+ src/OT/Layout/GPOS/AnchorFormat3.hh |  4 ++--
+ src/OT/Layout/GPOS/ValueFormat.hh   |  8 +++----
+ src/hb-ot-layout-common.hh          | 32 ++++++++++++++++++++++-----
+ src/hb-ot-layout-gdef-table.hh      | 18 +++++++++------
+ src/hb-subset-plan.cc               | 44 ++++++++++++++++++++++++++++++++++++-
+ 5 files changed, 86 insertions(+), 20 deletions(-)
+
+commit e03043bd0bd1da4b775d29e1fb4cb45217fa8a6c
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Aug 1 11:37:47 2022 -0700
+
+    [subset] don't let VariationStore subset() produce inner_maps
+    
+    Make it a subset-planning object so VariationStore can subset to
+    specified inner_maps.
+    
+    Also add a layout_variation_idx_delta_map in subset_plan
+
+ src/hb-ot-layout-common.hh     | 21 +++-----------------
+ src/hb-ot-layout-gdef-table.hh |  2 +-
+ src/hb-subset-plan.cc          | 44 ++++++++++++++++++++++++++++--------------
+ src/hb-subset-plan.hh          | 13 +++++++------
+ 4 files changed, 41 insertions(+), 39 deletions(-)
+
+commit 29d5c7f67adc673391bcb8ab1ffeb8f4d4524eb8
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Aug 31 15:03:09 2022 -0400
+
+    docs: Improve docs for some apis
+    
+    Various functions take hb_tag_t arrays. Those
+    arrays are expected to be 0-terminated. Document
+    that.
+
+ src/hb-ot-layout.cc | 18 ++++++++++++------
+ 1 file changed, 12 insertions(+), 6 deletions(-)
+
+commit c96bfca380bcdae0856ae0a39655640c85fc2f30
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Aug 31 08:05:14 2022 -0600
+
+    [get-alternates] Minor simplify
+
+ src/hb-ot-layout.cc | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+commit 41aa02ae721ddfa96debf95a039567960164d534
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Aug 29 11:17:22 2022 -0600
+
+    [layout] Improve get_feature_tags documentation
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3798
+
+ src/hb-ot-layout.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 6de56b67b6bd22f63be7ff50d954319534c01b43
+Merge: 9e4ae09fe ade87e153
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Aug 29 10:04:38 2022 -0600
+
+    Merge pull request #3797 from harfbuzz/unicode-15
+    
+    Update to Unicode 15.0.0
+
+commit ade87e153859683e0b7a89dc7baf74c80cd9b95d
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Aug 27 18:34:28 2022 -0400
+
+    [Unicode 15] Add tests
+
+ test/api/test-unicode.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+commit 14e754cd2cb986a28664b24f97c1e1605b4b4a45
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Aug 27 18:12:23 2022 -0400
+
+    [Unicode 15] Update the Arabic joining script list
+
+ src/hb-ot-shaper-arabic-joining-list.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 29386d963c08bcfc58a3507567f1d09c18609ec4
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Aug 27 18:09:08 2022 -0400
+
+    [Unicode 15] Send the new scripts to USE
+
+ src/hb-ot-shaper.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit cc0e0f7056bc401fd71b5e6377b36f50666288b3
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Aug 27 18:06:32 2022 -0400
+
+    [Unicode 15] Update the USE table
+
+ src/hb-ot-shaper-use-table.hh | 219 +++++++++++++++++++++---------------------
+ 1 file changed, 111 insertions(+), 108 deletions(-)
+
+commit e93c2d1309b3b4e7ba28d91c49de977be6dafa73
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Aug 27 16:10:10 2022 -0400
+
+    [Unicode 15] Update the emoji table & cluster test
+
+ src/hb-unicode-emoji-table.hh                       | 12 ++++++------
+ test/shape/data/in-house/tests/emoji-clusters.tests | 11 +++++++++++
+ 2 files changed, 17 insertions(+), 6 deletions(-)
+
+commit f0da4a587adda54186aea7d672d9e47591a3f9cc
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Aug 27 16:05:46 2022 -0400
+
+    [Unicode 15] Update the vowel constraint table
+
+ src/hb-ot-shaper-vowel-constraints.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit a223a61209aea4ef47453918dd4163ffe53cf3a4
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Aug 27 16:04:59 2022 -0400
+
+    [Unicode 15] Update the Indic table
+
+ src/hb-ot-shaper-indic-table.cc | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+commit 8467e12a74ed0dd1c6b3455292447d1a4cd4f7c7
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Aug 27 16:02:59 2022 -0400
+
+    [Unicode 15] Update the Arabic table
+
+ src/hb-ot-shaper-arabic-table.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit d0c32c5a0e1192c7b35b66998ecff362aa7b7205
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Aug 27 15:54:27 2022 -0400
+
+    [Unicode 15] Update the UCD table
+
+ src/hb-ucd-table.hh                          | 5403 +++++++++++++-------------
+ test/shape/data/in-house/tests/sara-am.tests |    4 +-
+ 2 files changed, 2737 insertions(+), 2670 deletions(-)
+
+commit 893512219e8f1bdf7d276a9454722cce385d6d71
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Aug 27 15:59:37 2022 -0400
+
+    Add a target to download Blocks.txt
+
+ src/update-unicode-tables.make | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b68d0af889141ef9393727afab26331f8b03995f
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Aug 27 15:41:07 2022 -0400
+
+    [Unicode 15] Add new `hb_script_t` values
+
+ src/hb-common.h | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+commit f9d48150e1b5fa5501c6c016791f89efffefa667
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Aug 27 15:39:39 2022 -0400
+
+    Regenerate files using Ragel
+
+ src/hb-buffer-deserialize-json.hh   |  8 ++++----
+ src/hb-buffer-deserialize-text.hh   | 10 +++++-----
+ src/hb-number-parser.hh             |  8 ++++----
+ src/hb-ot-shaper-indic-machine.hh   | 14 +++++++-------
+ src/hb-ot-shaper-khmer-machine.hh   | 14 +++++++-------
+ src/hb-ot-shaper-myanmar-machine.hh | 14 +++++++-------
+ src/hb-ot-shaper-use-machine.hh     | 14 +++++++-------
+ 7 files changed, 41 insertions(+), 41 deletions(-)
+
+commit 9e4ae09fe76e0ab908095940c880b4ded94c1e18
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Aug 24 05:02:06 2022 +0200
+
+    [ci] Fix linux-ci builds
+
+ .github/workflows/linux-ci.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 371c88678f32b4e81db9003bef47e99f7d716e5f
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Aug 23 22:28:58 2022 +0200
+
+    Add few missing since tags
+
+ src/hb-ot-layout.cc | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+commit 84d33a1ed8e93ee5fae9cb6fb0281be5ac0f7027
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 23 13:13:13 2022 -0600
+
+    [glyf] Fix compiler warning
+
+ src/OT/glyf/SimpleGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 82dc23f2a1ff63c34cbfe4e8625821269782d741
+Merge: 23461b750 f887ee0c6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 23 13:12:58 2022 -0600
+
+    Merge pull request #3759 from googlefonts/update_glyf
+    
+    [instance] update glyf/hmtx/vmtx/OS2/post tables
+
+commit f887ee0c675b92a203133b98353a1820ad89af69
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Jul 27 13:18:21 2022 -0700
+
+    [instance] update post.italicAngle
+    
+    Add tests for instancing glyf/hmtx
+
+ src/hb-ot-post-table.hh                                  |   8 ++++++++
+ ...ABC.default.retain-all-codepoint.wght=200,wdth=90.ttf | Bin 0 -> 6540 bytes
+ ...ABC.default.retain-all-codepoint.wght=650,wdth=85.ttf | Bin 0 -> 6492 bytes
+ ...ite.default.retain-all-codepoint.wght=200,wdth=90.ttf | Bin 0 -> 6332 bytes
+ ...ite.default.retain-all-codepoint.wght=650,wdth=85.ttf | Bin 0 -> 6284 bytes
+ test/subset/data/fonts/Roboto-Variable.composite.ttf     | Bin 0 -> 9576 bytes
+ test/subset/data/tests/instantiate_glyf.tests            |  13 +++++++++++++
+ test/subset/meson.build                                  |   3 +++
+ 8 files changed, 24 insertions(+)
+
+commit 4882c717b5bc6f2cfe45c5c84bb5ddc060f8ee2e
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Jul 27 12:54:33 2022 -0700
+
+    [instance] update OS/2.usWeightClass and OS/2.usWidthClass
+
+ src/hb-ot-os2-table.hh | 35 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 35 insertions(+)
+
+commit ac0e22fa8efae1fc581c2687f29f027fcb69a36c
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Jul 22 09:37:09 2022 -0700
+
+    [instance] update glyf/hmtx/vmtx tables
+
+ src/OT/glyf/CompositeGlyph.hh |  56 +++++++++++++++++++
+ src/OT/glyf/Glyph.hh          | 118 ++++++++++++++++++++++++++++++++++++++-
+ src/OT/glyf/SimpleGlyph.hh    | 126 ++++++++++++++++++++++++++++++++++++++++++
+ src/OT/glyf/SubsetGlyph.hh    |  14 +++++
+ src/OT/glyf/glyf.hh           |  42 +++++++++++++-
+ src/hb-ot-hmtx-table.hh       |  45 +++++++++++----
+ src/hb-subset-plan.cc         |  26 ++++-----
+ src/hb-subset-plan.hh         |   8 +++
+ src/hb-subset.cc              |  40 +++++++++++++-
+ 9 files changed, 448 insertions(+), 27 deletions(-)
+
+commit 23461b75020164252d6af018fa08e6e3e3907b8b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Aug 19 09:48:12 2022 -0600
+
+    [hb-ft] Only apply FT_Face's transform if we created FT_Face
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3788
+    
+    https://github.com/harfbuzz/harfbuzz/issues/3790
+
+ src/hb-ft.cc | 95 +++++++++++++++++++++++++++++++++++++++++-------------------
+ 1 file changed, 65 insertions(+), 30 deletions(-)
+
+commit 4f59211762a6f6fc1bd7516a4c37e83c4fcb709e
+Merge: 2eda2ab3b a91bfeeda
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Aug 18 16:33:44 2022 -0600
+
+    Merge pull request #3787 from harfbuzz/split_mark_base_bos
+    
+    [repacker] Add support for splitting MarkBasePosFormat1 in the packer.
+
+commit 2eda2ab3bbd2f2013457797727f9bee6ec103179
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Aug 18 16:15:54 2022 -0600
+
+    [object] Forward hb_object_create() arguments to constructor
+
+ src/hb-object.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit df040de9b4f44fefb4b7d0eed26cffe9d10777ef
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Aug 18 16:15:00 2022 -0600
+
+    [array] Add a std::forward
+
+ src/hb-array.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c606978ee01ee6b17a79847c196d14b1b4adf479
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Aug 18 16:13:56 2022 -0600
+
+    [array] Remove unused type pack
+
+ src/hb-array.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 37d61afd5eb2ce216eae032c6916ccbaad3ee31f
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 18 21:05:48 2022 +0000
+
+    [subset] add destructor to subset plan.
+    
+    This ensures that it's members get destructed before the plan itself is destructed, as hb_object_destroy calls the destructor for plan.
+
+ src/hb-subset-plan.cc | 40 +---------------------------------------
+ src/hb-subset-plan.hh | 44 ++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 45 insertions(+), 39 deletions(-)
+
+commit a91bfeeda53fcdf4674ff2069eb5f906f330e2de
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 18 22:01:48 2022 +0000
+
+    [repacker] comment cleanup.
+
+ src/graph/markbasepos-graph.hh | 3 +--
+ src/hb-repacker.hh             | 3 +--
+ 2 files changed, 2 insertions(+), 4 deletions(-)
+
+commit 015ca5bc3ce387c46c4e2f0c70e636d8c6ba76ab
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 18 21:52:55 2022 +0000
+
+    [repacker] fix compiler alignment warning.
+
+ src/test-repacker.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit de37b2650db78c795d1c8049f41444a591ffdf42
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Aug 18 15:21:48 2022 -0600
+
+    [object] Only destruct object if it's not trivially-destructible
+    
+    Such that we're legally free to access the object to destruct its
+    (pointer) fields ourselves afterwards.  For things like hb_font_t,
+    hb_face_t, etc.
+
+ src/hb-object.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 683c5dd21e63fd187ddc6f9b9ae106fac0078163
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 18 20:57:04 2022 +0000
+
+    [repacker] further reduce base count.
+
+ src/test-repacker.cc | 17 +++++++++++------
+ 1 file changed, 11 insertions(+), 6 deletions(-)
+
+commit 5ddf41fc9c1b528dbff4b4dd7eb5c0e7f5bac69d
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 18 20:28:05 2022 +0000
+
+    [repacker] speed up MarkBasePos test case by using a smaller basecount.
+
+ src/test-repacker.cc | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit bf28b84ae8cd58c1ca0d137f4a04d98d699ef9d6
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 18 01:51:37 2022 +0000
+
+    [repacker] cleanup unused base_array_id.
+
+ src/graph/markbasepos-graph.hh | 3 ---
+ 1 file changed, 3 deletions(-)
+
+commit 31976bfb502ae861e083b0933575c654292545f9
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 18 01:50:35 2022 +0000
+
+    [repacker] cleanup unused base_array_links.
+
+ src/graph/markbasepos-graph.hh | 4 ----
+ 1 file changed, 4 deletions(-)
+
+commit 6f5c52b604a3bed2a7870be5283994d9a5483fd6
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 18 01:48:10 2022 +0000
+
+    [repacker] optimize AnchorMatrix::clone.
+    
+    Previous runtime is O(n^2) reduced to O(n).
+
+ src/graph/markbasepos-graph.hh | 43 +++++++++++++++++++++++-------------------
+ 1 file changed, 24 insertions(+), 19 deletions(-)
+
+commit 29e3b2467e4b050f0aca8b27a6adb0af2d114323
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 18 01:19:54 2022 +0000
+
+    [repacker] optimzie remove_real_links as it's a hot method.
+
+ src/graph/graph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 46b5dbd7ce05841d37b009c2d35004c147f44934
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 18 01:18:16 2022 +0000
+
+    [repacker] optimize index_for_offset.
+
+ src/graph/graph.hh | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit 52303638b9446d9840aceecc0890790169a20f0f
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 18 01:10:42 2022 +0000
+
+    [repacker] correct size calculation for MarkBasePosFormat1.
+
+ src/graph/markbasepos-graph.hh | 20 ++++++++++++++++----
+ 1 file changed, 16 insertions(+), 4 deletions(-)
+
+commit ac1a853abc48da5f89e4cba6c28d2657ca1fb118
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 18 00:55:47 2022 +0000
+
+    [repacker] implement sanitize methods for MarkBasePos.
+
+ src/graph/graph.hh             | 12 ++++++------
+ src/graph/markbasepos-graph.hh | 28 ++++++++++++++++------------
+ 2 files changed, 22 insertions(+), 18 deletions(-)
+
+commit a3ed9f9099c8e6d951eb8d1aeda9bdc5278fa4a0
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Aug 17 23:39:11 2022 +0000
+
+    [repacker] fix graph comparison, and mark base pos generation for the tests.
+
+ src/graph/graph.hh             | 37 ++++++++++++++++++++++++++++++-------
+ src/graph/markbasepos-graph.hh |  8 +++++---
+ src/test-repacker.cc           | 33 +++++++++++++++++++++++++--------
+ 3 files changed, 60 insertions(+), 18 deletions(-)
+
+commit 19c51ed35c65f1f4758489645e24939f7b92cea6
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Aug 17 19:15:55 2022 +0000
+
+    [repacker] Get mark base pos test working.
+
+ src/test-repacker.cc | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+commit b46ced956285b1e554dea2086dbe48d78a458692
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Aug 17 17:51:02 2022 +0000
+
+    [repacker] correct MarkArray size calculation.
+
+ src/graph/markbasepos-graph.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 36c76c27c6078d9e494f27ce04b0160c906bc444
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Aug 17 17:30:21 2022 +0000
+
+    [repacker] when clearing links in MarkArray, also clear parents of the children.
+
+ src/graph/markbasepos-graph.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 8c3db8bdfd675b226a1c04ec09cd085284858211
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Aug 17 00:36:23 2022 +0000
+
+    [repacker] more progress on MarkBasePos tests.
+
+ src/graph/gsubgpos-graph.hh    |   7 +-
+ src/graph/markbasepos-graph.hh |  11 +--
+ src/test-repacker.cc           | 177 +++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 188 insertions(+), 7 deletions(-)
+
+commit 172cc82032bc66183eb66d02284000cacfb00573
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 16 13:21:02 2022 -0600
+
+    [BUILD] Minor reword (and reformat)
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3784
+
+ BUILD.md | 29 +++++++++++++++--------------
+ 1 file changed, 15 insertions(+), 14 deletions(-)
+
+commit 1405f96b6f211a6353fa8ad431de5486c8dcd309
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Aug 15 23:48:00 2022 +0000
+
+    [repacker] change run_resolve_overflow_test to check for graph equivalence.
+    
+    Replaces a check for an exact match on the final serialized bytes. The previous check enforced equivalent topological sorting between result and expected, but we only really care that the graph's are equivalent and don't overflow.
+
+ src/graph/graph.hh   | 33 +++++++++++++++++++++++++--------
+ src/test-repacker.cc | 50 +++++++++++++++++---------------------------------
+ 2 files changed, 42 insertions(+), 41 deletions(-)
+
+commit 07fd0528c0eb5d77ac65cf8cef3328df34f24889
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Aug 15 23:16:51 2022 +0000
+
+    [repacker] add graph equality check.
+    
+    Does not compare topological sorting, but looks for equivalence of the two graphs.
+
+ src/graph/graph.hh  | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-serialize.hh |  5 ++++-
+ 2 files changed, 57 insertions(+), 1 deletion(-)
+
+commit 5cf2a25a609a7401b0799b52a972dd10af245aad
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Aug 15 22:49:24 2022 +0000
+
+    [repacker] Expose on internal method in the repacker that allows the caller to pass in/out a graph.
+    
+    Will be used in testing so we can compare graphs instead of packed result.
+
+ src/graph/graph.hh            | 11 ++++++-
+ src/graph/gsubgpos-context.cc |  5 ++--
+ src/graph/gsubgpos-context.hh | 10 ++-----
+ src/hb-repacker.hh            | 67 +++++++++++++++++++++++++------------------
+ 4 files changed, 53 insertions(+), 40 deletions(-)
+
+commit c414ef292b7dee52cdf4fb8afaa8f0835b58749b
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Aug 15 22:10:37 2022 +0000
+
+    [repacker] Implement MarkArray::shrink.
+
+ src/graph/markbasepos-graph.hh | 46 ++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 40 insertions(+), 6 deletions(-)
+
+commit 4ab7e579cb8f4fd4f5ee2e1c0404e58edf8eb8e6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Aug 12 12:17:37 2022 -0600
+
+    Make HB_BORING_EXPANSION opt-in instead of opt-out
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3757
+
+ src/hb-config.hh                 | 3 +++
+ test/api/hb-test.h               | 4 +---
+ test/api/test-be-glyph-advance.c | 2 +-
+ test/api/test-be-num-glyphs.c    | 4 +++-
+ 4 files changed, 8 insertions(+), 5 deletions(-)
+
+commit f8b55205569aacb81f533179c0c0644d471b2aab
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 11 23:09:36 2022 +0000
+
+    [repacker] Add AnchorMatrix::shrink.
+
+ src/graph/markbasepos-graph.hh | 41 ++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 40 insertions(+), 1 deletion(-)
+
+commit bbe14417ad7fcc80b49d0e8426ad757fc7689ccc
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 11 22:53:30 2022 +0000
+
+    [repacker] Begin implementing MarkBasePosFormat1::shrink.
+
+ src/graph/markbasepos-graph.hh | 72 ++++++++++++++++++++++++------------------
+ 1 file changed, 42 insertions(+), 30 deletions(-)
+
+commit c9ddf0815a62c3812ff9386f89d29ac80dfb96ae
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 11 22:34:59 2022 +0000
+
+    [repacker] Implement AnchorMatrix::clone.
+
+ src/graph/markbasepos-graph.hh | 37 +++++++++++++++++++++++++++++++++----
+ 1 file changed, 33 insertions(+), 4 deletions(-)
+
+commit 5ea3c0be8f2cdbf998d1d4ec5b879bab5241ef66
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 11 22:21:28 2022 +0000
+
+    [repacker] Implement MarkArray::clone.
+
+ src/OT/Layout/GPOS/MarkRecord.hh |  2 +-
+ src/graph/markbasepos-graph.hh   | 27 +++++++++++++++++++++++++--
+ 2 files changed, 26 insertions(+), 3 deletions(-)
+
+commit 0083fd109c9dda14df9d42c9733745e359c62c7f
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 11 22:09:46 2022 +0000
+
+    [repacker] add as_table() helper to graph.
+
+ src/graph/graph.hh             | 40 +++++++++++++++++++++++++++++++++
+ src/graph/markbasepos-graph.hh | 50 +++++++++++++++++++-----------------------
+ 2 files changed, 62 insertions(+), 28 deletions(-)
+
+commit b00eb77682526b3e8c5f0eba0ddff0c28ff80abd
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 11 20:33:21 2022 +0000
+
+    [repack] Add add_link helper to graph.
+
+ src/graph/graph.hh             | 16 ++++++++++++++++
+ src/graph/markbasepos-graph.hh | 19 +++----------------
+ 2 files changed, 19 insertions(+), 16 deletions(-)
+
+commit 1acd2a8bf901dd9a22b5a23ab7ac7b4021969bd5
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 11 20:22:31 2022 +0000
+
+    [repacker] implement MarkBasePosFormat1::clone_range.
+
+ src/graph/coverage-graph.hh    |   2 +-
+ src/graph/graph.hh             |  12 ++++
+ src/graph/markbasepos-graph.hh | 145 +++++++++++++++++++++++++++++------------
+ src/graph/pairpos-graph.hh     |  10 +--
+ 4 files changed, 120 insertions(+), 49 deletions(-)
+
+commit cf817f3d99d46dd39e9004ef94ec71077d8af8d9
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 11 19:26:59 2022 +0000
+
+    [repacker] Hook up MarkBasePos splitting.
+
+ src/graph/gsubgpos-graph.hh    | 27 +++++++++++++++++++++++----
+ src/graph/markbasepos-graph.hh | 37 ++++++++++++++++---------------------
+ 2 files changed, 39 insertions(+), 25 deletions(-)
+
+commit 4418beac932f98d77a774e94d51745637b03b513
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 11 19:08:04 2022 +0000
+
+    [repacker] start implmenting MarkBasePos splitting.
+
+ src/Makefile.sources           |   2 +-
+ src/graph/markbasepos-graph.hh | 310 +++++++++++++++++++++++++++++++++++++++++
+ src/meson.build                |   1 +
+ 3 files changed, 312 insertions(+), 1 deletion(-)
+
+commit f4f7d691afba09c1c17ec53ce93e48c6f9038b8e
+Merge: 7fde6ab02 fa46dbca9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 9 22:23:23 2022 -0600
+
+    Merge pull request #3779 from harfbuzz/split_pair_pos_2
+    
+    [repacker] Add PairPosFormat2 table splitting in the repacker.
+
+commit fa46dbca9daea93424f09023547d77bddcd01c36
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Aug 8 17:07:14 2022 +0000
+
+    [repacker] Make actuate_subtable_split internal.
+
+ src/graph/split-helpers.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit fe15f2559f44377a40da50ff4fdbbc8438de8670
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Aug 8 16:57:28 2022 +0000
+
+    [repacker] use position instead of memory address as key in device_tables map.
+
+ src/graph/pairpos-graph.hh | 18 ++++++++++--------
+ 1 file changed, 10 insertions(+), 8 deletions(-)
+
+commit 163fbf0be11c8448f40c054ea5c69c1a7c6155f3
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Aug 5 23:37:11 2022 +0000
+
+    [repacker] Check for nullptr's before sanitizing.
+
+ src/graph/coverage-graph.hh |  2 +-
+ src/graph/gsubgpos-graph.hh | 11 +++++------
+ src/graph/pairpos-graph.hh  | 14 +++++++++-----
+ 3 files changed, 15 insertions(+), 12 deletions(-)
+
+commit 13253233f77196011d0eba3a55e3481381a9a68f
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Aug 5 23:15:10 2022 +0000
+
+    [repacker] in PairPosFormat2 splitting use the max estimated coverage/classdef size for sizing serialization buffers.
+
+ src/graph/pairpos-graph.hh | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+commit dde0a2b0711a5922db6124f08d62fe35f3500dd5
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Aug 5 22:30:37 2022 +0000
+
+    [repacker] track estimated coverage size during PairPosFormat1 split point analysis.
+
+ src/graph/pairpos-graph.hh | 22 ++++++++++++----------
+ 1 file changed, 12 insertions(+), 10 deletions(-)
+
+commit b37e8bef0ec1401710e10bf83ac83da7449e3178
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Aug 5 22:16:20 2022 +0000
+
+    [repacker] count size of the current class at the split point in the next segment.
+
+ src/graph/pairpos-graph.hh | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+commit 7fde6ab02560889c15f573f740b44b0463bcc45c
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Fri Aug 5 13:33:22 2022 -0700
+
+    fuzzer fix: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=49790
+
+ src/hb-ot-layout-common.hh                         |  39 ++++++++++-----------
+ src/hb-serialize.hh                                |   2 +-
+ ...ase-minimized-hb-subset-fuzzer-6362213417353216 | Bin 0 -> 131411 bytes
+ 3 files changed, 20 insertions(+), 21 deletions(-)
+
+commit a4e0fd1685a8ea0a6ae7ddf034edbe1a622c57c1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Aug 5 15:05:51 2022 -0600
+
+    [MultipleSubst] Rewrite serialize signature as single iterator
+
+ src/OT/Layout/GSUB/MultipleSubst.hh        | 10 ++++------
+ src/OT/Layout/GSUB/MultipleSubstFormat1.hh | 19 +++++++++++++------
+ src/OT/Layout/GSUB/SubstLookup.hh          | 12 ++++--------
+ 3 files changed, 21 insertions(+), 20 deletions(-)
+
+commit 65d28bc5a70e4fbd5e5321f56914ed25749db4c9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Aug 5 14:56:07 2022 -0600
+
+    [MultipleSubst] Rewrite serialize() in terms of iterators
+    
+    Unused still, and hence untested
+
+ src/OT/Layout/GSUB/MultipleSubst.hh        | 12 ++++++------
+ src/OT/Layout/GSUB/MultipleSubstFormat1.hh | 18 ++++++++++--------
+ src/OT/Layout/GSUB/SubstLookup.hh          | 17 +++++++++--------
+ 3 files changed, 25 insertions(+), 22 deletions(-)
+
+commit b57ea3b053d45f5437cae54a9ee23040124047da
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Aug 5 14:29:27 2022 -0600
+
+    Revert "[iter] Use && in uses of is_source_of"
+    
+    This reverts commit ccbba667a9bdc096f0053d5e3ee951a8b6298e8a.
+
+ src/OT/Layout/GSUB/AlternateSet.hh | 2 +-
+ src/OT/Layout/GSUB/Ligature.hh     | 2 +-
+ src/OT/Layout/GSUB/Sequence.hh     | 2 +-
+ src/OT/Layout/GSUB/SubstLookup.hh  | 2 +-
+ src/OT/glyf/glyf-helpers.hh        | 2 +-
+ src/hb-open-file.hh                | 4 ++--
+ src/hb-open-type.hh                | 6 +++---
+ src/hb-ot-name-table.hh            | 2 +-
+ 8 files changed, 11 insertions(+), 11 deletions(-)
+
+commit 0e48a65d329b4ecbadc31359fc3f7f57c8f3de5a
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Aug 5 20:19:11 2022 +0000
+
+    [repacker] estimate size of classDef1 and coverage during PairPos2 split point analysis.
+
+ src/graph/classdef-graph.hh      | 14 ++++++---
+ src/graph/pairpos-graph.hh       | 57 ++++++++++++++++++++++++++++------
+ src/graph/test-classdef-graph.cc | 39 +++++++++++++++---------
+ src/test-repacker.cc             | 66 +++++++++++++++++++++++++++++++---------
+ 4 files changed, 134 insertions(+), 42 deletions(-)
+
+commit 2264df6da3c25a803217338faf685f963972a68b
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Aug 5 18:33:03 2022 +0000
+
+    [repacker] add utility that can calculate the size of Coverage+ClassDef via incremental class inclusion.
+
+ src/Makefile.am                  |   5 ++
+ src/graph/classdef-graph.hh      |  82 +++++++++++++++++++++++++++++
+ src/graph/test-classdef-graph.cc | 110 +++++++++++++++++++++++++++++++++++++++
+ src/meson.build                  |   1 +
+ 4 files changed, 198 insertions(+)
+
+commit ccbba667a9bdc096f0053d5e3ee951a8b6298e8a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Aug 5 11:51:51 2022 -0600
+
+    [iter] Use && in uses of is_source_of
+
+ src/OT/Layout/GSUB/AlternateSet.hh | 2 +-
+ src/OT/Layout/GSUB/Ligature.hh     | 2 +-
+ src/OT/Layout/GSUB/Sequence.hh     | 2 +-
+ src/OT/Layout/GSUB/SubstLookup.hh  | 2 +-
+ src/OT/glyf/glyf-helpers.hh        | 2 +-
+ src/hb-open-file.hh                | 4 ++--
+ src/hb-open-type.hh                | 6 +++---
+ src/hb-ot-name-table.hh            | 2 +-
+ 8 files changed, 11 insertions(+), 11 deletions(-)
+
+commit 8fb7cc1c63c1f545717287db622a41317a51c2de
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Aug 5 11:49:29 2022 -0600
+
+    [iter] Use && in is_sink_of uses
+
+ src/OT/Layout/Common/Coverage.hh        | 2 +-
+ src/OT/Layout/Common/CoverageFormat1.hh | 2 +-
+ src/OT/Layout/Common/CoverageFormat2.hh | 2 +-
+ src/OT/glyf/glyf-helpers.hh             | 2 +-
+ 4 files changed, 4 insertions(+), 4 deletions(-)
+
+commit 5d824c09c0dd644b29f0a90ac2dd6bcbd119e789
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Aug 5 01:37:14 2022 +0000
+
+    [repacker] during table splits don't mutate shared coverage/classdef in place.
+    
+    If other subtables are sharing coverage with a subtable being split we have to duplicate the coverage/classdef tables before they are modified during the shrink operation.
+
+ src/graph/graph.hh         | 22 +++++++++++++++++++++-
+ src/graph/pairpos-graph.hh |  7 ++++---
+ 2 files changed, 25 insertions(+), 4 deletions(-)
+
+commit e1ab355056040e7f1566aef55408eb24fec4c5d4
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Aug 5 01:25:16 2022 +0000
+
+    [repacker] correct lookup link insertion.
+
+ src/graph/gsubgpos-graph.hh | 9 +++++++--
+ src/test-repacker.cc        | 3 +++
+ 2 files changed, 10 insertions(+), 2 deletions(-)
+
+commit a733a9afa581ba2c8bac54ba5c0fe3daaddfc30c
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Aug 5 00:32:47 2022 +0000
+
+    [repacker] insert new subtables immediately after the subtable they split from in the lookup.
+
+ src/graph/gsubgpos-graph.hh | 72 +++++++++++++++++++++++++++++++++------------
+ src/hb-serialize.hh         |  5 ++++
+ src/test-repacker.cc        |  6 ++--
+ 3 files changed, 60 insertions(+), 23 deletions(-)
+
+commit 506547c958b5e03d5b712b94b2333dffac0e6b7e
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 4 21:36:21 2022 +0000
+
+    [repacker] Use hb_pair_t constructor instead of hb_pair ().
+    
+    hb_pair was causing corrupted gid values.
+
+ src/graph/pairpos-graph.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit fdd1952c751960392f29162298e7884d5d5ca6c4
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 4 19:21:16 2022 +0000
+
+    [repacker] PairPosFormat2 splitting - fix coverage and classdef splitting.
+    
+    The old code was splitting based on coverage index, but should have been splitting on class value.
+
+ src/graph/classdef-graph.hh |  29 +++--------
+ src/graph/coverage-graph.hh |  16 ++++--
+ src/graph/pairpos-graph.hh  | 121 +++++++++++++++++++++++++-------------------
+ src/test-repacker.cc        |  44 ++++++++++------
+ 4 files changed, 119 insertions(+), 91 deletions(-)
+
+commit c67c1b745bb8306aa6a948f0337a98dc010042a5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Aug 4 11:42:22 2022 -0600
+
+    VarStore: simplify again
+
+ src/hb-ot-layout-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 914542bd18b236810ebd780060000b6c9bf29b78
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Aug 3 17:43:50 2022 -0600
+
+    Whitespace
+
+ src/OT/Layout/GSUB/SingleSubstFormat2.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit d7adc55e18c690b4d1390e1de821eadf24a9b063
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Aug 3 13:22:51 2022 -0600
+
+    [ot-font] Allow 24bit glyphs in advance cache
+
+ src/hb-cache.hh   | 6 ------
+ src/hb-ft.cc      | 4 +++-
+ src/hb-ot-font.cc | 8 +++++---
+ 3 files changed, 8 insertions(+), 10 deletions(-)
+
+commit 99070a734a08fc1cbcee604d19a15b89fa6816d5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Aug 3 13:19:33 2022 -0600
+
+    [cache] Use short instead of int if fits
+
+ src/hb-cache.hh | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+commit d831e935df1725a5a22190569544eed46a738b25
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Aug 4 10:15:21 2022 -0700
+
+    bug fix in VarData get_delta ()
+    
+    when LONG_WORDS flag is set, item row is not computed correctly
+    lcursor should be interpreted as INT32
+
+ src/hb-ot-layout-common.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit b154b1e4c3564bcef14f6efe9062e543808ed659
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 4 01:37:21 2022 +0000
+
+    [repacker] pull out PairPosFormat1,2::do_split() into a common helper method.
+
+ src/Makefile.sources       |   1 +
+ src/graph/pairpos-graph.hh | 111 ++++++++++++++++++---------------------------
+ src/graph/split-helpers.hh |  68 +++++++++++++++++++++++++++
+ src/meson.build            |   1 +
+ 4 files changed, 114 insertions(+), 67 deletions(-)
+
+commit 88e0dd02cb728ba91e96298d6346cdabe18a95ab
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Aug 4 01:03:07 2022 +0000
+
+    [repacker] add sanitization for PairPosFormat2.
+
+ src/graph/pairpos-graph.hh | 20 +++++++++++++++-----
+ 1 file changed, 15 insertions(+), 5 deletions(-)
+
+commit 51a5060273a896008a7bddbe1f851bbb452da408
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Aug 3 22:30:42 2022 +0000
+
+    [repacker] add test for splitting a PairPos2 w/ device tables.
+
+ src/test-repacker.cc | 77 ++++++++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 68 insertions(+), 9 deletions(-)
+
+commit 54fab21cb12d5e22382cba91506a195ae2e6c63a
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Aug 3 21:57:37 2022 +0000
+
+    [repacker] get basic pair pos 2 split test working.
+
+ src/graph/pairpos-graph.hh |  2 +-
+ src/test-repacker.cc       | 31 ++++++++++++++++---------------
+ 2 files changed, 17 insertions(+), 16 deletions(-)
+
+commit 60d6ffb3758fddca681cfc28828175eb8b5aa3e6
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Aug 3 21:01:23 2022 +0000
+
+    [repacker] always duplicate classDef2 when splitting a PairPos2.
+    
+    Splits are done in a way that it shouldn't be possible to share the classDef2 between split PairPos2's so pre-emptively duplicate it.
+
+ src/graph/pairpos-graph.hh | 1 +
+ src/test-repacker.cc       | 2 +-
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+commit 6be152420f8db34c7442b29ce3d47b0d975dbf61
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Aug 3 19:02:20 2022 +0000
+
+    [repacker] add basic test for PairPos2 splitting.
+
+ src/graph/pairpos-graph.hh |   4 +-
+ src/test-repacker.cc       | 161 +++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 164 insertions(+), 1 deletion(-)
+
+commit b78546b1d2af284ae1cb9d98732016a149322680
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Aug 3 13:02:18 2022 -0600
+
+    [cache] Residual
+
+ src/hb-cache.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit ec90d1e16179f1b689d7f030dd577489e0129b97
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Aug 3 13:00:48 2022 -0600
+
+    [cache] Add a non-threadsafe version
+    
+    Use in hb-ft, since already mutex'ed.
+
+ src/hb-cache.hh   | 17 +++++++++++++----
+ src/hb-ft.cc      |  2 +-
+ src/hb-ot-font.cc |  6 +++---
+ 3 files changed, 17 insertions(+), 8 deletions(-)
+
+commit f73c15ca6c371cd161b6d546ae10fbe40807913d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Aug 3 12:54:03 2022 -0600
+
+    [atomic-int] Add operators for relaxed ops
+
+ src/hb-atomic.hh          |  3 +++
+ src/hb-bit-set.hh         | 22 +++++++++++-----------
+ src/hb-cache.hh           |  6 +++---
+ src/hb-common.cc          |  2 +-
+ src/hb-debug.hh           |  4 ++--
+ src/hb-face.cc            |  6 +++---
+ src/hb-face.hh            |  4 ++--
+ src/hb-object.hh          | 16 ++++++++--------
+ src/hb-ot-shaper-indic.cc |  8 ++++----
+ src/hb-ot-tag.cc          |  4 ++--
+ src/hb-static.cc          |  4 ++--
+ 11 files changed, 41 insertions(+), 38 deletions(-)
+
+commit 86d1e22d4f3ee27aa803230490188b8a05097437
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Aug 3 12:43:28 2022 -0600
+
+    [atomic-ptr] Rename get
+
+ src/hb-atomic.hh        | 6 +++---
+ src/hb-machinery.hh     | 6 +++---
+ src/hb-object.hh        | 6 +++---
+ src/hb-ot-cff1-table.hh | 2 +-
+ src/hb-ot-font.cc       | 2 +-
+ src/hb-ot-post-table.hh | 4 ++--
+ 6 files changed, 13 insertions(+), 13 deletions(-)
+
+commit d3f2287e0b5dbb0fd8d30f4c5aa2f85b2bcd8899
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Aug 3 12:37:41 2022 -0600
+
+    [atomic-int] Rename get/set
+
+ src/hb-atomic.hh  | 4 ++--
+ src/hb-ot-font.cc | 6 +++---
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+commit afe6629b2f815486bd70b496249657312cdc8918
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Aug 3 19:56:29 2022 +0200
+
+    Fix make dist
+
+ test/fuzzing/Makefile.am | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e68e874da61ef72e63268d451ecde8785cd2f871
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Aug 3 11:31:04 2022 -0600
+
+    Update test/fuzzing/README
+
+ TESTING.md             |  6 +-----
+ test/fuzzing/README    | 21 ---------------------
+ test/fuzzing/README.md | 17 +++++++++++++++++
+ 3 files changed, 18 insertions(+), 26 deletions(-)
+
+commit c80e32972f485dbdc326d7daa110f94f4d66cbf9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 2 13:16:06 2022 -0600
+
+    [mvar] Use VarIdx
+
+ src/hb-ot-var-mvar-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 52bdc750c17652bc289895150778434380d4c49a
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Aug 3 10:39:52 2022 +0200
+
+    Revert "[meson] Use pathlib in gen-harfbuzzcc.py"
+    
+    This reverts commit eaf7e5686c0d15f2308b35b43aaccdded9967216.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3776
+    
+    No idea what is going on, but lets restore the old code.
+
+ src/gen-harfbuzzcc.py | 21 ++++++++++-----------
+ 1 file changed, 10 insertions(+), 11 deletions(-)
+
+commit 65ed82fde5ad413ebbfb214a692b4c671f49d097
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Aug 2 22:22:42 2022 +0000
+
+    [repacker] PairPosFormat2::do_split.
+
+ src/graph/pairpos-graph.hh | 45 ++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 40 insertions(+), 5 deletions(-)
+
+commit f43055f35ac3255589c842288dd4291d89b68e9c
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Aug 2 22:16:29 2022 +0000
+
+    [repacker] Implement PairPosFormat2::shrink.
+
+ src/graph/pairpos-graph.hh | 56 +++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 51 insertions(+), 5 deletions(-)
+
+commit 16bfe6536b32f6a83fcbf53bd445d222d74fa638
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Aug 2 23:46:04 2022 +0200
+
+    [meson] use cpp.get_argument_syntax not cpp.get_id
+    
+    To account for both MSVC and clang-cl.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3756
+
+ meson.build     | 4 ++--
+ src/meson.build | 8 ++++----
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+commit 9f2a44640c228e6e304ea81a56f8323c6fc67cf9
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Aug 2 21:47:53 2022 +0000
+
+    [repack] implement device table transfer for PairPosFormat2.
+
+ src/graph/pairpos-graph.hh | 82 +++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 77 insertions(+), 5 deletions(-)
+
+commit 22eae32b3b5fc901929d9a27a332b03d7b4ef656
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Aug 2 21:04:38 2022 +0000
+
+    [repacker] add classDef1 clone_range to PairPosFormat2 split.
+
+ src/graph/classdef-graph.hh |  4 ++--
+ src/graph/coverage-graph.hh | 16 ++++++++--------
+ src/graph/pairpos-graph.hh  | 23 +++++++++++++++++------
+ 3 files changed, 27 insertions(+), 16 deletions(-)
+
+commit 68b90153eae113589d0562b726d307ba23cac8a9
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Aug 2 20:58:35 2022 +0000
+
+    [repacker] Add class def sanitize and range cloning.
+
+ src/Makefile.sources        |   1 +
+ src/graph/classdef-graph.hh | 141 ++++++++++++++++++++++++++++++++++++++++++++
+ src/graph/coverage-graph.hh |   2 +-
+ src/graph/pairpos-graph.hh  |  14 ++++-
+ src/meson.build             |   1 +
+ 5 files changed, 156 insertions(+), 3 deletions(-)
+
+commit ca0df565f73191e624dcb05e9419947ba72ecfc0
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Aug 2 20:04:46 2022 +0000
+
+    [repacker] extract coverage cloning into helper.
+
+ src/graph/coverage-graph.hh |  62 +++++++++++++++++++++++++
+ src/graph/pairpos-graph.hh  | 110 ++++++++++++++++++++++++--------------------
+ 2 files changed, 123 insertions(+), 49 deletions(-)
+
+commit ee18ae3b76bce1d9dafcfdcc0bb049e099120c61
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 2 12:56:06 2022 -0600
+
+    [avar] Minor move code around
+
+ src/hb-ot-var-avar-table.hh | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+commit 7f4b2037a56609173682902a793efa5607eaa310
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Aug 2 18:43:25 2022 +0000
+
+    [repacker] include size of device tables when determining PairPos2 split points.
+
+ src/OT/Layout/GPOS/ValueFormat.hh | 21 ++++++++++-----
+ src/graph/pairpos-graph.hh        | 57 ++++++++++++++++++++++++++-------------
+ 2 files changed, 53 insertions(+), 25 deletions(-)
+
+commit 826639fab2b213af1dc5c00d3b1ab5b5187e30fe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 2 12:18:18 2022 -0600
+
+    [src] Add test-use-table
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3758
+
+ src/Makefile.am               |  5 +++++
+ src/gen-use-table.py          | 21 ---------------------
+ src/hb-ot-shaper-use-table.hh | 21 ---------------------
+ src/meson.build               |  1 +
+ src/test-use-table.cc         | 18 ++++++++++++++++++
+ 5 files changed, 24 insertions(+), 42 deletions(-)
+
+commit 58fdbd8e5daa5f4a44da45b3093fa7285ec1d5bf
+Author: Garret Rieger <grieger@google.com>
+Date:   Sat Jul 30 02:05:15 2022 +0000
+
+    [repacker] begin adding PairPosFormat2 splitting support.
+
+ src/OT/Layout/GPOS/ValueFormat.hh |  9 ++++
+ src/graph/pairpos-graph.hh        | 89 ++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 96 insertions(+), 2 deletions(-)
+
+commit e387b3acd32bf1a752fbdc63718187c03444a11d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Aug 2 09:46:23 2022 -0600
+
+    [ft] Try harder
+
+ src/hb-ft.cc | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+commit 40a3468906a60c10e85f0741f1c9c49d132525a3
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Aug 2 16:09:27 2022 +0200
+
+    hb-ft: cast to float to help windows sqrtf
+
+ src/hb-ft.cc | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+commit 6549aec89de04caf2546597fe6ebf3811944615d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Aug 1 13:11:14 2022 -0600
+
+    [SingleSubstFormat1] Help avoid timeouts in closure() some more
+    
+    For https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=49712
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit ba9b20534cd46e9ecf33fbcb7b9dbf75e7b7c9b4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Aug 1 12:42:05 2022 -0600
+
+    [ft] Try working around fonts with transform set
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3772
+
+ src/hb-buffer.h |  2 +-
+ src/hb-ft.cc    | 18 +++++++++---------
+ 2 files changed, 10 insertions(+), 10 deletions(-)
+
+commit 04d28d94e576aab099891e6736fd0088dfac3366
+Author: psykose <alice@ayaya.dev>
+Date:   Mon Aug 1 07:45:25 2022 +0000
+
+    [repacker] fix signedness of char in tests
+
+ src/test-repacker.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit f1f2be776bcd994fa9262622e1a7098a066e5cf7
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sun Jul 31 15:46:25 2022 +0200
+
+    5.1.0
+
+ NEWS             | 16 ++++++++++++++++
+ configure.ac     |  2 +-
+ meson.build      |  2 +-
+ src/hb-buffer.h  |  8 ++++++--
+ src/hb-version.h |  6 +++---
+ 5 files changed, 27 insertions(+), 7 deletions(-)
+
+commit d6e55f1baf89b8498a708b78da28517a6c694862
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Jul 30 23:35:47 2022 +0200
+
+    [automake] Use LANG=C when generating harfbuzz*.cc
+    
+    Since `sort` is locale-dependent.
+
+ src/Makefile.am | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit a722b3e6662d8ffdb529cd4b552ff8770b1523a5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 30 14:33:33 2022 -0600
+
+    [shape] Only add any unsafe-to-concat flag if requested
+    
+    Previously it was confusing as random incorrect flags were produced.
+
+ src/hb-ot-shape.cc | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+commit 0a31cfb225f78b3ac784088e9a74a4604fe3487d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 30 14:32:58 2022 -0600
+
+    [buffer] Fix produce-tatweel enum value
+
+ src/hb-buffer.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a0111e4fab5774aa25569c3acfac1d913990b7a2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 30 12:09:45 2022 -0600
+
+    [graph] Fix warning
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3766
+
+ src/graph/pairpos-graph.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit fc9e6ae8d965b3fb8f4f9d0c7dbb11bd1d9960e7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 30 12:02:36 2022 -0600
+
+    [run-tests.py] Write out the failing test
+
+ test/shape/run-tests.py | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 083d4ef5c40ff576366a94445ce9b0d5863097b1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 30 11:53:56 2022 -0600
+
+    [harfbuzz-subset.cc] Revert back the sort order
+    
+    Generator seems unstable.
+
+ src/harfbuzz-subset.cc | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit 065f1e33c8db6ca8d5ac836e450e70da3d9901ac
+Merge: 7c9e1ffa7 23dbd35ca
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 30 11:09:33 2022 -0600
+
+    Merge pull request #3763 from harfbuzz/split_pair_pos
+    
+    [repacker] Add ability for repacker to pre split PairPosFormat1 subtables.
+
+commit 7c9e1ffa7cbe7d3d3a20c2943814ddb7d9683837
+Merge: 5e31a582c f43dadb8e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 30 10:33:27 2022 -0600
+
+    Merge pull request #3762 from harfbuzz/safe-to-kashida
+    
+    Prototype glyph flag safe-to-kashida
+
+commit f43dadb8eea532cb90318a7ffcdd4bf968d3f711
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 30 10:23:03 2022 -0600
+
+    Rename kashida -> tatweel
+
+ src/hb-buffer.h            | 10 +++++-----
+ src/hb-buffer.hh           |  6 +++---
+ src/hb-ot-shape.cc         | 16 ++++++++--------
+ src/hb-ot-shaper-arabic.cc |  4 ++--
+ util/shape-options.hh      |  6 +++---
+ 5 files changed, 21 insertions(+), 21 deletions(-)
+
+commit 73c3ac917247be04d824d7adf3e6c233e92bb063
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 30 10:21:34 2022 -0600
+
+    Document kashida stuff
+
+ src/hb-buffer.h | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+commit 4f09ea5e6bd89add30c8206933efd04b3bbbf1cf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 30 10:12:24 2022 -0600
+
+    [hb-shape] Add --safe-to-insert-kashida flag
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3762
+
+ util/shape-options.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit d277addb2f198e7bb710a79d7ae0c97c85613719
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 30 10:10:21 2022 -0600
+
+    [buffer] Add HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_KASHIDA
+
+ src/hb-buffer.h    |  3 ++-
+ src/hb-buffer.hh   |  5 +++++
+ src/hb-ot-shape.cc | 21 +++++++++++++++++----
+ 3 files changed, 24 insertions(+), 5 deletions(-)
+
+commit 915e12ccbbeaba0ee3777feb26687ce4728a7e89
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 29 13:55:39 2022 -0600
+
+    Prototype glyph flag safe-to-kashida
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3721
+
+ src/hb-buffer.h            | 7 ++++---
+ src/hb-buffer.hh           | 6 ++++++
+ src/hb-ot-shape.cc         | 8 +++++++-
+ src/hb-ot-shaper-arabic.cc | 4 ++--
+ 4 files changed, 19 insertions(+), 6 deletions(-)
+
+commit 5e31a582c90df789c988c3a89e137d6d41e74e2b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 30 00:09:33 2022 -0600
+
+    [emoji] Bump compression level
+
+ src/gen-emoji-table.py        |  2 +-
+ src/hb-unicode-emoji-table.hh | 59 ++++++++++++++++++++-----------------------
+ 2 files changed, 28 insertions(+), 33 deletions(-)
+
+commit 56a5bc3bd0907fe1082e56f167867fd8635dec8b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 30 00:08:44 2022 -0600
+
+    [emoji] Regenerate test data
+    
+    Fix generator.
+
+ src/gen-emoji-table.py                             |  8 +--
+ .../shape/data/in-house/tests/emoji-clusters.tests | 75 ++++++++++++++++++++++
+ 2 files changed, 79 insertions(+), 4 deletions(-)
+
+commit 90a3355e66d3d75ac6273797913260c42b2be615
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 30 00:01:50 2022 -0600
+
+    [ucd-table] Use more compact compression numbers
+    
+    Doesn't show any slowdown in benchmarks.
+
+ src/gen-ucd-table.py |    6 +-
+ src/hb-ucd-table.hh  | 5451 ++++++++++++++++++++------------------------------
+ 2 files changed, 2153 insertions(+), 3304 deletions(-)
+
+commit 23dbd35ca38faac7f2092a681702e58db453b860
+Merge: 9578c44ea a5d9012e9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 29 19:51:57 2022 -0600
+
+    Merge branch 'main' into split_pair_pos
+
+commit a5d9012e94978a5af32021c5c478a8db95aea195
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 29 19:51:00 2022 -0600
+
+    Revert "[ot-font] Minor simplification"
+    
+    This reverts commit 28c02b37684b41bf584ed81d910a448bdf9f706a.
+    
+    Old code was used in case of memory allocation failure (as shown
+    by fuzzers...)
+
+ src/hb-ot-font.cc | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 9578c44ea226bfd0e230bc60de16f328c40ba557
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jul 29 21:58:24 2022 +0000
+
+    [repacker] add HB_FALLTRHOUGH.
+
+ src/graph/pairpos-graph.hh | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+commit 6a5e2cb2f89d46eac2211b90c8c79e922032bb5a
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jul 29 20:38:53 2022 +0000
+
+    [repacker] add todo.
+
+ src/graph/pairpos-graph.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 14f95ee0cf0289fe1daffa9e10a9d0dfc8e0e6be
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jul 29 20:09:52 2022 +0000
+
+    [repacker] re-count shared node sizes in split PairPos segments.
+
+ src/graph/pairpos-graph.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 3b91fb2a9fa71da0000246bbd124b019c350ee43
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jul 29 20:04:42 2022 +0000
+
+    [repacker] cleanup todo.
+
+ src/graph/graph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a0b8893e467d39aabac96836c0b6afbccb14c68d
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jul 29 19:58:51 2022 +0000
+
+    [repacker] add Coverage sanitize.
+
+ src/Makefile.sources        |  2 ++
+ src/graph/coverage-graph.hh | 80 +++++++++++++++++++++++++++++++++++++++++++++
+ src/graph/pairpos-graph.hh  | 21 ++++++++----
+ src/harfbuzz-subset.cc      | 14 ++++----
+ src/meson.build             |  4 +++
+ 5 files changed, 108 insertions(+), 13 deletions(-)
+
+commit 38846f41d3760f9f70a7728b07c9829b776468a5
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jul 29 18:30:24 2022 +0000
+
+    [repacker] more TODO cleanup.
+
+ src/graph/gsubgpos-graph.hh | 3 ---
+ src/graph/pairpos-graph.hh  | 4 ++--
+ 2 files changed, 2 insertions(+), 5 deletions(-)
+
+commit 46c1fa7d1b0a58cce20dc5d51d314b4d8148c679
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jul 29 18:29:12 2022 +0000
+
+    [repacker] sanitize PairPos during subtable extension.
+
+ src/graph/gsubgpos-graph.hh | 12 ++++++++++--
+ src/graph/pairpos-graph.hh  | 34 ++++++++++++++++++++++++++++++++++
+ 2 files changed, 44 insertions(+), 2 deletions(-)
+
+commit 2a5902ee50e81ce00d48a9a686ff7fc39690b475
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jul 29 18:12:49 2022 +0000
+
+    [repacker] cleanup.
+
+ src/hb-repacker.hh | 60 +++++++++++++++++++++++++-----------------------------
+ 1 file changed, 28 insertions(+), 32 deletions(-)
+
+commit 674f0194a3d33ba192bef875cbb91bec6d008fe3
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jul 29 17:59:50 2022 +0000
+
+    [repacker] add extension pairpos split test.
+
+ src/test-repacker.cc | 27 ++++++++++++++++++++++++---
+ 1 file changed, 24 insertions(+), 3 deletions(-)
+
+commit 1d2516f03706d00b362edbb45604c6bc74d4c60a
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jul 29 17:57:18 2022 +0000
+
+    [repack] get basic pairpos split test working.
+
+ src/test-repacker.cc | 68 +++++++++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 51 insertions(+), 17 deletions(-)
+
+commit fb3f6ad7c020fcf9553d21916b04089a243a0bcd
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jul 29 00:25:19 2022 +0000
+
+    [repacker] ensure lookup map is updated when lookup memory location changes.
+
+ src/graph/graph.hh          | 6 +++---
+ src/graph/gsubgpos-graph.hh | 9 +++++++--
+ src/hb-repacker.hh          | 3 ++-
+ 3 files changed, 12 insertions(+), 6 deletions(-)
+
+commit 4e7360f78dbf70b95a98713e15ebb1c1a40687cc
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jul 28 22:56:47 2022 +0000
+
+    [repacker] begin adding tests for PairPosFormat1 splitting.
+
+ src/test-repacker.cc | 214 +++++++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 175 insertions(+), 39 deletions(-)
+
+commit f1bfb6585f96839f45633f856c290ebb3a0da1ea
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jul 28 21:01:41 2022 +0000
+
+    [repacker] cleanup debug prints.
+
+ src/graph/pairpos-graph.hh | 17 +++++++----------
+ 1 file changed, 7 insertions(+), 10 deletions(-)
+
+commit 65afed047db086bf28aef47ba43e6983ba088ba1
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jul 28 20:54:28 2022 +0000
+
+    [repacker] more bug fixes.
+
+ src/graph/graph.hh          | 14 ++++++++++++++
+ src/graph/gsubgpos-graph.hh |  8 ++++----
+ src/hb-repacker.hh          |  4 ++++
+ 3 files changed, 22 insertions(+), 4 deletions(-)
+
+commit 1002a3dcd3ac50894e8b4b82ae1daef6277be13d
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jul 28 20:17:36 2022 +0000
+
+    [repacker] bug fixes.
+
+ src/graph/graph.hh | 19 +++++++++++--------
+ 1 file changed, 11 insertions(+), 8 deletions(-)
+
+commit a5c2c8c1319fcc4d776496ebed05ed6c69060a96
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jul 28 01:27:55 2022 +0000
+
+    [repack] fix incorrect shrink.
+
+ src/graph/pairpos-graph.hh | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+commit d589ce68ea80b22eebdf29efca438b97f97c64a3
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jul 28 01:04:37 2022 +0000
+
+    [repacker] add extension subtable when needed while adding new PairPos table's.
+
+ src/graph/gsubgpos-graph.hh | 16 +++++++++++-----
+ 1 file changed, 11 insertions(+), 5 deletions(-)
+
+commit 5024d4de679d5ae0e4ec842c70e8e7a4ad7603f5
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jul 28 00:55:36 2022 +0000
+
+    [repack] more PairPos split implementation.
+
+ src/graph/gsubgpos-context.hh |  5 +++
+ src/graph/gsubgpos-graph.hh   | 82 ++++++++++++++++++++++++++++---------
+ src/graph/pairpos-graph.hh    | 94 ++++++++++++++++++++++++++++++-------------
+ 3 files changed, 135 insertions(+), 46 deletions(-)
+
+commit 510b8ab1012d7aafd77ce99e6679d968a6a56c60
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 27 23:30:20 2022 +0000
+
+    [repack] link new coverage in PairPosFormat1::clone_range.
+
+ src/graph/pairpos-graph.hh | 31 +++++++++++++++++++++++--------
+ 1 file changed, 23 insertions(+), 8 deletions(-)
+
+commit 29cb8818cde8fa928e5a3d0270a7160a4d7f9c2d
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 27 21:02:48 2022 +0000
+
+    [repacker] new coverage serialization in PairPosFormat1.
+
+ src/graph/graph.hh         |  2 +-
+ src/graph/pairpos-graph.hh | 30 +++++++++++++++++++++++++++++-
+ 2 files changed, 30 insertions(+), 2 deletions(-)
+
+commit 8d63f60e5b07985f16bdf619f954665e5eee77f4
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 27 20:36:20 2022 +0000
+
+    [repack] add graph_t::move_child helper function.
+
+ src/graph/graph.hh         | 41 +++++++++++++++++++++++++++++++++++++++++
+ src/graph/pairpos-graph.hh | 27 +++++++++++++++++++++++++--
+ 2 files changed, 66 insertions(+), 2 deletions(-)
+
+commit 8e5fffc44a9606b0aea459d3668762c127430101
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 27 20:00:00 2022 +0000
+
+    [repack] add helper to create new nodes.
+    
+    Switch to malloc'ing each node individually rather than trying to guess up front the total buffer space needed.
+
+ src/graph/gsubgpos-context.cc | 23 +++++++++++++++++------
+ src/graph/gsubgpos-context.hh | 12 +++++++-----
+ src/graph/gsubgpos-graph.hh   | 11 +++++------
+ src/hb-repacker.hh            |  7 +------
+ 4 files changed, 30 insertions(+), 23 deletions(-)
+
+commit bf0986c7d1263f28ac0aceb74de8e586a2add362
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 27 19:33:46 2022 +0000
+
+    [repack] sketch splitting mechanism for PairPosFormat1.
+
+ src/graph/pairpos-graph.hh | 60 ++++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 50 insertions(+), 10 deletions(-)
+
+commit f6a242b6050e8342c34eb458a696fcedb40de2e5
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 27 18:58:41 2022 +0000
+
+    [repacker] begin adding PairPos splitting support.
+
+ src/Makefile.am                                    |   2 +-
+ src/Makefile.sources                               |   4 +-
+ src/OT/Layout/GPOS/MarkArray.hh                    |   9 +-
+ src/OT/Layout/GPOS/PairValueRecord.hh              |   2 +
+ .../{gsubgpos-graph.cc => gsubgpos-context.cc}     |   4 +-
+ src/graph/gsubgpos-context.hh                      |  60 +++++++++++
+ src/graph/gsubgpos-graph.hh                        |  76 +++++++++-----
+ src/graph/pairpos-graph.hh                         | 110 +++++++++++++++++++++
+ src/harfbuzz-subset.cc                             |   2 +-
+ src/hb-repacker.hh                                 |  31 +++++-
+ src/meson.build                                    |   4 +-
+ 11 files changed, 268 insertions(+), 36 deletions(-)
+
+commit f3aff45e04a5a1c46267f7c806fe6d572be5c6a1
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jul 29 21:33:11 2022 +0000
+
+    [repacker] Update call to hb_subset_repack_or_fail in tests.
+
+ test/api/test-subset-repacker.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 69913e012e6031ea614f43f6088ae99907ce2427
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jul 29 20:45:56 2022 +0000
+
+    [repacker] Update repacker api method to take a table tag.
+    
+    This is needed to allow table specific optimizations to be performed during repacking.
+
+ src/hb-subset-repacker.cc | 10 ++++++++--
+ src/hb-subset-repacker.h  |  3 ++-
+ 2 files changed, 10 insertions(+), 3 deletions(-)
+
+commit 28c02b37684b41bf584ed81d910a448bdf9f706a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 29 15:55:16 2022 -0600
+
+    [ot-font] Minor simplification
+
+ src/hb-ot-font.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 149b03052055dc4eef88bbe6070199a3e1f3c276
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 29 12:41:30 2022 -0600
+
+    Fix thinko
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit bdbb8c297e4839e5bf44e35a0a410cf224ae945e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 29 12:04:28 2022 -0600
+
+    Add test for previous commit
+
+ ...estcase-minimized-hb-subset-fuzzer-5145429829877760 | Bin 0 -> 123110 bytes
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+
+commit f7677213d7e2637796eb61df3bce89e163821cf4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 29 11:57:57 2022 -0600
+
+    [SingleSubstFormat1] Don't close glyphs in degenerate cases
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5145429829877760
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+commit 3da50c50aa1e2290f5d49bd52290557cc9dfb588
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 29 11:40:33 2022 -0600
+
+    Remove unused const
+
+ src/hb-ot-layout-common.hh | 4 ----
+ 1 file changed, 4 deletions(-)
+
+commit 0c4495e5553b9ed44212321c5a970826649d2973
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Jul 29 13:22:18 2022 +0200
+
+    [meson] Don’t use f-string
+    
+    It requires Python 3.6+
+    https://github.com/harfbuzz/harfbuzz/pull/3760#issuecomment-1198972788
+
+ src/gen-harfbuzzcc.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e51526bf0664918c5a784bf777b526e47a9a7e87
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 28 09:53:30 2022 -0600
+
+    [CompositeGlyph] Add HB_NO_BEYOND_64K
+
+ src/OT/glyf/CompositeGlyph.hh | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+commit 6e6b9cf9723ac1c535085ef77e44965b22dbfd7c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 28 09:34:23 2022 -0600
+
+    [use-table] Adjust main() code
+
+ src/gen-use-table.py          | 5 +++--
+ src/hb-ot-shaper-use-table.hh | 5 +++--
+ 2 files changed, 6 insertions(+), 4 deletions(-)
+
+commit eaf7e5686c0d15f2308b35b43aaccdded9967216
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Jul 28 12:32:49 2022 +0200
+
+    [meson] Use pathlib in gen-harfbuzzcc.py
+
+ src/gen-harfbuzzcc.py | 21 +++++++++++----------
+ 1 file changed, 11 insertions(+), 10 deletions(-)
+
+commit 5df2347cf3feac0b59d4661725240d33aff38c73
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Jul 28 02:19:26 2022 +0200
+
+    [meson] Don’t tamper with paths in amalgam files
+    
+    Using os.path.basename() breaks files in subdirectories
+    (gsubgpos-graph.cc instead of graph/gsubgpos-graph.cc).
+    
+    Use paths relative to current source dir instead.
+
+ src/gen-harfbuzzcc.py  | 2 +-
+ src/harfbuzz-subset.cc | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 0c5b60acbd1c08c2afbb70849c0c0ee88c7abcbf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 27 14:00:06 2022 -0600
+
+    [use-table] Fix previous commit
+
+ src/gen-use-table.py          | 2 +-
+ src/hb-ot-shaper-use-table.hh | 6 ++----
+ 2 files changed, 3 insertions(+), 5 deletions(-)
+
+commit 0788f7737183d6a309798da7a5e3bcce8b7c8fa6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 27 13:58:44 2022 -0600
+
+    [use-table] Add a main() to print categories
+
+ src/gen-use-table.py          | 20 ++++++++++++++++++++
+ src/hb-ot-shaper-use-table.hh | 22 ++++++++++++++++++++++
+ 2 files changed, 42 insertions(+)
+
+commit 9aaa835ac17db5eb85c2c18d396eab633d2c9cbe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 27 12:24:43 2022 -0600
+
+    [use-table] Regenerate with latest packtab
+
+ src/hb-ot-shaper-use-table.hh | 477 +++++++++++++++++++++---------------------
+ 1 file changed, 239 insertions(+), 238 deletions(-)
+
+commit 3698ae25bfe3564af7304f7bfc9c56f3e212df83
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 26 14:41:34 2022 -0600
+
+    [harfbuzz-subset.cc] Update
+
+ src/harfbuzz-subset.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit e2cc34e1908c26efddbfd497b707c712583f8243
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 26 12:31:15 2022 -0600
+
+    [subset/GPOS] Fix a fuzzer timeout test
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5234369031176192
+
+ src/OT/Layout/GPOS/SinglePosFormat1.hh                  |   8 +++-----
+ ...testcase-minimized-hb-subset-fuzzer-5234369031176192 | Bin 0 -> 83705 bytes
+ 2 files changed, 3 insertions(+), 5 deletions(-)
+
+commit 241ebc93542c6ca1176456aa2951944cef8829a0
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Jul 26 00:04:20 2022 +0000
+
+    [repacker] fix include paths.
+
+ src/graph/graph.hh          | 6 +++---
+ src/graph/gsubgpos-graph.hh | 4 ++--
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+commit 5f4adb9bf37e19a0dfb8bbdc690406215bd76d85
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Jul 25 21:59:57 2022 +0000
+
+    [repacker] fix to lookup size comparison.
+
+ src/hb-repacker.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 6627204c4d241e01c7dae37679025019bb4bfc69
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Jul 25 21:56:37 2022 +0000
+
+    [repacker] Makefile fix.
+
+ src/Makefile.am | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f56e66f3f00d1f252d37d038b1f3c83e96eb6bdd
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Jul 25 21:55:03 2022 +0000
+
+    [repacker] for ext promotion choose lookups from highest subtables per byte to lowest.
+    
+    Attempts to roughly maximize the number of subtables that are non-ext.
+
+ src/Makefile.sources |  2 ++
+ src/hb-repacker.hh   | 49 ++++++++++++++++++++++++++++++++-----------------
+ src/test-repacker.cc |  1 +
+ 3 files changed, 35 insertions(+), 17 deletions(-)
+
+commit 9d0b2da51bc529f0690e64c8f2edbd63c54d27d9
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Jul 25 20:46:49 2022 +0000
+
+    [repacker] count subtable size in each group of consecutive layers for extension promotion decisions.
+    
+    Enforce that the following groups are all <64k in size:
+    - LookupList + Lookups
+    - Lookups + SubTables
+    - SubTables + Descendants
+
+ src/graph/graph.hh   |  7 +++++--
+ src/hb-repacker.hh   | 45 +++++++++++++++++++++++++++++++++------------
+ src/test-repacker.cc |  2 ++
+ 3 files changed, 40 insertions(+), 14 deletions(-)
+
+commit 3d37b9f4db848a4fb9d99d00b0bffff22c813cac
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Jul 25 20:11:24 2022 +0000
+
+    [repacker] when calculating 16bit space size also consider ext lookup subtables.
+
+ src/hb-repacker.hh | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+commit 9db3beb721bc472211220576a3ae7957fba21e18
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Jul 25 19:42:58 2022 +0000
+
+    [repacker] include LookupList size when calculating size of 16bit space for ext promotion decisions.
+
+ src/graph/graph.hh          |  4 ++++
+ src/graph/gsubgpos-graph.cc |  5 ++++-
+ src/graph/gsubgpos-graph.hh | 10 ++++++++--
+ src/hb-repacker.hh          |  6 +++++-
+ 4 files changed, 21 insertions(+), 4 deletions(-)
+
+commit e0607af9769d7f3727a1fe6bfe20671ad9fb216a
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Jul 25 19:16:03 2022 +0000
+
+    [repacker] Use extension promotion when repacking invoked via hb-subset-repacker (eg. from fonttools).
+
+ src/hb-subset-repacker.cc | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit 8d611a7fd06dc2600cb9f9c8b94d305285686f84
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jul 22 22:49:40 2022 +0000
+
+    [repacker] remove temporary visibility overrides in gsubgpos.
+
+ src/graph/gsubgpos-graph.hh  | 23 ++++++++++++++++-------
+ src/hb-ot-layout-gsubgpos.hh |  9 +++++++--
+ 2 files changed, 23 insertions(+), 9 deletions(-)
+
+commit 7de136f8a8d3ea2f24e2052f1173933faac62be6
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jul 22 21:04:34 2022 +0000
+
+    [repacker] add ext promotion test.
+
+ src/graph/gsubgpos-graph.hh |   2 +-
+ src/hb-repacker.hh          |   3 +
+ src/test-repacker.cc        | 137 ++++++++++++++++++++++++++++++++++++++++++--
+ 3 files changed, 135 insertions(+), 7 deletions(-)
+
+commit c38896e07c375f01de0b8b19d1168c633646a96a
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jul 21 23:12:15 2022 +0000
+
+    [repacker] todo.
+
+ src/hb-repacker.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit ad0041f5f7c222da45b17134b3eee85fcf0992d4
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jul 21 22:50:14 2022 +0000
+
+    [repacker] Add basic version of the extension promotion selection algorithm.
+
+ src/graph/graph.hh | 12 ++++++++++
+ src/hb-repacker.hh | 65 +++++++++++++++++++++++++++++++++++++++++++++---------
+ 2 files changed, 67 insertions(+), 10 deletions(-)
+
+commit 0b6ca424fc21f409496eb05d287f185566388282
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jul 21 21:57:17 2022 +0000
+
+    [repacker] fix GSTAR sanitize.
+
+ src/graph/gsubgpos-graph.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 11709f0fbe88e9fc624cdcf3206232d52ecb716b
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jul 21 21:54:42 2022 +0000
+
+    [repacker] support extension promotion in 24bit GSUB/GPOS.
+
+ src/graph/gsubgpos-graph.hh | 19 ++++++++++++++-----
+ src/hb-repacker.hh          |  2 +-
+ 2 files changed, 15 insertions(+), 6 deletions(-)
+
+commit b37374b04f49148ea6dfca2e5d147982492927b6
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jul 21 21:50:23 2022 +0000
+
+    [repacker] save buffer reference (not copy).
+
+ src/graph/gsubgpos-graph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ae290ff4fe399d5db6a347be2d0e2d096ccdc441
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jul 21 21:45:04 2022 +0000
+
+    [repacker] add sanitization for GSUB/LookupList/Lookup during extension promotion.
+
+ src/graph/graph.hh          |   1 -
+ src/graph/gsubgpos-graph.cc |  16 +++++
+ src/graph/gsubgpos-graph.hh | 146 +++++++++++++++++++++++++-------------------
+ src/graph/serialize.hh      |   1 -
+ src/hb-repacker.hh          |  22 ++++---
+ 5 files changed, 111 insertions(+), 75 deletions(-)
+
+commit ce03c3538a7aff303a6da31dcd53b3cf2e761557
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jul 21 19:07:55 2022 +0000
+
+    [repacker] add make_extension_context_t.
+
+ src/graph/graph.hh          |  4 +++
+ src/graph/gsubgpos-graph.cc | 41 +++++++++++++++++++++++++
+ src/graph/gsubgpos-graph.hh | 74 +++++++++++++++++++++++++++++----------------
+ src/hb-repacker.hh          | 38 +++++------------------
+ src/meson.build             |  3 +-
+ 5 files changed, 103 insertions(+), 57 deletions(-)
+
+commit ebb64b50da52b40ff19e5ea6ad39114ca1c684e2
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jul 21 18:36:20 2022 +0000
+
+    [repacker] size buffer correctly.
+
+ src/graph/gsubgpos-graph.hh | 74 +++++++++++++++++++++++++++------------------
+ src/hb-repacker.hh          | 24 +++++++++++++--
+ 2 files changed, 66 insertions(+), 32 deletions(-)
+
+commit 815bb82b4d1074d236382ce75b05fc69ef0c44ca
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 20 18:17:29 2022 +0000
+
+    [repack] fix incorrect extension object bounds.
+
+ src/graph/graph.hh          | 36 ------------------------------------
+ src/graph/gsubgpos-graph.hh |  9 +++++++--
+ 2 files changed, 7 insertions(+), 38 deletions(-)
+
+commit 7e6f6c3e88ba007e1c6a953e0b9f300a19fcb445
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 20 03:26:29 2022 +0000
+
+    [repack] fix new node bounds.
+
+ src/graph/graph.hh          |  1 +
+ src/graph/gsubgpos-graph.hh |  3 ++-
+ src/graph/serialize.hh      |  1 +
+ src/hb-repacker.hh          | 16 +++++++++++++---
+ 4 files changed, 17 insertions(+), 4 deletions(-)
+
+commit b1d38a6d0bc00094900bbce566975ceae2ecdd40
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Jul 19 23:33:16 2022 +0000
+
+    [repack] WIP implement extension promotion mechanism.
+
+ src/graph/graph.hh           |  38 +++++++++-
+ src/graph/gsubgpos-graph.hh  | 174 +++++++++++++++++++++++++++++++++++++++++++
+ src/hb-ot-layout-gsubgpos.hh |   2 +-
+ src/hb-repacker.hh           |   7 +-
+ 4 files changed, 216 insertions(+), 5 deletions(-)
+
+commit 3f7a74ff40c605d3310397f30866c3fdd9f34711
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Jul 19 21:50:13 2022 +0000
+
+    [repacker] WIP extension promotion implementation.
+
+ src/graph/graph.hh           | 51 ++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-ot-layout-common.hh   |  2 +-
+ src/hb-ot-layout-gsubgpos.hh |  2 +-
+ src/hb-repacker.hh           | 16 ++++++++++++++
+ 4 files changed, 69 insertions(+), 2 deletions(-)
+
+commit 1945b400da4bb9fbc50e51b3e61f5d0c171c11c0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 25 10:45:55 2022 -0600
+
+    [cpluscplus] Wrap hb-subset types as well
+    
+    Also changes signature of get_user_data of hb.h types to take const
+    object. This is safe.
+
+ src/hb-blob.cc             |  2 +-
+ src/hb-blob.h              |  2 +-
+ src/hb-buffer.cc           |  2 +-
+ src/hb-buffer.h            |  2 +-
+ src/hb-cplusplus.hh        | 23 ++++++++++++++++++++++-
+ src/hb-face.cc             |  2 +-
+ src/hb-face.h              |  2 +-
+ src/hb-font.cc             |  6 +++---
+ src/hb-font.h              |  6 +++---
+ src/hb-map.cc              |  2 +-
+ src/hb-map.h               |  2 +-
+ src/hb-set.cc              |  2 +-
+ src/hb-set.h               |  2 +-
+ src/hb-shape-plan.cc       |  4 ++--
+ src/hb-shape-plan.h        |  4 ++--
+ src/hb-unicode.cc          |  4 ++--
+ src/hb-unicode.h           |  4 ++--
+ test/api/test-cplusplus.cc |  1 +
+ 18 files changed, 47 insertions(+), 25 deletions(-)
+
+commit 1ac21246a751031823179377c3eef7ed3d4d5686
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 25 08:40:02 2022 -0600
+
+    [hb-ft] Fix bitmap font rendering with hb_ft_font_changed()
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3754
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3755
+
+ src/hb-ft.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 94de328011130f6d60493783d267ed8ae213a6d1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 24 18:51:55 2022 -0600
+
+    [GSUB/GPOS] Adjust buffer message
+
+ src/hb-ot-layout-gsubgpos.hh | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+commit bc80e4b9231ccb90746cebde24a7f24653b5a45a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 24 18:48:38 2022 -0600
+
+    [GSUB/GPOS] More buffer message for contextuals
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3753
+
+ src/hb-ot-layout-gsubgpos.hh | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+commit 59b05359cd7937d5cb12d02e6df8fd138eb7ec5f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 24 17:14:09 2022 -0600
+
+    [GSUB/GPOS] Add more buffer messages
+    
+    Behind HB_BUFFER_MESSAGE_MORE.
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3495
+
+ src/OT/Layout/GPOS/CursivePosFormat1.hh            | 14 +++++
+ src/OT/Layout/GPOS/MarkArray.hh                    | 14 +++++
+ src/OT/Layout/GPOS/PairPosFormat2.hh               | 13 +++++
+ src/OT/Layout/GPOS/PairSet.hh                      | 16 ++++++
+ src/OT/Layout/GPOS/SinglePosFormat1.hh             | 14 +++++
+ src/OT/Layout/GPOS/SinglePosFormat2.hh             | 14 +++++
+ src/OT/Layout/GSUB/AlternateSet.hh                 | 15 ++++++
+ src/OT/Layout/GSUB/Ligature.hh                     | 50 ++++++++++++++++++
+ .../Layout/GSUB/ReverseChainSingleSubstFormat1.hh  | 16 ++++++
+ src/OT/Layout/GSUB/Sequence.hh                     | 61 ++++++++++++++++++++++
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh           | 15 ++++++
+ src/OT/Layout/GSUB/SingleSubstFormat2.hh           | 15 ++++++
+ src/hb-debug.hh                                    |  5 ++
+ 13 files changed, 262 insertions(+)
+
+commit 0722b627f4461ec618544f4fb22739a790dd6d62
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 24 17:35:44 2022 -0600
+
+    [buffer] Return delta from sync_so_far
+
+ src/hb-buffer.cc | 5 ++++-
+ src/hb-buffer.hh | 2 +-
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+commit c55c01977101f999145594b950d4ea802e723ce7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Mar 21 19:11:17 2022 -0600
+
+    [buffer] Add assertions of buffer sync status to message_impl
+
+ src/hb-buffer.cc | 10 +++++++++-
+ src/hb-buffer.hh |  4 ----
+ 2 files changed, 9 insertions(+), 5 deletions(-)
+
+commit da9edce84c340d5495861aadc66d9d2797fafb7b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Mar 21 18:51:01 2022 -0600
+
+    [buffer] Add sync_so_far()
+    
+    This removes separate out-buffer, at the cost of possibly changing
+    idx.
+
+ src/hb-buffer.cc | 28 +++++++++++++++++++++++++++-
+ src/hb-buffer.hh |  3 ++-
+ 2 files changed, 29 insertions(+), 2 deletions(-)
+
+commit cbccadba8d1e51d6cc03a891b7c3a17f598e774c
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Jul 23 22:09:06 2022 +0200
+
+    5.0.1
+
+ NEWS             | 6 ++++++
+ configure.ac     | 2 +-
+ meson.build      | 2 +-
+ src/hb-version.h | 4 ++--
+ 4 files changed, 10 insertions(+), 4 deletions(-)
+
+commit 61d0c547010096e37ced5b8629a0638cceaefddb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 23 13:25:54 2022 -0600
+
+    [ft] Pass design, not normalized, coords to freetype
+    
+    Needed for avar2 to work.
+
+ src/hb-ft.cc            | 6 +++---
+ util/helper-cairo-ft.hh | 6 +++---
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+commit 473a5e5651f36cfade809f78e5322860fe4fc194
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 23 13:25:40 2022 -0600
+
+    [font] Fix design-coords
+    
+    Ouch!
+
+ src/hb-font.cc              | 4 ++++
+ src/hb-ot-var-fvar-table.hh | 6 +++++-
+ 2 files changed, 9 insertions(+), 1 deletion(-)
+
+commit efab763885d73376018dab07a7c4006ecdf4a6ac
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Jul 23 20:26:56 2022 +0200
+
+    [ci] Fix docs deployment
+    
+    Trigger build on tag pushes, and simplify the condition for calling
+    .ci/deploy-docs.sh.
+
+ .ci/deploy-docs.sh             | 5 -----
+ .github/workflows/linux-ci.yml | 3 ++-
+ 2 files changed, 2 insertions(+), 6 deletions(-)
+
+commit 40b21edf48932cde4df94f081959aa61386da3d5
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Jul 23 16:45:32 2022 +0200
+
+    5.0.0
+
+ NEWS                   | 41 +++++++++++++++++++++++++++++++++++++++++
+ configure.ac           |  2 +-
+ docs/harfbuzz-docs.xml |  1 +
+ meson.build            |  2 +-
+ src/hb-common.cc       |  2 +-
+ src/hb-subset.h        |  2 +-
+ src/hb-version.h       |  8 ++++----
+ 7 files changed, 50 insertions(+), 8 deletions(-)
+
+commit 4cb83967aacf0aaf2622fc55539f04eb9ce2b7a0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 23 10:59:42 2022 -0600
+
+    [subset/ClassDefFormat2] Fix timeout
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5417800474165248
+
+ src/hb-ot-layout-common.hh                               |   3 ++-
+ ...-testcase-minimized-hb-subset-fuzzer-5417800474165248 | Bin 0 -> 3161 bytes
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+commit 32c85b8c8c1994e318dce49b928a7298a0b23560
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 23 10:50:26 2022 -0600
+
+    [avar2] Fix mapping when coords length don't match
+    
+    Ouch.
+    
+    Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=49407
+
+ src/hb-ot-var-avar-table.hh                               |   3 +++
+ ...zz-testcase-minimized-hb-shape-fuzzer-4523349576908800 | Bin 0 -> 140 bytes
+ 2 files changed, 3 insertions(+)
+
+commit 06c3ec0a19e6f552275773fdd667229ccd9b1977
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 23 10:36:39 2022 -0600
+
+    [avar2] Minor sanitize rewrite
+
+ src/hb-ot-var-avar-table.hh | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+commit f94a3ba1db674591952fcae00864f97bd67713fa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 23 10:36:08 2022 -0600
+
+    [varStore] Better protect against HB_NO_VAR builds
+
+ src/hb-ot-layout-common.hh | 25 +++++++++++++++++++++++--
+ 1 file changed, 23 insertions(+), 2 deletions(-)
+
+commit 17863bd16bc82c54fb68627cbf1e65702693dd09
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 22 22:38:08 2022 -0600
+
+    [config/avar2] add HB_NO_VARIATIONS2
+
+ src/hb-config.hh            |  1 +
+ src/hb-ot-var-avar-table.hh | 14 +++++++++++---
+ 2 files changed, 12 insertions(+), 3 deletions(-)
+
+commit 5a9c7930efc8ec055f60cae5ec2567ff8de0e972
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 22 21:33:15 2022 -0600
+
+    Add HB_NO_BEYOND_64K
+
+ src/hb-config.hh               |  4 ++++
+ src/hb-ot-hmtx-table.hh        |  2 +-
+ src/hb-ot-layout-common.hh     | 26 +++++++++++++-------------
+ src/hb-ot-layout-gdef-table.hh | 32 ++++++++++++++++----------------
+ src/hb-ot-layout-gsubgpos.hh   | 40 ++++++++++++++++++++--------------------
+ src/hb-ot-var-avar-table.hh    |  2 +-
+ src/hb-static.cc               |  4 ++--
+ 7 files changed, 57 insertions(+), 53 deletions(-)
+
+commit c76fd3c5f9fca4fc095031ce41d35b6d04d8ebfa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 22 15:29:38 2022 -0600
+
+    [avar2] Add link to "Spec".
+
+ src/hb-ot-var-avar-table.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit edca52c3b644f6ebc90eeeb307ed3e87a7245348
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 22 15:17:32 2022 -0600
+
+    [avar2] Use a varStore cache
+
+ src/hb-ot-var-avar-table.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 59f8afa73e3e0e1a7e3db5ffab06014dad5fd151
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 22 15:12:21 2022 -0600
+
+    [avar2] Remove XXX item
+
+ src/hb-ot-var-avar-table.hh | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit d6c4f757a4bfeabfea35804103cfce10650a101e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 29 11:09:54 2022 -0600
+
+    [avar2] Clamp out values
+
+ src/hb-ot-var-avar-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d0e2ad9297053635b65d0ad4c97c49f14f0cccee
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 28 21:19:15 2022 -0600
+
+    [avar] Pre-alloc vector
+
+ src/hb-ot-var-avar-table.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 2a877b554a4377f1c973ed007ae17ff5448483d1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 28 17:10:10 2022 -0600
+
+    [avar2] First stab at mapping v2 values
+
+ src/hb-ot-var-avar-table.hh | 28 +++++++++++++++++++++++++++-
+ 1 file changed, 27 insertions(+), 1 deletion(-)
+
+commit c3eb6713e90340109e1084924945d570e52bbe28
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 28 16:42:28 2022 -0600
+
+    [avar2] Add v2 structure and sanitize
+
+ src/hb-ot-var-avar-table.hh | 32 +++++++++++++++++++++++++++++++-
+ 1 file changed, 31 insertions(+), 1 deletion(-)
+
+commit c9e843942e39fb053cc5c05df85603720cbcbc2e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 22 09:01:07 2022 -0600
+
+    [min/max] Don't forward argument
+
+ src/hb-algs.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 7a219ca9f0f8140906cb7fd3b879b5bf5259badc
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Jul 22 14:18:59 2022 +0200
+
+    [ci] Install glib-utils on macOS
+    
+    The glib utils have been split into a separate homebrew package.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3747
+
+ .github/workflows/macos-ci.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit cb5ca6be29ef61d13b2d0dae7cf3fbf740ae20ec
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 22 05:48:27 2022 -0600
+
+    [ft] Actually call check_changed() from _changed()
+    
+    Ouch!
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3746
+
+ src/hb-ft.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit fd535a240bf56afcb4787c2038b0e33b4a6ddba3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 22 05:48:12 2022 -0600
+
+    [ft] Remove check_changed from get_glyph_shape()
+    
+    Leftover.
+
+ src/hb-ft.cc | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit 7cdde6a24174ea2f29da141bcb265feb9b15eb2b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 17:17:59 2022 -0600
+
+    [ClassDef] Write a loop as range for
+
+ src/hb-ot-layout-common.hh | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+commit 0cc2f3c218ec60377ef284ab0cded150fc57650a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 16:46:45 2022 -0600
+
+    [algs] Remove hb_pair_t()
+
+ src/hb-algs.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 9eab3ac72dc9cbd404da3dc4ef82b798d5e42c0e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 12:35:19 2022 -0600
+
+    [CoverageFormat2] Remove hand-written loop
+    
+    While on a fuzzer-found test case (added) that loop was faster,
+    on real fonts, including NotoNastaliq in our benchmark, it was
+    actually slower, which intuitively I would have expected.
+    
+    Still no idea why on that fuzzer case it's faster though. :(
+
+ src/OT/Layout/Common/CoverageFormat2.hh            |  35 +++------------------
+ ...ase-minimized-hb-subset-fuzzer-4549523149553664 | Bin 0 -> 66032 bytes
+ 2 files changed, 5 insertions(+), 30 deletions(-)
+
+commit bbb4db90dd2f24b237c3bbcf6ab24389f970d1b8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 12:34:46 2022 -0600
+
+    [Coverage/SingleSubst] Move hand-written loop to Coverage
+
+ src/OT/Layout/Common/CoverageFormat2.hh  | 35 ++++++++++++++++++++++++-----
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 38 ++++++--------------------------
+ 2 files changed, 37 insertions(+), 36 deletions(-)
+
+commit 7b95783efb36e35cc6acf579e4bb88bcefd50ae9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 12:18:51 2022 -0600
+
+    [Coverage] Internal rename
+
+ src/OT/Layout/Common/Coverage.hh        | 6 +++---
+ src/OT/Layout/Common/CoverageFormat1.hh | 6 +++---
+ src/OT/Layout/Common/CoverageFormat2.hh | 6 +++---
+ 3 files changed, 9 insertions(+), 9 deletions(-)
+
+commit afa65f2903b2a1d32bbb70d445666b9343c86837
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 12:17:08 2022 -0600
+
+    [Coverage] Minor type change
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b38587aa0ba3521c2b6aa22594e46e026035f70b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 12:14:06 2022 -0600
+
+    [Coverage] Internal renames
+
+ src/OT/Layout/Common/Coverage.hh        | 16 ++++++++--------
+ src/OT/Layout/Common/CoverageFormat1.hh |  5 ++---
+ src/OT/Layout/Common/CoverageFormat2.hh |  7 +++----
+ 3 files changed, 13 insertions(+), 15 deletions(-)
+
+commit 84d38df828e69e6ac1a796fc0460ba33e3bd3f29
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 12:12:04 2022 -0600
+
+    [Coverage] Minor use range-based loop
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+commit b017b73ffe0e24bf7c621592ee3c31cc209a2155
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 12:06:55 2022 -0600
+
+    [Coverage] Minor remove a couple unnecessary as_array()'s
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 9e650b4e0cd0571caf9e67f0186ea3690e615710
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 12:01:52 2022 -0600
+
+    [Coverage] Speedup intersect_set
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit efa388074d76339c2dc80fec675c6dbbb6511c91
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 11:52:36 2022 -0600
+
+    [subset/SingleSubsetFormat1] Use Coverage.intersect_set
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 12 +++++-------
+ 1 file changed, 5 insertions(+), 7 deletions(-)
+
+commit 00dfbbce1c65c2e709b3ffaac45d234bdd02528d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 11:39:32 2022 -0600
+
+    [Coverage] Rename and templatize intersected_coverage_glyphs
+
+ src/OT/Layout/Common/Coverage.hh         | 12 ++++++-----
+ src/OT/Layout/Common/CoverageFormat1.hh  |  8 +++++---
+ src/OT/Layout/Common/CoverageFormat2.hh  | 12 ++++++-----
+ src/OT/Layout/Common/RangeRecord.hh      |  4 ++--
+ src/OT/Layout/GPOS/SinglePosFormat1.hh   |  2 +-
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh |  2 +-
+ src/hb-ot-layout-common.hh               |  6 +++---
+ src/hb-ot-layout-gsubgpos.hh             | 35 ++++++++++++++++----------------
+ 8 files changed, 43 insertions(+), 38 deletions(-)
+
+commit d0eb273791814b36d3a9298caf99f60bef857dc3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 11:24:56 2022 -0600
+
+    [subset/GSUB/GPOS] Use more intersected_coverage_glyphs()
+
+ src/OT/Layout/GPOS/SinglePosFormat1.hh   |  6 ++++--
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 34 ++------------------------------
+ 2 files changed, 6 insertions(+), 34 deletions(-)
+
+commit 450d834679738820e1d9afa579de125bb8087dbf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 11:05:35 2022 -0600
+
+    [subset/PairPosFormat1] Speed up significantly
+
+ src/OT/Layout/GPOS/SinglePosFormat1.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 5d7556e1841bafc851d043bb9d0195651edb0ce3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 10:42:29 2022 -0600
+
+    Revert "[subst/SingleSubstFormat1] Rewrite nicer"
+    
+    This reverts commit bababe10724c27b2cbb09bf25e7dcf4aeea07588.
+    
+    The hand-written code is still much faster :(.
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 64 +++++++++++++++++++++++++-------
+ 1 file changed, 50 insertions(+), 14 deletions(-)
+
+commit 71ce931e6ddbb7ba31b9ec3243d3c09eda251ff1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 10:41:29 2022 -0600
+
+    [PairPos] Don't compute newFormat
+    
+    It was wrong, because it would be writing wrong values.
+    
+    Test suite doesn't seem to catch any.
+
+ src/OT/Layout/GPOS/SinglePos.hh             | 3 ---
+ src/OT/Layout/GSUB/AlternateSubstFormat1.hh | 1 -
+ 2 files changed, 4 deletions(-)
+
+commit 02ca02544348edc9d89f436ed2000f4ba4f50231
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 10:30:23 2022 -0600
+
+    [layout] Add large_int to Types
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 6 +++---
+ src/OT/Layout/types.hh                  | 2 ++
+ 2 files changed, 5 insertions(+), 3 deletions(-)
+
+commit bababe10724c27b2cbb09bf25e7dcf4aeea07588
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 10:25:27 2022 -0600
+
+    [subst/SingleSubstFormat1] Rewrite nicer
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 64 +++++++-------------------------
+ 1 file changed, 14 insertions(+), 50 deletions(-)
+
+commit cf123e6a0dae59131b028676ed919c5a09dae919
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 10:21:57 2022 -0600
+
+    [Coverage] Add get_population ()
+
+ src/OT/Layout/Common/Coverage.hh        | 13 +++++++++++++
+ src/OT/Layout/Common/CoverageFormat1.hh |  5 +++++
+ src/OT/Layout/Common/CoverageFormat2.hh |  8 ++++++++
+ src/OT/Layout/Common/RangeRecord.hh     |  6 ++++++
+ 4 files changed, 32 insertions(+)
+
+commit 2ad3c0c7709fe07122934e4842225f55267ce84c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 09:46:25 2022 -0600
+
+    Fix uninitialized variable
+
+ src/hb-ot-map.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit fa471043fccb94444510e3300ac2573297c82137
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 22:42:18 2022 -0600
+
+    [subset] Fix previous commit
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c4d2ef90047e8b6747adcf99a42984730979fbc3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 22:36:35 2022 -0600
+
+    [subset] Speed up subsetting of SingleSubstFormat1_3
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 36 ++++++++++++++++++++++++++++++--
+ 1 file changed, 34 insertions(+), 2 deletions(-)
+
+commit d01e6babe6660ca5ac3b941b1e977af9dcda954f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 22:17:33 2022 -0600
+
+    [subset] Speed up SingleSubstFormat1_3 closure
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 38 +++++++++++++++++++++++++++-----
+ 1 file changed, 33 insertions(+), 5 deletions(-)
+
+commit 0f800769379d05a3086cd3fc56f0c4c1a19076f8
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Jul 20 14:59:02 2022 -0700
+
+    [subset] Do not repeat COLR table closure
+
+ src/hb-subset-plan.cc | 24 +++++++++---------------
+ 1 file changed, 9 insertions(+), 15 deletions(-)
+
+commit 9fc31db6faa29eeac734bbb3196dbce2eabaa4c7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 16:03:02 2022 -0600
+
+    [blob] Initialize members if ever on the stack
+
+ src/hb-blob.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit 60a9175f2c711e5b1b76b25c8121440177848513
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 15:59:46 2022 -0600
+
+    [blob] Remove fini_shallow()
+
+ src/hb-blob.cc | 2 --
+ src/hb-blob.hh | 2 +-
+ 2 files changed, 1 insertion(+), 3 deletions(-)
+
+commit bcd59b5142d6c8bee71c252c8f44240542ab9dab
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 15:57:09 2022 -0600
+
+    [set/map] Remove init_shallow/fini_shallow()
+
+ src/hb-map.hh | 18 ++++++------------
+ src/hb-set.hh |  6 ++----
+ 2 files changed, 8 insertions(+), 16 deletions(-)
+
+commit 79b23cc25d1e029ce87676a13a41f2ff8c6b980c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 15:38:34 2022 -0600
+
+    Fix another leak
+
+ src/hb-shape-plan.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 3fad942ee21f7e5bbb29b2c5af6b1c3b77f484dd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 15:26:32 2022 -0600
+
+    Try fix leak
+
+ src/hb-ot-shape.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit e1b5f2f806f4aafec5eaa26cb528622e7e0b1606
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 15:03:20 2022 -0600
+
+    [object] Call destructor in hb_object_destroy()
+
+ src/hb-map.cc         | 2 --
+ src/hb-map.hh         | 2 +-
+ src/hb-object.hh      | 5 ++++-
+ src/hb-set.cc         | 2 --
+ src/hb-shape-plan.cc  | 4 ----
+ src/hb-subset-plan.cc | 2 --
+ 6 files changed, 5 insertions(+), 12 deletions(-)
+
+commit 9ea4ab60514d5f22d360a0a199cf8a126adf5e18
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 14:57:32 2022 -0600
+
+    [object] Call constructor
+
+ src/hb-font.cc   | 1 +
+ src/hb-map.cc    | 2 --
+ src/hb-map.hh    | 2 --
+ src/hb-object.hh | 3 +++
+ src/hb-set.cc    | 2 --
+ 5 files changed, 4 insertions(+), 6 deletions(-)
+
+commit 61c04384256390d3ef5d0fd576bd2bc2fb34624e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 14:43:58 2022 -0600
+
+    [map] Allow geting non-const value pointer out with has()
+
+ src/hb-map.hh   | 3 ++-
+ src/test-map.cc | 4 ++++
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+commit 00cfc5c17d3b792a579356ca998e361bcb414260
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 14:38:28 2022 -0600
+
+    [map] Don't set out value in has() if not found
+
+ src/hb-map.hh | 6 ------
+ 1 file changed, 6 deletions(-)
+
+commit 485f043211ad21d6b0d926505f41c772330890a1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 14:34:55 2022 -0600
+
+    [map] Enable using hashmap with unique_ptr
+
+ src/hb-map.hh   | 11 +++++++++++
+ src/test-map.cc |  6 ++++++
+ 2 files changed, 17 insertions(+)
+
+commit 53fd4c92368abe260673649330e5eb19e9df7a60
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 13:33:49 2022 -0600
+
+    [set] A variable rename
+
+ src/hb-bit-page.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 6826b2c3fdd881a98bd0eb3be5c114bda0282bbe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 13:25:34 2022 -0600
+
+    [gsubgpos/closure] Minor condition use bool operator
+
+ src/hb-ot-layout-gsubgpos.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 55a1e0bb1195332414acc2f832600269894e2f7b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 13:10:28 2022 -0600
+
+    [ot-map] Use hb_array for a return value
+
+ src/hb-ot-map.hh          | 14 +++++---------
+ src/hb-ot-shaper-indic.cc | 12 +++++-------
+ 2 files changed, 10 insertions(+), 16 deletions(-)
+
+commit a92d988d3d793f1f5660b443de301eedd715fd7d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 13:01:29 2022 -0600
+
+    Revert "[ci] Upgrade codecov-action to v3.1"
+    
+    This reverts commit 5b8bff8dca3a81de02878c596f3721d268d29bb4.
+
+ .github/workflows/linux-ci.yml | 2 +-
+ .github/workflows/macos-ci.yml | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 5b8bff8dca3a81de02878c596f3721d268d29bb4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 12:59:36 2022 -0600
+
+    [ci] Upgrade codecov-action to v3.1
+
+ .github/workflows/linux-ci.yml | 2 +-
+ .github/workflows/macos-ci.yml | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 8d923363dbc7738d0c53a1f78e9407c24010ac53
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 12:08:18 2022 -0600
+
+    [layout] Reduce number of closure rounds
+
+ src/hb-ot-layout-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 2eb561ebead8276c6c905e33585d4aa216a25b41
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 12:02:38 2022 -0600
+
+    [ci] Upgrade macos runner from 10.15 to latest (11)
+
+ .github/workflows/macos-ci.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit aae8c74e0551fd889f041a0c0cce708f8fab0c5a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 11:51:09 2022 -0600
+
+    [>64k:layout:SingleSubstFormat3] Fix masking
+    
+    https://github.com/be-fonts/boring-expansion-spec/issues/31
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 30 +++++++++++++++++++-----------
+ 1 file changed, 19 insertions(+), 11 deletions(-)
+
+commit 3c137ef041850150d54e4817388cdcdc3a3ff0bc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 11:29:30 2022 -0600
+
+    [GPOS/CursivePos] Fix unsafe-to-break marking
+    
+    Fixes test.
+
+ src/OT/Layout/GPOS/CursivePosFormat1.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 7050021fedf549e11056f37cec7234238e7cd7e8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 11:27:12 2022 -0600
+
+    [cursive-positioning.tests] Fix test specification
+    
+    Still failing. Figuring out.
+
+ test/shape/data/in-house/tests/cursive-positioning.tests | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+commit 5998cd00c83864d76788f1a7ee47f4b429ecc866
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 11:16:32 2022 -0600
+
+    [hebrew] Break out of reordering loop when pattern found
+
+ src/hb-ot-shaper-hebrew.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 42f1d7794b9b4e46cf45de6d6e8139667f1c18bd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 11:13:16 2022 -0600
+
+    Add tests for multiple cursive positioning
+    
+    From https://github.com/harfbuzz/harfbuzz/issues/2469
+
+ .../fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf   | Bin 0 -> 1076 bytes
+ test/shape/data/in-house/tests/cursive-positioning.tests |  11 +++++++++++
+ 2 files changed, 11 insertions(+)
+
+commit d861303797e09f202acfe19740ceafdc7726b1b7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 10:57:12 2022 -0600
+
+    [hebrew] Comment
+
+ src/hb-ot-shaper-hebrew.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c60d810d509e16bf29fa7399d35c173b17c924c3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 10:24:54 2022 -0600
+
+    [hebrew] Implement Jerusalem mark reordering
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/2947
+
+ src/hb-ot-shaper-hebrew.cc | 27 ++++++++++++++++++++++++++-
+ 1 file changed, 26 insertions(+), 1 deletion(-)
+
+commit 605bb1ee3dd1d6ef19676be0194d001c21533d60
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Jul 19 21:15:21 2022 +0200
+
+    [subset] Add amalgam harfbuzz-subset.cc
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3733
+
+ .circleci/config.yml   |  2 +-
+ src/Makefile.am        | 14 ++++++++++++-
+ src/gen-harfbuzzcc.py  |  4 +++-
+ src/harfbuzz-subset.cc | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/harfbuzz.cc        | 18 ++++++++--------
+ src/meson.build        |  8 ++++++++
+ 6 files changed, 90 insertions(+), 12 deletions(-)
+
+commit a66ba594b4a31a85de8960b2ddf294aaea2348e8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 19 16:32:32 2022 -0600
+
+    [util] Fix stack-underflow
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3737
+
+ util/hb-subset.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c6ef11daf51bba4e06c4eabbc387b1058e8ce8ab
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 19 15:19:52 2022 -0600
+
+    [util] Fix build with HB_NO_VAR
+
+ util/font-options.hh    | 10 ++++++++++
+ util/helper-cairo-ft.hh |  2 +-
+ 2 files changed, 11 insertions(+), 1 deletion(-)
+
+commit 712bfa8872532b19e6c5be9bf16c9bee36b50922
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Jul 19 13:57:14 2022 -0700
+
+    build fix for HB_NO_VAR
+
+ src/hb-subset-plan.cc | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit 798a0c8a58852d1eb177db9054ead9e897672175
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 19 14:40:47 2022 -0600
+
+    Fix build
+
+ src/hb-ot-layout-gdef-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 8737dea4d9012ea4636db12274532c5f3c6abb40
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 19 14:39:47 2022 -0600
+
+    [>64k:layout:GDEF] Implement version 2
+    
+    Implements https://github.com/be-fonts/boring-expansion-spec/issues/36
+    
+    Subset does NOT lower format.
+
+ src/hb-ot-layout-gdef-table.hh | 48 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 48 insertions(+)
+
+commit 8080e01afc86fe4921c8fa87c85134f076f40675
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 19 14:35:58 2022 -0600
+
+    [>64k:layout] Templatize GDEFVersion1
+
+ src/hb-ot-layout-gdef-table.hh | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+commit 1665cf6bc4ac1c57d2e43070cd0aeab7c562e2bc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 19 13:56:23 2022 -0600
+
+    [>64k:layout] Split GDEFVersion1
+    
+    https://github.com/be-fonts/boring-expansion-spec/issues/36
+
+ src/hb-ot-layout-gdef-table.hh | 315 ++++++++++++++++++++++++++++-------------
+ src/hb-ot-layout-gsubgpos.hh   |   1 -
+ 2 files changed, 213 insertions(+), 103 deletions(-)
+
+commit 1de5591cf743a789b240b1c1f8536d909f63a857
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 19 13:37:30 2022 -0600
+
+    [>64k:layout] Prepare GDEF for templatizing
+    
+    https://github.com/be-fonts/boring-expansion-spec/issues/36
+
+ src/hb-ot-layout-gdef-table.hh | 41 +++++++++++++++++++++++------------------
+ src/main.cc                    |  8 ++++----
+ 2 files changed, 27 insertions(+), 22 deletions(-)
+
+commit c0d60bd4964701402aacf98390e0936c9dcba953
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Jul 19 18:21:09 2022 +0200
+
+    [meta] Fix warning with emscripten
+    
+    For whatever reason, em++ takes the first branch and spouts a gazillion
+    warnings like:
+    
+    ./harfbuzz/src/hb-vector.hh:229:20: warning: builtin __has_trivial_assign is deprecated; use __is_trivially_assignable instead [-Wdeprecated-builtins]
+                hb_enable_if (hb_is_trivially_copy_assignable(T))>
+                              ^
+    ./harfbuzz/src/hb-meta.hh:193:44: note: expanded from macro 'hb_is_trivially_copy_assignable'
+
+ src/hb-meta.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 91c60802e646ee10daa8eda0ab2d2ea06206cc41
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 22:24:28 2022 -0600
+
+    [open-type] Fix overflow check
+    
+    Without the cast, the compiler is within its rights to reason that
+    overflow didn't happen and optimize away the check, as clang was.
+
+ src/hb-open-type.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 4279304a627d467866aac751548e728eaa841b73
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 22:20:06 2022 -0600
+
+    [stat] Fix double-promotion warnings
+
+ src/hb-ot-stat-table.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 54e9ab4a91a762dc8a730e22a5b103b206b05db7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 18:57:14 2022 -0600
+
+    [GPOS/Cursive] Fix breaking of parent-child attachment
+    
+    Mostly fixes https://github.com/harfbuzz/harfbuzz/issues/2469
+
+ src/OT/Layout/GPOS/CursivePosFormat1.hh | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit c2baf2796cd1c2de60788897502bd42905c78cb0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 15:41:20 2022 -0600
+
+    [arabic] Make more features F_MANUAL_ZWJ
+    
+    The change to `ccmp` fixes shaping of certain sequences with
+    Calibri on Windows 11.  Addition of `liga` and `clig` is
+    speculative.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3530
+
+ src/hb-ot-shaper-arabic.cc | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+commit ddeef8c87548a57356ec72c3ed6d277c916330c7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 15:13:47 2022 -0600
+
+    [test-ot-glyphname] Fix return value
+
+ src/test-ot-glyphname.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f1a69ff1b94a4fd4de69fddcbc80fba6f819e16b
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Jun 30 16:22:15 2022 -0700
+
+    [instance] update scripts for testing instancing
+
+ ...lt.retain-all-codepoint.wght=400,wdth=100.0.ttf | Bin 0 -> 6584 bytes
+ ...ult.retain-all-codepoint.wght=drop,wdth=100.ttf | Bin 0 -> 6584 bytes
+ test/subset/data/fonts/Roboto-Variable.ABC.ttf     | Bin 0 -> 13480 bytes
+ test/subset/data/tests/pin_all_at_default.tests    |  12 ++++++++
+ test/subset/generate-expected-outputs.py           |  25 ++++++++++++++--
+ test/subset/run-tests.py                           |   3 ++
+ test/subset/subset_test_suite.py                   |  32 +++++++++++++++++----
+ 7 files changed, 65 insertions(+), 7 deletions(-)
+
+commit be8e8e8c80cc69d9d3a02f357a3ef252738d96e6
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Jun 30 14:24:36 2022 -0700
+
+    [instance] prune name tables after axes pinned at fixed locations
+    
+    Restricting axes to ranges is not supported yet.
+
+ src/hb-ot-stat-table.hh     | 19 +++++++++++++++-
+ src/hb-ot-var-fvar-table.hh | 53 +++++++++++++++++++++++++++++++++------------
+ src/hb-subset-plan.cc       | 11 ++++++----
+ 3 files changed, 64 insertions(+), 19 deletions(-)
+
+commit df55f840cb4cf2d5cfe9e93e289aa59e7d592f7f
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Jun 30 09:36:19 2022 -0700
+
+    [instance] instantiate STAT table when axes are pinned at fixed locations
+    
+    restricting ranges is not supported yet.
+
+ src/hb-ot-stat-table.hh | 235 ++++++++++++++++++++++++++++++++++++++++++++----
+ src/hb-subset-input.cc  |  11 +--
+ src/hb-subset-plan.cc   |  10 +++
+ src/hb-subset-plan.hh   |   2 +
+ src/hb-subset.cc        |   6 ++
+ 5 files changed, 236 insertions(+), 28 deletions(-)
+
+commit 2a4773e43d528343a1b4a305905d275ba5eda829
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Jun 21 19:29:52 2022 -0700
+
+    add option "--instance", store axes_location in subset_plan and drop all
+    variation tables when all axes are pinned at default
+
+ src/gen-def.py              |  4 ++-
+ src/hb-map.hh               | 24 +++++++++++++
+ src/hb-ot-var-avar-table.hh |  8 +++++
+ src/hb-ot-var-fvar-table.hh |  2 ++
+ src/hb-subset-input.cc      | 65 ++++++++++++++++++++++++++++++++++-
+ src/hb-subset-input.hh      |  4 ++-
+ src/hb-subset-plan.cc       | 84 ++++++++++++++++++++++++++++++---------------
+ src/hb-subset-plan.hh       |  3 ++
+ src/hb-subset.cc            | 10 ++++++
+ src/hb-subset.h             | 15 ++++++++
+ util/hb-subset.cc           | 78 +++++++++++++++++++++++++++++++++++++++++
+ 11 files changed, 267 insertions(+), 30 deletions(-)
+
+commit 5744e951fc5e647c42a8e75652d2a32c7479fc1f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 14:54:44 2022 -0600
+
+    [gir] Skip graphite API
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/2557
+
+ src/hb-graphite2.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 1eb8e820864771509b7aed4ce76a83e8cd2272b0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 14:47:49 2022 -0600
+
+    [util] Accept space as delimiter for --features/--variations
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3715
+
+ util/font-options.hh  | 4 ++--
+ util/shape-options.hh | 4 ++--
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit 378663409ac9d2a54d8a738c88a76a5b9873181f
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Jul 18 21:02:41 2022 +0200
+
+    [ci] Deploy docs only on tagged builds
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/2786
+
+ .ci/deploy-docs.sh | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+commit 3723b8544b63d4eb95ff1448e4ebfc6a25127360
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 14:00:14 2022 -0600
+
+    [cff] Better max op counting
+
+ src/hb-cff-interp-cs-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3c84aa8416cac7aba1430cc18ec76a393c47f3cd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 13:57:59 2022 -0600
+
+    [cff] Add a max work counter
+    
+    Set to 10,000 per interpretation right now.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3700
+    Fixes https://oss-fuzz.com/testcase-detail/5667125715927040
+
+ src/hb-cff-interp-cs-common.hh                            |   7 +++++++
+ ...uzz-testcase-minimized-hb-draw-fuzzer-5667125715927040 | Bin 0 -> 472 bytes
+ test/fuzzing/hb-draw-fuzzer.cc                            |   1 +
+ 3 files changed, 8 insertions(+)
+
+commit 89de8c700f16bd50617c20a81b77c6555f3a8988
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 13:07:29 2022 -0600
+
+    [CoverageFormat2] Another fix for broken tables
+    
+    Fixes https://oss-fuzz.com/testcase-detail/6005342714068992
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit faac252f9f6876d971c7d487f064261eb6070952
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 12:23:57 2022 -0600
+
+    [util/hb-ot-shape-closure] Fix showing glyph names
+
+ util/hb-ot-shape-closure.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 38f2ec1703655d1527170c6e48f2647047716d46
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 12:17:08 2022 -0600
+
+    [hb-shape] Move shape_output_t into separate file
+
+ util/Makefile.sources |   1 +
+ util/hb-shape.cc      | 126 +--------------------------------------
+ util/shape-output.hh  | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 161 insertions(+), 125 deletions(-)
+
+commit 94be45980883bea99bb1028445c6ab7100c11409
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 12:13:48 2022 -0600
+
+    [hb-shape] Internal rename
+
+ util/hb-shape.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 4f22397f05f8b0b65897e58a0176c8fa9b85f2a4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 11:03:54 2022 -0600
+
+    [ft] A couple of introspection fixes
+
+ src/hb-ft.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit faa8cdc89877888fbcc182b368490f64a721b067
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 10:22:19 2022 -0600
+
+    [util] Allow HB_CHAFA=2/3 to enable wedges/all symbols in Chafa
+
+ util/helper-cairo-ansi.hh | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+commit b4e95965c8b9b508aca2afdc7483b89d4a56eb99
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 10:14:14 2022 -0600
+
+    [util] Revert Chafa to use simple blocks only
+    
+    The wedges are nice but not available on Mac.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3729
+
+ util/helper-cairo-ansi.hh | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+commit f7f6d278bb166942c9a87fd7cefbd7fa294a0ba2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 22:15:42 2022 -0600
+
+    Add hb_language_matches()
+    
+    New API:
+    + hb_language_matches()
+
+ docs/harfbuzz-sections.txt      |  1 +
+ src/hb-aat-layout-morx-table.hh |  2 +-
+ src/hb-common.cc                | 32 ++++++++++++++++++++++++++++++++
+ src/hb-common.h                 |  3 +++
+ src/hb-ot-name-table.hh         | 14 +++++---------
+ src/hb-ot-tag.cc                |  2 ++
+ 6 files changed, 44 insertions(+), 10 deletions(-)
+
+commit d57ce30054ec7bf03fe27fa9bbb3c2e6963e05d6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 21:56:56 2022 -0600
+
+    [ot-shape] Pass reference to props instead of pointer
+    
+    Since cannot be nullptr.
+
+ src/hb-aat-map.hh  |  4 ++--
+ src/hb-ot-map.cc   |  4 ++--
+ src/hb-ot-map.hh   |  2 +-
+ src/hb-ot-shape.cc | 10 +++++-----
+ src/hb-ot-shape.hh |  2 +-
+ 5 files changed, 11 insertions(+), 11 deletions(-)
+
+commit a972d05d7eea86516d98d494f99b1b0ce719e260
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 21:42:04 2022 -0600
+
+    [aat] Fix build
+
+ src/hb-aat-layout-morx-table.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit a5dad50072e1881a5fc7595cfbe4942534d2ea5a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 21:39:24 2022 -0600
+
+    [aat/morx] Add test for previous commit
+    
+    https://github.com/harfbuzz/harfbuzz/issues/1373
+
+ test/shape/data/in-house/tests/macos.tests | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 2124ad8906bb77eee099071dccc49d3c60fe331f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 21:32:27 2022 -0600
+
+    [aat/morx] Implement language-specific forms
+    
+    Test on Mac with, eg.
+    
+    $ hb-view /Library/Fonts/BigCaslon.ttf -u 107
+    vs
+    $ hb-view /Library/Fonts/BigCaslon.ttf -u 107 --language pl
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/1373
+
+ src/hb-aat-layout-morx-table.hh | 7 +++++++
+ src/hb-aat-map.hh               | 6 ++++--
+ 2 files changed, 11 insertions(+), 2 deletions(-)
+
+commit d8574b44ccde97fc7111b4d983f5303e200f0ae8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 18:44:27 2022 -0600
+
+    [CoverageFormat2] Fix iterator to avoid infinite loop
+    
+    on invalid data.
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5304497047470080
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit b475a2ab29eec981ac92c5ebc555b2c30288fe57
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 18:44:11 2022 -0600
+
+    [array] Adjust operator !=
+
+ src/hb-array.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 9518d602f33d157343b273fe1846b8b5c60fe56e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 17:03:40 2022 -0600
+
+    [atomic] Disable compiler memory barrier on MSVC
+    
+    It keeps giving me internal compiler error.
+    
+    https://github.com/harfbuzz/harfbuzz/issues/3728
+
+ src/hb-atomic.hh | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+commit f0707e2348c455113e5ef9efc86b85920bb107b1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 16:47:16 2022 -0600
+
+    [atomic] Add compiler memory_r_barrier
+    
+    https://github.com/harfbuzz/harfbuzz/issues/3728
+
+ src/hb-atomic.hh    |  7 +++++++
+ src/hb-open-type.hh | 28 ++++++++++++++--------------
+ 2 files changed, 21 insertions(+), 14 deletions(-)
+
+commit f3151b6582a38fb1a377eb6070b8cecedb2ea711
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 16:19:28 2022 -0600
+
+    [ArrayOf family] Use memory barrier before accessing array
+    
+    Without it, the compiler was reordering and batching the read
+    of array length and array[0] if the 0'th member was accessed
+    constantly and function was inlined.  This felt safe to the
+    compiler because HB_VAR_ARRAY is 1, but could be unsafe actually.
+    The memory barrier disallows that.
+    
+    This was found by afl/honggfuzz address sanitizers.
+    Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=49187
+
+ src/hb-open-type.hh        | 14 ++++++++++++++
+ src/hb-ot-layout-common.hh |  2 +-
+ 2 files changed, 15 insertions(+), 1 deletion(-)
+
+commit 90e40f24fed3e0a8ccb16e56fbe926fd5953b970
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 15:01:04 2022 -0600
+
+    [algs] Tweak attribute(packed) usage
+    
+    Allow disabling it. Also don't cast this pointer.
+
+ src/hb-algs.hh | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+commit af84680f23d1a3078f2a3eb8651e174b40f99bf8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 12:00:04 2022 -0600
+
+    [GSUB] Remove a reinterpret_cast
+
+ src/OT/Layout/GSUB/SubstLookup.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9843f07658ae6b9b7b586f9c69cdb2c99b24ad18
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 16:03:55 2022 -0600
+
+    [OffsetTo] Try catching nullable offsets to unbounded types
+    
+    Doesn't catch all cases; if type is not fully defined at
+    OffsetTo time, we can't know.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/1300
+    to the best we can do.
+
+ src/hb-open-type.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 1327d8e3dfcaadba6c5029f830ffaa0903a8647b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 16:03:38 2022 -0600
+
+    [layout-common] Reshuffle code so Feature is defined before it's used
+
+ src/hb-ot-layout-common.hh | 865 ++++++++++++++++++++++-----------------------
+ 1 file changed, 432 insertions(+), 433 deletions(-)
+
+commit f7147835eb3e3397ec5ad37bd6b9e1a4dfbd4f9d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 16:03:25 2022 -0600
+
+    [colr] Add MIN_SIZE to Paint
+
+ src/hb-ot-color-colr-table.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit e1d2facd5363951adec78b080cf616e4bc3ff9d3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 16:02:58 2022 -0600
+
+    [null] Add hb_has_null_size() and hb_has_min_size()
+
+ src/hb-null.hh | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+commit c8908f92d77e88d69d6f365290f82c4d3c3d629b
+Merge: 3ac110560 6ed57de15
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 15:32:58 2022 -0600
+
+    Merge pull request #3726 from harfbuzz/ft-bitmap
+    
+    Ft bitmap
+
+commit 6ed57de15c92f5bf04d9872d989d6eb129f4bec0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 15:09:28 2022 -0600
+
+    [ft] Fix negative font sizes for bitmaps
+
+ src/hb-ft.cc | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+commit 307ee9baff687912e4f451a0cc463ff84314554f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 14:48:29 2022 -0600
+
+    [ft] Fix bitmap-only vertical metrics
+
+ src/hb-ft.cc | 17 ++++++++++++++---
+ 1 file changed, 14 insertions(+), 3 deletions(-)
+
+commit 87d338eb61e35d6d8270b083c8225e004f73c03f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 14:19:17 2022 -0600
+
+    [ft] Fix test
+
+ src/hb-ft.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit e294200dac3d7cd41a02e0753f63acfbb5e24820
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Jul 15 21:36:50 2022 +0200
+
+    [ft] Check for FT_Get_Transform at build time
+
+ configure.ac |  2 +-
+ meson.build  |  1 +
+ src/hb-ft.cc | 22 ++++++++++++++++++++++
+ 3 files changed, 24 insertions(+), 1 deletion(-)
+
+commit 901236f721e59e9955637cd44121b28f89c5bebe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 12:55:31 2022 -0600
+
+    [ft] Implement loading (color) bitmap fonts
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/489
+    
+    Something about the vertical metrics is still off, not matching
+    hb-ot.  I cannot figure out what.
+
+ src/hb-ft.cc | 92 ++++++++++++++++++++++++++++++++++++------------------------
+ 1 file changed, 56 insertions(+), 36 deletions(-)
+
+commit 3ac110560dc3f103d4b95e543afc6e4b6c302728
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 12:48:11 2022 -0600
+
+    [ft] Fix scale when font-sizes are negative
+
+ src/hb-ft.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit d68507d06212904661d51907e81012f3ce21821c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 14 11:20:00 2022 -0600
+
+    [arabic] Pause after calt only if no rclt
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/1573
+
+ src/hb-ot-map.cc           | 15 +++++++++++++++
+ src/hb-ot-map.hh           |  2 ++
+ src/hb-ot-shaper-arabic.cc | 14 +++++++-------
+ 3 files changed, 24 insertions(+), 7 deletions(-)
+
+commit 8b379ddc765dc1912f768dbc903b94ef106e6a32
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 14 16:20:04 2022 -0600
+
+    [test-iter] Add back test of OT namespace iteration
+
+ src/test-iter.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit ab21c4c283f2ab37ba4c9ba759d9b92a7eb52b94
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 14 16:02:10 2022 -0600
+
+    [hb-view] Add one to row of padding
+
+ util/helper-cairo-ansi.hh | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+commit 2da36cf99a737d8cf4a145f1f5d540cbb4eb1b95
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 14 15:57:43 2022 -0600
+
+    [hb-view] Use envvar HB_CHAFA=0 to disable Chafa output
+
+ util/helper-cairo-ansi.hh | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit 76e6feb77f373a47fa035620e518daee199e66c9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 14 13:45:39 2022 -0600
+
+    [util/ansi] Enable all symbols in Chafa
+    
+    Gives vastly smoother output. The previous setting was
+    equivalent to our in-house renderer.
+
+ util/helper-cairo-ansi.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 679c87ca369b4bac851cd7c70b09b6187cacf03a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 14 13:39:14 2022 -0600
+
+    [util/ansi] Fix chafa cell width/height
+    
+    No idea why it was set to 10/20 instead of 8/16.
+
+ util/helper-cairo-ansi.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b706be540c4db61e228ac0433ee9b88e5286d50b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 14 11:03:04 2022 -0600
+
+    [mingw32] Update instructions
+
+ README.mingw.md | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 5363e40de13425938bc833ae2b6c1d9d565bcf65
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 13 23:03:54 2022 +0000
+
+    [reorg] update build files.
+
+ src/Makefile.sources | 5 +++++
+ src/meson.build      | 5 +++++
+ 2 files changed, 10 insertions(+)
+
+commit d82ace5c6feba702eea0d869273f5c3090139d0a
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 13 23:00:01 2022 +0000
+
+    [reorg] add TODO to RangeRecord.
+
+ src/OT/Layout/Common/RangeRecord.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit c1e280ea7824a06c8f3bc14714a255c8e2b35aa3
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 13 22:43:38 2022 +0000
+
+    [reorg] Move Coverage, RangeRecord into new namespace layout.
+
+ src/OT/Layout/Common/Coverage.hh        | 323 +++++++++++++++++
+ src/OT/Layout/Common/CoverageFormat1.hh | 120 +++++++
+ src/OT/Layout/Common/CoverageFormat2.hh | 224 ++++++++++++
+ src/OT/Layout/Common/RangeRecord.hh     |  75 ++++
+ src/OT/Layout/types.hh                  |  64 ++++
+ src/hb-ot-layout-common.hh              | 601 +-------------------------------
+ src/test-iter.cc                        |   2 -
+ src/test-serialize.cc                   |   3 +-
+ 8 files changed, 816 insertions(+), 596 deletions(-)
+
+commit 9c2518988dcdafb8388f8f1f5e76db6e08ef6a0e
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 13 22:55:58 2022 +0000
+
+    [repack] Don't count space isolation against round limit.
+    
+    Restore max rounds to 20 but don't count space isolation against the limit. The number of iterations space isolation can make changes for is already bounded to a reasonable max (the number of lookups in the font) so no need to cap the number of iterations.
+
+ src/hb-repacker.hh | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+commit a2f0723148e8bdca7a024929cb8dba6961f26485
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 16:02:39 2022 -0600
+
+    [GPOS] Adjust mark attachment on multiple substitution some more
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/1545
+
+ src/OT/Layout/GPOS/MarkBasePosFormat1.hh                 |   1 +
+ .../fonts/7c24183f26d60df414578a0a9f5e79ab9d32a22b.ttf   | Bin 0 -> 2544 bytes
+ test/shape/data/in-house/tests/use.tests                 |   1 +
+ 3 files changed, 2 insertions(+)
+
+commit ac216972abd3803947d4f2208380648965d26e94
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 15:32:19 2022 -0600
+
+    [subset] Add table size blowup bound
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3091
+
+ src/hb-subset.cc | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit 4b3afafb000f7aa0fbad3695a5faf7ef68c77897
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 15:13:07 2022 -0600
+
+    [array] Use hb_swap() in reverse()
+
+ src/hb-array.hh | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+commit 87167acfe3aee9e23b2a256f6e3785ee4de5122e
+Merge: a369ab133 7549d447b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 14:58:09 2022 -0600
+
+    Merge pull request #3704 from harfbuzz/64k
+    
+    Towards breaking the 64k in GSUB/GPOS
+
+commit a369ab133b77d17fe58abdac613d8e33215c0820
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 13 19:00:08 2022 +0000
+
+    [repacker] Increase max_rounds when called via public api.
+
+ src/hb-repacker.hh        | 2 +-
+ src/hb-subset-repacker.cc | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 4ee471922d6d99a81bbd6582134ac1a4e07bdcb8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 10:36:53 2022 -0600
+
+    More -Wcomma fixes
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3716
+
+ src/hb-algs.hh       |  2 +-
+ src/hb-ot-metrics.cc | 12 ++++++------
+ 2 files changed, 7 insertions(+), 7 deletions(-)
+
+commit c2712ff4f5451145e28c760841646313bc0b8873
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 13:34:11 2022 -0600
+
+    Reorder hb_ot_shaper_t members to save 8 bytes of data per shaper
+
+ src/hb-ot-shaper-arabic.cc  |  4 ++--
+ src/hb-ot-shaper-default.cc |  8 ++++----
+ src/hb-ot-shaper-hangul.cc  |  4 ++--
+ src/hb-ot-shaper-hebrew.cc  |  4 ++--
+ src/hb-ot-shaper-indic.cc   |  4 ++--
+ src/hb-ot-shaper-khmer.cc   |  4 ++--
+ src/hb-ot-shaper-myanmar.cc |  8 ++++----
+ src/hb-ot-shaper-thai.cc    |  4 ++--
+ src/hb-ot-shaper-use.cc     |  4 ++--
+ src/hb-ot-shaper.hh         | 16 ++++++++--------
+ 10 files changed, 30 insertions(+), 30 deletions(-)
+
+commit e5f0bc8f0a903db5f7080bf9116fd258cbb036c0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 13:22:34 2022 -0600
+
+    [set] Save a few kilobytes via type erasure of process()
+
+ src/hb-bit-set.hh | 17 ++++++++++++-----
+ 1 file changed, 12 insertions(+), 5 deletions(-)
+
+commit 42da7da5efe76057b177ed9589947d7b1982435e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 12:46:36 2022 -0600
+
+    Fix HB_NO_SHAPER HB_NO_OT_SHAPE build
+
+ src/hb-shape-plan.cc | 2 +-
+ src/hb-shaper.cc     | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 015aecfcdd82382e19e85dd4c396ce45667f2548
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 12:15:01 2022 -0600
+
+    [use-table] Port to using packtab
+    
+    Saves around 9kb.
+
+ src/gen-use-table.py          |   69 +-
+ src/hb-ot-shaper-use-table.hh | 1690 +++++++----------------------------------
+ src/hb-ot-shaper-use.cc       |    2 +-
+ 3 files changed, 266 insertions(+), 1495 deletions(-)
+
+commit 0fcd1decb7ab9bf0b298b302bdd51976620119ab
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 12:17:35 2022 -0600
+
+    Fix file permissions
+
+ src/fix_get_types.py  | 0
+ src/gen-arabic-pua.py | 0
+ 2 files changed, 0 insertions(+), 0 deletions(-)
+
+commit 7549d447ba4bb1ef031dedbde764690ff082b22a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 21:52:25 2022 -0600
+
+    [>64k:glyf] Implement composites for >64k
+    
+    Implements https://github.com/be-fonts/boring-expansion-spec/issues/42
+
+ src/OT/glyf/CompositeGlyph.hh | 36 ++++++++++++++++++++++++++++++------
+ 1 file changed, 30 insertions(+), 6 deletions(-)
+
+commit 09de94788b3c588542e6f3f50b6d73577dca8456
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 15:08:22 2022 -0600
+
+    [>64k:glyf] Hid composite glyphIndex
+
+ src/OT/glyf/CompositeGlyph.hh | 4 ++++
+ src/OT/glyf/Glyph.hh          | 2 +-
+ src/OT/glyf/SubsetGlyph.hh    | 4 ++--
+ src/hb-subset-plan.cc         | 2 +-
+ 4 files changed, 8 insertions(+), 4 deletions(-)
+
+commit df7eebf40a080655bd56795b5d3c57f4cce03f08
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 14:14:55 2022 -0600
+
+    [>64k:layout] Fix layout of RangeRecord
+    
+    https://github.com/be-fonts/boring-expansion-spec/issues/30
+
+ src/hb-ot-layout-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 99f017f41dfcb2add11d3f9e748882d7fe061132
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 13:13:19 2022 -0600
+
+    [>64k:layout:GSUBGPOS] Implement format 2
+    
+    Implements https://github.com/be-fonts/boring-expansion-spec/issues/58
+    
+    Subset does NOT lower format.
+
+ src/hb-ot-layout-gsubgpos.hh | 35 ++++++++++++++++++++++++++++++-----
+ 1 file changed, 30 insertions(+), 5 deletions(-)
+
+commit 9ef9fc01148ace504d38ecf304f0e49827e4d27b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 13:29:23 2022 -0600
+
+    [>64k:layout] Templatize GSUBGPOSFormat1
+
+ src/hb-open-type.hh          |  2 +-
+ src/hb-ot-layout-common.hh   |  4 ++--
+ src/hb-ot-layout-gsubgpos.hh | 12 ++++++------
+ 3 files changed, 9 insertions(+), 9 deletions(-)
+
+commit 5fd0a3f0b9235a50a72e3a89fb8ae41a28fc049e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 13:10:04 2022 -0600
+
+    [>64k:layout] Templatize GSUBGPOSFormat1
+
+ src/hb-ot-layout-common.hh   |  3 ++-
+ src/hb-ot-layout-gsubgpos.hh | 15 ++++++++-------
+ 2 files changed, 10 insertions(+), 8 deletions(-)
+
+commit f6c2aaeea46bc10833d225d1514a96254a3e6434
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 13:06:48 2022 -0600
+
+    [>64k:layout] Add List16OfOffsetTo
+
+ src/hb-open-type.hh | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+commit 6d0e3e677be11f330c44f5e1037f61d268f6a621
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 12:28:53 2022 -0600
+
+    [>64k:layout] Split GSUBGPOSVersion1 into own struct
+
+ src/hb-ot-layout-gsubgpos.hh | 280 +++++++++++++++++++++++++++----------------
+ 1 file changed, 175 insertions(+), 105 deletions(-)
+
+commit 04c5cd4085837cf627aaab328b142a73de6a9c93
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 11:39:41 2022 -0600
+
+    [subset/layout] Move find_duplicate_features to subset from layout
+
+ src/hb-ot-layout-gsubgpos.hh | 62 ----------------------------------------
+ src/hb-subset-plan.cc        | 67 +++++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 66 insertions(+), 63 deletions(-)
+
+commit 1bf8fa2f1f67a4f72d14c53bc4242e38e46ab475
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 8 14:22:21 2022 -0600
+
+    [>64k:layout:(Chain)Context] Implement format 4
+    
+    Implements rest of https://github.com/be-fonts/boring-expansion-spec/issues/34
+    
+    Subset does NOT lower format.
+
+ src/hb-ot-layout-gsubgpos.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 0f13eb1f5ceee50be88a9c5864b0d80a3266b7a5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 8 13:43:33 2022 -0600
+
+    [>64k:layout] Templatize (Chain)ContextFormat1
+
+ src/hb-ot-layout-gsubgpos.hh | 64 ++++++++++++++++++++++++++++++--------------
+ 1 file changed, 44 insertions(+), 20 deletions(-)
+
+commit d1f58e5979bb8227e1136fbf72facce7c2e9bb7c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 8 13:25:07 2022 -0600
+
+    [>64k:layout:(Chain)Context] Implement format 5
+    
+    Implements part of https://github.com/be-fonts/boring-expansion-spec/issues/34
+    
+    Subset does NOT lower format.
+
+ src/hb-ot-layout-gsubgpos.hh | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+commit a90c5af9d2a9b3fdbf083359d2d6ab7ba73d35e6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 8 13:11:47 2022 -0600
+
+    [>64k:layout] Templatize (Chain)ContextFormat2
+
+ src/hb-ot-layout-gsubgpos.hh | 48 +++++++++++++++++++++++---------------------
+ 1 file changed, 25 insertions(+), 23 deletions(-)
+
+commit cc83b0b8fde5a6ac5e1800663238c4c9354da1ec
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 8 12:25:15 2022 -0600
+
+    [>64k:layout:MarkBasePos/MarkMarkPos/MarkLigPos] Implement format 2
+    
+    Implements https://github.com/be-fonts/boring-expansion-spec/issues/40
+    
+    Subset does NOT lower format.
+
+ src/OT/Layout/GPOS/MarkBasePos.hh | 6 ++++++
+ src/OT/Layout/GPOS/MarkLigPos.hh  | 6 ++++++
+ src/OT/Layout/GPOS/MarkMarkPos.hh | 6 ++++++
+ 3 files changed, 18 insertions(+)
+
+commit 4b43070e2f67b2ea42673056f3f38b87ee9e5a06
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 8 12:22:16 2022 -0600
+
+    [>64k:layout] Templatize MarkBasePos/MarkMarkPos/MarkLigPos
+
+ src/OT/Layout/GPOS/MarkBasePos.hh        |  4 ++--
+ src/OT/Layout/GPOS/MarkBasePosFormat1.hh | 13 +++++++------
+ src/OT/Layout/GPOS/MarkLigPos.hh         |  4 ++--
+ src/OT/Layout/GPOS/MarkLigPosFormat1.hh  | 13 +++++++------
+ src/OT/Layout/GPOS/MarkMarkPos.hh        |  4 ++--
+ src/OT/Layout/GPOS/MarkMarkPosFormat1.hh | 13 +++++++------
+ 6 files changed, 27 insertions(+), 24 deletions(-)
+
+commit f0d6dda5a61649226ddf82b41a611c147d19729f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 7 16:28:24 2022 -0600
+
+    [>64k:layout:PairPos] Implement format 3
+    
+    Implements rest of https://github.com/be-fonts/boring-expansion-spec/issues/38
+    
+    Subset does NOT lower format.
+
+ src/OT/Layout/GPOS/PairPos.hh        |  4 +++-
+ src/OT/Layout/GPOS/PairPosFormat1.hh | 12 ++++++------
+ 2 files changed, 9 insertions(+), 7 deletions(-)
+
+commit 298ee47c55640c1ea68409451cf4bad979cafebd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 7 16:27:49 2022 -0600
+
+    [>64k:layout] Templatize PairPosFormat1
+
+ src/OT/Layout/GPOS/PairPos.hh         | 2 +-
+ src/OT/Layout/GPOS/PairPosFormat1.hh  | 8 ++++++--
+ src/OT/Layout/GPOS/PairSet.hh         | 8 ++++++--
+ src/OT/Layout/GPOS/PairValueRecord.hh | 7 +++++--
+ 4 files changed, 18 insertions(+), 7 deletions(-)
+
+commit e9f8010fd0ca12ff008e72e669e4ce5c0f1fa836
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 7 13:55:26 2022 -0600
+
+    [>64k:layout:PairPos] Templatize & implement format 4
+    
+    Implements part of https://github.com/be-fonts/boring-expansion-spec/issues/38
+    
+    Subset does NOT lower format.
+
+ src/OT/Layout/GPOS/PairPos.hh        | 12 +++++++++---
+ src/OT/Layout/GPOS/PairPosFormat2.hh | 11 ++++++-----
+ 2 files changed, 15 insertions(+), 8 deletions(-)
+
+commit ecd8bc5a9cc9ec1616a4f20cc98319fa839c2067
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 17:49:56 2022 -0600
+
+    [>64k:layout:LigatureSubst] Implement format 2
+    
+    Implements https://github.com/be-fonts/boring-expansion-spec/issues/33
+    
+    Subset does NOT lower format.
+
+ src/OT/Layout/GSUB/LigatureSubst.hh | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+commit 9d0e9faa4358b9800989918fa4710694aa3cb732
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 17:49:07 2022 -0600
+
+    [>64k:layout] Templatable bunch of GSUBGPOS internal functions
+
+ src/hb-ot-layout-gsubgpos.hh | 66 +++++++++++++++++++++++++++-----------------
+ 1 file changed, 41 insertions(+), 25 deletions(-)
+
+commit 429b387a6f620dc590a3d22e4274519b4f220321
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 17:37:11 2022 -0600
+
+    [>64k:layout] Support HBUINT24 in skippy_iter
+
+ src/hb-ot-layout-gsubgpos.hh | 61 ++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 53 insertions(+), 8 deletions(-)
+
+commit 1ef67a6d6663b8cc50bdea1a67775e9fc95f9dc8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 17:28:02 2022 -0600
+
+    [gsubgpos] Remove HBUINT16 from matcher
+
+ src/hb-ot-layout-gsubgpos.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 704e696ad08db74b45baff78acac8ebe53589edb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 14:19:20 2022 -0600
+
+    [>64k:layout] Templatize LigatureSubst
+
+ src/OT/Layout/GSUB/Ligature.hh             | 10 ++++++----
+ src/OT/Layout/GSUB/LigatureSet.hh          | 13 +++++++------
+ src/OT/Layout/GSUB/LigatureSubst.hh        |  4 ++--
+ src/OT/Layout/GSUB/LigatureSubstFormat1.hh | 21 +++++++++++----------
+ 4 files changed, 26 insertions(+), 22 deletions(-)
+
+commit 27d24212db0c61cf2802409e55a55dff39590dd4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 14:05:21 2022 -0600
+
+    [>64k:layout:AlternateSubst] Implement format 2
+    
+    Implements rest of https://github.com/be-fonts/boring-expansion-spec/issues/32
+    
+    Subset does NOT lower format.
+
+ src/OT/Layout/GSUB/AlternateSubst.hh | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+commit c53d3ad51eddc9a6945aa07e64c85bdb20f3cdcd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 14:03:45 2022 -0600
+
+    [>64k:layout] Templatize AlternateSet
+
+ src/OT/Layout/GSUB/AlternateSet.hh          |  3 ++-
+ src/OT/Layout/GSUB/AlternateSubst.hh        |  4 ++--
+ src/OT/Layout/GSUB/AlternateSubstFormat1.hh | 13 +++++++------
+ 3 files changed, 11 insertions(+), 9 deletions(-)
+
+commit a58a48622adc2d24daefbc62b1e71e5d850a0f58
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 13:58:35 2022 -0600
+
+    [>64k:layout:MultipleSubst] Implement format 2
+    
+    Implements part of https://github.com/be-fonts/boring-expansion-spec/issues/32
+    
+    Subset is NOT updated to lower format.
+
+ src/OT/Layout/GSUB/MultipleSubst.hh | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+commit 684c8fcea7a1ac91dcef256d6242a68445664dd4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 13:37:52 2022 -0600
+
+    [>64k:layout] Templatize MultipleSubst
+
+ src/OT/Layout/GSUB/MultipleSubst.hh        |  4 ++--
+ src/OT/Layout/GSUB/MultipleSubstFormat1.hh | 13 +++++++------
+ src/OT/Layout/GSUB/Sequence.hh             |  3 ++-
+ 3 files changed, 11 insertions(+), 9 deletions(-)
+
+commit 8775e9b4a4f985ec29bba609b7fc53424f24834c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 13:28:17 2022 -0600
+
+    [>64k:layout:SingleSubst] Implement format 3/4
+    
+    Implements https://github.com/be-fonts/boring-expansion-spec/issues/31
+
+ src/OT/Layout/GSUB/SingleSubst.hh        | 32 ++++++++++++++++++++++++++++++--
+ src/OT/Layout/GSUB/SingleSubstFormat2.hh |  2 +-
+ 2 files changed, 31 insertions(+), 3 deletions(-)
+
+commit e3caf8d50a2c033039c2609b7bf6ebae302741a7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 13:11:53 2022 -0600
+
+    [>64k:layout] Templatize SingleSubst
+
+ src/OT/Layout/GSUB/SingleSubst.hh        |  6 +++---
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 10 ++++++----
+ src/OT/Layout/GSUB/SingleSubstFormat2.hh |  9 +++++----
+ 3 files changed, 14 insertions(+), 11 deletions(-)
+
+commit ca5c8a64191e7bb7ccd79687d1c2c4e7231cbdd7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 13:02:49 2022 -0600
+
+    [>64k:layout:Coverage] Implement format 3/4
+    
+    Implements rest of https://github.com/be-fonts/boring-expansion-spec/issues/30
+
+ src/hb-ot-layout-common.hh | 65 ++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 65 insertions(+)
+
+commit 25de6fb4e7153fee6ce1792aa2c24c556726a116
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 12:52:03 2022 -0600
+
+    [>64k:layout:ClassDef] Implement format 3/4
+    
+    This implements part of https://github.com/be-fonts/boring-expansion-spec/issues/30
+
+ src/hb-ot-layout-common.hh | 59 ++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 57 insertions(+), 2 deletions(-)
+
+commit 9286526f3746b7fec0624141632e7859775717cf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 12:26:58 2022 -0600
+
+    [>64k:layout] Templatize Coverage & ClassDef
+    
+    Have not added new formats yet.
+
+ src/hb-ot-layout-common.hh | 76 +++++++++++++++++++++++++---------------------
+ 1 file changed, 41 insertions(+), 35 deletions(-)
+
+commit e8cce9d1b3211550b584728c2c5b9a4a6d9efb09
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 5 14:05:43 2022 -0600
+
+    [>64k:layout] Add SmallTypes & MediumTypes
+
+ src/hb-ot-layout-common.hh | 28 +++++++++++++++++++++++++++-
+ 1 file changed, 27 insertions(+), 1 deletion(-)
+
+commit d8f9d517801c5c361f329764329731bc0bde950f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 12 13:19:31 2022 -0600
+
+    [hashmap] Add keys_ref() and values_ref()
+
+ src/hb-map.hh   | 12 ++++++++++++
+ src/test-map.cc |  7 +++++++
+ 2 files changed, 19 insertions(+)
+
+commit cddcb31065939928050f2804b7a1fc0b69e10c76
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 12 13:15:38 2022 -0600
+
+    [vector] Remove residual nullptr_t from when hashmap needed it
+
+ src/hb-vector.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 46a36771f4369994df67535e15ac7af71fad345a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 12 12:03:00 2022 -0600
+
+    [draw] Fix leak from e0a5231657a6f09ca4afc93e1b2224eba7a0b544
+
+ src/hb-draw.cc | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit f8544cbfc09cbd52cdb7f9241df2eeb2262a9f68
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 12 11:52:33 2022 -0600
+
+    [draw] Fix regression from e0a5231657a6f09ca4afc93e1b2224eba7a0b544
+
+ src/hb-draw.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit d15041be7dbbfbd17f1ec21f3acf4a6c6e91ba9f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 13:39:21 2022 -0600
+
+    [GSUB/GPOS] Trace toplevel sanitize
+
+ src/OT/Layout/GPOS/GPOS.hh | 5 ++++-
+ src/OT/Layout/GSUB/GSUB.hh | 5 ++++-
+ 2 files changed, 8 insertions(+), 2 deletions(-)
+
+commit 7c4e9080c0f135c1f82e71b946e7883b91a81d0f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 14:01:52 2022 -0600
+
+    [sanitize] Minor trace format fixup
+    
+    This likely() is unlikely to make a difference, and obscures
+    the return_trace() message by writing out "something" instead
+    of the true/false value.
+
+ src/hb-aat-layout-bsln-table.hh |  4 ++--
+ src/hb-aat-layout-feat-table.hh |  2 +-
+ src/hb-aat-layout-just-table.hh | 12 ++++++------
+ src/hb-aat-layout-kerx-table.hh |  2 +-
+ src/hb-aat-layout-opbd-table.hh |  2 +-
+ src/hb-open-type.hh             |  4 ++--
+ src/hb-ot-color-colr-table.hh   |  2 +-
+ src/hb-ot-layout-base-table.hh  |  2 +-
+ src/hb-ot-post-table.hh         |  8 ++++----
+ src/hb-ot-stat-table.hh         | 12 ++++++------
+ 10 files changed, 25 insertions(+), 25 deletions(-)
+
+commit d826a5920cc6dec5d942768f1c44e1a155de87c2
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Jul 9 21:57:25 2022 -0400
+
+    docs: Clarify 0xFFFF as palette index
+    
+    Mention that a palette index of 0xFFFF
+    means to use the foreground color.
+
+ src/hb-ot-color.h | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 0cd404d0b815898afc695de6e68f0177c43056e4
+Author: jfkthame <jfkthame@gmail.com>
+Date:   Sat Jul 9 20:23:22 2022 +0100
+
+    Typo fix in hb-subset
+    
+    s/substract/subtract/
+
+ util/hb-subset.cc | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit 6d051f4018e21ce1ec93fe4876c4a15819d0940a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 8 14:08:51 2022 -0600
+
+    [layout] Simplify StructAfter<> usage
+
+ src/hb-ot-layout-gsubgpos.hh | 107 ++++++++++++++++++++++---------------------
+ 1 file changed, 54 insertions(+), 53 deletions(-)
+
+commit 5192294f83a0f6be13bbf7a7c38b9cf4a38d33b2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 8 14:00:24 2022 -0600
+
+    .
+
+ .../Layout/GSUB/ReverseChainSingleSubstFormat1.hh  |  22 ++--
+ src/hb-ot-layout-gsubgpos.hh                       | 124 ++++++++++-----------
+ 2 files changed, 73 insertions(+), 73 deletions(-)
+
+commit 29f149c16cdee85a1cd2d953e307e27262deee1a
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jul 7 20:16:16 2022 +0000
+
+    [subset] cache sanitized tables in subset plan to avoid sanitizing tables multiple times.
+
+ src/hb-subset-plan.cc | 39 +++++++++++++++++++++++++--------------
+ src/hb-subset-plan.hh | 21 +++++++++++++++++++++
+ src/hb-subset.cc      | 16 ++++++++--------
+ 3 files changed, 54 insertions(+), 22 deletions(-)
+
+commit 8b349e1139dfdc8e29d1d19734bff8941024bf2a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 17:22:34 2022 -0600
+
+    [gsubgpos] Remove HBUINT16 from match functions signatures
+
+ src/hb-ot-layout-gsubgpos.hh | 37 ++++++++++++++++++++-----------------
+ 1 file changed, 20 insertions(+), 17 deletions(-)
+
+commit f114b18c5871f891c4e59a9d698f7be9eb8df557
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 17:31:46 2022 -0600
+
+    [gsubgpos] Break skippy_iter set_match_func into two
+
+ src/hb-ot-layout-gsubgpos.hh | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+commit 8a107125a5637583ec80256f59dbb348e774863e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 13:46:30 2022 -0600
+
+    [layout] Make SubstLookup:serialize_single take iterators
+
+ src/OT/Layout/GSUB/SubstLookup.hh | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+commit 8a971d01e98c98dc8848ca1e89894f6dddb73f91
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 12:37:43 2022 -0600
+
+    [layout] Use is_source_of instead of is_iterator
+
+ src/hb-ot-layout-common.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 0dc0da054d03584a1526ce852d0d3c7839e1d630
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 12:33:37 2022 -0600
+
+    [iter] Add hb_is_sorted_iterator(_of)
+
+ src/hb-iter.hh             | 2 ++
+ src/hb-ot-layout-common.hh | 6 +++---
+ 2 files changed, 5 insertions(+), 3 deletions(-)
+
+commit 2c67261723a9a3081ee89549b89a3409ac8306fb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 12:26:16 2022 -0600
+
+    [open-type] Add HBGlyph24
+
+ src/hb-open-type.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 7cfe7fe651fbf479db75e4f96869b9248227f728
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 12:25:54 2022 -0600
+
+    [null] Change null bytes for RangeRecord
+    
+    Should be harmless.
+
+ src/hb-static.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 486555c6916750a97f1e35f506447594bf03639f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 5 17:12:59 2022 -0600
+
+    [open-type] Add Array24Of<> and SortedArray24Of<>
+
+ src/hb-open-type.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 1e503f587b3ce368b6b759c1927aa9708096c8f3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 5 15:44:58 2022 -0600
+
+    [null] Add DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1
+
+ src/hb-aat-layout-common.hh | 13 +------------
+ src/hb-null.hh              | 13 ++++++++++++-
+ src/hb-static.cc            |  3 +--
+ 3 files changed, 14 insertions(+), 15 deletions(-)
+
+commit ea11029a6e72be7b5f0f3b815dd7b78a105195fa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 8 11:58:43 2022 -0600
+
+    [GPOS] Split LigatureArray.hh
+
+ src/Makefile.sources                    |  1 +
+ src/OT/Layout/GPOS/LigatureArray.hh     | 56 +++++++++++++++++++++++++++++++++
+ src/OT/Layout/GPOS/MarkLigPosFormat1.hh | 43 ++-----------------------
+ src/meson.build                         |  1 +
+ 4 files changed, 60 insertions(+), 41 deletions(-)
+
+commit 68b2742fe4eebddf0a8388ca8c57be41e45cee41
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 7 16:11:15 2022 -0600
+
+    [GPOS] Move code around
+
+ src/OT/Layout/GPOS/PairPosFormat1.hh  |  1 -
+ src/OT/Layout/GPOS/PairSet.hh         | 60 +++++++++++++++++------------------
+ src/OT/Layout/GPOS/PairValueRecord.hh | 18 +++++------
+ 3 files changed, 39 insertions(+), 40 deletions(-)
+
+commit 6a3043a0c146d01f878c4d3b446cb8ff8c52ae7c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 7 14:51:37 2022 -0600
+
+    Fix tests
+
+ src/OT/Layout/GPOS/PairSet.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit aa68657434f186f6792d2facda085859b15bbae5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 7 14:07:45 2022 -0600
+
+    [Makefile.sources/meson.build] Sort file names
+
+ src/Makefile.sources | 90 ++++++++++++++++++++++++++--------------------------
+ src/meson.build      | 90 ++++++++++++++++++++++++++--------------------------
+ 2 files changed, 90 insertions(+), 90 deletions(-)
+
+commit 0b0e3b30ce44b3f305d85827780d374bd94ff077
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 7 14:06:44 2022 -0600
+
+    [GPOS] Break down PairPosFormat1 into new layout
+
+ src/Makefile.sources                  |   2 +
+ src/OT/Layout/GPOS/PairPosFormat1.hh  | 234 +---------------------------------
+ src/OT/Layout/GPOS/PairSet.hh         | 169 ++++++++++++++++++++++++
+ src/OT/Layout/GPOS/PairValueRecord.hh |  94 ++++++++++++++
+ src/meson.build                       |   2 +
+ 5 files changed, 269 insertions(+), 232 deletions(-)
+
+commit aec34e17eb69b67cb0beb5d2f50f544b6f95d22c
+Author: Not-a-Bug Won't Fix <notabugwontfix@proton.me>
+Date:   Thu Jul 7 15:42:51 2022 +0300
+
+    Fix target_link_libraries signatures mixing
+
+ CMakeLists.txt | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a64fc71033a4cff9bb5911ee28ac45ba93f4867a
+Merge: 3a722c535 6fad6b411
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 7 13:35:38 2022 -0600
+
+    Merge pull request #3710 from googlefonts/24bit_repacking
+    
+    [subset] Prepare the repacker for handling 24bit offsets in GSUB/GPOS.
+
+commit 6fad6b4113750d3aabea633685bc272f98a2ef83
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 6 19:18:27 2022 +0000
+
+    [repacker] add tests for special casing of 24bit offsets.
+
+ src/test-repacker.cc | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 84 insertions(+)
+
+commit b4f561dbbf61c7df9b284d1f2d4989b4517fb908
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 6 18:49:23 2022 +0000
+
+    [subset] Add some comments to find_space_roots/find_32_bit_roots methods.
+
+ src/graph/graph.hh | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+commit 401066bf3d20bf8913d340811fd1c61ed65bb5f1
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 6 18:44:40 2022 +0000
+
+    [subset] Prepare the repacker for handling 24bit offsets in GSUB/GPOS.
+    
+    The boring expansion (https://github.com/be-fonts/boring-expansion-spec) plans to introduce 24bit offsets into GSUB/GPOS. This changes the repacker to treat 24 bit offsets similar to 32 bit offsets and assign the top level 24 bit offsets into spaces to improve packing.
+
+ src/graph/graph.hh | 73 +++++++++++++++++++++++++++++++++++++++++++-----------
+ src/hb-repacker.hh |  2 +-
+ 2 files changed, 59 insertions(+), 16 deletions(-)
+
+commit 3a722c53545a5e8fb504a81acaa38f230433fadf
+Author: Luca Bacci <luca.bacci982@gmail.com>
+Date:   Wed Jul 6 19:22:38 2022 +0200
+
+    Fixes for DWrite header checks
+
+ CMakeLists.txt | 11 ++++++++---
+ configure.ac   |  2 +-
+ 2 files changed, 9 insertions(+), 4 deletions(-)
+
+commit c091d029c2038de28f77d104f472b2d3bd417f0c
+Merge: 2587dced4 1abc14b46
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 10:51:04 2022 -0600
+
+    Merge pull request #3706 from lb90/dwrite-dll
+    
+    Load DirectWrite dynamically
+
+commit 1abc14b4635970b6f6358e0f15505f19d34e3612
+Author: Luca Bacci <luca.bacci982@gmail.com>
+Date:   Wed Jul 6 17:52:29 2022 +0200
+
+    Do not link with the DWrite lib
+    
+    It's loaded dynamically now
+
+ CMakeLists.txt  | 5 ++++-
+ configure.ac    | 4 ----
+ meson.build     | 7 +------
+ src/meson.build | 1 -
+ 4 files changed, 5 insertions(+), 12 deletions(-)
+
+commit c22acfa8bd4529583079338150fea4c05abcad41
+Author: Luca Bacci <luca.bacci982@gmail.com>
+Date:   Wed Jul 6 13:50:47 2022 +0200
+
+    Fix function pointer typedef
+
+ src/hb-directwrite.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 2587dced4ceac75950272949610f6b2780522605
+Merge: 386e1bbad 79eb0f748
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 09:38:18 2022 -0600
+
+    Merge pull request #3707 from kleisauke/workaround-gcc-bug
+    
+    Fix build on GCC < 7
+
+commit 79eb0f74860fb6309e3162b4f17f98481c05a318
+Author: Kleis Auke Wolthuizen <github@kleisauke.nl>
+Date:   Wed Jul 6 13:29:55 2022 +0200
+
+    [GSUB] Fix build on GCC < 7
+
+ src/OT/Layout/GSUB/GSUB.hh     | 5 +++--
+ src/hb-ot-layout-gsub-table.hh | 8 ++++----
+ 2 files changed, 7 insertions(+), 6 deletions(-)
+
+commit 3238cb744bb570a75326ab4438968c59069e9af2
+Author: Kleis Auke Wolthuizen <github@kleisauke.nl>
+Date:   Wed Jul 6 13:18:14 2022 +0200
+
+    [GPOS] Fix build on GCC < 7
+
+ src/OT/Layout/GPOS/GPOS.hh     | 17 ++++++++++-------
+ src/hb-ot-layout-gpos-table.hh |  6 ++++--
+ 2 files changed, 14 insertions(+), 9 deletions(-)
+
+commit 3e881efbe4e8ad0a6c67112b150205297561c38e
+Author: Luca Bacci <luca.bacci982@gmail.com>
+Date:   Mon Jun 27 14:34:18 2022 +0200
+
+    Revert "Revert "Revert "[hb-directwrite] Don't load dwrit.dll dynamically"""
+    
+    This reverts commit 361a438658dcddea29d7c8b9c68bf2bc88109bde.
+
+ src/hb-directwrite.cc | 36 ++++++++++++++++++++++++++++++++++--
+ 1 file changed, 34 insertions(+), 2 deletions(-)
+
+commit 7b51bc95d9cf0d9a2e91a37319fa34e4e5f26927
+Author: Kleis Auke Wolthuizen <github@kleisauke.nl>
+Date:   Wed Jul 6 12:58:15 2022 +0200
+
+    [cplusplus] Fix build on GCC < 7
+
+ src/hb-cplusplus.hh | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+commit 386e1bbad81e720ac58a1a18c3028d47b27c6de9
+Merge: d9ab805e6 30309ec8d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 5 12:46:05 2022 -0600
+
+    Merge pull request #3699 from googlefonts/filter_scripts
+    
+    [subset] Add support for --layout-scripts
+
+commit 30309ec8d3eb39f6f5c05ff0e7464095c5d7bfbf
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Jul 5 18:33:19 2022 +0000
+
+    [subset] add null element in _filter_tag_list.
+
+ src/hb-subset-plan.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 216cf5946bdea85b954c73669c085437f9e99a72
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Jul 5 17:49:12 2022 +0000
+
+    [subset] Allocate space for null entry in script/feature list.
+
+ src/hb-subset-plan.cc | 8 +++-----
+ src/hb-subset.h       | 2 +-
+ 2 files changed, 4 insertions(+), 6 deletions(-)
+
+commit d9ab805e61e0d0aca6623203b4d7b68c84b026b8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 5 11:45:10 2022 -0600
+
+    Fix LookupFlag negation
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3703
+
+ src/OT/Layout/GPOS/MarkMarkPosFormat1.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b0cb9a1a635e65889e8bb9888b3c48f556d69db9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 15:32:32 2022 -0600
+
+    Make get_leading_bearing return bool
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3496
+    
+    Part of supporting >64k glyphs correctly.
+
+ src/OT/glyf/Glyph.hh       |  8 +++++---
+ src/OT/glyf/GlyphHeader.hh |  4 +++-
+ src/OT/glyf/glyf.hh        | 13 +++++--------
+ src/hb-ot-font.cc          | 13 +++++++------
+ src/hb-ot-hmtx-table.hh    | 45 ++++++++++++++++++++++++++++-----------------
+ 5 files changed, 48 insertions(+), 35 deletions(-)
+
+commit 115e1a03e7612a888ed248505ef5bd25a55eedb1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 14:45:12 2022 -0600
+
+    [glyf] Relax condition for matching number of coords
+
+ src/OT/glyf/glyf.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 800760c5bd894687e5ae1ff9b08cc27e5abdfcf6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 13:21:06 2022 -0600
+
+    [glyf] Rename get_extents functions for clarity
+
+ src/OT/glyf/Glyph.hh       | 6 +++---
+ src/OT/glyf/GlyphHeader.hh | 4 ++--
+ src/OT/glyf/glyf.hh        | 2 +-
+ 3 files changed, 6 insertions(+), 6 deletions(-)
+
+commit ab327f93b79863c598a3497bef82ed9aa43db69e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 13:17:03 2022 -0600
+
+    [glyf] Fix another bug with scaling
+    
+    Of advances this time.
+    
+    That codepath is never exercised though, if font has HVAR table.
+
+ src/OT/glyf/glyf.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f46ddeba48bee8c8f7a8a4ceadc0e02b7d197632
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 13:12:49 2022 -0600
+
+    [hmtx/glyf] Rename side-bearing functions for clarity
+
+ src/OT/glyf/Glyph.hh       |  4 ++--
+ src/OT/glyf/GlyphHeader.hh |  2 +-
+ src/OT/glyf/glyf.hh        |  6 +++---
+ src/hb-ot-font.cc          |  6 +++---
+ src/hb-ot-hmtx-table.hh    | 12 ++++++------
+ 5 files changed, 15 insertions(+), 15 deletions(-)
+
+commit 23435d52855b477408548100bb5e5ff3a956b27b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 13:04:27 2022 -0600
+
+    [hvar] Rename advance function for clarity
+
+ src/hb-ot-hmtx-table.hh     | 6 +++---
+ src/hb-ot-var-hvar-table.hh | 6 +++---
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+commit 9f974cae4a0f94f069f710ad04541f791d2aef16
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 13:03:12 2022 -0600
+
+    [hvar] Rename lsb function for clarity
+
+ src/hb-ot-hmtx-table.hh     | 4 ++--
+ src/hb-ot-var-hvar-table.hh | 6 +++---
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+commit ab5ce6431387be417bd312c9579208d902c9e222
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 13:00:22 2022 -0600
+
+    [VVAR] Rename vorg function for clarity
+
+ src/hb-ot-font.cc           | 6 +++---
+ src/hb-ot-var-hvar-table.hh | 6 +++---
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+commit b2d60cbd6ebbcaa51291144701312578efd90ebd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 12:56:48 2022 -0600
+
+    [glyf] Rename advance functions for clarity
+
+ src/OT/glyf/glyf.hh     | 2 +-
+ src/hb-ot-font.cc       | 4 ++--
+ src/hb-ot-hmtx-table.hh | 4 ++--
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+commit 35c00c1216f85ca543057bb7faff7247c4e8a491
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 12:54:17 2022 -0600
+
+    [hmtx] Rename advance functions for clarity
+
+ src/OT/glyf/Glyph.hh    |  4 ++--
+ src/OT/glyf/glyf.hh     |  4 ++--
+ src/hb-ot-font.cc       |  6 +++---
+ src/hb-ot-hmtx-table.hh | 18 +++++++++---------
+ 4 files changed, 16 insertions(+), 16 deletions(-)
+
+commit 6b82d4faa15e6ac00303f086160a61bc8d2027e3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 12:45:27 2022 -0600
+
+    [glyf] Make an optional argument non-optional
+
+ src/OT/glyf/glyf.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 3ef590808fb57cc3879c86ed5bf4c7301a2237da
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 12:44:24 2022 -0600
+
+    [glyf] Internal flip a variable
+
+ src/OT/glyf/glyf.hh | 28 ++++++++++++++--------------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+commit b07fa2bb1a07712bf5350955573512e60cecd53f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 2 13:43:23 2022 -0600
+
+    [ot-font] Respect VORG even if it has no variations
+
+ src/hb-ot-font.cc | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+commit 71d52e10aa353ab5e6161c66aeb00fcc68d510da
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 2 11:21:36 2022 -0600
+
+    [var] Fix getting side-bearing variations
+    
+    In HVAR/VVAR, if the side-bearing mappings are null, it means the
+    table does not have them and they should be loaded from glyf table.
+    Previous logic was returning zer0.
+    
+    Part of fixing https://github.com/harfbuzz/harfbuzz/issues/1694
+
+ src/hb-ot-hmtx-table.hh     |  5 +++--
+ src/hb-ot-var-hvar-table.hh | 12 ++++++------
+ 2 files changed, 9 insertions(+), 8 deletions(-)
+
+commit 78b4f3982193fdd0714853dd39fa60e5eafeb379
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 2 16:37:26 2022 -0600
+
+    [glyf] Fix confusion between scaled vs unscaled lsb
+    
+    Was always broken.
+
+ src/OT/glyf/glyf.hh | 28 ++++++++++++++++++++--------
+ 1 file changed, 20 insertions(+), 8 deletions(-)
+
+commit 6665881c7da58c32e243121809e154eeca33968c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 2 11:21:12 2022 -0600
+
+    [glyf] Change side-bearing rounding
+
+ src/OT/glyf/glyf.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 0a295fcde6a07271de27bbbd9ca1b47612427cdf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 1 17:16:24 2022 -0600
+
+    [var] Fix DeltaSetIndexMapFormat1
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3692
+
+ src/hb-ot-var-common.hh | 63 ++++++++++---------------------------------------
+ 1 file changed, 12 insertions(+), 51 deletions(-)
+
+commit 351cccdb75c434a46dc6193b71ba71d3d12c1857
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 1 16:52:49 2022 -0600
+
+    [buffer-deserialize] Deserialize glyph flags
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/1482
+
+ src/hb-buffer-deserialize-json.hh   | 425 +++++++++++++++------------
+ src/hb-buffer-deserialize-json.rl   |  31 +-
+ src/hb-buffer-deserialize-text.hh   | 570 ++++++++++++++++++++++++------------
+ src/hb-buffer-deserialize-text.rl   |  13 +-
+ src/hb-number-parser.hh             |   8 +-
+ src/hb-ot-shaper-indic-machine.hh   |  14 +-
+ src/hb-ot-shaper-khmer-machine.hh   |  14 +-
+ src/hb-ot-shaper-myanmar-machine.hh |  14 +-
+ src/hb-ot-shaper-use-machine.hh     |  14 +-
+ src/test-buffer-serialize.cc        |   6 +-
+ 10 files changed, 694 insertions(+), 415 deletions(-)
+
+commit 5134041f216bbe0941ea5d068e008fc534d0732e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 1 16:48:47 2022 -0600
+
+    [deserialize-json] Make it actually work!
+    
+    Was not correctly deserializing glyph names as it was not dropping
+    double-quotes from glyph name before parsing.
+
+ src/hb-buffer-deserialize-json.hh | 12 ++++++------
+ src/hb-buffer-deserialize-json.rl |  2 +-
+ src/hb-buffer-deserialize-text.hh | 10 +++++-----
+ 3 files changed, 12 insertions(+), 12 deletions(-)
+
+commit 534b0911f7e6f95e77edf853be2d90d059012b16
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 1 16:20:31 2022 -0600
+
+    [aat-layout] Add an unlikely()
+
+ src/hb-aat-layout-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b8c7c0a0e6ceb133f8c2e8f4ab15ca1633123fd2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 1 12:11:15 2022 -0600
+
+    [fuzzer] In 50% of runs don't fail the allocator
+
+ test/fuzzing/hb-draw-fuzzer.cc   |  2 +-
+ test/fuzzing/hb-fuzzer.hh        | 16 ++++++++++++++++
+ test/fuzzing/hb-set-fuzzer.cc    |  2 +-
+ test/fuzzing/hb-shape-fuzzer.cc  |  2 +-
+ test/fuzzing/hb-subset-fuzzer.cc |  2 +-
+ 5 files changed, 20 insertions(+), 4 deletions(-)
+
+commit 14b018124c52da6c7bc8ab93a2c571ca2e8c2f80
+Author: Stephan Bergmann <sbergman@redhat.com>
+Date:   Mon Aug 9 17:17:48 2021 +0200
+
+    hb_graphite2_cluster_t::advance can apparently be negative
+    
+    ...as seen with HarfBuzz used by LibreOffice, with `instdir/program/soffice
+    --headless --convert-to pdf` of doc/abi6073-2.doc from the LibreOffice crash-
+    testing corpus when run under UBSan,
+    
+    > hb-graphite2.cc:361:15: runtime error: -1024 is outside the range of representable values of type 'unsigned int'
+    >  #0 in _hb_graphite2_shape at workdir/UnpackedTarball/harfbuzz/src/hb-graphite2.cc:361:15
+    >  #1 in _hb_shape_plan_execute_internal(hb_shape_plan_t*, hb_font_t*, hb_buffer_t*, hb_feature_t const*, unsigned int) at workdir/UnpackedTarball/harfbuzz/src/./hb-shaper-list.hh:38:1
+    >  #2 in hb_shape_plan_execute at workdir/UnpackedTarball/harfbuzz/src/hb-shape-plan.cc:453:14
+    >  #3 in hb_shape_full at workdir/UnpackedTarball/harfbuzz/src/hb-shape.cc:139:19
+    >  #4 in GenericSalLayout::LayoutText(ImplLayoutArgs&, SalLayoutGlyphsImpl const*) at vcl/source/gdi/CommonSalLayout.cxx:495:23
+    >  #5 in OutputDevice::getFallbackLayout(LogicalFontInstance*, int, ImplLayoutArgs&, SalLayoutGlyphs const*) const at vcl/source/outdev/font.cxx:1232:21
+    >  #6 in OutputDevice::ImplGlyphFallbackLayout(std::unique_ptr<SalLayout, std::default_delete<SalLayout> >, ImplLayoutArgs&, SalLayoutGlyphs const*) const at vcl/source/outdev/font.cxx:1300:48
+    >  #7 in OutputDevice::ImplLayout(rtl::OUString const&, int, int, Point const&, long, long const*, SalLayoutFlags, vcl::TextLayoutCache const*, SalLayoutGlyphs const*) const at vcl/source/outdev/text.cxx:1332:22
+    >  #8 in lcl_CreateLayout(SwTextGlyphsKey const&, __gnu_debug::_Safe_iterator<std::_Rb_tree_iterator<std::pair<SwTextGlyphsKey const, SwTextGlyphsData> >, std::__debug::map<SwTextGlyphsKey, SwTextGlyphsData, std::less<SwTextGlyphsKey>, std::allocator<std::pair<SwTextGlyphsKey const, SwTextGlyphsData> > >, std::bidirectional_iterator_tag>) at sw/source/core/txtnode/fntcache.cxx:233:33
+    >  #9 in SwFntObj::GetCachedSalLayoutGlyphs(SwTextGlyphsKey const&) at sw/source/core/txtnode/fntcache.cxx:257:12
+    >  #10 in SwFont::GetTextBreak(SwDrawTextInfo const&, long) at sw/source/core/txtnode/fntcache.cxx:2551:58
+    >  #11 in SwTextSizeInfo::GetTextBreak(long, o3tl::strong_int<int, Tag_TextFrameIndex>, unsigned short, vcl::TextLayoutCache const*) const at sw/source/core/text/inftxt.cxx:450:20
+    >  #12 in SwTextGuess::Guess(SwTextPortion const&, SwTextFormatInfo&, unsigned short) at sw/source/core/text/guess.cxx:205:26
+    >  #13 in SwTextPortion::Format_(SwTextFormatInfo&) at sw/source/core/text/portxt.cxx:305:32
+    >  #14 in SwTextPortion::Format(SwTextFormatInfo&) at sw/source/core/text/portxt.cxx:456:12
+    >  #15 in SwLineLayout::Format(SwTextFormatInfo&) at sw/source/core/text/porlay.cxx:260:31
+    
+    (where in frame #4 GenericSalLayout::LayoutText, pHbBuffer->props.direction is
+    HB_DIRECTION_RTL, in case that is relevant).
+    
+    It is unclear to me whether it is sufficient to only change
+    hb_graphite2_cluster_t::advance from signed to unsigned int, as there are other
+    unsigned int variables (like curradv in _hb_graphite2_shape) whose value depend
+    on hb_graphite2_cluster_t::advance, and which thus might also become negative.
+    But unlike the float -> unsigned int conversion that UBSan warned about here
+    (where gr_slot_origin_X() and xscale are float), those are signed int ->
+    unsigned int conversions that do not cause undefined behavior.  At least, with
+    this change, the above --convert-to pdf and a full `make check screenshot`
+    succeeded for me under without further UBSan warnings.
+    
+    (For the version of HarfBuzz optionally built as part of the LibreOffice build,
+    this has been addressed with
+    <https://git.libreoffice.org/core/+/6e53e03f752c2f85283c4d47efaaf0683299783c%5E!/>
+    "external/harfbuzz: hb_graphite2_cluster_t::advance can apparently be
+    negative.")
+
+ src/hb-graphite2.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit dbfd2bf3275466ea507a8a41614e4785873213f4
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 23:04:35 2022 +0000
+
+    minor.
+
+ src/hb-subset-plan.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d6f579e96affe78919936f24cb54cb18cffe2ea5
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 22:22:03 2022 +0000
+
+    [subset] add tests that exercise script filtering.
+
+ ...egular.filter-scripts-features.1FC,21,41,20,62,63.ttf | Bin 0 -> 2856 bytes
+ ...ular.filter-scripts-features.2.1FC,21,41,20,62,63.ttf | Bin 0 -> 2856 bytes
+ ...ripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 4560 bytes
+ ...Roboto-Regular.filter-scripts-features.2.61,62,63.ttf | Bin 0 -> 2484 bytes
+ ...-Regular.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf | Bin 0 -> 2828 bytes
+ ...scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 3932 bytes
+ .../Roboto-Regular.filter-scripts-features.61,62,63.ttf  | Bin 0 -> 2484 bytes
+ ...to-Regular.filter-scripts-features.D7,D8,D9,DA,DE.ttf | Bin 0 -> 2828 bytes
+ .../Roboto-Regular.filter-scripts.1FC,21,41,20,62,63.ttf | Bin 0 -> 2972 bytes
+ ...r.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 4140 bytes
+ .../full-font/Roboto-Regular.filter-scripts.61,62,63.ttf | Bin 0 -> 2600 bytes
+ .../Roboto-Regular.filter-scripts.D7,D8,D9,DA,DE.ttf     | Bin 0 -> 2928 bytes
+ .../Roboto-Regular.no-scripts.1FC,21,41,20,62,63.ttf     | Bin 0 -> 2836 bytes
+ ...gular.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 3912 bytes
+ .../full-font/Roboto-Regular.no-scripts.61,62,63.ttf     | Bin 0 -> 2464 bytes
+ .../Roboto-Regular.no-scripts.D7,D8,D9,DA,DE.ttf         | Bin 0 -> 2808 bytes
+ ...-Roman.filter-scripts-features.1FC,21,41,20,62,63.ttf | Bin 0 -> 3476 bytes
+ ...oman.filter-scripts-features.2.1FC,21,41,20,62,63.ttf | Bin 0 -> 3476 bytes
+ ...ripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 8700 bytes
+ ...Variable-Roman.filter-scripts-features.2.61,62,63.ttf | Bin 0 -> 3476 bytes
+ ...le-Roman.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf | Bin 0 -> 3948 bytes
+ ...scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 6584 bytes
+ ...ifVariable-Roman.filter-scripts-features.61,62,63.ttf | Bin 0 -> 3476 bytes
+ ...able-Roman.filter-scripts-features.D7,D8,D9,DA,DE.ttf | Bin 0 -> 3948 bytes
+ ...fVariable-Roman.filter-scripts.1FC,21,41,20,62,63.ttf | Bin 0 -> 3856 bytes
+ ...n.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 9548 bytes
+ ...SourceSerifVariable-Roman.filter-scripts.61,62,63.ttf | Bin 0 -> 3752 bytes
+ ...SerifVariable-Roman.filter-scripts.D7,D8,D9,DA,DE.ttf | Bin 0 -> 4292 bytes
+ ...SerifVariable-Roman.no-scripts.1FC,21,41,20,62,63.ttf | Bin 0 -> 3456 bytes
+ ...Roman.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 6564 bytes
+ .../SourceSerifVariable-Roman.no-scripts.61,62,63.ttf    | Bin 0 -> 3456 bytes
+ ...urceSerifVariable-Roman.no-scripts.D7,D8,D9,DA,DE.ttf | Bin 0 -> 3928 bytes
+ test/subset/data/profiles/filter-scripts-features.2.txt  |   2 ++
+ test/subset/data/profiles/filter-scripts-features.txt    |   2 ++
+ test/subset/data/profiles/filter-scripts.txt             |   1 +
+ test/subset/data/profiles/no-scripts.txt                 |   1 +
+ test/subset/data/tests/full-font.tests                   |   4 ++++
+ 37 files changed, 10 insertions(+)
+
+commit 79bdcbef0d63607ac8f652168848e19651c5819f
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 22:20:32 2022 +0000
+
+    [subset] Fix GDEF version downgrade logic.
+
+ src/hb-ot-layout-gdef-table.hh | 18 +++++++++++-------
+ 1 file changed, 11 insertions(+), 7 deletions(-)
+
+commit 587969af42dad7342871de693bd37683822eb6cf
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 21:37:42 2022 +0000
+
+    [subset] Drop scripts that are not in the layout_scripts list.
+
+ src/hb-ot-layout-common.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 900476c635b3baaff4b1316d1220d5a073b9b51a
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 19:21:23 2022 +0000
+
+    Move GSUB.hh GPOS.hh back into the GPOS/GSUB sub directories.
+
+ src/Makefile.sources             |  4 ++--
+ src/OT/Layout/{ => GPOS}/GPOS.hh | 14 +++++++-------
+ src/OT/Layout/{ => GSUB}/GSUB.hh | 12 ++++++------
+ src/hb-ot-layout-gpos-table.hh   |  2 +-
+ src/hb-ot-layout-gsub-table.hh   |  2 +-
+ src/meson.build                  |  4 ++--
+ 6 files changed, 19 insertions(+), 19 deletions(-)
+
+commit 5fdae68481a4d53eb5a23285c62986340d7e5715
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jun 29 23:52:08 2022 +0000
+
+    [reorg] Move GSUB.hh up one level and change GSUB namespace to GSUB_impl.
+
+ src/Makefile.sources                                |  2 +-
+ src/OT/Layout/{GSUB => }/GSUB.hh                    | 21 +++++++++------------
+ src/OT/Layout/GSUB/AlternateSet.hh                  |  2 +-
+ src/OT/Layout/GSUB/AlternateSubst.hh                |  2 +-
+ src/OT/Layout/GSUB/AlternateSubstFormat1.hh         |  2 +-
+ src/OT/Layout/GSUB/ChainContextSubst.hh             |  2 +-
+ src/OT/Layout/GSUB/Common.hh                        |  2 +-
+ src/OT/Layout/GSUB/ContextSubst.hh                  |  2 +-
+ src/OT/Layout/GSUB/ExtensionSubst.hh                |  2 +-
+ src/OT/Layout/GSUB/Ligature.hh                      |  2 +-
+ src/OT/Layout/GSUB/LigatureSet.hh                   |  2 +-
+ src/OT/Layout/GSUB/LigatureSubst.hh                 |  2 +-
+ src/OT/Layout/GSUB/LigatureSubstFormat1.hh          |  2 +-
+ src/OT/Layout/GSUB/MultipleSubst.hh                 |  2 +-
+ src/OT/Layout/GSUB/MultipleSubstFormat1.hh          |  2 +-
+ src/OT/Layout/GSUB/ReverseChainSingleSubst.hh       |  2 +-
+ .../Layout/GSUB/ReverseChainSingleSubstFormat1.hh   |  2 +-
+ src/OT/Layout/GSUB/Sequence.hh                      |  2 +-
+ src/OT/Layout/GSUB/SingleSubst.hh                   |  2 +-
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh            |  2 +-
+ src/OT/Layout/GSUB/SingleSubstFormat2.hh            |  2 +-
+ src/OT/Layout/GSUB/SubstLookup.hh                   |  2 +-
+ src/OT/Layout/GSUB/SubstLookupSubTable.hh           |  2 +-
+ src/hb-ot-layout-gsub-table.hh                      |  6 +++---
+ src/hb-ot-layout.cc                                 |  2 +-
+ src/hb-ot-layout.hh                                 |  4 ++--
+ src/hb-subset-plan.cc                               |  2 +-
+ src/hb-subset.cc                                    |  2 +-
+ src/meson.build                                     |  2 +-
+ 29 files changed, 40 insertions(+), 43 deletions(-)
+
+commit 38e81f2be9711f5dcde3b9cae40fdddb9104c493
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 21:09:11 2022 +0000
+
+    [subset] Add --layout-scripts command line flag.
+
+ util/hb-subset.cc | 61 +++++++++++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 48 insertions(+), 13 deletions(-)
+
+commit 70e32a662f53409a849ad175d460dd524da14489
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 21:00:48 2022 +0000
+
+    [subset] Add layout_scripts to subset input.
+
+ src/hb-subset-input.cc | 2 ++
+ src/hb-subset-input.hh | 1 +
+ src/hb-subset-plan.cc  | 3 +--
+ src/hb-subset.h        | 3 +++
+ 4 files changed, 7 insertions(+), 2 deletions(-)
+
+commit 13c499cb26e11494f53709efabcff79a962b3d95
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 30 14:25:09 2022 -0600
+
+    [hvar] Minor internal rewiring
+    
+    Not passing font to functions makes it more clear that they don't
+    scale values.
+
+ src/hb-ot-hmtx-table.hh     | 10 ++++++----
+ src/hb-ot-var-hvar-table.hh |  5 ++---
+ 2 files changed, 8 insertions(+), 7 deletions(-)
+
+commit 41d2c335bcf7f4f57b91ec8469dbfaa4d7b47e84
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 20:24:42 2022 +0000
+
+    [subset] Apply script list filter when doing layout collection.
+
+ src/hb-subset-plan.cc | 27 ++++++++++++---------------
+ 1 file changed, 12 insertions(+), 15 deletions(-)
+
+commit e5c8a2f4e11fa2b5b1b64ecf1d210fc3dc862381
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 20:14:29 2022 +0000
+
+    [subset] Pass plan through to collect methods.
+    
+    Allows to more easily access the filtering sets as they are added and enables propagating errors to the plan.
+
+ src/hb-subset-plan.cc | 40 ++++++++++++++++------------------------
+ 1 file changed, 16 insertions(+), 24 deletions(-)
+
+commit aba4a4957ad48fd34917d44d7005ffe73b3065e9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 30 14:13:44 2022 -0600
+
+    [ot-font] Disable VORG variation code in HB_NO_VAR
+
+ src/hb-ot-font.cc | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit d5921b379b91bdb4a3d5b2b62036d6f8d8613b0f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 30 14:08:29 2022 -0600
+
+    [tt-font] Apply VVAR.vOrg variation to VORG origin
+    
+    Mostly fixes https://github.com/harfbuzz/harfbuzz/issues/1694
+
+ src/hb-ot-font.cc           | 13 ++++++++++++-
+ src/hb-ot-var-hvar-table.hh | 10 ++++++++++
+ 2 files changed, 22 insertions(+), 1 deletion(-)
+
+commit eee29f7327de51d735c56b26798f2d296d1cb485
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 30 14:03:07 2022 -0600
+
+    [hmtx] Specialize var_table
+
+ src/hb-ot-font.cc       |  4 ++--
+ src/hb-ot-hmtx-table.hh | 10 +++++-----
+ 2 files changed, 7 insertions(+), 7 deletions(-)
+
+commit 031fd20a5a9e86f96f7fea1598a18f76875d828d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 30 13:50:18 2022 -0600
+
+    [perf] Update README
+
+ perf/README.md | 16 ++++++++++++----
+ 1 file changed, 12 insertions(+), 4 deletions(-)
+
+commit 1bf051ef3bafe2d6c24983863dc3bf2f04505b3c
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 20:03:33 2022 +0000
+
+    [subset] refactor feature tag filtering so it can be used for scripts as well.
+
+ src/hb-subset-plan.cc | 68 +++++++++++++++++++++++++++++++++------------------
+ src/hb-subset-plan.hh |  3 +++
+ 2 files changed, 47 insertions(+), 24 deletions(-)
+
+commit f6f93c30f3dd966dd0a041f3a5876a892ebcacfa
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Jun 30 08:50:59 2022 +0200
+
+    [docs] Fix warning
+    
+    These comment blocks don’t use gtk-doc syntax.
+
+ src/hb-subset-repacker.h | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit d9c5292b277116af5317afc46c745f0058e6c042
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Jun 30 08:47:49 2022 +0200
+
+    [docs] Remove duplicate or non existing symbols
+
+ docs/harfbuzz-sections.txt | 5 -----
+ 1 file changed, 5 deletions(-)
+
+commit 98e90cc67cdff8cee730e8459692bc4a07d9a279
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Jun 30 08:43:57 2022 +0200
+
+    [docs] Reduce warnings
+    
+    Use markdown syntax for inline code blocks instead of %true, %false, and
+    %NULL.
+
+ src/hb-aat-layout.cc       |  6 +++---
+ src/hb-blob.cc             | 10 +++++-----
+ src/hb-buffer-serialize.cc | 24 ++++++++++++------------
+ src/hb-buffer.cc           | 38 +++++++++++++++++++-------------------
+ src/hb-buffer.h            |  6 +++---
+ src/hb-common.cc           | 26 +++++++++++++-------------
+ src/hb-deprecated.h        |  2 +-
+ src/hb-draw.cc             |  4 ++--
+ src/hb-face.cc             |  4 ++--
+ src/hb-font.cc             | 36 ++++++++++++++++++------------------
+ src/hb-font.h              | 14 +++++++-------
+ src/hb-ft.cc               |  4 ++--
+ src/hb-graphite2.cc        |  2 +-
+ src/hb-map.cc              | 10 +++++-----
+ src/hb-ot-color.cc         |  8 ++++----
+ src/hb-ot-layout.cc        | 40 ++++++++++++++++++++--------------------
+ src/hb-ot-math.cc          |  4 ++--
+ src/hb-ot-var.cc           |  4 ++--
+ src/hb-set.cc              | 20 ++++++++++----------
+ src/hb-shape-plan.cc       |  4 ++--
+ src/hb-shape.cc            | 12 ++++++------
+ src/hb-subset-input.cc     |  4 ++--
+ src/hb-subset-plan.cc      |  2 +-
+ src/hb-unicode.cc          |  8 ++++----
+ src/hb-unicode.h           |  4 ++--
+ 25 files changed, 148 insertions(+), 148 deletions(-)
+
+commit c69ec6f5bb42f9efe56e9c8086624458a359c5ae
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 29 16:32:30 2022 -0600
+
+    [kern2] Fix sanitize issue on 32bit systems
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3483
+
+ src/hb-aat-layout-common.hh | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+commit 32e542d6f00992e0c2c1f51248242ab52ec278ab
+Author: Frédéric Wang <fwang@igalia.com>
+Date:   Wed Jun 29 06:45:38 2022 +0200
+
+    try & fix build errors on the bot
+
+ test/api/test-ot-face.c | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+commit 03d23767455539ebcaf01d4407a532c073d227ed
+Author: Frédéric Wang <fwang@igalia.com>
+Date:   Wed Jun 29 06:21:31 2022 +0200
+
+    [math] Improve fuzzing coverage
+    
+    Extend testing to cover parts that are missing according to the recent
+    oss-fuzz-coverage report:
+    - Retriving all constants from MathConstants.
+    - Retrieving entries from MathKern, MathGlyphPartRecord and
+      MathGlyphAssembly.
+    - Retrieving italic correction from MathGlyphAssembly.
+    - Choosing between horizontal/vertical offset in MathVariants.
+    
+    https://storage.googleapis.com/oss-fuzz-coverage/harfbuzz/reports/20220627/linux/src/harfbuzz/src/hb-ot-math-table.hh.html
+    https://github.com/harfbuzz/harfbuzz/issues/3688
+
+ test/api/test-ot-face.c | 37 +++++++++++++++++++++++++++++++------
+ 1 file changed, 31 insertions(+), 6 deletions(-)
+
+commit 22835dea292fb476dbce157d7dea5e57effcde47
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Jun 29 07:49:28 2022 +0200
+
+    [docs] Add missing symbol
+
+ docs/harfbuzz-sections.txt | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 34d3d49e7898566b8a70177b8b8f934a485cc040
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Jun 29 07:46:21 2022 +0200
+
+    [docs] Fix Since annotation
+
+ src/hb-font.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 096aaa62a6e0d07c02a4894fc036efc927e5aaf9
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Jun 29 07:30:05 2022 +0200
+
+    4.4.1
+
+ NEWS             | 7 +++++++
+ configure.ac     | 2 +-
+ meson.build      | 2 +-
+ src/hb-version.h | 4 ++--
+ 4 files changed, 11 insertions(+), 4 deletions(-)
+
+commit 4d1d7aec8d7430ea062241b46be5fa78660df2f4
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Jun 29 07:29:39 2022 +0200
+
+    [docs] Add missing 4.4.0 index
+
+ docs/harfbuzz-docs.xml | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 050f169078e272abb56c35fe3ec00a1c6238e518
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 28 18:52:27 2022 -0600
+
+    [GPOS/kerx] Call into impl namespace from kerx
+
+ src/hb-aat-layout-kerx-table.hh | 8 ++++----
+ src/hb-ot-layout-gpos-table.hh  | 3 ---
+ 2 files changed, 4 insertions(+), 7 deletions(-)
+
+commit 910a137f4ef61b4986fb9071253e25b4f9c56c06
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jun 29 00:05:35 2022 +0000
+
+    [reorg] Fix propagate_attachment_offsets definition.
+
+ src/OT/Layout/GPOS.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 3fbf2dece7f2a0b5820e01846da76114babe5a2f
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Jun 28 23:55:32 2022 +0000
+
+    [reorg] Move OT::Layout::GPOS_impl::GPOS to OT::Layout::GPOS.
+
+ src/Makefile.sources             | 29 +++++++++++++++++++++++++++
+ src/OT/Layout/{GPOS => }/GPOS.hh | 42 ++++++++++++++++++----------------------
+ src/OT/Layout/GPOS/PosLookup.hh  |  2 +-
+ src/hb-ot-layout-gpos-table.hh   |  2 +-
+ src/hb-ot-layout.cc              |  2 +-
+ src/hb-subset-plan.cc            |  2 +-
+ src/hb-subset.cc                 |  2 +-
+ src/meson.build                  | 29 +++++++++++++++++++++++++++
+ 8 files changed, 82 insertions(+), 28 deletions(-)
+
+commit 88ef3c5a9abc22927365e9c60d7aa0e3e8a339b9
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Jun 28 23:26:49 2022 +0000
+
+    [reorg] Change OT::Layout::GPOS to OT::Layout::GPOS_impl.
+
+ src/OT/Layout/GPOS/Anchor.hh             |  2 +-
+ src/OT/Layout/GPOS/AnchorFormat1.hh      |  2 +-
+ src/OT/Layout/GPOS/AnchorFormat2.hh      |  2 +-
+ src/OT/Layout/GPOS/AnchorFormat3.hh      |  2 +-
+ src/OT/Layout/GPOS/AnchorMatrix.hh       |  2 +-
+ src/OT/Layout/GPOS/ChainContextPos.hh    |  2 +-
+ src/OT/Layout/GPOS/Common.hh             |  2 +-
+ src/OT/Layout/GPOS/ContextPos.hh         |  2 +-
+ src/OT/Layout/GPOS/CursivePos.hh         |  2 +-
+ src/OT/Layout/GPOS/CursivePosFormat1.hh  |  4 ++--
+ src/OT/Layout/GPOS/ExtensionPos.hh       |  2 +-
+ src/OT/Layout/GPOS/GPOS.hh               |  6 +++---
+ src/OT/Layout/GPOS/MarkArray.hh          |  2 +-
+ src/OT/Layout/GPOS/MarkBasePos.hh        |  2 +-
+ src/OT/Layout/GPOS/MarkBasePosFormat1.hh |  2 +-
+ src/OT/Layout/GPOS/MarkLigPos.hh         |  2 +-
+ src/OT/Layout/GPOS/MarkLigPosFormat1.hh  |  2 +-
+ src/OT/Layout/GPOS/MarkMarkPos.hh        |  2 +-
+ src/OT/Layout/GPOS/MarkMarkPosFormat1.hh |  2 +-
+ src/OT/Layout/GPOS/MarkRecord.hh         |  2 +-
+ src/OT/Layout/GPOS/PairPos.hh            |  2 +-
+ src/OT/Layout/GPOS/PairPosFormat1.hh     |  2 +-
+ src/OT/Layout/GPOS/PairPosFormat2.hh     |  2 +-
+ src/OT/Layout/GPOS/PosLookup.hh          |  2 +-
+ src/OT/Layout/GPOS/PosLookupSubTable.hh  |  2 +-
+ src/OT/Layout/GPOS/SinglePos.hh          |  2 +-
+ src/OT/Layout/GPOS/SinglePosFormat1.hh   |  2 +-
+ src/OT/Layout/GPOS/SinglePosFormat2.hh   |  2 +-
+ src/OT/Layout/GPOS/ValueFormat.hh        |  2 +-
+ src/hb-ot-layout-gpos-table.hh           | 20 ++++++++++----------
+ src/hb-ot-layout.cc                      |  2 +-
+ src/hb-subset-plan.cc                    |  2 +-
+ src/hb-subset.cc                         |  2 +-
+ 33 files changed, 45 insertions(+), 45 deletions(-)
+
+commit 49ddf069e02bea6786f47780cbd2e5917e9364a5
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Jun 28 23:15:07 2022 +0000
+
+    [reorg] Move GPOS reverse_cursive_minor_offset implementation into new directory layout.
+
+ src/OT/Layout/GPOS/CursivePosFormat1.hh | 25 ++++++++++++++-
+ src/hb-ot-layout-gpos-table.hh          | 56 ++++++---------------------------
+ 2 files changed, 33 insertions(+), 48 deletions(-)
+
+commit 74f45f7c2ac4bb1d465926ebf2c3fba5a4572767
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jun 24 23:14:30 2022 +0000
+
+    [reorg] Move remaining GPOS lookup types to new directory.
+
+ src/OT/Layout/GPOS/ChainContextPos.hh    |  14 ++
+ src/OT/Layout/GPOS/ContextPos.hh         |  14 ++
+ src/OT/Layout/GPOS/ExtensionPos.hh       |  17 ++
+ src/OT/Layout/GPOS/GPOS.hh               | 101 +++++++-
+ src/OT/Layout/GPOS/MarkBasePos.hh        |   1 +
+ src/OT/Layout/GPOS/MarkLigPos.hh         |   1 +
+ src/OT/Layout/GPOS/MarkMarkPos.hh        |  36 +++
+ src/OT/Layout/GPOS/MarkMarkPosFormat1.hh | 227 ++++++++++++++++++
+ src/OT/Layout/GPOS/PosLookup.hh          |   1 -
+ src/OT/Layout/GPOS/PosLookupSubTable.hh  |   6 +-
+ src/OT/Layout/GPOS/ValueFormat.hh        |   2 +
+ src/hb-ot-layout-gpos-table.hh           | 382 +------------------------------
+ src/hb-ot-layout.cc                      |  15 +-
+ src/hb-subset-plan.cc                    |   6 +-
+ src/hb-subset.cc                         |   3 +-
+ 15 files changed, 442 insertions(+), 384 deletions(-)
+
+commit 197d9a5c994eb41c8c89b7b958b26b1eacfeeb00
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jun 24 22:36:14 2022 +0000
+
+    [reorg] Move more GPOS lookups to new directory.
+
+ src/OT/Layout/GPOS/Anchor.hh             |  84 +++
+ src/OT/Layout/GPOS/AnchorFormat1.hh      |  46 ++
+ src/OT/Layout/GPOS/AnchorFormat2.hh      |  58 ++
+ src/OT/Layout/GPOS/AnchorFormat3.hh      |  70 +++
+ src/OT/Layout/GPOS/AnchorMatrix.hh       |  77 +++
+ src/OT/Layout/GPOS/Common.hh             |  14 +
+ src/OT/Layout/GPOS/CursivePosFormat1.hh  |   2 +
+ src/OT/Layout/GPOS/MarkArray.hh          | 113 ++++
+ src/OT/Layout/GPOS/MarkBasePos.hh        |  34 ++
+ src/OT/Layout/GPOS/MarkBasePosFormat1.hh | 217 ++++++++
+ src/OT/Layout/GPOS/MarkLigPos.hh         |  34 ++
+ src/OT/Layout/GPOS/MarkLigPosFormat1.hh  | 244 +++++++++
+ src/OT/Layout/GPOS/MarkRecord.hh         |  52 ++
+ src/OT/Layout/GPOS/PosLookupSubTable.hh  |   2 +
+ src/hb-ot-layout-gpos-table.hh           | 875 +------------------------------
+ 15 files changed, 1049 insertions(+), 873 deletions(-)
+
+commit c7307ca06ab3126f7783093a27388745af1d646b
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jun 24 22:01:02 2022 +0000
+
+    [reorg] Begin moving GPOS into the new directory layout.
+
+ src/OT/Layout/GPOS/Common.hh            |   18 +
+ src/OT/Layout/GPOS/CursivePos.hh        |   35 +
+ src/OT/Layout/GPOS/CursivePosFormat1.hh |  256 ++++
+ src/OT/Layout/GPOS/GPOS.hh              |   69 ++
+ src/OT/Layout/GPOS/PairPos.hh           |   38 +
+ src/OT/Layout/GPOS/PairPosFormat1.hh    |  420 +++++++
+ src/OT/Layout/GPOS/PairPosFormat2.hh    |  314 +++++
+ src/OT/Layout/GPOS/PosLookup.hh         |   80 ++
+ src/OT/Layout/GPOS/PosLookupSubTable.hh |   73 ++
+ src/OT/Layout/GPOS/SinglePos.hh         |   98 ++
+ src/OT/Layout/GPOS/SinglePosFormat1.hh  |  124 ++
+ src/OT/Layout/GPOS/SinglePosFormat2.hh  |  140 +++
+ src/OT/Layout/GPOS/ValueFormat.hh       |  327 +++++
+ src/hb-ot-layout-gpos-table.hh          | 1975 ++-----------------------------
+ 14 files changed, 2075 insertions(+), 1892 deletions(-)
+
+commit 7b0d8d9d18fe4d0371b62bdc87b9d6e52e05f6e2
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Jun 29 00:34:09 2022 +0200
+
+    [meson] Remove ttf-parser wrap
+    
+    We don’t have a ttf-parser dependency anymore.
+
+ Makefile.am                 | 1 -
+ subprojects/ttf-parser.wrap | 5 -----
+ 2 files changed, 6 deletions(-)
+
+commit 9909d11f6f7b3eeddc00a981e24f26559d9ef3b7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 28 15:59:40 2022 -0600
+
+    [indic generator] Fix regression
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3690
+
+ src/gen-indic-table.py                                   |   2 +-
+ src/hb-ot-shaper-indic-table.cc                          |  12 ++++++------
+ .../fonts/e716f6bd00a108d186b7e9f47b4515565f784f36.ttf   | Bin 0 -> 6260 bytes
+ test/shape/data/in-house/tests/indic-special-cases.tests |   1 +
+ 4 files changed, 8 insertions(+), 7 deletions(-)
+
+commit 4499ae0225172ab7590619219b21fe0a0c14d66e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 28 15:43:57 2022 -0600
+
+    [coretext] Fix positioning of out-of-order glyphs
+    
+    Unfortunately this now generates negative advances. To be fixed...
+
+ src/hb-coretext.cc | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+commit 58d2e9309952c139a4fa05ed44c22bb712fd6cd4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 28 15:38:58 2022 -0600
+
+    [coretext] Fix up clusters only if needed
+
+ src/hb-coretext.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit eaba5e74a9285647739dfc563471321d4d0ec9e0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 28 13:47:49 2022 -0600
+
+    [directwrite] Simplify
+
+ src/hb-directwrite.cc | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+commit 33e3bf2d79c9b5598ba373ab093ec8b71404794b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 28 13:46:04 2022 -0600
+
+    [font] Drop caches on variation changes
+
+ src/hb-font.cc | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit c90130e6252b2914d9fdf9007a62fc924ef3d963
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 28 13:30:44 2022 -0600
+
+    [coretext] Remove old hack now that font layer takes care...
+    
+    of invalidating font data when font settings change.
+
+ src/hb-coretext.cc | 37 +++----------------------------------
+ 1 file changed, 3 insertions(+), 34 deletions(-)
+
+commit c1c78ade71fabe826f695704acda836c7bc21bf4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 28 13:19:12 2022 -0600
+
+    [font] When font changes, drop font shaper data
+    
+    https://github.com/harfbuzz/harfbuzz/issues/3683#issuecomment-1168016509
+
+ src/hb-font.hh      | 2 ++
+ src/hb-machinery.hh | 2 +-
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+commit 34c6c0193c57110219eecd58cc67daffcd84d071
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 20:26:19 2022 -0600
+
+    [glyf] Fix byterange check again
+
+ src/OT/glyf/SimpleGlyph.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 20572f914ce7c386e9ffb9cc2833b1f43d0025b2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 20:22:09 2022 -0600
+
+    [glyf] Move read_flags into a function
+
+ src/OT/glyf/SimpleGlyph.hh | 41 ++++++++++++++++++++++++-----------------
+ 1 file changed, 24 insertions(+), 17 deletions(-)
+
+commit 7b0fc0be539ae02af71a7fa076a96c779c116b68
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Mon Jun 27 21:18:36 2022 -0400
+
+    [test] Test the reordering of U+0E33 and U+0EB3
+
+ test/shape/README.md                               |   2 +-
+ test/shape/data/in-house/Makefile.sources          |   1 +
+ .../63a539a90a371ccf028dc2dcced9b63b07163be7.ttf   | Bin 0 -> 1656 bytes
+ test/shape/data/in-house/meson.build               |   1 +
+ test/shape/data/in-house/tests/sara-am.tests       |  52 +++++++++++++++++++++
+ 5 files changed, 55 insertions(+), 1 deletion(-)
+
+commit 3c34b9ec30f4d07414a8053ae39be555001c64cc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 19:45:58 2022 -0600
+
+    [mingw2] Turn optimization flag on
+
+ mingw-configure.sh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 31e985d7d1089e50c80c7186ebf1e475cc6c238d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 16:32:02 2022 -0600
+
+    [buffer] Likely that not messaging
+
+ src/hb-buffer.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4be074e2cb6d94fb9dfb833e713e30c0e6c6cc72
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 16:12:42 2022 -0600
+
+    [gvar] Whitespace
+
+ src/hb-ot-var-gvar-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a96647841afb02579caf7eb926dfeb7979cbfbe7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 15:41:02 2022 -0600
+
+    [gvar] Optimize apply_deltas_to_points
+
+ src/hb-ot-var-gvar-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit e9af9062c0e1be1f479a43ad878cda622c781a56
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 15:38:42 2022 -0600
+
+    [gvar] Optimize unpack_deltas
+
+ src/hb-ot-var-gvar-table.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 573e77280b4f78c9a880c4abfa1f86d70354bc79
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 15:35:28 2022 -0600
+
+    [gvar] Optimize unpack_deltas
+
+ src/hb-ot-var-gvar-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 698f51464c4a8f2e7e49c2e99fb0c8b4bfce9493
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 15:30:19 2022 -0600
+
+    [gvar] Share vector allocation across delta-sets
+
+ src/hb-ot-var-gvar-table.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 39e280c256894662d4591b4de7517b7e1147c66f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 15:25:50 2022 -0600
+
+    [gvar] Handle a couple of error conditions
+
+ src/hb-ot-var-gvar-table.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 5be6e5dd577b8680ee5ffdedeec93638dffb5547
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 15:22:16 2022 -0600
+
+    [gvar] Rewrite linear interpolation
+
+ src/hb-ot-var-gvar-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 57519b532da6fb1ef2442eb1eda26192f9617552
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 15:18:56 2022 -0600
+
+    [gvar] Use pointer-to-member instead of function
+
+ src/hb-ot-var-gvar-table.hh | 20 +++++++++-----------
+ 1 file changed, 9 insertions(+), 11 deletions(-)
+
+commit ab15fe082ab79b608d9ff346c92dcc000404343d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 15:13:10 2022 -0600
+
+    [gvar] Handle a couple of error conditions
+
+ src/hb-ot-var-gvar-table.hh | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+commit b7e9e8785c75b1a9b97a6eb648e5887093a3257a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 15:08:51 2022 -0600
+
+    [gvar] Optimize deltas and points loading
+
+ src/hb-ot-var-gvar-table.hh | 34 ++++++++++++++++------------------
+ 1 file changed, 16 insertions(+), 18 deletions(-)
+
+commit 6e72c2e3faf84634ac98d31be2344c2d604bed14
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 14:02:15 2022 -0600
+
+    [glyf] Add an assertion
+
+ src/OT/glyf/SimpleGlyph.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 5da341ce92352860fb43296cdeb7ed4141ff2864
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 13:29:22 2022 -0600
+
+    [map] Another try at hiding minus1
+    
+    To fix https://github.com/harfbuzz/harfbuzz/issues/3684
+
+ src/hb-map.hh    | 8 +++++++-
+ src/hb-static.cc | 3 +++
+ 2 files changed, 10 insertions(+), 1 deletion(-)
+
+commit c72d3104ed0fe1fa91eb1ff02b0761578161edb0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 13:31:05 2022 -0600
+
+    [map] Return const reference in operator[]
+
+ src/hb-map.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 69d53f3e7fde164a1fe7bb5f812045e5275893a7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 13:17:10 2022 -0600
+
+    [map] Make default_value() inline
+    
+    See if it make fix https://github.com/harfbuzz/harfbuzz/issues/3684
+
+ src/hb-map.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 3a0e27e794bd7a0a49ed5be41c044d9be910ea07
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 13:07:39 2022 -0600
+
+    [glyf] Move comment
+
+ src/OT/glyf/Glyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d0836dee7a6b81a4d037b3e1dc841416cc14bf87
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 13:05:58 2022 -0600
+
+    [glyf] Minor typo change
+
+ src/OT/glyf/SimpleGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 5cca25e5d0d976020eead5113da82aae11c0d2ae
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 13:03:06 2022 -0600
+
+    [glyf] Accumulate points as int
+    
+    Everything is int at this stage.
+    Doesn't seem to matter for performance though.
+
+ src/OT/glyf/SimpleGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d6f60b3c190e3fd050f8c4a0613939d417f53a69
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 13:00:08 2022 -0600
+
+    [glyf] Minor optimization
+
+ src/OT/glyf/SimpleGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b30a3dcba3e69f93e551fb1736785dcec5a0ca70
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 12:56:21 2022 -0600
+
+    [glyf] Another bounds check
+    
+    Very unlikely that is needed but technically possible.
+
+ src/OT/glyf/SimpleGlyph.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 2e9dbdcbbe17a1c55e39f1d4acef023e5a26842f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 12:55:13 2022 -0600
+
+    [glyf] Protect against an unlikely overflow
+
+ src/OT/glyf/SimpleGlyph.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 8537d681728e141550b4470b591fa059f6ca2670
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Jun 27 20:51:16 2022 +0200
+
+    4.4.0
+
+ NEWS             | 34 ++++++++++++++++++++++++++++++++++
+ configure.ac     |  2 +-
+ meson.build      |  2 +-
+ src/hb-buffer.h  |  4 ++--
+ src/hb-font.cc   |  4 ++--
+ src/hb-ft.cc     |  2 +-
+ src/hb-map.cc    |  4 ++--
+ src/hb-set.cc    |  2 +-
+ src/hb-version.h |  4 ++--
+ 9 files changed, 46 insertions(+), 12 deletions(-)
+
+commit f1fb8c4489f3530badaab6c4f1172f044febc346
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 12:41:46 2022 -0600
+
+    [glyf] Optimize Glyph layout
+
+ src/OT/glyf/Glyph.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 34e3f561b53de6feaa6d3f2dfea6014a12661d86
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 12:39:35 2022 -0600
+
+    [glyf] Fix a bug I introduced recently
+    
+    Pass gid to Glyph in trim_padding codepath.
+
+ src/OT/glyf/glyf.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 97cbc2d40a2af1ecb3c1a8c765807e56ffdb4dba
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 12:37:11 2022 -0600
+
+    [gvar] Remove condition that font num_coords should match gvar's
+
+ src/hb-ot-var-gvar-table.hh | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+commit 19cbfb9ce962ff18234f564de4c578209dd0d319
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 12:32:18 2022 -0600
+
+    [glyf] Relax a condition that font num_coords be equal to gvar's
+    
+    gvar itself still checks the same.
+
+ src/OT/glyf/glyf.hh | 2 +-
+ src/hb-coretext.cc  | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit d5cfbaa0684d4bf33e21bf1609f730436312bc10
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 12:24:20 2022 -0600
+
+    [glyf] Optimize composite points loading
+
+ src/OT/glyf/Glyph.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 32dc0641e17a339c5d429fc5f59c1b086dc96c47
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 12:22:06 2022 -0600
+
+    [glyf] Remove an unnecessary condition
+
+ src/OT/glyf/Glyph.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 95bfa0913da18bc752030ca814c9339bbc76159b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 12:09:42 2022 -0600
+
+    [gvar] Optimize translate()
+
+ src/hb-ot-var-gvar-table.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 9f067582b80ade3235f4c290afbb65b2851ada78
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 12:08:47 2022 -0600
+
+    [gvar] Optimize transform()
+
+ src/hb-ot-var-gvar-table.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit cfc57ef862c911c2e2c6dc9992e866373b6ba89f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 11:56:28 2022 -0600
+
+    [glyf] Optimize contour_point_t layout
+
+ src/hb-ot-var-gvar-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 75ca78a6bbbfda8d8fcb363ef71d3012949aee5e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 11:55:37 2022 -0600
+
+    [glyf] Optimize hb_contour_points_t::extend
+
+ src/hb-ot-var-gvar-table.hh | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+commit 98fbe87a26f5b4ef480c1f68526479e0b7121ddd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 11:48:59 2022 -0600
+
+    [benchmark-font] Disable quadratic callback
+    
+    We are interested in the quadratic-to-cubic codepath benchmarking.
+
+ perf/benchmark-font.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 04c4767150fe398d1f687e044cfc014151ad5e26
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sun Jun 26 21:44:51 2022 -0400
+
+    [lao] Decompose and reorder U+0EB3 around U+0EBB
+
+ src/hb-algs.hh           | 5 +++++
+ src/hb-ot-shaper-thai.cc | 8 ++++----
+ 2 files changed, 9 insertions(+), 4 deletions(-)
+
+commit d3308f4713eb9087a300c0db9b1ca06015180e7f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 11:28:44 2022 -0600
+
+    [font] Optimize font scaling further
+
+ src/hb-font.cc       |  9 ++++-----
+ src/hb-font.hh       | 37 +++++++++++++++++++------------------
+ test/api/test-draw.c |  2 +-
+ 3 files changed, 24 insertions(+), 24 deletions(-)
+
+commit e72506d08545c17c8f71a2d7167828a3c6aef8db
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Mon Jun 27 07:41:13 2022 -0400
+
+    Fix the annotation for hb_blob_get_data
+    
+    This function will return NULL for the the
+    empty blob. That is important information for
+    bindings that treat nullability as a type trait.
+
+ src/hb-blob.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3c49a6a60a26bacfa0fc1284566db7a9c680e9c2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 27 10:57:51 2022 -0600
+
+    [glyf] Fix an allocation error
+    
+    Try fixing assertion failure found by fuzzers:
+    
+    hb-draw-fuzzer: ../../src/harfbuzz/src/OT/glyf/glyf.hh:175: bool OT::glyf_accelerator_t::get_points(hb_font_t *, hb_codepoint_t, T) const [T = OT::glyf_impl::path_builder_t]: Assertion `count >= glyf_impl::PHANTOM_COUNT' failed.
+
+ src/OT/glyf/Glyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 556e7078f0cc283d95d6e5814ed3c64a2c02d9a8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 26 17:48:43 2022 -0600
+
+    [font] Optimize glyph scaling
+
+ src/hb-font.cc       |  4 ++++
+ src/hb-font.hh       | 13 ++++++++-----
+ test/api/test-draw.c |  2 +-
+ 3 files changed, 13 insertions(+), 6 deletions(-)
+
+commit a1c45bbb55a753ac6f6ad166fc87097dac95dea6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 26 17:30:16 2022 -0600
+
+    [glyf] Minor simplify
+
+ src/OT/glyf/SimpleGlyph.hh | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+commit a21a9bb855de199bacb80a15049340d818edcd41
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 26 17:24:29 2022 -0600
+
+    [glyf] Optimize flags decoding byte range checking
+
+ src/OT/glyf/SimpleGlyph.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 0f1fdf461c1abd1fa0674d0619402942494bd69c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 26 17:22:45 2022 -0600
+
+    [glyf] Optimize points decoding byte range checking
+
+ src/OT/glyf/SimpleGlyph.hh | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+commit 51cfcf29571dba41281fbb96fb1dd943f2ef1e44
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 26 17:04:47 2022 -0600
+
+    [glyf] Optimize points decoding
+
+ src/OT/glyf/SimpleGlyph.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit 86b702250361485f0d57dcf6fe4a38eaacf0d87e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 26 16:56:24 2022 -0600
+
+    [glyf] Optimize flag decoding
+
+ src/OT/glyf/SimpleGlyph.hh | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+commit 30d58bfd0f4b3c0b97740281ae680c3164dd17d0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 26 16:47:21 2022 -0600
+
+    [glyf] Don't translate/transform components if has no effect
+
+ src/hb-ot-var-gvar-table.hh | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit 2bb0fa878a3c1f51bb9d944829465bc1a4262d37
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 26 16:43:05 2022 -0600
+
+    [glyf] Remove unneeded point init()
+
+ src/OT/glyf/Glyph.hh | 3 ---
+ 1 file changed, 3 deletions(-)
+
+commit fc72a1d22dc9efd52a9fa43143673253b20b0c69
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 26 16:42:01 2022 -0600
+
+    [glyf] Add a pre-allocation for phantom points
+
+ src/OT/glyf/SimpleGlyph.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 8d242aaa8ba7a2669fd7f1b393a2ba130ffb8544
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 26 16:36:08 2022 -0600
+
+    [glyf] Rewrite a loop harmlessly
+    
+    I hope...
+
+ src/OT/glyf/glyf.hh | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit cf57f04ddb8a731b13c9e09cb40c43253faa1fdb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 26 16:26:17 2022 -0600
+
+    [glyf/path-builder] Optimize scaling code
+    
+    Scale each point once upon entry to function.
+    
+    This makes our shape fetching code as fast as FreeType for all
+    benchmark cases now.
+
+ src/OT/glyf/path-builder.hh | 32 ++++++++++++++++----------------
+ 1 file changed, 16 insertions(+), 16 deletions(-)
+
+commit 36dd5d32fbcce76b5d58496ca8075bc5c71ae2de
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 26 16:16:43 2022 -0600
+
+    [draw] Use multiplication instead of division in quadratic conversion
+
+ src/hb-draw.cc | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+commit b095df1343d6d883f602ef4e18230dd6d1d0a816
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 26 16:12:50 2022 -0600
+
+    [glyf/path-builder] Use operator bool for style
+
+ src/OT/glyf/path-builder.hh | 17 +++++++++--------
+ 1 file changed, 9 insertions(+), 8 deletions(-)
+
+commit abb433d0f4736376d82e488b7790c02ec98351d2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 26 16:09:32 2022 -0600
+
+    [glyf] Avoid a copy of points in shape fetching for simple glyphs
+    
+    Matches performance with freetype now.
+
+ src/OT/glyf/Glyph.hh | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+commit 7eac779abf14243124af2c6e89cff71e18e41cb3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 26 16:02:27 2022 -0600
+
+    Revert "Revert "[glyf] Optimize shape loading""
+    
+    This reverts commit 164bd288cfe66f1742183ab38fa9bd121b1cd8a0.
+
+ src/OT/glyf/Glyph.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 164bd288cfe66f1742183ab38fa9bd121b1cd8a0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 26 16:01:15 2022 -0600
+
+    Revert "[glyf] Optimize shape loading"
+    
+    This reverts commit f0819301b74871c4c0a58e16918d3f8df2c6f74d.
+    
+    Broke tests. To be debugged and redone.
+
+ src/OT/glyf/Glyph.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit f0819301b74871c4c0a58e16918d3f8df2c6f74d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 26 15:52:54 2022 -0600
+
+    [glyf] Optimize shape loading
+    
+    Do away with a copy for simple glyph load.
+
+ src/OT/glyf/Glyph.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit ea5131507a723b4858f6a90584351ac14a990ecb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 26 13:30:11 2022 -0600
+
+    [mingw] Build with directwrite if available
+
+ configure.ac       | 2 +-
+ mingw-configure.sh | 2 ++
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+commit 65b066f18e835d7cba57bea84fc5b244ad5e5b90
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 26 13:18:00 2022 -0600
+
+    [glyf/path-builder] Simplify initialization
+
+ src/OT/glyf/path-builder.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit b2abd5c7e8c757db793243856debfd57eefb320a
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Jun 25 22:55:50 2022 -0400
+
+    [thai] Reword to include all relevant marks
+
+ src/hb-ot-shaper-thai.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 2d4557fe04504d97db02e697482388a91fc9613e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 19:28:33 2022 -0600
+
+    [glyf/SimpleGlyph] Use member pointer instead of lambda
+
+ src/OT/glyf/SimpleGlyph.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 9ce97730404300eed6d8ec1ea806fae8f4aab077
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 19:24:05 2022 -0600
+
+    [glyf/SimpleGlyph] Minor use constructor for contour_point_t
+
+ src/OT/glyf/SimpleGlyph.hh  | 1 -
+ src/hb-ot-var-gvar-table.hh | 7 ++++---
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit f897978f21c8bf3f6a8f10004e1c1e5dc8619c6d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 19:17:56 2022 -0600
+
+    [glyf] Adjust a check-range
+
+ src/OT/glyf/SimpleGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit db039d97ff991deecbdffb034b23f4ce086fa562
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 19:06:27 2022 -0600
+
+    [glyf/Composite] Make glyphIndex public
+
+ src/OT/glyf/CompositeGlyph.hh | 5 +----
+ src/OT/glyf/Glyph.hh          | 2 +-
+ src/OT/glyf/SubsetGlyph.hh    | 4 ++--
+ src/hb-subset-plan.cc         | 2 +-
+ 4 files changed, 5 insertions(+), 8 deletions(-)
+
+commit 1b14bf8aa842d1e13728a2b5675458adcd9b9de1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 19:03:30 2022 -0600
+
+    [glyf] Rename CompositeGlyphChain to CompositeGlyphRecord
+
+ src/OT/glyf/CompositeGlyph.hh | 22 +++++++++++-----------
+ src/OT/glyf/SubsetGlyph.hh    |  2 +-
+ 2 files changed, 12 insertions(+), 12 deletions(-)
+
+commit a5ac7f2ea65849b3926cb27a49bc6e5112510ae8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 19:01:43 2022 -0600
+
+    [glyf/composite_iter_t] Renames
+
+ src/OT/glyf/CompositeGlyph.hh | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+commit d15260ca9580d04d04829eefbcb239112afef2ed
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 19:53:11 2022 -0600
+
+    [gpos] Limit recursion depth in propagate_attachment_offsets()
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/2927
+
+ src/hb-ot-layout-gpos-table.hh | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+commit 449bdeed5f2272ebe1176fa371833941a98b1e8f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 18:31:31 2022 -0600
+
+    [glyf] Rename get_iterator() to iter()
+    
+    That's the standard name.
+
+ src/OT/glyf/CompositeGlyph.hh | 8 ++++----
+ src/OT/glyf/Glyph.hh          | 4 ++--
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+commit 11d267067601ac185858075d01fa68c26c0224b9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 18:19:09 2022 -0600
+
+    [glyf] Split off glyf-helpers.hh
+
+ src/Makefile.sources        |  1 +
+ src/OT/glyf/glyf-helpers.hh | 90 +++++++++++++++++++++++++++++++++++++++++++++
+ src/OT/glyf/glyf.hh         | 77 ++------------------------------------
+ src/meson.build             |  1 +
+ 4 files changed, 96 insertions(+), 73 deletions(-)
+
+commit 7c4b8c9bf413389f536ad32a53b44144b26329c4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 18:14:42 2022 -0600
+
+    [glyf] path-builder minor header guards fix test
+
+ src/OT/glyf/path-builder.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 499c6379225e39b5e96752246b97e6b4e0ddd489
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 18:07:49 2022 -0600
+
+    [glyf] Split off path-builder.hh
+
+ src/Makefile.sources        |   1 +
+ src/OT/glyf/glyf.hh         | 120 +--------------------------------------
+ src/OT/glyf/path-builder.hh | 134 ++++++++++++++++++++++++++++++++++++++++++++
+ src/meson.build             |   1 +
+ 4 files changed, 138 insertions(+), 118 deletions(-)
+
+commit 13aadc89617f1695bfcf152c96307ec97969c21e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 18:03:15 2022 -0600
+
+    [glyf] Split off CompositeGlyph.hh
+
+ src/Makefile.sources          |   1 +
+ src/OT/glyf/CompositeGlyph.hh | 261 ++++++++++++++++++++++++++++++++++++++++++
+ src/OT/glyf/Glyph.hh          | 246 +--------------------------------------
+ src/meson.build               |   1 +
+ 4 files changed, 264 insertions(+), 245 deletions(-)
+
+commit f0ec2b728e0576611b77ecbd7527044ee194191d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 17:55:16 2022 -0600
+
+    [glyf] Split off SimpleGlyph.hh
+
+ src/Makefile.sources       |   1 +
+ src/OT/glyf/Glyph.hh       | 184 +----------------------------------------
+ src/OT/glyf/SimpleGlyph.hh | 200 +++++++++++++++++++++++++++++++++++++++++++++
+ src/meson.build            |   1 +
+ 4 files changed, 203 insertions(+), 183 deletions(-)
+
+commit 8ed78627f0fd1f6957eadffdfab4c8c61d0bfcbb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 17:53:13 2022 -0600
+
+    [glyf] Split off GlyphHeader.hh
+
+ src/Makefile.sources       |  1 +
+ src/OT/glyf/Glyph.hh       | 33 ++-----------------------------
+ src/OT/glyf/GlyphHeader.hh | 48 ++++++++++++++++++++++++++++++++++++++++++++++
+ src/meson.build            |  1 +
+ 4 files changed, 52 insertions(+), 31 deletions(-)
+
+commit 81315a3016803d17d95a72c9fcfc6ab2a841e14d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 17:50:44 2022 -0600
+
+    [glyf] Namespace implementation in glyf_impl
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/3677
+
+ src/OT/glyf/Glyph.hh       |  4 ++++
+ src/OT/glyf/SubsetGlyph.hh |  2 ++
+ src/OT/glyf/glyf.hh        | 42 +++++++++++++++++++++---------------------
+ 3 files changed, 27 insertions(+), 21 deletions(-)
+
+commit be1d4bcf29ba87747252eff087a89eda5b4fa007
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 17:45:21 2022 -0600
+
+    [glyf] Add fast __end__ to composite iterator
+
+ src/OT/glyf/Glyph.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit ef250eea7e1b08bdf1d324bda8abaeb7b31dc8e4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 17:37:59 2022 -0600
+
+    [glyf] Move a few structs out of Glyph{}
+
+ src/OT/glyf/Glyph.hh | 415 ++++++++++++++++++++++++++-------------------------
+ src/OT/glyf/glyf.hh  |   4 +-
+ 2 files changed, 210 insertions(+), 209 deletions(-)
+
+commit ae75f066b573e9d29407c45af144ef69570e356b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 17:11:04 2022 -0600
+
+    [glyf] Split SubsetGlyph
+
+ src/Makefile.sources       |  1 +
+ src/OT/glyf/SubsetGlyph.hh | 70 ++++++++++++++++++++++++++++++++++++++++++++++
+ src/OT/glyf/glyf.hh        | 56 +------------------------------------
+ src/meson.build            |  1 +
+ 4 files changed, 73 insertions(+), 55 deletions(-)
+
+commit 0031069f47d0fd51c42b92f0d929196c17787c4d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 17:05:18 2022 -0600
+
+    [glyf] Fix includes
+
+ src/OT/glyf/Glyph.hh |  2 +-
+ src/OT/glyf/glyf.hh  | 16 ++++++++--------
+ src/OT/glyf/loca.hh  |  2 +-
+ 3 files changed, 10 insertions(+), 10 deletions(-)
+
+commit b4a0c30d98ff3bece104edf4a19a9ba65fa78b1b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 17:01:11 2022 -0600
+
+    [glyf] Remove hardcoded HB_MAX_COMPOSITE_OPERATIONS
+
+ src/hb-subset-plan.cc | 17 +++++++++--------
+ 1 file changed, 9 insertions(+), 8 deletions(-)
+
+commit 36373ee15c209ba6d49f4a36aaece91a3cff2f55
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 16:54:46 2022 -0600
+
+    [glyf] Move add_gid_and_children to subset-plan where it belongs
+
+ src/OT/glyf/glyf.hh   | 25 -------------------------
+ src/hb-subset-plan.cc | 31 ++++++++++++++++++++++++++++++-
+ 2 files changed, 30 insertions(+), 26 deletions(-)
+
+commit ba1c9eda3887d360b1585ae0dcf9bfc526ce8f7e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 16:51:33 2022 -0600
+
+    [glyf] Use a range for loop
+
+ src/OT/glyf/glyf.hh | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+commit e4f2bc93425f756ca5740a5d050a7521ee72465c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 16:38:50 2022 -0600
+
+    [glyf] Split Glyph.hh
+
+ src/Makefile.sources |    1 +
+ src/OT/glyf/Glyph.hh |  680 +++++++++++++++++++++++++
+ src/OT/glyf/glyf.hh  | 1368 +++++++++++++-------------------------------------
+ src/OT/glyf/loca.hh  |    1 +
+ src/meson.build      |    1 +
+ 5 files changed, 1037 insertions(+), 1014 deletions(-)
+
+commit 3f9c6bf3fcef9c2b0bc1e1d001440dcf76158b05
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 14:46:26 2022 -0600
+
+    [glyf] Minor in _write_loca()
+
+ src/OT/glyf/glyf.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 852985da0fb4686a2eb81b33f79f305fe4104425
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 14:41:51 2022 -0600
+
+    [glyf] Split loca.hh
+
+ src/Makefile.sources |  1 +
+ src/OT/glyf/glyf.hh  | 30 ++----------------------------
+ src/OT/glyf/loca.hh  | 42 ++++++++++++++++++++++++++++++++++++++++++
+ src/meson.build      |  1 +
+ 4 files changed, 46 insertions(+), 28 deletions(-)
+
+commit 100576b7b740cb65e808beba66d88f1c720715e5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 14:38:43 2022 -0600
+
+    [glyf] Start splitting file
+
+ src/Makefile.sources    |    1 +
+ src/OT/glyf/glyf.hh     | 1338 +++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-ot-glyf-table.hh | 1333 +---------------------------------------------
+ src/hb-subset-plan.cc   |    2 +-
+ src/meson.build         |    1 +
+ 5 files changed, 1342 insertions(+), 1333 deletions(-)
+
+commit e867ac3aefbd89a5f5da7f1740d0fb0ef532c8b5
+Merge: b1629b0ce 78c5ae397
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 12:43:04 2022 -0600
+
+    Merge pull request #3674 from harfbuzz/use-sinhala-no-hacks
+    
+    [use] Switch Sinhala to USE
+
+commit b1629b0ce000b561b2d643339747ae29e956b9d8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 25 11:51:31 2022 -0600
+
+    [gdef] Minor harmless use of HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED
+
+ src/hb-ot-layout-gdef-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 78c5ae3979d7915a32ffd355670b41db7d5fa91a
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Jun 25 13:32:04 2022 -0400
+
+    [indic] Remove remnants of Sinhala
+
+ docs/features.dot                    |   4 +-
+ docs/usermanual-shaping-concepts.xml |   2 +-
+ docs/usermanual-what-is-harfbuzz.xml |   3 +-
+ src/gen-indic-table.py               |   5 -
+ src/hb-ot-shaper-indic-machine.hh    | 579 +++++++++++++++++------------------
+ src/hb-ot-shaper-indic-machine.rl    |   3 +-
+ src/hb-ot-shaper-indic-table.cc      |  68 ++--
+ src/hb-ot-shaper-indic.cc            | 206 ++++---------
+ src/hb-ot-shaper-indic.hh            |   5 +-
+ 9 files changed, 366 insertions(+), 509 deletions(-)
+
+commit 0cc948b96cfca4d1e1b02fe16f8e6d525a88e53a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Oct 1 12:23:39 2018 +0200
+
+    [use] Switch Sinhala to USE
+    
+    https://github.com/harfbuzz/harfbuzz/issues/1044
+
+ src/hb-ot-shaper.hh | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+commit 605982876918b16e20dab7d440a2b1c002fa8520
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Jun 25 11:33:44 2022 -0400
+
+    [use] Reintroduce the HVM class for U+0DCA
+
+ src/gen-use-table.py            |   7 +-
+ src/hb-ot-shaper-use-machine.hh | 968 ++++++++++++++++++++++------------------
+ src/hb-ot-shaper-use-machine.rl |   5 +-
+ src/hb-ot-shaper-use-table.hh   |   4 +-
+ src/hb-ot-shaper-use.cc         |   2 +-
+ 5 files changed, 538 insertions(+), 448 deletions(-)
+
+commit 1555b3008197b77d142587322c0aec3fa83bc99f
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Fri Jun 24 21:02:26 2022 -0400
+
+    Add U+25CC to lone Robatic but not after U+17D9
+
+ src/gen-indic-table.py                             |   2 +
+ src/hb-ot-shaper-indic-table.cc                    |   6 +-
+ src/hb-ot-shaper-khmer-machine.hh                  | 266 +++++++++++----------
+ src/hb-ot-shaper-khmer-machine.rl                  |   2 +-
+ .../086d83239e8f958391ff6cdd8fda9376a4bd3673.ttf   | Bin 0 -> 1076 bytes
+ test/shape/data/in-house/tests/khmer-misc.tests    |   2 +
+ 6 files changed, 149 insertions(+), 129 deletions(-)
+
+commit 0f15cb12de7a3d5b1c8ae0820a33d7b60132c3f7
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Fri Jun 24 20:37:01 2022 -0400
+
+    [indic-table] Fix block headers
+
+ src/gen-indic-table.py          | 47 +++++++++++++++++++----------------------
+ src/hb-ot-shaper-indic-table.cc | 18 ++++++----------
+ 2 files changed, 28 insertions(+), 37 deletions(-)
+
+commit e35cfb4bdeed7eefc5d7e36ba2adfba52577ba20
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Fri Jun 24 20:18:10 2022 -0400
+
+    Document the subsetter argument of record-test.sh
+
+ test/shape/README.md | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 2674962cf5bdeea949fac5636c83acf63cbecac4
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jun 24 21:00:54 2022 +0000
+
+    [repacker] Add comment to graph class.
+
+ src/graph/graph.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 81a2dd0e80710b08054234a89463efd5814d998a
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jun 24 20:59:20 2022 +0000
+
+    [repacker] Update Makefile for repacker re-org.
+
+ src/Makefile.sources | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 7078560e330bad2aa4a027b1abc2f4186330b51e
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jun 24 19:20:20 2022 +0000
+
+    [repacker] extract graph serialization code into a seperate file.
+
+ src/graph/graph.hh     | 113 +---------------------------------------------
+ src/graph/serialize.hh | 119 +++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-repacker.hh     |  21 ++++-----
+ src/test-repacker.cc   |   6 +--
+ 4 files changed, 135 insertions(+), 124 deletions(-)
+
+commit 20b02a672d9f4c96f2db1b625f079cda5196450e
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Jun 24 18:58:17 2022 +0000
+
+    [repacker] Begin splitting up the repacker implementation into several files.
+
+ src/graph/graph.hh     |  965 ++++++++++++++++++++++++++++++++++++++++++++
+ src/graph/serialize.hh |  130 ++++++
+ src/hb-repacker.hh     | 1031 +-----------------------------------------------
+ src/test-repacker.cc   |    3 +-
+ 4 files changed, 1103 insertions(+), 1026 deletions(-)
+
+commit ad2ab1ddb42a16e02c6b16bb499bb8702d3d1654
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 24 11:08:35 2022 -0600
+
+    [indic] Clear syllables at the end of GSUB
+
+ src/hb-ot-shaper-indic.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 1f462804d1024b448df9281ab5648fb0027fe801
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 23 15:35:38 2022 -0600
+
+    [README.mingw.md] Add link to issue with further instructions
+
+ README.mingw.md | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit 8bfb3e9df2ed9832c970c14ebc1f69a812059616
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 23 13:28:07 2022 -0600
+
+    [indic] Disable vowel-constraints under uniscribe-bug-compatible
+
+ src/hb-ot-shaper-indic.cc | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit f8d052df6d97fcfec9d3cb317f1c16b7ba2a57fa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 22 18:35:48 2022 -0600
+
+    [ansi-print] Remove impossible condition
+
+ util/ansi-print.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 251320ea222dbd9a6184f477d35829a4da1c0cf5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 22 16:44:07 2022 -0600
+
+    [ansi-print] Whitespace
+
+ util/ansi-print.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 0d59d7952c334f6a3760a5b63456ede74dbf2351
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 22 16:39:36 2022 -0600
+
+    [ansi-print] Precision
+
+ util/ansi-print.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit c695a0915499061090a2c40360fbedb962a19eef
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 22 16:33:37 2022 -0600
+
+    [ansi-print] Reorder cases; harmless
+
+ util/ansi-print.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit ae0fce31cd6e92418e80dd197d989e3cb5b5eb71
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 22 16:31:21 2022 -0600
+
+    [ansi-print] Fix quadrants
+
+ util/ansi-print.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 2ebaf0c5bac475f1e0f2d645ab44081c0e0663f6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 22 16:17:49 2022 -0600
+
+    [ansi-print] Fix unicolor detection
+
+ util/ansi-print.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit a4db80ca0a96a76dcba5b85b799c1858fafe7222
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 22 16:13:53 2022 -0600
+
+    [ansi-print] Fix color calculation
+    
+    Still something's wrong.
+
+ util/ansi-print.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 1abec5cd0da2a169d3bd6a512b2483f64b5b1be8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 21 13:39:16 2022 -0600
+
+    [CONFIG.md] Grammar
+
+ CONFIG.md | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+commit 0ab08a8bbb7ce288bd06a0718ba00e0cf58e8264
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 21 13:19:08 2022 -0600
+
+    [doap] Update
+
+ harfbuzz.doap | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit a5cf1a873845d39111e5eb14d084ca2112d03902
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 20 18:01:25 2022 -0600
+
+    Another null adjustment
+
+ src/hb-shape.cc  | 4 ++--
+ src/hb-shaper.cc | 4 ++--
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit a7960bdfb00f055b821a1da96c6aad6563789646
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 17 15:10:20 2022 -0600
+
+    [config] Add HB_NO_LANGUAGE_LONG and enable in TINY profile
+    
+    Disables 3letter language tags and more complex ones.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3664
+
+ src/gen-tag-table.py   |  8 ++++++--
+ src/hb-config.hh       |  1 +
+ src/hb-ot-tag-table.hh |  6 ++++--
+ src/hb-ot-tag.cc       | 19 +++++++++++++++++--
+ 4 files changed, 28 insertions(+), 6 deletions(-)
+
+commit 0d03123350404b5cf0b4865c4b0c7d740269cc13
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 20 16:51:35 2022 -0600
+
+    Mark a null variable as const
+
+ src/hb-shape.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 91d00ab722c1a07a0f5d880bcefd12307778fe74
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jun 20 13:36:01 2022 -0600
+
+    [ucd] Update
+
+ src/hb-ucd-table.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit a15ad778fede9e94428f6811293c71a63216234a
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sun Jun 19 19:55:09 2022 +0200
+
+    [arabic-fallback] Generate PUA table from data
+    
+    Uses packtab for more compact arrays.
+
+ src/{ArabicPUA1.txt => ArabicPUASimplified.txt}  |   0
+ src/{ArabicPUA2.txt => ArabicPUATraditional.txt} |   0
+ src/gen-arabic-pua.py                            |  35 +++
+ src/hb-ot-cmap-table.hh                          |   6 +-
+ src/hb-ot-shaper-arabic-pua.hh                   | 383 +++++++----------------
+ 5 files changed, 144 insertions(+), 280 deletions(-)
+
+commit abc0685749e9e2dfc710773cc2a7a46c37b918bf
+Merge: 7ec4a556d 8c27c51c2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 19 11:05:17 2022 -0600
+
+    Merge pull request #3063 from harfbuzz/arabic-pua
+    
+    Arabic PUA shaping
+
+commit 7ec4a556d9addb1ad072ac4326659ec1a2900739
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 19 11:01:45 2022 -0600
+
+    [normalize] Cosmetic
+    
+    I didn't know this syntax is allowed in old C++.
+
+ src/hb-ot-shape-normalize.cc | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 8c27c51c27c760a54350bf18ddfae34aaa19d89e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 19 10:47:38 2022 -0600
+
+    [arabic-pua] Rename symbols
+
+ src/hb-ft.cc                   |  4 ++--
+ src/hb-ot-cmap-table.hh        |  8 ++++----
+ src/hb-ot-shaper-arabic-pua.hh | 36 ++++++++++++++++++------------------
+ 3 files changed, 24 insertions(+), 24 deletions(-)
+
+commit 769896291176936d01c79a56bce3b33eb64e2776
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 19 10:41:45 2022 -0600
+
+    [arabic-fallback] Disable PUA shaping under HB_NO_OT_SHAPER_ARABIC_FALLBACK
+
+ src/hb-ft.cc            | 2 ++
+ src/hb-ot-cmap-table.hh | 2 ++
+ 2 files changed, 4 insertions(+)
+
+commit 4520911429dae90dc1342fadf1112967839e5899
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 19 10:36:24 2022 -0600
+
+    [arabic-fallback] Fix warning
+
+ src/hb-ot-shaper-arabic-fallback.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 55350377b0d26c06f152f0cd30c3911fd6060b85
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 19 10:13:31 2022 -0600
+
+    [cmap/ft] Only map 0xF000 range if font_page is NONE
+
+ src/hb-ft.cc            | 4 +++-
+ src/hb-ot-cmap-table.hh | 5 ++++-
+ 2 files changed, 7 insertions(+), 2 deletions(-)
+
+commit 41a079bdec091e40e8afe36db4ef647cc3bde195
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 18 14:47:10 2022 -0600
+
+    [arabic-fallback] Make win1256 code build again
+    
+    Humm. Untested.
+
+ src/hb-ot-shaper-arabic-fallback.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 1db6fddb24f6bb27d5d13890ea233859db7960a7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 18 14:34:46 2022 -0600
+
+    [arabic-fallback.hh] Hook up 3-letter ligatures
+
+ src/hb-null.hh                                               |  2 +-
+ src/hb-ot-shaper-arabic-fallback.hh                          | 10 ++++++----
+ test/shape/data/in-house/tests/arabic-fallback-shaping.tests |  2 +-
+ 3 files changed, 8 insertions(+), 6 deletions(-)
+
+commit 20e9f0b1d2efe86b632dcfda067244c578c0e20f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 18 14:12:30 2022 -0600
+
+    [arabic-fallback] Add the component loop
+    
+    Should be able to support 3-letter ligatures now.  Hooking up next.
+
+ src/hb-ot-shaper-arabic-fallback.hh | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+commit 9684d2d8aa86b5dade7a87f1cbea245904e20872
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 18 14:07:48 2022 -0600
+
+    [arabic-fallback] More baby steps
+
+ src/hb-ot-shaper-arabic-fallback.hh | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+commit 08715d75e07a3672e1e0e1159e58ec6a1c55d68e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 18 14:04:56 2022 -0600
+
+    [arabic-fallback] Another baby-step
+
+ src/hb-ot-shaper-arabic-fallback.hh | 19 ++++++++++++-------
+ 1 file changed, 12 insertions(+), 7 deletions(-)
+
+commit 15dd34b51587a8c00b449960e76d18d1add89ff6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 18 13:47:00 2022 -0600
+
+    [arabic-fallback] Another minor rename towards supporting 3-letter ligatures
+
+ src/hb-ot-shaper-arabic-fallback.hh | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+commit d86effa4a68138bb813fae056aebbb90d1af6b23
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 18 13:41:30 2022 -0600
+
+    [arabic-fallback] Rename; towards supporting 3-letter ligatures
+
+ src/gen-arabic-table.py             |  13 ++--
+ src/hb-ot-shaper-arabic-fallback.hh |   2 +-
+ src/hb-ot-shaper-arabic-table.hh    | 137 ++++++++++++++++++------------------
+ 3 files changed, 75 insertions(+), 77 deletions(-)
+
+commit 8978a18f31ca297e342cbac9caab486bbe2597d3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 18 13:25:46 2022 -0600
+
+    [arabick-fallback] Apply mark ligatures
+
+ test/shape/data/in-house/tests/arabic-fallback-shaping.tests | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 16c23713523f3c55bf24caabccb816becc8cc5af
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 18 13:25:46 2022 -0600
+
+    [arabick-fallback] Apply mark ligatures
+
+ src/hb-ot-shaper-arabic-fallback.hh | 28 +++++++++++++++++++++-------
+ 1 file changed, 21 insertions(+), 7 deletions(-)
+
+commit 7f362196c5b7ed2856e310f41999092e07d82281
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Jun 18 20:28:43 2022 +0200
+
+    [arabic] Split ligature array
+    
+    Generate marks and 3-component ligatures in separate arrays. The new
+    arrays are unused currently.
+
+ src/gen-arabic-table.py          | 102 +++++++++++++++++++++++++++++++--------
+ src/hb-ot-shaper-arabic-table.hh |  42 +++++++++++++---
+ 2 files changed, 117 insertions(+), 27 deletions(-)
+
+commit 6e29060af2e4490e67e24ec2ef5172541275a855
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Jun 18 15:34:40 2022 +0200
+
+    [arabic] Add mapping files for the PUA encoding
+    
+    Unused right now.
+
+ src/ArabicPUA1.txt | 250 +++++++++++++++++++++++++++++++++++++++++++++
+ src/ArabicPUA2.txt | 295 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 545 insertions(+)
+
+commit dfc5e5a27dce6e95c523fcb6ad997f18e771801c
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Jun 18 14:00:30 2022 +0200
+
+    [test] Skip glyph positions for test failing on CI
+    
+    We are not interested in glyph positioning for this test, and the
+    FreeType version on some CI machines is giving some different glyph
+    advances here.
+
+ test/shape/data/in-house/tests/arabic-fallback-shaping.tests | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 189e8c326e8421f2e59f10d9ab7355d2c3114147
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Jun 18 13:28:54 2022 +0200
+
+    [ft] Remap legacy Arabic PUA codepoints
+    
+    Similar to what ot font finctions does, to support Support legacy
+    pre-OpenType Windows 3.1-era fonts.
+
+ src/hb-ft.cc                                       | 29 ++++++++++++++++------
+ .../in-house/tests/arabic-fallback-shaping.tests   | 20 +++++++--------
+ 2 files changed, 31 insertions(+), 18 deletions(-)
+
+commit 69cbd365cc0e5e5d90d510cc3407e4056d2a1734
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Aug 14 02:39:46 2021 +0200
+
+    WIP: manually add data entries for PUA ligatures
+    
+    Just a test, I’m not entirely convinced we should do this.
+
+ src/gen-arabic-table.py          | 9 ++++++++-
+ src/hb-ot-shaper-arabic-table.hh | 1 +
+ 2 files changed, 9 insertions(+), 1 deletion(-)
+
+commit c3f590bb1eb5e2451b80aa3d10a29c62b32b860d
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Jun 16 11:04:13 2022 -0600
+
+    [arabic] Support legacy PUA shaping
+    
+    Support legacy pre-OpenType Windows 3.1-era fonts, by remapping PUA code
+    points in cmap table and letting our fallback shaper build the GSUB
+    table.
+    
+    Uniscribe applies also mset-like substitution, but our fallback mark
+    positioning gives better results, so this is not implemented.
+
+ src/Makefile.sources                               |   1 +
+ src/gen-arabic-table.py                            |  27 +-
+ src/hb-ot-cmap-table.hh                            |  45 +++-
+ src/hb-ot-os2-table.hh                             |   4 +-
+ src/hb-ot-shaper-arabic-pua.hh                     | 289 +++++++++++++++++++++
+ src/hb-ot-shaper-arabic-table.hh                   |  89 ++++++-
+ src/meson.build                                    |   1 +
+ test/shape/data/in-house/fonts/SimpArabicTest.ttf  | Bin 0 -> 17168 bytes
+ test/shape/data/in-house/fonts/TradArabicTest.ttf  | Bin 0 -> 58132 bytes
+ .../in-house/tests/arabic-fallback-shaping.tests   |  10 +
+ 10 files changed, 449 insertions(+), 17 deletions(-)
+
+commit b172f88c7d33cf2c563ca995104476cf0a876e05
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 18 14:00:27 2022 -0600
+
+    Fix a warning
+    
+    D:\a\harfbuzz\harfbuzz\src\hb-bit-set-invertible.hh(83): warning C4805: '^': unsafe mix of type 'uint32_t' and type 'const bool' in operation
+    [870/1075] Compiling C++ object src/harfbuzz.dll.p/hb-face.cc.obj
+    cl : Command line warning D9025 : overriding '/EHs' with '/EHs-'
+    cl : Command line warning D9025 : overriding '/EHc' with '/EHc-'
+
+ src/hb-bit-set-invertible.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit af74ab452f5796fb02d6a406a70033803781f17d
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 16 18:12:09 2022 +0000
+
+    [repack] always run the sort in repack.
+    
+    This is needed to ensure virtual link ordering constraints are respected when repack is being called from fontTools. For subset usage, repack won't be called if the graph doesn't already overflow so this change doesn't cause any extra work.
+
+ src/hb-repacker.hh                   |   6 ++----
+ test/api/fonts/repacker_expected.otf | Bin 1400 -> 1400 bytes
+ 2 files changed, 2 insertions(+), 4 deletions(-)
+
+commit 29811a720c48d746c63c7109905b847425d29282
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 16 14:04:08 2022 -0600
+
+    Fix typo
+
+ src/check-symbols.py | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit c859cbfb88acf7e0063bbd4c2b576c153fbed17f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 16 13:55:12 2022 -0600
+
+    Mark an array as static
+    
+    Not sure how this wasn't flagged before.
+
+ src/hb-common.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 19802dfdf04da6565c869103298fc6deb6ac0ea6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 16 13:50:35 2022 -0600
+
+    Minor rename of static symbols to namespace them
+
+ src/hb-buffer-serialize.cc        |  8 ++++----
+ src/hb-ot-name-language-static.hh | 12 ++++++------
+ src/hb-shaper.cc                  | 12 ++++++------
+ 3 files changed, 16 insertions(+), 16 deletions(-)
+
+commit e0a5231657a6f09ca4afc93e1b2224eba7a0b544
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 16 13:24:02 2022 -0600
+
+    [draw] Lazy-allocate user-data/destroy callback vector
+
+ src/hb-draw.cc | 53 ++++++++++++++++++++++++++++++++++++++---------------
+ src/hb-draw.hh | 14 +++++++-------
+ 2 files changed, 45 insertions(+), 22 deletions(-)
+
+commit 823f32a0e2f242ba02fcf1db95361051ac374a49
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jun 15 18:50:45 2022 +0000
+
+    [subset] Fix potential out of bounds write setting overlap flag on composite glyphs.
+
+ src/hb-ot-glyf-table.hh | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+commit 3f9226da37e088e356fbd5bd00730062cd335ee4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 16 09:28:47 2022 -0600
+
+    [meta] Fix typo
+
+ src/hb-meta.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1c0eeb7cb32ad071d95380dc3bc79952cbabd98d
+Author: Ryan VanderMeulen <rvandermeulen@mozilla.com>
+Date:   Wed Jun 15 23:05:15 2022 -0400
+
+    Don't try to set _USE_MATH_DEFINES if already defined
+
+ src/hb.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 25917c780f27d2d068f356b7a74f5eef22a83b3f
+Author: Ryan VanderMeulen <rvandermeulen@mozilla.com>
+Date:   Wed Jun 15 23:03:22 2022 -0400
+
+    Fix build warning when __GNUG__ isn't defined
+
+ src/hb-meta.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e9c0a74063b19e2cd6b333fad0c834e4f40a241c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 15 16:57:16 2022 -0600
+
+    Fix clang -Wcomma warnings
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3656
+
+ src/hb-bit-set-invertible.hh | 2 +-
+ src/hb-coretext.cc           | 4 ++--
+ src/hb-ot-var-fvar-table.hh  | 4 ++--
+ src/hb-repacker.hh           | 2 +-
+ src/hb-subset.cc             | 4 ++--
+ src/hb.hh                    | 1 +
+ 6 files changed, 9 insertions(+), 8 deletions(-)
+
+commit d9c18cc2f0bbd1b4e5c739665e80d8b48d01d33b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 15 16:50:34 2022 -0600
+
+    [indic-table] Update
+
+ src/hb-ot-shaper-indic-table.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 99a26bc19d7818adfba64502c41491606a89bba8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 15 16:14:31 2022 -0600
+
+    [indic-generator] Fix typo
+
+ src/gen-indic-table.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 2cbb7758665f2b98f72d1193f7a3343f13d44cee
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 11 08:57:21 2022 -0600
+
+    [myanmar] Fold category P into GB
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3649
+    
+    This actually now allows Asat after the Myanmar punctuation marks;
+    something I see in Wikipedia data.
+
+ src/gen-indic-table.py              |   4 +-
+ src/hb-ot-shaper-indic-table.cc     |  13 +-
+ src/hb-ot-shaper-myanmar-machine.hh | 620 ++++++++++++++++++------------------
+ src/hb-ot-shaper-myanmar-machine.rl |   7 +-
+ src/hb-ot-shaper-myanmar.cc         |   1 -
+ 5 files changed, 312 insertions(+), 333 deletions(-)
+
+commit b350e301863db05d1e1651bccc90f3447829c50e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 11 08:52:11 2022 -0600
+
+    [myanmar] Remove category D completely
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3651
+
+ src/gen-indic-table.py              |  2 --
+ src/hb-ot-shaper-myanmar-machine.hh | 29 ++++++++++++-----------------
+ src/hb-ot-shaper-myanmar-machine.rl |  6 +++---
+ 3 files changed, 15 insertions(+), 22 deletions(-)
+
+commit 8533214ac567145cfcdc54f59ec58b8ad0b749b6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 11 08:49:36 2022 -0600
+
+    [khmer] Fold category Coeng completely into category H
+
+ src/gen-indic-table.py              |  4 +---
+ src/hb-ot-shaper-indic-machine.hh   | 36 ++++++++++++++++++------------------
+ src/hb-ot-shaper-indic-table.cc     |  9 +++------
+ src/hb-ot-shaper-khmer-machine.hh   |  2 +-
+ src/hb-ot-shaper-khmer-machine.rl   |  8 +++++---
+ src/hb-ot-shaper-khmer.cc           |  2 +-
+ src/hb-ot-shaper-myanmar-machine.hh | 22 +++++++++++-----------
+ 7 files changed, 40 insertions(+), 43 deletions(-)
+
+commit 607a9fe793aa586d73fceae90424a3d3a45ad2b8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 11 04:20:23 2022 -0600
+
+    [indic-like] Remove category duplication
+
+ src/gen-indic-table.py              | 77 ++++++++++++++++++++++++++++++++++++-
+ src/hb-ot-shaper-indic-machine.hh   | 51 ++++++++++++------------
+ src/hb-ot-shaper-indic-machine.rl   |  5 +--
+ src/hb-ot-shaper-indic-table.cc     | 54 ++++++++++++++++++++++++++
+ src/hb-ot-shaper-indic.cc           | 23 -----------
+ src/hb-ot-shaper-indic.hh           | 61 -----------------------------
+ src/hb-ot-shaper-khmer-machine.hh   |  2 +-
+ src/hb-ot-shaper-khmer-machine.rl   |  4 +-
+ src/hb-ot-shaper-khmer.cc           | 23 -----------
+ src/hb-ot-shaper-myanmar-machine.hh |  2 +-
+ src/hb-ot-shaper-myanmar-machine.rl |  5 +--
+ src/hb-ot-shaper-myanmar.cc         | 35 -----------------
+ 12 files changed, 162 insertions(+), 180 deletions(-)
+
+commit 04851921951cde16121a8c6a913306f56dab77fe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 11 03:55:23 2022 -0600
+
+    [indic-like] Remove dependence on ot_category_t
+
+ src/hb-ot-shaper-indic-machine.hh   | 2 +-
+ src/hb-ot-shaper-indic-machine.rl   | 2 +-
+ src/hb-ot-shaper-khmer-machine.hh   | 2 +-
+ src/hb-ot-shaper-khmer-machine.rl   | 2 +-
+ src/hb-ot-shaper-myanmar-machine.hh | 2 +-
+ src/hb-ot-shaper-myanmar-machine.rl | 2 +-
+ 6 files changed, 6 insertions(+), 6 deletions(-)
+
+commit 14049003ac3cf17631cc68ea78ba5989e248bd52
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 11 03:53:47 2022 -0600
+
+    [indic-like] Reduce indic-dependency of khmer/myanmar even more
+
+ src/hb-ot-shaper-indic-machine.hh   | 56 ++++++++++++++++++++-----------------
+ src/hb-ot-shaper-indic-machine.rl   |  4 +++
+ src/hb-ot-shaper-indic.hh           |  5 ----
+ src/hb-ot-shaper-khmer-machine.hh   |  2 +-
+ src/hb-ot-shaper-khmer-machine.rl   |  2 +-
+ src/hb-ot-shaper-myanmar-machine.hh |  4 +--
+ src/hb-ot-shaper-myanmar-machine.rl |  4 +--
+ src/hb-ot-shaper-myanmar.cc         |  2 +-
+ 8 files changed, 41 insertions(+), 38 deletions(-)
+
+commit a1c299da13008abcc119bdd44b6ed64a746efc54
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Mon Jun 13 10:50:59 2022 +0000
+
+    Bump actions/setup-python from 3 to 4
+    
+    Bumps [actions/setup-python](https://github.com/actions/setup-python) from 3 to 4.
+    - [Release notes](https://github.com/actions/setup-python/releases)
+    - [Commits](https://github.com/actions/setup-python/compare/v3...v4)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: actions/setup-python
+      dependency-type: direct:production
+      update-type: version-update:semver-major
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/msvc-ci.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f9f0969cb6d54f8ee43a28c6a454d8787d10a075
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Jun 13 17:55:26 2022 +0000
+
+    [subset] switch to hb_memcpy.
+
+ src/hb-ot-post-table-v2subset.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 1e34852f074e9d8afdd6b63590ef0b22bb0bf174
+Author: Garret Rieger <grieger@google.com>
+Date:   Sat Jun 11 01:27:33 2022 +0000
+
+    [subset] Fix undefined behaviour.
+    
+    Don't memcpy if there's nothing to copy.
+
+ src/hb-ot-post-table-v2subset.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 311413f16b92a8d5811897b5793ca8a9f218b779
+Author: Garret Rieger <grieger@google.com>
+Date:   Sat Jun 11 01:05:57 2022 +0000
+
+    [subset] Fix fuzzer issue.
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5693568490012672. new_index should be set from new_index2 when the entry is present in the map.
+
+ src/hb-ot-post-table-v2subset.hh                         |   7 ++++---
+ ...-testcase-minimized-hb-subset-fuzzer-5693568490012672 | Bin 0 -> 1543 bytes
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+commit 4ba7980b8eb2144f114054751c94c45fd8f61263
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Jun 11 15:50:37 2022 -0400
+
+    Fix the generated gobject headers
+    
+    These headers are not acceptable to modern compilers.
+    gcc says things like:
+    
+    /usr/include/harfbuzz/hb-gobject-enums.h:100:1: warning:
+      function declaration isn’t a prototype [-Wstrict-prototypes]
+      100 | hb_gobject_ot_metrics_tag_get_type () G_GNUC_CONST;
+
+ src/hb-gobject-enums.h.tmpl | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 79bb3b52787d8ef9b3bc1a83222068c702c01c1b
+Author: Ali Chraghi <63465728+alichraghi@users.noreply.github.com>
+Date:   Sat Jun 11 14:31:28 2022 +0430
+
+    [docs] fix typo
+
+ src/hb-buffer-serialize.cc | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit b5bdb9f955b7ccb5e212b29133e2718864bcb072
+Merge: 148283d0e 98116e5cf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 11 10:44:09 2022 +0100
+
+    Merge pull request #3648 from harfbuzz/indic-cleanup
+    
+    Indic cleanup
+
+commit 98116e5cf5f4f9b5cc2da634d3380defe9d55ab1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 11 03:42:36 2022 -0600
+
+    [myanmar] Fix comments on categories
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3648#discussion_r894955430
+
+ src/hb-ot-shaper-indic.hh           | 4 ++--
+ src/hb-ot-shaper-myanmar-machine.rl | 4 ++--
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit 02016914b300692655d9967e31020a827623280b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 17:24:19 2022 -0600
+
+    [indic-generator] Remove unnecessary Myanmar category=D overrides
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3648#discussion_r894685106
+
+ src/gen-indic-table.py          | 21 +--------------------
+ src/hb-ot-shaper-indic-table.cc | 16 +++++++---------
+ 2 files changed, 8 insertions(+), 29 deletions(-)
+
+commit 937c878078869870520702006c286099f9167624
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 17:20:15 2022 -0600
+
+    [indic-generator] Remove unnecessary override for Myanmar U+1039
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3648#discussion_r894762535
+
+ src/gen-indic-table.py          | 2 --
+ src/hb-ot-shaper-indic-table.cc | 6 +++---
+ 2 files changed, 3 insertions(+), 5 deletions(-)
+
+commit 9504037ccb2391fc7e4041f9d35eb9a620052c67
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 17:13:16 2022 -0600
+
+    [indic-generator] Remove three unneeded Myanmar overrides U+AA74-6
+    
+    These three characters have Indic_Syllabic_Category=Consonant_Placeholder. The
+    original evidence that prompted these overrides says they can take tone marks.
+    They are not subjoined: Khamti Shan apparently does not use subjoined
+    characters at all. Therefore, PLACEHOLDER is good enough and these need not be
+    overridden to C.
+    
+    https://www.unicode.org/L2/L2008/08276-khamti-proposal.pdf
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3648#discussion_r894640713
+
+ src/gen-indic-table.py          | 5 -----
+ src/hb-ot-shaper-indic-table.cc | 6 +++---
+ 2 files changed, 3 insertions(+), 8 deletions(-)
+
+commit 02eb6606d7dfb8ad1d4dbdcad3badebc37a8dc49
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 17:10:42 2022 -0600
+
+    [indic-generator] Remove redundant PLACEHODER characters overrides
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3648#discussion_r894631922
+
+ src/gen-indic-table.py | 58 ++++++++++++++++++++++++--------------------------
+ 1 file changed, 28 insertions(+), 30 deletions(-)
+
+commit e16669ceacd417eaf348bb8653e5816b1d7f947a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 17:05:35 2022 -0600
+
+    [indic-generator] Remove redundant override of U+2010 / U+2011
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3648#discussion_r894630596
+
+ src/gen-indic-table.py | 3 ---
+ 1 file changed, 3 deletions(-)
+
+commit bb255cd9a6f42a982daada48b6069d96812eb35f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 17:03:52 2022 -0600
+
+    [indic-generator] Remove redundant override of U+0980
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3648#discussion_r894627064
+
+ src/gen-indic-table.py | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 30d8c87d018c05560c21f5c4ddda4ac817983292
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 16:56:15 2022 -0600
+
+    [myanmar] Document Medials
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3648#discussion_r894532676
+
+ src/hb-ot-shaper-indic.hh           | 8 ++++----
+ src/hb-ot-shaper-myanmar-machine.rl | 8 ++++----
+ 2 files changed, 8 insertions(+), 8 deletions(-)
+
+commit e1826c371442851eb99628655a081d8bd78829ac
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 16:53:11 2022 -0600
+
+    [khmer] Reuse OT_H for OT_Coeng
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3648#discussion_r894517417
+
+ src/hb-ot-shaper-indic.hh         |   2 +-
+ src/hb-ot-shaper-khmer-machine.hh | 232 +++++++++++++++++++-------------------
+ src/hb-ot-shaper-khmer-machine.rl |   2 +-
+ 3 files changed, 119 insertions(+), 117 deletions(-)
+
+commit eb2f2e318ac2f43c0871f3b5a6101040602e0570
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 16:47:59 2022 -0600
+
+    [indic-generator] Update comment re U+104E
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3648#pullrequestreview-1002150048
+
+ src/gen-indic-table.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 0daafefdd193ed5f10454bf4eea5652a7d2eff4c
+Merge: 39c132a62 148283d0e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 10:55:49 2022 -0600
+
+    Merge branch 'main' into indic-cleanup
+
+commit 148283d0e060c00da2a661a3e7c86f824250ccec
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 07:48:39 2022 -0600
+
+    [syllabic] Use a buffer scratch-flag for has-broken-syllable
+
+ src/hb-buffer.hh                    |  1 +
+ src/hb-ot-shaper-indic-machine.hh   |  6 +++---
+ src/hb-ot-shaper-indic-machine.rl   |  2 +-
+ src/hb-ot-shaper-khmer-machine.hh   |  6 +++---
+ src/hb-ot-shaper-khmer-machine.rl   |  2 +-
+ src/hb-ot-shaper-myanmar-machine.hh |  4 ++--
+ src/hb-ot-shaper-myanmar-machine.rl |  2 +-
+ src/hb-ot-shaper-syllabic.cc        | 15 +--------------
+ src/hb-ot-shaper-use-machine.hh     |  4 ++--
+ src/hb-ot-shaper-use-machine.rl     |  2 +-
+ 10 files changed, 16 insertions(+), 28 deletions(-)
+
+commit 6997d10bc0cab13103b660eb968bc49e2a0fb0f7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 07:43:33 2022 -0600
+
+    [arabic] Remove a couple TODO items
+
+ src/hb-ot-shaper-arabic-fallback.hh | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit e1575f23473af32816e583f4f10e6ef8899dff90
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 07:41:39 2022 -0600
+
+    [iter] Remove a few TODO items
+
+ src/hb-iter.hh | 16 +++-------------
+ 1 file changed, 3 insertions(+), 13 deletions(-)
+
+commit 689c77530a69cefbe6f142842a135988a1454315
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 07:37:45 2022 -0600
+
+    [buffer] Actually remove TODO item
+    
+    In reality, one side is smaller and one side is larger. The existing code
+    handles that just fine.
+
+ src/hb-buffer.cc | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit d09e962b9f5cbb4866e1c51b2fc967b83e323b69
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 07:35:16 2022 -0600
+
+    [buffer] Update a TODO item
+
+ src/hb-buffer.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b3f689e7e5a4272b52e4ee34fbac04e2723b2439
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 07:31:47 2022 -0600
+
+    [serializer] Remove TODO that's not gonna happen
+
+ src/hb-serialize.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 10a8cc28fc6455482b67cf1781fe72765826c4a5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 07:31:06 2022 -0600
+
+    [normalizer] Remove a TODO that's not going to happen
+
+ src/hb-ot-shape-normalize.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 7635568f29e8e9e32bc30f6a6c2651500991dde8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 07:29:15 2022 -0600
+
+    [font] Remove a TODO item that's not gonna happen
+
+ src/hb-font.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit bd453de7575ac808780e706734ca6dd4baa43660
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 07:25:48 2022 -0600
+
+    [unicode] Accept a couple hacks as permanent
+
+ src/hb-unicode.hh | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+commit 39c132a62d57d736971fe16e1e47817e443df4f0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 07:12:39 2022 -0600
+
+    [indic/myanmar] Simplify compare functions
+
+ src/hb-ot-shaper-indic.cc   | 2 +-
+ src/hb-ot-shaper-myanmar.cc | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit a5bcd8567fc42442510b3838b4be925fa1a45288
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 07:03:02 2022 -0600
+
+    [indic] Update comment re category listing
+
+ src/hb-ot-shaper-indic.hh | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+commit 10a5485136563e8bb2c7ca78b9d230483c36c682
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 06:34:56 2022 -0600
+
+    [indic/myanmar] Move is_consonant to .cc files
+
+ src/hb-ot-shaper-indic.cc   | 24 ++++++++++++++++++++++++
+ src/hb-ot-shaper-indic.hh   | 24 ------------------------
+ src/hb-ot-shaper-myanmar.cc | 27 ++++++++++++++++++++++++++-
+ 3 files changed, 50 insertions(+), 25 deletions(-)
+
+commit 1c657460efacb3848a4a719a1c97b40fb88b49fd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 06:29:45 2022 -0600
+
+    [indic] Expand MEDIAL_FLAGS
+
+ src/hb-ot-shaper-indic.cc | 2 +-
+ src/hb-ot-shaper-indic.hh | 4 +---
+ 2 files changed, 2 insertions(+), 4 deletions(-)
+
+commit 9e3917f6d61ced3771d6b4b9e74c20f5c40012b2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 06:20:56 2022 -0600
+
+    [indic] Move a couple of functions to .cc file
+
+ src/hb-ot-shaper-indic.cc | 14 ++++++++++++++
+ src/hb-ot-shaper-indic.hh | 14 --------------
+ 2 files changed, 14 insertions(+), 14 deletions(-)
+
+commit 165ef55e57194bb443b69830d3ddcbefa5d04e95
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 06:20:10 2022 -0600
+
+    [indic-generator] Move INDIC_COMBINE_CATEGORIES here
+
+ src/gen-indic-table.py          | 3 +++
+ src/hb-ot-shaper-indic-table.cc | 3 +++
+ src/hb-ot-shaper-indic.hh       | 2 --
+ 3 files changed, 6 insertions(+), 2 deletions(-)
+
+commit b030dd9e8806cc35d01136d2cf371109e174b663
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 06:12:13 2022 -0600
+
+    [indic-table] Minor rename
+
+ src/gen-indic-table.py          |   4 +-
+ src/hb-ot-shaper-indic-table.cc | 194 ++++++++++++++++++++--------------------
+ 2 files changed, 99 insertions(+), 99 deletions(-)
+
+commit d414fb332811851c382d5120ae3055b468b33ede
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 10 00:50:47 2022 -0600
+
+    [indic/khmer/myanmar] Add static_assert that categories match OT_*
+
+ src/hb-ot-shaper-indic-machine.hh   | 36 ++++++++++++++++++------------------
+ src/hb-ot-shaper-indic-machine.rl   |  5 ++++-
+ src/hb-ot-shaper-indic.cc           | 28 +++++++++++++++++++++++-----
+ src/hb-ot-shaper-indic.hh           |  3 +++
+ src/hb-ot-shaper-khmer-machine.hh   | 22 +++++++++++-----------
+ src/hb-ot-shaper-khmer-machine.rl   |  5 ++++-
+ src/hb-ot-shaper-khmer.cc           | 24 ++++++++++++++++++++++++
+ src/hb-ot-shaper-myanmar-machine.hh | 22 +++++++++++-----------
+ src/hb-ot-shaper-myanmar-machine.rl |  4 +++-
+ src/hb-ot-shaper-myanmar.cc         | 36 ++++++++++++++++++++++++++++++++++++
+ 10 files changed, 137 insertions(+), 48 deletions(-)
+
+commit 15ea4ccb045838ff2fe880dbc01215c361ed9363
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 9 17:47:46 2022 -0600
+
+    [indic-like] Add note about replicated values
+
+ src/hb-ot-shaper-indic-machine.rl   | 1 +
+ src/hb-ot-shaper-khmer-machine.rl   | 1 +
+ src/hb-ot-shaper-myanmar-machine.rl | 1 +
+ 3 files changed, 3 insertions(+)
+
+commit 3289e815328114a39e19179ddbdf4a2ec2458fe5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 9 17:46:15 2022 -0600
+
+    [indic] Use categories from the machine
+
+ src/hb-ot-shaper-indic-machine.hh   | 60 ++++++++++++----------
+ src/hb-ot-shaper-indic-machine.rl   |  8 +++
+ src/hb-ot-shaper-indic.cc           | 99 +++++++++++++++++++++++++------------
+ src/hb-ot-shaper-indic.hh           | 54 +-------------------
+ src/hb-ot-shaper-khmer-machine.hh   |  2 +-
+ src/hb-ot-shaper-khmer-machine.rl   |  2 +-
+ src/hb-ot-shaper-myanmar-machine.hh |  4 +-
+ src/hb-ot-shaper-myanmar-machine.rl |  4 +-
+ 8 files changed, 118 insertions(+), 115 deletions(-)
+
+commit 37217fc9be1a60622ad16f0204b172a44d82e947
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 9 16:43:50 2022 -0600
+
+    [indic-generator/myanmar] Move most Myanmar category overrides to generator
+
+ src/gen-indic-table.py              | 110 +++++++++
+ src/hb-ot-shaper-indic-table.cc     | 120 ++++++----
+ src/hb-ot-shaper-indic.hh           |  19 +-
+ src/hb-ot-shaper-myanmar-machine.hh | 440 ++++++++++++++++++------------------
+ src/hb-ot-shaper-myanmar-machine.rl |  29 +--
+ src/hb-ot-shaper-myanmar.cc         |  94 +-------
+ 6 files changed, 443 insertions(+), 369 deletions(-)
+
+commit c136227f57b0ad42a2dcf8303e3d6df4c9c6280f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 9 13:36:19 2022 -0600
+
+    [indic-generator/khmer] Move Khmer overrides to generator
+
+ src/gen-indic-table.py          | 27 +++++++++++++++++++++++++++
+ src/hb-ot-shaper-indic-table.cc | 40 ++++++++++++++++++++++------------------
+ src/hb-ot-shaper-indic.hh       |  6 ++----
+ src/hb-ot-shaper-khmer.cc       | 38 +-------------------------------------
+ 4 files changed, 52 insertions(+), 59 deletions(-)
+
+commit 40aa4e8320204ec376e9b16f91da9c95ae82e6d9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 9 13:30:00 2022 -0600
+
+    [indic/khmer/myanmar] Add Khmer/Myanmar categories to indic_category_t
+
+ src/hb-ot-shaper-indic.hh           |  30 ++-
+ src/hb-ot-shaper-khmer-machine.hh   | 262 ++++++++++----------
+ src/hb-ot-shaper-khmer-machine.rl   |  18 +-
+ src/hb-ot-shaper-myanmar-machine.hh | 467 ++++++++++++++++++++----------------
+ src/hb-ot-shaper-myanmar-machine.rl |  47 ++--
+ 5 files changed, 454 insertions(+), 370 deletions(-)
+
+commit 25793075e2884a4462063e904b13d70edb449ff2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 9 13:11:46 2022 -0600
+
+    [indic-generator] Move Khmer/Myanmar vowel categories to the generator
+
+ src/gen-indic-table.py          | 16 +++++++++++++---
+ src/hb-ot-shaper-indic-table.cc | 42 ++++++++++++++++++++++++-----------------
+ src/hb-ot-shaper-khmer.cc       | 14 --------------
+ src/hb-ot-shaper-myanmar.cc     | 12 ------------
+ 4 files changed, 38 insertions(+), 46 deletions(-)
+
+commit a6c82d4b8c6bc130889b67bd53971be7ee513e4a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 9 13:04:28 2022 -0600
+
+    [myanmar] Simplify to not use position info from the indic table for shaping
+
+ src/hb-ot-shaper-myanmar.cc | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+commit 10cd8ac0e50b319c3838d05bd8e9c38ddf79beba
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 9 12:27:31 2022 -0600
+
+    [indic-generator] Move matra category overrides to generator
+
+ src/gen-indic-table.py          |  52 ++++++++++++
+ src/hb-ot-shaper-indic-table.cc | 178 +++++++++++++++++++++-------------------
+ src/hb-ot-shaper-indic.hh       |  61 --------------
+ src/hb-ot-shaper-khmer.cc       |   1 -
+ 4 files changed, 145 insertions(+), 147 deletions(-)
+
+commit c4e4f1d3874058439373f82d560855f967fb843d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 9 11:56:57 2022 -0600
+
+    [indic-generator] Move SMVD position overrides to generator
+
+ src/gen-indic-table.py          |  6 ++-
+ src/hb-ot-shaper-indic-table.cc | 88 +++++++++++++++++++++--------------------
+ src/hb-ot-shaper-indic.hh       |  4 --
+ 3 files changed, 50 insertions(+), 48 deletions(-)
+
+commit 2963154c155888072e441b0f9b5ecfe61593871e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 9 11:49:02 2022 -0600
+
+    [indic-generator] Add a couple comments
+
+ src/gen-indic-table.py    | 7 +++++--
+ src/hb-ot-shaper-indic.hh | 4 +++-
+ 2 files changed, 8 insertions(+), 3 deletions(-)
+
+commit 91d6f45bc97b3920c0b780d2d5b056486e0e1b3f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 9 07:34:44 2022 -0600
+
+    [indic-generator] Move some position overrides to the generator
+
+ src/gen-indic-table.py          |  35 +++-
+ src/hb-ot-shaper-indic-table.cc | 438 +++++++++++++++++-----------------------
+ src/hb-ot-shaper-indic.hh       |  14 +-
+ 3 files changed, 212 insertions(+), 275 deletions(-)
+
+commit 0ec4dcb93d56c72624a0030e274e8171b117bc8e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 9 07:33:43 2022 -0600
+
+    [indic-generator] Ouch
+    
+    Not sure how this was passing tests still.
+
+ src/gen-indic-table.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f0269e0f1b58e481b65f23621065626f0c83eb97
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 9 07:10:47 2022 -0600
+
+    [indic-generator] Move Ra handling to the generator
+
+ src/gen-indic-table.py          | 14 +++++++
+ src/hb-ot-shaper-indic-table.cc | 88 +++++++++++++++++++++++++++++++++--------
+ src/hb-ot-shaper-indic.hh       | 30 +-------------
+ 3 files changed, 87 insertions(+), 45 deletions(-)
+
+commit 419d2146c27483ce91ca6ef2b1aec880a0bfdab7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 9 07:01:14 2022 -0600
+
+    [indic-generator] Cap off what categories have positions
+    
+    This was left off of the commit moving Indic categories to the generator.
+    It didn't fail any tests, but adding it back because it has implications
+    possibly.
+
+ src/gen-indic-table.py          |  7 +++++
+ src/hb-ot-shaper-indic-table.cc | 68 ++++++++++++++++++++---------------------
+ 2 files changed, 41 insertions(+), 34 deletions(-)
+
+commit e1d965d527a433fcb8e7b26451fdf77a1566f7e1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 9 06:48:25 2022 -0600
+
+    [indic-generator] Move position mapping to generator
+
+ src/gen-indic-table.py          |  38 ++-
+ src/hb-ot-shaper-indic-table.cc | 526 ++++++++++++++++++++--------------------
+ src/hb-ot-shaper-indic.hh       |  23 --
+ 3 files changed, 288 insertions(+), 299 deletions(-)
+
+commit 490751402686e86832019df0dfb0905b1a0b42d5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 9 06:33:51 2022 -0600
+
+    [indic-generator] Move category overrides to generator
+
+ src/gen-indic-table.py          |  96 +++++++++++++++++++++------
+ src/hb-ot-shaper-indic-table.cc | 144 +++++++++++++++++++++++++---------------
+ src/hb-ot-shaper-indic.hh       |  52 +--------------
+ 3 files changed, 169 insertions(+), 123 deletions(-)
+
+commit 58eeb3a180d03c9b39b39d99a6b9dbf30d17fd9f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 9 05:34:49 2022 -0600
+
+    [indic-generator] Move category mapping to generator
+
+ src/gen-indic-table.py          |  90 ++++++--
+ src/hb-ot-shaper-indic-table.cc | 492 ++++++++++++++++++----------------------
+ src/hb-ot-shaper-indic.hh       |  60 +----
+ 3 files changed, 305 insertions(+), 337 deletions(-)
+
+commit 899ca24387d84ebeff8ad6c9adbd72cd758b3aea
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 5 01:52:31 2022 -0600
+
+    [myanmar] Remove duplication of categories in the Myanmar shaper
+
+ src/Makefile.sources                |   1 -
+ src/hb-ot-shaper-myanmar-machine.hh |  50 ++++++----
+ src/hb-ot-shaper-myanmar-machine.rl |  40 +++++---
+ src/hb-ot-shaper-myanmar.cc         | 135 ++++++++++++++++++++++++---
+ src/hb-ot-shaper-myanmar.hh         | 177 ------------------------------------
+ src/meson.build                     |   1 -
+ 6 files changed, 181 insertions(+), 223 deletions(-)
+
+commit ce0528c0ff1bf14dc5741ea5cd8bd1e618e25310
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 5 01:34:10 2022 -0600
+
+    [khmer] Remove duplication of categories in the Khmer shaper
+
+ src/Makefile.sources              |   1 -
+ src/hb-ot-shaper-khmer-machine.hh |  48 +++++++++-------
+ src/hb-ot-shaper-khmer-machine.rl |  10 ++++
+ src/hb-ot-shaper-khmer.cc         |  72 ++++++++++++++++++++++--
+ src/hb-ot-shaper-khmer.hh         | 115 --------------------------------------
+ src/meson.build                   |   1 -
+ 6 files changed, 105 insertions(+), 142 deletions(-)
+
+commit 17c80035adc61c52a9e9600664496e3e4b837e37
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 9 04:17:38 2022 -0600
+
+    Revert "[cplusplus] Internally allow using hb_unique_ptr with hb_free()"
+    
+    This reverts commit b5f621b08d56c15832ab4f588a0673fce03305a0.
+    
+    A build was failing with clang 14 for Firefox apparently, sigh.
+    
+    https://github.com/harfbuzz/harfbuzz/issues/3647
+
+ src/hb.hh | 15 +--------------
+ 1 file changed, 1 insertion(+), 14 deletions(-)
+
+commit 9fc9b1ece4a0e7214456a27110e74e47ff3dbc15
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 8 12:35:43 2022 -0600
+
+    [layout] Minor, add using Lookup to GSUB/GPOS
+
+ src/OT/Layout/GSUB/GSUB.hh        | 2 ++
+ src/OT/Layout/GSUB/SubstLookup.hh | 2 +-
+ src/hb-ot-layout-gpos-table.hh    | 4 +++-
+ 3 files changed, 6 insertions(+), 2 deletions(-)
+
+commit d4ddb3acf89f8539e56a742b30ed3cd424e043dd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 8 11:45:14 2022 -0600
+
+    Comments typos
+
+ src/hb-set-digest.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 4119f73c21f5fae7635d0c0658732b339711a76c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 8 06:34:48 2022 -0600
+
+    [subset/layout] Rename dispatch_closure_lookups_recurse_func to dispatch_recurse_func<>
+
+ src/OT/Layout/GSUB/SubstLookup.hh | 4 ----
+ src/hb-ot-layout-gpos-table.hh    | 7 +++----
+ src/hb-ot-layout-gsub-table.hh    | 4 +++-
+ src/hb-ot-layout-gsubgpos.hh      | 2 ++
+ 4 files changed, 8 insertions(+), 9 deletions(-)
+
+commit c13ff395201cf20af0f91c38f08908a1c1570b0b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 8 06:25:23 2022 -0600
+
+    [layout] Rename apply_recurse_func to specialization of dispatch_recurse_func
+
+ src/OT/Layout/GSUB/SubstLookup.hh | 2 --
+ src/hb-ot-layout-gpos-table.hh    | 5 ++---
+ src/hb-ot-layout-gsub-table.hh    | 3 ++-
+ src/hb-ot-layout.cc               | 2 +-
+ 4 files changed, 5 insertions(+), 7 deletions(-)
+
+commit 6a1edb8c9751bebd463664227d60e0218af18dd2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 8 11:38:17 2022 -0600
+
+    [set-digest] One more rename
+
+ src/hb-set-digest.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 6453737b0edac0624b141a8e2892deddfa7e3765
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 8 11:37:12 2022 -0600
+
+    [set-digest] Rename lowest_bits to bits_pattern
+
+ src/hb-set-digest.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit 2a061cb9cc86c43e62ed5234850ed38fd690a896
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 8 11:35:50 2022 -0600
+
+    [set-digest] Improve documentation
+
+ src/hb-set-digest.hh | 20 ++++++++++++++++----
+ 1 file changed, 16 insertions(+), 4 deletions(-)
+
+commit 9342adb0d6336fe56f1c28271db27d07c6ed7c3b
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Wed Jun 8 12:47:05 2022 +0000
+
+    Bump actions/checkout from 2 to 3
+    
+    Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
+    - [Release notes](https://github.com/actions/checkout/releases)
+    - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
+    - [Commits](https://github.com/actions/checkout/compare/v2...v3)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: actions/checkout
+      dependency-type: direct:production
+      update-type: version-update:semver-major
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/configs-build.yml | 2 +-
+ .github/workflows/coverity-scan.yml | 2 +-
+ .github/workflows/linux-ci.yml      | 2 +-
+ .github/workflows/macos-ci.yml      | 2 +-
+ .github/workflows/msvc-ci.yml       | 2 +-
+ .github/workflows/msys2-ci.yml      | 2 +-
+ 6 files changed, 6 insertions(+), 6 deletions(-)
+
+commit 335d058bf4a61fa12373b375fcaff6fdd0aca55f
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Wed Jun 8 11:52:25 2022 +0000
+
+    Bump codecov/codecov-action from 1 to 3
+    
+    Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 1 to 3.
+    - [Release notes](https://github.com/codecov/codecov-action/releases)
+    - [Changelog](https://github.com/codecov/codecov-action/blob/master/CHANGELOG.md)
+    - [Commits](https://github.com/codecov/codecov-action/compare/v1...v3)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: codecov/codecov-action
+      dependency-type: direct:production
+      update-type: version-update:semver-major
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/linux-ci.yml | 2 +-
+ .github/workflows/macos-ci.yml | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit a51c3a66f2cb1a59f0d53d1b93060ebbd9048b80
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Wed Jun 8 11:52:27 2022 +0000
+
+    Bump actions/upload-artifact from 1 to 3
+    
+    Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 1 to 3.
+    - [Release notes](https://github.com/actions/upload-artifact/releases)
+    - [Commits](https://github.com/actions/upload-artifact/compare/v1...v3)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: actions/upload-artifact
+      dependency-type: direct:production
+      update-type: version-update:semver-major
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/cifuzz.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 80bf2b3d2f6dbe578c779d659d1a37610fa5b522
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date:   Wed Jun 8 11:52:30 2022 +0000
+
+    Bump actions/setup-python from 1 to 3
+    
+    Bumps [actions/setup-python](https://github.com/actions/setup-python) from 1 to 3.
+    - [Release notes](https://github.com/actions/setup-python/releases)
+    - [Commits](https://github.com/actions/setup-python/compare/v1...v3)
+    
+    ---
+    updated-dependencies:
+    - dependency-name: actions/setup-python
+      dependency-type: direct:production
+      update-type: version-update:semver-major
+    ...
+    
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+ .github/workflows/msvc-ci.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit acd21519272b60f686c2c9099d4ef34c4694cabc
+Author: naveen <172697+naveensrinivasan@users.noreply.github.com>
+Date:   Wed Jun 8 01:29:27 2022 +0000
+
+    chore: Included githubactions in the dependabot config
+    
+    This should help with keeping the GitHub actions updated on new releases. This will also help with keeping it secure.
+    
+    Dependabot helps in keeping the supply chain secure https://docs.github.com/en/code-security/dependabot
+    
+    GitHub actions up to date https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot
+    
+    https://github.com/ossf/scorecard/blob/main/docs/checks.md#dependency-update-tool
+    Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com>
+
+ .github/dependabot.yml | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 42051fe18a4326bb844577f8c4bc11b58abf7c3a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 8 04:00:21 2022 -0600
+
+    [layout] s/inplace/always_inplace/g
+
+ src/hb-ot-layout.cc | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 21346af01d4222cdf50478fd4ad8b445d5e2f62e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 7 14:41:39 2022 -0600
+
+    [layout-cache] Adjust cost-function for recent change
+
+ src/hb-ot-layout-gsubgpos.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit bfee6839b0de03453653e35dce97300488463142
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 7 11:41:05 2022 -0600
+
+    [layout-cache] Cache lookahead, not input, classdef in ChainContextFormat2
+    
+    From the commit:
+    
+    +    /* For ChainContextFormat2 we cache the LookaheadClassDef instead of InputClassDef.
+    +     * The reason is that most heavy fonts want to identify a glyph in context and apply
+    +     * a lookup to it. In this scenario, the length of the input sequence is one, whereas
+    +     * the lookahead / backtrack are typically longer.  The one glyph in input sequence is
+    +     * looked-up below and no input glyph is looked up in individual rules, whereas the
+    +     * lookahead and backtrack glyphs are tried.  Since we match lookahead before backtrack,
+    +     * we should cache lookahead.  This decisions showed a 20% improvement in shaping of
+    +     * the Gulzar font.
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3636
+
+ src/hb-ot-layout-gsubgpos.hh | 23 +++++++++++++----------
+ 1 file changed, 13 insertions(+), 10 deletions(-)
+
+commit 39820af72f5632cc45ede44da2e2f0caa5df46a6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 7 10:18:38 2022 -0600
+
+    [layout] Add HB_NO_OT_LAYOUT_LOOKUP_CACHE to disable caching lookups
+    
+    Enabled when optimize-size profile is enabled.
+
+ src/hb-config.hh             |  4 ++++
+ src/hb-ot-layout-gsubgpos.hh | 48 ++++++++++++++++++++++++++++++++++++--------
+ 2 files changed, 44 insertions(+), 8 deletions(-)
+
+commit 845279c34ce38e72adc4573f6bb45ec0e657e673
+Merge: b59e25f25 c8fb048f7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 7 16:40:22 2022 +0100
+
+    Merge pull request #3636 from harfbuzz/classdef-cache
+    
+    Classdef cache
+
+commit b59e25f25ef20dddc7e4dff0432c63d1afe287ae
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 7 09:27:09 2022 -0600
+
+    [cff] Try fixing Heap-buffer-overflow in CFF::Charset::collect_glyph_to_sid_map
+    
+    Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=47790
+
+ src/hb-ot-cff1-table.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit c8fb048f79964e0b6cdf9d322fc12c71328cfde8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 7 09:20:27 2022 -0600
+
+    [gsubgpos] Document caching
+
+ src/hb-ot-layout-gsubgpos.hh | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+commit 5963cf446907127c55fe0404e068c19ca7eb4490
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 7 09:12:45 2022 -0600
+
+    [gsubgpos] Merge cache_enter and cache_leave entry points
+    
+    Saves a pointer per subtable
+
+ src/hb-ot-layout-gsubgpos.hh | 102 ++++++++++++++++++++-----------------------
+ 1 file changed, 47 insertions(+), 55 deletions(-)
+
+commit d4c09e9a872967ebc2b9921ad1d267162e5ad569
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 7 09:03:30 2022 -0600
+
+    [gsubgpos] Remove apply_cached() entry point
+    
+    Just use a bool to apply()
+
+ src/hb-ot-layout-gsubgpos.hh | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+commit b96622d15c5e22ae214e4184142d28ee609293a4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 5 02:45:41 2022 -0600
+
+    [layout] Use a cache for main input ClassDef of (Chain)ContextLookupFormat2
+    
+    This commit adds a per-lookup caching infrastructure to GSUB/GPOS, and
+    uses it to cache input ClassDef.get_class value for (Chain)ContextLookupFormat2.
+    
+    For fonts heavy on use of heave class-based2 context matching, this shows
+    a good speedup. For NotoNastaliqUrdu for example, I observe 17% speedup.
+    
+    Unfortunately not many other lookups can use a cache like this :(.
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3636
+
+ src/hb-ot-layout-common.hh   |  13 ++
+ src/hb-ot-layout-gsubgpos.hh | 277 ++++++++++++++++++++++++++++++++++++-------
+ src/hb-ot-layout.cc          |  10 +-
+ 3 files changed, 257 insertions(+), 43 deletions(-)
+
+commit 356c1f833641c139b554548edbcd33bfbbc44540
+Author: neilnaveen <42328488+neilnaveen@users.noreply.github.com>
+Date:   Tue Jun 7 01:08:13 2022 +0000
+
+    chore: Set permissions for GitHub actions
+    
+     Restrict the GitHub token permissions only to the required ones; this way, even if the attackers will succeed in compromising your workflow, they won’t be able to do much.
+    
+    - Included permissions for the action. https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions
+    
+    https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
+    
+    https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
+    
+    [Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/)
+    
+    Signed-off-by: neilnaveen <42328488+neilnaveen@users.noreply.github.com>
+
+ .github/workflows/configs-build.yml | 3 +++
+ .github/workflows/coverity-scan.yml | 3 +++
+ .github/workflows/linux-ci.yml      | 3 +++
+ .github/workflows/macos-ci.yml      | 3 +++
+ .github/workflows/msvc-ci.yml       | 3 +++
+ .github/workflows/msys2-ci.yml      | 3 +++
+ 6 files changed, 18 insertions(+)
+
+commit 4266f4e29ada827cec1f38ab88ff2c071f6deb2f
+Author: Xavier Claessens <xavier.claessens@collabora.com>
+Date:   Fri Jun 3 12:06:56 2022 -0400
+
+    Fix check-* scripts when harfbuzz is a subproject
+    
+    When harfbuzz is a subproject paths are in the form
+    "subprojects/harfbuzz/src/...". Instead of removing "src/" prefix, take
+    the absolute path and make it relative to current source dir.
+    
+    This fix regression introduced in
+    https://github.com/harfbuzz/harfbuzz/pull/3394.
+
+ src/Makefile.am              |  1 +
+ src/check-c-linkage-decls.py | 16 +++++++++-------
+ src/check-header-guards.py   | 15 ++++++++-------
+ src/check-includes.py        | 15 ++++++++-------
+ src/meson.build              |  1 +
+ 5 files changed, 27 insertions(+), 21 deletions(-)
+
+commit 15543f70e04e726639c1b50ace6bdaa9c3ab50b6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 4 10:55:50 2022 -0600
+
+    [indic-like] Move allocation of syllable() buffer var to shapers that use it
+    
+    In indic, we don't have a pause location release the var.
+
+ src/hb-ot-layout.cc          | 1 -
+ src/hb-ot-layout.hh          | 3 ---
+ src/hb-ot-shaper-indic.cc    | 1 +
+ src/hb-ot-shaper-khmer.cc    | 3 ++-
+ src/hb-ot-shaper-myanmar.cc  | 2 ++
+ src/hb-ot-shaper-syllabic.cc | 8 ++++++++
+ src/hb-ot-shaper-syllabic.hh | 5 +++++
+ src/hb-ot-shaper-use.cc      | 2 ++
+ 8 files changed, 20 insertions(+), 5 deletions(-)
+
+commit 104dc85a2235cc14d2f40638c2f9fa00b39dc5a4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 4 06:56:35 2022 -0600
+
+    [buffer] Add try_allocate for buffer variables
+
+ src/hb-buffer.hh | 27 ++++++++++++++-------------
+ 1 file changed, 14 insertions(+), 13 deletions(-)
+
+commit b5f621b08d56c15832ab4f588a0673fce03305a0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 5 07:52:51 2022 -0600
+
+    [cplusplus] Internally allow using hb_unique_ptr with hb_free()
+    
+    ...for arbitrary types.
+
+ src/hb.hh | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+commit f18eb000d3884795a43ea46ce5faa95086267b2c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 5 04:17:05 2022 -0600
+
+    [buffer] Mark a variable as unused
+    
+    Weird. Somehow our HB_TINY bot started erring as this var being unused
+    in non-debug builds. Not sure why now...
+    
+        In file included from src/hb-ot-map.hh:32:0,
+                         from src/hb-ot-shape.hh:32,
+                         from src/hb-aat-layout.hh:32,
+                         from src/hb-aat-layout.cc:30,
+                         from src/harfbuzz.cc:1:
+        src/hb-buffer.hh: In member function ‘void hb_buffer_t::assert_var(unsigned int, unsigned int)’:
+        src/hb-buffer.hh:192:18: error: unused variable ‘bits’ [-Werror=unused-variable]
+             unsigned int bits = (1u<<end) - (1u<<start);
+                          ^~~~
+    cc1plus: some warnings being treated as errors
+    Error: Process completed with exit code 1.
+
+ src/hb-buffer.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e6409d3905d8801d1be647d505524f71230c6ca1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 5 06:57:37 2022 -0600
+
+    Revert "[layout] Use a cache for main input ClassDef of (Chain)ContextLookups"
+    
+    This reverts commit 57d1c08739d0acd94b96da2f9d5dd6c0ff3b3722.
+    
+    Err. This was an accident.
+
+ src/hb-ot-layout-common.hh   |  13 --
+ src/hb-ot-layout-gsubgpos.hh | 275 +++++++------------------------------------
+ src/hb-ot-layout.cc          |  10 +-
+ 3 files changed, 43 insertions(+), 255 deletions(-)
+
+commit 57d1c08739d0acd94b96da2f9d5dd6c0ff3b3722
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 5 02:45:41 2022 -0600
+
+    [layout] Use a cache for main input ClassDef of (Chain)ContextLookups
+
+ src/hb-ot-layout-common.hh   |  13 ++
+ src/hb-ot-layout-gsubgpos.hh | 275 ++++++++++++++++++++++++++++++++++++-------
+ src/hb-ot-layout.cc          |  10 +-
+ 3 files changed, 255 insertions(+), 43 deletions(-)
+
+commit 697287fbd7a8c8e21a36c9b73eeffecd6b862aaa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 5 06:53:42 2022 -0600
+
+    [benchmark-shape,hb-shape-threads] Fix argument parsing order
+    
+    After recent change.
+
+ perf/benchmark-shape.cc          | 4 ++--
+ test/threads/hb-shape-threads.cc | 4 ++--
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit c03a31417b5346b7b91ca1c2137a77625cd62c14
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 5 02:31:21 2022 -0600
+
+    [hb-shape-threads] Adjustments similar to benchmark-shape
+    
+    Duplication sighz.
+
+ test/threads/hb-shape-threads.cc | 34 ++++++++++++++++------------------
+ 1 file changed, 16 insertions(+), 18 deletions(-)
+
+commit d7c9cc34ae549ad6e54095732a6fc4aadfbadff4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 5 02:30:11 2022 -0600
+
+    Fix build
+
+ test/threads/hb-shape-threads.cc | 8 --------
+ 1 file changed, 8 deletions(-)
+
+commit 2dec74207067b793c5203fe7f8a00930f81d2f5a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 5 02:04:02 2022 -0600
+
+    [benchmark-shape] Remove a few tests
+    
+    They were not adding value.
+
+ perf/benchmark-shape.cc     | 12 ------------
+ perf/texts/fa-monologue.txt |  1 -
+ 2 files changed, 13 deletions(-)
+
+commit 3c258e1373e056cbddf27c31f1675547b884cfef
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 5 02:01:17 2022 -0600
+
+    [benchmark-shape] Reorder text vs font order for better output
+
+ perf/benchmark-shape.cc | 45 +++++++++++++++++++++++----------------------
+ 1 file changed, 23 insertions(+), 22 deletions(-)
+
+commit 92e81ab1dfcbd4e8ed4d70082a427c8e339269c9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 5 01:14:32 2022 -0600
+
+    [indic/khmer/myanmar] Shift category numbers around to avoid overlap
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3632
+
+ src/hb-ot-shaper-indic-machine.hh   | 433 +++++++++++++++++-------------------
+ src/hb-ot-shaper-indic-machine.rl   |  20 +-
+ src/hb-ot-shaper-indic.hh           |  21 +-
+ src/hb-ot-shaper-khmer-machine.hh   | 188 ++++++++--------
+ src/hb-ot-shaper-khmer-machine.rl   |   8 +-
+ src/hb-ot-shaper-myanmar-machine.hh | 298 ++++++++++++-------------
+ src/hb-ot-shaper-myanmar-machine.rl |   8 +-
+ 7 files changed, 481 insertions(+), 495 deletions(-)
+
+commit d6dbc0d17524e3f4bdaf7dbfd7f97b02e51fdb14
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 5 00:58:53 2022 -0600
+
+    [gi/ft] Silence warnings
+    
+    gi doesn't understand that FT_Face is a pointer, and not bare struct.
+    So it skips these APIs anyway. Mark skip to silense the warning.
+    
+    ../src/hb-ft.cc:242: Warning: HarfBuzz: hb_ft_font_get_face: return value: Invalid non-constant return of bare structure or union; register as boxed type or (skip)
+    ../src/hb-ft.cc:264: Warning: HarfBuzz: hb_ft_font_lock_face: return value: Invalid non-constant return of bare structure or union; register as boxed type or (skip)
+
+ src/hb-ft.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit f78a25098adc30ec24cde24676c2a077883a25e1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 5 00:55:35 2022 -0600
+
+    [gi] Remove Xconstructor annotations
+
+ src/hb-buffer.cc     | 2 +-
+ src/hb-draw.cc       | 2 +-
+ src/hb-face.cc       | 2 +-
+ src/hb-font.cc       | 4 ++--
+ src/hb-map.cc        | 2 +-
+ src/hb-set.cc        | 2 +-
+ src/hb-shape-plan.cc | 4 ++--
+ src/hb-unicode.cc    | 2 +-
+ 8 files changed, 10 insertions(+), 10 deletions(-)
+
+commit aef92b2846f08f99a30b2bd491b046c33576a884
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 5 00:44:31 2022 -0600
+
+    [ci] Better compiler specification in configs-build job
+
+ .github/workflows/configs-build.yml | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit cb961eac5ce98d43b0aa477b341b5bdd0b93fea2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jun 5 00:44:07 2022 -0600
+
+    [configs] Fix builds with HB_NO_BUFFER_SERIALIZE but not HB_NO_BUFFER_VERIFY
+    
+    https://github.com/harfbuzz/harfbuzz/commit/e986c12075a69300a5e114fe139ae5acd762ef1b#commitcomment-75339317
+
+ src/hb-buffer-verify.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 67852504f61eda5721ebe3831d91cd6167922157
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 4 08:45:03 2022 -0600
+
+    [indic/myanmar] No-op update to machines
+
+ src/hb-ot-shaper-indic-machine.hh   |  49 +++---
+ src/hb-ot-shaper-indic-machine.rl   |   3 +-
+ src/hb-ot-shaper-indic.hh           |   5 +-
+ src/hb-ot-shaper-myanmar-machine.hh | 331 ++++++++++++++++++------------------
+ 4 files changed, 193 insertions(+), 195 deletions(-)
+
+commit 20a61ca447a952c54b18ecae273aa8639e6650d4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 4 08:35:22 2022 -0600
+
+    [myanmar] Fold D category into GB
+    
+    Trying to free a byte the buffer vars, for caching of lookups.
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/3633
+
+ src/hb-ot-shaper-myanmar-machine.hh | 4 ++--
+ src/hb-ot-shaper-myanmar-machine.rl | 4 ++--
+ src/hb-ot-shaper-myanmar.hh         | 4 ++--
+ 3 files changed, 6 insertions(+), 6 deletions(-)
+
+commit f9b643f6b25ececbb6506dcc86eb5c50fd9824ca
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 4 07:29:40 2022 -0600
+
+    [layout] s/hb_get_subtables_context_t/hb_accelerate_subtables_context_t/g
+
+ src/hb-ot-layout-gsubgpos.hh | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+commit d4dfb8c1f19fe9ba99ff19718a67543fa027cb33
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 4 06:50:38 2022 -0600
+
+    [arabic] Free up buffer variable earlier
+
+ src/hb-ot-shaper-arabic.cc | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+commit 0c3d8c0d0f102c7ea622d94f86a24698206cb7a1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 4 06:05:23 2022 -0600
+
+    [README] Test adding as a symlink
+    
+    Autoconf requires README
+
+ README | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 4510d9a92894039a2ae3043b9b08a28b03c5ca66
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 4 06:02:25 2022 -0600
+
+    [README] Delete. We ship README.md
+
+ README | 15 ---------------
+ 1 file changed, 15 deletions(-)
+
+commit 01337e7a64d9c0fb907fc5aa5de495b84713ce9c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 4 06:01:52 2022 -0600
+
+    [README.md] minor
+
+ README.md | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3972ec7340270d2f0385502ee8b9b13dd5b23ab7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 4 06:01:17 2022 -0600
+
+    [TESTING.md] Update profiling instructions.
+
+ TESTING.md | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+commit af41be6fa7e7a19f6d0e608b1d77b8ff4f4cef97
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Apr 25 02:59:00 2022 +0200
+
+    Move freedesktop.org/wiki/HarfBuzz content to README.md
+
+ README.md | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+commit 9622337b524449257c43e70e8015627b4c6529dd
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Apr 25 04:14:03 2022 +0200
+
+    Move old harfbuzz.org content to README.md
+    
+    Copied from:
+    
+      https://web.archive.org/web/20191221151847/https://freedesktop.org/wiki/Software/HarfBuzz/
+    
+    Edited lightly trying to merge it with existing README.md content and
+    remove grossly outdated bits. Might still need more editing.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/1919
+
+ README.md | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 55 insertions(+), 2 deletions(-)
+
+commit e2ece939fbc23fc8dbb44242680fbe682f9623ab
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Jun 3 21:01:52 2022 +0200
+
+    [doc] Expand a little bit on Uniscribe compatibility
+    
+    https://github.com/harfbuzz/harfbuzz/issues/3556#issuecomment-1130247124
+
+ docs/usermanual-opentype-features.xml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 8d36300154d8fd774abebf8348cfdd6af971c50d
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Jun 3 21:00:08 2022 +0200
+
+    [doc] Talk less about “complex” scripts
+    
+    Use more neutral terms and don’t make it like some scripts are outliers.
+
+ docs/usermanual-clusters.xml          |  2 +-
+ docs/usermanual-getting-started.xml   |  2 +-
+ docs/usermanual-opentype-features.xml |  4 ++--
+ docs/usermanual-shaping-concepts.xml  | 45 +++++++++++++++--------------------
+ 4 files changed, 23 insertions(+), 30 deletions(-)
+
+commit bd44840fab0532078e14201e7aad34614f981f81
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Jun 3 20:24:32 2022 +0200
+
+    [doc] s/complexshapers/shapers/g
+
+ docs/features.dot | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit cc7ebb0ffa488a3e51efd13973ece4ddd8010dba
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jun 4 05:42:58 2022 -0600
+
+    Remove remaining mention to complex shapers in the code
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3628#issuecomment-1146248037
+
+ src/hb-ot-shape-normalize.cc | 2 +-
+ src/hb-ot-shape.cc           | 8 ++++----
+ src/hb-subset-input.cc       | 3 ++-
+ 3 files changed, 7 insertions(+), 6 deletions(-)
+
+commit b39b5f2f31d69d5fbe24659d294fd22f099f5956
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 04:10:28 2022 -0600
+
+    [name] Implement approximate language matching
+    
+    Very rudimentary.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3354
+
+ src/hb-ot-name-table.hh | 36 +++++++++++++++++++++++++++++++-----
+ test/api/test-ot-name.c |  7 +++++++
+ 2 files changed, 38 insertions(+), 5 deletions(-)
+
+commit 40d7d56e53035e66db5a76a15be3fedd3f9f11cf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 05:40:18 2022 -0600
+
+    [subset-input] Minor move
+
+ src/hb-subset-input.cc | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 40193adbfcd4e33fa1fde2fa61b3bcca3548fd05
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 05:35:19 2022 -0600
+
+    [subset] Update default features list
+
+ src/hb-subset-input.cc | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+commit 26d8066a41fa75160429846e757a4989a7b54f12
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Jun 3 10:28:02 2022 +0200
+
+    [test/shape] Remove texts subdirectory
+    
+    These texts were never hooked into the test suite, they however
+    represent a good collection of test texts, but one can always access
+    them from git history.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3123
+
+ test/shape/Makefile.am                             |    1 -
+ .../script-arabic/language-persian/mehran.txt      |    8 -
+ .../language-urdu/crulp/ligatures/2grams.txt       |  601 --
+ .../language-urdu/crulp/ligatures/3grams.txt       | 3415 -----------
+ .../language-urdu/crulp/ligatures/4grams.txt       | 6316 --------------------
+ .../language-urdu/crulp/ligatures/5grams.txt       | 5029 ----------------
+ .../language-urdu/crulp/ligatures/6grams.txt       | 1542 -----
+ .../language-urdu/crulp/ligatures/7grams.txt       |  354 --
+ .../language-urdu/crulp/ligatures/8grams.txt       |   26 -
+ .../language-urdu/crulp/ligatures/LICENSE          |    3 -
+ .../language-urdu/crulp/ligatures/README           |   16 -
+ .../language-urdu/crulp/ligatures/SOURCES          |    4 -
+ .../script-arabic/misc/diacritics/lam-alef.txt     |   28 -
+ .../misc/diacritics/language-arabic.txt            |  695 ---
+ .../misc/diacritics/language-persian.txt           |   48 -
+ .../misc/diacritics/language-urdu.txt              |  188 -
+ .../misc/diacritics/ligature-components.txt        |   18 -
+ .../misc/diacritics/ligature-diacritics.txt        |    1 -
+ .../misc/diacritics/mark-skipping.txt              |   10 -
+ .../shaper-arabic/script-mongolian/misc/misc.txt   |    6 -
+ .../script-mongolian/misc/non-joining.txt          |    8 -
+ .../shaper-arabic/script-mongolian/misc/poem.txt   |    4 -
+ .../script-mongolian/misc/variation-selectors.txt  |    8 -
+ .../shaper-arabic/script-nko/misc/misc.txt         |    5 -
+ .../shaper-arabic/script-phags-pa/misc/misc.txt    |   14 -
+ .../script-syriac/misc/abbreviation-mark.txt       |   11 -
+ .../shaper-arabic/script-syriac/misc/alaph.txt     |   98 -
+ .../shaper-default/script-ethiopic/misc/misc.txt   |    1 -
+ .../shaper-default/script-han/misc/cjk-compat.txt  |    3 -
+ .../script-hiragana/misc/kazuraki-liga-lines.txt   |    8 -
+ .../script-hiragana/misc/kazuraki-liga.txt         |   53 -
+ .../shaper-default/script-linear-b/misc/misc.txt   |    1 -
+ .../shaper-default/script-tifinagh/misc/misc.txt   |   10 -
+ .../shaper-hangul/script-hangul/misc/misc.txt      |    4 -
+ .../script-hebrew/misc/diacritics.txt              |   16 -
+ .../shaper-indic/script-assamese/utrrs/LICENSE     |   19 -
+ .../shaper-indic/script-assamese/utrrs/README      |   13 -
+ .../shaper-indic/script-assamese/utrrs/SOURCES     |    2 -
+ .../IndicFontFeatureCodepoint-AdditionalVowels.txt |    4 -
+ .../IndicFontFeatureCodepoint-Consonants.txt       |   40 -
+ .../IndicFontFeatureCodepoint-DependentVowels.txt  |   10 -
+ .../codepoint/IndicFontFeatureCodepoint-Digits.txt |   10 -
+ ...IndicFontFeatureCodepoint-IndependentVowels.txt |   11 -
+ .../IndicFontFeatureCodepoint-Reserved.txt         |    2 -
+ .../IndicFontFeatureCodepoint-VariousSigns.txt     |    6 -
+ .../utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt  |   59 -
+ .../utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt  |  131 -
+ .../utrrs/gsub/IndicFontFeatureGSUB.txt            |  139 -
+ .../script-bengali/bengali-vowel-letters.txt       |    3 -
+ .../shaper-indic/script-bengali/misc/misc.txt      |   53 -
+ .../shaper-indic/script-bengali/misc/reph.txt      |   14 -
+ .../shaper-indic/script-bengali/utrrs/LICENSE      |   19 -
+ .../shaper-indic/script-bengali/utrrs/README       |   13 -
+ .../shaper-indic/script-bengali/utrrs/SOURCES      |    2 -
+ .../IndicFontFeatureCodepoint-AdditionalVowels.txt |    1 -
+ .../IndicFontFeatureCodepoint-Consonants.txt       |   36 -
+ .../IndicFontFeatureCodepoint-DependentVowels.txt  |   10 -
+ .../codepoint/IndicFontFeatureCodepoint-Digits.txt |   10 -
+ ...IndicFontFeatureCodepoint-IndependentVowels.txt |   12 -
+ .../IndicFontFeatureCodepoint-Reserved.txt         |    2 -
+ .../IndicFontFeatureCodepoint-VariousSigns.txt     |    6 -
+ .../utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt  |   58 -
+ .../utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt  |  119 -
+ .../utrrs/gsub/IndicFontFeatureGSUB.txt            |  215 -
+ .../devanagari-atomic-consonants.txt               |   33 -
+ .../script-devanagari/devanagari-vowel-letters.txt |   17 -
+ .../script-devanagari/misc/dottedcircle.txt        |    8 -
+ .../script-devanagari/misc/eyelash.txt             |    3 -
+ .../script-devanagari/misc/joiners.txt             |   19 -
+ .../shaper-indic/script-devanagari/misc/misc.txt   |   36 -
+ .../script-devanagari/misc/spec-deviations.txt     |    1 -
+ .../script-devanagari/misc/tricky-reordering.txt   |    5 -
+ .../shaper-indic/script-devanagari/utrrs/LICENSE   |   19 -
+ .../shaper-indic/script-devanagari/utrrs/README    |   13 -
+ .../shaper-indic/script-devanagari/utrrs/SOURCES   |    2 -
+ ...icFontFeatureCodepoint-AdditionalConsonants.txt |    8 -
+ .../IndicFontFeatureCodepoint-AdditionalVowels.txt |    4 -
+ .../IndicFontFeatureCodepoint-Consonants.txt       |   45 -
+ .../IndicFontFeatureCodepoint-DependentVowels.txt  |   14 -
+ ...tFeatureCodepoint-DevnagariSpecificAddition.txt |    1 -
+ .../codepoint/IndicFontFeatureCodepoint-Digits.txt |   10 -
+ ...ndicFontFeatureCodepoint-GenericPunctuation.txt |    2 -
+ ...IndicFontFeatureCodepoint-IndependentVowels.txt |   16 -
+ .../IndicFontFeatureCodepoint-VariousSigns.txt     |   10 -
+ .../utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt  |  185 -
+ .../utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt  |  185 -
+ .../utrrs/gsub/IndicFontFeatureGSUB.txt            | 1367 -----
+ .../script-gujarati/gujarati-vowel-letters.txt     |    8 -
+ .../shaper-indic/script-gujarati/utrrs/LICENSE     |   19 -
+ .../shaper-indic/script-gujarati/utrrs/README      |   13 -
+ .../shaper-indic/script-gujarati/utrrs/SOURCES     |    2 -
+ .../IndicFontFeatureCodepoint-AdditionalVowels.txt |    1 -
+ .../IndicFontFeatureCodepoint-Consonants.txt       |   34 -
+ .../IndicFontFeatureCodepoint-DependentVowels.txt  |   12 -
+ .../codepoint/IndicFontFeatureCodepoint-Digits.txt |   10 -
+ ...IndicFontFeatureCodepoint-IndependentVowels.txt |   13 -
+ .../IndicFontFeatureCodepoint-Reserved.txt         |    2 -
+ .../IndicFontFeatureCodepoint-VariousSigns.txt     |    7 -
+ .../utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt  |  170 -
+ .../utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt  |  170 -
+ .../utrrs/gsub/IndicFontFeatureGSUB.txt            | 1156 ----
+ .../script-gurmukhi/gurmukhi-vowel-letters.txt     |    9 -
+ .../shaper-indic/script-gurmukhi/misc/misc.txt     |    2 -
+ .../shaper-indic/script-gurmukhi/utrrs/LICENSE     |   19 -
+ .../shaper-indic/script-gurmukhi/utrrs/README      |   13 -
+ .../shaper-indic/script-gurmukhi/utrrs/SOURCES     |    2 -
+ .../IndicFontFeatureCodepoint-Consonants.txt       |   38 -
+ .../IndicFontFeatureCodepoint-DependentVowels.txt  |    9 -
+ .../codepoint/IndicFontFeatureCodepoint-Digits.txt |   10 -
+ .../IndicFontFeatureCodepoint-GurmukhiSpecific.txt |    6 -
+ ...IndicFontFeatureCodepoint-IndependentVowels.txt |   10 -
+ .../IndicFontFeatureCodepoint-Reserved.txt         |    2 -
+ .../IndicFontFeatureCodepoint-VariousSigns.txt     |    6 -
+ .../utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt  |   22 -
+ .../utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt  |    2 -
+ .../utrrs/gsub/IndicFontFeatureGSUB.txt            |  152 -
+ .../script-kannada/kannada-vowel-letters.txt       |    3 -
+ .../shaper-indic/script-kannada/misc/misc.txt      |   20 -
+ .../script-kannada/misc/right-matras.txt           |    7 -
+ .../shaper-indic/script-kannada/utrrs/LICENSE      |   19 -
+ .../shaper-indic/script-kannada/utrrs/README       |   13 -
+ .../shaper-indic/script-kannada/utrrs/SOURCES      |    2 -
+ ...icFontFeatureCodepoint-AdditionalConsonants.txt |    1 -
+ .../IndicFontFeatureCodepoint-AdditionalVowels.txt |    4 -
+ .../IndicFontFeatureCodepoint-Consonants.txt       |   40 -
+ .../IndicFontFeatureCodepoint-DependentVowels.txt  |   13 -
+ .../codepoint/IndicFontFeatureCodepoint-Digits.txt |   10 -
+ ...IndicFontFeatureCodepoint-IndependentVowels.txt |   14 -
+ .../IndicFontFeatureCodepoint-Reserved.txt         |    2 -
+ .../IndicFontFeatureCodepoint-VariousSigns.txt     |    9 -
+ .../utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt  |  188 -
+ .../utrrs/gsub/IndicFontFeatureGSUB.txt            |  306 -
+ .../script-malayalam/malayalam-vowel-letters.txt   |    5 -
+ .../shaper-indic/script-malayalam/misc/cibu.txt    |  188 -
+ .../script-malayalam/misc/dot-reph.txt             |   15 -
+ .../shaper-indic/script-malayalam/misc/misc.txt    |   65 -
+ .../shaper-indic/script-malayalam/utrrs/LICENSE    |   19 -
+ .../shaper-indic/script-malayalam/utrrs/README     |   13 -
+ .../shaper-indic/script-malayalam/utrrs/SOURCES    |    2 -
+ .../IndicFontFeatureCodepoint-AdditionalVowels.txt |    2 -
+ .../IndicFontFeatureCodepoint-Consonants.txt       |   36 -
+ .../IndicFontFeatureCodepoint-DependentVowels.txt  |   12 -
+ .../codepoint/IndicFontFeatureCodepoint-Digits.txt |   10 -
+ ...IndicFontFeatureCodepoint-IndependentVowels.txt |   14 -
+ .../IndicFontFeatureCodepoint-Reserved.txt         |    2 -
+ .../IndicFontFeatureCodepoint-VariousSigns.txt     |    4 -
+ .../utrrs/gsub/IndicFontFeatureGSUB.txt            |  254 -
+ .../shaper-indic/script-oriya/misc/bindu.txt       |    2 -
+ .../shaper-indic/script-oriya/misc/misc.txt        |   28 -
+ .../script-oriya/oriya-vowel-letters.txt           |    3 -
+ .../shaper-indic/script-oriya/utrrs/LICENSE        |   19 -
+ .../shaper-indic/script-oriya/utrrs/README         |   13 -
+ .../shaper-indic/script-oriya/utrrs/SOURCES        |    2 -
+ ...icFontFeatureCodepoint-AdditionalConsonants.txt |    3 -
+ .../IndicFontFeatureCodepoint-AdditionalVowels.txt |    2 -
+ .../IndicFontFeatureCodepoint-Consonants.txt       |   34 -
+ .../IndicFontFeatureCodepoint-DependentVowels.txt  |   12 -
+ .../codepoint/IndicFontFeatureCodepoint-Digits.txt |   10 -
+ ...IndicFontFeatureCodepoint-IndependentVowels.txt |   12 -
+ .../IndicFontFeatureCodepoint-OriyaSpecific.txt    |    2 -
+ .../IndicFontFeatureCodepoint-Reserved.txt         |    2 -
+ .../IndicFontFeatureCodepoint-VariousSigns.txt     |    8 -
+ .../utrrs/gsub/IndicFontFeatureGSUB.txt            |  170 -
+ .../shaper-indic/script-sinhala/misc/extensive.txt | 4390 --------------
+ .../shaper-indic/script-sinhala/misc/misc.txt      |   41 -
+ .../shaper-indic/script-sinhala/misc/reph.txt      |    3 -
+ .../script-sinhala/misc/split-matras.txt           |    4 -
+ .../shaper-indic/script-sinhala/utrrs/LICENSE      |   19 -
+ .../shaper-indic/script-sinhala/utrrs/README       |   13 -
+ .../shaper-indic/script-sinhala/utrrs/SOURCES      |    2 -
+ .../IndicFontFeatureCodepoint-Consonants.txt       |   41 -
+ .../IndicFontFeatureCodepoint-DependentVowels.txt  |   17 -
+ ...IndicFontFeatureCodepoint-IndependentVowels.txt |   18 -
+ .../IndicFontFeatureCodepoint-Punctuation.txt      |    1 -
+ .../IndicFontFeatureCodepoint-VariousSigns.txt     |    3 -
+ .../utrrs/gpos/IndicFontFeatureGPOS.txt            |  162 -
+ .../utrrs/gsub/IndicFontFeatureGSUB-Conjunct.txt   |    1 -
+ .../gsub/IndicFontFeatureGSUB-Rakaaraansaya.txt    |   41 -
+ .../utrrs/gsub/IndicFontFeatureGSUB-Repaya.txt     |   42 -
+ .../gsub/IndicFontFeatureGSUB-Special-Cases.txt    |    2 -
+ .../gsub/IndicFontFeatureGSUB-TouchingLetters.txt  |    1 -
+ .../utrrs/gsub/IndicFontFeatureGSUB-Yansaya.txt    |   41 -
+ .../utrrs/gsub/IndicFontFeatureGSUB.txt            |    1 -
+ .../shaper-indic/script-tamil/misc/misc.txt        |   43 -
+ .../shaper-indic/script-tamil/utrrs/LICENSE        |   19 -
+ .../shaper-indic/script-tamil/utrrs/README         |   13 -
+ .../shaper-indic/script-tamil/utrrs/SOURCES        |    2 -
+ .../IndicFontFeatureCodepoint-Consonants.txt       |   23 -
+ .../IndicFontFeatureCodepoint-CurrencySymbols.txt  |    1 -
+ .../IndicFontFeatureCodepoint-DependentVowels.txt  |   11 -
+ .../codepoint/IndicFontFeatureCodepoint-Digits.txt |   10 -
+ ...IndicFontFeatureCodepoint-IndependentVowels.txt |   12 -
+ .../IndicFontFeatureCodepoint-Numerics.txt         |    3 -
+ .../IndicFontFeatureCodepoint-Reserved.txt         |    2 -
+ .../IndicFontFeatureCodepoint-Symbols.txt          |    6 -
+ .../IndicFontFeatureCodepoint-TamilSymbol.txt      |    1 -
+ .../IndicFontFeatureCodepoint-VariousSigns.txt     |    4 -
+ .../utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt  |   64 -
+ .../utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt  |   44 -
+ .../utrrs/gsub/IndicFontFeatureGSUB.txt            |    4 -
+ .../shaper-indic/script-telugu/misc/misc.txt       |   12 -
+ .../script-telugu/telugu-vowel-letters.txt         |    5 -
+ .../shaper-indic/script-telugu/utrrs/LICENSE       |   19 -
+ .../shaper-indic/script-telugu/utrrs/README        |   13 -
+ .../shaper-indic/script-telugu/utrrs/SOURCES       |    2 -
+ .../IndicFontFeatureCodepoint-AdditionalVowels.txt |    2 -
+ .../IndicFontFeatureCodepoint-Consonants.txt       |   38 -
+ .../IndicFontFeatureCodepoint-DependentVowels.txt  |   13 -
+ .../codepoint/IndicFontFeatureCodepoint-Digits.txt |   10 -
+ ...IndicFontFeatureCodepoint-IndependentVowels.txt |   14 -
+ .../IndicFontFeatureCodepoint-Reserved.txt         |    2 -
+ .../IndicFontFeatureCodepoint-VariousSigns.txt     |    6 -
+ .../utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt  |  385 --
+ .../utrrs/gsub/IndicFontFeatureGSUB.txt            |  287 -
+ test/shape/texts/in-house/shaper-khmer/misc.txt    |   89 -
+ .../in-house/shaper-khmer/other-marks-invalid.txt  |    4 -
+ .../texts/in-house/shaper-khmer/other-marks.txt    |    7 -
+ .../shaper-myanmar/script-myanmar/misc/misc.txt    |    7 -
+ .../shaper-myanmar/script-myanmar/misc/otspec.txt  |    1 -
+ .../shaper-myanmar/script-myanmar/misc/utn11.txt   |   34 -
+ .../shaper-thai/script-lao/misc/sara-am.txt        |   20 -
+ .../in-house/shaper-thai/script-thai/misc/misc.txt |   11 -
+ .../shaper-thai/script-thai/misc/phinthu.txt       |   16 -
+ .../shaper-thai/script-thai/misc/pua-shaping.txt   |   11 -
+ .../shaper-thai/script-thai/misc/sara-am.txt       |   20 -
+ .../script-tibetan/misc/contractions.txt           |  612 --
+ .../shaper-tibetan/script-tibetan/misc/misc.txt    |    2 -
+ .../in-house/shaper-use/script-batak/misc.txt      |    9 -
+ .../in-house/shaper-use/script-buginese/misc.txt   |   70 -
+ .../texts/in-house/shaper-use/script-cham/misc.txt |    3 -
+ .../in-house/shaper-use/script-javanese/misc.txt   |   54 -
+ .../in-house/shaper-use/script-kaithi/misc.txt     |    6 -
+ .../in-house/shaper-use/script-kharoshti/misc.txt  |   36 -
+ .../in-house/shaper-use/script-tai-tham/misc.txt   |    2 -
+ .../shaper-use/script-tai-tham/torture.txt         |   23 -
+ 235 files changed, 32058 deletions(-)
+
+commit cd41557a96a57383266413818b065729b890d261
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Jun 3 09:46:57 2022 +0200
+
+    [test/shape] Add PhagsPa tests
+    
+    Adopted from texts/in-house/shaper-arabic/script-phags-pa/misc/misc.txt.
+    
+    Using Noto Sans PhagsPa.
+
+ test/shape/data/in-house/Makefile.sources                |   1 +
+ .../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf   | Bin 0 -> 8324 bytes
+ test/shape/data/in-house/meson.build                     |   1 +
+ test/shape/data/in-house/tests/arabic-phags-pa.tests     |  14 ++++++++++++++
+ 4 files changed, 16 insertions(+)
+
+commit 1ab12e314a64fac78d9c720cb6f786a1a3705228
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Jun 3 09:37:25 2022 +0200
+
+    [test/shape] Add Malayalam dot-reph tests
+    
+    Adopted from texts/in-house/shaper-indic/script-malayalam/misc/dot-reph.txt.
+    
+    Using Noto Sans Malayalam.
+
+ test/shape/data/in-house/Makefile.sources                |   1 +
+ .../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf   | Bin 0 -> 5464 bytes
+ test/shape/data/in-house/meson.build                     |   1 +
+ .../data/in-house/tests/indic-malayalam-dot-reph.tests   |  15 +++++++++++++++
+ 4 files changed, 17 insertions(+)
+
+commit 6b2f3b5a99110fd8081f1e51cc5c3c1fcfbf7e2a
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Jun 3 09:15:24 2022 +0200
+
+    [test/shape] Add Javanese tests
+    
+    Adopted from texts/in-house/shaper-use/script-javanese/misc.txt.
+    
+    I don’t know what font this was originally tested against, so I used
+    Noto Sans Javanese.
+
+ test/shape/data/in-house/Makefile.sources          |   1 +
+ .../f70f345188472b93f565d1d7fae8c668dd6a3244.ttf   | Bin 0 -> 90140 bytes
+ test/shape/data/in-house/meson.build               |   1 +
+ test/shape/data/in-house/tests/use-javanese.tests  |  54 +++++++++++++++++++++
+ 4 files changed, 56 insertions(+)
+
+commit c9c47dd8ad12cade0a5639086173bd3a3c23f4bd
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Jun 3 08:58:57 2022 +0200
+
+    [test/shape] Add Hebrew diacritics tests
+    
+    Adopted from 406044986a68676f3050f9350ccc448c615fc685. Using
+    TaameyFrankCLM.ttf from the Mozilla issue.
+
+ test/shape/data/in-house/Makefile.sources          |   1 +
+ .../b895f8ff06493cc893ec44de380690ca0074edfa.ttf   | Bin 0 -> 29284 bytes
+ test/shape/data/in-house/meson.build               |   1 +
+ .../data/in-house/tests/hebrew-diacritics.tests    |  31 +++++++++++++++++++++
+ 4 files changed, 33 insertions(+)
+
+commit ef5d7febc826279e81aba84db8eb7ddf8289d2b0
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Jun 3 08:46:30 2022 +0200
+
+    [test/shape] Allow using hb-subset in record-test.sh
+    
+    I think it is about time we use our own subsetter here. FontTools can
+    still be used.
+
+ test/shape/record-test.sh | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+commit 5bfb0b721c6c492ad61abf99bd36913cc83ec0b8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 02:56:41 2022 -0600
+
+    Rename s/shape-complex/shaper/g
+
+ src/Makefile.sources                               | 64 +++++++++++-----------
+ src/gen-indic-table.py                             |  2 +-
+ src/gen-use-table.py                               |  2 +-
+ src/gen-vowel-constraints.py                       |  2 +-
+ src/harfbuzz.cc                                    | 24 ++++----
+ src/hb-ot-shape-normalize.cc                       |  2 +-
+ src/hb-ot-shape.cc                                 |  2 +-
+ ...fallback.hh => hb-ot-shaper-arabic-fallback.hh} |  2 +-
+ ...list.hh => hb-ot-shaper-arabic-joining-list.hh} |  0
+ ...rabic-table.hh => hb-ot-shaper-arabic-table.hh} |  0
+ ...c-win1256.hh => hb-ot-shaper-arabic-win1256.hh} |  2 +-
+ ...pe-complex-arabic.cc => hb-ot-shaper-arabic.cc} |  6 +-
+ ...pe-complex-arabic.hh => hb-ot-shaper-arabic.hh} |  2 +-
+ ...-complex-default.cc => hb-ot-shaper-default.cc} |  2 +-
+ ...pe-complex-hangul.cc => hb-ot-shaper-hangul.cc} |  2 +-
+ ...pe-complex-hebrew.cc => hb-ot-shaper-hebrew.cc} |  2 +-
+ ...ic-machine.hh => hb-ot-shaper-indic-machine.hh} | 54 +++++++++---------
+ ...ic-machine.rl => hb-ot-shaper-indic-machine.rl} |  0
+ ...-indic-table.cc => hb-ot-shaper-indic-table.cc} |  2 +-
+ ...hape-complex-indic.cc => hb-ot-shaper-indic.cc} |  6 +-
+ ...hape-complex-indic.hh => hb-ot-shaper-indic.hh} |  2 +-
+ ...er-machine.hh => hb-ot-shaper-khmer-machine.hh} | 40 +++++++-------
+ ...er-machine.rl => hb-ot-shaper-khmer-machine.rl} |  0
+ ...hape-complex-khmer.cc => hb-ot-shaper-khmer.cc} |  4 +-
+ ...hape-complex-khmer.hh => hb-ot-shaper-khmer.hh} |  2 +-
+ ...-machine.hh => hb-ot-shaper-myanmar-machine.hh} | 40 +++++++-------
+ ...-machine.rl => hb-ot-shaper-myanmar-machine.rl} |  0
+ ...-complex-myanmar.cc => hb-ot-shaper-myanmar.cc} |  4 +-
+ ...-complex-myanmar.hh => hb-ot-shaper-myanmar.hh} |  2 +-
+ ...omplex-syllabic.cc => hb-ot-shaper-syllabic.cc} |  2 +-
+ ...omplex-syllabic.hh => hb-ot-shaper-syllabic.hh} |  2 +-
+ ...-shape-complex-thai.cc => hb-ot-shaper-thai.cc} |  2 +-
+ ...-use-machine.hh => hb-ot-shaper-use-machine.hh} | 54 +++++++++---------
+ ...-use-machine.rl => hb-ot-shaper-use-machine.rl} |  2 +-
+ ...plex-use-table.hh => hb-ot-shaper-use-table.hh} |  2 +-
+ ...ot-shape-complex-use.cc => hb-ot-shaper-use.cc} | 10 ++--
+ ...raints.cc => hb-ot-shaper-vowel-constraints.cc} |  2 +-
+ ...raints.hh => hb-ot-shaper-vowel-constraints.hh} |  2 +-
+ src/{hb-ot-shape-complex.hh => hb-ot-shaper.hh}    |  0
+ src/meson.build                                    | 64 +++++++++++-----------
+ src/update-unicode-tables.make                     | 20 +++----
+ 41 files changed, 217 insertions(+), 217 deletions(-)
+
+commit 44be1e5dfb8f7f9398d16421157ef363d1cae157
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 02:54:33 2022 -0600
+
+    s/SHAPE_COMPLEX/SHAPER/g
+
+ src/gen-arabic-joining-list.py                 | 6 +++---
+ src/gen-arabic-table.py                        | 6 +++---
+ src/gen-use-table.py                           | 6 +++---
+ src/gen-vowel-constraints.py                   | 2 +-
+ src/hb-config.hh                               | 8 ++++----
+ src/hb-ot-shape-complex-arabic-fallback.hh     | 6 +++---
+ src/hb-ot-shape-complex-arabic-joining-list.hh | 6 +++---
+ src/hb-ot-shape-complex-arabic-table.hh        | 6 +++---
+ src/hb-ot-shape-complex-arabic-win1256.hh      | 6 +++---
+ src/hb-ot-shape-complex-arabic.cc              | 2 +-
+ src/hb-ot-shape-complex-arabic.hh              | 6 +++---
+ src/hb-ot-shape-complex-hebrew.cc              | 2 +-
+ src/hb-ot-shape-complex-indic-machine.hh       | 6 +++---
+ src/hb-ot-shape-complex-indic-machine.rl       | 6 +++---
+ src/hb-ot-shape-complex-indic.hh               | 6 +++---
+ src/hb-ot-shape-complex-khmer-machine.hh       | 6 +++---
+ src/hb-ot-shape-complex-khmer-machine.rl       | 6 +++---
+ src/hb-ot-shape-complex-khmer.hh               | 6 +++---
+ src/hb-ot-shape-complex-myanmar-machine.hh     | 6 +++---
+ src/hb-ot-shape-complex-myanmar-machine.rl     | 6 +++---
+ src/hb-ot-shape-complex-myanmar.hh             | 6 +++---
+ src/hb-ot-shape-complex-syllabic.hh            | 6 +++---
+ src/hb-ot-shape-complex-thai.cc                | 2 +-
+ src/hb-ot-shape-complex-use-machine.hh         | 6 +++---
+ src/hb-ot-shape-complex-use-machine.rl         | 6 +++---
+ src/hb-ot-shape-complex-use-table.hh           | 6 +++---
+ src/hb-ot-shape-complex-vowel-constraints.cc   | 2 +-
+ src/hb-ot-shape-complex-vowel-constraints.hh   | 6 +++---
+ src/hb-ot-shape-complex.hh                     | 6 +++---
+ 29 files changed, 78 insertions(+), 78 deletions(-)
+
+commit 6fbb552156cc36e90ef25b0c6519a661bf76f597
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 02:50:25 2022 -0600
+
+    s/FLAG_COMPLEX/FLAG_SHAPER/g
+
+ src/hb-buffer.hh                  | 10 +++++-----
+ src/hb-ot-shape-complex-arabic.cc |  2 +-
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+commit 6d9e94d2b88915e6e672b0a937da3b89085b520a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 02:48:34 2022 -0600
+
+    s/hb_ot_shape_complex_categorize/hb_ot_shaper_categorize/g
+
+ src/hb-ot-shape-complex.hh | 2 +-
+ src/hb-ot-shape.cc         | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit a560182cb3b97d9484c6ab0697f99895c0109eb0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 02:46:58 2022 -0600
+
+    s/complex_var/ot_shaper_var/g
+
+ src/hb-ot-shape-complex-arabic.cc      | 2 +-
+ src/hb-ot-shape-complex-hangul.cc      | 2 +-
+ src/hb-ot-shape-complex-indic.hh       | 4 ++--
+ src/hb-ot-shape-complex-syllabic.cc    | 6 +++---
+ src/hb-ot-shape-complex-use-machine.hh | 2 +-
+ src/hb-ot-shape-complex-use-machine.rl | 2 +-
+ src/hb-ot-shape-complex.hh             | 6 +++---
+ 7 files changed, 12 insertions(+), 12 deletions(-)
+
+commit 13fbed29e484df26d51944b9e10d480449a9f0b1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 02:45:04 2022 -0600
+
+    s/HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS/HB_OT_SHAPE_MAX_COMBINING_MARKS/g
+
+ src/hb-ot-shape-complex-arabic.cc | 2 +-
+ src/hb-ot-shape-complex.hh        | 2 +-
+ src/hb-ot-shape-normalize.cc      | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+commit 44a7b3b773ad13bfa494aed266c7453996c41696
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 02:42:34 2022 -0600
+
+    s/ot_complex_shaper/ot_shaper/g
+
+ src/gen-vowel-constraints.py       |  2 +-
+ src/hb-ot-shape-complex-arabic.cc  |  2 +-
+ src/hb-ot-shape-complex-default.cc |  4 ++--
+ src/hb-ot-shape-complex-hangul.cc  |  2 +-
+ src/hb-ot-shape-complex-hebrew.cc  |  2 +-
+ src/hb-ot-shape-complex-indic.cc   |  2 +-
+ src/hb-ot-shape-complex-khmer.cc   |  2 +-
+ src/hb-ot-shape-complex-myanmar.cc |  4 ++--
+ src/hb-ot-shape-complex-thai.cc    |  2 +-
+ src/hb-ot-shape-complex-use.cc     |  2 +-
+ src/hb-ot-shape-complex.hh         | 36 ++++++++++++++++++------------------
+ src/hb-ot-shape.cc                 |  4 ++--
+ src/hb-ot-shape.hh                 |  4 ++--
+ 13 files changed, 34 insertions(+), 34 deletions(-)
+
+commit e5161977a40f2596af9d198565ccf2c4739300f9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 02:40:54 2022 -0600
+
+    s/COMPLEX_SHAPER/OT_SHAPER/g
+
+ src/hb-ot-shape-complex.hh | 30 +++++++++++++++---------------
+ 1 file changed, 15 insertions(+), 15 deletions(-)
+
+commit f3a8b7f36b29fa7a7c7946023cbdcb915e1d6cbf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 02:21:46 2022 -0600
+
+    [algs] Test hb_hash()
+
+ src/test-algs.cc | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+commit 7aacdd05bd4d6fa1305d6671521dd01d28b622c3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 02:10:06 2022 -0600
+
+    [cplusplus] Test hashing shared_ptr / unique_ptr
+
+ test/api/test-cplusplus.cc | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+commit 51ca1c9b59932899487f5c116cd33ce733929cfa
+Merge: 7ec3aad20 215a0afad
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 08:56:20 2022 +0100
+
+    Merge pull request #3626 from harfbuzz/fix-map
+    
+    Fix map
+
+commit 215a0afad19a43f88cb8fbeb51877997b40e2567
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 01:48:46 2022 -0600
+
+    [algs] Remove unused hb_coerce()
+
+ src/hb-algs.hh | 8 --------
+ 1 file changed, 8 deletions(-)
+
+commit 5dc12d7d8d7aeb3418870d2b3695ff10a53296f6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 01:37:02 2022 -0600
+
+    [cmap] Rewrite set_for() slightly
+
+ src/hb-ot-cmap-table.hh | 16 ++++++++++++----
+ 1 file changed, 12 insertions(+), 4 deletions(-)
+
+commit 9552955e081f3d871765055fd5abad9070cfcf90
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 01:33:01 2022 -0600
+
+    Add an unlikely
+
+ src/hb-ot-cmap-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 88f00ecb84a5f78dffabdfa5a8bdc2ed1d452ce4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 01:30:27 2022 -0600
+
+    [map] Fix iter_ref () and test it
+
+ src/hb-map.hh   | 4 ++--
+ src/test-map.cc | 2 ++
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+commit a42c624fcaa030a68c51acaf007caf402c8c262c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 01:22:34 2022 -0600
+
+    Convert one final use of hashmap to unique_ptr
+
+ src/hb-ot-layout-gsubgpos.hh | 16 +++-------------
+ 1 file changed, 3 insertions(+), 13 deletions(-)
+
+commit f13a79548fca34663ec3f0f86de6f2e742a09ab9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 01:17:20 2022 -0600
+
+    [subset] Convert another use of hashmap to unique_ptr
+
+ src/hb-ot-layout-common.hh   | 14 +++++---------
+ src/hb-ot-layout-gsubgpos.hh |  2 +-
+ src/hb-subset-plan.cc        |  8 +-------
+ src/hb-subset-plan.hh        |  4 ++--
+ 4 files changed, 9 insertions(+), 19 deletions(-)
+
+commit 25f57230d58524d9165a9b33d1666f84005617d5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jun 3 01:11:22 2022 -0600
+
+    [map] Return references from new iter_ref()
+
+ src/hb-map.hh | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+commit a7a688616ab348a66873df5577eec66a0f70206f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 18:59:15 2022 -0600
+
+    [cmap] Convert another map use to unique_ptr
+
+ src/hb-ot-cmap-table.hh | 13 ++-----------
+ 1 file changed, 2 insertions(+), 11 deletions(-)
+
+commit 997d9cc466abfb9031f46d1baef5a2cb3164f7cc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 18:04:12 2022 -0600
+
+    [map] Make unique_ptr hashable
+
+ src/hb-bimap.hh                  |  3 ++-
+ src/hb-map.hh                    | 24 ++++++++++++------------
+ src/hb-ot-color-cpal-table.hh    |  4 ++--
+ src/hb-ot-layout-common.hh       |  4 ++--
+ src/hb-ot-layout-gsubgpos.hh     |  7 +++----
+ src/hb-ot-layout.cc              |  4 ++--
+ src/hb-ot-post-table-v2subset.hh |  4 +++-
+ src/hb-repacker.hh               | 16 ++++++++--------
+ src/test-map.cc                  |  8 ++++++++
+ 9 files changed, 42 insertions(+), 32 deletions(-)
+
+commit 8bb2a3326e92d553b9bea7462574a2d44782cbfd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 15:18:23 2022 -0600
+
+    [map] Remove unneeded assignment
+
+ src/hb-map.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit d7785a6da0a5ced69203270a48a9a4da9e8f230a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 12:42:24 2022 -0600
+
+    [cplusplus] Add unique_ptr
+
+ src/hb-algs.hh             |  5 +++++
+ src/hb-cplusplus.hh        | 44 +++++++++++++++++++++++++++++++++++++++++++-
+ test/api/test-cplusplus.cc |  2 ++
+ 3 files changed, 50 insertions(+), 1 deletion(-)
+
+commit bca710e8ad2cccaa013e19a63c58899e45284df8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 12:06:25 2022 -0600
+
+    [gsubgpos] Use map has() instead of get() when appropriate
+
+ src/hb-ot-layout-gsubgpos.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e9407a2bd25f80d65559b6a869585033e2a08b24
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 11:29:44 2022 -0600
+
+    Use shared_ptr<hb_set_t> in one place
+    
+    See if valgrind is happy...
+
+ src/hb-map.hh                |  2 +-
+ src/hb-ot-layout-gsubgpos.hh |  9 +++------
+ src/hb-ot-layout.cc          | 10 ++--------
+ 3 files changed, 6 insertions(+), 15 deletions(-)
+
+commit a42a703cb62c84b2ed141e64570e1f1a2d74695e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 11:51:20 2022 -0600
+
+    [shared_ptr] Clear p in destructor
+
+ src/hb-cplusplus.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f0a0dcad703ca1db037687b4c59ce11668f38ca6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 11:25:56 2022 -0600
+
+    [test-map] Test hashing shared_ptr
+
+ src/test-map.cc | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+commit 4c1b5d9ece8b59eb5346a8eaeaad09dfeb8dfd7f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 11:25:11 2022 -0600
+
+    Whitespace
+
+ src/test-map.cc | 9 ---------
+ 1 file changed, 9 deletions(-)
+
+commit b9230c542558afac93f1fb6d7ca1442a06688d38
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 11:18:38 2022 -0600
+
+    [map] Fix has()
+
+ src/hb-map.hh | 21 +++++++++++++++++----
+ 1 file changed, 17 insertions(+), 4 deletions(-)
+
+commit 97ea10a63a0be388bfb02ae203c468533304bda0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 11:14:17 2022 -0600
+
+    Remove old nullptr_t hacks
+    
+    Were used for hashmap before.
+
+ src/hb-array.hh | 2 --
+ src/hb-map.hh   | 2 --
+ src/hb-set.hh   | 1 -
+ 3 files changed, 5 deletions(-)
+
+commit 3f78a71ca059b461f79d0ee64766c7c3f4327b14
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 11:11:35 2022 -0600
+
+    [map] Finally! Just can usd hb_hashmap_t<obj_t, obj_t>
+    
+    Yay!
+
+ src/hb-map.hh                    | 29 ++++++++++++++-------------
+ src/hb-ot-post-table-v2subset.hh |  2 +-
+ src/hb-serialize.hh              |  3 +--
+ src/test-map.cc                  | 43 ++++++++++------------------------------
+ 4 files changed, 27 insertions(+), 50 deletions(-)
+
+commit 0ccab339f98ab7af27b3ca0db8489ff836ca11f3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 10:43:36 2022 -0600
+
+    [map] Remove invalid-key template arguments since unused
+
+ src/hb-map.hh                    |  6 ------
+ src/hb-ot-post-table-v2subset.hh |  2 +-
+ src/hb-serialize.hh              |  3 +--
+ src/test-map.cc                  | 26 +++++++++++++-------------
+ 4 files changed, 15 insertions(+), 22 deletions(-)
+
+commit 3f6a8f69a099398ac397bb652e6d8332167f6538
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 10:36:07 2022 -0600
+
+    [map] Remove invalid-key special-casing
+    
+    Can override invalid-key value now.
+
+ src/hb-map.hh   |  3 ---
+ src/test-map.cc | 15 ++++++---------
+ 2 files changed, 6 insertions(+), 12 deletions(-)
+
+commit 5328b73fbaf5b952cf7eb23a7b4a228585502c10
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 10:32:56 2022 -0600
+
+    [map] Reduce map item size again
+
+ src/hb-map.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 4f58ae60eb781b9ade164c4ea2abad708d00f4ce
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 10:13:55 2022 -0600
+
+    [map] Keep is_used, is_tombstone as booleans
+
+ src/hb-map.hh | 44 ++++++++++++++++++++------------------------
+ 1 file changed, 20 insertions(+), 24 deletions(-)
+
+commit 7ec3aad20f04a51d7b3089374f3ea36b496eb8f5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 10:50:55 2022 -0600
+
+    [shared_ptr] Fix hb_hash() crash on nullptr
+
+ src/hb-algs.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4d646773cf0fddb648119fbf575fbe3e5b6ab9fc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 10:02:44 2022 -0600
+
+    [cplusplus] Make .reference() return T*
+
+ src/hb-cplusplus.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 7e7a4a8f05289552dbb217d20c4840efd43e31d2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 09:59:41 2022 -0600
+
+    [cplusplus] Fix build
+
+ src/hb-cplusplus.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit a089d91fda71e4c19c9c3c822abe86bbcd878dbc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 09:55:43 2022 -0600
+
+    [hash] Adjust hash for shared_ptr, implement it for std::hash
+
+ src/hb-algs.hh      | 12 ++++++------
+ src/hb-cplusplus.hh | 15 +++++++++++++--
+ 2 files changed, 19 insertions(+), 8 deletions(-)
+
+commit e037325efbfca23739e2b3265261c2528f52bae1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 08:51:12 2022 -0600
+
+    [hash] Remove custom hash, rely on std::hash
+
+ src/hb-algs.hh | 8 --------
+ 1 file changed, 8 deletions(-)
+
+commit 0d3d5b62ae9988695627db7f8b2d4fde044c8778
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 2 08:00:08 2022 -0600
+
+    [cplusplus] Adjustments
+
+ src/hb-cplusplus.hh | 8 +++++++-
+ src/test-map.cc     | 4 +++-
+ 2 files changed, 10 insertions(+), 2 deletions(-)
+
+commit 0b35940a72aaa4575e4dd1f8991abb037bc2a0ed
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 1 15:10:19 2022 -0600
+
+    Make hb::shared_ptr hashable
+
+ src/hb-algs.hh      | 16 +++++++++++-----
+ src/hb-cplusplus.hh |  1 +
+ src/test-map.cc     |  9 +++++++++
+ 3 files changed, 21 insertions(+), 5 deletions(-)
+
+commit 3817bdfd7f2747519024213aa0a26fdfdd27b293
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 1 12:35:03 2022 -0600
+
+    [hb.hh] Include hb-cplusplus.hh
+
+ src/hb.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit e0f3cab2466e3d47e16a18270b5026eae1daa807
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 1 11:51:43 2022 -0600
+
+    [cplusplus] Add hb-cplusplus.hh
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/2152
+
+ src/Makefile.sources       |   1 +
+ src/hb-cplusplus.hh        | 133 +++++++++++++++++++++++++++++++++++++++++++++
+ src/meson.build            |   1 +
+ src/test-map.cc            |   1 -
+ src/test-set.cc            |   2 -
+ test/api/test-c.c          |   2 +-
+ test/api/test-cplusplus.cc |  84 +++++++++++++++++++++++++++-
+ 7 files changed, 218 insertions(+), 6 deletions(-)
+
+commit 98aaecd3978c4389741789657d3fcacc8d1686d0
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jun 1 21:01:16 2022 +0000
+
+    [subset] fix data race touching Crap() in cff subsetting.
+
+ src/hb-ot-cff1-table.hh           | 3 ++-
+ src/hb-subset-cff-common.hh       | 3 ++-
+ test/threads/hb-subset-threads.cc | 2 +-
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+
+commit d8d96b26e74aa02aae6af96d35648981d5cea38d
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jun 1 19:55:02 2022 +0000
+
+    [threads-test] Add a threads test against hb-subset.
+
+ test/threads/Makefile.am          |   1 +
+ test/threads/hb-subset-threads.cc | 180 ++++++++++++++++++++++++++++++++++++++
+ test/threads/meson.build          |  15 ++++
+ 3 files changed, 196 insertions(+)
+
+commit 858570b1d9912a1b746ab39fbe62a646c4f7a5b1
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jun 1 18:08:09 2022 +0000
+
+    [subset] add some additional 32bit var store cases.
+    
+    Test the path where the 32 bit delta is not included.
+
+ .../32bit_var_store.notdef-outline-retain-gids.62.otf    | Bin 0 -> 3904 bytes
+ .../32bit_var_store.notdef-outline-retain-gids.63.otf    | Bin 0 -> 3828 bytes
+ .../32bit_var_store.notdef-outline-retain-gids.64.otf    | Bin 0 -> 3800 bytes
+ .../32bit_var_store.notdef-outline.62.otf                | Bin 0 -> 3892 bytes
+ .../32bit_var_store.notdef-outline.63.otf                | Bin 0 -> 3812 bytes
+ .../32bit_var_store.notdef-outline.64.otf                | Bin 0 -> 3780 bytes
+ test/subset/data/tests/32bit_var_store.tests             |   3 +++
+ 7 files changed, 3 insertions(+)
+
+commit 209d6aa2b789a757b2ead71e2a77d2e6c81f90c7
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jun 1 18:02:03 2022 +0000
+
+    [subset] Update make files for 32bit_var_store test.
+
+ test/subset/data/Makefile.am      | 1 +
+ test/subset/data/Makefile.sources | 1 +
+ test/subset/meson.build           | 1 +
+ 3 files changed, 3 insertions(+)
+
+commit 9c41bfe1a6119865dc94ff7142c7f8104063347c
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jun 1 17:53:14 2022 +0000
+
+    [subset] Add subset test of font with 32 bit delta in a var store.
+
+ ..._var_store.notdef-outline-retain-gids.61,62,63,64.otf | Bin 0 -> 5676 bytes
+ .../32bit_var_store.notdef-outline-retain-gids.61,62.otf | Bin 0 -> 4776 bytes
+ .../32bit_var_store.notdef-outline-retain-gids.61,63.otf | Bin 0 -> 4588 bytes
+ .../32bit_var_store.notdef-outline-retain-gids.61,64.otf | Bin 0 -> 4764 bytes
+ .../32bit_var_store.notdef-outline-retain-gids.61.otf    | Bin 0 -> 4128 bytes
+ .../32bit_var_store.notdef-outline.61,62,63,64.otf       | Bin 0 -> 5676 bytes
+ .../32bit_var_store.notdef-outline.61,62.otf             | Bin 0 -> 4776 bytes
+ .../32bit_var_store.notdef-outline.61,63.otf             | Bin 0 -> 4584 bytes
+ .../32bit_var_store.notdef-outline.61,64.otf             | Bin 0 -> 4744 bytes
+ .../32bit_var_store.notdef-outline.61.otf                | Bin 0 -> 4128 bytes
+ test/subset/data/fonts/32bit_var_store.otf               | Bin 0 -> 5664 bytes
+ test/subset/data/tests/32bit_var_store.tests             |  13 +++++++++++++
+ 12 files changed, 13 insertions(+)
+
+commit c88a6a9ec3c38793ec8b662362282e076e948943
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 1 09:46:41 2022 -0600
+
+    [face] Remove const from get_user_data prototype
+    
+    This was done by mistake.
+    
+    Since the returned user_data can be changed, face should not be marked
+    const. Other object types follow this parttern.
+
+ src/hb-face.cc | 2 +-
+ src/hb-face.h  | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit bc6ecaa2629d065583ffa86ebed4dcea53505f42
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 1 09:19:11 2022 -0600
+
+    [font-funcs] Handle case of null func but non-null destroy or user-data
+
+ src/hb-font.cc | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+commit 88ccbd2c4356b70107c212a81b5a99d08d2d3dd0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 1 08:44:07 2022 -0600
+
+    [font-funcs] Optimize user-data/destroy storage
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/2427
+
+ src/hb-font.cc | 74 ++++++++++++++++++++++++++++++++--------------------------
+ src/hb-font.hh | 40 +++++++++++++++----------------
+ 2 files changed, 61 insertions(+), 53 deletions(-)
+
+commit e421613e8f825508afa9a0b54d33085557c37441
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 1 09:07:57 2022 -0600
+
+    [sbix] Fix conditional
+
+ src/hb-ot-color-sbix-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 55b911d863a1aad9e0e00c1b91102f9614b56eec
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 1 08:13:06 2022 -0600
+
+    [buffer] Mark getter functions as taking const buffer
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/2873
+
+ src/hb-buffer.cc | 24 ++++++++++++------------
+ src/hb-buffer.h  | 24 ++++++++++++------------
+ 2 files changed, 24 insertions(+), 24 deletions(-)
+
+commit 18cd15bedefad709be80fd341549f46a1a8127bb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 1 07:55:59 2022 -0600
+
+    Rename test
+
+ test/threads/meson.build | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9e1479b5f041c48456aefeca93d3f885f84fb401
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 1 07:54:45 2022 -0600
+
+    [morx] Limit context length
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3097
+
+ src/hb-aat-layout-morx-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 62e803b36173fd096d7ad460dd1d1db9be542593
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 1 07:38:21 2022 -0600
+
+    [sbix] Limit glyph extents
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3557
+
+ src/hb-ot-color-sbix-table.hh       |   6 ++++++
+ test/fuzzing/fonts/sbix-extents.ttf | Bin 0 -> 582 bytes
+ 2 files changed, 6 insertions(+)
+
+commit cd05d187c893ad0bcf754393a865c417d5cff36d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 1 07:27:30 2022 -0600
+
+    [font] Fix undefined-behavior when scales are negative
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3555
+
+ src/hb-font.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit fc4d42ff99018f9f640d3191bcd621c547ed61ea
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 1 05:19:23 2022 -0600
+
+    [ft] Add API to notify that hb_font_t changed
+    
+    New API:
+    - hb_ft_hb_font_changed()
+    
+    Mostly reverts 56e0ff9ea129aa91dfcc746cd61f8cbbc427dba7
+    
+    Related https://github.com/harfbuzz/harfbuzz/issues/2270
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3619
+
+ src/hb-ft.cc | 54 +++++++++++++++++++++++++++++++++---------------------
+ src/hb-ft.h  |  9 ++++++++-
+ 2 files changed, 41 insertions(+), 22 deletions(-)
+
+commit a31fd97c356cc49f9d4539567861b07c20bd034a
+Merge: 9c0c31dfa e246723f0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 1 12:26:08 2022 +0100
+
+    Merge pull request #3432 from harfbuzz/fuzz-verify
+    
+    [fuzz-shape] Verify shape output
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3432
+
+commit e246723f0c796ec5207e1b64dd7a409cebb91d99
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 1 04:54:18 2022 -0600
+
+    [shape] Fail shaping internally if buffer ops exceeded
+
+ src/hb-buffer.cc   |  2 ++
+ src/hb-ot-shape.cc |  2 --
+ src/hb-shape.cc    | 10 +++++++++-
+ 3 files changed, 11 insertions(+), 3 deletions(-)
+
+commit 5a058ba15837be53d8835031a689c22e369531b2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 31 05:35:17 2022 -0600
+
+    [shape-fuzzer] Add commented out more buffer-verify option
+    
+    Those currently fail and I've been unable to debug them.
+    
+    I tried two, passing them to hb-shape doesn't reproduce the failure. :(
+
+ test/fuzzing/hb-shape-fuzzer.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 189f65344a9c34618ecc11af30591165f8ff24d0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 13 13:22:08 2022 -0600
+
+    [fuzz-shape] Verify shape output
+    
+    Let the fuzzers loose on shape verify.
+
+ test/fuzzing/hb-shape-fuzzer.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9c0c31dfaab3dd3b3debb2604fec580ca6fdfb62
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 31 09:35:49 2022 -0600
+
+    [buffer] When deleting glyphs, check cluster backwards as well
+
+ src/hb-buffer.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 0384f80e78e79cdce2bb6a9f9bb08550bf0b95c5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 31 08:23:48 2022 -0600
+
+    [buffer-verify] If shaping buffers failed during verification, pass the test
+
+ src/hb-buffer-verify.cc | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+commit eba626ff6a2cbf92ddff267633ba1b7e5cb9540c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 31 08:20:56 2022 -0600
+
+    [shape-plan] Return empty plan if buffer direction is invalid
+    
+    Happens if buffer creation failed.
+
+ src/hb-shape-plan.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit a441c6c16b8f8355ce58543ad95621455dcb0824
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 31 07:52:04 2022 -0600
+
+    [shape] Only verify if text_buffer is successful
+
+ src/hb-shape.cc | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit f7f61aeb6fa9a9c9e62727f215d6fa4e55ddb546
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 31 09:37:38 2022 -0600
+
+    [buffer] Add TODO item
+
+ src/hb-buffer.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit d72d37008d25d346b73a24087202bbf957733121
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 1 04:43:10 2022 -0600
+
+    [shape] Allow null buffer
+    
+    Ouch!
+
+ src/hb-shape.cc | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 33145a4b75c1b31f657c379444aaa9c946b8fd61
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 31 04:59:07 2022 -0600
+
+    [test/shape] Pass --unsafe-to-concat to hb-shape
+
+ test/shape/run-tests.py | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 45a2252607740ae1612b5c2b03437c62cc6d221f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 31 06:23:47 2022 -0600
+
+    [flags] Fix undefined-behavior
+    
+    SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior ../src/hb-buffer.hh:60:1 in
+    failure on clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5736539338833920
+
+ src/hb-algs.hh          |  2 +-
+ src/hb-buffer-verify.cc | 10 +++++-----
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+commit f3f9fc1544ba1a0d7d11dbd93d242f09b9349a0d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 31 06:05:57 2022 -0600
+
+    [buffer] Mark glyph_flags_t as flags
+
+ src/hb-buffer.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit ab143e85c377512365134c1904b8f9f668309438
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 31 06:00:41 2022 -0600
+
+    [buffer] Add HB_BUFFER_FLAG_DEFINED and HB_BUFFER_SERIALIZE_FLAG_DEFINED
+    
+    New API:
+    + HB_BUFFER_FLAG_DEFINED
+    + HB_BUFFER_SERIALIZE_FLAG_DEFINED
+
+ src/hb-buffer.h | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+commit 9a2a857043598fbc6826753e543e0a0c058dff35
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 31 04:25:20 2022 -0600
+
+    [ot-shape] Don't verify buffer if shaping failed
+    
+    Fixes all of fuzzing verify failures, which were result of buffer failure
+    on super-long results, which fails unsafe-to-break because shorter strings
+    don't fail shaping.
+
+ src/hb-buffer.cc             | 2 ++
+ src/hb-buffer.hh             | 1 +
+ src/hb-ot-layout-gsubgpos.hh | 3 +++
+ src/hb-shape.cc              | 4 +++-
+ 4 files changed, 9 insertions(+), 1 deletion(-)
+
+commit f8b26f43ece70d7b63f3d844db8059f682bdc50b
+Merge: 6dd7e31f7 5af5a5659
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 31 11:22:32 2022 +0100
+
+    Merge pull request #3606 from harfbuzz/32bit-varstore
+    
+    32bit varstore
+
+commit 6dd7e31f71e6c8aa9200f9af585c594db548e2fd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 31 04:09:06 2022 -0600
+
+    [util] Accept | as delimiter in Unicode parsing
+
+ util/text-options.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 5af5a565938505a4a549a5cee49b62ee03d73a18
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 30 08:32:50 2022 -0600
+
+    [VarStore] Implement writing 32bit var-store
+    
+    Untested.
+    
+    Finishes fixing https://github.com/harfbuzz/harfbuzz/issues/2965
+
+ src/hb-ot-layout-common.hh | 49 +++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 35 insertions(+), 14 deletions(-)
+
+commit 75112098ac3141416e8502779bf004cc5f7325a8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 23 12:42:15 2022 -0600
+
+    [VarStore] Implement reading 32bit var-store
+    
+    Untested.
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/2965
+    
+    Serializing is incomplete.
+
+ src/hb-ot-layout-common.hh | 68 ++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 53 insertions(+), 15 deletions(-)
+
+commit 334bd013d9c27907112df1b51da1431900fe288f
+Author: Xavier Claessens <xavier.claessens@collabora.com>
+Date:   Mon May 30 11:46:08 2022 -0400
+
+    Skip warning when building as subproject and  ragel is missing
+    
+    It is unlikely to be a developer build in that case.
+
+ src/meson.build | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit e5d6da79052d2ccabf423959f850ea90a9af7e6b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 23 12:25:39 2022 -0600
+
+    [varStore] rename shortCount to wordCount
+
+ src/hb-ot-layout-common.hh | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+commit d11455f2851dcf26c1300d88d12991d0988f115e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 30 06:59:03 2022 -0600
+
+    [blob] Fix strncpy() use in Mac resource opening code
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3616
+
+ src/hb-blob.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9eab6d326fc09d8957e082fb363cbe03b15feee0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 26 12:00:45 2022 -0600
+
+    [benchmark-set] Another Pause/Resume
+
+ perf/benchmark-set.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit ea2dd54b68db49adb05266ec18414b2bbc20af0f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 26 11:31:28 2022 -0600
+
+    [map] Place item hash between key and value, not after them
+    
+    This way if only one of key and value is 64bit (eg. pointer), and other is 32bit,
+    the whole item will fit in 128bit, whereas before it would have been bumped up to
+    196 if only value was 64bit (a common use-case for us.)
+
+ src/hb-map.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ec6cefc46acec92322d08bf60ccd7585aac890bf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 26 11:26:37 2022 -0600
+
+    [repacker] Simplify map types
+
+ src/hb-repacker.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit cbcdf442c505b1461ef9591d1eedd849237a279b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 26 11:20:27 2022 -0600
+
+    [map] Speed up map's own hash()
+
+ src/hb-map.hh | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+commit de33ef61b7f8ce231bad8aa0e644142e2c23a633
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 26 11:07:21 2022 -0600
+
+    [map] Add TODO item
+
+ src/hb-map.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit fc5739ea901804f6b2eca643c8b30c5e1af4a2e5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 26 11:04:52 2022 -0600
+
+    [test-map] Whitespace
+
+ src/test-map.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 3e64abd5d6515d3f77b5bd3ca185c9161d5e3e17
+Merge: efa4385b1 b010962c3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 30 05:52:21 2022 -0600
+
+    Merge pull request #3613 from harfbuzz/threads-test
+    
+    Threads test
+
+commit efa4385b16a6f8881aaf40d4be1a4e894f8ee4c8
+Merge: f4a8b7001 342751198
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 30 05:40:56 2022 -0600
+
+    Merge pull request #3615 from harfbuzz/gir-freetype
+    
+    [gi] Add freetype2-2.0 for g-i-r includes
+
+commit b010962c3b9901e9b7a68d20c2ab5acb1653c925
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 30 05:34:25 2022 -0600
+
+    [test/hb-shape-threads] Silence hb_language_get_default() threadysafety issue
+
+ test/threads/hb-shape-threads.cc | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit f4a8b70016fa24cba8bee20f4aca0e2dd5a11c5c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 30 05:30:37 2022 -0600
+
+    More member initialization
+
+ src/hb-ot-layout-gsubgpos.hh | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+commit 4e59900ff5c14e09dd329bb42b5a7a566ad46d45
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 30 05:21:55 2022 -0600
+
+    [test/hb-shape-threads] Share font amongst threads
+
+ test/threads/hb-shape-threads.cc | 70 ++++++++++++++++++++--------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
+
+commit 18b0bd0f5ff1d614ba8253b76619728d0aa28c6c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 30 05:12:12 2022 -0600
+
+    [test/hb-shape-threads] Verify buffer
+
+ test/threads/hb-shape-threads.cc | 1 +
+ test/threads/meson.build         | 2 +-
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+commit 484cc18732700aad614695aba271f70728bbebf9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 30 05:06:43 2022 -0600
+
+    [test-shape-threads] Set language
+
+ src/hb.hh                        | 1 -
+ test/threads/hb-shape-threads.cc | 5 +++++
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+commit f371789b40af052a33ad348b722a5c27f14b4c02
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat May 28 04:02:36 2022 -0600
+
+    Sprinkle static around
+
+ perf/benchmark-font.cc           | 4 ++--
+ perf/benchmark-shape.cc          | 4 ++--
+ test/threads/hb-shape-threads.cc | 8 ++++----
+ 3 files changed, 8 insertions(+), 8 deletions(-)
+
+commit 4386626ee072c5c8a7791040b041fac66f1b5dc0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 27 17:32:32 2022 -0600
+
+    [test/threads] Fix dependency
+
+ test/threads/meson.build | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit bf4b11cfa42f4f5906df412ed1ce0a93bc6b3ee9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 27 17:20:36 2022 -0600
+
+    [configure] Another try at fixing distcheck
+
+ configure.ac | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit e0544c481d6f218ebc04772e8e91c81a7cb8587c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 27 17:10:07 2022 -0600
+
+    [test/threads] Fix distcheck
+
+ test/Makefile.am         |  2 +-
+ test/threads/Makefile.am | 16 ++++++++++++++++
+ 2 files changed, 17 insertions(+), 1 deletion(-)
+
+commit e3d5a117a3e0f795a038b8e2c167399b4b662168
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 27 17:05:23 2022 -0600
+
+    [hb-shape-threads] Fix tsan race
+
+ test/threads/hb-shape-threads.cc | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit 33c990f0a9e3c0541f3673dfb4308153ff96decd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 27 16:57:00 2022 -0600
+
+    Include cassert to fix bots
+
+ perf/benchmark-font.cc           | 1 +
+ perf/benchmark-map.cc            | 1 +
+ perf/benchmark-set.cc            | 1 +
+ perf/benchmark-shape.cc          | 2 ++
+ perf/benchmark-subset.cc         | 1 +
+ test/threads/hb-shape-threads.cc | 1 +
+ 6 files changed, 7 insertions(+)
+
+commit 049af186840bf376c32b9cf786979c9f522afc6d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 27 16:53:25 2022 -0600
+
+    [threads] Add suite to test
+
+ test/threads/meson.build | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 87453f63faa710d46d3473d6c5419558d8b093fb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 27 16:51:12 2022 -0600
+
+    [hb-shape-threads] Fix current-work-dir so test passes
+
+ test/threads/meson.build | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit f77faf865480e049fbaf4ee2cf1f045870378836
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 27 16:34:28 2022 -0600
+
+    [hb-shape-threads] Allow overriding test parameters from cmdline
+
+ test/threads/hb-shape-threads.cc | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+commit f0fba59969d13a8639de3660007f720b00411a6c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 27 16:30:19 2022 -0600
+
+    [hb-shape-threads] Reduce num-iterations
+
+ test/threads/hb-shape-threads.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e8a2436332a38d2b69d54d0c39f55410d332780a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 27 16:29:17 2022 -0600
+
+    [threads] Add a condition_variable to test for all threads to be ready
+
+ test/threads/hb-shape-threads.cc | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+commit 4d42a94c19db547086d7d60cfcef548c018e5cbc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 27 16:23:12 2022 -0600
+
+    [threads] Add hb-shape-threads test
+
+ test/meson.build                 |   1 +
+ test/threads/hb-shape-threads.cc | 185 +++++++++++++++++++++++++++++++++++++++
+ test/threads/meson.build         |   9 ++
+ 3 files changed, 195 insertions(+)
+
+commit 315ef83b4eae5fe7792df8c3959656fd7c3c0c5e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 30 05:09:26 2022 -0600
+
+    Revert "Revert "[ot-lang] Use atomic int for cache""
+    
+    This reverts commit c56ce8681c209abd147328142806769752091b1c.
+    
+    The revert was not intentional. Ouch!
+
+ src/hb-ot-tag.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 34275119887bdf12d4f6ea87fcd55df34089f184
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon May 30 04:46:02 2022 +0200
+
+    [gi] Add freetype2-2.0 for g-i-r includes
+    
+    Fixes the warnings:
+    ../src/hb-ft.cc:810: Warning: HarfBuzz: hb_ft_face_create: argument ft_face: Unresolved type: 'FT_Face'
+    ../src/hb-ft.cc:886: Warning: HarfBuzz: hb_ft_face_create_cached: argument ft_face: Unresolved type: 'FT_Face'
+    ../src/hb-ft.cc:855: Warning: HarfBuzz: hb_ft_face_create_referenced: argument ft_face: Unresolved type: 'FT_Face'
+    ../src/hb-ft.cc:920: Warning: HarfBuzz: hb_ft_font_create: argument ft_face: Unresolved type: 'FT_Face'
+    ../src/hb-ft.cc:1029: Warning: HarfBuzz: hb_ft_font_create_referenced: argument ft_face: Unresolved type: 'FT_Face'
+    ../src/hb-ft.cc:240: Warning: HarfBuzz: hb_ft_font_get_face: return value: Unresolved type: 'FT_Face'
+    ../src/hb-ft.cc:262: Warning: HarfBuzz: hb_ft_font_lock_face: return value: Unresolved type: 'FT_Face'
+
+ src/Makefile.am | 2 +-
+ src/meson.build | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 97aa1ce6ba7e5a1d2816600449b5b5406e618abb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun May 29 10:32:59 2022 -0600
+
+    [gsubgpos] Move some member initialization
+
+ src/hb-ot-layout-gsubgpos.hh | 33 ++++++++++-----------------------
+ 1 file changed, 10 insertions(+), 23 deletions(-)
+
+commit 0bb4c1f021b0c9d0985e61e9596757e57298f144
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun May 29 10:23:19 2022 -0600
+
+    [cache] Set default values for cache template parameters
+
+ src/hb-cache.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3957d2927d670d176ca90ec7a7aa6e86822fbec3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun May 29 07:30:58 2022 -0600
+
+    [layout] Remove stale comment
+
+ src/hb-ot-layout.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b6fed6f7116b258c6bd76024064a0d856d3ccd97
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun May 29 06:33:34 2022 -0600
+
+    [set-digest] Minor don't use !! when auto bool conversion happens
+
+ src/hb-set-digest.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 371e14d99c6c84e11d71957c55b536530db1e415
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat May 28 13:40:30 2022 -0600
+
+    Combine uses of map has() then get() with has(.., &..)
+
+ src/hb-ot-color-cpal-table.hh    |  5 +++--
+ src/hb-ot-layout-common.hh       |  3 ++-
+ src/hb-ot-post-table-v2subset.hh |  3 +--
+ src/hb-repacker.hh               | 18 +++++++++++-------
+ 4 files changed, 17 insertions(+), 12 deletions(-)
+
+commit b99efa6c8dcfe7ea2c0804a77fbb6a485d38e664
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat May 28 05:16:34 2022 -0600
+
+    [map] Minor: use const reference in has()
+
+ src/hb-map.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 24d5a11dcb767d1c24fbdbd6d6779422e36ee794
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat May 28 05:14:16 2022 -0600
+
+    [bimap] Add unlikely and minor optimization in is_empty()
+
+ src/hb-bimap.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit c56ce8681c209abd147328142806769752091b1c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat May 28 04:25:51 2022 -0600
+
+    Revert "[ot-lang] Use atomic int for cache"
+    
+    This reverts commit d61b2074915cf5f8044dcb8e3dafc04b5b58c6b8.
+
+ src/hb-ot-tag.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 63bc6be0cf7151dfbd7a004f5b644e802c2ff6ca
+Merge: e2aa29907 a719e6788
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 27 08:25:22 2022 -0600
+
+    Merge pull request #3603 from harfbuzz/font-serial
+    
+    Add font serial API
+
+commit e2aa29907dd172fdd779fe34b4ecd9893eac3391
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 27 07:06:02 2022 -0600
+
+    [set] Use relaxed atomic ops for last_page_index
+    
+    Since iterating a set from multiple threads is supported.
+
+ src/hb-bit-set.hh | 32 ++++++++++++++++----------------
+ 1 file changed, 16 insertions(+), 16 deletions(-)
+
+commit d61b2074915cf5f8044dcb8e3dafc04b5b58c6b8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 26 18:24:43 2022 -0600
+
+    [ot-lang] Use atomic int for cache
+    
+    Fixes(?) https://github.com/harfbuzz/harfbuzz/issues/3612
+
+ src/hb-ot-tag.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 67bd147c73b3b01a62dd010f8081129b9ddb1ef5
+Merge: 0fe186922 e00c7358a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 26 05:16:07 2022 -0600
+
+    Merge pull request #3610 from googlefonts/subset_create_tables_face
+    
+    [subset] fix subsetting of faces created via hb_face_create_for_tables.
+
+commit a719e67887ccd5659aab0ba1fc6ff819795f7aa7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 24 17:51:24 2022 -0600
+
+    [ot-font] Use atomic ops for cache serial number
+    
+    This guarantees the cache is coherent.
+
+ src/hb-ot-font.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 5248b2567b9f627097ad25afd9671da9c9997224
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 24 13:55:17 2022 -0600
+
+    [ot-font/h-advance] Adjust varStore cache condition
+    
+    This gives best performance for short strings, now that we have a h-advance cache as well.
+    The en-words benchmark in particular, now ot-font is faster than ft.
+    
+    Second to last line is of interest:
+    
+    Before:
+    -----------------------------------------------------------------------------------------------------
+    Benchmark                                                           Time             CPU   Iterations
+    -----------------------------------------------------------------------------------------------------
+    BM_Shape/en-words.txt/Roboto-Regular.ttf/hb                      29.8 ms         29.8 ms           23
+    BM_Shape/en-words.txt/Roboto-Regular.ttf/ft                      30.4 ms         30.4 ms           23
+    BM_Shape/en-words.txt/SourceSerifVariable-Roman.ttf/hb           16.3 ms         16.3 ms           43
+    BM_Shape/en-words.txt/SourceSerifVariable-Roman.ttf/ft           16.5 ms         16.5 ms           42
+    BM_Shape/en-words.txt/SourceSerifVariable-Roman.ttf/var/hb       18.0 ms         18.0 ms           39
+    BM_Shape/en-words.txt/SourceSerifVariable-Roman.ttf/var/ft       17.8 ms         17.8 ms           39
+    
+    After:
+    behdad@Behdads-MacBook-Pro harfbuzz % ninja -Cbuild && build/perf/benchmark-shape --benchmark_filter=en-words
+    -----------------------------------------------------------------------------------------------------
+    Benchmark                                                           Time             CPU   Iterations
+    -----------------------------------------------------------------------------------------------------
+    BM_Shape/en-words.txt/Roboto-Regular.ttf/hb                      30.0 ms         30.0 ms           23
+    BM_Shape/en-words.txt/Roboto-Regular.ttf/ft                      30.3 ms         30.3 ms           23
+    BM_Shape/en-words.txt/SourceSerifVariable-Roman.ttf/hb           16.3 ms         16.3 ms           43
+    BM_Shape/en-words.txt/SourceSerifVariable-Roman.ttf/ft           16.4 ms         16.4 ms           43
+    BM_Shape/en-words.txt/SourceSerifVariable-Roman.ttf/var/hb       17.6 ms         17.6 ms           40
+    BM_Shape/en-words.txt/SourceSerifVariable-Roman.ttf/var/ft       17.8 ms         17.8 ms           39
+
+ src/hb-ot-font.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 12fff976b6cc4433dd3ed6aa7cf852031f7bd289
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 24 13:42:25 2022 -0600
+
+    [ot-var] Use atomic int for cached-serial
+
+ src/hb-ot-font.cc | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 0919eaa6e84c4de9d9fbaab8938474295a480892
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 24 13:07:24 2022 -0600
+
+    [ot-font] Remove lock around cache
+    
+    Not needed.
+
+ src/hb-ot-cff1-table.hh |  6 +++---
+ src/hb-ot-font.cc       | 46 +++++++++++++++++++++++++---------------------
+ 2 files changed, 28 insertions(+), 24 deletions(-)
+
+commit 3548b6025fb53fd287910642cd52b12991e82d2d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 23 19:39:52 2022 -0600
+
+    [ot-font] Cache h-advances for variable fonts
+
+ src/hb-ot-font.cc | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 89 insertions(+), 8 deletions(-)
+
+commit 39a07bf3eba74ab91827cb43b98127ae85f781e2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 23 19:13:05 2022 -0600
+
+    [ot-font] Rename cache to varStore_cache
+
+ src/hb-ot-font.cc | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+commit 970e03ecaebdc5cf5120ec80cb6716dd9bd40e52
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 23 19:02:36 2022 -0600
+
+    [ot-font] Add a hb_ot_font_t struct
+
+ src/hb-ot-font.cc | 41 +++++++++++++++++++++++++++++++----------
+ 1 file changed, 31 insertions(+), 10 deletions(-)
+
+commit 80c49933c6dead0ebb6678eece7520e22552e6c8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 23 19:02:27 2022 -0600
+
+    [hb-ft] Adjust serial signature
+
+ src/hb-ft.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 56e0ff9ea129aa91dfcc746cd61f8cbbc427dba7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 20 12:30:46 2022 -0600
+
+    [ft] If hb_font changed, update FT_Face
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/2270
+    
+    Rather untested.
+
+ src/hb-ft.cc | 100 +++++++++++++++++++++++++++++++++++++++--------------------
+ 1 file changed, 67 insertions(+), 33 deletions(-)
+
+commit d0de389de8f65f39ae97bb8b359d4b05cabd12b4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 20 12:18:43 2022 -0600
+
+    [font] Fix test
+
+ src/hb-font.cc | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+commit a2015cd300282b05d7082fbdbdf1c0a93a8993fb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 20 12:15:00 2022 -0600
+
+    [font] Add a separate serial_coords
+
+ src/hb-font.cc | 11 ++++++-----
+ src/hb-font.h  |  2 +-
+ src/hb-font.hh |  3 ++-
+ 3 files changed, 9 insertions(+), 7 deletions(-)
+
+commit 8629df188ad1a8563c2118de2cde983bdac4ecdd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 20 12:06:22 2022 -0600
+
+    [ft] Discard advance cache if font changed
+    
+    Uses newly added font serial API.
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/2270
+    
+    But doesn't set new coords on the FT_Face. That's a lot more
+    work :(.
+
+ src/hb-ft.cc | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 48db1c958323cd1739a1e6fe8f6dfd625db7ad5d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 20 12:03:32 2022 -0600
+
+    [font] Add serial API
+    
+    New API:
+    + hb_font_get_serial()
+    + hb_font_changed()
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/2426
+    
+    Unused internally as of now.
+
+ docs/harfbuzz-sections.txt |  2 ++
+ src/hb-font.cc             | 88 ++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-font.h              |  6 ++++
+ src/hb-font.hh             |  1 +
+ 4 files changed, 97 insertions(+)
+
+commit 0fe18692286257df06f9af3fe8317edd4e7308dd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 24 17:49:15 2022 -0600
+
+    [benchmark-set] Pause timing around set copy initialization
+
+ perf/benchmark-set.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit ce5435a862cd6078e86698073186652af8639aa4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 24 16:34:04 2022 -0600
+
+    [benchmark-set] Remove use of rand() inside benchmark
+
+ perf/benchmark-set.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit efa2a5796ef06fd035bd58a573c249f90a141ead
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 24 16:24:00 2022 -0600
+
+    [map] Add hb_map_copy()
+    
+    New API:
+    + hb_map_copy()
+
+ docs/harfbuzz-sections.txt |  1 +
+ src/hb-map.cc              | 19 +++++++++++++++++++
+ src/hb-map.h               |  3 +++
+ src/hb-set.cc              |  1 +
+ 4 files changed, 24 insertions(+)
+
+commit 3b28cff9c078d9a29b611a2b7fe014b8e4168762
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 26 04:42:17 2022 -0600
+
+    [cff1] Fix null dereference on memory alloc failure
+
+ src/hb-ot-cff1-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 8df9aba99774c39839d05231c5ee7e38a2614663
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 26 03:59:21 2022 -0600
+
+    Actually try to fix null-size undefined behavior
+    
+    Related to:
+    https://github.com/harfbuzz/harfbuzz/pull/2067
+    https://bugzilla.mozilla.org/show_bug.cgi?id=1577584
+
+ src/hb-null.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit e00c7358a0bb953d028b167911e557acdbaeb485
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed May 25 22:35:23 2022 +0000
+
+    [subset] special case table presence check for hb_face_create_from_tables faces.
+
+ src/hb-subset.cc | 16 ++++++++++++----
+ 1 file changed, 12 insertions(+), 4 deletions(-)
+
+commit 6a149a09e73cfb26cd375ad8a5fcc1e2f3b7d75c
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed May 25 22:22:35 2022 +0000
+
+    [subset] fix use of lazy static constructor.
+
+ src/hb-subset.cc | 119 ++++++++++++++++++++++++++++---------------------------
+ 1 file changed, 60 insertions(+), 59 deletions(-)
+
+commit d4c7939eb7483d818671f60033ff4e09eaea9816
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed May 25 22:11:32 2022 +0000
+
+    [subset] use a list of known tables instead of handled tables.
+
+ src/hb-subset.cc | 69 +++++++++++++++++++++++++++++++++++++-------------------
+ 1 file changed, 46 insertions(+), 23 deletions(-)
+
+commit 3472f73b79e3bd257507df29958b1c6145fb8bb5
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed May 25 21:49:12 2022 +0000
+
+    [subset] also include no subset tables when guessing which tables are present.
+
+ src/hb-subset.cc       | 112 ++++++++++++++++++++++++-------------------------
+ test/api/test-subset.c |   1 +
+ 2 files changed, 57 insertions(+), 56 deletions(-)
+
+commit 9564d987390a8437e2d077432629899a7bcd6d0f
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed May 25 21:16:37 2022 +0000
+
+    [subset] fix subsetting of faces created via hb_face_create_for_tables.
+    
+    Fixes #3609.
+
+ src/hb-subset.cc       | 83 ++++++++++++++++++++++++++++++++++++++++++++++++--
+ test/api/test-subset.c | 36 ++++++++++++++++++++++
+ 2 files changed, 117 insertions(+), 2 deletions(-)
+
+commit 6010feeeb543d5944c4d112571a94ea99807aca9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 24 09:00:44 2022 -0600
+
+    [varStore] Rename variable as per review
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3605
+
+ src/hb-ot-layout-common.hh | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit 89939c9cc372344196d5b32ed01c5cfa2a920b83
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue May 24 03:29:23 2022 +0200
+
+    [ci] Fix fedora-valgrind job
+    
+    Fedora 33 is EOL since 2021-11-30, try the latest Fedora release (36).
+
+ .circleci/config.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 8a7cfe17874b19afbba0378f1ace9bd21aab46ba
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 23 14:36:06 2022 -0600
+
+    [perf/benchmark-shape] Test ft font backend as well
+
+ perf/benchmark-shape.cc | 64 +++++++++++++++++++++++++++++++++++++++----------
+ perf/meson.build        |  2 +-
+ 2 files changed, 52 insertions(+), 14 deletions(-)
+
+commit d473397831fafa216a1658de830dc0178ec0fab3
+Merge: e1f4445df 3eb7eff48
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 23 12:24:38 2022 -0600
+
+    Merge pull request #3605 from harfbuzz/cache-varstore
+    
+    Cache varstore
+    https://github.com/harfbuzz/harfbuzz/pull/3605
+
+commit 3eb7eff487f5aa3abaf5f7e1e40f96cb1de1c364
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat May 21 15:25:53 2022 -0600
+
+    Remove varstore cache use if HB_NO_VAR
+
+ src/hb-ot-font.cc            | 12 ++++++++++++
+ src/hb-ot-layout-gsubgpos.hh | 15 +++++++++++++--
+ 2 files changed, 25 insertions(+), 2 deletions(-)
+
+commit 099482a37ad51d3dec5e762ab9f1d7dd3d3bb6a3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat May 21 15:20:23 2022 -0600
+
+    [ot-font] Cache v_advance varstore as well
+
+ src/hb-ot-font.cc | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+commit d9acc045f1651db5ffb42fe38ff2e2895199be87
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat May 21 14:16:21 2022 -0600
+
+    [VarStore] Sprinkle cache_t type around
+    
+    It's available so no need to use void*.
+
+ src/hb-ot-layout-common.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit da38312e4201185621b440faf8faf57084a38e7f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 20 17:32:56 2022 -0600
+
+    [VarStore] Pepper cache with likely()
+
+ src/hb-ot-layout-common.hh | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+commit cf8f00e3548c4e4eb8dca7da598bfe9990b53dd3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 20 17:14:10 2022 -0600
+
+    [VarStore] Don't use NAN
+    
+    Is faster.
+    
+    With this, I'm seeing 25 to 28% speedup in glyph_h_advances benchmark
+    of benchmark-font for var/hb tests.
+
+ src/hb-ot-layout-common.hh | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+commit 5336ba70f6fc995858881c2e4339e035b16c70a0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 20 17:03:18 2022 -0600
+
+    [HVAR] Cache VarStore region scalars
+
+ src/hb-ot-font.cc           |  8 +++++++-
+ src/hb-ot-hmtx-table.hh     |  9 +++++----
+ src/hb-ot-var-hvar-table.hh | 11 ++++++++---
+ 3 files changed, 20 insertions(+), 8 deletions(-)
+
+commit 880f50f7e423858209c490acab13328ca475a89c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 20 16:50:00 2022 -0600
+
+    Refactor varstore cache
+
+ src/hb-ot-layout-common.hh     | 63 +++++++++++++++++++++++++++---------------
+ src/hb-ot-layout-gpos-table.hh |  6 ++--
+ src/hb-ot-layout-gsubgpos.hh   | 19 +++++--------
+ 3 files changed, 50 insertions(+), 38 deletions(-)
+
+commit f2a2fb91a34cde23448eadd11a0fbc294153fcf5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 20 16:06:05 2022 -0600
+
+    [GPOS] Cache VarStore region scalars
+
+ src/hb-ot-layout-common.hh     |  2 ++
+ src/hb-ot-layout-gpos-table.hh | 13 +++++++------
+ src/hb-ot-layout-gsubgpos.hh   | 12 +++++++++++-
+ 3 files changed, 20 insertions(+), 7 deletions(-)
+
+commit 5fbc70c59b2d867e2142dba821802e2f26237c81
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 20 14:07:27 2022 -0600
+
+    [VarStore] Add cache API
+
+ src/hb-ot-layout-common.hh | 67 +++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 49 insertions(+), 18 deletions(-)
+
+commit e1f4445dff20a221287ad7b4c0140d03fe077866
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat May 21 15:11:53 2022 -0600
+
+    [benchmark-shape] Allow taking multiple tests from cmdline
+
+ perf/benchmark-shape.cc | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+commit 1bf2d5f885ea9c38025970f1587af6ba905acf76
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat May 21 14:42:50 2022 -0600
+
+    [perf/benchmark-shape] Allow taking text-file/font-file args from cmdline
+
+ perf/benchmark-font.cc  |  5 ++++-
+ perf/benchmark-shape.cc | 32 +++++++++++++++++++++++++++-----
+ 2 files changed, 31 insertions(+), 6 deletions(-)
+
+commit 852a8f04ebbd928333b69ea1f29a268e119910f7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat May 21 14:31:09 2022 -0600
+
+    [perf/benchmark-font] Allow benchmarking fonts specified on cmdline
+
+ perf/benchmark-font.cc | 25 +++++++++++++++++++++----
+ 1 file changed, 21 insertions(+), 4 deletions(-)
+
+commit 05e82aa12e8b85d7eaa31f7d25beb6bfd4c147ed
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 20 12:17:31 2022 -0600
+
+    [ft] Add missing lock to kerning function
+
+ src/hb-ft.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit da4b6f1527002d5e88b5556fb269e8434fd22598
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 20 17:21:04 2022 -0600
+
+    [benchmark-shape] Add variable fonts
+
+ perf/benchmark-shape.cc | 53 ++++++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 41 insertions(+), 12 deletions(-)
+
+commit 4ea2725704ae7e4d345b036ca2f574330233f00d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 20 13:19:27 2022 -0600
+
+    [set/map] Expose hash API publicly
+    
+    New API:
+    + hb_set_hash()
+    + hb_map_hash()
+
+ docs/harfbuzz-sections.txt |  2 ++
+ src/hb-map.cc              | 17 +++++++++++++++++
+ src/hb-map.h               |  3 +++
+ src/hb-set.cc              | 17 +++++++++++++++++
+ src/hb-set.h               |  3 +++
+ 5 files changed, 42 insertions(+)
+
+commit 2e186d9f2412ec858d94f7a8084b2fd7d3483449
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 20 13:15:52 2022 -0600
+
+    [buffer] Improve hash function of segment_properties_t
+
+ src/hb-buffer.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit aee123fc83388b8f5acfb301d87bd92eccc5b843
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri May 20 21:07:25 2022 +0200
+
+    4.3.0
+
+ NEWS                   | 17 +++++++++++++++++
+ configure.ac           |  2 +-
+ docs/harfbuzz-docs.xml |  1 +
+ meson.build            |  2 +-
+ src/hb-map.cc          |  2 +-
+ src/hb-version.h       |  6 +++---
+ 6 files changed, 24 insertions(+), 6 deletions(-)
+
+commit 975a5f919467c9bc4cad1340ebf07ae32bf07e14
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 20 12:34:49 2022 -0600
+
+    [array] Use hb_memcmp instead of memcmp
+    
+    Fixes ubsan error.
+
+ src/hb-array.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 55804e8d68af0685867d20a1796b952c6ff8db60
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 20 11:40:44 2022 -0600
+
+    [hb-ft] Minor rearrange of struct members
+    
+    To make clear what members the lock protects.
+
+ src/hb-ft.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 4e11da054d2c527fa64b33d49b33e3aa6b49077c
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri May 20 01:42:34 2022 +0000
+
+    [repacker] update repacker test golden file.
+    
+    Changed due to removal of Kahn sorting.
+
+ test/api/fonts/repacker_expected.otf | Bin 1400 -> 1400 bytes
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+
+commit cbf8f44c9b6de43387c61fdd43cf6bf0b89c3c08
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu May 19 21:25:21 2022 +0000
+
+    [subset-perf] swap instead of copying vertice's when reordering during sort.
+
+ src/hb-repacker.hh  | 22 ++++++++++++++++------
+ src/hb-serialize.hh | 11 ++++++++++-
+ 2 files changed, 26 insertions(+), 7 deletions(-)
+
+commit b32ca2a292f256a40e445990f104f09c5920d0bd
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu May 19 20:45:39 2022 +0000
+
+    [subset-perf] remove sort_kahn from repacker.
+    
+    Without an optimized FIFO queue implementation it's nearly as slow as the now optimized sort_shortest_distance.
+
+ src/hb-repacker.hh   | 53 ---------------------------------
+ src/test-repacker.cc | 84 ----------------------------------------------------
+ 2 files changed, 137 deletions(-)
+
+commit 4266cf3be266aef27a5d60530860915c68ba03e1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 18:15:46 2022 -0600
+
+    [array] Specialize operator== for bytes_t and ubytes_t
+
+ src/hb-array.hh | 17 +++++++++++++----
+ 1 file changed, 13 insertions(+), 4 deletions(-)
+
+commit 6eaa22e9d71d2b09d4bd211026194d618dcc8aad
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 18:00:58 2022 -0600
+
+    [serialize] Reduce link_t size from 16 to 12
+
+ src/hb-serialize.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 30ba9a39e2249b86310c36564373f4f0347012e1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 17:34:58 2022 -0600
+
+    [vector] Add emplacing push implementation
+
+ src/hb-vector.hh | 24 +++++++++++++++++++++---
+ 1 file changed, 21 insertions(+), 3 deletions(-)
+
+commit 25393288f0d6b98355bc4b72bce15ab6f77a5b0e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 17:19:21 2022 -0600
+
+    [test] Fix compiler warning
+
+ test/api/test-set.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit 73b8360dcfb57eaa9acffc7967015a113421eeda
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu May 19 22:59:51 2022 +0000
+
+    [subset] fix fuzzer found underflow when heap push fails.
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5148625505746944.
+
+ src/hb-priority-queue.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit f1bf14ea89ea082e5edd4e9c90738370bffcab1c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 16:42:35 2022 -0600
+
+    Revert "[set] Cache hash value"
+    
+    This reverts commit 44952bcc259a906b8875ed62dc40de96ade8b95c.
+    
+    While we investivate https://github.com/harfbuzz/harfbuzz/issues/3599
+
+ src/hb-bit-set.hh | 22 +---------------------
+ 1 file changed, 1 insertion(+), 21 deletions(-)
+
+commit b4d1ec310cd2c8a6e250c71f865c45fe7cadd5fa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 16:06:21 2022 -0600
+
+    [algs] Declare coerce() as constexpr
+
+ src/hb-algs.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 2fdb7616f589ebb9fc060fdb88745e0219a78a14
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 16:00:43 2022 -0600
+
+    [map Further adjust hash function
+
+ src/hb-map.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 01fc90b68c023d380f3cd44e13b21972b3a41dcf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 16:00:06 2022 -0600
+
+    [map] Adjust hash function
+
+ src/hb-map.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a47b0aebf5f8d56dd78ddd651d40727b729a7577
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 15:52:00 2022 -0600
+
+    [vector] Fix remove() implementation
+    
+    test-vector under valgrind happy now.
+
+ src/hb-vector.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3bd755c32dc7c6ba189783daf89e4cde81715483
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 15:51:18 2022 -0600
+
+    [test-vector] Test remove()
+    
+    Currently buggy. Valgrind confirms.
+
+ src/test-vector.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 58f848daa8f596007a8dadee3fcb462548def980
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 15:42:54 2022 -0600
+
+    [set/map] Adjust hash function return type
+
+ src/hb-bit-page.hh           | 8 ++++----
+ src/hb-bit-set-invertible.hh | 2 +-
+ src/hb-bit-set.hh            | 6 +++---
+ src/hb-map.hh                | 4 ++--
+ src/hb-set.hh                | 2 +-
+ 5 files changed, 11 insertions(+), 11 deletions(-)
+
+commit 6544fc284f55ec1d3199bc610eeac39af935df9c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 15:28:09 2022 -0600
+
+    [vector] Add further copy implementation
+
+ src/hb-vector.hh | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+commit c19f1169521c6fa95c690285a3d24123f387a98e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 15:27:52 2022 -0600
+
+    [meta] Remove non-existing gcc4 trait implementation
+
+ src/hb-meta.hh   | 2 --
+ src/hb-vector.hh | 2 +-
+ 2 files changed, 1 insertion(+), 3 deletions(-)
+
+commit 679b900e9b27fdecb9a694c58f71e7bc9e2cd125
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 15:27:32 2022 -0600
+
+    [meta] Fix gcc4 trait implementation
+
+ src/hb-meta.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit fb77f48ffd3fe7fcd17843b9cdc6ca677d36602c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 15:02:10 2022 -0600
+
+    [vector] Optimize vector copy
+
+ src/hb-meta.hh   |  4 ++++
+ src/hb-vector.hh | 30 ++++++++++++++++++++++++++++--
+ 2 files changed, 32 insertions(+), 2 deletions(-)
+
+commit 28b44ac46a24f6987d2c2565e0ac72d5b2763d81
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 15:01:56 2022 -0600
+
+    [set] Switch set copy to vector operator =
+    
+    Slows it down currently.
+
+ src/hb-bit-set.hh | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+commit 37d3275dec01edfafe2cc744ed85a3febb964594
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 15:01:23 2022 -0600
+
+    [test-vector] Enable disabled test
+    
+    This seems to work already.
+
+ src/test-vector.cc | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 544ffb913ea515fae77f26714a1c7c620cdab0ed
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 14:50:12 2022 -0600
+
+    [set] Adjust grow_vector condition
+
+ src/hb-vector.hh | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+commit 0623aa598ba6a7cc14d00091935bc8811b3c6aac
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 14:12:42 2022 -0600
+
+    [benchmark-set] Add benchmark for set copy
+
+ perf/benchmark-set.cc | 23 +++++++++++++++++++++++
+ src/hb-set.hh         |  8 ++++----
+ 2 files changed, 27 insertions(+), 4 deletions(-)
+
+commit 44952bcc259a906b8875ed62dc40de96ade8b95c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 14:02:48 2022 -0600
+
+    [set] Cache hash value
+
+ src/hb-bit-set.hh | 26 +++++++++++++++++++++++---
+ 1 file changed, 23 insertions(+), 3 deletions(-)
+
+commit 844ac328e46f9bfcc5481f2dd525603c9a448ffe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 13:54:31 2022 -0600
+
+    [set] Fix hb_set_t hash stability
+
+ src/hb-bit-page.hh | 2 +-
+ src/hb-bit-set.hh  | 6 ++++--
+ 2 files changed, 5 insertions(+), 3 deletions(-)
+
+commit 2d0b1248b23c9eb931c013a35daec62c48ee293f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 13:53:53 2022 -0600
+
+    [test-map] Test hb_set_t hash stability
+    
+    Fails currently.
+
+ src/test-map.cc | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 561e02fefb72be902482fc49dcec66b4c585b798
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 13:38:52 2022 -0600
+
+    [map] Make hb_map_t hashable
+
+ src/hb-map.hh   |  8 ++++++++
+ src/test-map.cc | 21 +++++++++++----------
+ 2 files changed, 19 insertions(+), 10 deletions(-)
+
+commit ad176990895963c1b83274d0ef3c5ae148a4f760
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 13:36:12 2022 -0600
+
+    [map] Add is_equal() / towards making hb_map_t hashable
+    
+    New API:
+    + hb_map_is_equal()
+
+ docs/harfbuzz-sections.txt |  1 +
+ src/hb-map.cc              | 20 ++++++++++++++++++++
+ src/hb-map.h               |  4 ++++
+ src/hb-map.hh              | 15 +++++++++++++++
+ src/test-map.cc            | 24 ++++++++++++++++++++++++
+ 5 files changed, 64 insertions(+)
+
+commit 14a24d8e3f7d9b8379452b1596e4aff6603e1f25
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 13:03:50 2022 -0600
+
+    [vector] Make hb_vector_t hashable
+
+ src/hb-vector.hh |  1 +
+ src/test-map.cc  | 26 ++++++++++++++++++++++++++
+ 2 files changed, 27 insertions(+)
+
+commit 124f9aeb9b4c77fe1e2a733c5aceb9172d169f9f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 19 12:58:02 2022 -0600
+
+    [set] Make hb_set_t hashable
+
+ src/hb-bit-page.hh           |  7 +++++++
+ src/hb-bit-set-invertible.hh |  2 ++
+ src/hb-bit-set.hh            |  6 ++++++
+ src/hb-set.hh                |  4 ++++
+ src/test-map.cc              | 23 +++++++++++++++++++++++
+ 5 files changed, 42 insertions(+)
+
+commit 3ab2c7935f5b9706e4767a6e28ff1dcd739ac271
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu May 19 17:23:36 2022 +0000
+
+    [subset-perf] Signficiantly speed up ClassDef*::subset.
+    
+    Eliminates the usage of a glyph -> klass hash map and replaces it with a vector storing the mapping. This allows us to use the vector directly as the iterator driving the serialize. Approximately 1% speedup for Noto Nastaliq.
+
+ src/hb-ot-layout-common.hh | 72 ++++++++++++++++++++++------------------------
+ 1 file changed, 35 insertions(+), 37 deletions(-)
+
+commit e3e685e5eec1cb400e0b4bd371872cb9394c79bc
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Wed May 18 15:05:55 2022 -0400
+
+    [ot-tags] Fix `min_subtag_len` calculations
+
+ src/gen-tag-table.py   | 12 +++++-------
+ src/hb-ot-tag-table.hh |  3 +--
+ 2 files changed, 6 insertions(+), 9 deletions(-)
+
+commit 0b1c2ff96a333a3e78eeefe54cb9e9509120990a
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed May 18 23:32:03 2022 +0000
+
+    [subset-perf] Remove extra map lookup in ClassDef subset methods.
+
+ src/hb-ot-layout-common.hh | 15 ++++++++-------
+ 1 file changed, 8 insertions(+), 7 deletions(-)
+
+commit 13ace77f1daaf94d79ad400e3943f71fa5139e70
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed May 18 22:38:43 2022 +0000
+
+    [subset-perf] Use glyph_map instead of set in ClassDefFormat.
+
+ src/hb-ot-layout-common.hh | 29 +++++++++++++++--------------
+ 1 file changed, 15 insertions(+), 14 deletions(-)
+
+commit adae2f2272bf51c6b4df2ba5d0e10eb25386e58c
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed May 18 21:42:28 2022 +0000
+
+    [subset-perf] Cache a glyph map for gsub.
+    
+    This allows us in some cases to avoid using glyph_set_gsub as a filter.
+
+ src/hb-ot-layout-common.hh |  8 +++-----
+ src/hb-subset-plan.cc      | 21 +++++++++++++++++++++
+ src/hb-subset-plan.hh      |  1 +
+ 3 files changed, 25 insertions(+), 5 deletions(-)
+
+commit 202e6c469963fe76f3320a956be8b194adb9089d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 17:12:43 2022 -0600
+
+    [subset] Remove unnecessary test
+
+ src/hb-ot-layout-gsubgpos.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit cedf739646d67e73c06e2569d4be2d7f32e39fd8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 16:52:35 2022 -0600
+
+    Add some commented-out code
+
+ src/hb-ot-layout-common.hh | 14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
+
+commit 6b62c10f0228d011526ef41772a65e6f12022ddb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 16:27:54 2022 -0600
+
+    [priority-queue] Remove old init/fini
+
+ src/hb-priority-queue.hh | 7 -------
+ 1 file changed, 7 deletions(-)
+
+commit bff8248a9d44654d7901150e86e684af0cfa8681
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 16:25:03 2022 -0600
+
+    [repacker] Pre-alloc vertices
+
+ src/hb-repacker.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 39a424caf04392702b62950c832fd1f67204ba62
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 16:17:16 2022 -0600
+
+    [priority-queue] Optimize heap access
+
+ src/hb-priority-queue.hh   | 18 ++++++++++++------
+ src/test-priority-queue.cc |  8 --------
+ 2 files changed, 12 insertions(+), 14 deletions(-)
+
+commit 9308659fd76bb400da2c869ca2f945760adfaf56
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 16:14:25 2022 -0600
+
+    [priority-queue] Optimize swap()
+
+ src/hb-priority-queue.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit c7317ef7617a1387c88db19582f1b9879a722d7a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 16:03:41 2022 -0600
+
+    [repacker] Avoid destroying and recreating objects
+
+ src/hb-repacker.hh | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit 864e09a0c460916c06d8becbc3480d06692cd634
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 15:59:29 2022 -0600
+
+    [repacker] Reuse allocated vector
+
+ src/hb-repacker.hh | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+commit ca77f164704c6463b09d973251f6f9995172d8c1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 15:55:49 2022 -0600
+
+    [repacker] Remove unnecessary vector .fini() calls
+
+ src/hb-repacker.hh | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit 4cfc2d668e3df53a6564cef1be65ad0239470123
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 15:32:19 2022 -0600
+
+    [subset] Use a std::move on set_t when feasible
+
+ src/hb-ot-layout-gsubgpos.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1f578b5a32337011766e078331c0ba8ce4ce8af8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 15:24:40 2022 -0600
+
+    [set] Add pre-allocation internal API
+
+ src/hb-bit-set-invertible.hh | 1 +
+ src/hb-bit-set.hh            | 7 +++++++
+ src/hb-set.hh                | 1 +
+ 3 files changed, 9 insertions(+)
+
+commit 48dfbd54a3c9876e86bcdbeb47ae42300ee9f08f
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed May 18 21:03:56 2022 +0000
+
+    [subset] minor cleanup.
+
+ src/hb-ot-layout-common.hh | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+commit 482c6e5dc41402e60acf609fca0d9d8e8fbc4d9d
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed May 18 19:58:55 2022 +0000
+
+    [subset-perf] Speed up Coverage::serialize by caching iterator.
+
+ src/hb-ot-layout-common.hh | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+commit 14b18725f04bba0dac6da943244230c65d3879d4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 15:14:32 2022 -0600
+
+    In Coverage::iter_t, assume iterators are from same Coverage object
+    
+    No need to support otherwise.
+
+ src/hb-ot-layout-common.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 27141735c3e8caa807c3528ce9793b8c8f05a556
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 15:12:49 2022 -0600
+
+    [subset] Add Coverage::__end__ implementation
+
+ src/hb-ot-layout-common.hh | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+commit c476f58adba6680c655cb7bcbdd28d3bd4b7ad37
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 14:20:23 2022 -0600
+
+    [subset] Write CoverageFormat2::intersects_coverage() as bsearch()
+
+ src/hb-ot-layout-common.hh | 23 ++++++++++++++---------
+ 1 file changed, 14 insertions(+), 9 deletions(-)
+
+commit 63c6695108ceb19b4b79e00782c3106801d7dc01
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 13:53:52 2022 -0600
+
+    [ot-layout] Cosmetic
+    
+    The implementation of HBUINT16 operator == is slower than just
+    comparing to ints.
+
+ src/hb-ot-layout-common.hh | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+commit 777debd748dfd803bbd16bcc1bbf2afd7db2fc82
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 13:46:06 2022 -0600
+
+    [subset] Rewrite CoverageFormat2::intersects as dagger
+
+ src/hb-ot-layout-common.hh | 10 +++-------
+ 1 file changed, 3 insertions(+), 7 deletions(-)
+
+commit cf5001fac7770286082ced9d3c5c5fefa3b19d79
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 13:38:29 2022 -0600
+
+    [subset] Optimize CoverageFormat2::intersected_coverage_glyphs
+
+ src/hb-ot-layout-common.hh | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 6f37c2079815bc0ac9193c8e9028da4872374402
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 13:25:42 2022 -0600
+
+    [subset] Minor rewrite in CoverageFormat2::serialize()
+
+ src/hb-ot-layout-common.hh | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+commit e91863b7173543b850e1758873f96c76c67f8ce8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 12:39:55 2022 -0600
+
+    [subset-cff] Pre-size map in subr_remap_t::create()
+
+ src/hb-bimap.hh             | 6 ++++++
+ src/hb-subset-cff-common.hh | 1 +
+ 2 files changed, 7 insertions(+)
+
+commit ce60462173c7d22f9bad8531a2490a551f004197
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 12:34:27 2022 -0600
+
+    [subset-plan] Pre-size maps in _create_old_gid_to_new_gid_map()
+
+ src/hb-subset-plan.cc | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+commit f82ee17a75dda53ac5c506136221b93eed53aee1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 12:17:43 2022 -0600
+
+    [map] Pre-size map in constructor if we can
+
+ src/hb-map.hh           | 13 ++++++++-----
+ src/hb-ot-cmap-table.hh |  4 ++--
+ 2 files changed, 10 insertions(+), 7 deletions(-)
+
+commit b5aa8a27eac851503eaee086912f269b51e68724
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 11:58:58 2022 -0600
+
+    [subset-cff] Cosmetic
+
+ src/hb-subset-cff-common.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit 0b201623f54420a898d3538c8673b450923bcac1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 11:58:22 2022 -0600
+
+    [subset-cff] Fix previous commit
+    
+    Oops!
+
+ src/hb-subset-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4792309265ea17aea0c5fd6821ed453fe8427ab4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 11:54:08 2022 -0600
+
+    [subset-cff] Access vector directly
+
+ src/hb-subset-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 7c86f2e763e44b4c96cd26f1ce06225b4aba977f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 11:45:27 2022 -0600
+
+    [subset-cff] Pre-alloc out buffer
+
+ src/hb-subset-cff-common.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 0761e7cdfd00d5347657bdf009c3035be4ebab44
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 11:37:57 2022 -0600
+
+    [subset-cff] Avoid resetting buffer as encoder does
+
+ src/hb-subset-cff-common.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 71aa10a3942081f2c4ce0c2c5d4c3897d13d887c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 11:37:24 2022 -0600
+
+    [subset-cff] Manually grow vector to avoid memset overhead
+
+ src/hb-subset-cff-common.hh | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+commit f455cc53fd4a30682c549fcad6d4112b98688aca
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 11:31:55 2022 -0600
+
+    [subset-cff] Reuse buffer allocation
+
+ src/hb-subset-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3e4ab2ad9c2de17218c16787b59d63c236262d8f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 11:16:46 2022 -0600
+
+    [perf/benchmark-ot] Add zh-hans
+
+ perf/benchmark-ot.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 6e668a2adefdc186dcd300136b3535c43d6fdffd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 11:16:11 2022 -0600
+
+    [perf/benchmark-ot] Rename test
+
+ perf/benchmark-ot.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e24797aeac65aaa1edd836bf9708f488044d3939
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 11:10:10 2022 -0600
+
+    [ot-tags] Follow-up to previous commit
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/3591
+
+ src/gen-tag-table.py   | 16 ++++++++--------
+ src/hb-ot-tag-table.hh | 18 +++++++++---------
+ 2 files changed, 17 insertions(+), 17 deletions(-)
+
+commit f5d619be79e9f23f67f23513e60c546fc498f1b8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 18 11:04:52 2022 -0600
+
+    [ot-tags] Further gate the slow complex case, and add more tests
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/3591
+    
+    Still 'zh-trad' is the slowest case.
+    
+    --------------------------------------------------------------------------------------------------
+    Benchmark                                                        Time             CPU   Iterations
+    --------------------------------------------------------------------------------------------------
+    BM_hb_ot_tags_from_script_and_language/COMMON zh_trad          136 ns          136 ns      5107838
+    BM_hb_ot_tags_from_script_and_language/COMMON ab_abcd          115 ns          115 ns      6103104
+    BM_hb_ot_tags_from_script_and_language/COMMON ab_abc          25.4 ns         25.3 ns     27674482
+    BM_hb_ot_tags_from_script_and_language/COMMON abcdef_XY       20.2 ns         20.1 ns     34795719
+    BM_hb_ot_tags_from_script_and_language/COMMON abcd_XY         19.4 ns         19.3 ns     36390401
+    BM_hb_ot_tags_from_script_and_language/COMMON cxy_CN          33.5 ns         33.4 ns     20998939
+    BM_hb_ot_tags_from_script_and_language/COMMON exy_CN          25.1 ns         25.0 ns     27705832
+    BM_hb_ot_tags_from_script_and_language/COMMON zh_CN           34.2 ns         34.1 ns     20564356
+    BM_hb_ot_tags_from_script_and_language/COMMON en_US           15.5 ns         15.5 ns     45032204
+    BM_hb_ot_tags_from_script_and_language/LATIN en_US            15.9 ns         15.8 ns     44412379
+    BM_hb_ot_tags_from_script_and_language/COMMON none            4.72 ns         4.71 ns    149101665
+    BM_hb_ot_tags_from_script_and_language/LATIN none             4.72 ns         4.70 ns    149254498
+
+ perf/benchmark-ot.cc   | 3 +++
+ src/gen-tag-table.py   | 3 +++
+ src/hb-ot-tag-table.hh | 3 +++
+ 3 files changed, 9 insertions(+)
+
+commit 9c64bda21dd4215a3caa32e4127d9f2017e50de2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 17 17:31:18 2022 -0600
+
+    [ot-tag] Whitespace
+
+ src/hb-ot-tag.cc | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+commit 3df8017e9b7ea2b72477294133563b4ff304a007
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 17 17:29:39 2022 -0600
+
+    [ot-tag] Optimize subtag_matches() more
+
+ src/gen-tag-table.py   |   2 +-
+ src/hb-ot-tag-table.hh | 112 ++++++++++++++++++++++++-------------------------
+ src/hb-ot-tag.cc       |   5 +--
+ 3 files changed, 59 insertions(+), 60 deletions(-)
+
+commit b231fc2dbcee402d1cff578371f9ad89ff594bb2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 17 17:02:48 2022 -0600
+
+    [perf/benchmark-ot] Add a couple more test cases
+
+ perf/benchmark-ot.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 3524b14fa06dbf9caddef1d2f598e2f4f46315c1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 17 17:02:48 2022 -0600
+
+    [perf/benchmark-ot] Add a couple more test cases
+
+ perf/benchmark-ot.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 7f6e8c5536fd13a56b4bd030233960aa1af38d05
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 17 16:58:35 2022 -0600
+
+    [ot-tags] Optimize subtag_matches() further
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/3591
+    
+    Comparing before to after
+    Benchmark                                                               Time             CPU      Time Old      Time New       CPU Old       CPU New
+    ----------------------------------------------------------------------------------------------------------------------------------------------------
+    BM_hb_ot_tags_from_script_and_language/COMMON abcd_XY                -0.3371         -0.3371            71            47            71            47
+
+ src/hb-ot-tag.cc | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 27c11405a263ad43d24e2ed460e15f247ac06d17
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 17 16:51:51 2022 -0600
+
+    [ot-tag] Optimize subtag_matches
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/3591
+
+ src/hb-ot-tag.cc | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit a07d818597385c6d83265f8320b9c1334c539758
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 17 16:46:10 2022 -0600
+
+    [ot-tag] Add a likely() to the cache hit case
+
+ src/hb-ot-tag.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 0ff5d36cd451dffe51a8c0637b4a544882663a1d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 17 16:34:52 2022 -0600
+
+    [perf/benchmark-ot] Fix benchmark
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/3591
+    
+    Ouch!
+    
+    These are the current numbers:
+    
+    ------------------------------------------------------------------------------------------------
+    Benchmark                                                      Time             CPU   Iterations
+    ------------------------------------------------------------------------------------------------
+    BM_hb_ot_tags_from_script_and_language/COMMON abcd_XY       78.0 ns         77.7 ns      8917912
+    BM_hb_ot_tags_from_script_and_language/COMMON zh_CN         44.9 ns         44.8 ns     15475318
+    BM_hb_ot_tags_from_script_and_language/COMMON en_US         17.6 ns         17.5 ns     39812340
+    BM_hb_ot_tags_from_script_and_language/LATIN en_US          18.2 ns         18.1 ns     38356204
+    BM_hb_ot_tags_from_script_and_language/COMMON none          4.76 ns         4.74 ns    148746131
+    BM_hb_ot_tags_from_script_and_language/LATIN none           4.73 ns         4.71 ns    148421349
+
+ perf/benchmark-ot.cc | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+commit dfca47f419b6ef5c6df813822e4b10a7cec92434
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 17 16:21:02 2022 -0600
+
+    [ot-tag] Cache last bsearch result
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/3591
+    
+    Humm. Looks like not all of the fat is bsearch overhead now. I cached
+    the last bsearch result, but most of the time is still there. I'm
+    baffled.
+    
+    Before:
+    ------------------------------------------------------------------------------------------------
+    Benchmark                                                      Time             CPU   Iterations
+    ------------------------------------------------------------------------------------------------
+    BM_hb_ot_tags_from_script_and_language/COMMON abcd_XY       8.08 ns         8.05 ns     84500482
+    BM_hb_ot_tags_from_script_and_language/COMMON zh_CN         42.2 ns         42.1 ns     16722006
+    BM_hb_ot_tags_from_script_and_language/COMMON en_US         16.1 ns         16.0 ns     43461527
+    BM_hb_ot_tags_from_script_and_language/LATIN en_US          16.5 ns         16.5 ns     42448505
+    BM_hb_ot_tags_from_script_and_language/COMMON none          4.34 ns         4.33 ns    161290530
+    BM_hb_ot_tags_from_script_and_language/LATIN none           4.34 ns         4.33 ns    162339799
+    
+    After:
+    ------------------------------------------------------------------------------------------------
+    Benchmark                                                      Time             CPU   Iterations
+    ------------------------------------------------------------------------------------------------
+    BM_hb_ot_tags_from_script_and_language/COMMON abcd_XY       8.13 ns         8.11 ns     80438134
+    BM_hb_ot_tags_from_script_and_language/COMMON zh_CN         40.0 ns         39.9 ns     17487939
+    BM_hb_ot_tags_from_script_and_language/COMMON en_US         12.7 ns         12.7 ns     55124394
+    BM_hb_ot_tags_from_script_and_language/LATIN en_US          13.1 ns         13.0 ns     53660125
+    BM_hb_ot_tags_from_script_and_language/COMMON none          4.61 ns         4.60 ns    151394104
+    BM_hb_ot_tags_from_script_and_language/LATIN none           4.70 ns         4.68 ns    150402847
+
+ src/hb-ot-tag.cc | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+commit 909f00ac6e6b3eb459f0553b84fe508bb697e9af
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 17 15:51:41 2022 -0600
+
+    [ot-tags] Further speed up language bsearch()
+    
+    Using an integer tag to bsearch, instead of string.
+    
+    Part of: https://github.com/harfbuzz/harfbuzz/issues/3591
+    
+    Before:
+    ------------------------------------------------------------------------------------------------
+    Benchmark                                                      Time             CPU   Iterations
+    ------------------------------------------------------------------------------------------------
+    BM_hb_ot_tags_from_script_and_language/COMMON abcd_XY       8.11 ns         8.08 ns     87067795
+    BM_hb_ot_tags_from_script_and_language/COMMON zh_CN         53.6 ns         53.5 ns     13042418
+    BM_hb_ot_tags_from_script_and_language/COMMON en_US         24.2 ns         24.1 ns     29052731
+    BM_hb_ot_tags_from_script_and_language/LATIN en_US          24.4 ns         24.3 ns     28736769
+    BM_hb_ot_tags_from_script_and_language/COMMON none          4.43 ns         4.41 ns    160370413
+    BM_hb_ot_tags_from_script_and_language/LATIN none           4.35 ns         4.34 ns    160578191
+    
+    After:
+    ------------------------------------------------------------------------------------------------
+    Benchmark                                                      Time             CPU   Iterations
+    ------------------------------------------------------------------------------------------------
+    BM_hb_ot_tags_from_script_and_language/COMMON abcd_XY       7.97 ns         7.95 ns     85208363
+    BM_hb_ot_tags_from_script_and_language/COMMON zh_CN         41.7 ns         41.6 ns     16945817
+    BM_hb_ot_tags_from_script_and_language/COMMON en_US         16.1 ns         16.0 ns     43613523
+    BM_hb_ot_tags_from_script_and_language/LATIN en_US          16.5 ns         16.4 ns     42568107
+    BM_hb_ot_tags_from_script_and_language/COMMON none          4.30 ns         4.29 ns    164055469
+    BM_hb_ot_tags_from_script_and_language/LATIN none           4.29 ns         4.27 ns    163793591
+
+ src/gen-tag-table.py   |    2 +-
+ src/hb-ot-tag-table.hh | 3206 ++++++++++++++++++++++++------------------------
+ src/hb-ot-tag.cc       |   29 +-
+ 3 files changed, 1622 insertions(+), 1615 deletions(-)
+
+commit c460cf74ce2a3ebe5d285e03dc122fb60ff70e01
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 17 15:30:11 2022 -0600
+
+    [ot-tags] Cosmetic
+
+ src/hb-ot-tag.cc | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 1c8226ed14c1ac7d82ea5482bdf2a7d019dd38a2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 17 15:28:50 2022 -0600
+
+    Fix compiler warning
+    
+    On Mac compiler:
+    
+    FAILED: src/libharfbuzz.0.dylib.p/hb-ot-tag.cc.o
+    c++ -Isrc/libharfbuzz.0.dylib.p -Isrc -I../src -I. -I.. -I/usr/local/opt/freetype/include/freetype2 -I/usr/local/Cellar/graphite2/1.3.14/include -I/usr/local/Cellar/glib/2.72.1/include/glib-2.0 -I/usr/local/Cellar/glib/2.72.1/lib/glib-2.0/include -I/usr/local/opt/gettext/include -I/usr/local/Cellar/pcre/8.45/include -Xclang -fcolor-diagnostics --coverage -pipe -Wall -Winvalid-pch -Wnon-virtual-dtor -std=c++11 -fno-rtti -O2 -g -fno-exceptions -fno-rtti -fno-threadsafe-statics -fvisibility-inlines-hidden -DHAVE_CONFIG_H -Wno-non-virtual-dtor -MD -MQ src/libharfbuzz.0.dylib.p/hb-ot-tag.cc.o -MF src/libharfbuzz.0.dylib.p/hb-ot-tag.cc.o.d -o src/libharfbuzz.0.dylib.p/hb-ot-tag.cc.o -c ../src/hb-ot-tag.cc
+    In file included from ../src/hb-ot-tag.cc:29:
+    In file included from ../src/hb.hh:481:
+    ../src/hb-array.hh:359:14: error: missing default argument on parameter 'ds'
+                  Ts... ds) const
+                        ^
+    ../src/hb-ot-tag.cc:292:58: note: in instantiation of function template specialization 'hb_sorted_array_t<const LangTag>::bfind<const char *, unsigned int>' requested here
+        if (hb_sorted_array (ot_languages, ot_languages_len).bfind (lang_str, &tag_idx,
+                                                             ^
+    1 error generated.
+
+ src/hb-array.hh  | 9 ++++-----
+ src/hb-ot-tag.cc | 4 +---
+ 2 files changed, 5 insertions(+), 8 deletions(-)
+
+commit c1f4b57c064d41a291976e6d126f7bf0f6e66bc9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 17 15:19:40 2022 -0600
+
+    [ot-tags] Optimize language comparison
+    
+    Now that we know both strings are of equal len of 2 or 3, optimize.
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/3591
+    
+    Before:
+    ------------------------------------------------------------------------------------------------
+    Benchmark                                                      Time             CPU   Iterations
+    ------------------------------------------------------------------------------------------------
+    BM_hb_ot_tags_from_script_and_language/COMMON abcd_XY       8.50 ns         8.47 ns     81221549
+    BM_hb_ot_tags_from_script_and_language/COMMON zh_CN         79.6 ns         79.3 ns      8785804
+    BM_hb_ot_tags_from_script_and_language/COMMON en_US         40.0 ns         39.9 ns     17462768
+    BM_hb_ot_tags_from_script_and_language/LATIN en_US          39.2 ns         39.1 ns     17886793
+    BM_hb_ot_tags_from_script_and_language/COMMON none          4.31 ns         4.30 ns    162805417
+    BM_hb_ot_tags_from_script_and_language/LATIN none           4.32 ns         4.31 ns    162656688
+    
+    After:
+    ------------------------------------------------------------------------------------------------
+    Benchmark                                                      Time             CPU   Iterations
+    ------------------------------------------------------------------------------------------------
+    BM_hb_ot_tags_from_script_and_language/COMMON abcd_XY       8.27 ns         8.24 ns     81868701
+    BM_hb_ot_tags_from_script_and_language/COMMON zh_CN         56.1 ns         56.0 ns     12353284
+    BM_hb_ot_tags_from_script_and_language/COMMON en_US         24.3 ns         24.2 ns     28955030
+    BM_hb_ot_tags_from_script_and_language/LATIN en_US          24.5 ns         24.4 ns     28664868
+    BM_hb_ot_tags_from_script_and_language/COMMON none          4.35 ns         4.34 ns    161190014
+    BM_hb_ot_tags_from_script_and_language/LATIN none           4.36 ns         4.34 ns    161319000
+
+ src/hb-array.hh  | 14 ++++++++------
+ src/hb-ot-tag.cc | 19 ++++++-------------
+ 2 files changed, 14 insertions(+), 19 deletions(-)
+
+commit dde48d78c1e1c11f3c770491a1d618386b3d92f8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 17 15:07:49 2022 -0600
+
+    Fix compiler warning
+
+ src/hb-ot-tag.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 15be0deda03f68c0260d07bdc67c8952aa6ccfa7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 17 14:57:08 2022 -0600
+
+    [ot-tags] Optimize lang_matches()
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/3591
+    
+    Before:
+    ------------------------------------------------------------------------------------------------
+    Benchmark                                                      Time             CPU   Iterations
+    ------------------------------------------------------------------------------------------------
+    BM_hb_ot_tags_from_script_and_language/COMMON abcd_XY       8.67 ns         8.64 ns     80324382
+    BM_hb_ot_tags_from_script_and_language/COMMON zh_CN         91.2 ns         90.9 ns      7674131
+    BM_hb_ot_tags_from_script_and_language/COMMON en_US         41.1 ns         41.0 ns     17174093
+    BM_hb_ot_tags_from_script_and_language/LATIN en_US          41.3 ns         41.2 ns     17000876
+    BM_hb_ot_tags_from_script_and_language/COMMON none          4.56 ns         4.55 ns    153914130
+    BM_hb_ot_tags_from_script_and_language/LATIN none           4.53 ns         4.52 ns    153830303
+    
+    After:
+    ------------------------------------------------------------------------------------------------
+    Benchmark                                                      Time             CPU   Iterations
+    ------------------------------------------------------------------------------------------------
+    BM_hb_ot_tags_from_script_and_language/COMMON abcd_XY       8.24 ns         8.21 ns     84078465
+    BM_hb_ot_tags_from_script_and_language/COMMON zh_CN         77.5 ns         77.2 ns      9059230
+    BM_hb_ot_tags_from_script_and_language/COMMON en_US         38.8 ns         38.7 ns     17790692
+    BM_hb_ot_tags_from_script_and_language/LATIN en_US          37.6 ns         37.5 ns     18648293
+    BM_hb_ot_tags_from_script_and_language/COMMON none          4.50 ns         4.49 ns    155573267
+    BM_hb_ot_tags_from_script_and_language/LATIN none           4.49 ns         4.47 ns    156456653
+
+ src/gen-tag-table.py   |   2 +-
+ src/hb-ot-tag-table.hh | 126 ++++++++++++++++++++++++-------------------------
+ src/hb-ot-tag.cc       |  11 +++--
+ 3 files changed, 70 insertions(+), 69 deletions(-)
+
+commit 407a135baf8ccd53cf1bc3502f3216f3dbcf3328
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 17 14:45:45 2022 -0600
+
+    [perf/benchmark-ot] Add one more test
+
+ perf/benchmark-ot.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit dd3c858f84105021cf1e427399b971bf26dde8b3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 17 14:28:28 2022 -0600
+
+    [ot-tags] Speed up hb_ot_tags_from_language()
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/3591
+    
+    "After that, bulk of the time I suppose is spent in binary-searching the
+    language table. I suggest we split the language table in 2-letter and
+    3-letter tags, to speed-up the vast majority of cases that are
+    2-letter."
+    
+    benchmark-ot, before:
+    
+    ----------------------------------------------------------------------------------------------
+    Benchmark                                                    Time             CPU   Iterations
+    ----------------------------------------------------------------------------------------------
+    BM_hb_ot_tags_from_script_and_language/COMMON zh_CN        112 ns          111 ns      6286271
+    BM_hb_ot_tags_from_script_and_language/COMMON en_US       60.6 ns         60.4 ns     11671176
+    BM_hb_ot_tags_from_script_and_language/LATIN en_US        61.3 ns         61.1 ns     11442645
+    BM_hb_ot_tags_from_script_and_language/COMMON none        4.75 ns         4.74 ns    146997235
+    BM_hb_ot_tags_from_script_and_language/LATIN none         4.65 ns         4.64 ns    150938747
+    
+    After:
+    
+    ----------------------------------------------------------------------------------------------
+    Benchmark                                                    Time             CPU   Iterations
+    ----------------------------------------------------------------------------------------------
+    BM_hb_ot_tags_from_script_and_language/COMMON zh_CN       89.5 ns         89.2 ns      7747649
+    BM_hb_ot_tags_from_script_and_language/COMMON en_US       38.5 ns         38.4 ns     18199432
+    BM_hb_ot_tags_from_script_and_language/LATIN en_US        39.0 ns         38.9 ns     18049238
+    BM_hb_ot_tags_from_script_and_language/COMMON none        4.53 ns         4.52 ns    154895110
+    BM_hb_ot_tags_from_script_and_language/LATIN none         4.54 ns         4.52 ns    154762105
+
+ src/gen-tag-table.py   |  55 +++----
+ src/hb-ot-tag-table.hh | 409 +++++++++++++++++++++++++------------------------
+ src/hb-ot-tag.cc       |  45 ++++--
+ 3 files changed, 270 insertions(+), 239 deletions(-)
+
+commit 9baccb986087319ae56e77624082036063d67d90
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 17 13:34:34 2022 -0600
+
+    [ot-tags] Speed up hb_ot_tags_from_complex_language()
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/3591
+    
+    2. All the subtag_matches outside the switch match long strings (>= 6 or so).
+       As such, check the tag for such length before going into any of them.
+    
+    benchmark-ot, before:
+    
+    ----------------------------------------------------------------------------------------------
+    Benchmark                                                    Time             CPU   Iterations
+    ----------------------------------------------------------------------------------------------
+    BM_hb_ot_tags_from_script_and_language/COMMON zh_CN        172 ns          171 ns      4083155
+    BM_hb_ot_tags_from_script_and_language/COMMON en_US        120 ns          119 ns      5849947
+    BM_hb_ot_tags_from_script_and_language/LATIN en_US         113 ns          112 ns      5840326
+    BM_hb_ot_tags_from_script_and_language/COMMON none        4.66 ns         4.64 ns    151396224
+    BM_hb_ot_tags_from_script_and_language/LATIN none         4.66 ns         4.64 ns    149019593
+    
+    After:
+    
+    ----------------------------------------------------------------------------------------------
+    Benchmark                                                    Time             CPU   Iterations
+    ----------------------------------------------------------------------------------------------
+    BM_hb_ot_tags_from_script_and_language/COMMON zh_CN        112 ns          112 ns      6357763
+    BM_hb_ot_tags_from_script_and_language/COMMON en_US       60.5 ns         60.3 ns     11475091
+    BM_hb_ot_tags_from_script_and_language/LATIN en_US        54.9 ns         54.8 ns     12575690
+    BM_hb_ot_tags_from_script_and_language/COMMON none        4.61 ns         4.59 ns    152388450
+    BM_hb_ot_tags_from_script_and_language/LATIN none         4.66 ns         4.64 ns    151497600
+
+ src/gen-tag-table.py   |  41 +++++++++++-----
+ src/hb-ot-tag-table.hh | 126 +++++++++++++++++++++++++------------------------
+ 2 files changed, 95 insertions(+), 72 deletions(-)
+
+commit 26d906b88b324ea953f42acf1b82086cc4ad3642
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 17 13:12:17 2022 -0600
+
+    [perf] Add benchmark-ot
+
+ perf/Makefile.am     |  1 +
+ perf/benchmark-ot.cc | 35 +++++++++++++++++++++++++++++++++++
+ perf/meson.build     | 10 ++++++++++
+ 3 files changed, 46 insertions(+)
+
+commit 629fa8ee87a419c3a2f6b1477d7ecd81571f0d7e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 16 17:44:50 2022 -0600
+
+    [perf/benchmark-font] Test Roboto as variable even though it's not
+
+ perf/benchmark-font.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 71a0cda869f55c00727fdbbf079b671f7fe374ff
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 16 17:43:48 2022 -0600
+
+    [perf/benchmark-font] Only certain fonts are variable
+    
+    Don't test every font as variable.
+
+ perf/benchmark-font.cc | 17 +++++++++--------
+ 1 file changed, 9 insertions(+), 8 deletions(-)
+
+commit fb413f52022aa2edb8a5b64e9d28f826a161d0aa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 16 17:08:43 2022 -0600
+
+    [subset/cff] Don't use bitfields for hot bools
+    
+    The struct has room because of alignment, and these bools are hot.
+
+ src/hb-subset-cff-common.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit a4d98b63ea59f17ef5e4795f6048f9cd6baa4340
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 16 17:02:40 2022 -0600
+
+    [subset/cff1] Collect glyph-to-sid map to avoid an O(n^2) algorithm
+    
+    Saves 13 for largest benchmark:
+    
+    BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/10000                    -0.1313         -0.1308            75            65            75            65
+    
+    BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/4096                 -0.1009         -0.1004            54            48            54            48
+    BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/10000                -0.1067         -0.1066            70            62            69            62
+
+ src/hb-ot-cff1-table.hh | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
+ src/hb-subset-cff1.cc   |  8 +++++++-
+ 2 files changed, 53 insertions(+), 2 deletions(-)
+
+commit b87f48e948077297b823ac929e950d4188ec627d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 16 16:33:31 2022 -0600
+
+    [cff1] get_sid() move bounds check into each implementation
+
+ src/hb-ot-cff1-table.hh | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+commit e1e359b4daac86cea0a4f02f7f175e93ea9440d7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 16 15:53:28 2022 -0600
+
+    [cff1] Tighten up range_list_t a bit
+
+ src/hb-subset-cff1.cc | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit 3fbac0942da80457f8c226105f5a4a1bdfe502f5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 16 15:41:11 2022 -0600
+
+    [cff1] Lazy-load & sort glyph names
+    
+    Improves subset benchmarks by up to 70% for small CFF1 subset of
+    non-CID fonts!
+    
+    BM_subset/subset_glyphs/SourceSansPro-Regular.otf/10                              -0.7067         -0.7071             1             0             1             0
+    BM_subset/subset_glyphs/SourceSansPro-Regular.otf/64                              -0.4817         -0.4824             1             0             1             0
+    BM_subset/subset_glyphs/SourceSansPro-Regular.otf/512                             -0.1948         -0.1956             2             2             2             2
+    BM_subset/subset_glyphs/SourceSansPro-Regular.otf/2000                            -0.0767         -0.0761             6             6             6             6
+
+ src/hb-ot-cff1-table.hh | 74 +++++++++++++++++++++++++++++++++++--------------
+ 1 file changed, 53 insertions(+), 21 deletions(-)
+
+commit b58bfd9818243fc1178ecad0731fa24a5aa3f235
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 16 11:21:45 2022 -0600
+
+    [font] Minor move of code to silence gcc-12 warning
+    
+    See mailing list discussion.
+
+ src/hb-font.cc | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 602e0ca79d1a651fee0cd23d2fa3580621006c87
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 16 10:14:34 2022 -0600
+
+    [cff] Minor restructure of struct
+    
+    Surprisingly this shows tiny benchmark improvement consistently.
+
+ src/hb-cff-interp-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit acdab17ed3507bc9524cb57bef703a983e1031cf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 13 14:14:36 2022 -0600
+
+    [cff] Cosmetic in parsed_values_t
+
+ src/hb-cff-interp-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit b46c7faa9c77e288d16869b9ac609524e0f89468
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 13 14:02:54 2022 -0600
+
+    [cff] Check buf_len, not buf
+    
+    Ouch!
+
+ src/hb-ot-cff1-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 19a8db85458f02f5be268747b85a2c4fab1319b9
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri May 13 18:05:05 2022 +0000
+
+    [subset] fix potential integer overflow in gname_t::cmp.
+
+ src/hb-ot-cff-common.hh | 3 ++-
+ src/hb-ot-cff1-table.hh | 2 +-
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+commit 2d2f66e1a300e14aac16120f2dc193717502129e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 13 13:53:17 2022 -0600
+
+    [cff-common] In INDEX, return empty bytes if length is zero
+    
+    Before it was possible to return non-null arrayZ.
+
+ src/hb-ot-cff-common.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit a2f132f1fc5ed1c8426dea1b1e27aa1eaf8eeb04
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 13 13:49:17 2022 -0600
+
+    [cff] Check glyph-name's length, not arrayZ
+    
+    As the latter can be non-null while still zero-length.
+
+ src/hb-ot-cff1-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit dc09053f1924a486058a8737fda22567e6d95213
+Author: jeremiazhao <jeremiazhao@tencent.com>
+Date:   Fri May 13 17:54:11 2022 +0800
+
+    fix build requirements for fedora/centos in buiding document
+
+ BUILD.md | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c657c4e1f8e6f23828fefbc441b01f7bee685c79
+Author: Thomas Devoogdt <thomas.devoogdt@barco.com>
+Date:   Tue May 10 10:00:06 2022 +0200
+
+    [meta] fix type traits on gcc 4.9 #3526
+    
+    Signed-off-by: Thomas Devoogdt <thomas.devoogdt@barco.com>
+
+ src/hb-meta.hh      | 11 +++++++++++
+ src/hb-open-type.hh | 11 ++++++-----
+ src/hb-vector.hh    | 17 +++++++++--------
+ 3 files changed, 26 insertions(+), 13 deletions(-)
+
+commit e4e053c8b3a72295c7f414726085aaa01c137c6f
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri May 13 17:00:57 2022 +0000
+
+    [perf] fix typo in perf Makefile.
+
+ perf/Makefile.am | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit e61234c5f75e21901a81df08945daddca5cbfde3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 12 13:20:10 2022 -0600
+
+    [vector] Add tests for move constructor/assignment
+
+ src/test-vector.cc | 17 +++++++++++++----
+ 1 file changed, 13 insertions(+), 4 deletions(-)
+
+commit 7fa580bc4f83f5440b23531f53b546d52af0f69b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 12 13:05:32 2022 -0600
+
+    [map] Fix map copy/move constructors to actually work
+    
+    Ouch!
+
+ src/hb-map.hh   |  5 +++--
+ src/hb-set.hh   |  3 +--
+ src/test-map.cc | 22 ++++++++++++++++++----
+ src/test-set.cc |  4 +++-
+ 4 files changed, 25 insertions(+), 9 deletions(-)
+
+commit a09dd87ca373c1629c05803e3b8611274cb15a6c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 12 12:58:07 2022 -0600
+
+    [set] Fix set copy/move constructors to actually work
+    
+    Ouch!
+
+ src/hb-set.hh   | 16 ++++++++++------
+ src/test-set.cc | 19 ++++++++++++++-----
+ 2 files changed, 24 insertions(+), 11 deletions(-)
+
+commit 76fc27713f52cc338f0325650c2c7798f5cfa2ce
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 12 12:14:07 2022 -0600
+
+    [vector] Remove explicit std::move
+    
+    Was confusing compilers. Let them figure it out themselves.
+    
+    Makes NotoNastaliqu subsetting/1000 benchmark more than twice faster:
+    
+    Benchmark                                                                       Time             CPU      Time Old      Time New       CPU Old       CPU New
+    ------------------------------------------------------------------------------------------------------------------------------------------------------------
+    BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/1000                    -0.5064         -0.5065           111            55           110            55
+    BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/1000                -0.5494         -0.5493           132            59           131            59
+
+ src/hb-vector.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c81198b5bc7d5d0990752b36ad2b1fcdec963abf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 12 11:58:37 2022 -0600
+
+    [set] Tweak move operators a bit
+    
+    Should be equivalent.
+
+ src/hb-bit-set-invertible.hh | 6 +++---
+ src/hb-set.hh                | 4 ++--
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+commit 8dc072d20d87d2986cd58797bc1993c372e5d4d6
+Merge: bff78e651 175319cd8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 11 16:45:40 2022 -0600
+
+    Merge pull request #3579 from harfbuzz/subset-retain-buffer
+    
+    Subset retain buffer
+
+commit 175319cd89fbab431616eb83d4d7c569fe4e8800
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 11 13:47:17 2022 -0600
+
+    [gsubgpos] Clean up OT::ClassDefFormat2::intersected_class_glyphs 0 case
+
+ src/hb-ot-layout-common.hh | 18 ++++++++++--------
+ 1 file changed, 10 insertions(+), 8 deletions(-)
+
+commit 137af3612bcf038103bfc315f445d6574cba8d2c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 11 13:39:30 2022 -0600
+
+    [gsubgpos] Simplify OT::ClassDefFormat2::intersected_class_glyphs()
+
+ src/hb-ot-layout-common.hh | 39 +++++++++++++++++++--------------------
+ 1 file changed, 19 insertions(+), 20 deletions(-)
+
+commit 3261e05bdbb067cb9411a38a585bb04be1fb2542
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 11 13:16:31 2022 -0600
+
+    [subset] Optimize ClassDef1::intersected_class_glyphs() for class0
+
+ src/hb-ot-layout-common.hh | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+commit c78d8ba60b49013e3ca98a2d7b030dc5d8c569d8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 11 13:05:41 2022 -0600
+
+    [subset] Allocate same size as source table for GSUB/GPOS/name
+
+ src/hb-subset.cc | 16 +++++++++++-----
+ 1 file changed, 11 insertions(+), 5 deletions(-)
+
+commit 2e7f1ae48feaa2db8248b7ae01e46ef70e461a31
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 11 12:49:16 2022 -0600
+
+    [subset] Use vector.allocated size instead of tracking buf_size
+
+ src/hb-subset.cc | 10 +++++-----
+ src/hb-vector.hh |  3 +--
+ 2 files changed, 6 insertions(+), 7 deletions(-)
+
+commit f08537963b5157cd9e7a02f6e1695ff6bd27cc1b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 11 12:10:03 2022 -0600
+
+    [cff-subset] Pre-alloc vector for operator decoding
+
+ src/hb-cff-interp-common.hh | 5 +++++
+ src/hb-subset-cff-common.hh | 1 +
+ 2 files changed, 6 insertions(+)
+
+commit 7edd54f3ddadc10307577575f47e943b86198e9d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 10 18:44:14 2022 -0600
+
+    [perf/benchmark-subset] Minor cleanup
+
+ perf/benchmark-subset.cc | 32 +++++++++++++++++++-------------
+ 1 file changed, 19 insertions(+), 13 deletions(-)
+
+commit aeb50b8942b92cda2b1d5bb03d685f97f79faf5d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 10 18:06:53 2022 -0600
+
+    [subset] Retain buffer across table subset operations
+
+ src/hb-subset.cc | 61 +++++++++++++++++++++++++++++---------------------------
+ 1 file changed, 32 insertions(+), 29 deletions(-)
+
+commit bff78e651555e6376d2a4b49c323cf5e9fe3a25c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 10 16:33:37 2022 -0600
+
+    [cff] Convert interpretation environment to use constructor
+
+ src/hb-cff-interp-common.hh      | 29 ++++++++---------------------
+ src/hb-cff-interp-cs-common.hh   | 13 +++++--------
+ src/hb-cff-interp-dict-common.hh |  2 ++
+ src/hb-cff1-interp-cs.hh         |  8 +++-----
+ src/hb-cff2-interp-cs.hh         |  9 ++++-----
+ src/hb-ot-cff1-table.cc          | 16 ++++++++--------
+ src/hb-ot-cff1-table.hh          | 19 ++++++++++---------
+ src/hb-ot-cff2-table.cc          |  8 ++++----
+ src/hb-ot-cff2-table.hh          | 24 ++++++++++--------------
+ src/hb-subset-cff-common.hh      |  8 ++++----
+ 10 files changed, 58 insertions(+), 78 deletions(-)
+
+commit de053e2efbcf0166590868c993bfbe7cc3453a06
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 10 15:38:37 2022 -0600
+
+    [cff] Convert subr_subset_param_t to use constructor
+
+ src/hb-subset-cff-common.hh | 59 ++++++++++++++++++++++++---------------------
+ 1 file changed, 31 insertions(+), 28 deletions(-)
+
+commit 96140db485b61995b0fe9528b6323a5ea928e5a8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 10 15:34:33 2022 -0600
+
+    [cff] Convert cff2_extents_param_t to use constructor
+
+ src/hb-ot-cff2-table.cc | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+commit 54544f2a57373b2d74bda55d4a48f58a0121c22c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 10 15:31:49 2022 -0600
+
+    [cff] Convert cff1_extents_param_t to use constructor
+
+ src/hb-ot-cff1-table.cc | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+commit 377befd0c72071190029112ee04ab0a06fea60b6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 10 15:29:12 2022 -0600
+
+    [cff] Convert get_seac_param_t to use constructor
+
+ src/hb-ot-cff1-table.cc | 14 ++++----------
+ 1 file changed, 4 insertions(+), 10 deletions(-)
+
+commit 8fd70362fa4c0f411fc67b15b67b69a7c43431e3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 10 15:15:49 2022 -0600
+
+    [cff] Use hb_ubytes_t() instead of Null(hb_ubytes_t)
+
+ src/hb-cff-interp-cs-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9033c7f99d5ffe80c349a2ed5e4ef68ca4bed434
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 10 14:58:53 2022 -0600
+
+    [cff-common] Optimize INDEX::operator[]
+    
+    Previous try showed slowdown in benchmarks, suprisingly.
+    
+    Rewrite it keeping the function, hopefully allowing better optimization.
+
+ src/hb-ot-cff-common.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 3aace2431b9bd503cb706760d831ae313d059107
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 10 14:54:04 2022 -0600
+
+    Revert "[cff-common] Optimize INDEX::operator[]"
+    
+    This reverts commit 9edb03ac7ac4b4d0814f3fd1f20cc8d2be99e971.
+
+ src/hb-ot-cff-common.hh | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+commit b31ef081db0d91fd6d3e72a59fc97248ab28a904
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 10 14:52:40 2022 -0600
+
+    Revert "[cff] Add an unlikely()"
+    
+    This reverts commit 9ba9adb7ed6d48504e97a2af117b7da1fdb28450.
+    
+    This shows slowdown in benchmarks.
+
+ src/hb-cff-interp-cs-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9ba9adb7ed6d48504e97a2af117b7da1fdb28450
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 10 14:42:50 2022 -0600
+
+    [cff] Add an unlikely()
+
+ src/hb-cff-interp-cs-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9edb03ac7ac4b4d0814f3fd1f20cc8d2be99e971
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 10 14:25:08 2022 -0600
+
+    [cff-common] Optimize INDEX::operator[]
+
+ src/hb-ot-cff-common.hh | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+commit 52d59bf150b2a6312fe4c3b6f2ec882febe814d9
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue May 10 19:40:37 2022 +0000
+
+    [perf] Make subset benchmark data driven.
+
+ perf/benchmark-subset.cc                           | 153 +++++++--------------
+ .../data}/fonts/NotoSansDevanagari-Regular.ttf     | Bin
+ 2 files changed, 52 insertions(+), 101 deletions(-)
+
+commit 0a42410dc8a8457f49b94a0b533f0b83191ce8d5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue May 10 12:05:19 2022 -0600
+
+    [cff2] Change extents/shape stack to be just a number
+    
+    Do the blending immediately.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3559
+    
+    Benchmark on AdobeVFPrototype shows 35% speedup. Now we're faster
+    than FreeType:
+    
+    Benchmark                                                           Time             CPU      Time Old      Time New       CPU Old       CPU New
+    ------------------------------------------------------------------------------------------------------------------------------------------------
+    BM_Font/glyph_extents/AdobeVFPrototype.otf/hb                    -0.3792         -0.3792          1584           983          1581           982
+    BM_Font/glyph_extents/AdobeVFPrototype.otf/ft                    +0.0228         +0.0224          1220          1248          1218          1245
+    BM_Font/glyph_extents/AdobeVFPrototype.otf/var/hb                -0.3513         -0.3518          1616          1048          1613          1046
+    BM_Font/glyph_extents/AdobeVFPrototype.otf/var/ft                +0.0172         +0.0169          1232          1254          1230          1251
+
+ src/hb-cff-interp-common.hh |  4 +--
+ src/hb-cff2-interp-cs.hh    | 82 +++++++++++++++++++++++++++------------------
+ src/hb-ot-cff2-table.cc     | 24 ++++++-------
+ src/hb-subset-cff2.cc       | 28 ++++++++--------
+ 4 files changed, 77 insertions(+), 61 deletions(-)
+
+commit 5277a5772b0b9ebbbcdec0eae7f1b13d41a8d170
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue May 10 18:14:25 2022 +0000
+
+    [perf] Add benchmarks for CFF subsetting.
+
+ perf/benchmark-subset.cc | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+commit 8f9f0c494b9ea516903e8142e8aba391ddcb581c
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue May 10 17:47:08 2022 +0000
+
+    [subset] Enforce cmap12 group ordering constraints in collect_mapping.
+    
+    Fixes fuzzer issue: https://oss-fuzz.com/testcase-detail/6365271012540416
+
+ src/hb-ot-cmap-table.hh                                |   8 ++++++++
+ ...estcase-minimized-hb-subset-fuzzer-6365271012540416 | Bin 0 -> 161424 bytes
+ 2 files changed, 8 insertions(+)
+
+commit c99ad0f015d1328cbb9803777f66ca491b2cb115
+Merge: c941ece60 1b14d2ff1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 18:52:19 2022 -0600
+
+    Merge pull request #3572 from harfbuzz/cff-stack
+    
+    Cff stack
+
+commit 1b14d2ff136a9f7522995393fda6f6644377657f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 18:15:31 2022 -0600
+
+    [cff] Fix arg-stack peek() impl
+
+ src/hb-cff-interp-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 6106ef8c0f61453c38c58f71a045481bf5546f2d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 18:12:09 2022 -0600
+
+    [cff] Tighten up arg-stack access
+
+ src/hb-cff-interp-common.hh | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+commit 8c616a6efe7370e110d6a2f822bb1a38bf768ea6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 17:49:54 2022 -0600
+
+    [cff] Allocate stack inline instead of using hb_vector_t
+    
+    Speeds up glyph_extents and glyph_shape benchmarks for CFF by 10
+    to 16 percent!
+
+ src/hb-cff-interp-common.hh | 18 +++++++-----------
+ 1 file changed, 7 insertions(+), 11 deletions(-)
+
+commit c941ece60fe791b58697a0ac9d92cd27682f0698
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 16:20:22 2022 -0600
+
+    [cff] Use using instead of typedef
+
+ src/hb-cff-interp-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 64d63cebe2968bc8d9882991b5402c7d626ecf90
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 16:16:07 2022 -0600
+
+    [cff-common] Use existing types for str_buff_vec_t
+
+ src/hb-ot-cff-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit e1838ec1f863758bdd3fa33dce8bf8bfb7fa1518
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 16:14:13 2022 -0600
+
+    [cff-common] Remove unused method
+
+ src/hb-ot-cff-common.hh | 11 +----------
+ 1 file changed, 1 insertion(+), 10 deletions(-)
+
+commit 8aa54aaca250e2934bd2c97047db8b40bf027908
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 16:09:56 2022 -0600
+
+    [cff] Replace byte_str_t with hb_bytes_t use
+
+ src/hb-cff-interp-common.hh    | 25 ++++++++++---------------
+ src/hb-cff-interp-cs-common.hh |  6 +++---
+ src/hb-cff1-interp-cs.hh       |  2 +-
+ src/hb-cff2-interp-cs.hh       |  2 +-
+ src/hb-ot-cff-common.hh        | 14 +++++++-------
+ src/hb-ot-cff1-table.cc        |  6 +++---
+ src/hb-ot-cff1-table.hh        | 12 ++++++------
+ src/hb-ot-cff2-table.cc        |  4 ++--
+ src/hb-ot-cff2-table.hh        |  8 ++++----
+ src/hb-subset-cff-common.hh    |  6 +++---
+ src/hb-subset-cff1.cc          |  2 +-
+ 11 files changed, 41 insertions(+), 46 deletions(-)
+
+commit fe1d85a55a53797f0808d1f473475b7ce15eeb92
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 16:04:52 2022 -0600
+
+    [cff] Remove custom byte_str_t impl
+
+ src/hb-cff-interp-common.hh | 35 ++++++++++-------------------------
+ src/hb-ot-cff1-table.hh     |  4 ++--
+ src/hb-ot-cff2-table.hh     |  4 ++--
+ 3 files changed, 14 insertions(+), 29 deletions(-)
+
+commit c8a5f1e3c0cb8b2c0c546e89134cb66b9af2b53a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 15:49:47 2022 -0600
+
+    [cff-common] Indent
+
+ src/hb-ot-cff-common.hh | 49 +++++++++++++++++++++++++------------------------
+ 1 file changed, 25 insertions(+), 24 deletions(-)
+
+commit be7b2905cb118a5d4d08f42e870fe5f5f5ee9b0e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 15:48:18 2022 -0600
+
+    [cff-common] Remove unused INDEX::serialize() method
+
+ src/hb-ot-cff-common.hh | 10 ----------
+ 1 file changed, 10 deletions(-)
+
+commit 60390169b65632406391f3492efdbd66c688555f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 15:44:09 2022 -0600
+
+    [cff-common] Write str_buf_t::total_size() as dagger
+
+ src/hb-ot-cff-common.hh | 11 ++++-------
+ 1 file changed, 4 insertions(+), 7 deletions(-)
+
+commit 258afb45b7fefa42e36f74731d56862b9367f91e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 15:40:55 2022 -0600
+
+    [cff-common] Use range-based loop in str_buff_vec_t
+
+ src/hb-ot-cff-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 8bb1a3ce9ae8a24c168a51c6faf16779561138ae
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 15:38:40 2022 -0600
+
+    [cff-common] Write INDEX offset-size calc using hb_bit_storage()
+
+ src/hb-ot-cff-common.hh | 15 +--------------
+ 1 file changed, 1 insertion(+), 14 deletions(-)
+
+commit 2ccfe84eff7f72159c87012d7e10e9c8ecdbc956
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 15:35:04 2022 -0600
+
+    [cff-common] Add assert to INDEX::set_offset_at()
+
+ src/hb-ot-cff-common.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 4bcab9e99a7fb7456f5788e2da6fae8fc5b14584
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 15:30:42 2022 -0600
+
+    [cff-common] Use byte_str_t() instead of Null(byte_str_t)
+
+ src/hb-ot-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 94f7a263228a120754ca31600cabb15de0652501
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 15:29:14 2022 -0600
+
+    [cff-common] Fix get_size() for Null object
+    
+    The special-casing didn't make sense.
+
+ src/hb-ot-cff-common.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit c9cc7d5d21dc2550e820de841f5d24f5c94dcc7e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 15:27:27 2022 -0600
+
+    [cff-common] Inline once-used method in INDEX
+
+ src/hb-ot-cff-common.hh | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+commit 11482a3a3927eff8e408f825082f61a202c9be9b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 15:25:21 2022 -0600
+
+    [cff-common] Remove unused method from INDEX
+
+ src/hb-ot-cff-common.hh | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit d1bb3b08f65965bfc07b11becc3e344554c398cc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 15:23:59 2022 -0600
+
+    [cff-common] Hide more INDEX internals
+
+ src/hb-ot-cff-common.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit d3b21387fde2923a624903915a58c9745d2602af
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 15:22:55 2022 -0600
+
+    [cff-common] Remove redundant operator implementation
+
+ src/hb-ot-cff-common.hh | 7 -------
+ 1 file changed, 7 deletions(-)
+
+commit a96b408d805c53c051764b66a7e19aa902c82546
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 9 15:20:16 2022 -0600
+
+    [cff-common] Hide INDEX internals
+
+ src/hb-ot-cff-common.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 335b1d83cf61d1d712e9343a2217594f37018880
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 6 13:37:11 2022 -0600
+
+    [cff-common] No need to check max-offset in INDEX
+    
+    The length_at() function makes sure out-of-range offsets
+    are discarded. We just need to check the last offset.
+
+ src/hb-ot-cff-common.hh | 19 ++++---------------
+ 1 file changed, 4 insertions(+), 15 deletions(-)
+
+commit b051f3fa8388d25c7023a7f48dfea415bde1c94c
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu May 5 23:27:34 2022 +0000
+
+    [subset] Fix cpal subsetting when there are partial palette overlaps.
+    
+    The existing code doesn't correctly handle the case where palettes partially overlap in the color record array. This changes the subsetting to only share entries in the color record array when palettes have the same first color index. Partially overlapping palettes will be converted to disjoint segments in the color record array.
+    
+    Updates one of the color tests to use multiple palettes.
+    
+    Also fixes fuzzer: https://oss-fuzz.com/testcase-detail/5568200165687296.
+
+ src/hb-ot-color-cpal-table.hh                      |  60 +++++++++++++--------
+ ...ase-minimized-hb-subset-fuzzer-5568200165687296 | Bin 0 -> 220551 bytes
+ .../colr_with_components/colr-table.default.6B.ttf | Bin 4260 -> 4320 bytes
+ .../colr-table.drop-hints-retain-gids.6B.ttf       | Bin 4984 -> 5044 bytes
+ .../colr-table.drop-hints.6B.ttf                   | Bin 4260 -> 4320 bytes
+ .../colr-table.retain-gids.6B.ttf                  | Bin 4984 -> 5044 bytes
+ test/subset/data/fonts/colr-table.ttf              | Bin 26952 -> 27328 bytes
+ 7 files changed, 37 insertions(+), 23 deletions(-)
+
+commit 2884eb97bf448448c8c06f51e1a60acbff33bcbf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 6 12:54:02 2022 -0600
+
+    [cff-common] Remove special-casing of count=0 in INDEX serialize
+    
+    The generic code-path now can handle count=0.
+
+ src/hb-ot-cff-common.hh | 15 +++------------
+ 1 file changed, 3 insertions(+), 12 deletions(-)
+
+commit fc7f51aecea6b7a66772d4f759f52447f34197f1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 6 12:53:19 2022 -0600
+
+    [cff-common] Reduce iterator calls
+
+ src/hb-ot-cff-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit c857b8e3c642476aedea634c294ee101d6ce39f3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 6 12:50:37 2022 -0600
+
+    [cff-common] Set INDEX min_size to 2
+    
+    That is what it is, for an empty INDEX.
+
+ src/hb-ot-cff-common.hh | 21 ++++++++++++---------
+ 1 file changed, 12 insertions(+), 9 deletions(-)
+
+commit dd71d2c1c30ca85ddd7b1d7e3a9e2bbdacd6ae7a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 6 13:02:26 2022 -0600
+
+    [gvar] Protect against offset underflow
+
+ src/hb-ot-var-gvar-table.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 9a6dabd61a1af848abbab21b0152e58875604a37
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 6 12:01:37 2022 -0600
+
+    [gvar] Remove sanitize check for data array
+    
+    We are not checking in sanitize that offset array is ascending,
+    so this check was bogus.
+
+ src/hb-ot-var-gvar-table.hh | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+commit 38478d1061d4971c6f10910db1b8988aab900bcf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 6 12:00:01 2022 -0600
+
+    [gvar] DEFINE_SIZE_ARRAY instead of DEFINE_SIZE_MIN
+
+ src/hb-ot-var-gvar-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 90d278c92e2ef076d2b239fed56a9dc11f4b6c12
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 6 11:58:53 2022 -0600
+
+    [gvar] Remove requirement that num_glyphs matches the font's
+
+ src/hb-ot-var-gvar-table.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit ca8a0f3ea32af8fdaf2f99ad87a43e82be854f62
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri May 6 11:54:38 2022 -0600
+
+    [gvar] Protect against out-of-range access
+    
+    Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=47281
+    Fixes https://oss-fuzz.com/testcase-detail/5508865908670464
+
+ src/hb-ot-var-gvar-table.hh                             |   5 ++++-
+ ...usterfuzz-testcase-hb-subset-fuzzer-5508865908670464 | Bin 0 -> 17004 bytes
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+commit f10ddb8dd870fd691c8876c1c7151e607aab0625
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 5 11:21:24 2022 -0600
+
+    [cmap] Use -1 as Unicode sentinel, not U+FFFF in Format12 serialize
+
+ src/hb-ot-cmap-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 8a19968c8b8f8118e6247489a65edfb707bc838e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 5 11:17:23 2022 -0600
+
+    [cmap] Use iterator bool operator
+
+ src/hb-ot-cmap-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 8bfeea482838a0c4f678c7f666f4520f4f2e8dd9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 5 10:48:24 2022 -0600
+
+    [subset] Compute set max using previous()
+
+ src/hb-subset-plan.cc | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+commit 00cb8c629d8f5615d316ac6541d6652dfa2d3145
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 5 10:33:50 2022 -0600
+
+    [subset] Don't go into glyf table if it's empty
+
+ src/hb-ot-glyf-table.hh |  2 ++
+ src/hb-subset-plan.cc   | 17 ++++++++++-------
+ 2 files changed, 12 insertions(+), 7 deletions(-)
+
+commit 4fe69bc41327596af540a2f683062b41a4f37f45
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu May 5 10:19:16 2022 -0600
+
+    [subset] Use del_range in _remove_invalid_gids
+
+ src/hb-subset-plan.cc | 9 ++-------
+ 1 file changed, 2 insertions(+), 7 deletions(-)
+
+commit 2a42edccbe55ede9ed7bbf643b7bec41698078ed
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 4 17:06:18 2022 -0600
+
+    [subset] Cosmetic; use set bulk array population instead of for loop
+
+ src/hb-subset-plan.cc | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+commit bc5129d7fa6fae7ce4c653b699944dd9416eca68
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed May 4 22:16:03 2022 +0000
+
+    [perf] use option_t in subset benchmark to select between glyphs and codepoint subset.
+
+ perf/benchmark-subset.cc | 134 ++++++++++++++++++++++-------------------------
+ 1 file changed, 62 insertions(+), 72 deletions(-)
+
+commit 43938ecdc2b5cda45f9499f8c3360a0a3ac0842b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 4 16:59:28 2022 -0600
+
+    [subset] Remove outdated comment
+    
+    I tried something like that. It was slower because of the allocations.
+
+ src/hb-subset-plan.cc | 3 ---
+ 1 file changed, 3 deletions(-)
+
+commit 6212856ce80d1cbdb5ebbd6d8f899e2b1e45d611
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed May 4 22:16:03 2022 +0000
+
+    [perf] benchmark subsetting via glyphs.
+
+ perf/benchmark-subset.cc | 78 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 78 insertions(+)
+
+commit 6829dd30ad9058170674760f3795fcafe3ed6f27
+Merge: 052812b6b 50db78ba8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 4 16:49:45 2022 -0600
+
+    Merge pull request #3562 from harfbuzz/subset-cmap-no-qsort
+    
+    [subset] In cmap planning, remove a qsort()
+
+commit 50db78ba834b35b96a808c07e550a50b3e1fa5ec
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 4 15:48:18 2022 -0600
+
+    [subset] In cmap planning, remove a qsort()
+
+ src/hb-subset-plan.cc | 30 ++++++++++--------------------
+ 1 file changed, 10 insertions(+), 20 deletions(-)
+
+commit 052812b6ba424b4be677d60a722375f69decb89f
+Merge: f67e6bf79 7cb36e422
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed May 4 15:38:30 2022 -0600
+
+    Merge pull request #3561 from googlefonts/cmap_opt
+    
+    [subset] Further cmap subsetting speed optimizations
+
+commit 7cb36e422218305329102849c156ab94db91cbef
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed May 4 21:22:26 2022 +0000
+
+    [subset] Re-introduce size threshold in choosing unicode collection method.
+    
+    Threshold is needed since the unicodes set might be an inverted set.
+
+ src/hb-subset-plan.cc | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+commit 42c54eba839f510c885fe1a63732b0f706af1bff
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed May 4 20:21:43 2022 +0000
+
+    [subset] Presize unicode to gid list to unicodes + glyphs size.
+
+ src/hb-subset-plan.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 7c7c01d28cee221f1c64684539c8e6160f144f61
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue May 3 22:40:56 2022 +0000
+
+    [subset] Remove switch to alternate unicode collection at large subset sizes.
+    
+    Benchmarks show that the first path is always faster even at large subset sizes:
+    
+    BM_subset_codepoints/subset_roboto/10_median                              +0.0324         +0.0325             0             0             0             0
+    BM_subset_codepoints/subset_roboto/64_median                              +0.0253         +0.0255             0             1             0             1
+    BM_subset_codepoints/subset_roboto/512_median                             +0.0126         +0.0128             1             1             1             1
+    BM_subset_codepoints/subset_roboto/4000_median                            +0.0500         +0.0491             6             7             6             7
+    BM_subset_codepoints/subset_amiri/10_median                               +0.0338         +0.0332             1             1             1             1
+    BM_subset_codepoints/subset_amiri/64_median                               +0.0238         +0.0234             1             1             1             1
+    BM_subset_codepoints/subset_amiri/512_median                              +0.0066         +0.0063             8             8             8             8
+    BM_subset_codepoints/subset_amiri/4000_median                             -0.0011         -0.0012            13            13            13            13
+    BM_subset_codepoints/subset_noto_nastaliq_urdu/10_median                  +0.0226         +0.0226             0             0             0             0
+    BM_subset_codepoints/subset_noto_nastaliq_urdu/64_median                  +0.0047         +0.0044            20            20            20            20
+    BM_subset_codepoints/subset_noto_nastaliq_urdu/512_median                 +0.0022         +0.0021           165           166           165           166
+    BM_subset_codepoints/subset_noto_nastaliq_urdu/1000_median                -0.0021         -0.0023           166           166           166           165
+    BM_subset_codepoints/subset_noto_devangari/10_median                      +0.0054         +0.0054             0             0             0             0
+    BM_subset_codepoints/subset_noto_devangari/64_median                      +0.0024         +0.0019             0             0             0             0
+    BM_subset_codepoints/subset_noto_devangari/512_median                     +0.0089         +0.0090             5             5             5             5
+    BM_subset_codepoints/subset_noto_devangari/1000_median                    -0.0028         -0.0019             5             5             5             5
+    BM_subset_codepoints/subset_mplus1p/10_median                             +0.0001         +0.0002             0             0             0             0
+    BM_subset_codepoints/subset_mplus1p/64_median                             +0.0073         +0.0075             1             1             1             1
+    BM_subset_codepoints/subset_mplus1p/512_median                            +0.0034         +0.0034             1             1             1             1
+    BM_subset_codepoints/subset_mplus1p/4096_median                           -0.1248         -0.1248             7             6             7             6
+    BM_subset_codepoints/subset_mplus1p/10000_median                          -0.0885         -0.0885            13            12            13            12
+    BM_subset_codepoints/subset_notocjk/10_median                             +0.0031         +0.0032             2             2             2             2
+    BM_subset_codepoints/subset_notocjk/64_median                             -0.0010         -0.0010             2             2             2             2
+    BM_subset_codepoints/subset_notocjk/512_median                            -0.0023         -0.0023             9             9             9             9
+    BM_subset_codepoints/subset_notocjk/4096_median                           -0.1725         -0.1726            28            23            28            23
+    BM_subset_codepoints/subset_notocjk/32768_median                          -0.0277         -0.0287           140           137           140           136
+    BM_subset_codepoints/subset_notocjk/100000_median                         -0.0929         -0.0926           162           147           162           147
+
+ src/hb-subset-plan.cc | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit f0c04114bc229b3b519ed2242689959ccec64098
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue May 3 22:02:59 2022 +0000
+
+    [subset] Embed unicode to gid list vector in subset plan.
+
+ src/hb-ot-cmap-table.hh |  2 +-
+ src/hb-subset-plan.cc   | 35 ++++++++++++++++-------------------
+ src/hb-subset-plan.hh   |  2 +-
+ 3 files changed, 18 insertions(+), 21 deletions(-)
+
+commit f67e6bf79cd1ac3892a2d6dfe6e479483290bd41
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 2 16:59:48 2022 -0600
+
+    [perf/benchmark-font] Add benchmark for glyph_h_advance
+
+ perf/benchmark-font.cc | 26 +++++++++++++++++++++++---
+ 1 file changed, 23 insertions(+), 3 deletions(-)
+
+commit 1c0a3d4d16b3ff6864c701fc94aa6878ea82a5c4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 2 16:50:54 2022 -0600
+
+    [perf/benchmark-font] Add a couple Noto fonts
+
+ perf/benchmark-font.cc | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 15fa8afb217582bce4d360c43ad7674861dc1278
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 2 16:46:41 2022 -0600
+
+    Add fast-path for big-endian 32-bit byteswap
+    
+    Speeds up cmap format-12 decoding by some 40% as measured by
+    the newly added test in perf/benchmark-font!
+
+ src/hb-algs.hh | 24 ++++++++++++++++++++----
+ 1 file changed, 20 insertions(+), 4 deletions(-)
+
+commit 3fff2e9182fc6c3cd8ade0336fa67e71967e82c5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 2 16:31:59 2022 -0600
+
+    [perf/benchmark-font] Cosmetic
+
+ perf/benchmark-font.cc  | 2 +-
+ src/hb-ot-cmap-table.hh | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 307d2d8bb6e74ad974207d3b9f706568a6a87e75
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 2 16:30:22 2022 -0600
+
+    [cmap] Sprinkle some 'unlikely's
+
+ src/hb-ot-cmap-table.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit 85ec5cbcefeb2361536031f2e05518c2d817d98a
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon May 2 22:29:43 2022 +0000
+
+    [subset] In _populate_unicodes_to_retain populate unicodes in order.
+    
+    Allows the set insert to take advantage of page lookup cache.
+
+ src/hb-subset-plan.cc | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+commit 0d1f8dcaf3a45dc8ed61dde370df0874af008870
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 2 16:18:53 2022 -0600
+
+    [perf/benchmark-font] Actually make nominal_glyph bench work
+
+ perf/benchmark-font.cc | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+commit 6cf69d10e710cfa7282509c2a43e12618d4673bc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 2 16:07:32 2022 -0600
+
+    [perf/benchmark-font] Add back testing of is_variable
+
+ perf/benchmark-font.cc | 18 +++++++++++-------
+ 1 file changed, 11 insertions(+), 7 deletions(-)
+
+commit 3aa2ff7988583a7c078032e762cd2bde006fc896
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 2 16:01:22 2022 -0600
+
+    [perf/benchmark-font] Fix build without freetype
+
+ perf/benchmark-font.cc | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+commit 58a0988b576f915a21f4171f71d6d2603d6f3414
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 2 15:57:19 2022 -0600
+
+    [perf/benchmark-font] Benchmark get_nominal_glyph
+
+ perf/benchmark-font.cc | 37 ++++++++++++++++++++++++++++++-------
+ 1 file changed, 30 insertions(+), 7 deletions(-)
+
+commit 03f16fab585e57f184642398172bb2e17aa57635
+Merge: a4522df37 6d29903e8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 2 15:44:41 2022 -0600
+
+    Merge pull request #3560 from harfbuzz/perf-cleanup
+    
+    Perf cleanup
+
+commit 088133d939d8bc4ce3d97eed7d835c1831e68766
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon May 2 21:29:16 2022 +0000
+
+    [subset] cache cp to new gid list in subset plan.
+    
+    This avoids having to recompute the ordered list multiple times during cmap generation.
+
+ src/hb-ot-cmap-table.hh |  9 +--------
+ src/hb-subset-plan.cc   | 30 ++++++++++++++++++++++++++++++
+ src/hb-subset-plan.hh   |  1 +
+ 3 files changed, 32 insertions(+), 8 deletions(-)
+
+commit 6d29903e86d1f6b0fe7ca884a071d047f0ee130b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 2 14:03:15 2022 -0600
+
+    [perf/benchmark-font] Parametrize test
+
+ perf/benchmark-font.cc  | 115 +++++++++++++++++++++++++-----------------------
+ perf/benchmark-shape.cc |   2 +
+ 2 files changed, 63 insertions(+), 54 deletions(-)
+
+commit 636c90e81c2eb9a907a1c14d0f3450902d95f65a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 2 13:41:49 2022 -0600
+
+    [perf/perf] Rename to benchmark-font
+
+ perf/Makefile.am                         |  3 +-
+ perf/{perf-draw.hh => benchmark-font.cc} |  0
+ perf/meson.build                         |  7 ++--
+ perf/perf-extents.hh                     | 65 --------------------------------
+ perf/perf.cc                             |  3 --
+ 5 files changed, 4 insertions(+), 74 deletions(-)
+
+commit 036d03d2e91fc20133150696c405d3281326a552
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 2 13:39:54 2022 -0600
+
+    [perf/perf] Move all logic to perf-draw, for now
+    
+    To be renamed.
+
+ perf/Makefile.am  |   1 -
+ perf/perf-draw.hh | 124 +++++++++++++++++++++++++++++++++++++++++-------------
+ perf/perf.cc      |  10 -----
+ 3 files changed, 94 insertions(+), 41 deletions(-)
+
+commit 746c3c03c5017b4e1404c65a04a5a6122a6cd831
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 2 13:26:41 2022 -0600
+
+    [perf/perf] Remove ttf-parser backend
+
+ perf/meson.build     | 11 +------
+ perf/perf-draw.hh    | 91 +++++++++++-----------------------------------------
+ perf/perf-extents.hh | 50 ++++-------------------------
+ perf/perf.cc         |  2 +-
+ 4 files changed, 28 insertions(+), 126 deletions(-)
+
+commit 4aaa0af7d99f7a44a02542ab8a8d467e3f6a3f64
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon May 2 13:06:27 2022 -0600
+
+    [perf/perf] Rely on hb-draw to measure ft performance
+
+ perf/perf-draw.hh | 50 +++++++-------------------------------------------
+ 1 file changed, 7 insertions(+), 43 deletions(-)
+
+commit a4522df378259653f6cdda535980c4acee4d3021
+Merge: 4de5352a3 6922a2561
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 29 18:34:00 2022 -0600
+
+    Merge pull request #3558 from harfbuzz/set-optimize
+    
+    [perf] hb_set_t optimizations and perf suite improvements
+
+commit 6922a2561f75468c328fa158fef289a0b4156d87
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Apr 29 23:30:32 2022 +0000
+
+    [subset] Change serialize_rangeoffset_glyid back to using iterator.
+
+ src/hb-ot-cmap-table.hh | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+commit c66fd50c269a7ab8ab22c404354c783ab5419bcc
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Apr 29 23:18:53 2022 +0000
+
+    [subset] in cmap4 serialization save cp to gid iter to memory.
+    
+    Iterator accesses are slow and it's iterated multiple times.
+
+ src/hb-ot-cmap-table.hh | 21 +++++++++++++--------
+ 1 file changed, 13 insertions(+), 8 deletions(-)
+
+commit 17b98563dc426674d633b79194ce591c8dd38e01
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Apr 29 22:49:02 2022 +0000
+
+    [subset] In cmap4 serialization reduce unnessecary calls into the iterator.
+    
+    Gives ~20% speedup for large subsets.
+
+ src/hb-ot-cmap-table.hh | 30 +++++++++++++++++-------------
+ 1 file changed, 17 insertions(+), 13 deletions(-)
+
+commit 5e241094bfa72840a4142c33264d128b60f12330
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Apr 29 22:44:43 2022 +0000
+
+    [subset] In unicodes cache cleanup if set insert fails.
+
+ src/hb-ot-cmap-table.hh | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit 217d38dfc7b7b1152b74ceb46472bf6a05d35f1a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 29 16:18:17 2022 -0600
+
+    Try to fix distcheck
+
+ Makefile.am      | 15 +--------------
+ configure.ac     |  1 +
+ perf/Makefile.am | 24 ++++++++++++++++++++++++
+ 3 files changed, 26 insertions(+), 14 deletions(-)
+
+commit a424a92ce5e47b35d3128be1a612d3130c4c85b0
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Apr 29 22:14:03 2022 +0000
+
+    [subset] s/void */intptr_t.
+
+ src/hb-ot-cmap-table.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit aad67f5629b1407df1b3152dfce0aefafbfb4132
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Apr 29 22:01:06 2022 +0000
+
+    [subset] cache results of collect_unicodes.
+
+ src/hb-ot-cmap-table.hh | 45 +++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 37 insertions(+), 8 deletions(-)
+
+commit 35681b3edb79b1286f1aa0ece2f6ae99e0363190
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 29 16:02:55 2022 -0600
+
+    [benchmark-shape] Break lines and shape separately
+
+ perf/benchmark-shape.cc | 23 +++++++++++++++++------
+ 1 file changed, 17 insertions(+), 6 deletions(-)
+
+commit be1ac9c57232317647e59983e72b6a86f93151a2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 29 15:55:19 2022 -0600
+
+    [benchmark-shape] Data-driven test sets
+
+ perf/benchmark-shape.cc | 78 ++++++++++++++++++++++++++++---------------------
+ 1 file changed, 44 insertions(+), 34 deletions(-)
+
+commit ae3efc64248f46478fe9ad3863a5dfb0a362fe5f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 29 15:37:11 2022 -0600
+
+    [perf] Spawn off benchmark-shape from perf runner
+
+ perf/{perf-shaping.hh => benchmark-shape.cc} |  2 ++
+ perf/meson.build                             | 10 ++++++++++
+ perf/perf.cc                                 |  1 -
+ 3 files changed, 12 insertions(+), 1 deletion(-)
+
+commit 5f43ce825afbedb1edbbc6610d1c017aa0f5fe27
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 29 13:37:46 2022 -0600
+
+    [benchmark-set] Split SetLookup into an ordered and random version
+
+ perf/benchmark-set.cc | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+commit ae9c7b861b257897a7ff0044d38e70f95df3eec7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 29 13:39:04 2022 -0600
+
+    [benchmark-set] At least increase needle by one in lookup benchmark
+
+ perf/benchmark-set.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 68a9b83d157c2c2ece2c49732f5bf68d843a77a8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 29 13:27:42 2022 -0600
+
+    [benchmark-set] At least increase needle by one in lookup benchmark
+
+ perf/benchmark-set.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b4236b7de6bb2823a4561357342309b0f6d7d264
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Apr 29 19:21:13 2022 +0000
+
+    [subset] Optimize Cmap4 collect_unicodes.
+    
+    Use set add_range() instead of individual add() calls.
+
+ src/hb-ot-cmap-table.hh | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+commit 5866ec05f5a2a613501095e1de64d641ad898021
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 29 13:14:41 2022 -0600
+
+    [benchmark-map] Remove rand() overhead from benchmark
+
+ perf/benchmark-map.cc | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+commit 067225a86d4309020b950661ef9de6cb0c51eb98
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 29 13:04:36 2022 -0600
+
+    [set] Optimize const page_for() using last_page_lookup caching
+    
+    Similar to previous commit.
+    
+    This speeds up SetLookup benchmark by 50%, but that's because that
+    lookup always hits the same page...
+
+ src/hb-bit-set.hh | 24 +++++++++++++++++++-----
+ 1 file changed, 19 insertions(+), 5 deletions(-)
+
+commit c283e41ce39bb3740417bed4f240cf625fb38cd4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 29 12:45:48 2022 -0600
+
+    [set] Optimize non-const page_for() using last_page_lookup caching
+    
+    This speeds up SetOrderedInsert tests by 15 to 40 percent, and the
+    subset_mplus1p benchmarks by 9 to 27 percent.
+
+ src/hb-bit-set.hh | 16 +++++++++++++++-
+ 1 file changed, 15 insertions(+), 1 deletion(-)
+
+commit dd005911b955da49a11aa755acb9addc0c8a2a24
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 29 12:23:53 2022 -0600
+
+    [benchmark-set] Reduce lookup benchmark overhead
+    
+    Turnsout 90% was overhead...  Now lookup is in the 4ns ballpark.
+
+ perf/benchmark-set.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 4de5352a3d4f501b68907fa419a4fed70676e720
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 28 14:40:33 2022 -0600
+
+    [test] Add test
+    
+    From https://github.com/harfbuzz/harfbuzz/issues/3545
+    
+    Dropped the CFF table.
+
+ .../fonts/a59fd13f1525a91cbe529c882e93d9d1fbb80463.ttf   | Bin 0 -> 1180 bytes
+ test/shape/data/in-house/tests/context-matching.tests    |   1 +
+ 2 files changed, 1 insertion(+)
+
+commit d8292b8446b7875281a0d6fc8cb90e96b2f8d156
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 27 12:38:35 2022 -0600
+
+    [CFF] Fix parsing of empty Index
+    
+    https://github.com/harfbuzz/harfbuzz/issues/3545#issuecomment-1111047941
+
+ src/hb-ot-cff-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 6454cec085ba51cefcd12b1f8027bc4a647347d5
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sun Apr 24 11:10:17 2022 -0400
+
+    [USE] Classify U+10A38 as CONS_MOD_BELOW
+
+ src/gen-use-table.py                 | 3 +++
+ src/hb-ot-shape-complex-use-table.hh | 2 +-
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+commit f7aee78e90bc53b3a95eb56d7550c9effe569ea2
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sun Apr 24 05:47:57 2022 +0200
+
+    4.2.1
+
+ NEWS             | 12 ++++++++++++
+ configure.ac     |  2 +-
+ meson.build      |  2 +-
+ src/hb-version.h |  4 ++--
+ 4 files changed, 16 insertions(+), 4 deletions(-)
+
+commit 6695bf056065f2e2e56c0e00b9740e6685a8af28
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Apr 22 13:48:41 2022 -0600
+
+    [gsubgpos] Remove wrong condition in Context application
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3545
+
+ src/hb-ot-layout-gsubgpos.hh | 5 -----
+ 1 file changed, 5 deletions(-)
+
+commit 038203de61d67b56b3426015b449178aa661157a
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Apr 22 01:29:29 2022 +0200
+
+    Remove ABI tracker link
+    
+    Seems dead, no update since 2020.
+
+ README.md | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit c8810277bb004ad4ef1c0b2485c0fdecf39764b9
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Apr 22 01:01:06 2022 +0200
+
+    Update Coverity settings
+
+ .github/workflows/coverity-scan.yml | 6 +++---
+ README.md                           | 2 +-
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit b2d317339a66be756b136d50ad74b328c3acfcec
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Apr 22 00:47:37 2022 +0200
+
+    Update codacy badge
+
+ README.md | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 6a38c83d4f9b285b66177d8d1757744621de23e2
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Apr 22 00:39:45 2022 +0200
+
+    Remove coveralls badge
+    
+    We stopped pushing coveralls builds since 2020.
+
+ README.md | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 392f201047db16cdbc082217c0fb4e9db86a9097
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Apr 21 21:24:58 2022 +0200
+
+    [ci] Pin gcovr to version 5.0
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3540
+
+ .github/workflows/linux-ci.yml | 4 ++--
+ .github/workflows/macos-ci.yml | 4 ++--
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit 4c177de1f597512f61e90039d54afa2f3884eb71
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 21 13:51:37 2022 -0600
+
+    [perf] Err. Remove HUGE font from perf suite
+
+ perf/benchmark-subset.cc        |   2 ++
+ perf/fonts/NotoSansCJKsc-VF.ttf | Bin 36144788 -> 0 bytes
+ 2 files changed, 2 insertions(+)
+
+commit 7f7ebdc6bb73bc24d6aa51f2a2c6b214484f5ee4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 21 11:25:12 2022 -0600
+
+    [perf] Reuse a font
+
+ perf/benchmark-subset.cc       |   2 +-
+ perf/fonts/Mplus1p-Regular.ttf | Bin 1757292 -> 0 bytes
+ 2 files changed, 1 insertion(+), 1 deletion(-)
+
+commit 85142f3247c6ee8cb69006872629cd855f5eeb8f
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Apr 20 22:32:54 2022 +0000
+
+    [perf] Add missing ninja command in profiling instructions.
+
+ perf/README.md | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit a5cf917892f31a7197ea9b58d2938f0cae3aaf9e
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Apr 20 22:31:26 2022 +0000
+
+    [perf] Update readme with profiling instructions.
+
+ perf/README.md | 21 +++++++++++++++++++++
+ 1 file changed, 21 insertions(+)
+
+commit df3ecea773c5f68632e5b4ff0fb5568ce1864272
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 20 16:06:06 2022 -0600
+
+    [perf/perf] Fix run when ttfparser is not available
+
+ perf/perf-draw.hh    | 3 +++
+ perf/perf-extents.hh | 3 +++
+ 2 files changed, 6 insertions(+)
+
+commit f48647e58958e17e8a379c74d2f504f893d4c336
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Apr 20 22:08:33 2022 +0000
+
+    In perf/README update meson command line to set release build type.
+
+ perf/README.md | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b3ce96da3b689dda4910ee72aa3b0f14d73230c7
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Apr 20 21:51:20 2022 +0000
+
+    [perf] Add several more fonts to the subset benchmarks.
+
+ perf/benchmark-subset.cc        |  46 ++++++++++++++++++++++++++--------------
+ perf/fonts/Mplus1p-Regular.ttf  | Bin 0 -> 1757292 bytes
+ perf/fonts/NotoSansCJKsc-VF.ttf | Bin 0 -> 36144788 bytes
+ 3 files changed, 30 insertions(+), 16 deletions(-)
+
+commit 9ad300360d4fd9dee74e9aca65b2878a791cb64f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 20 15:53:37 2022 -0600
+
+    [perf/perf-draw] Port to new draw API
+
+ perf/perf-draw.hh | 27 +++++++++++----------------
+ 1 file changed, 11 insertions(+), 16 deletions(-)
+
+commit 23c7c305bb4a8ba0fc70a7818a81f7af5ab1289d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 20 15:45:37 2022 -0600
+
+    [perf/benchmark-map] Adjust range specifiers
+
+ perf/benchmark-map.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 2b03bcedef6523a2ff3103cd4420561b4a696b6b
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Apr 20 21:34:45 2022 +0000
+
+    [perf] Cleanup range specifiers in set benchmark.
+
+ perf/benchmark-set.cc | 28 ++++++++++++----------------
+ 1 file changed, 12 insertions(+), 16 deletions(-)
+
+commit 178c67003f4554220494ce949723af19582cea7b
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Apr 20 21:19:54 2022 +0000
+
+    [perf] Rework set insert test to not use pause/resume timing.
+    
+    These have high overhead which affect the result. Also change set iteration to time the individual iteration operation.
+
+ perf/benchmark-set.cc    | 52 +++++++++++++++++++++++++++++++++---------------
+ perf/benchmark-subset.cc |  3 +++
+ 2 files changed, 39 insertions(+), 16 deletions(-)
+
+commit fbd183d0eb4aff0c3e790f58788d361d6640430e
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Apr 20 20:05:14 2022 +0000
+
+    [perf] Start writing subset benchmarks.
+
+ perf/benchmark-subset.cc | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
+ perf/meson.build         | 10 +++++++
+ 2 files changed, 80 insertions(+)
+
+commit fc2027bf0709e356f3b66d3bc4edd1e9042e94ee
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Apr 20 19:33:04 2022 +0000
+
+    [perf] Add map benchmarks.
+
+ perf/benchmark-map.cc | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ perf/benchmark-set.cc |  5 ++++
+ perf/meson.build      | 16 +++++++++----
+ 3 files changed, 79 insertions(+), 5 deletions(-)
+
+commit 057ec2c95396ddcaf1820f5c9fa6f7986bb010b3
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Apr 20 19:15:03 2022 +0000
+
+    [perf] Add set ieration and lookup benchmarks.
+
+ perf/benchmark-set.cc | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 48 insertions(+)
+
+commit 40975fc3c233af72d5f5591d957d128793e1c2dc
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Apr 20 18:54:36 2022 +0000
+
+    [perf] Add some instructions for building/running benchmarks.
+
+ perf/README.md | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+commit cef64b947d26c10cbad47ea73e3c9fc9e5c55fc4
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Apr 20 18:36:35 2022 +0000
+
+    [perf] Add the start of a benchmark for set operations.
+
+ perf/benchmark-set.cc | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
+ perf/meson.build      | 15 +++++++++++++++
+ 2 files changed, 64 insertions(+)
+
+commit e8b40c7a09607ecf6e2ce0d9bc32b826a5481ad7
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Apr 20 17:47:02 2022 +0000
+
+    Upgrade google benchmark dep to latest version to fix build failure.
+
+ subprojects/.gitignore            |  2 +-
+ subprojects/google-benchmark.wrap | 16 +++++++++-------
+ 2 files changed, 10 insertions(+), 8 deletions(-)
+
+commit 8575a8f50c25ce96932f94d50425b1d7de8aeb12
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Apr 21 11:14:09 2022 -0600
+
+    Add _hb_codepoint_is_regional_indicator()
+
+ src/hb-ot-shape.cc | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+commit c1ee7d28f3ea476b6e80a82d1485e91a0efc9c3f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 20 13:38:05 2022 -0600
+
+    Typo
+    
+    Co-authored-by: Khaled Hosny <khaled@aliftype.com>
+
+ src/hb-ot-shape.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4d48fae4f247c789612f6a888aba6abf7906f012
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 20 11:35:19 2022 -0600
+
+    Enforce Regional_Indicators native direction to LTR
+    
+    And undo the morx direction reversal change introduced in
+    https://github.com/harfbuzz/harfbuzz/pull/3315
+    23159084b43c1ce429d9e98035bf845919fd8a89
+    
+    This fixes original bug https://github.com/harfbuzz/harfbuzz/issues/3314
+    
+    And the reversion in morx code fixes regressions:
+    https://github.com/harfbuzz/harfbuzz/issues/3528
+    https://github.com/harfbuzz/harfbuzz/issues/3535
+    
+    Supersedes:
+    https://github.com/harfbuzz/harfbuzz/pull/3529
+
+ src/hb-aat-layout-morx-table.hh            |  4 ++--
+ src/hb-ot-shape.cc                         | 19 ++++++++++++++-----
+ test/shape/data/in-house/tests/macos.tests |  8 +++++++-
+ 3 files changed, 23 insertions(+), 8 deletions(-)
+
+commit a85461b9b6367d5ce313c800f9efc6a1ad750616
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 20 12:13:16 2022 -0600
+
+    Add link to Context LookupFlag discussion
+    
+    https://github.com/harfbuzz/harfbuzz/discussions/3538
+
+ src/hb-ot-layout-gsubgpos.hh | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+commit af9eb6850a188a0491fcfd8a379534c5632a0a05
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Wed Apr 20 16:55:31 2022 +0100
+
+    Updated version
+
+ docs/features.dot | 89 +++++++++++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 70 insertions(+), 19 deletions(-)
+
+commit 91e2f3b92a6a21ad462b6ef41bfd6a88f598e965
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Tue Apr 19 15:20:53 2022 +0100
+
+    Add cheat sheet
+
+ docs/features.dot | 208 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 208 insertions(+)
+
+commit 9e59c401e05018eacc09d277251f692a517652c8
+Author: Simon Cozens <simon@simon-cozens.org>
+Date:   Wed Apr 20 16:56:34 2022 +0100
+
+    [myanmar] Reword confusing comment about masks
+
+ src/hb-ot-shape-complex-myanmar.cc | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 383c11d75659540f4d064824f83446389a8334ce
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Apr 19 16:31:44 2022 +0200
+
+    Add test for ligature-id allocation
+    
+    Test for the fix in 7bdc20ec810c14056d6362b076aa6717f10f26a0 for the
+    regression from 43be5ba442548528c89ad31c0927cc68515b736e.
+
+ .../fonts/8339c821814d9bad7c77169332327ad8b0f33c81.ttf   | Bin 0 -> 2312 bytes
+ test/shape/data/in-house/tests/ligature-id.tests         |   1 +
+ 2 files changed, 1 insertion(+)
+
+commit 903cf8cfce631e5e0a5c8941d207dff3e3a59b82
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 13 15:31:51 2022 -0600
+
+    [check-static-inits] Unbreak test
+
+ src/check-static-inits.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ec925ece05f3de0ba49a7712a4a2ebb389c54f70
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Apr 13 11:51:48 2022 -0600
+
+    [khmer] Reinstate a pause after basic features
+    
+    This was removed as part of 044d7a06db552e1564b8575f4d23798f009d9dde,
+    which caused the regression.  Just adding a pause fixes the shaping.
+    Debugged by just tracing the good/bad shaping and observing the
+    lookup orders intermingling in the bad shaping.
+    
+    Test:
+    hb-shape LeelawUI.ttf --unicodes U+1780,U+17D2,U+179A,U+17BB
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3531
+
+ src/hb-ot-shape-complex-khmer.cc | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+commit cc0f1f3b60a920d5da19cc4f2886fd0e74655e8c
+Author: Cosimo Lupo <clupo@google.com>
+Date:   Tue Apr 12 10:45:43 2022 +0100
+
+    Expose --passthrough-tables option to hb-subset CLI tool
+
+ util/hb-subset.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 53eeeab0e39a9079324f8aad39a6ca0f446030e1
+Author: Cosimo Lupo <clupo@google.com>
+Date:   Wed Apr 6 12:54:40 2022 +0100
+
+    CMakeLists.txt: also match 'AppleClang' compiler to not link with libc++
+
+ CMakeLists.txt | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 88bb746b42ca4ae67e5e25cb669b604170d349c6
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Apr 1 02:18:37 2022 +0200
+
+    [blob] Return nullptr from create_from_file_or_fail
+    
+    Fix a couple of cases where it would return empty blob, possibly
+    missed in bdfed8f113431a2156e13d59a4b21e19feb7efd9.
+
+ src/hb-blob.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit b179d357a99884370dd8719d71ae87ca6dca33d7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Mar 30 12:59:52 2022 -0600
+
+    [main] Fix unused-variable warnings
+
+ src/main.cc | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+commit 9d5730b958974bc9db95e46e6bad52e9e9cd6e1c
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Mar 30 15:08:34 2022 +0200
+
+    4.2.0
+
+ NEWS                   | 22 +++++++++++++++++++++-
+ configure.ac           |  2 +-
+ docs/harfbuzz-docs.xml |  1 +
+ meson.build            |  2 +-
+ src/hb-set.cc          |  2 +-
+ src/hb-version.h       |  4 ++--
+ 6 files changed, 27 insertions(+), 6 deletions(-)
+
+commit ecb3e7ec929aac83d4b4cef065bd87e0be400660
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Mon Mar 28 19:42:04 2022 -0400
+
+    Enable indic-feature-order.tests
+
+ test/shape/data/in-house/Makefile.sources | 1 +
+ test/shape/data/in-house/meson.build      | 1 +
+ 2 files changed, 2 insertions(+)
+
+commit 044d7a06db552e1564b8575f4d23798f009d9dde
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Mar 28 12:38:56 2022 -0600
+
+    [indic-like] Add per-lookup per-syllable flag
+    
+    This allows mix-and-matching per-syllable and other lookups.
+    In fact, removes the clear-syllables call completely.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3513
+
+ src/hb-ot-layout-gsubgpos.hh                       |  13 +++++--
+ src/hb-ot-layout.cc                                |   1 +
+ src/hb-ot-layout.hh                                |  11 ------
+ src/hb-ot-map.cc                                   |   8 +++--
+ src/hb-ot-map.hh                                   |   8 +++--
+ src/hb-ot-shape-complex-indic.cc                   |  40 ++++++++++-----------
+ src/hb-ot-shape-complex-khmer.cc                   |  22 +++++-------
+ src/hb-ot-shape-complex-myanmar.cc                 |   8 ++---
+ src/hb-ot-shape-complex-use.cc                     |  15 ++++----
+ .../41071178fbce4956d151f50967af458dbf555f7b.ttf   | Bin 0 -> 3216 bytes
+ .../shape/data/in-house/tests/indic-syllable.tests |   1 +
+ 11 files changed, 61 insertions(+), 66 deletions(-)
+
+commit 61486746d3d8937c2b656c3ba72bd666fadef76c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Mar 28 15:57:07 2022 -0600
+
+    Revert "[indic] Clear syllables before presentation features"
+    
+    This reverts commit 90f09b1e877dc6edf63fc4ac2b397ef4e5c92083.
+    
+    This regressed Indic shaping. See:
+    https://github.com/harfbuzz/harfbuzz/issues/3513
+
+ src/hb-ot-shape-complex-indic.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 18c0290cf50eaa4bc5db62678f26c11a1409292f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Mar 28 13:24:16 2022 -0600
+
+    Add test for previous commit
+
+ test/shape/data/in-house/tests/macos.tests | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit e8f3397f4ef0db9700eb28f1b6843ba7e80e373e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Mar 28 12:07:05 2022 -0600
+
+    [matcher] Simplify syllable initialization
+
+ src/hb-ot-layout-gsubgpos.hh | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+commit 94f5c630fc07e6aa653ac552b90444f9e7ea7c7f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Mar 28 11:25:44 2022 -0600
+
+    [aat] Remove morx deleted-glyphs before GPOS processing
+    
+    Fixes new Apple Color Emoji glyphs sequences rendering.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3512
+
+ src/hb-ot-shape.cc | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+commit 0dcbdbde9cff68384bb3a5b9847283ca0676e54a
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Mar 26 20:56:50 2022 -0400
+
+    [indic] Categorize U+0D04 as Consonant_Placeholder
+
+ src/hb-ot-shape-complex-indic.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit a665e29ed71602dc37fbb987f0de6806bcc7d710
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Mar 23 17:30:25 2022 -0600
+
+    [use] Avoid O(n^2) in the machine
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3502
+
+ src/hb-ot-shape-complex-use-machine.hh             |  36 ++++++++++++++-------
+ src/hb-ot-shape-complex-use-machine.rl             |  22 ++++++++++---
+ ...rfuzz-testcase-hb-shape-fuzzer-5446125635633152 | Bin 0 -> 655 bytes
+ 3 files changed, 43 insertions(+), 15 deletions(-)
+
+commit ccd9161bfd08b644d2563b58f353ee7fea97608d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Mar 24 13:10:48 2022 -0600
+
+    [apply-lookup] Try to fix the logic for contextual lookups
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/1611
+    
+    Notably, this fixes Myles's AdditionFont:
+    https://litherum.blogspot.com/2019/03/addition-font.html
+    
+    Test with AdditionFont, eg.:
+    $ util/hb-view AdditionFont.otf =1112112+1113134=
+
+ src/hb-ot-layout-gsubgpos.hh                       |  22 ++++++++++++++-------
+ .../5bbf3712e6f79775c66a4407837a90e591efbef2.ttf   | Bin 0 -> 6400 bytes
+ .../data/in-house/tests/context-matching.tests     |   1 +
+ 3 files changed, 16 insertions(+), 7 deletions(-)
+
+commit fa15fc44bbf17ae417021f92552b9f04a5c1a69e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Mar 25 15:00:11 2022 -0600
+
+    [subset] Require exact harfbuzz version in .pc file
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/1446
+
+ src/harfbuzz-subset.pc.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b619b05f39509b0a4805d844636a31a9183d5dd4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Mar 25 14:56:55 2022 -0600
+
+    [subset] Adjust name in .pc file
+
+ src/harfbuzz-subset.pc.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 122907866036e4ad03ddeefe0fe07a28e559fe8e
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Mar 25 22:41:25 2022 +0200
+
+    [set] Fix annotation
+
+ src/hb-set.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3a78cf92c83c6f05154e42e8f7b17bd8bc93f1d6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Mar 25 12:56:44 2022 -0600
+
+    [gvar] Fix decoding of private vs shared points
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3506
+
+ src/hb-ot-var-gvar-table.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit a02fb4a0dcafce485b0db07fee58a12b7adee83a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Mar 25 12:56:19 2022 -0600
+
+    [glyf] Don't bail rendering glyf even if gvar failed
+    
+    Part of https://github.com/harfbuzz/harfbuzz/issues/3506
+
+ src/hb-ot-glyf-table.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 0a38878549968e1d636a6d878c55d4efe76ce9fc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Mar 25 09:42:36 2022 -0600
+
+    [set] Minor touch-up on the previous commit
+
+ docs/harfbuzz-sections.txt   |  1 +
+ src/hb-bit-set-invertible.hh | 10 +++++-----
+ src/hb-bit-set.hh            | 12 ++++++------
+ src/hb-set.cc                |  6 +++---
+ src/hb-set.hh                |  4 ++--
+ 5 files changed, 17 insertions(+), 16 deletions(-)
+
+commit a003fc0df1a2dad57e18c1be8b40591dfbcc9547
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Mar 25 09:37:50 2022 -0600
+
+    Remove accidental files
+
+ test/subset/__pycache__/repack_test.cpython-39.pyc       | Bin 1299 -> 0 bytes
+ test/subset/__pycache__/subset_test_suite.cpython-39.pyc | Bin 3501 -> 0 bytes
+ 2 files changed, 0 insertions(+), 0 deletions(-)
+
+commit 0182988229591476eea1606dde0d78a1864ca017
+Author: Andrew John <45769922+andyjgf@users.noreply.github.com>
+Date:   Fri Mar 25 08:36:44 2022 -0700
+
+    [set] Add call to export set contents to an array. (#3500)
+    
+    [set] Add hb_set_next_many.
+
+ src/hb-bit-page.hh                                 |  69 ++++++++++++-
+ src/hb-bit-set-invertible.hh                       |   8 ++
+ src/hb-bit-set.hh                                  |  94 +++++++++++++++++
+ src/hb-set.cc                                      |  25 +++++
+ src/hb-set.h                                       |   6 ++
+ src/hb-set.hh                                      |   3 +
+ test/api/test-set.c                                | 111 +++++++++++++++++++++
+ test/subset/__pycache__/repack_test.cpython-39.pyc | Bin 0 -> 1299 bytes
+ .../__pycache__/subset_test_suite.cpython-39.pyc   | Bin 0 -> 3501 bytes
+ 9 files changed, 315 insertions(+), 1 deletion(-)
+
+commit a55a42444d0578125425c3fe64d5f8172c508f44
+Author: aneejit1 <100675750+aneejit1@users.noreply.github.com>
+Date:   Thu Mar 24 20:16:41 2022 +0000
+
+     Meson build writes to the source directory (issue #3507 ) (#3508)
+    
+    Don't write to source directory if files did not change
+    
+    Remove writes to the source directory which cause a meson build failure
+    if the source directory is read-only.
+    
+    https://github.com/harfbuzz/harfbuzz/pull/3508
+
+ src/gen-harfbuzzcc.py | 8 ++++++--
+ src/gen-hb-version.py | 8 ++++++--
+ 2 files changed, 12 insertions(+), 4 deletions(-)
+
+commit bf2a845a17ef7b45867c38f9b7c041e4c479d340
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Mar 24 13:09:53 2022 -0600
+
+    [ot-layout] Comment
+
+ src/hb-ot-layout-gsubgpos.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a792e16e48188f67d38768c1d25ac5d7f26ec607
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Mar 24 13:08:51 2022 -0600
+
+    [ot-layout] Change max nesting level of lookups from 6 to 64
+
+ src/hb-ot-layout-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f76ffa8374799b5acb16a0e25d72ae80d4d3f964
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Mar 24 06:23:22 2022 +0200
+
+    [build] Change how platform shaper tests are enable
+    
+    Run the tests unconditionally and skip if the shaper is not available.
+    This fixes distcheck (https://github.com/harfbuzz/harfbuzz/pull/3504)
+    and shows SKIP for these tests instead of ignoring them.
+
+ test/shape/data/in-house/Makefile.am      | 14 +++++++++++---
+ test/shape/data/in-house/Makefile.sources | 13 +++----------
+ test/shape/data/in-house/meson.build      | 17 ++++-------------
+ test/shape/meson.build                    | 14 +++-----------
+ test/shape/run-tests.py                   | 17 ++++++++++++++++-
+ 5 files changed, 37 insertions(+), 38 deletions(-)
+
+commit 38575c9042f8c4e7ea03260671b705c0dbf505fe
+Merge: 444c2375a eb44d64bc
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Mar 24 05:51:22 2022 +0200
+
+    Merge pull request #3504 from fanc999/dist-plat-shaper-tests
+    
+    test: Dist the platform shaper test data
+
+commit eb44d64bc25c10028d3d44aa93c5507d217bd193
+Author: Chun-wei Fan <fanchunwei@src.gnome.org>
+Date:   Thu Mar 24 10:52:48 2022 +0800
+
+    test: Dist the platform shaper test data
+    
+    For builds from release tarballs, the tests fail in the DirectWrite and
+    Uniscribe tests when these platform shapers are enabled, since the data files
+    were not found in the source tree, when building with Meson at least.
+    
+    Fix this by dist'ing the platform shaper test data files.
+
+ test/shape/data/in-house/Makefile.sources | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+commit 444c2375a155500248d21ed074fffd353304a1d3
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Mar 23 16:49:13 2022 -0700
+
+    [reorg] Use relative includes for hb-ot-layout-gsubgpos.hh
+
+ src/OT/Layout/GSUB/ChainContextSubst.hh | 2 +-
+ src/OT/Layout/GSUB/ContextSubst.hh      | 2 +-
+ src/OT/Layout/GSUB/ExtensionSubst.hh    | 2 +-
+ src/OT/Layout/GSUB/GSUB.hh              | 2 +-
+ 4 files changed, 4 insertions(+), 4 deletions(-)
+
+commit b342adeb96148570d71d5e0eb07436eb7d53b5e7
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Mar 23 16:28:22 2022 -0700
+
+    [reorg] Move GSUB into OT::Layout::GSUB namespace.
+
+ src/OT/Layout/GSUB/GSUB.hh | 15 +++++++--------
+ src/hb-ot-layout.cc        |  8 +++++---
+ src/hb-subset-plan.cc      |  4 +++-
+ src/hb-subset.cc           |  4 +++-
+ 4 files changed, 18 insertions(+), 13 deletions(-)
+
+commit a9910e258fe2d8f782ccb3594b79f9d150e60e08
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Mar 23 16:09:41 2022 -0700
+
+    [reorg] Move SubstLookup and GSUB into the new layout.
+
+ src/Makefile.sources                      |   6 +
+ src/OT/Layout/GSUB/ChainContextSubst.hh   |  18 ++
+ src/OT/Layout/GSUB/ContextSubst.hh        |  18 ++
+ src/OT/Layout/GSUB/ExtensionSubst.hh      |  22 ++
+ src/OT/Layout/GSUB/GSUB.hh                |  59 ++++++
+ src/OT/Layout/GSUB/SubstLookup.hh         | 224 ++++++++++++++++++++
+ src/OT/Layout/GSUB/SubstLookupSubTable.hh |  77 +++++++
+ src/hb-ot-layout-gsub-table.hh            | 332 +-----------------------------
+ src/hb-ot-layout.hh                       |   8 +-
+ src/meson.build                           |   6 +
+ 10 files changed, 440 insertions(+), 330 deletions(-)
+
+commit 90af2143d58947b4ed82ff6c9b86bc483d3a58bb
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Mar 23 15:28:29 2022 -0700
+
+    [reorg] Move ReverseChainSingleSubst to new layout.
+
+ src/Makefile.sources                               |   2 +
+ src/OT/Layout/GSUB/ReverseChainSingleSubst.hh      |  36 ++++
+ .../Layout/GSUB/ReverseChainSingleSubstFormat1.hh  | 228 ++++++++++++++++++++
+ src/hb-ot-layout-gsub-table.hh                     | 239 +--------------------
+ src/meson.build                                    |   2 +
+ 5 files changed, 270 insertions(+), 237 deletions(-)
+
+commit 403feb3804cb61a73c32ff2c87659fd49900fe4f
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Mar 23 15:19:04 2022 -0700
+
+    [reorg] Move LigatureSubst to new layout.
+
+ src/Makefile.sources                       |   4 +
+ src/OT/Layout/GSUB/Ligature.hh             | 135 ++++++++++
+ src/OT/Layout/GSUB/LigatureSet.hh          | 118 ++++++++
+ src/OT/Layout/GSUB/LigatureSubst.hh        |  59 ++++
+ src/OT/Layout/GSUB/LigatureSubstFormat1.hh | 165 ++++++++++++
+ src/hb-ot-layout-gsub-table.hh             | 420 +----------------------------
+ src/meson.build                            |   4 +
+ 7 files changed, 487 insertions(+), 418 deletions(-)
+
+commit 6a369389d6cb8de126141cfe71f3c6bc0faedd15
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Mar 23 15:04:11 2022 -0700
+
+    [reorg] Move AlternateSubst to new layout.
+
+ src/Makefile.sources                        |   3 +
+ src/OT/Layout/GSUB/AlternateSet.hh          | 110 +++++++++++++
+ src/OT/Layout/GSUB/AlternateSubst.hh        |  51 ++++++
+ src/OT/Layout/GSUB/AlternateSubstFormat1.hh | 128 ++++++++++++++
+ src/hb-ot-layout-gsub-table.hh              | 247 +---------------------------
+ src/meson.build                             |   3 +
+ 6 files changed, 297 insertions(+), 245 deletions(-)
+
+commit dea0681db2cca618e58b27a471863ff42f43bb31
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Mar 23 14:48:58 2022 -0700
+
+    [reorg] Move MultipleSubst into new layout.
+
+ src/Makefile.sources                       |   3 +
+ src/OT/Layout/GSUB/MultipleSubst.hh        |  53 +++++++
+ src/OT/Layout/GSUB/MultipleSubstFormat1.hh | 120 +++++++++++++++
+ src/OT/Layout/GSUB/Sequence.hh             | 103 +++++++++++++
+ src/hb-ot-layout-gsub-table.hh             | 229 +----------------------------
+ src/meson.build                            |   3 +
+ 6 files changed, 284 insertions(+), 227 deletions(-)
+
+commit 7243bf3e4119bf73d31de2252003a5fc4b2ed6d8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 26 08:26:50 2022 -0700
+
+    [reorg] Use relative include
+
+ src/OT/Layout/GSUB/Common.hh             | 3 ++-
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 1 -
+ src/OT/Layout/GSUB/SingleSubstFormat2.hh | 1 -
+ 3 files changed, 2 insertions(+), 3 deletions(-)
+
+commit c180f93766cbeec4e516800e9cbf956b740e4779
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jan 26 08:22:40 2022 -0700
+
+    [reorg] Move sanitize/dispatch and size macros to top
+
+ src/OT/Layout/GSUB/SingleSubst.hh        | 39 ++++++++++++++++----------------
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 16 ++++++-------
+ src/OT/Layout/GSUB/SingleSubstFormat2.hh | 16 ++++++-------
+ 3 files changed, 34 insertions(+), 37 deletions(-)
+
+commit f577d02f4a750e462814d385e416c9fd45986d1e
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jan 20 14:39:48 2022 -0800
+
+    [reorg] Fix check-* scripts to work with sources files in directories.
+
+ src/Makefile.sources                     |  4 ++++
+ src/OT/Layout/GSUB/Common.hh             |  6 +++---
+ src/OT/Layout/GSUB/SingleSubst.hh        |  6 +++---
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh |  6 +++---
+ src/OT/Layout/GSUB/SingleSubstFormat2.hh |  6 +++---
+ src/check-c-linkage-decls.py             | 14 +++++++++++---
+ src/check-header-guards.py               | 19 +++++++++++++++----
+ src/check-includes.py                    | 17 ++++++++++++++---
+ 8 files changed, 56 insertions(+), 22 deletions(-)
+
+commit 3ef180db4492a38f6a9f8d91505828f85d43960b
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jan 13 15:22:55 2022 -0800
+
+    [reorg] Move SingleSubst opentype fields to top of the classes.
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 17 ++++++++++-------
+ src/OT/Layout/GSUB/SingleSubstFormat2.hh | 23 +++++++++++++----------
+ 2 files changed, 23 insertions(+), 17 deletions(-)
+
+commit 7dfd9e700190fbe00314bfc61f691953320829e3
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jan 13 14:17:51 2022 -0800
+
+    [reorganization] WIP move single substitution into separate files.
+
+ src/OT/Layout/GSUB/Common.hh             |  20 +++
+ src/OT/Layout/GSUB/SingleSubst.hh        |  74 ++++++++
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 122 ++++++++++++++
+ src/OT/Layout/GSUB/SingleSubstFormat2.hh | 120 +++++++++++++
+ src/hb-ot-layout-gsub-table.hh           | 280 +------------------------------
+ src/meson.build                          |   4 +
+ 6 files changed, 345 insertions(+), 275 deletions(-)
+
+commit c36844d6d923bfc765f841fde10d6f505ff297fd
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Mar 23 07:20:59 2022 +0200
+
+    4.1.0
+
+ NEWS                   | 14 ++++++++++++++
+ configure.ac           |  2 +-
+ docs/harfbuzz-docs.xml |  1 +
+ meson.build            |  2 +-
+ src/hb-set.cc          |  2 +-
+ src/hb-version.h       |  6 +++---
+ 6 files changed, 21 insertions(+), 6 deletions(-)
+
+commit 0fec8ad8482bbbcc134a1f16b315a5a72acacb59
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Mar 22 13:44:22 2022 -0600
+
+    Remove old TODO file
+
+ TODO | 28 ----------------------------
+ 1 file changed, 28 deletions(-)
+
+commit d35c73cd3766953ad6f07ba8e83159868141635c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Mar 22 10:20:28 2022 -0600
+
+    [buffer] Whitespace
+
+ src/hb-buffer.cc | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 280355b31f15528c1690fca035bd68317b0bbaf8
+Merge: f41945e31 36b8f9741
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Mar 21 22:03:00 2022 -0600
+
+    Merge pull request #3497 from harfbuzz/vertical-origin
+    
+    [ot-font] Fix vertical-origin fallback to match FreeType
+
+commit 36b8f97413a1edcded818b3b14fee45fc320e6b5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Mar 21 21:50:04 2022 -0600
+
+    Update tests for recent changes
+
+ test/api/test-ot-metrics-tt-var.c                  |  4 +--
+ test/shape/data/in-house/tests/collections.tests   |  6 ++--
+ .../data/in-house/tests/indic-decompose.tests      |  2 +-
+ test/shape/data/in-house/tests/spaces.tests        | 34 +++++++++++-----------
+ test/shape/data/in-house/tests/vertical.tests      |  2 +-
+ 5 files changed, 24 insertions(+), 24 deletions(-)
+
+commit 1449498e1df3ea7497c7417f2278b14c50278b1c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Mar 21 21:40:07 2022 -0600
+
+    [ot-font] Vertically center glyph in vertical writing fallback
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/537
+
+ src/hb-ot-font.cc | 19 ++++++++++++++-----
+ 1 file changed, 14 insertions(+), 5 deletions(-)
+
+commit bf03d7e962ec831d720efcfa33e5397bbbaa1ec4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Mar 21 21:27:31 2022 -0600
+
+    [ot-font] Use ascent+descent for fallback vertical advance
+    
+    This matches what FreeType does.
+    
+    Part of fixing https://github.com/harfbuzz/harfbuzz/issues/537
+
+ src/hb-ot-font.cc | 22 ++++++++++++++++++----
+ 1 file changed, 18 insertions(+), 4 deletions(-)
+
+commit df42d28d18598d893d4d8e5458b246010058dea7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Mar 21 21:17:15 2022 -0600
+
+    [hmtx] Change default advance for horizontal direction to upem/2 again
+
+ src/hb-ot-hmtx-table.hh | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+commit 6d0e67dee09d1232f86671b362b04b05ecb0a18f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Mar 21 21:07:11 2022 -0600
+
+    [ot-font] Only use vmtx side-bearing if table exists
+    
+    Part of fixing https://github.com/harfbuzz/harfbuzz/issues/537
+
+ src/hb-ft.cc            | 1 +
+ src/hb-ot-font.cc       | 3 ++-
+ src/hb-ot-hmtx-table.hh | 2 ++
+ 3 files changed, 5 insertions(+), 1 deletion(-)
+
+commit f41945e313ca053253bfd339186b87c977da3bf3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Mar 21 18:24:30 2022 -0600
+
+    [cmap] In collect_unicodes() of format 12/13, limit to max Unicode
+    
+    Fixes fuzzer timeout:
+    https://oss-fuzz.com/testcase-detail/5062368881672192
+
+ src/hb-ot-cmap-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 03085132bac6bb3f69378cab3eaf5a57ad1362ff
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Mar 21 18:06:33 2022 -0600
+
+    [buffer] Fix out-buffer under memory-alloc failure
+    
+    This was broken in July refactoring of the buffer, and exposed to
+    ReverseChainSingleSubstFormat1 in 3807061d634b60bd6235d6e1d8c47a034377f924
+    
+    Fixes:
+    https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=38800
+    https://bugs.chromium.org/p/chromium/issues/detail?id=1303552
+
+ src/hb-buffer.cc                                         |   1 +
+ ...z-testcase-minimized-hb-shape-fuzzer-5349416110784512 | Bin 0 -> 1603 bytes
+ 2 files changed, 1 insertion(+)
+
+commit 116cc6923601d088f6886ef6f535346885c45a7b
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Mar 22 00:11:26 2022 +0200
+
+    [set] Fix documentation
+
+ docs/harfbuzz-sections.txt | 2 +-
+ src/hb-set.cc              | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 98b4852434e5b7583aeb03069efad83caa224a37
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Mon Mar 21 17:17:39 2022 -0400
+
+    [indic] Test clearing syllables earlier
+
+ .../fonts/190a621e48d4af1fffd8144bd41d2027e9a32fbf.ttf   | Bin 0 -> 1320 bytes
+ test/shape/data/in-house/tests/indic-feature-order.tests |   1 +
+ 2 files changed, 1 insertion(+)
+
+commit 90f09b1e877dc6edf63fc4ac2b397ef4e5c92083
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Mar 21 10:24:23 2022 -0600
+
+    [indic] Clear syllables before presentation features
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3488
+
+ src/hb-ot-shape-complex-indic.cc | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 4289684cdbbe5fbfa394bc3ce568eb8f27f404f4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Mar 21 15:37:05 2022 -0600
+
+    [set] Fix-up previous commits
+
+ docs/harfbuzz-sections.txt |  1 +
+ src/hb-set.cc              | 10 ++++++++--
+ src/hb-set.h               | 10 +++++-----
+ 3 files changed, 14 insertions(+), 7 deletions(-)
+
+commit 1176620ba4e788d40a2be8d33c2647bc5aba9c82
+Author: Andy John <andyj@google.com>
+Date:   Mon Mar 21 14:31:47 2022 -0700
+
+    Move fn, fix doc.
+
+ src/hb-set.cc | 33 +++++++++++++++++----------------
+ 1 file changed, 17 insertions(+), 16 deletions(-)
+
+commit 7d802994be2cc53e5e7fcd90e2eaa9fa497cd12a
+Author: Andy John <andyj@google.com>
+Date:   Mon Mar 21 13:55:34 2022 -0700
+
+    Remove null checks.
+
+ src/hb-set.cc | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit ef588ea97bee45b0ca5bb771c3646f79d5ee7c74
+Author: Andy John <andyj@google.com>
+Date:   Mon Mar 21 13:29:22 2022 -0700
+
+    Add option to insert a sorted arrays of values to sets.
+
+ src/hb-bit-set.hh   |  4 ++--
+ src/hb-set.cc       | 18 ++++++++++++++++++
+ src/hb-set.h        |  5 +++++
+ test/api/test-set.c | 19 +++++++++++++++++++
+ 4 files changed, 44 insertions(+), 2 deletions(-)
+
+commit 7a1e79c3ba3d8bf0dec93907396953aa96393be3
+Author: Andy John <andyj@google.com>
+Date:   Mon Mar 21 13:18:04 2022 -0700
+
+    Fix typo.
+
+ src/hb-bit-set.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 4ee00f943f4fde9418c21804a263f902557e76dc
+Author: Andy John <andyj@google.com>
+Date:   Mon Mar 21 13:16:28 2022 -0700
+
+    Use bit shifting instead of multiplying and dividing.
+
+ src/hb-bit-set.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 3125f5ae3348a81e20067e55093644d8669d1f16
+Author: Andy John <andyj@google.com>
+Date:   Mon Mar 21 13:12:14 2022 -0700
+
+    Add log base 2 versions of constants.
+
+ src/hb-bit-page.hh | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit 1ffe637a0e36577b18e1708c252749fcbcb08754
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Mar 21 10:37:42 2022 -0600
+
+    [coretext] Remove dead code
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3484
+
+ src/hb-coretext.cc | 18 +-----------------
+ 1 file changed, 1 insertion(+), 17 deletions(-)
+
+commit 7bdc20ec810c14056d6362b076aa6717f10f26a0
+Author: TheBluuDot <62665768+TheBluuDot@users.noreply.github.com>
+Date:   Sat Mar 19 17:47:04 2022 +0500
+
+    restores unintended addition in 43be5ba
+    
+    restores two lines in restore in _hb_allocate_lig_id function that were unintentionally deleted in 43be5ba
+
+ src/hb-ot-layout.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 7cb002cb58d4e3f17fcab174e400c0292880c059
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Mon Mar 14 11:40:35 2022 -0700
+
+    [subset] bug fix in prune_langsys
+    
+    we should not cache visited langsys cause 2 different Record<Langsys>
+    could have different Tag while pointing to the same Langsys, a langsys
+    is redundant in Record<Langsys> A does not mean it's redundant in Record
+    B. Same thing for visited_script.
+    Also adding the number of features in the LangSys's feature list to the
+    visited langsys count so it's more accurate.
+    Plus some improvement in langsys compare()
+
+ src/hb-ot-layout-common.hh                         |  59 ++++++++-------------
+ ...ar.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 4800 bytes
+ ...drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 2452 bytes
+ ...an.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 9704 bytes
+ ...drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 9704 bytes
+ test/subset/data/tests/full-font.tests             |   1 +
+ 6 files changed, 23 insertions(+), 37 deletions(-)
+
+commit cad2fe8e639f53fee4b0ae6ff0389ef9ed028143
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Mar 15 10:49:29 2022 -0600
+
+    [baseline] Fix HB_NO_METRICS build
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3482
+
+ src/hb-ot-layout.cc | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit a8a89b80b406cef53e6dd8e411a49d75ed04cda9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Mar 15 10:48:03 2022 -0600
+
+    [layout] Whitespace
+
+ src/hb-ot-layout.cc | 120 ++++++++++++++++++++++++++--------------------------
+ 1 file changed, 60 insertions(+), 60 deletions(-)
+
+commit 21f5ef56f53247958c6c346ac5205a96f6de0c66
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Mar 15 10:45:50 2022 -0600
+
+    [metrics] Simplify x-height fallback
+
+ src/hb-ot-metrics.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 6bf8f0a38fdb43ef9593eedabd7deba6064df44b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Mar 15 10:44:41 2022 -0600
+
+    [baseline] Use ot-metrics fallback API
+
+ src/hb-ot-layout.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 965cf1d66589b0db60e75961cc58f5a65521078e
+Author: Dominik Röttsches <drott@chromium.org>
+Date:   Mon Mar 14 12:48:18 2022 +0000
+
+    Make load_num_glyphs_from_loca conditional on HB_NO_BORING_EXPANSION
+    
+    Fixes build errors complaining about this function being unused.
+
+ src/hb-static.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 49fb8f9072ae07c6df0ff0067f005e3aaa1ac26b
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sun Mar 13 15:01:11 2022 -0400
+
+    [USE] Treat visible viramas like dependent vowels
+
+ src/gen-use-table.py                               |  17 +-
+ src/hb-ot-shape-complex-use-machine.hh             | 865 +++++++++++----------
+ src/hb-ot-shape-complex-use-machine.rl             |  10 +-
+ src/hb-ot-shape-complex-use-table.hh               |  28 +-
+ src/hb-ot-shape-complex-use.cc                     |   2 +-
+ .../23406a60ab081c4fb15e1596ea1cd4f27ae8443e.ttf   | Bin 0 -> 1400 bytes
+ test/shape/data/in-house/tests/use-syllable.tests  |   1 +
+ test/shape/data/in-house/tests/use.tests           |   1 +
+ 8 files changed, 491 insertions(+), 433 deletions(-)
+
+commit 1f79ba9407ecd54e382997940cbcc3fb71bef8be
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Mar 11 20:19:04 2022 +0200
+
+    4.0.1
+
+ NEWS             | 20 ++++++++++++++++++++
+ configure.ac     |  2 +-
+ meson.build      |  2 +-
+ src/hb-version.h |  4 ++--
+ 4 files changed, 24 insertions(+), 4 deletions(-)
+
+commit a34eea301387f95d34f646b93fc8fc2027f0b0a4
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Mar 11 19:57:53 2022 +0200
+
+    [doc] Add experimental repacker API to private section
+    
+    Hides the warning about them until they are no longer experimental.
+
+ docs/harfbuzz-sections.txt | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit a35757c6bc3a792791c0714d143f47537d7ec110
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Feb 2 10:30:34 2022 -0800
+
+    [repacker] expose hb_subset_repack() API, hb_object_t and hb_link_t structs
+
+ src/Makefile.sources                 |   2 +
+ src/gen-def.py                       |   2 +-
+ src/hb-repacker.hh                   |  19 +--
+ src/hb-serialize.hh                  |  35 ++++++
+ src/hb-subset-repacker.cc            |  49 ++++++++
+ src/hb-subset-repacker.h             |  80 +++++++++++++
+ src/meson.build                      |   6 +-
+ test/api/Makefile.am                 |   2 +
+ test/api/fonts/repacker_expected.otf | Bin 0 -> 1400 bytes
+ test/api/meson.build                 |   1 +
+ test/api/test-subset-repacker.c      | 225 +++++++++++++++++++++++++++++++++++
+ 11 files changed, 411 insertions(+), 10 deletions(-)
+
+commit e7ab42b24618df6fbf6263dfe8aa964c843a006e
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Thu Mar 10 09:05:43 2022 -0500
+
+    [layout] Fix handling of baseline variations
+    
+    For BASE table format 1.1, the handling of design
+    space vs user space coordinates was inconsistent.
+    We were applying design -> user transformation
+    twice for the deltas, leading to wrong baseline
+    values.
+    
+    Patch by Ebrahim Byagowi <ebrahim@gnu.org>
+    
+    Fixes: #3476
+
+ src/hb-ot-layout-base-table.hh | 20 ++++++++++++--------
+ src/hb-ot-layout.cc            |  7 +------
+ 2 files changed, 13 insertions(+), 14 deletions(-)
+
+commit e5707a440caf9e4102c6e580084b35248b27dbfb
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Wed Mar 2 21:30:22 2022 -0500
+
+    Update IANA Language Subtag Registry to 2022-03-02
+
+ src/hb-ot-tag-table.hh | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+commit 13bb46cfd52c8791077779fc9ffa60547a22f022
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sun Mar 6 15:35:31 2022 -0500
+
+    [USE] Remove obsolete overrides
+
+ src/gen-use-table.py | 20 ++------------------
+ 1 file changed, 2 insertions(+), 18 deletions(-)
+
+commit c33468d48ec8b49971232b457605298c28fd6d5b
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sun Mar 6 12:26:37 2022 -0500
+
+    [USE] Treat all gc=Cn as independent clusters
+
+ src/gen-use-table.py                 |  69 ++---
+ src/hb-ot-shape-complex-use-table.hh | 499 ++++++++++++++++++-----------------
+ src/hb-ot-shape-complex-use.cc       |   2 +-
+ 3 files changed, 290 insertions(+), 280 deletions(-)
+
+commit e497a8f142f127c6a8d52cf854352e3eb2e6ed95
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sun Mar 6 11:36:43 2022 -0500
+
+    [USE] Remove obsolete symbol/punctuation overrides
+
+ src/gen-use-table.py                 | 11 -----------
+ src/hb-ot-shape-complex-use-table.hh |  8 ++++----
+ 2 files changed, 4 insertions(+), 15 deletions(-)
+
+commit 854219e05675bfb380005e2e156bd025e56c1530
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Sat Mar 5 10:46:31 2022 -0500
+
+    [USE] Simplify `not_ccs_default_ignorable`
+
+ src/hb-ot-shape-complex-use-machine.hh | 2 +-
+ src/hb-ot-shape-complex-use-machine.rl | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 6e059a46b79894f85cef01f168b5da7f29ffe3ff
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Fri Mar 4 19:18:40 2022 -0500
+
+    [USE] Allow any non-numeric tail in symbol cluster
+
+ src/hb-ot-shape-complex-use-machine.hh | 647 +++++++++++++++++++++------------
+ src/hb-ot-shape-complex-use-machine.rl |   5 +-
+ src/hb-ot-shape-complex-use.cc         |   3 +-
+ 3 files changed, 428 insertions(+), 227 deletions(-)
+
+commit 5b0a59812d97104ec24de8b3658cfca6ce872a27
+Author: David Corbett <corbett.dav@northeastern.edu>
+Date:   Fri Mar 4 20:45:30 2022 -0500
+
+    [USE] Restore the category WJ
+
+ src/gen-use-table.py                              |  11 +-
+ src/hb-ot-shape-complex-use-machine.hh            |  43 +--
+ src/hb-ot-shape-complex-use-machine.rl            |   1 +
+ src/hb-ot-shape-complex-use-table.hh              | 372 +++++++++++++++++++---
+ src/ms-use/IndicPositionalCategory-Additional.txt |  12 +-
+ 5 files changed, 366 insertions(+), 73 deletions(-)
+
+commit 05b3bdb0b382078fcc0a6837bcc28730908531b8
+Author: Florian Pircher <florian@addpixel.net>
+Date:   Sun Mar 6 03:10:48 2022 +0100
+
+    [aat] Update OT to AAT mappings for hist and vrtr
+
+ src/hb-aat-layout.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 4302466481941a470a48573b410892f7ee057fb5
+Merge: 756395270 cf3a0f7ab
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sun Mar 6 05:24:35 2022 +0200
+
+    Merge pull request #3464 from luzpaz/typos
+    
+    Fixed various misc. typos
+
+commit cf3a0f7ab54984ffb9ab386a673358619dfaab4f
+Author: luz paz <luzpaz@users.noreply.github.com>
+Date:   Tue Mar 1 19:55:58 2022 -0500
+
+    Fixed various misc. typos
+    
+    Found via `codespell -q 3 -S ./perf/texts -L actualy,als,ba,beng,clen,crasher,dependant,eachother,fo,gir,inout,ist,nd,ned,ot,pres,ro,statics,te,teh,timne`
+
+ docs/serializer.md                |  2 +-
+ src/hb-buffer-deserialize-text.hh | 16 ++++++++--------
+ src/hb-buffer-deserialize-text.rl |  2 +-
+ src/hb-buffer.h                   |  2 +-
+ 4 files changed, 11 insertions(+), 11 deletions(-)
+
+commit 756395270dc41efa98036d3756ed282a46046c51
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Mar 2 12:56:33 2022 +0200
+
+    Minor [ci skip]
+
+ NEWS | 52 ++++++++++++++++++++++++++--------------------------
+ 1 file changed, 26 insertions(+), 26 deletions(-)
+
+commit 8d1b000a3edc90c12267b836b4ef3f81c0e53edc
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Mar 1 21:27:32 2022 +0200
+
+    4.0.0
+
+ NEWS                   | 92 +++++++++++++++++++++++++++++++++++++++++++++++++-
+ configure.ac           |  2 +-
+ docs/harfbuzz-docs.xml |  1 +
+ meson.build            |  2 +-
+ src/hb-buffer.h        |  4 +--
+ src/hb-draw.cc         | 20 +++++------
+ src/hb-draw.h          | 24 ++++++-------
+ src/hb-font.cc         |  2 +-
+ src/hb-font.h          |  4 +--
+ src/hb-ot-layout.cc    |  4 +--
+ src/hb-ot-layout.h     |  4 +--
+ src/hb-ot-metrics.cc   |  2 +-
+ src/hb-subset-plan.cc  | 16 ++++-----
+ src/hb-subset.cc       |  2 +-
+ src/hb-version.h       |  6 ++--
+ 15 files changed, 138 insertions(+), 47 deletions(-)
+
+commit 6e466256e40a049201a6d3329dcc1bb00ab310fb
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Mar 1 12:01:18 2022 +0200
+
+    [doc] Typo
+
+ src/hb-subset-plan.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f6071c16b0eb482bf6811b2a55b2f882cb6ce02e
+Author: Garret Rieger <grieger@google.com>
+Date:   Mon Feb 28 14:45:40 2022 -0700
+
+    [subset] Rename codepoint -> unicode in subset plan api
+
+ docs/harfbuzz-sections.txt | 2 +-
+ src/hb-subset-plan.cc      | 4 ++--
+ src/hb-subset.h            | 2 +-
+ test/api/test-subset.c     | 2 +-
+ 4 files changed, 5 insertions(+), 5 deletions(-)
+
+commit 1b5a2e0809b2f90fea891cbd7e6e2caee1dcb01f
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Feb 25 04:22:33 2022 +0200
+
+    [doc] Various fixes to newly added documentation
+
+ docs/harfbuzz-docs.xml     |  1 -
+ docs/harfbuzz-sections.txt | 10 ++++++++++
+ src/hb-buffer.h            |  1 +
+ src/hb-subset-plan.cc      | 18 +++++++++++++-----
+ 4 files changed, 24 insertions(+), 6 deletions(-)
+
+commit 924dd71de3c8444125f532655a8647c713f0cdc0
+Merge: 222301bfa e045dbf61
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Feb 25 04:31:24 2022 +0200
+
+    Merge pull request #3423 from harfbuzz/revert-ci-msvc
+    
+    Revert "[ci] Downgrade pip on MSVC jobs"
+
+commit 222301bfa4010554abb900df5ed113722885277a
+Merge: 78f3d7f0a fc1548cf7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 24 12:55:01 2022 -0700
+
+    Merge pull request #3429 from harfbuzz/external_plan
+    
+    [subset] expose subset plan in public subsetting API
+
+commit 78f3d7f0a8dc399415dbd6983212997fdf9831b1
+Merge: d4cb07728 256dcde14
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Feb 21 18:21:03 2022 +0200
+
+    Merge pull request #3459 from jameshilliard/icu-defs-mutliarg
+    
+    [meson] handle multiple element ICU DEFS
+
+commit 256dcde149737246a04cfc0fe388cb91acb65522
+Author: James Hilliard <james.hilliard1@gmail.com>
+Date:   Mon Feb 21 00:07:03 2022 -0700
+
+    [meson] handle multiple element ICU DEFS
+
+ meson.build | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit d4cb07728ccf0f8c2f3287e2b3be663995eb5c11
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Feb 18 18:25:56 2022 -0600
+
+    Add a missing file
+    
+    The style test is using notosansitalic.ttf now,
+    but I forgot to add it with the test. Fix that.
+
+ test/api/fonts/notosansitalic.ttf | Bin 0 -> 1464 bytes
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+
+commit 651c280d0b8a9b0894022fea971141015eab73f3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 18 18:21:46 2022 -0600
+
+    [style] Move the negation into the constant
+
+ src/hb-style.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 16b232be0ed2c8486a9f30523f989e77dd8d13f2
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Feb 18 18:05:58 2022 -0600
+
+    [hb-style] Fix the sign of slant ratios
+    
+    We want negative slant angles to yield
+    positive slant ratios. Fix that.
+    
+    Test included.
+
+ src/hb-style.cc       |  4 ++--
+ src/hb-style.h        |  4 +++-
+ test/api/test-style.c | 12 ++++++++++++
+ 3 files changed, 17 insertions(+), 3 deletions(-)
+
+commit e76061a7372077d063432548e2fb85db5fad8670
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Fri Feb 18 17:27:19 2022 -0600
+
+    [hb-style] Fix synthetic slant values
+    
+    When reporting the slant ratio of a font
+    that has synthetic slant set, we were
+    reporting twice the expected value.
+    Fix that. Test included.
+
+ src/hb-style.cc       |  3 +--
+ test/api/test-style.c | 17 +++++++++++++++++
+ 2 files changed, 18 insertions(+), 2 deletions(-)
+
+commit 56f11ec938260836387256225bc47665473e2bbe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 18 14:08:43 2022 -0600
+
+    [buffer] Add HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3454
+
+ src/hb-buffer-verify.cc                               |  3 ++-
+ src/hb-buffer.h                                       | 14 +++++++++++---
+ src/hb-buffer.hh                                      |  4 ++++
+ test/shape/data/in-house/tests/unsafe-to-concat.tests |  2 +-
+ util/shape-options.hh                                 |  3 +++
+ 5 files changed, 21 insertions(+), 5 deletions(-)
+
+commit c0b2f50c0b08e5b2f6238e54bae03d164b12548e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 18 12:29:14 2022 -0600
+
+    [util] Rename template typenames to avoid clashing with actual types
+    
+    Apparently MSVC2015 can confuse them
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3379
+
+ util/hb-ot-shape-closure.cc |  4 ++--
+ util/helper-cairo.hh        |  4 ++--
+ util/main-font-text.hh      | 14 ++++++++++----
+ 3 files changed, 14 insertions(+), 8 deletions(-)
+
+commit fc1548cf71a9396c0addce27134661aa2799429e
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Feb 17 17:16:31 2022 -0800
+
+    [subset] document return values.
+
+ src/hb-subset-plan.cc | 3 ++-
+ src/hb-subset.cc      | 9 ++++++---
+ 2 files changed, 8 insertions(+), 4 deletions(-)
+
+commit f6efe34f5e9a5657bfe706dc173c9a62817838d3
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Tue Feb 15 17:17:09 2022 -0600
+
+    [ot-metrics] Synthesize missing metrics
+    
+    Add a variant of hb_ot_metrics_get_position that
+    synthesizes missing values.
+    
+    New api: hb_ot_metrics_get_position_with_fallback
+
+ docs/harfbuzz-sections.txt |   1 +
+ src/hb-ot-metrics.cc       | 139 +++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-ot-metrics.h        |   5 ++
+ 3 files changed, 145 insertions(+)
+
+commit f8e9e315bbe809763b89bfc66facad33ffc0491d
+Merge: 8e900f2cd 95bb2ff71
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 17 14:34:46 2022 -0600
+
+    Merge pull request #3437 from matthiasclasen/synthesize-missing-baselines
+    
+    [BASE] Synthesize missing baselines
+
+commit 8e900f2cda0acd938eb50d8294a0b074761f9a91
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 17 13:28:44 2022 -0600
+
+    Revert "hb-algs.hh: Fix build on Visual Studio 2015"
+    
+    This reverts commit 52c536bb8d90cf0f09e13f5e9e21bf489cc08c23.
+    
+    See https://github.com/harfbuzz/harfbuzz/pull/3448
+
+ src/hb-algs.hh | 6 ------
+ 1 file changed, 6 deletions(-)
+
+commit da801cdee1d90bb787e1ac1c6a296f306218d57d
+Merge: 5de67c896 e6aa4b7d0
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Feb 17 13:30:40 2022 +0200
+
+    Merge pull request #3449 from fanc999/msvc-meson-use-cmake
+    
+    Meson: Use CMake more to find dependencies on Windows
+
+commit e6aa4b7d0e3026f3186738b1e8b50286988ba38f
+Author: Chun-wei Fan <fanchunwei@src.gnome.org>
+Date:   Thu Feb 17 15:28:42 2022 +0800
+
+    BUILD.md: Mention that installing CMake is recommended for MSVC
+    
+    We are using CMake to help us find dependencies in Meson builds on Visual
+    Studio, so let people know that it's recommended.
+
+ BUILD.md | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit d24ac4aac33bee06082c6bfcca907569740c7f59
+Author: Chun-wei Fan <fanchunwei@src.gnome.org>
+Date:   Thu Feb 17 16:18:41 2022 +0800
+
+    freetype2.wrap: Provide fallback for CMake dep as well
+    
+    Add a freetype identifier in the 'provides' section so that the fallback will
+    kick in if FreeType is requested but was not found, and wrap mode is not
+    disabled.
+
+ subprojects/freetype2.wrap | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit f0573d8462ef18bd21c6ae3fc7d2c15c660ff1c7
+Author: Chun-wei Fan <fanchunwei@src.gnome.org>
+Date:   Thu Feb 17 14:39:31 2022 +0800
+
+    meson: Clean up finding ICU-UC on Visual Studio
+    
+    Nowadays Meson has much better CMake support which we can use to find
+    dependencies on Visual Studio builds (and Visual Studio 2017 and later provides
+    CMake as an optional install item), so we can use it to help us find ICU-UC
+    on Visual Studio builds, since CMake has built-in support for finding it by
+    the components we need for some time.
+
+ meson.build | 31 +++++++++----------------------
+ 1 file changed, 9 insertions(+), 22 deletions(-)
+
+commit 561e8ba8870d9f18a92c886593f8b0162f98d941
+Author: Chun-wei Fan <fanchunwei@src.gnome.org>
+Date:   Thu Feb 17 14:19:35 2022 +0800
+
+    meson: Cleanup finding FreeType on Visual Studio
+    
+    Nowadays, CMake is much better supported with Meson and is a common tool on
+    Windows (it is even an optionally-installed item for Visual Studio 2017+), so
+    make use of that to find FreeType.  The package to search for, however, is
+    `freetype` instead of `freetype2`.
+
+ meson.build | 20 ++++----------------
+ 1 file changed, 4 insertions(+), 16 deletions(-)
+
+commit 95bb2ff7198e4811b1a712c8c6dfbae29e453d49
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Wed Feb 16 13:10:52 2022 -0600
+
+    [ot-layout] Add central baselines
+    
+    Add HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL
+    and HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL
+    which are the centers of the ideographic em-box
+    and face box.
+
+ src/hb-ot-layout.cc | 40 ++++++++++++++++++++++++++++++++++++++++
+ src/hb-ot-layout.h  |  4 ++++
+ 2 files changed, 44 insertions(+)
+
+commit f81578fd86455eb8eba3bd586d604b83aa55ed56
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sun Feb 13 19:15:36 2022 -0600
+
+    [ot-layout] Synthesize missing baselines
+    
+    Add a variation of hb_ot_layout_get_baseline that
+    synthesizes missing baselines, using heuristics in part
+    taken from the CSS Inline Layout Module, Level 3.
+    
+    Includes some new tests for synthesized baselines.
+    The base2.ttf is a subset of Noto Sans Bengali that
+    includes just the Bengali Ka.
+    
+    New API: hb_ot_layout_get_baseline_with_fallback
+
+ docs/harfbuzz-sections.txt |   1 +
+ src/hb-ot-layout.cc        | 184 ++++++++++++++++++++++++++++++++++++++++++++-
+ src/hb-ot-layout.h         |   8 ++
+ test/api/fonts/base2.ttf   | Bin 0 -> 5236 bytes
+ test/api/test-baseline.c   |  53 +++++++++++++
+ 5 files changed, 245 insertions(+), 1 deletion(-)
+
+commit 5de67c8961555ee6c5ef27ebe7a9e087dda01b56
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 16 17:07:17 2022 -0600
+
+    [ot-layout] Remove commented-out prototypes
+    
+    Not gonna happen.
+
+ docs/harfbuzz-sections.txt |  6 ------
+ src/hb-ot-layout.h         | 47 ----------------------------------------------
+ 2 files changed, 53 deletions(-)
+
+commit d2998faad3e431b8c94262f049b7422fecb6e238
+Merge: 98079109e f567b5561
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 16 14:37:09 2022 -0600
+
+    Merge pull request #3410 from harfbuzz/boring-expansion
+    
+    [Boring Expansion] >64k loca & hmtx tables
+    
+    This does two things:
+    
+    The num-glyphs reported by the face now is the maximum reported by the maxp and that deduced from the length of the loca table; I think this is the right thing to do anyway; According to OpenType such loca tables are invalid.
+    
+    The interpretation hmtx tables that have excessive bytes at the end, again, invalid according to OpenType, has changed. Previously we were interpreting those excessive bytes as extra lsb values. Now we interpret them as extra advance values, the last of which is repeated for all missing glyphs. Again, these are tables that are invalid according to OpenType, and the advances are for glyph indices beyond maxp table's num-glyphs.
+    
+    The combined effect is that the font can have shapes and advances for gid's beyond the maxp limit of 64k. In fact, maxp table becomes optional.
+
+commit 98079109e6ebc8f05b6c8de97fcd0ed5667907d1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 13 18:15:32 2022 -0600
+
+    [ot-layout] Add +hb_ot_layout_get_horizontal_baseline_tag_for_script()
+    
+    New API:
+    +hb_ot_layout_get_horizontal_baseline_tag_for_script()
+
+ docs/harfbuzz-sections.txt |  1 +
+ src/hb-ot-layout.cc        | 70 ++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-ot-layout.h         |  3 ++
+ 3 files changed, 74 insertions(+)
+
+commit cfa8cd7fb0962967d647c09e4cfab4b8600fb360
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Feb 16 11:42:36 2022 +0200
+
+    [autotools] Fix make distcheck
+    
+    The test-draw.c can now optionally uses hb-ft, but automake file was not
+    passing FreeType cflags or libs to it.
+
+ test/api/Makefile.am | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 9909e3326806f0ad1405648c16296cd42dff39fc
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Tue Feb 15 18:02:09 2022 -0600
+
+    Improve docs for hb_ot_layout_get_ligature_carets
+    
+    Add some relevant details to the documentation
+    for this function.
+    
+    Fixes: #3168
+
+ src/hb-ot-layout.cc | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+commit a396543ae15569dca7ab7cc47c060f262f6bdfea
+Merge: 1bf588e28 c8b6036cf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 15 18:47:55 2022 -0600
+
+    Merge pull request #3411 from harfbuzz/draw
+    
+    [draw] Finish and release draw API
+
+commit f567b5561928e713737edc4655c6532ea6138a1d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 15 18:26:43 2022 -0600
+
+    [face] Use max numGlyphs of maxp and loca
+
+ src/hb-static.cc | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+commit c8fd8c133755fd9c62efc67033ca0193bd0dfc76
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 15 18:02:53 2022 -0600
+
+    [ot-face] Use core tables
+
+ src/hb-ot-face-table-list.hh |  1 +
+ src/hb-ot-glyf-table.hh      |  3 +--
+ src/hb-static.cc             | 24 +++---------------------
+ 3 files changed, 5 insertions(+), 23 deletions(-)
+
+commit 2a430790adfac00a1280c0ebfcf579be1b557ffb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 15 17:33:52 2022 -0600
+
+    [machinery] Add "core table" machinery
+    
+    To be used in subsequent commit; or tried anyway.
+
+ src/hb-machinery.hh          | 11 ++++++++---
+ src/hb-ot-face-table-list.hh | 13 +++++++++++--
+ src/hb-ot-face.hh            |  3 +++
+ 3 files changed, 22 insertions(+), 5 deletions(-)
+
+commit 67eb9acf792a63e4d6a8447c23cbb5d4b97891dc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 15 17:17:49 2022 -0600
+
+    [config] Add HB_NO_BORING_EXPANSION
+
+ src/hb-config.hh                 | 1 +
+ src/hb-ot-hmtx-table.hh          | 4 ++++
+ src/hb-static.cc                 | 5 ++++-
+ test/api/test-be-glyph-advance.c | 2 ++
+ test/api/test-be-num-glyphs.c    | 2 ++
+ 5 files changed, 13 insertions(+), 1 deletion(-)
+
+commit 1bf588e28b1ead28b5ca755e840112520c551aba
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 15 16:57:23 2022 -0600
+
+    [test/shape] Internal rename
+    
+    Residual from e0d7060f80f8c4b9b8241c3a4d8faa33f48da86d
+
+ test/shape/meson.build | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+commit d12c51e6e6225c3a4efaa358f01c711946964d7d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 15 14:31:59 2022 -0600
+
+    [ci] Rename configs-ci to configs-build
+    
+    Since it doesn't run any tests.
+
+ .github/workflows/{configs-ci.yml => configs-build.yml} | 0
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+
+commit 197ed8f5923b04cfd843942428814ea14b88632e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 15 14:30:12 2022 -0600
+
+    [test/api] Fix leaks
+
+ test/api/hb-test.h | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+commit 531c27d199be9413523ae1f48703931d0ebf922f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 15 14:20:54 2022 -0600
+
+    Fix build
+
+ test/api/Makefile.am | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 8b7ccc41c4b06ad93927849c54288a9ad1816dba
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 15 14:15:12 2022 -0600
+
+    [hmtx] Implement [boring-expansion] >64k expansion
+    
+    This implements https://github.com/be-fonts/boring-expansion-spec/issues/7
+
+ src/hb-ot-face-table-list.hh     |  1 +
+ src/hb-ot-hmtx-table.hh          | 80 +++++++++++++++++++++++++++-------------
+ test/api/test-be-glyph-advance.c |  6 +--
+ 3 files changed, 59 insertions(+), 28 deletions(-)
+
+commit 379e526aa41b216fa1dd19cf4345e55ec3c8a8c9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 14 15:02:31 2022 -0600
+
+    [test] Add test for current hmtx logic
+
+ test/api/Makefile.am             |  1 +
+ test/api/meson.build             |  1 +
+ test/api/test-be-glyph-advance.c | 99 ++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 101 insertions(+)
+
+commit 431c948ed742c936623a340e046e0e708ee0736f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 14 14:13:04 2022 -0600
+
+    [hmtx] Document
+
+ src/hb-ot-hmtx-table.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit be4ddcc30b8c1932def1b9a5beee9ead90f8928f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 14 14:12:07 2022 -0600
+
+    [hmtx] Rename internal num_advances to num_long_metrics
+
+ src/hb-ot-hmtx-table.hh | 56 ++++++++++++++++++++++++-------------------------
+ 1 file changed, 28 insertions(+), 28 deletions(-)
+
+commit 622cbc485f286770ee816524c0b12aef7e81d510
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 14 14:09:40 2022 -0600
+
+    [hmtx] Internal rename num_metrics to num_bearings
+
+ src/hb-ot-hmtx-table.hh | 22 +++++++++++-----------
+ 1 file changed, 11 insertions(+), 11 deletions(-)
+
+commit ed6d287d1105219b246a2810685097918f974497
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 2 14:10:16 2022 -0600
+
+    [ot-face] Load num-glyphs from `loca` table before `maxp`
+    
+    Implements [boring-expansion] [maxp] Relax
+    https://github.com/be-fonts/boring-expansion-spec/issues/6
+
+ src/hb-ot-hmtx-table.hh       |  2 +-
+ src/hb-static.cc              | 52 ++++++++++++++++++++++++++++----
+ test/api/Makefile.am          |  1 +
+ test/api/hb-test.h            |  7 +++++
+ test/api/meson.build          |  1 +
+ test/api/test-be-num-glyphs.c | 69 +++++++++++++++++++++++++++++++++++++++++++
+ 6 files changed, 126 insertions(+), 6 deletions(-)
+
+commit 93962977bcd3de314f4e613990b7e74ac8803a68
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 13 19:38:59 2022 -0600
+
+    Remove return of void
+
+ src/hb-font.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit c8b6036cf305a119203c0e1a3f061cb26299b930
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Feb 14 02:17:38 2022 +0200
+
+    [meson] Update Cairo subproject
+    
+    Fixes another color fonts issue.
+
+ subprojects/cairo.wrap | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 6b75a30a730356c41a6ed748847fd95494e51ad5
+Author: Ebrahim Byagowi <ebrahim@gnu.org>
+Date:   Mon Feb 14 01:38:06 2022 +0330
+
+    [draw/test] Swap a freetype test case with a simpler one
+    
+    As CI failure, apparently the my local freetype and CI one have different
+    result so let's switch the case with a simpler one just to test quadratic command
+    is emitted correctly.
+
+ test/api/test-draw.c | 9 ++-------
+ 1 file changed, 2 insertions(+), 7 deletions(-)
+
+commit ae223764a305e3dbfd3654892e2f5562a89e213a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 13 15:39:14 2022 -0600
+
+    [test/draw] Typo
+
+ test/api/test-draw.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 0429921c109a24205ed19e21bc5f0d1cd570400d
+Author: Ebrahim Byagowi <ebrahim@gnu.org>
+Date:   Mon Feb 14 00:16:35 2022 +0330
+
+    [draw/test] Add test for freetype callback
+    
+    Let's have that part of the code also covered.
+
+ test/api/test-draw.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 59 insertions(+)
+
+commit d4588204e52eece7dab04f45e37d2986b1545cb7
+Author: Ebrahim Byagowi <ebrahim@gnu.org>
+Date:   Sun Feb 13 23:49:41 2022 +0330
+
+    [draw/glyf] Emit empty contours
+    
+    This makes it actually match freetype behaviour even though rasterizer
+    should filter such contours specially for stroking.
+    
+    See https://github.com/harfbuzz/harfbuzz/pull/3411#discussion_r802283827 for the context.
+
+ src/hb-ot-glyf-table.hh | 6 ++++++
+ test/api/test-draw.c    | 5 +++--
+ 2 files changed, 9 insertions(+), 2 deletions(-)
+
+commit 94517850dd1105dfcdc7e0f44adbbee0eb92d3a3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 13 13:39:26 2022 -0600
+
+    [algs] Fix typo in hb_pair_t conversion operator
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/2083
+
+ src/hb-algs.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f942874facdfe31322b4cbe5cc7bb0dc0db48e5d
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Feb 12 01:43:11 2022 +0200
+
+    [draw] Fix some introspection warnings
+
+ src/hb-draw.cc            | 32 ++++++++++++++++++++++----------
+ src/hb-draw.h             | 10 +++++-----
+ src/hb-font.h             |  3 ---
+ src/hb-gobject-structs.cc |  1 +
+ src/hb-gobject-structs.h  |  4 ++++
+ 5 files changed, 32 insertions(+), 18 deletions(-)
+
+commit 2da6accda6583962feca64d38807fbf694cca601
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Feb 12 01:14:15 2022 +0200
+
+    [meson] Update cairo submodule
+    
+    To include the latest color glyph fixes
+
+ subprojects/cairo.wrap | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 0858463ac3e4db60c339e85061f3c9e8ab81ee0a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 11 14:42:15 2022 -0600
+
+    [draw/glyf] Don't skip empty contours of size 2
+    
+    See:
+    https://github.com/harfbuzz/harfbuzz/pull/3411#discussion_r804988217
+
+ src/hb-ot-glyf-table.hh | 4 ----
+ 1 file changed, 4 deletions(-)
+
+commit 0e357c504ca18cd0e01dc23eef0a6db6e75a54dc
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Feb 11 04:31:13 2022 +0200
+
+    [draw] Test scaling subfont differently from parent
+
+ test/api/test-draw.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 68 insertions(+)
+
+commit 096121badbbc19d77a46015339de968817dc5c4f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 10 19:27:33 2022 -0600
+
+    [util] Implement --sub-font
+    
+    Internally creates a font at 2x and creates a sub-font from it...
+
+ util/font-options.hh      | 11 +++++++++++
+ util/helper-cairo-user.hh | 10 ----------
+ 2 files changed, 11 insertions(+), 10 deletions(-)
+
+commit 57aa8c3b3a5df1a7895269f696e21952e361247b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 10 19:04:52 2022 -0600
+
+    [draw] Another try at a stable draw moveto semantic
+
+ src/hb-draw.hh            |  2 +-
+ src/hb-font.cc            |  6 ------
+ util/helper-cairo-user.hh | 10 ++++++++++
+ 3 files changed, 11 insertions(+), 7 deletions(-)
+
+commit 151f205819dbec29c78fbc0ebcefd72752809ff5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 10 16:27:18 2022 -0600
+
+    [draw] Emit move_to immediately, like other operators
+
+ src/hb-draw.hh                 |  8 +++++---
+ src/hb-font.cc                 |  3 +++
+ test/fuzzing/hb-draw-fuzzer.cc | 22 ++++++----------------
+ 3 files changed, 14 insertions(+), 19 deletions(-)
+
+commit aca80a4a4019f3b808b4ccbd0c26d1bef6a2fdb4
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Feb 9 22:44:38 2022 +0200
+
+    [draw] Add test for applying synthetic slant
+
+ test/api/test-draw.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 44 insertions(+), 1 deletion(-)
+
+commit 052fd2d8b98defaa593dd18d9b30f11652dd6dde
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Feb 9 22:10:23 2022 +0200
+
+    [draw] Add test for hb_draw_move_to() etc
+
+ test/api/test-draw.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 49 insertions(+)
+
+commit 640b6ffddd0dd7dc7d17f66e252d5450333035a0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 8 18:20:59 2022 -0600
+
+    [util] Default font-funcs to 'ot' instead of 'ft'
+
+ util/font-options.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9cc9ffe3523980fad86ea9950cf82a53b79a9583
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 8 18:18:47 2022 -0600
+
+    [util/draw] If HB_DRAW is not set, choose depending on cairo version
+    
+    If HB_DRAW=0, don't use it, if HB_DRAW=1, use it, if unset, choose depending
+    on cairo version
+
+ util/helper-cairo.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit 22f2c78c283846250e029026b15dc778c9fba633
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 8 17:52:56 2022 -0600
+
+    [util/draw] Explicitly chain from render_color_glyph to render_glyph
+    
+    This seems to be more robust.  See:
+    https://github.com/harfbuzz/harfbuzz/pull/3411#issuecomment-1033176635
+
+ util/helper-cairo-user.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 6a3dec357ce4a66ed1c78abd1aee982d4646cbac
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 8 17:39:16 2022 -0600
+
+    [util/draw] Use hb-draw in hb-view only if HB_DRAW=1
+
+ util/helper-cairo.hh | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+commit 18b8a1c3451be24c61d6471d754e1daeaa8eb4d8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 8 16:33:09 2022 -0600
+
+    [draw] Fix conversion warnings
+
+ util/helper-cairo-user.hh | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+commit 6812f7ee1eeca874ccc132f37f67f173e0e2e3fb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 8 16:15:37 2022 -0600
+
+    [draw] Implement COLRv0 fonts
+
+ util/helper-cairo-user.hh | 101 +++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 92 insertions(+), 9 deletions(-)
+
+commit 74ebfc646a662fa84e20f3aafeb02f42daf41496
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Feb 8 22:44:11 2022 +0200
+
+    [meson] Update cairo subproject
+    
+    Update to the current master branch so that is has
+    cairo_user_font_face_set_render_color_glyph_func().
+    
+    I had to disable optimized builds on win[32|64] crossbuild setups
+    because they are now broken in the CI (something about cairo defining
+    _FORTIFY_SOURCE for optimized builds that MingW does not like).
+
+ .ci/build-win32.sh     | 1 -
+ .ci/build-win64.sh     | 1 -
+ meson.build            | 3 +--
+ subprojects/cairo.wrap | 2 +-
+ 4 files changed, 2 insertions(+), 5 deletions(-)
+
+commit 628847b5c8d8783c46a51c9f2bdc481b4bbee960
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Feb 8 22:09:49 2022 +0200
+
+    [doc] Link to respective draw callback functions
+
+ src/hb-draw.h | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 7245298e259a4ce30d149174d6880e27f9766125
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Feb 8 21:38:57 2022 +0200
+
+    [doc] Document HB_DRAW_STATE_DEFAULT
+
+ src/hb-draw.h | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit 8f519d55ac0ba6ae9c81d83ee598416e851ca3f6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Feb 8 13:28:00 2022 -0600
+
+    [meson] Put back Experimental-API infrastructure
+    
+    Just unused for now.
+
+ .github/workflows/coverity-scan.yml | 2 +-
+ meson.build                         | 5 +++++
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+commit 8e892bdb544b946e4c1b8705f86baffe67584c54
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Feb 8 19:36:29 2022 +0200
+
+    [doc] Message draw documentation a bit
+
+ src/hb-draw.cc |  9 +++++++
+ src/hb-draw.h  | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-font.cc |  2 +-
+ src/hb-font.h  |  2 +-
+ 4 files changed, 94 insertions(+), 2 deletions(-)
+
+commit cf28821337735bb1bee3599129592e9e84c53616
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Feb 8 19:03:17 2022 +0200
+
+    [meson] fix building with Cairo subproject
+    
+    We can’t pass internal (subproject) dependency to cpp.has_function(), so
+    we manually hard-code the result.
+
+ meson.build | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit cdf1cb35db2e479d40e629e355a9de348ab1c17c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 7 19:05:52 2022 -0600
+
+    [draw] Destroy callback data
+
+ src/hb-draw.cc | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 5c558586eba3b6cc13e66cfd8271d6d654fd2488
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 7 18:54:16 2022 -0600
+
+    [util/draw] Apply slant to non-user-fonts as well
+
+ util/helper-cairo.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit c56c13756b637c231843d634d48c26bc891303a9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 7 18:38:00 2022 -0600
+
+    [draw] Document more
+
+ src/hb-draw.cc | 135 ++++++++++++++++++---------------------------------------
+ src/hb-draw.h  | 105 ++++++++++++++++++++++++++++++++++++--------
+ src/hb-font.cc |   4 +-
+ 3 files changed, 130 insertions(+), 114 deletions(-)
+
+commit 23762305235f25ca89de34bed7948d925c98fba3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 7 18:23:26 2022 -0600
+
+    [draw] Flesh out docs a bit
+
+ docs/harfbuzz-docs.xml     |  1 +
+ docs/harfbuzz-sections.txt | 31 ++++++++++++++++++++++
+ src/hb-draw.cc             | 64 ++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 96 insertions(+)
+
+commit bc6c3b84016852a348d425a79d47cfd1aa927984
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 7 18:04:36 2022 -0600
+
+    [font] Update get_glyph_shape() doc
+
+ src/hb-font.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 732c749ef7a8e27b8b0d9eb1ec2e37d3902b5712
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 7 18:02:37 2022 -0600
+
+    [font] Adjust synthetic-slant docs
+
+ src/hb-font.cc | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+commit 4818b7ed72c4f397920d695dfdae8b3649209a16
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 7 18:00:14 2022 -0600
+
+    [util] Add --font-slant
+
+ util/font-options.hh | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+commit 59067db9f47fa2d0fc6cdc4adcc38d63601f9123
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 7 17:55:01 2022 -0600
+
+    [font/draw] Slant drawings
+    
+    Need to update hb_font_set_synthetic_slant() docs now that we do this.
+
+ src/hb-ft.cc      | 2 +-
+ src/hb-ot-font.cc | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit aa5c7a3811ae5035bd1bd06a9f8e73119b837b12
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Feb 7 17:53:38 2022 -0600
+
+    [draw-session] Add slant
+
+ src/hb-draw.hh | 50 ++++++++++++++++++++++++++++++++++++--------------
+ 1 file changed, 36 insertions(+), 14 deletions(-)
+
+commit 4f2704adb61c1fd699822cbf8dd3b32f3313d816
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Feb 6 13:13:34 2022 -0600
+
+    [draw] Add more reserved items to hb_draw_state_t
+    
+    Since these are free basically.
+
+ src/hb-draw.h | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 2ce19f2868ebbb545d6e376a5642c2b93d966dca
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 5 15:01:15 2022 -0600
+
+    [font/draw] Fetch shape from parent font if not implemented in font
+
+ src/hb-draw.cc |   2 +-
+ src/hb-font.cc | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 116 insertions(+), 3 deletions(-)
+
+commit d6b61dff952c8a1b14629371fc76e1113936c3a0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 5 13:46:48 2022 -0600
+
+    [draw] Minor cleanup
+
+ src/hb-draw.cc | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+commit cfc06c24d595b403ea09e5598597127406403a1b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 5 13:31:05 2022 -0600
+
+    [util/draw] Render color glyphs if cairo API available
+
+ configure.ac              |  4 +++
+ meson.build               |  1 +
+ util/helper-cairo-user.hh | 88 ++++++++++++++++++++++++++++++++++++++++++++++-
+ 3 files changed, 92 insertions(+), 1 deletion(-)
+
+commit 542f8269cbb5028cead28f7add6500611b57e772
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 4 18:45:04 2022 -0600
+
+    [util/draw/ft] Use hb-draw for font-funcs=ft as well
+    
+    If cairo is >= 1.17.5.
+    
+    This essentially breaks emoji and bitmap fonts for now.
+
+ util/helper-cairo.hh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 6d5b998f256f8d5217bede6fa32a4c9dd82aca56
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 4 18:44:38 2022 -0600
+
+    [ft/draw] Implement hb-draw for hb-ft
+
+ src/hb-ft.cc | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 82 insertions(+)
+
+commit 370bec938ba0b626ef1a494cb82cf236c7b2c598
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Feb 4 18:40:44 2022 -0600
+
+    [draw] Rename internal draw_session_t to hb_draw_session_t
+
+ src/hb-draw.hh          |  6 +++---
+ src/hb-ot-cff1-table.cc | 10 +++++-----
+ src/hb-ot-cff1-table.hh |  2 +-
+ src/hb-ot-cff2-table.cc |  6 +++---
+ src/hb-ot-cff2-table.hh |  2 +-
+ src/hb-ot-font.cc       |  2 +-
+ src/hb-ot-glyf-table.hh |  6 +++---
+ 7 files changed, 17 insertions(+), 17 deletions(-)
+
+commit 5d2df1208a58e537cb16e3b8009135dcf4d9393b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 3 17:18:54 2022 -0600
+
+    [util] Use hb-draw to render alternatively to cairo-ft
+    
+    Is automatically enabled if cairo is recent enough, and font-funcs are
+    not 'ft'.
+    
+    Uses cairo-user-font backend internally.
+
+ util/Makefile.sources     |   2 +
+ util/helper-cairo-ft.hh   | 120 +++++++++++++++++++++++++++++++++++++++
+ util/helper-cairo-user.hh | 142 ++++++++++++++++++++++++++++++++++++++++++++++
+ util/helper-cairo.hh      |  86 +++++-----------------------
+ 4 files changed, 279 insertions(+), 71 deletions(-)
+
+commit a357e5d8896e4f540c3e78177f656a2f509a996d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 3 14:42:56 2022 -0600
+
+    [draw] Do quadratic-to-cubic conversion in nil quadratic implementation
+
+ src/hb-draw.cc | 22 +++++++++++++---------
+ src/hb-draw.hh | 12 +-----------
+ 2 files changed, 14 insertions(+), 20 deletions(-)
+
+commit c681331c3ff6b7743723b082c2100bd47d28bfac
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 3 14:36:12 2022 -0600
+
+    [draw] Rename internal draw_helper_t to draw_session_t
+
+ src/hb-draw.hh          |  6 +++---
+ src/hb-ot-cff1-table.cc | 28 ++++++++++++++--------------
+ src/hb-ot-cff1-table.hh |  2 +-
+ src/hb-ot-cff2-table.cc | 16 ++++++++--------
+ src/hb-ot-cff2-table.hh |  2 +-
+ src/hb-ot-font.cc       |  8 ++++----
+ src/hb-ot-glyf-table.hh | 30 +++++++++++++++---------------
+ 7 files changed, 46 insertions(+), 46 deletions(-)
+
+commit f1a9a9ccaf329e1d1935f468a8299fa9c8d663ba
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 3 14:10:40 2022 -0600
+
+    [draw-state] Pass state down to callbacks
+
+ src/hb-draw.cc                 |  5 +++++
+ src/hb-draw.h                  |  5 +++++
+ src/hb-draw.hh                 | 34 +++++++++++++++++-----------------
+ src/main.cc                    |  5 +++++
+ test/api/test-draw.c           |  5 +++++
+ test/fuzzing/hb-draw-fuzzer.cc |  5 +++++
+ 6 files changed, 42 insertions(+), 17 deletions(-)
+
+commit a9dd9f0bae6fc05001d51ecd78d47e3afd3a8d72
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 3 13:58:36 2022 -0600
+
+    [draw] Add public move_to/line_to/... API that take a draw-state
+
+ src/hb-draw.cc          |  51 ++++++++++++++++++++++
+ src/hb-draw.h           |  31 ++++++++++++++
+ src/hb-draw.hh          | 112 ++++++++++++++++++++++++++++++++----------------
+ src/hb-ot-cff1-table.cc |   2 +-
+ src/hb-ot-glyf-table.hh |   2 +-
+ 5 files changed, 160 insertions(+), 38 deletions(-)
+
+commit 9f05362d435c621e49fe430a0cb4653a9b82b9bf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 3 13:08:32 2022 -0600
+
+    [test-draw] Fix compiler warning
+
+ test/api/test-draw.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ebc2a133c37cd87ee3698d88604de61f2913c1d4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 3 13:00:39 2022 -0600
+
+    [draw] Rename internal methods
+
+ src/hb-draw.hh | 48 ++++++++++++++++++++++++------------------------
+ 1 file changed, 24 insertions(+), 24 deletions(-)
+
+commit 86fcd4fe98448a564fa72476ddea9d56acae1efa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 3 12:54:32 2022 -0600
+
+    [draw] Simplify start_path
+
+ src/hb-draw.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1740916ede028c4bc90e5a74f625be0a221884bd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 3 12:50:47 2022 -0600
+
+    [draw] Remove check for no-op
+    
+    This is unnecessary overhead. Up to rasterizers to handle this.  Plus,
+    this throws off point-numbers in uses that rely on it.
+    
+    Disabled one test that broke with this.
+
+ src/hb-draw.hh                 |  9 ---------
+ test/api/test-draw.c           |  2 +-
+ test/fuzzing/hb-draw-fuzzer.cc | 10 +++++-----
+ 3 files changed, 6 insertions(+), 15 deletions(-)
+
+commit fc78592e6767b158e0871446d3d7c8ae54c0ab7e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 3 12:43:25 2022 -0600
+
+    [draw-state] Add type and use in draw-helper
+
+ src/hb-common.h | 10 ++++++++++
+ src/hb-draw.h   | 19 ++++++++++++++++++
+ src/hb-draw.hh  | 62 ++++++++++++++++++++++++---------------------------------
+ 3 files changed, 55 insertions(+), 36 deletions(-)
+
+commit 5610fa1da0a3f1a5e3753bae60ea97fd6bf32eed
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 3 10:29:04 2022 -0600
+
+    [test-draw] Re-enable two disabled tests
+
+ test/api/test-draw.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit a755f93e8d49672ded0811fa2e68bf75b141ab07
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 3 10:28:07 2022 -0600
+
+    [draw] Add TODO
+
+ src/hb-font.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit cdb1a1fc06059a866edd17cc6ef95870c22925da
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 3 01:25:37 2022 -0600
+
+    [draw] Add REPLACEME
+
+ src/hb-font.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 8b4f42900041cf8312c61a1b59f13c802336ff6a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 3 01:14:47 2022 -0600
+
+    [draw] Virtualize hb_font_draw_glyph() into hb_font_get_glyph_shape()
+    
+    To be implemented in hb-ft.
+
+ src/Makefile.sources           |  1 -
+ src/harfbuzz.cc                |  1 -
+ src/hb-draw-glyph.cc           | 63 -------------------------------------
+ src/hb-font.cc                 | 38 +++++++++++++++++++++++
+ src/hb-font.h                  | 47 +++++++++++++++++++++++++---
+ src/hb-font.hh                 | 10 ++++++
+ src/hb-ot-font.cc              | 21 +++++++++++++
+ src/main.cc                    |  4 +--
+ src/meson.build                |  1 -
+ test/api/test-draw.c           | 70 +++++++++++++++++++++---------------------
+ test/api/test-ot-face.c        |  2 +-
+ test/fuzzing/hb-draw-fuzzer.cc |  2 +-
+ 12 files changed, 150 insertions(+), 110 deletions(-)
+
+commit 92e6e53b30ecf013cf3bfcd43e6c149acc47edf3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 3 00:23:13 2022 -0600
+
+    [draw] Rename user_data to draw_data
+
+ src/hb-draw-glyph.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 3b915389b517a6e14e2e7566f6e621f93ce6a98c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Feb 3 00:03:13 2022 -0600
+
+    [draw] Remove unneeded roundf() calls
+
+ src/hb-draw.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 2bed4f46fb09f338fd0959d233d16a40db08cf4e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 2 21:42:48 2022 -0600
+
+    [draw] Fix draw signatures
+
+ src/hb-draw-glyph.cc           |   2 +-
+ src/hb-draw.cc                 | 141 ++++++++++--------
+ src/hb-draw.h                  |  54 +++----
+ src/hb-draw.hh                 |  97 +++++++++---
+ src/hb-font.h                  |   2 +-
+ src/main.cc                    |  65 ++++----
+ test/api/test-draw.c           | 327 +++++++++++++++++++++--------------------
+ test/fuzzing/hb-draw-fuzzer.cc | 105 +++++++------
+ 8 files changed, 448 insertions(+), 345 deletions(-)
+
+commit 08e1096609394d27683fe4fe8770e6cb980502c9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 2 19:01:42 2022 -0600
+
+    [draw-fuzzer] Fix signatures
+
+ test/fuzzing/hb-draw-fuzzer.cc | 22 +++++++++++-----------
+ 1 file changed, 11 insertions(+), 11 deletions(-)
+
+commit e0ac6c587bc5099d67c5026355f8acf62c1955a0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 2 18:57:12 2022 -0600
+
+    Remove remaining traces of HB_EXPERIMENTAL_API
+
+ .github/workflows/coverity-scan.yml | 2 +-
+ meson.build                         | 5 -----
+ perf/perf.cc                        | 2 --
+ src/harfbuzz.cc                     | 1 +
+ test/api/test-ot-face.c             | 2 --
+ test/api/test-var-coords.c          | 2 --
+ test/fuzzing/hb-draw-fuzzer.cc      | 8 --------
+ 7 files changed, 2 insertions(+), 20 deletions(-)
+
+commit 5207ce828aacef52e43beaf9ba8c712b8107db21
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 2 18:54:10 2022 -0600
+
+    [draw] Enable draw tests
+    
+    Disable two failing ones.
+
+ test/api/test-draw.c | 29 ++++++++++++-----------------
+ 1 file changed, 12 insertions(+), 17 deletions(-)
+
+commit 157caf254e4ffe552c3c35b99e3d87f46e320efb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 2 18:46:34 2022 -0600
+
+    [test-draw] Fix compiler warning
+
+ test/api/test-draw.c | 70 ++++++++++++++++++++++++++--------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
+
+commit 27dfd69fc702550b454a35e1aa7b0ad5676a602d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 2 18:13:46 2022 -0600
+
+    [draw] Another Since: tag update
+
+ src/hb-draw.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 7ac23f4e7887fbbfd96317319b216029ad14561e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 2 18:12:03 2022 -0600
+
+    [draw] Whitespace
+
+ src/hb-draw.h | 23 ++++++++++++++++-------
+ 1 file changed, 16 insertions(+), 7 deletions(-)
+
+commit e157b50345214d804023cb744a2daaa5584278df
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 2 16:16:57 2022 -0600
+
+    [draw] Remove return value of hb_font_draw_glyph()
+
+ src/hb-draw-glyph.cc | 15 +++++++--------
+ src/hb-font.h        |  8 +++++---
+ src/main.cc          |  6 ++----
+ 3 files changed, 14 insertions(+), 15 deletions(-)
+
+commit ddc36df3322ff012956605f5fedeae23d893e3b5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 2 16:15:04 2022 -0600
+
+    [draw] Move hb_font_draw_glyph() to hb-draw-glyph.cc
+
+ src/Makefile.sources |  1 +
+ src/hb-draw-glyph.cc | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-draw.cc       | 35 ----------------------------
+ src/meson.build      |  1 +
+ 4 files changed, 66 insertions(+), 35 deletions(-)
+
+commit 9a1508a2be20c85b08557ec1b8224dc1af3113e3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 2 16:12:42 2022 -0600
+
+    [draw] Replace API Since tags with REPLACEME
+
+ src/hb-draw.cc | 22 +++++++++++-----------
+ 1 file changed, 11 insertions(+), 11 deletions(-)
+
+commit a428c1193c3ed5fe0ef3de92c3a87bdcfa1da390
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 2 16:09:46 2022 -0600
+
+    [main] Fix compiler warnings
+
+ src/main.cc | 26 +++++++++++++-------------
+ 1 file changed, 13 insertions(+), 13 deletions(-)
+
+commit 35190dc9610100fb49050a224536c8b6dfe26b40
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 2 16:08:40 2022 -0600
+
+    [draw] Convert API to float instead of hb_position_t
+
+ src/hb-draw.cc          | 14 +++++++-------
+ src/hb-draw.h           | 14 +++++++-------
+ src/hb-draw.hh          | 24 ++++++++++++------------
+ src/hb-ot-cff1-table.cc | 10 +++++-----
+ src/hb-ot-cff2-table.cc | 10 +++++-----
+ src/hb-ot-glyf-table.hh | 28 ++++++++++++++--------------
+ src/main.cc             | 22 +++++++++++-----------
+ 7 files changed, 61 insertions(+), 61 deletions(-)
+
+commit d6e49b8278fee01fea521b2a157d797f17580b3f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 2 15:45:43 2022 -0600
+
+    [font] Add em_fscalef_[xy] That take and return float
+
+ src/hb-font.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 6c0b65a6a8a9a7fec31aaad04e29a01d7991db5c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 2 15:42:33 2022 -0600
+
+    [font] Add em_scaleff() that returns float
+
+ src/hb-font.hh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit dd7b6e2c3fddca7896f4cb306bc574b48c7a61a6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Feb 2 14:46:10 2022 -0600
+
+    [draw] Remove EXPERIMENTAL_API tag
+
+ src/gen-def.py          | 18 +-----------------
+ src/hb-draw.cc          |  2 --
+ src/hb-draw.h           |  2 --
+ src/hb-draw.hh          |  2 --
+ src/hb-font.h           |  2 --
+ src/hb-ot-cff1-table.cc |  2 --
+ src/hb-ot-cff1-table.hh |  2 --
+ src/hb-ot-cff2-table.cc |  2 --
+ src/hb-ot-cff2-table.hh |  2 --
+ src/hb-ot-glyf-table.hh |  2 --
+ src/main.cc             |  4 ++--
+ 11 files changed, 3 insertions(+), 37 deletions(-)
+
+commit 7af165dbf0617ae102a16e63d90e3001aab1065e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 12 21:25:24 2022 -0600
+
+    Fix compiler warning
+
+ src/hb-ot-shape-complex-use-machine.hh | 4 +++-
+ src/hb-ot-shape-complex-use-machine.rl | 4 +++-
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+commit b2f5131029111b8ca585f141845d4bee91469f5d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Feb 12 21:08:43 2022 -0600
+
+    [ci] Add configs-ci.yml to test different configs
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/2884
+
+ .github/workflows/configs-ci.yml | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+commit db04af27825621773a701b6226c3287d3615724f
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sun Feb 13 00:33:12 2022 +0200
+
+    Typo
+
+ NEWS | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
 commit 0a129961341da370ec82bfccdd11ec9b1094b5a2
 Author: Khaled Hosny <khaled@aliftype.com>
 Date:   Sun Feb 13 00:30:50 2022 +0200
@@ -74,6 +49194,54 @@ Date:   Sat Feb 12 13:53:16 2022 -0600
  .../fonts/crash-d223bc42a8226c4d655c417d63d9a76760d05985  | Bin 0 -> 316 bytes
  1 file changed, 0 insertions(+), 0 deletions(-)
 
+commit 27a6c895ba749c69c8dfd3a14714dd86504b6ad8
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Feb 11 16:19:43 2022 -0800
+
+    [subset] Fix memory leak in plan creation.
+
+ src/hb-subset-plan.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 670ef070bd3a7510fa9c524f79ee11944ce6ae0f
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Feb 11 16:01:33 2022 -0800
+
+    [subset] Change subset plan create to be or_fail.
+
+ src/hb-subset-plan.cc  | 18 +++++++++++-------
+ src/hb-subset.cc       |  7 +++----
+ src/hb-subset.h        |  4 ++--
+ test/api/test-subset.c |  3 ++-
+ 4 files changed, 18 insertions(+), 14 deletions(-)
+
+commit ae8d373bcf94d8cfd4416ff995c264259903aafa
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Feb 11 14:54:23 2022 -0800
+
+    [subset] add subset plan reference, set/get user data functions.
+
+ src/hb-subset-plan.cc  | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-subset.cc       |  4 ++--
+ src/hb-subset.h        | 22 ++++++++++++++++---
+ test/api/test-subset.c |  2 +-
+ 4 files changed, 81 insertions(+), 6 deletions(-)
+
+commit b65e48a7864d53d5047211b57428d2a8bfa95ce5
+Author: Garret Rieger <grieger@google.com>
+Date:   Fri Feb 11 12:44:58 2022 -0800
+
+    [subset] Add subset plan to public API.
+    
+    Add the ability to create a subset plan which an be used to gather info on things like glyph mappings in the final subset. The plan can then be passed on to perform the subsetting operation.
+
+ src/hb-subset-plan.cc  | 55 +++++++++++++++++++++++++++++++++++++++++++++-----
+ src/hb-subset-plan.hh  |  9 ---------
+ src/hb-subset.cc       | 29 +++++++++++++++++++++-----
+ src/hb-subset.h        | 28 +++++++++++++++++++++++++
+ test/api/test-subset.c | 38 ++++++++++++++++++++++++++++++++++
+ 5 files changed, 140 insertions(+), 19 deletions(-)
+
 commit 68937238791181b6172ea4cd3d127ff4f6bbdd98
 Author: Behdad Esfahbod <behdad@behdad.org>
 Date:   Fri Feb 11 13:16:25 2022 -0600
@@ -114,6 +49282,17 @@ Date:   Thu Feb 10 16:39:40 2022 +0800
  src/hb-algs.hh | 6 ++++++
  1 file changed, 6 insertions(+)
 
+commit e045dbf6174413eafea2169a7987b44b57a6bf84
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Feb 10 04:06:20 2022 +0200
+
+    [ci] Upgrade pip on MSVC job
+    
+    To avoid bad pre-installed version.
+
+ .github/workflows/msvc-ci.yml | 3 +++
+ 1 file changed, 3 insertions(+)
+
 commit 81754a5a962ebefef848237ee218c019f85ef316
 Author: Alexis King <lexi.lambda@gmail.com>
 Date:   Wed Feb 9 12:00:47 2022 -0600
@@ -130,6 +49309,17 @@ Date:   Wed Feb 9 12:00:47 2022 -0600
  test/api/test-ot-math.c    | 82 ++++++++++++++++++++++++++++++++++++++++++++++
  6 files changed, 230 insertions(+)
 
+commit 02a737e53249e1d4d24e80128fc294db1faa6557
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Feb 8 21:45:42 2022 +0200
+
+    Revert "[ci] Downgrade pip on MSVC jobs"
+    
+    This reverts commit c4cf5ddb272cb1c05a572db5b76629368f9054f5.
+
+ .github/workflows/msvc-ci.yml | 4 ----
+ 1 file changed, 4 deletions(-)
+
 commit 1bc4bad7a59e9d4d79d8faeb9e695df19aa494da
 Author: Alexis King <lexi.lambda@gmail.com>
 Date:   Mon Feb 7 19:57:25 2022 -0600
index 3055e5a..c14b4b7 100644 (file)
@@ -4,7 +4,7 @@ NULL =
 
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = src util test docs
+SUBDIRS = src util test perf docs
 
 EXTRA_DIST = \
        autogen.sh \
@@ -25,20 +25,6 @@ EXTRA_DIST = \
        subprojects/google-benchmark.wrap \
        subprojects/ragel.wrap \
        subprojects/packagefiles/ragel/meson.build \
-       subprojects/ttf-parser.wrap \
-       perf/meson.build \
-       perf/perf-draw.hh \
-       perf/perf-extents.hh \
-       perf/perf-shaping.hh \
-       perf/perf.cc \
-       perf/fonts/Amiri-Regular.ttf \
-       perf/fonts/NotoNastaliqUrdu-Regular.ttf \
-       perf/fonts/NotoSansDevanagari-Regular.ttf \
-       perf/fonts/Roboto-Regular.ttf \
-       perf/texts/en-thelittleprince.txt \
-       perf/texts/en-words.txt \
-       perf/texts/fa-monologue.txt \
-       perf/texts/fa-thelittleprince.txt \
        mingw-configure.sh \
        $(NULL)
 
index 540a3e7..1d8a0e3 100644 (file)
@@ -166,8 +166,8 @@ CTAGS = ctags
 CSCOPE = cscope
 DIST_SUBDIRS = $(SUBDIRS)
 am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in AUTHORS \
-       COPYING ChangeLog INSTALL NEWS README THANKS TODO ar-lib \
-       compile config.guess config.sub install-sh ltmain.sh missing
+       COPYING ChangeLog INSTALL NEWS README THANKS ar-lib compile \
+       config.guess config.sub install-sh ltmain.sh missing
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 distdir = $(PACKAGE)-$(VERSION)
 top_distdir = $(distdir)
@@ -244,8 +244,6 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
-DIRECTWRITE_CXXFLAGS = @DIRECTWRITE_CXXFLAGS@
-DIRECTWRITE_LIBS = @DIRECTWRITE_LIBS@
 DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -343,6 +341,8 @@ STRIP = @STRIP@
 UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
 UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
 VERSION = @VERSION@
+WASM_CFLAGS = @WASM_CFLAGS@
+WASM_LIBS = @WASM_LIBS@
 _GI_EXP_DATADIR = @_GI_EXP_DATADIR@
 _GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@
 abs_builddir = @abs_builddir@
@@ -403,7 +403,7 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 NULL = 
 ACLOCAL_AMFLAGS = -I m4
-SUBDIRS = src util test docs
+SUBDIRS = src util test perf docs
 EXTRA_DIST = \
        autogen.sh \
        harfbuzz.doap \
@@ -423,20 +423,6 @@ EXTRA_DIST = \
        subprojects/google-benchmark.wrap \
        subprojects/ragel.wrap \
        subprojects/packagefiles/ragel/meson.build \
-       subprojects/ttf-parser.wrap \
-       perf/meson.build \
-       perf/perf-draw.hh \
-       perf/perf-extents.hh \
-       perf/perf-shaping.hh \
-       perf/perf.cc \
-       perf/fonts/Amiri-Regular.ttf \
-       perf/fonts/NotoNastaliqUrdu-Regular.ttf \
-       perf/fonts/NotoSansDevanagari-Regular.ttf \
-       perf/fonts/Roboto-Regular.ttf \
-       perf/texts/en-thelittleprince.txt \
-       perf/texts/en-words.txt \
-       perf/texts/fa-monologue.txt \
-       perf/texts/fa-thelittleprince.txt \
        mingw-configure.sh \
        $(NULL)
 
diff --git a/NEWS b/NEWS
index dbe1755..9154938 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,692 @@
+Overview of changes leading to 8.2.2
+Wednesday, October 18, 2023
+“From the river to the sea, Palestine will be free”
+====================================
+- Fix regression from 8.1.0 in shaping fonts with duplicate feature tags.
+- Fix regression from 8.2.0 in parsing CSS-style feature strings.
+- Variable fonts instanciation now handles more tables.
+- Various CMake build improvements.
+- various fixes to build without errors with gcc 4.9.2.
+
+
+Overview of changes leading to 8.2.1
+Monday, September 18, 2023
+====================================
+- Unicode 15.1 support.
+
+
+Overview of changes leading to 8.2.0
+Friday, September 8, 2023
+====================================
+- Various build and fuzzing fixes
+- Improvements to COLRv1 painting.
+
+- New API:
++hb_paint_color_glyph_func_t
++hb_paint_funcs_set_color_glyph_func
++hb_paint_color_glyph
+
+
+Overview of changes leading to 8.1.1
+Wednesday, August 2, 2023
+====================================
+- Fix shaping of contextual rules at the end of string, introduced in 8.1.0
+- Fix stack-overflow in repacker with malicious fonts.
+- 30% speed up loading Noto Duployan font.
+
+
+Overview of changes leading to 8.1.0
+Tuesday, August 1, 2023
+====================================
+- Fix long-standing build issue with the AIX compiler and older Apple clang.
+
+- Revert optimization that could cause timeout during subsetting with malicious fonts.
+
+- More optimization work:
+  - 45% speed up in shaping Noto Duployan font.
+  - 10% speed up in subsetting Noto Duployan font.
+  - Another 8% speed up in shaping Gulzar.
+  - 5% speed up in loading Roboto.
+
+- New API:
++hb_ot_layout_collect_features_map()
+
+
+Overview of changes leading to 8.0.1
+Wednesday, July 12, 2023
+====================================
+- Build fix on 32-bit ARM.
+
+- More speed optimizations:
+  - 60% speed up in retain-gid (used for IFT) subsetting of SourceHanSans-VF.
+  - 16% speed up in retain-gid (used for IFT) subsetting of NotoSansCJKkr.
+  - 38% speed up in subsetting (beyond-64k) mega-merged Noto.
+
+
+Overview of changes leading to 8.0.0
+Sunday, July 9, 2023
+====================================
+- New, experimental, WebAssembly (WASM) shaper, that provides greater
+  flexibility over OpenType/AAT/Graphite shaping, using WebAssembly embedded
+  inside the font file. Currently WASM shaper is disabled by default and needs
+  to be enabled at build time. For details, see:
+
+    https://github.com/harfbuzz/harfbuzz/blob/main/docs/wasm-shaper.md
+
+  For example fonts making use of the WASM shaper, see:
+
+    https://github.com/harfbuzz/harfbuzz-wasm-examples
+
+- Improvements to Experimental features introduced in earlier releases:
+  - Support for subsetting beyond-64k and VarComposites fonts.
+  - Support for instancing variable fonts with cubic “glyf” table.
+
+- Many big speed optimizations:
+  - Up to 89% speedup loading variable fonts for shaping.
+  - Up to 88% speedup in small subsets of large (eg. CJK) fonts (both TTF and
+    OTF), essential for Incremental Font Transfer (IFT).
+  - Over 50% speedup in loading Roboto font for shaping.
+  - Up to 40% speed up in loading (sanitizing) complex fonts.
+  - 30% speed up in shaping Gulzar font.
+  - Over 25% speedup in glyph loading Roboto font.
+  - 10% speed up loading glyph shapes in VarComposite Hangul font.
+  - hb-hashmap optimizations & hashing improvements.
+
+- New macro HB_ALWAYS_INLINE. HarfBuzz now inlines functions more aggressively,
+  which results in some speedup at the expense of bigger code size. To disable
+  this feature define the macro to just inline.
+
+- New API:
++HB_CODEPOINT_INVALID
++hb_ot_layout_get_baseline2()
++hb_ot_layout_get_baseline_with_fallback2()
++hb_ot_layout_get_font_extents()
++hb_ot_layout_get_font_extents2()
++hb_subset_input_set_axis_range()
+
+
+Overview of changes leading to 7.3.0
+Tuesday, May 9, 2023
+====================================
+- Speedup applying glyph variation in VarComposites fonts (over 40% speedup).
+  (Behdad Esfahbod)
+- Speedup instancing some fonts (over 20% speedup in instancing RobotoFlex).
+  (Behdad Esfahbod)
+- Speedup shaping some fonts (over 30% speedup in shaping Roboto).
+  (Behdad Esfahbod)
+- Support subsetting VarComposites and beyond-64k fonts. (Behdad Esfahbod)
+- New configuration macro HB_MINIMIZE_MEMORY_USAGE to favor optimizing memory
+  usage over speed. (Behdad Esfahbod)
+- Supporting setting the mapping between old and new glyph indices during
+  subsetting. (Garret Rieger)
+- Various fixes and improvements.
+  (Behdad Esfahbod, Denis Rochette, Garret Rieger, Han Seung Min, Qunxin Liu)
+
+- New API:
++hb_subset_input_old_to_new_glyph_mapping()
+
+
+Overview of changes leading to 7.2.0
+Thursday, April 27, 2023
+====================================
+- Add Tifinagh to the list of scripts that can natively be either right-to-left
+  or left-to-right, to improve handling of its glyph positioning.
+  (Simon Cozens)
+- Return also single substitution from hb_ot_layout_lookup_get_glyph_alternates()
+  (Behdad Esfahbod)
+- Fix 4.2.0 regression in applying across syllables in syllabic scripts.
+  (Behdad Esfahbod)
+- Add flag to avoid glyph substitution closure during subsetting, and the
+  corresponding “--no-layout-closure” option to “hb-subset” command line tool.
+  (Garret Rieger)
+- Support instancing COLRv1 table. (Qunxin Liu)
+- Don’t drop used user-defined name table entries during subsetting.
+  (Qunxin Liu)
+- Optimize handling of “gvar” table. (Behdad Esfahbod)
+- Various subsetter bug fixes and improvements. (Garret Rieger, Qunxin Liu)
+- Various documentation improvements. (Behdad Esfahbod, Josef Friedrich)
+
+- New API:
++HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE
++HB_UNICODE_COMBINING_CLASS_CCC132
+
+- Deprecated API:
++HB_UNICODE_COMBINING_CLASS_CCC133
+
+
+Overview of changes leading to 7.1.0
+Friday, March 3, 2023
+====================================
+- New experimental hb_shape_justify() API that uses font variations to expand
+  or shrink the text to a given advance. (Behdad Esfahbod)
+- Various build and bug fixes. (Behdad Esfahbod, Garret Rieger, Qunxin Liu)
+
+- New API:
++hb_font_set_variation()
+
+
+Overview of changes leading to 7.0.1
+Monday, February 20, 2023
+====================================
+- Various build and bug fixes.
+
+
+Overview of changes leading to 7.0.0
+Saturday, February 11, 2023
+====================================
+- New hb-paint API that is designed mainly to paint “COLRv1” glyphs, but can be
+  also used as a unified API to paint any of the glyph representations
+  supported by HarfBuzz (B/W outlines, color layers, or color bitmaps). 
+  (Behdad Esfahbod, Matthias Clasen)
+- New hb-cairo API for integrating with cairo graphics library. This is provided
+  as a separate harfbuzz-cairo library. (Behdad Esfahbod, Matthias Clasen)
+- Support for instancing “CFF2” table. (Behdad Esfahbod)
+- Support font emboldening. (Behdad Esfahbod)
+- Support feature ranges with AAT shaping. (Behdad Esfahbod)
+- Experimental support to cubic curves in “glyf” table, see
+  https://github.com/harfbuzz/boring-expansion-spec/blob/main/glyf1-cubicOutlines.md
+  for spec. (Behdad Esfahbod)
+- Various subsetter improvements. (Garret Rieger, Qunxin Liu, Behdad Esfahbod)
+- Various documentation improvements. 
+  (Behdad Esfahbod, Matthias Clasen, Khaled Hosny)
+- Significantly reduced memory use during shaping. (Behdad Esfahbod)
+- Greatly reduced memory use during subsetting “CFF” table. (Behdad Esfahbod)
+- New command line utility, hb-info, for querying various font information.
+  (Behdad Esfahbod, Matthias Clasen)
+- New hb-shape/hb-view options: --glyphs, --color-palette, --font-bold,
+  --font-grade, and --named-instance. (Behdad Esfahbod)
+- Miscellaneous fixes and improvements.
+  (Amir Masoud Abdol, Andres Salomon, Behdad Esfahbod, Chun-wei Fan,
+  Garret Rieger, Jens Kutilek, Khaled Hosny, Konstantin Käfer, Matthias Clasen,
+  Nirbheek Chauhan, Pedro J. Estébanez, Qunxin Liu, Sergei Trofimovich)
+
+- New API:
++HB_FONT_NO_VAR_NAMED_INSTANCE
++HB_PAINT_IMAGE_FORMAT_BGRA
++HB_PAINT_IMAGE_FORMAT_PNG
++HB_PAINT_IMAGE_FORMAT_SVG
++hb_cairo_font_face_create_for_face
++hb_cairo_font_face_create_for_font
++hb_cairo_font_face_get_face
++hb_cairo_font_face_get_font
++hb_cairo_font_face_get_scale_factor
++hb_cairo_font_face_set_font_init_func
++hb_cairo_font_face_set_scale_factor
++hb_cairo_font_init_func_t
++hb_cairo_glyphs_from_buffer
++hb_cairo_scaled_font_get_font
++hb_color_line_get_color_stops
++hb_color_line_get_color_stops_func_t
++hb_color_line_get_extend
++hb_color_line_get_extend_func_t
++hb_color_line_t
++hb_color_stop_t
++hb_draw_funcs_get_empty
++hb_draw_funcs_get_user_data
++hb_draw_funcs_set_user_data
++hb_face_collect_nominal_glyph_mapping
++hb_font_draw_glyph
++hb_font_draw_glyph_func_t
++hb_font_funcs_set_draw_glyph_func
++hb_font_funcs_set_paint_glyph_func
++hb_font_get_synthetic_bold
++hb_font_get_var_named_instance
++hb_font_paint_glyph
++hb_font_paint_glyph_func_t
++hb_font_set_synthetic_bold
++hb_map_keys
++hb_map_next
++hb_map_update
++hb_map_values
++hb_ot_color_glyph_has_paint
++hb_ot_color_has_paint
++hb_ot_layout_script_select_language2
++hb_ot_name_id_predefined_t
++hb_paint_color
++hb_paint_color_func_t
++hb_paint_composite_mode_t
++hb_paint_custom_palette_color
++hb_paint_custom_palette_color_func_t
++hb_paint_extend_t
++hb_paint_funcs_create
++hb_paint_funcs_destroy
++hb_paint_funcs_get_empty
++hb_paint_funcs_get_user_data
++hb_paint_funcs_is_immutable
++hb_paint_funcs_make_immutable
++hb_paint_funcs_reference
++hb_paint_funcs_set_color_func
++hb_paint_funcs_set_custom_palette_color_func
++hb_paint_funcs_set_image_func
++hb_paint_funcs_set_linear_gradient_func
++hb_paint_funcs_set_pop_clip_func
++hb_paint_funcs_set_pop_group_func
++hb_paint_funcs_set_pop_transform_func
++hb_paint_funcs_set_push_clip_glyph_func
++hb_paint_funcs_set_push_clip_rectangle_func
++hb_paint_funcs_set_push_group_func
++hb_paint_funcs_set_push_transform_func
++hb_paint_funcs_set_radial_gradient_func
++hb_paint_funcs_set_sweep_gradient_func
++hb_paint_funcs_set_user_data
++hb_paint_funcs_t
++hb_paint_image
++hb_paint_image_func_t
++hb_paint_linear_gradient
++hb_paint_linear_gradient_func_t
++hb_paint_pop_clip
++hb_paint_pop_clip_func_t
++hb_paint_pop_group
++hb_paint_pop_group_func_t
++hb_paint_pop_transform
++hb_paint_pop_transform_func_t
++hb_paint_push_clip_glyph
++hb_paint_push_clip_glyph_func_t
++hb_paint_push_clip_rectangle
++hb_paint_push_clip_rectangle_func_t
++hb_paint_push_group
++hb_paint_push_group_func_t
++hb_paint_push_transform
++hb_paint_push_transform_func_t
++hb_paint_radial_gradient
++hb_paint_radial_gradient_func_t
++hb_paint_sweep_gradient
++hb_paint_sweep_gradient_func_t
++hb_set_is_inverted
++hb_subset_input_keep_everything
+
+- Deprecated API:
++hb_font_funcs_set_glyph_shape_func
++hb_font_get_glyph_shape_func_t
++hb_font_get_glyph_shape
+
+
+Overview of changes leading to 6.0.0
+Friday, December 16, 2022
+====================================
+- A new API have been added to pre-process the face and speed up future
+  subsetting operations on that face. Provides up to a 95% reduction in
+  subsetting times when the same face is subset more than once.
+
+  For more details and benchmarks, see:
+  https://github.com/harfbuzz/harfbuzz/blob/main/docs/subset-preprocessing.md
+
+  (Garret Rieger, Behdad Esfahbod)
+
+- Shaping have been speedup by skipping entire lookups when the buffer contents
+  don't intersect with the lookup. Shows up to a 10% speedup in shaping some
+  fonts. (Behdad Esfahbod)
+
+- A new experimental feature, “Variable Composites” (enabled by passing
+  -Dexperimental_api=true to meson), is also featured in this release.
+  This technology enables drastic compression of fonts in the Chinese,
+  Japanese, Korean, and other writing systems, by reusing the OpenType Font
+  Variations technology for encoding “smart components” into the font.
+
+  The specification for these  extensions to the font format can be found in:
+  https://github.com/harfbuzz/boring-expansion-spec/blob/glyf1/glyf1.md
+
+  A test variable-font with ~7160 Hangul syllables derived from the
+  NotoSerifKR-VF font has been built, with existing OpenType technology, as
+  well as with the new Variable Composites (VarComposites) technology. The
+  VarComposites font is over 90% smaller than the OpenType version of the font!
+  Both fonts can be obtained from the “smarties” repository:
+  https://github.com/behdad/smarties/tree/3.0/fonts/hangul/serif
+
+  When building HarfBuzz with experimental features enabled, you can test
+  the “smarties” font with a sample character like this:
+
+  $ hb-view butchered-hangul-serif-smarties-variable.ttf -u AE01 --variations=wght=700
+
+  (Behdad Esfahbod)
+
+- The HarfBuzz subsetter can now drop axes by pinning them to specific values
+  (also referred to as instancing). There are a couple of restrictions
+  currently:
+
+  - Only works with TrueType (“glyf”) based fonts. “CFF2” fonts are not yet
+    supported.
+  - Only supports the case where all axes in a font are pinned.
+
+  (Garret Rieger, Qunxin Liu)
+
+- Miscellaneous fixes and improvements.
+
+  (Behdad Esfahbod, Christoph Reiter, David Corbett, Eli Schwartz, Garret
+   Rieger, Joel Auterson, Jordan Petridis, Khaled Hosny, Lorenz Wildberg,
+   Marco Rebhan, Martin Storsjö, Matthias Clasen, Qunxin Liu, Satadru Pramanik)
+
+
+- New API
++hb_subset_input_pin_axis_location()
++hb_subset_input_pin_axis_to_default()
++hb_subset_preprocess()
+
+
+Overview of changes leading to 5.3.1
+Wednesday, October 19, 2022
+====================================
+- Subsetter repacker fixes. (Garret Rieger)
+- Adjust Grapheme clusters for Katakana voiced sound marks. (Behdad Esfahbod)
+- New “hb-subset” option “--preprocess-face”. (Garret Rieger)
+
+
+Overview of changes leading to 5.3.0
+Saturday, October 8, 2022
+"Women, Life, Freedom" #MahsaAmini
+====================================
+- Don’t add glyphs from dropped MATH or COLR tables to the subset glyphs.
+  (Khaled Hosny)
+- Map “rlig” to appropriate AAT feature selectors. (Jonathan Kew)
+- Update USE data files to latest version. (David Corbett)
+- Check “CBDT” extents first before outline tables, to help with fonts that
+  also include an empty “glyf” table. (Khaled Hosny)
+- More work towards variable font instancing in the subsetter. (Qunxin Liu)
+- Subsetter repacker improvements. (Garret Rieger)
+- New API:
++hb_ot_layout_lookup_get_optical_bound()
++hb_face_builder_sort_tables()
+
+
+Overview of changes leading to 5.2.0
+Saturday, September 17, 2022
+====================================
+- Fix regressions in hb-ft font functions for FT_Face’s with transformation
+  matrix. (Behdad Esfahbod)
+- The experimental hb-repacker API now supports splitting several GPOS subtable
+  types when needed. (Garret Rieger)
+- The HarfBuzz extensions to OpenType font format are now opt-in behind
+  build-time flags. (Behdad Esfahbod)
+- The experimental hb-subset variable fonts instantiation API can now
+  instantiate more font tables and arbitrary axis locations. (Qunxin Liu)
+- Unicode 15 support. (David Corbett)
+- Various documentation improvements. (Behdad Esfahbod, Matthias Clasen)
+- The hb-view command line tool now detects WezTerm inline images support.
+  (Wez Furlong)
+- Fix FreeType and ICU dependency lookup with meson. (Xavier Claessens)
+
+- New API:
++HB_SCRIPT_KAWI
++HB_SCRIPT_NAG_MUNDARI
+
+
+Overview of changes leading to 5.1.0
+Sunday, July 31, 2022
+====================================
+- More extensive buffer tracing messages. (Behdad Esfahbod)
+- Fix hb-ft regression in bitmap fonts rendering. (Behdad Esfahbod)
+- Support extension promotion of lookups in hb-subset-repacker. (Garret Rieger)
+- A new HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL for scripts that use elongation
+  (e.g. Arabic) to signify where it is safe to insert tatweel glyph without
+  interrupting shaping. (Behdad Esfahbod)
+- Add “--safe-to-insert-tatweel” to “hb-shape” tool. (Behdad Esfahbod)
+
+- New API
++HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL
++HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL
+
+
+Overview of changes leading to 5.0.1
+Saturday, July 23, 2022
+====================================
+- Fix version 2 “avar” table with hb-ft. (Behdad Esfahbod)
+
+
+Overview of changes leading to 5.0.0
+Saturday, July 23, 2022
+====================================
+- Support fonts with more than 65535 glyphs in “GDEF”, “GSUB”, and “GPOS”
+  tables. This is part of https://github.com/be-fonts/boring-expansion-spec to
+  extend OpenType in a backward-compatible way.
+  (Behdad Esfahbod, Garret Rieger)
+- Complete support for more than 65535 glyphs in “glyf” table that started in
+  4.0.0 release. Part of boring-expansion-spec. (Behdad Esfahbod)
+- Support version 2 of “avar” table. Part of boring-expansion-spec.
+  (Behdad Esfahbod)
+- Fix mark attachment on multiple substitutions in some cases.
+  (Behdad Esfahbod)
+- Fix application of “calt”, “rclt”, and “ccmp” features to better match
+  Uniscribe behaviour with some Arabic fonts. (Behdad Esfahbod)
+- Improvement to interaction between multiple cursive attachments.
+  (Behdad Esfahbod)
+- Improve multiple mark interactions in Hebrew. (Behdad Esfahbod)
+- Implement language-specific forms in AAT shaping. (Behdad Esfahbod)
+- Fix variation of “VORG” table. (Behdad Esfahbod)
+- Support for specific script tags to be retained in the subsetter, and add
+  “--layout-scripts” option to “hb-subset” tool. (Garret Rieger)
+- Accept space as delimiter for --features/--variations in command line tools.
+- Improve subsetting of “COLR” table. (Qunxin Liu)
+- Improved fuzzing coverage for ot-math API. (Frédéric Wang)
+- Fix “kern” table version 2 (AAT) sanitization on 32-bit systems.
+  (Behdad Esfahbod)
+- Allow negative glyph advances from “graphite2” shaper. (Stephan Bergmann)
+- Implement loading (color) bitmap fonts with hb-ft. (Behdad Esfahbod)
+- Fix regression in hb-ft when changing font size. (Behdad Esfahbod)
+- Fix build on GCC < 7. (Kleis Auke Wolthuizen)
+- Dynamically load dwrite.dll on windows if “directwrite” shaper is enabled.
+  (Luca Bacci)
+- Provide a single-file harfbuzz-subset.cc file for easier alternate building
+  of hb-subset library, similar to harfbuzz.cc. (Khaled Hosny)
+
+- New API
++HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG
++hb_language_matches()
+
+
+Overview of changes leading to 4.4.1
+Wednesday, June 29, 2022
+====================================
+- Fix test failure with some compilers.
+- Fix Telugu and Kannada kerning regression.
+
+
+Overview of changes leading to 4.4.0
+Monday, June 27, 2022
+====================================
+- Caching of variable fonts shaping, in particular when using HarfBuzz’s own
+  font loading functions (ot). Bringing performance of variable shaping in par
+  with non-variable fonts shaping. (Behdad Esfahbod)
+- Caching of format 2 “Contextual Substitution” and “Chained Contexts
+  Substitution” lookups. Resulting in up to 20% speedup of lookup-heavy fonts
+  like Gulzar or Noto Nastaliq Urdu. (Behdad Esfahbod)
+- Improved ANSI output from hb-view. (Behdad Esfahbod)
+- Support for shaping legacy, pre-OpenType Windows 3.1-era, Arabic fonts that
+  relied on a fixed PUA encoding. (Khaled Hosny, Behdad Esfahbod)
+- Sinhala script is now shaped by the USE shaper instead of “indic” one.
+  (Behdad Esfahbod, David Corbett)
+- Thai shaper improvements. (David Corbett)
+- hb-ot-name API supports approximate BCP-47 language matching, for example
+  asking for “en_US” in a font that has only “en” names will return them.
+  (Behdad Esfahbod)
+- Optimized TrueType glyph shape loading. (Behdad Esfahbod)
+- Fix subsetting of HarfBuzz faces created via hb_face_create_for_tables().
+  (Garret Rieger)
+- Add 32 bit var store support to the subsetter. (Garret Rieger)
+
+- New API
++HB_BUFFER_FLAG_DEFINED
++HB_BUFFER_SERIALIZE_FLAG_DEFINED
++hb_font_changed()
++hb_font_get_serial()
++hb_ft_hb_font_changed()
++hb_set_hash()
++hb_map_copy()
++hb_map_hash()
+
+
+Overview of changes leading to 4.3.0
+Friday, May 20, 2022
+====================================
+- Major speed up in loading and subsetting fonts, especially in
+  handling CFF table. Subsetting some fonts is now 3 times faster.
+  (Behdad Esfahbod, Garret Rieger)
+- Speed up blending CFF2 table. (Behdad Esfahbod)
+- Speed up hb_ot_tags_from_language(). (Behdad Esfahbod, David Corbett)
+- Fix USE classification of U+10A38 to fix multiple marks on single Kharoshthi
+  base. (David Corbett)
+- Fix parsing of empty CFF Index. (Behdad Esfahbod)
+- Fix subsetting CPAL table with partial palette overlaps. (Garret Rieger)
+
+- New API
++hb_map_is_equal() (Behdad Esfahbod)
+
+
+Overview of changes leading to 4.2.1
+Sunday, April 24, 2022
+====================================
+- Make sure hb_blob_create_from_file_or_fail() always returns nullptr in case
+  of failure and not empty blob sometimes. (Khaled Hosny)
+- Add --passthrough-tables option to hb-subset. (Cosimo Lupo)
+- Reinstate a pause after basic features in Khmer shaper, fixing a regression
+  introduced in previous release. (Behdad Esfahbod)
+- Better handling of Regional_Indicator when shaped with RTL-native scripts,
+  reverting earlier fix that caused regressions in AAT shaping. (Behdad Esfahbod)
+
+
+Overview of changes leading to 4.2.0
+Wednesday, March 30, 2022
+====================================
+- Source code reorganization, splitting large hb-ot-layout files into smaller,
+  per-subtable ones under OT/Layout/*. Code for more tables will follow suit in
+  later releases. (Garret Rieger, Behdad Esfahbod)
+- Revert Indic shaper change in previous release that broke some fonts and
+  instead make per-syllable restriction of “GSUB” application limited to
+  script-specific Indic features, while applying them and discretionary
+  features in one go. (Behdad Esfahbod)
+- Fix decoding of private in gvar table. (Behdad Esfahbod)
+- Fix handling of contextual lookups that delete too many glyphs. (Behdad Esfahbod)
+- Make “morx” deleted glyphs don’t block “GPOS” application. (Behdad Esfahbod)
+- Various build fixes. (Chun-wei Fan, Khaled Hosny)
+
+- New API
++hb_set_next_many() (Andrew John)
+
+
+Overview of changes leading to 4.1.0
+Wednesday, March 23, 2022
+====================================
+- Various OSS-Fuzz fixes. (Behdad Esfahbod)
+- Make fallback vertical-origin match FreeType’s. (Behdad Esfahbod)
+- Treat visible viramas like dependent vowels in USE shaper. (David Corbett)
+- Apply presentation forms features and discretionary features in one go in
+  Indic shaper, which seems to match Uniscribe and CoreText behaviour.
+  (Behdad Esfahbod, David Corbett)
+- Various bug fixes.
+
+- New API
++hb_set_add_sorted_array() (Andrew John)
+
+
+Overview of changes leading to 4.0.1
+Friday, March 11, 2022
+====================================
+- Update OpenType to AAT mappings for “hist” and “vrtr” features.
+  (Florian Pircher)
+- Update IANA Language Subtag Registry to 2022-03-02. (David Corbett)
+- Update USE shaper to allow any non-numeric tail in a symbol cluster, and
+  remove obsolete data overrides. (David Corbett)
+- Fix handling of baseline variations to return correctly scaled values.
+  (Matthias Clasen)
+- A new experimental hb_subset_repack_or_fail() to repack an array of objects,
+  eliminating offset overflows. The API is not available unless HarfBuzz is
+  built with experimental APIs enabled. (Qunxin Liu)
+
+- New experimental API
++hb_link_t
++hb_object_t
++hb_subset_repack_or_fail()
+
+
+Overview of changes leading to 4.0.0
+Tuesday, March 1, 2022
+====================================
+- New public API to create subset plan and gather information on things like
+  glyph mappings in the final subset. The plan can then be passed on to perform
+  the subsetting operation. (Garret Rieger)
+- Draw API for extracting glyph shapes have been extended and finalized and is
+  no longer an experimental API. The draw API supports glyf, CFF and CFF2
+  glyph outlines tables, and applies variation settings set on the font as well
+  as synthetic slant. The new public API is not backward compatible with the
+  previous, non-public, experimental API. (Behdad Esfahbod)
+- The hb-view tool will use HarfBuzz draw API to render the glyphs instead of
+  cairo-ft when compiled with Cairo 1.17.5 or newer, setting HB_DRAW
+  environment variable to 1 or 0 will force using or not use the draw API,
+  respectively. (Behdad Esfahbod)
+- The hb-shape and hb-view tools now default to using HarfBuzz’s own font
+  loading functions (ot) instead of FreeType ones (ft). They also have a new
+  option, --font-slant, to apply synthetic slant to the font. (Behdad Esfahbod)
+- HarfBuzz now supports more than 65535 (the OpenType limit) glyph shapes and
+  metrics. See https://github.com/be-fonts/boring-expansion-spec/issues/6 and
+  https://github.com/be-fonts/boring-expansion-spec/issues/7 for details.
+  (Behdad Esfahbod)
+- New API to get the dominant horizontal baseline tag for a given script.
+  (Behdad Esfahbod)
+- New API to get the baseline positions from the font, and synthesize missing
+  ones. As well as new API to get font metrics and synthesize missing ones.
+  (Matthias Clasen)
+- Improvements to finding dependencies on Windows when building with Visual
+  Studio. (Chun-wei Fan)
+- New buffer flag, HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT, that must be set
+  during shaping for HB_GLYPH_FLAG_UNSAFE_TO_CONCAT flag to be reliably
+  produced. This is to limit the performance hit of producing this flag to when
+  it is actually needed. (Behdad Esfahbod)
+- Documentation improvements. (Matthias Clasen)
+
+- New API
+ - General:
+   +HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT
+   +hb_var_num_t
+
+ - Draw:
+   +hb_draw_funcs_t
+   +hb_draw_funcs_create()
+   +hb_draw_funcs_reference()
+   +hb_draw_funcs_destroy()
+   +hb_draw_funcs_is_immutable()
+   +hb_draw_funcs_make_immutable()
+   +hb_draw_move_to_func_t
+   +hb_draw_funcs_set_move_to_func()
+   +hb_draw_line_to_func_t
+   +hb_draw_funcs_set_line_to_func()
+   +hb_draw_quadratic_to_func_t
+   +hb_draw_funcs_set_quadratic_to_func()
+   +hb_draw_cubic_to_func_t
+   +hb_draw_funcs_set_cubic_to_func()
+   +hb_draw_close_path_func_t
+   +hb_draw_funcs_set_close_path_func()
+   +hb_draw_state_t
+   +HB_DRAW_STATE_DEFAULT
+   +hb_draw_move_to()
+   +hb_draw_line_to()
+   +hb_draw_quadratic_to()
+   +hb_draw_cubic_to()
+   +hb_draw_close_path()
+   +hb_font_get_glyph_shape_func_t
+   +hb_font_funcs_set_glyph_shape_func()
+   +hb_font_get_glyph_shape()
+
+ - OpenType layout
+   +HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL
+   +HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL
+   +hb_ot_layout_get_horizontal_baseline_tag_for_script()
+   +hb_ot_layout_get_baseline_with_fallback()
+
+ - Metrics:
+   +hb_ot_metrics_get_position_with_fallback()
+
+ - Subset:
+   +hb_subset_plan_t
+   +hb_subset_plan_create_or_fail()
+   +hb_subset_plan_reference()
+   +hb_subset_plan_destroy()
+   +hb_subset_plan_set_user_data()
+   +hb_subset_plan_get_user_data()
+   +hb_subset_plan_execute_or_fail()
+   +hb_subset_plan_unicode_to_old_glyph_mapping()
+   +hb_subset_plan_new_to_old_glyph_mapping()
+   +hb_subset_plan_old_to_new_glyph_mapping()
+
+
 Overview of changes leading to 3.4.0
 Sunday, February 13, 2022
 ====================================
@@ -10,15 +699,15 @@ Sunday, February 13, 2022
   ‘math’ tag. (Alexis King)
 - It is now possible to get at once all math kerning values for a given glyph
   at a given corner. (Alexis King)
-- Fix locale_t portability issues on systems the typdef’s it to a void pointer.
-  (Behdad Esfahbod)
+- Fix locale_t portability issues on systems the typedef’s it to a void
+  pointer. (Behdad Esfahbod)
 
 - New API:
 +HB_BUFFER_FLAG_VERIFY
 +HB_OT_TAG_MATH_SCRIPT
 +HB_SCRIPT_MATH
 +hb_ot_math_kern_entry_t
-+hb_ot_math_get_glyph_kernings
++hb_ot_math_get_glyph_kernings()
 
 - Deprecated API
 +HB_OT_MATH_SCRIPT
diff --git a/README b/README
index 84c542f..099d4b7 100644 (file)
--- a/README
+++ b/README
-This is HarfBuzz, a text shaping library.
+[![Linux CI Status](https://github.com/harfbuzz/harfbuzz/workflows/linux-ci/badge.svg)](https://github.com/harfbuzz/harfbuzz/workflows/linux-ci/badge.svg)
+[![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main)
+[![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/harfbuzz.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html)
+[![Coverity Scan Build Status](https://scan.coverity.com/projects/15166/badge.svg)](https://scan.coverity.com/projects/harfbuzz)
+[![Codacy Badge](https://app.codacy.com/project/badge/Grade/89c872f5ce1c42af802602bfcd15d90a)](https://www.codacy.com/gh/harfbuzz/harfbuzz/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=harfbuzz/harfbuzz&amp;utm_campaign=Badge_Grade)
+[![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/main/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz)
+[![Packaging status](https://repology.org/badge/tiny-repos/harfbuzz.svg)](https://repology.org/project/harfbuzz/versions)
+[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/harfbuzz/harfbuzz/badge)](https://securityscorecards.dev/viewer/?uri=github.com/harfbuzz/harfbuzz)
+
+
+# HarfBuzz
+
+HarfBuzz is a text shaping engine. It primarily supports [OpenType][1], but also
+[Apple Advanced Typography][2]. HarfBuzz is used in Android, Chrome,
+ChromeOS, Firefox, GNOME, GTK+, KDE, Qt, LibreOffice, OpenJDK, XeTeX,
+PlayStation, Microsoft Edge, Photoshop, Illustrator, InDesign,
+and other places.
 
 For bug reports, mailing list, and other information please visit:
 
   http://harfbuzz.org/
 
-For license information, see https://github.com/harfbuzz/harfbuzz/blob/main/COPYING
+For license information, see [COPYING](COPYING).
+
+## Documentation
+
+For user manual as well as API documentation, check: https://harfbuzz.github.io
+
+## Download
+
+For tarball releases of HarfBuzz, look [here][3]. At the same place you
+will also find Win32/Win64 binary bundles that include `libharfbuzz` DLL,
+`hb-view.exe`, `hb-shape.exe`, and all dependencies.
+
+The canonical source tree is available on [github][4].
+
+The API that comes with `hb.h` will not change incompatibly. Other, peripheral,
+headers are more likely to go through minor modifications, but again, we do our
+best to never change API in an incompatible way. We will never break the ABI.
+
+If you are not sure whether Pango or HarfBuzz is right for you, read [Pango vs
+HarfBuzz][5].
+
+## Development
+
+For build information, see [BUILD.md](BUILD.md).
+
+For custom configurations, see [CONFIG.md](CONFIG.md).
+
+For testing and profiling, see [TESTING.md](TESTING.md).
+
+To get a better idea of where HarfBuzz stands in the text rendering stack you
+may want to read [State of Text Rendering][6], though, that document is many
+years old. Here are a few presentation slides about HarfBuzz at the
+Internationalization and Unicode Conference over the years:
+
+*   November 2014, [Unicode, OpenType, and HarfBuzz: Closing the Circle][7],
+*   October 2012, [HarfBuzz, The Free and Open Text Shaping Engine][8],
+*   October 2009, [HarfBuzz: the Free and Open Shaping Engine][9].
+
+Both development and user support discussion around HarfBuzz happens on the
+[github][4].
+
+To report bugs or submit patches please use [github][4] issues and
+pull-requests.
+
+For a comparison of old vs new HarfBuzz memory consumption see [this][10].
+
+<!--See past and upcoming [HarfBuzz Hackfests](https://freedesktop.org/wiki/Software/HarfBuzz/Hackfests/)!-->
+
+## Name
+
+HarfBuzz (حرف‌باز) is my Persian translation of “[OpenType][1]”,
+transliterated using the Latin script. It sports a second meaning, but that
+ain’t translatable.
+
+> Background: Originally there was this font format called TrueType. People and
+> companies started calling their type engines all things ending in Type:
+> FreeType, CoolType, ClearType, etc. And then came OpenType, which is the
+> successor of TrueType. So, for my OpenType implementation, I decided to stick
+> with the concept but use the Persian translation. Which is fitting given that
+> Persian is written in the Arabic script, and OpenType is an extension of
+> TrueType that adds support for complex script rendering, and HarfBuzz is an
+> implementation of OpenType complex text shaping.
 
-For build information, see https://github.com/harfbuzz/harfbuzz/blob/main/BUILD.md
+<details>
+  <summary>Packaging status of HarfBuzz</summary>
 
-For custom configurations, see https://github.com/harfbuzz/harfbuzz/blob/main/CONFIG.md
+[![Packaging status](https://repology.org/badge/vertical-allrepos/harfbuzz.svg?header=harfbuzz)](https://repology.org/project/harfbuzz/versions)
 
-For test execution, see https://github.com/harfbuzz/harfbuzz/blob/main/TESTING.md
+</details>
 
-Documentation: https://harfbuzz.github.io
+[1]: https://docs.microsoft.com/en-us/typography/opentype/spec/
+[2]: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6AATIntro.html
+[3]: https://github.com/harfbuzz/harfbuzz/releases
+[4]: https://github.com/harfbuzz/harfbuzz
+[5]: http://mces.blogspot.com/2009/11/pango-vs-harfbuzz.html
+[6]: http://behdad.org/text/
+[7]: https://goo.gl/FSIQuC
+[8]: https://goo.gl/2wSRu
+[9]: http://behdad.org/download/Presentations/slippy/harfbuzz_slides.pdf
+[10]: https://goo.gl/woyty
index 9deb32c..099d4b7 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,14 +1,20 @@
 [![Linux CI Status](https://github.com/harfbuzz/harfbuzz/workflows/linux-ci/badge.svg)](https://github.com/harfbuzz/harfbuzz/workflows/linux-ci/badge.svg)
 [![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main)
 [![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/harfbuzz.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html)
-[![Coverity Code Health](https://img.shields.io/coverity/scan/5450.svg)](https://scan.coverity.com/projects/behdad-harfbuzz)
-[![Codacy Code Health](https://api.codacy.com/project/badge/Grade/f17f1708783c447488bc8dd317150eaa)](https://app.codacy.com/app/behdad/harfbuzz)
+[![Coverity Scan Build Status](https://scan.coverity.com/projects/15166/badge.svg)](https://scan.coverity.com/projects/harfbuzz)
+[![Codacy Badge](https://app.codacy.com/project/badge/Grade/89c872f5ce1c42af802602bfcd15d90a)](https://www.codacy.com/gh/harfbuzz/harfbuzz/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=harfbuzz/harfbuzz&amp;utm_campaign=Badge_Grade)
 [![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/main/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz)
-[![Coverals Code Coverage](https://img.shields.io/coveralls/harfbuzz/harfbuzz.svg)](https://coveralls.io/r/harfbuzz/harfbuzz)
 [![Packaging status](https://repology.org/badge/tiny-repos/harfbuzz.svg)](https://repology.org/project/harfbuzz/versions)
-[ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
+[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/harfbuzz/harfbuzz/badge)](https://securityscorecards.dev/viewer/?uri=github.com/harfbuzz/harfbuzz)
 
-This is HarfBuzz, a text shaping library.
+
+# HarfBuzz
+
+HarfBuzz is a text shaping engine. It primarily supports [OpenType][1], but also
+[Apple Advanced Typography][2]. HarfBuzz is used in Android, Chrome,
+ChromeOS, Firefox, GNOME, GTK+, KDE, Qt, LibreOffice, OpenJDK, XeTeX,
+PlayStation, Microsoft Edge, Photoshop, Illustrator, InDesign,
+and other places.
 
 For bug reports, mailing list, and other information please visit:
 
@@ -16,14 +22,66 @@ For bug reports, mailing list, and other information please visit:
 
 For license information, see [COPYING](COPYING).
 
+## Documentation
+
+For user manual as well as API documentation, check: https://harfbuzz.github.io
+
+## Download
+
+For tarball releases of HarfBuzz, look [here][3]. At the same place you
+will also find Win32/Win64 binary bundles that include `libharfbuzz` DLL,
+`hb-view.exe`, `hb-shape.exe`, and all dependencies.
+
+The canonical source tree is available on [github][4].
+
+The API that comes with `hb.h` will not change incompatibly. Other, peripheral,
+headers are more likely to go through minor modifications, but again, we do our
+best to never change API in an incompatible way. We will never break the ABI.
+
+If you are not sure whether Pango or HarfBuzz is right for you, read [Pango vs
+HarfBuzz][5].
+
+## Development
+
 For build information, see [BUILD.md](BUILD.md).
 
 For custom configurations, see [CONFIG.md](CONFIG.md).
 
-For test execution, see [TESTING.md](TESTING.md).
+For testing and profiling, see [TESTING.md](TESTING.md).
+
+To get a better idea of where HarfBuzz stands in the text rendering stack you
+may want to read [State of Text Rendering][6], though, that document is many
+years old. Here are a few presentation slides about HarfBuzz at the
+Internationalization and Unicode Conference over the years:
+
+*   November 2014, [Unicode, OpenType, and HarfBuzz: Closing the Circle][7],
+*   October 2012, [HarfBuzz, The Free and Open Text Shaping Engine][8],
+*   October 2009, [HarfBuzz: the Free and Open Shaping Engine][9].
+
+Both development and user support discussion around HarfBuzz happens on the
+[github][4].
+
+To report bugs or submit patches please use [github][4] issues and
+pull-requests.
 
-Documentation: https://harfbuzz.github.io
+For a comparison of old vs new HarfBuzz memory consumption see [this][10].
 
+<!--See past and upcoming [HarfBuzz Hackfests](https://freedesktop.org/wiki/Software/HarfBuzz/Hackfests/)!-->
+
+## Name
+
+HarfBuzz (حرف‌باز) is my Persian translation of “[OpenType][1]”,
+transliterated using the Latin script. It sports a second meaning, but that
+ain’t translatable.
+
+> Background: Originally there was this font format called TrueType. People and
+> companies started calling their type engines all things ending in Type:
+> FreeType, CoolType, ClearType, etc. And then came OpenType, which is the
+> successor of TrueType. So, for my OpenType implementation, I decided to stick
+> with the concept but use the Persian translation. Which is fitting given that
+> Persian is written in the Arabic script, and OpenType is an extension of
+> TrueType that adds support for complex script rendering, and HarfBuzz is an
+> implementation of OpenType complex text shaping.
 
 <details>
   <summary>Packaging status of HarfBuzz</summary>
@@ -31,3 +89,14 @@ Documentation: https://harfbuzz.github.io
 [![Packaging status](https://repology.org/badge/vertical-allrepos/harfbuzz.svg?header=harfbuzz)](https://repology.org/project/harfbuzz/versions)
 
 </details>
+
+[1]: https://docs.microsoft.com/en-us/typography/opentype/spec/
+[2]: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6AATIntro.html
+[3]: https://github.com/harfbuzz/harfbuzz/releases
+[4]: https://github.com/harfbuzz/harfbuzz
+[5]: http://mces.blogspot.com/2009/11/pango-vs-harfbuzz.html
+[6]: http://behdad.org/text/
+[7]: https://goo.gl/FSIQuC
+[8]: https://goo.gl/2wSRu
+[9]: http://behdad.org/download/Presentations/slippy/harfbuzz_slides.pdf
+[10]: https://goo.gl/woyty
index 7496f04..c945d08 100644 (file)
@@ -9,9 +9,13 @@ sudo apt-get install libgirepository1.0-dev
 And then run `meson setup` and make sure that `Introspection` is reported
 enabled in output.
 
+If you are building with Visual Studio, it is recommended that Visual Studio
+2019 or later is used for this build, for the best build experience.
+
 Compile and install.
 
-Make sure you have the installation lib dir in `LD_LIBRARY_PATH`, as needed
+Make sure you have the installation lib dir in `LD_LIBRARY_PATH` (or the
+installation DLL dir in `PATH` for Windows systems), as needed
 for the linker to find the library.
 
 Then make sure you also have `GI_TYPELIB_PATH` pointing to the resulting
index 8d5a406..2e5f2bd 100644 (file)
@@ -17,7 +17,7 @@
 
 - [ ] Based on severity of changes, decide whether it's a minor or micro release number bump.
 
-- [ ] Search for REPLACEME on the repository and replace it with the chosen version for the release.
+- [ ] Search for 'XSince: REPLACEME' on the repository and replace it with the chosen version for the release, e.g. 'Since: 1.4.7'.
 
 - [ ] Make sure you have correct date and new version at the top of NEWS file.
 
index c722834..18d7020 100644 (file)
@@ -39,17 +39,9 @@ ninja -C build
 
 ## Test with the Fuzzer
 
-```shell
-CXXFLAGS="-fsanitize=address,fuzzer-no-link" meson fuzzbuild --default-library=static -Dfuzzer_ldflags="-fsanitize=address,fuzzer" -Dexperimental_api=true
-ninja -Cfuzzbuild test/fuzzing/hb-{shape,draw,subset,set}-fuzzer
-fuzzbuild/test/fuzzing/hb-subset-fuzzer test/fuzzing/fonts
-```
+FOr fuzzing, see `test/fuzzing/README.md`.
 
 ## Profiling
 
-```
-meson build --reconfigure
-meson compile -C build
-build/perf/perf
-```
+For profiling, see `perf/README.md`.
 
diff --git a/TODO b/TODO
deleted file mode 100644 (file)
index d8e4105..0000000
--- a/TODO
+++ /dev/null
@@ -1,28 +0,0 @@
-API issues:
-===========
-
-- API to accept a list of languages?
-
-- Remove hb_ot_shape_glyphs_closure()?
-
-
-API additions
-=============
-
-- Language to/from script.
-
-- Add hb-cairo glue
-
-- Add sanitize API.
-
-- Add query / enumeration API for aalt-like features?
-
-- Add segmentation API
-
-- Add hb-fribidi glue?
-
-
-hb-view / hb-shape enhancements:
-===============================
-
-- Add --width, --height, --auto-size, --ink-box, --align, etc?
index 409cc8e..ab960fb 100644 (file)
 /* Have cairo-ft support in cairo graphics library */
 #undef HAVE_CAIRO_FT
 
+/* Define to 1 if you have the
+   `cairo_user_font_face_set_render_color_glyph_func' function. */
+#undef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
+
 /* Have chafa terminal graphics library */
 #undef HAVE_CHAFA
 
@@ -27,8 +31,8 @@
 /* Define to 1 if you have the <dlfcn.h> header file. */
 #undef HAVE_DLFCN_H
 
-/* Define to 1 if you have the <dwrite.h> header file. */
-#undef HAVE_DWRITE_H
+/* Define to 1 if you have the <dwrite_1.h> header file. */
+#undef HAVE_DWRITE_1_H
 
 /* Have FreeType 2 library */
 #undef HAVE_FREETYPE
@@ -36,6 +40,9 @@
 /* Define to 1 if you have the `FT_Done_MM_Var' function. */
 #undef HAVE_FT_DONE_MM_VAR
 
+/* Define to 1 if you have the `FT_Get_Transform' function. */
+#undef HAVE_FT_GET_TRANSFORM
+
 /* Define to 1 if you have the `FT_Get_Var_Blend_Coordinates' function. */
 #undef HAVE_FT_GET_VAR_BLEND_COORDINATES
 
@@ -87,6 +94,9 @@
 /* Have PTHREAD_PRIO_INHERIT. */
 #undef HAVE_PTHREAD_PRIO_INHERIT
 
+/* Define to 1 if you have the `sincosf' function. */
+#undef HAVE_SINCOSF
+
 /* Define to 1 if you have the <stdbool.h> header file. */
 #undef HAVE_STDBOOL_H
 
 /* Define to 1 if you have the <usp10.h> header file. */
 #undef HAVE_USP10_H
 
+/* Have wasm-micro-runtime library */
+#undef HAVE_WASM
+
+/* Define to 1 if you have the <wasm_export.h> header file. */
+#undef HAVE_WASM_EXPORT_H
+
 /* Define to 1 if you have the <windows.h> header file. */
 #undef HAVE_WINDOWS_H
 
index 969a83a..589bc1a 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for HarfBuzz 3.4.0.
+# Generated by GNU Autoconf 2.69 for HarfBuzz 8.2.2.
 #
 # Report bugs to <https://github.com/harfbuzz/harfbuzz/issues/new>.
 #
@@ -590,8 +590,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='HarfBuzz'
 PACKAGE_TARNAME='harfbuzz'
-PACKAGE_VERSION='3.4.0'
-PACKAGE_STRING='HarfBuzz 3.4.0'
+PACKAGE_VERSION='8.2.2'
+PACKAGE_STRING='HarfBuzz 8.2.2'
 PACKAGE_BUGREPORT='https://github.com/harfbuzz/harfbuzz/issues/new'
 PACKAGE_URL='http://harfbuzz.org/'
 
@@ -636,14 +636,16 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+HAVE_WASM_FALSE
+HAVE_WASM_TRUE
+WASM_LIBS
+WASM_CFLAGS
 HAVE_CORETEXT_FALSE
 HAVE_CORETEXT_TRUE
 CORETEXT_LIBS
 CORETEXT_CFLAGS
 HAVE_DIRECTWRITE_FALSE
 HAVE_DIRECTWRITE_TRUE
-DIRECTWRITE_LIBS
-DIRECTWRITE_CXXFLAGS
 HAVE_GDI_FALSE
 HAVE_GDI_TRUE
 GDI_LIBS
@@ -911,6 +913,7 @@ with_uniscribe
 with_gdi
 with_directwrite
 with_coretext
+with_wasm
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1497,7 +1500,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures HarfBuzz 3.4.0 to adapt to many kinds of systems.
+\`configure' configures HarfBuzz 8.2.2 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1568,7 +1571,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of HarfBuzz 3.4.0:";;
+     short | recursive ) echo "Configuration of HarfBuzz 8.2.2:";;
    esac
   cat <<\_ACEOF
 
@@ -1633,6 +1636,8 @@ Optional Packages:
                           [default=no]
   --with-coretext=[yes/no/auto]
                           Use CoreText [default=no]
+  --with-wasm=[yes/no/auto]
+                          Use the wasm-micro-runtime library [default=no]
 
 Some influential environment variables:
   CC          C compiler command
@@ -1751,7 +1756,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-HarfBuzz configure 3.4.0
+HarfBuzz configure 8.2.2
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2569,7 +2574,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by HarfBuzz $as_me 3.4.0, which was
+It was created by HarfBuzz $as_me 8.2.2, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -3438,7 +3443,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='harfbuzz'
- VERSION='3.4.0'
+ VERSION='8.2.2'
 
 
 # Some tools Automake needs.
@@ -19354,10 +19359,10 @@ GIT=${GIT-"${am_missing_run}git"}
 
 
 
-HB_VERSION_MAJOR=3
-HB_VERSION_MINOR=4
-HB_VERSION_MICRO=0
-HB_VERSION=3.4.0
+HB_VERSION_MAJOR=8
+HB_VERSION_MINOR=2
+HB_VERSION_MICRO=2
+HB_VERSION=8.2.2
 
 
 
@@ -19365,7 +19370,7 @@ HB_VERSION=3.4.0
 
 # Libtool version
 
-HB_LIBTOOL_VERSION_INFO=30400:0:30400
+HB_LIBTOOL_VERSION_INFO=60822:0:60822
 
 
 
@@ -19764,7 +19769,7 @@ fi
 
 
 # Functions and headers
-for ac_func in atexit mprotect sysconf getpagesize mmap isatty newlocale uselocale
+for ac_func in atexit mprotect sysconf getpagesize mmap isatty newlocale uselocale sincosf
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -21035,6 +21040,20 @@ else
 $as_echo "yes" >&6; }
        have_cairo=true
 fi
+       save_libs=$LIBS
+       LIBS="$LIBS $CAIRO_LIBS"
+       for ac_func in cairo_user_font_face_set_render_color_glyph_func
+do :
+  ac_fn_c_check_func "$LINENO" "cairo_user_font_face_set_render_color_glyph_func" "ac_cv_func_cairo_user_font_face_set_render_color_glyph_func"
+if test "x$ac_cv_func_cairo_user_font_face_set_render_color_glyph_func" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC 1
+_ACEOF
+
+fi
+done
+
+       LIBS=$save_libs
 fi
 if test "x$with_cairo" = "xyes" -a "x$have_cairo" != "xtrue"; then
        as_fn_error $? "cairo support requested but not found" "$LINENO" 5
@@ -21570,7 +21589,7 @@ $as_echo "#define HAVE_FREETYPE 1" >>confdefs.h
 
        save_libs=$LIBS
        LIBS="$LIBS $FREETYPE_LIBS"
-       for ac_func in FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var
+       for ac_func in FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var FT_Get_Transform
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -21702,12 +21721,12 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
 
 if test "x$with_directwrite" = "xyes" -o "x$with_directwrite" = "xauto"; then
 
-for ac_header in dwrite.h
+for ac_header in dwrite_1.h
 do :
-  ac_fn_cxx_check_header_mongrel "$LINENO" "dwrite.h" "ac_cv_header_dwrite_h" "$ac_includes_default"
-if test "x$ac_cv_header_dwrite_h" = xyes; then :
+  ac_fn_cxx_check_header_mongrel "$LINENO" "dwrite_1.h" "ac_cv_header_dwrite_1_h" "$ac_includes_default"
+if test "x$ac_cv_header_dwrite_1_h" = xyes; then :
   cat >>confdefs.h <<_ACEOF
-#define HAVE_DWRITE_H 1
+#define HAVE_DWRITE_1_H 1
 _ACEOF
  have_directwrite=true
 fi
@@ -21725,10 +21744,6 @@ if test "x$with_directwrite" = "xyes" -a "x$have_directwrite" != "xtrue"; then
        as_fn_error $? "directwrite support requested but not found" "$LINENO" 5
 fi
 if $have_directwrite; then
-       DIRECTWRITE_CXXFLAGS=
-       DIRECTWRITE_LIBS=
-
-
 
 $as_echo "#define HAVE_DIRECTWRITE 1" >>confdefs.h
 
 
 
 
-ac_config_files="$ac_config_files Makefile src/Makefile src/harfbuzz-config.cmake util/Makefile test/Makefile test/api/Makefile test/fuzzing/Makefile test/shape/Makefile test/shape/data/Makefile test/shape/data/aots/Makefile test/shape/data/in-house/Makefile test/shape/data/text-rendering-tests/Makefile test/subset/Makefile test/subset/data/Makefile test/subset/data/repack_tests/Makefile docs/Makefile docs/version.xml"
+
+# Check whether --with-wasm was given.
+if test "${with_wasm+set}" = set; then :
+  withval=$with_wasm;
+else
+  with_wasm=no
+fi
+
+have_wasm=false
+if test "x$with_wasm" = "xyes" -o "x$with_wasm" = "xauto"; then
+       for ac_header in wasm_export.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "wasm_export.h" "ac_cv_header_wasm_export_h" "$ac_includes_default"
+if test "x$ac_cv_header_wasm_export_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_WASM_EXPORT_H 1
+_ACEOF
+ have_wasm=true
+fi
+
+done
+
+fi
+if test "x$with_wasm" = "xyes" -a "x$have_wasm" != "xtrue"; then
+       as_fn_error $? "wasm support requested but not found" "$LINENO" 5
+fi
+if $have_wasm; then
+       WASM_CFLAGS=
+       WASM_LIBS="-liwasm"
+
+
+
+$as_echo "#define HAVE_WASM 1" >>confdefs.h
+
+fi
+ if $have_wasm; then
+  HAVE_WASM_TRUE=
+  HAVE_WASM_FALSE='#'
+else
+  HAVE_WASM_TRUE='#'
+  HAVE_WASM_FALSE=
+fi
+
+
+
+ac_config_files="$ac_config_files Makefile src/Makefile src/harfbuzz-config.cmake util/Makefile test/Makefile test/api/Makefile test/fuzzing/Makefile test/shape/Makefile test/shape/data/Makefile test/shape/data/aots/Makefile test/shape/data/in-house/Makefile test/shape/data/text-rendering-tests/Makefile test/subset/Makefile test/subset/data/Makefile test/subset/data/repack_tests/Makefile test/threads/Makefile perf/Makefile docs/Makefile docs/version.xml"
 
 
 cat >confcache <<\_ACEOF
@@ -22051,6 +22111,10 @@ if test -z "${HAVE_CORETEXT_TRUE}" && test -z "${HAVE_CORETEXT_FALSE}"; then
   as_fn_error $? "conditional \"HAVE_CORETEXT\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${HAVE_WASM_TRUE}" && test -z "${HAVE_WASM_FALSE}"; then
+  as_fn_error $? "conditional \"HAVE_WASM\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 
 : "${CONFIG_STATUS=./config.status}"
 ac_write_fail=0
@@ -22448,7 +22512,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by HarfBuzz $as_me 3.4.0, which was
+This file was extended by HarfBuzz $as_me 8.2.2, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -22515,7 +22579,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-HarfBuzz config.status 3.4.0
+HarfBuzz config.status 8.2.2
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
@@ -23043,6 +23107,8 @@ do
     "test/subset/Makefile") CONFIG_FILES="$CONFIG_FILES test/subset/Makefile" ;;
     "test/subset/data/Makefile") CONFIG_FILES="$CONFIG_FILES test/subset/data/Makefile" ;;
     "test/subset/data/repack_tests/Makefile") CONFIG_FILES="$CONFIG_FILES test/subset/data/repack_tests/Makefile" ;;
+    "test/threads/Makefile") CONFIG_FILES="$CONFIG_FILES test/threads/Makefile" ;;
+    "perf/Makefile") CONFIG_FILES="$CONFIG_FILES perf/Makefile" ;;
     "docs/Makefile") CONFIG_FILES="$CONFIG_FILES docs/Makefile" ;;
     "docs/version.xml") CONFIG_FILES="$CONFIG_FILES docs/version.xml" ;;
 
@@ -24525,6 +24591,7 @@ Platform shapers (not normally needed):
        DirectWrite:            ${have_directwrite}
        GDI:                    ${have_gdi}
        Uniscribe:              ${have_uniscribe}
+       WebAssembly:            ${have_wasm}
 
 Other features:
        Documentation:          ${enable_gtk_doc}
@@ -24555,6 +24622,7 @@ Platform shapers (not normally needed):
        DirectWrite:            ${have_directwrite}
        GDI:                    ${have_gdi}
        Uniscribe:              ${have_uniscribe}
+       WebAssembly:            ${have_wasm}
 
 Other features:
        Documentation:          ${enable_gtk_doc}
index 24048cf..fbcd257 100644 (file)
@@ -1,6 +1,6 @@
 AC_PREREQ([2.64])
 AC_INIT([HarfBuzz],
-        [3.4.0],
+        [8.2.2],
         [https://github.com/harfbuzz/harfbuzz/issues/new],
         [harfbuzz],
         [http://harfbuzz.org/])
@@ -45,7 +45,7 @@ AC_SUBST(HB_VERSION)
 
 # Libtool version
 m4_define([hb_version_int],
-         m4_eval(hb_version_major*10000 + hb_version_minor*100 + hb_version_micro))
+         m4_eval(60000 + hb_version_major*100 + hb_version_minor*10 + hb_version_micro))
 HB_LIBTOOL_VERSION_INFO=hb_version_int:0:hb_version_int
 AC_SUBST(HB_LIBTOOL_VERSION_INFO)
 
@@ -68,7 +68,7 @@ GTK_DOC_CHECK([1.15],[--flavour no-tmpl])
 ])
 
 # Functions and headers
-AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale uselocale)
+AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale uselocale sincosf)
 AC_CHECK_HEADERS(unistd.h sys/mman.h stdbool.h xlocale.h)
 
 # Compiler flags
@@ -194,6 +194,10 @@ AC_ARG_WITH(cairo,
 have_cairo=false
 if test "x$with_cairo" = "xyes" -o "x$with_cairo" = "xauto"; then
        PKG_CHECK_MODULES(CAIRO, cairo >= 1.8.0, have_cairo=true, :)
+       save_libs=$LIBS
+       LIBS="$LIBS $CAIRO_LIBS"
+       AC_CHECK_FUNCS(cairo_user_font_face_set_render_color_glyph_func)
+       LIBS=$save_libs
 fi
 if test "x$with_cairo" = "xyes" -a "x$have_cairo" != "xtrue"; then
        AC_MSG_ERROR([cairo support requested but not found])
@@ -304,7 +308,7 @@ if $have_freetype; then
        AC_DEFINE(HAVE_FREETYPE, 1, [Have FreeType 2 library])
        save_libs=$LIBS
        LIBS="$LIBS $FREETYPE_LIBS"
-       AC_CHECK_FUNCS(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var)
+       AC_CHECK_FUNCS(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var FT_Get_Transform)
        LIBS=$save_libs
 fi
 AM_CONDITIONAL(HAVE_FREETYPE, $have_freetype)
@@ -362,17 +366,13 @@ AC_ARG_WITH(directwrite,
 have_directwrite=false
 AC_LANG_PUSH([C++])
 if test "x$with_directwrite" = "xyes" -o "x$with_directwrite" = "xauto"; then
-       AC_CHECK_HEADERS(dwrite.h, have_directwrite=true)
+       AC_CHECK_HEADERS(dwrite_1.h, have_directwrite=true)
 fi
 AC_LANG_POP([C++])
 if test "x$with_directwrite" = "xyes" -a "x$have_directwrite" != "xtrue"; then
        AC_MSG_ERROR([directwrite support requested but not found])
 fi
 if $have_directwrite; then
-       DIRECTWRITE_CXXFLAGS=
-       DIRECTWRITE_LIBS=
-       AC_SUBST(DIRECTWRITE_CXXFLAGS)
-       AC_SUBST(DIRECTWRITE_LIBS)
        AC_DEFINE(HAVE_DIRECTWRITE, 1, [Have DirectWrite library])
 fi
 AM_CONDITIONAL(HAVE_DIRECTWRITE, $have_directwrite)
@@ -417,6 +417,28 @@ AM_CONDITIONAL(HAVE_CORETEXT, $have_coretext)
 
 dnl ===========================================================================
 
+AC_ARG_WITH(wasm,
+       [AS_HELP_STRING([--with-wasm=@<:@yes/no/auto@:>@],
+                       [Use the wasm-micro-runtime library @<:@default=no@:>@])],,
+       [with_wasm=no])
+have_wasm=false
+if test "x$with_wasm" = "xyes" -o "x$with_wasm" = "xauto"; then
+       AC_CHECK_HEADERS(wasm_export.h, have_wasm=true)
+fi
+if test "x$with_wasm" = "xyes" -a "x$have_wasm" != "xtrue"; then
+       AC_MSG_ERROR([wasm support requested but not found])
+fi
+if $have_wasm; then
+       WASM_CFLAGS=
+       WASM_LIBS="-liwasm"
+       AC_SUBST(WASM_CFLAGS)
+       AC_SUBST(WASM_LIBS)
+       AC_DEFINE(HAVE_WASM, 1, [Have wasm-micro-runtime library])
+fi
+AM_CONDITIONAL(HAVE_WASM, $have_wasm)
+
+dnl ===========================================================================
+
 AC_CONFIG_FILES([
 Makefile
 src/Makefile
@@ -433,6 +455,8 @@ test/shape/data/text-rendering-tests/Makefile
 test/subset/Makefile
 test/subset/data/Makefile
 test/subset/data/repack_tests/Makefile
+test/threads/Makefile
+perf/Makefile
 docs/Makefile
 docs/version.xml
 ])
@@ -476,6 +500,7 @@ Platform shapers (not normally needed):
        DirectWrite:            ${have_directwrite}
        GDI:                    ${have_gdi}
        Uniscribe:              ${have_uniscribe}
+       WebAssembly:            ${have_wasm}
 
 Other features:
        Documentation:          ${enable_gtk_doc}
index 36da8ae..a9de8eb 100644 (file)
@@ -29,7 +29,7 @@ SCANGOBJ_OPTIONS=
 # Extra options to supply to gtkdoc-scan.
 # e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
 SCAN_OPTIONS=--rebuild-types --deprecated-guards="HB_DISABLE_DEPRECATED" \
-       --ignore-decorators='HB_EXTERN|HB_DEPRECATED'
+       --ignore-decorators='HB_EXTERN|HB_DEPRECATED|HB_DEPRECATED_FOR()'
 
 # Header files or dirs to ignore when scanning. Use base file/dir names
 # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
index 8e0aeb2..abb7b90 100644 (file)
@@ -187,8 +187,6 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
-DIRECTWRITE_CXXFLAGS = @DIRECTWRITE_CXXFLAGS@
-DIRECTWRITE_LIBS = @DIRECTWRITE_LIBS@
 DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -286,6 +284,8 @@ STRIP = @STRIP@
 UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
 UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
 VERSION = @VERSION@
+WASM_CFLAGS = @WASM_CFLAGS@
+WASM_LIBS = @WASM_LIBS@
 _GI_EXP_DATADIR = @_GI_EXP_DATADIR@
 _GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@
 abs_builddir = @abs_builddir@
@@ -374,7 +374,7 @@ SCANGOBJ_OPTIONS =
 # Extra options to supply to gtkdoc-scan.
 # e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
 SCAN_OPTIONS = --rebuild-types --deprecated-guards="HB_DISABLE_DEPRECATED" \
-       --ignore-decorators='HB_EXTERN|HB_DEPRECATED'
+       --ignore-decorators='HB_EXTERN|HB_DEPRECATED|HB_DEPRECATED_FOR()'
 
 
 # Header files or dirs to ignore when scanning. Use base file/dir names
index d81b9fd..59bf821 100644 (file)
@@ -56,6 +56,9 @@
         <xi:include href="xml/hb-blob.xml"/>
         <xi:include href="xml/hb-buffer.xml"/>
         <xi:include href="xml/hb-common.xml"/>
+        <xi:include href="xml/hb-features.xml"/>
+        <xi:include href="xml/hb-draw.xml"/>
+        <xi:include href="xml/hb-paint.xml"/>
         <xi:include href="xml/hb-deprecated.xml"/>
         <xi:include href="xml/hb-face.xml"/>
         <xi:include href="xml/hb-font.xml"/>
@@ -95,6 +98,7 @@
         <xi:include href="xml/hb-uniscribe.xml"/>
         <xi:include href="xml/hb-gdi.xml"/>
         <xi:include href="xml/hb-directwrite.xml"/>
+        <xi:include href="xml/hb-cairo.xml"/>
       </chapter>
 
       <chapter id="style-api">
       </chapter-->
 
       <index id="api-index-full"><title>API Index</title><xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include></index>
-      <index id="deprecated-api-index" role="deprecated"><title>Index of deprecated API</title><xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include></index>
-
-      <index id="api-index-3-4-0" role="3.4.0"><title>Index of new symbols in 3.4.0</title><xi:include href="xml/api-index-3.4.0.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-3-3-0" role="3.3.0"><title>Index of new symbols in 3.3.0</title><xi:include href="xml/api-index-3.3.0.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-3-1-0" role="3.1.0"><title>Index of new symbols in 3.1.0</title><xi:include href="xml/api-index-3.1.0.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-3-0-0" role="3.0.0"><title>Index of new symbols in 3.0.0</title><xi:include href="xml/api-index-3.0.0.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-2-9-1" role="2.9.1"><title>Index of new symbols in 2.9.1</title><xi:include href="xml/api-index-2.9.1.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-2-9-0" role="2.9.0"><title>Index of new symbols in 2.9.0</title><xi:include href="xml/api-index-2.9.0.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-2-8-2" role="2.8.2"><title>Index of new symbols in 2.8.2</title><xi:include href="xml/api-index-2.8.2.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-2-7-3" role="2.7.3"><title>Index of new symbols in 2.7.3</title><xi:include href="xml/api-index-2.7.3.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-2-6-8" role="2.6.8"><title>Index of new symbols in 2.6.8</title><xi:include href="xml/api-index-2.6.8.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-2-6-5" role="2.6.5"><title>Index of new symbols in 2.6.5</title><xi:include href="xml/api-index-2.6.5.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-2-6-3" role="2.6.3"><title>Index of new symbols in 2.6.3</title><xi:include href="xml/api-index-2.6.3.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-2-6-0" role="2.6.0"><title>Index of new symbols in 2.6.0</title><xi:include href="xml/api-index-2.6.0.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-2-5-0" role="2.5.0"><title>Index of new symbols in 2.5.0</title><xi:include href="xml/api-index-2.5.0.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-2-4-0" role="2.4.0"><title>Index of new symbols in 2.4.0</title><xi:include href="xml/api-index-2.4.0.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-2-3-0" role="2.3.0"><title>Index of new symbols in 2.3.0</title><xi:include href="xml/api-index-2.3.0.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-2-2-0" role="2.2.0"><title>Index of new symbols in 2.2.0</title><xi:include href="xml/api-index-2.2.0.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-2-1-0" role="2.1.0"><title>Index of new symbols in 2.1.0</title><xi:include href="xml/api-index-2.1.0.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-2-0-0" role="2.0.0"><title>Index of new symbols in 2.0.0</title><xi:include href="xml/api-index-2.0.0.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-1-9-0" role="1.9.0"><title>Index of new symbols in 1.9.0</title><xi:include href="xml/api-index-1.9.0.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-1-8-6" role="1.8.6"><title>Index of new symbols in 1.8.6</title><xi:include href="xml/api-index-1.8.6.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-1-8-5" role="1.8.5"><title>Index of new symbols in 1.8.5</title><xi:include href="xml/api-index-1.8.5.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-1-8-1" role="1.8.1"><title>Index of new symbols in 1.8.1</title><xi:include href="xml/api-index-1.8.1.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-1-8-0" role="1.8.0"><title>Index of new symbols in 1.8.0</title><xi:include href="xml/api-index-1.8.0.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-1-7-7" role="1.7.7"><title>Index of new symbols in 1.7.7</title><xi:include href="xml/api-index-1.7.7.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-1-7-5" role="1.7.5"><title>Index of new symbols in 1.7.5</title><xi:include href="xml/api-index-1.7.5.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-1-7-2" role="1.7.2"><title>Index of new symbols in 1.7.2</title><xi:include href="xml/api-index-1.7.2.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-1-6-0" role="1.6.0"><title>Index of new symbols in 1.6.0</title><xi:include href="xml/api-index-1.6.0.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-1-5-0" role="1.5.0"><title>Index of new symbols in 1.5.0</title><xi:include href="xml/api-index-1.5.0.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-1-4-3" role="1.4.3"><title>Index of new symbols in 1.4.3</title><xi:include href="xml/api-index-1.4.3.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-1-4-2" role="1.4.2"><title>Index of new symbols in 1.4.2</title><xi:include href="xml/api-index-1.4.2.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-1-4-0" role="1.4.0"><title>Index of new symbols in 1.4.0</title><xi:include href="xml/api-index-1.4.0.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-1-3-3" role="1.3.3"><title>Index of new symbols in 1.3.3</title><xi:include href="xml/api-index-1.3.3.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-1-2-3" role="1.2.3"><title>Index of new symbols in 1.2.3</title><xi:include href="xml/api-index-1.2.3.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-1-1-3" role="1.1.3"><title>Index of new symbols in 1.1.3</title><xi:include href="xml/api-index-1.1.3.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-1-1-2" role="1.1.2"><title>Index of new symbols in 1.1.2</title><xi:include href="xml/api-index-1.1.2.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-1-0-5" role="1.0.5"><title>Index of new symbols in 1.0.5</title><xi:include href="xml/api-index-1.0.5.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-0-9-42" role="0.9.42"><title>Index of new symbols in 0.9.42</title><xi:include href="xml/api-index-0.9.42.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-0-9-41" role="0.9.41"><title>Index of new symbols in 0.9.41</title><xi:include href="xml/api-index-0.9.41.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-0-9-39" role="0.9.39"><title>Index of new symbols in 0.9.39</title><xi:include href="xml/api-index-0.9.39.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-0-9-38" role="0.9.38"><title>Index of new symbols in 0.9.38</title><xi:include href="xml/api-index-0.9.38.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-0-9-33" role="0.9.33"><title>Index of new symbols in 0.9.33</title><xi:include href="xml/api-index-0.9.33.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-0-9-31" role="0.9.31"><title>Index of new symbols in 0.9.31</title><xi:include href="xml/api-index-0.9.31.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-0-9-30" role="0.9.30"><title>Index of new symbols in 0.9.30</title><xi:include href="xml/api-index-0.9.30.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-0-9-28" role="0.9.28"><title>Index of new symbols in 0.9.28</title><xi:include href="xml/api-index-0.9.28.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-0-9-26" role="0.9.26"><title>Index of new symbols in 0.9.26</title><xi:include href="xml/api-index-0.9.26.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-0-9-22" role="0.9.22"><title>Index of new symbols in 0.9.22</title><xi:include href="xml/api-index-0.9.22.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-0-9-21" role="0.9.21"><title>Index of new symbols in 0.9.21</title><xi:include href="xml/api-index-0.9.21.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-0-9-20" role="0.9.20"><title>Index of new symbols in 0.9.20</title><xi:include href="xml/api-index-0.9.20.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-0-9-11" role="0.9.11"><title>Index of new symbols in 0.9.11</title><xi:include href="xml/api-index-0.9.11.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-0-9-10" role="0.9.10"><title>Index of new symbols in 0.9.10</title><xi:include href="xml/api-index-0.9.10.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-0-9-8" role="0.9.8"><title>Index of new symbols in 0.9.8</title><xi:include href="xml/api-index-0.9.8.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-0-9-7" role="0.9.7"><title>Index of new symbols in 0.9.7</title><xi:include href="xml/api-index-0.9.7.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-0-9-5" role="0.9.5"><title>Index of new symbols in 0.9.5</title><xi:include href="xml/api-index-0.9.5.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-0-9-2" role="0.9.2"><title>Index of new symbols in 0.9.2</title><xi:include href="xml/api-index-0.9.2.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-0-6-0" role="0.6.0"><title>Index of new symbols in 0.6.0</title><xi:include href="xml/api-index-0.6.0.xml"><xi:fallback /></xi:include></index>
+      <index id="deprecated-api-index"><title>Index of deprecated API</title><xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include></index>
+
+      <index id="api-index-8-2-0"><title>Index of new symbols in 8.2.0</title><xi:include href="xml/api-index-8.2.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-8-1-0"><title>Index of new symbols in 8.1.0</title><xi:include href="xml/api-index-8.1.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-8-0-0"><title>Index of new symbols in 8.0.0</title><xi:include href="xml/api-index-8.0.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-7-3-0"><title>Index of new symbols in 7.3.0</title><xi:include href="xml/api-index-7.3.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-7-1-0"><title>Index of new symbols in 7.1.0</title><xi:include href="xml/api-index-7.1.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-7-0-0"><title>Index of new symbols in 7.0.0</title><xi:include href="xml/api-index-7.0.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-6-0-0"><title>Index of new symbols in 6.0.0</title><xi:include href="xml/api-index-6.0.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-5-3-0"><title>Index of new symbols in 5.3.0</title><xi:include href="xml/api-index-5.3.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-5-0-0"><title>Index of new symbols in 5.0.0</title><xi:include href="xml/api-index-5.0.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-4-4-0"><title>Index of new symbols in 4.4.0</title><xi:include href="xml/api-index-4.4.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-4-3-0"><title>Index of new symbols in 4.3.0</title><xi:include href="xml/api-index-4.3.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-4-2-0"><title>Index of new symbols in 4.2.0</title><xi:include href="xml/api-index-4.2.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-4-1-0"><title>Index of new symbols in 4.1.0</title><xi:include href="xml/api-index-4.1.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-4-0-0"><title>Index of new symbols in 4.0.0</title><xi:include href="xml/api-index-4.0.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-3-4-0"><title>Index of new symbols in 3.4.0</title><xi:include href="xml/api-index-3.4.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-3-3-0"><title>Index of new symbols in 3.3.0</title><xi:include href="xml/api-index-3.3.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-3-1-0"><title>Index of new symbols in 3.1.0</title><xi:include href="xml/api-index-3.1.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-3-0-0"><title>Index of new symbols in 3.0.0</title><xi:include href="xml/api-index-3.0.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-2-9-1"><title>Index of new symbols in 2.9.1</title><xi:include href="xml/api-index-2.9.1.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-2-9-0"><title>Index of new symbols in 2.9.0</title><xi:include href="xml/api-index-2.9.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-2-8-2"><title>Index of new symbols in 2.8.2</title><xi:include href="xml/api-index-2.8.2.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-2-7-3"><title>Index of new symbols in 2.7.3</title><xi:include href="xml/api-index-2.7.3.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-2-6-8"><title>Index of new symbols in 2.6.8</title><xi:include href="xml/api-index-2.6.8.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-2-6-5"><title>Index of new symbols in 2.6.5</title><xi:include href="xml/api-index-2.6.5.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-2-6-3"><title>Index of new symbols in 2.6.3</title><xi:include href="xml/api-index-2.6.3.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-2-6-0"><title>Index of new symbols in 2.6.0</title><xi:include href="xml/api-index-2.6.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-2-5-0"><title>Index of new symbols in 2.5.0</title><xi:include href="xml/api-index-2.5.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-2-4-0"><title>Index of new symbols in 2.4.0</title><xi:include href="xml/api-index-2.4.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-2-3-0"><title>Index of new symbols in 2.3.0</title><xi:include href="xml/api-index-2.3.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-2-2-0"><title>Index of new symbols in 2.2.0</title><xi:include href="xml/api-index-2.2.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-2-1-0"><title>Index of new symbols in 2.1.0</title><xi:include href="xml/api-index-2.1.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-2-0-0"><title>Index of new symbols in 2.0.0</title><xi:include href="xml/api-index-2.0.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-1-9-0"><title>Index of new symbols in 1.9.0</title><xi:include href="xml/api-index-1.9.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-1-8-6"><title>Index of new symbols in 1.8.6</title><xi:include href="xml/api-index-1.8.6.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-1-8-5"><title>Index of new symbols in 1.8.5</title><xi:include href="xml/api-index-1.8.5.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-1-8-1"><title>Index of new symbols in 1.8.1</title><xi:include href="xml/api-index-1.8.1.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-1-8-0"><title>Index of new symbols in 1.8.0</title><xi:include href="xml/api-index-1.8.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-1-7-7"><title>Index of new symbols in 1.7.7</title><xi:include href="xml/api-index-1.7.7.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-1-7-2"><title>Index of new symbols in 1.7.2</title><xi:include href="xml/api-index-1.7.2.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-1-6-0"><title>Index of new symbols in 1.6.0</title><xi:include href="xml/api-index-1.6.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-1-5-0"><title>Index of new symbols in 1.5.0</title><xi:include href="xml/api-index-1.5.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-1-4-3"><title>Index of new symbols in 1.4.3</title><xi:include href="xml/api-index-1.4.3.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-1-4-2"><title>Index of new symbols in 1.4.2</title><xi:include href="xml/api-index-1.4.2.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-1-4-0"><title>Index of new symbols in 1.4.0</title><xi:include href="xml/api-index-1.4.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-1-3-3"><title>Index of new symbols in 1.3.3</title><xi:include href="xml/api-index-1.3.3.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-1-2-3"><title>Index of new symbols in 1.2.3</title><xi:include href="xml/api-index-1.2.3.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-1-1-3"><title>Index of new symbols in 1.1.3</title><xi:include href="xml/api-index-1.1.3.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-1-1-2"><title>Index of new symbols in 1.1.2</title><xi:include href="xml/api-index-1.1.2.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-1-0-5"><title>Index of new symbols in 1.0.5</title><xi:include href="xml/api-index-1.0.5.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-0-9-42"><title>Index of new symbols in 0.9.42</title><xi:include href="xml/api-index-0.9.42.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-0-9-41"><title>Index of new symbols in 0.9.41</title><xi:include href="xml/api-index-0.9.41.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-0-9-39"><title>Index of new symbols in 0.9.39</title><xi:include href="xml/api-index-0.9.39.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-0-9-38"><title>Index of new symbols in 0.9.38</title><xi:include href="xml/api-index-0.9.38.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-0-9-33"><title>Index of new symbols in 0.9.33</title><xi:include href="xml/api-index-0.9.33.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-0-9-31"><title>Index of new symbols in 0.9.31</title><xi:include href="xml/api-index-0.9.31.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-0-9-30"><title>Index of new symbols in 0.9.30</title><xi:include href="xml/api-index-0.9.30.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-0-9-28"><title>Index of new symbols in 0.9.28</title><xi:include href="xml/api-index-0.9.28.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-0-9-26"><title>Index of new symbols in 0.9.26</title><xi:include href="xml/api-index-0.9.26.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-0-9-22"><title>Index of new symbols in 0.9.22</title><xi:include href="xml/api-index-0.9.22.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-0-9-21"><title>Index of new symbols in 0.9.21</title><xi:include href="xml/api-index-0.9.21.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-0-9-20"><title>Index of new symbols in 0.9.20</title><xi:include href="xml/api-index-0.9.20.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-0-9-11"><title>Index of new symbols in 0.9.11</title><xi:include href="xml/api-index-0.9.11.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-0-9-10"><title>Index of new symbols in 0.9.10</title><xi:include href="xml/api-index-0.9.10.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-0-9-8"><title>Index of new symbols in 0.9.8</title><xi:include href="xml/api-index-0.9.8.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-0-9-7"><title>Index of new symbols in 0.9.7</title><xi:include href="xml/api-index-0.9.7.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-0-9-5"><title>Index of new symbols in 0.9.5</title><xi:include href="xml/api-index-0.9.5.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-0-9-2"><title>Index of new symbols in 0.9.2</title><xi:include href="xml/api-index-0.9.2.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-0-6-0"><title>Index of new symbols in 0.6.0</title><xi:include href="xml/api-index-0.6.0.xml"><xi:fallback /></xi:include></index>
 
       <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
   </part>
 
   <note>
     <para>
-      The current HarfBuzz codebase is versioned 2.x.x and is stable
+      The current HarfBuzz codebase is stable
       and under active maintenance. This is what is used in latest
       versions of Firefox, GNOME, ChromeOS, Chrome, LibreOffice,
       XeTeX, Android, and KDE, among other places.
index 8f21edf..a9307f2 100644 (file)
@@ -1,9 +1,3 @@
-<SUBSECTION Private>
-HB_H_IN
-HB_OT_H_IN
-HB_AAT_H_IN
-</SECTION>
-
 <SECTION>
 <FILE>hb-aat-layout</FILE>
 HB_AAT_LAYOUT_NO_SELECTOR_INDEX
@@ -26,33 +20,33 @@ hb_blob_create_from_file
 hb_blob_create_from_file_or_fail
 hb_blob_create_sub_blob
 hb_blob_copy_writable_or_fail
+hb_blob_get_empty
+hb_blob_reference
 hb_blob_destroy
+hb_blob_set_user_data
+hb_blob_get_user_data
+hb_blob_make_immutable
+hb_blob_is_immutable
 hb_blob_get_data
 hb_blob_get_data_writable
-hb_blob_get_empty
 hb_blob_get_length
-hb_blob_get_user_data
-hb_blob_is_immutable
-hb_blob_make_immutable
-hb_blob_reference
-hb_blob_set_user_data
 hb_blob_t
 hb_memory_mode_t
 </SECTION>
 
 <SECTION>
 <FILE>hb-buffer</FILE>
-HB_SEGMENT_PROPERTIES_DEFAULT
-HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT
 hb_buffer_create
+hb_buffer_allocation_successful
 hb_buffer_create_similar
-hb_buffer_reference
 hb_buffer_get_empty
+hb_buffer_reference
 hb_buffer_destroy
+hb_buffer_set_user_data
+hb_buffer_get_user_data
 hb_buffer_reset
 hb_buffer_clear_contents
 hb_buffer_pre_allocate
-hb_buffer_allocation_successful
 hb_buffer_add
 hb_buffer_add_codepoints
 hb_buffer_add_utf32
@@ -79,15 +73,14 @@ hb_buffer_get_segment_properties
 hb_buffer_guess_segment_properties
 hb_buffer_set_unicode_funcs
 hb_buffer_get_unicode_funcs
-hb_buffer_set_user_data
-hb_buffer_get_user_data
 hb_buffer_get_glyph_infos
+hb_glyph_info_get_glyph_flags
 hb_buffer_get_glyph_positions
 hb_buffer_has_positions
-hb_buffer_get_invisible_glyph
 hb_buffer_set_invisible_glyph
-hb_buffer_get_not_found_glyph
+hb_buffer_get_invisible_glyph
 hb_buffer_set_not_found_glyph
+hb_buffer_get_not_found_glyph
 hb_buffer_set_replacement_codepoint
 hb_buffer_get_replacement_codepoint
 hb_buffer_normalize_glyphs
@@ -106,9 +99,11 @@ hb_segment_properties_equal
 hb_segment_properties_hash
 hb_segment_properties_overlay
 hb_buffer_diff
+hb_buffer_message_func_t
 hb_buffer_set_message_func
+HB_SEGMENT_PROPERTIES_DEFAULT
+HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT
 hb_buffer_t
-hb_glyph_info_get_glyph_flags
 hb_glyph_info_t
 hb_glyph_flags_t
 hb_glyph_position_t
@@ -119,28 +114,37 @@ hb_segment_properties_t
 hb_buffer_serialize_format_t
 hb_buffer_serialize_flags_t
 hb_buffer_diff_flags_t
-hb_buffer_message_func_t
 </SECTION>
 
 <SECTION>
 <FILE>hb-common</FILE>
+HB_TAG
+HB_UNTAG
 hb_tag_from_string
 hb_tag_to_string
 hb_direction_from_string
 hb_direction_to_string
+HB_DIRECTION_REVERSE
+HB_DIRECTION_IS_BACKWARD
+HB_DIRECTION_IS_FORWARD
+HB_DIRECTION_IS_HORIZONTAL
+HB_DIRECTION_IS_VALID
+HB_DIRECTION_IS_VERTICAL
 hb_script_from_iso15924_tag
-hb_script_from_string
 hb_script_to_iso15924_tag
+hb_script_from_string
 hb_script_get_horizontal_direction
 hb_language_from_string
 hb_language_to_string
 hb_language_get_default
+hb_language_matches
 hb_feature_from_string
 hb_feature_to_string
 hb_variation_from_string
 hb_variation_to_string
 hb_bool_t
 hb_codepoint_t
+HB_CODEPOINT_INVALID
 hb_destroy_func_t
 hb_direction_t
 hb_language_t
@@ -151,17 +155,9 @@ hb_position_t
 hb_tag_t
 hb_script_t
 hb_user_data_key_t
-HB_TAG
 HB_TAG_NONE
 HB_TAG_MAX
 HB_TAG_MAX_SIGNED
-HB_UNTAG
-HB_DIRECTION_REVERSE
-HB_DIRECTION_IS_BACKWARD
-HB_DIRECTION_IS_FORWARD
-HB_DIRECTION_IS_HORIZONTAL
-HB_DIRECTION_IS_VALID
-HB_DIRECTION_IS_VERTICAL
 HB_LANGUAGE_INVALID
 HB_FEATURE_GLOBAL_END
 HB_FEATURE_GLOBAL_START
@@ -169,6 +165,7 @@ HB_FEATURE_GLOBAL_START
 HB_BEGIN_DECLS
 HB_END_DECLS
 hb_var_int_t
+hb_var_num_t
 int16_t
 int32_t
 int64_t
@@ -177,10 +174,126 @@ uint16_t
 uint32_t
 uint64_t
 uint8_t
-<SUBSECTION Private>
 HB_EXTERN
 HB_DEPRECATED
 HB_DEPRECATED_FOR
+<SUBSECTION Private>
+HB_H_IN
+HB_OT_H_IN
+HB_AAT_H_IN
+</SECTION>
+
+<SECTION>
+<FILE>hb-features</FILE>
+HB_HAS_CAIRO
+HB_HAS_CORETEXT
+HB_HAS_DIRECTWRITE
+HB_HAS_FREETYPE
+HB_HAS_GDI
+HB_HAS_GLIB
+HB_HAS_GOBJECT
+HB_HAS_GRAPHITE
+HB_HAS_ICU
+HB_HAS_UNISCRIBE
+HB_HAS_WASM
+</SECTION>
+
+<SECTION>
+<FILE>hb-draw</FILE>
+hb_draw_funcs_create
+hb_draw_funcs_get_empty
+hb_draw_funcs_reference
+hb_draw_funcs_destroy
+hb_draw_funcs_set_user_data
+hb_draw_funcs_get_user_data
+hb_draw_funcs_make_immutable
+hb_draw_funcs_is_immutable
+hb_draw_move_to_func_t
+hb_draw_funcs_set_move_to_func
+hb_draw_line_to_func_t
+hb_draw_funcs_set_line_to_func
+hb_draw_quadratic_to_func_t
+hb_draw_funcs_set_quadratic_to_func
+hb_draw_cubic_to_func_t
+hb_draw_funcs_set_cubic_to_func
+hb_draw_close_path_func_t
+hb_draw_funcs_set_close_path_func
+hb_draw_move_to
+hb_draw_line_to
+hb_draw_quadratic_to
+hb_draw_cubic_to
+hb_draw_close_path
+HB_DRAW_STATE_DEFAULT
+hb_draw_funcs_t
+hb_draw_state_t
+</SECTION>
+
+<SECTION>
+<FILE>hb-paint</FILE>
+hb_paint_funcs_t
+hb_paint_funcs_create
+hb_paint_funcs_get_empty
+hb_paint_funcs_reference
+hb_paint_funcs_destroy
+hb_paint_funcs_set_user_data
+hb_paint_funcs_get_user_data
+hb_paint_funcs_make_immutable
+hb_paint_funcs_is_immutable
+
+hb_paint_push_transform_func_t
+hb_paint_funcs_set_push_transform_func
+hb_paint_pop_transform_func_t
+hb_paint_funcs_set_pop_transform_func
+hb_paint_color_glyph_func_t
+hb_paint_funcs_set_color_glyph_func
+hb_paint_push_clip_glyph_func_t
+hb_paint_funcs_set_push_clip_glyph_func
+hb_paint_push_clip_rectangle_func_t
+hb_paint_funcs_set_push_clip_rectangle_func
+hb_paint_pop_clip_func_t
+hb_paint_funcs_set_pop_clip_func
+hb_paint_color_func_t
+hb_paint_funcs_set_color_func
+HB_PAINT_IMAGE_FORMAT_PNG
+HB_PAINT_IMAGE_FORMAT_SVG
+HB_PAINT_IMAGE_FORMAT_BGRA
+hb_paint_image_func_t
+hb_paint_funcs_set_image_func
+hb_color_line_t
+hb_color_stop_t
+hb_color_line_get_color_stops_func_t
+hb_color_line_get_color_stops
+hb_paint_extend_t
+hb_color_line_get_extend_func_t
+hb_color_line_get_extend
+hb_paint_linear_gradient_func_t
+hb_paint_funcs_set_linear_gradient_func
+hb_paint_radial_gradient_func_t
+hb_paint_funcs_set_radial_gradient_func
+hb_paint_sweep_gradient_func_t
+hb_paint_funcs_set_sweep_gradient_func
+hb_paint_composite_mode_t
+hb_paint_push_group_func_t
+hb_paint_funcs_set_push_group_func
+hb_paint_pop_group_func_t
+hb_paint_funcs_set_pop_group_func
+hb_paint_custom_palette_color_func_t
+hb_paint_funcs_set_custom_palette_color_func
+
+hb_paint_push_transform
+hb_paint_pop_transform
+hb_paint_color_glyph
+hb_paint_push_clip_glyph
+hb_paint_push_clip_rectangle
+hb_paint_pop_clip
+hb_paint_color
+hb_paint_image
+hb_paint_linear_gradient
+hb_paint_radial_gradient
+hb_paint_sweep_gradient
+hb_paint_push_group
+hb_paint_pop_group
+hb_paint_custom_palette_color
 </SECTION>
 
 <SECTION>
@@ -207,7 +320,11 @@ HB_UNICODE_MAX_DECOMPOSITION_LEN
 hb_unicode_decompose_compatibility_func_t
 hb_unicode_decompose_compatibility
 hb_unicode_funcs_set_decompose_compatibility_func
+HB_UNICODE_COMBINING_CLASS_CCC133
 hb_font_funcs_set_glyph_v_kerning_func
+hb_font_get_glyph_shape
+hb_font_get_glyph_shape_func_t
+hb_font_funcs_set_glyph_shape_func
 hb_font_get_glyph_v_kerning
 hb_font_get_glyph_v_kerning_func_t
 </SECTION>
@@ -227,8 +344,6 @@ hb_coretext_font_get_ct_font
 <FILE>hb-directwrite</FILE>
 hb_directwrite_face_create
 hb_directwrite_face_get_font_face
-<SUBSECTION Private>
-hb_directwrite_shape_experimental_width
 </SECTION>
 
 <SECTION>
@@ -237,27 +352,29 @@ hb_face_count
 hb_face_t
 hb_face_create
 hb_face_create_for_tables
-hb_face_destroy
 hb_face_get_empty
+hb_face_reference
+hb_face_destroy
+hb_face_set_user_data
+hb_face_get_user_data
+hb_face_make_immutable
+hb_face_is_immutable
 hb_face_get_table_tags
+hb_face_set_glyph_count
 hb_face_get_glyph_count
+hb_face_set_index
 hb_face_get_index
+hb_face_set_upem
 hb_face_get_upem
-hb_face_get_user_data
-hb_face_is_immutable
-hb_face_make_immutable
-hb_face_reference
 hb_face_reference_blob
 hb_face_reference_table
-hb_face_set_glyph_count
-hb_face_set_index
-hb_face_set_upem
-hb_face_set_user_data
 hb_face_collect_unicodes
+hb_face_collect_nominal_glyph_mapping
 hb_face_collect_variation_selectors
 hb_face_collect_variation_unicodes
 hb_face_builder_create
 hb_face_builder_add_table
+hb_face_builder_sort_tables
 </SECTION>
 
 <SECTION>
@@ -265,113 +382,123 @@ hb_face_builder_add_table
 hb_font_add_glyph_origin_for_direction
 hb_font_create
 hb_font_create_sub_font
-hb_font_destroy
-hb_font_funcs_create
-hb_font_funcs_destroy
-hb_font_funcs_get_empty
-hb_font_funcs_get_user_data
-hb_font_funcs_is_immutable
-hb_font_funcs_make_immutable
-hb_font_funcs_reference
-hb_font_funcs_set_glyph_contour_point_func
-hb_font_funcs_set_glyph_extents_func
-hb_font_funcs_set_glyph_from_name_func
-hb_font_funcs_set_glyph_h_advance_func
-hb_font_funcs_set_glyph_h_advances_func
-hb_font_funcs_set_glyph_h_kerning_func
-hb_font_funcs_set_glyph_h_origin_func
-hb_font_funcs_set_glyph_name_func
-hb_font_funcs_set_glyph_v_advance_func
-hb_font_funcs_set_glyph_v_advances_func
-hb_font_funcs_set_glyph_v_origin_func
-hb_font_funcs_set_nominal_glyph_func
-hb_font_funcs_set_nominal_glyphs_func
-hb_font_funcs_set_user_data
-hb_font_funcs_set_variation_glyph_func
-hb_font_funcs_t
 hb_font_get_empty
+hb_font_reference
+hb_font_destroy
+hb_font_set_user_data
+hb_font_get_user_data
+hb_font_make_immutable
+hb_font_is_immutable
+hb_font_set_face
 hb_font_get_face
 hb_font_get_glyph
 hb_font_get_glyph_advance_for_direction
-hb_font_get_glyph_advance_func_t
 hb_font_get_glyph_advances_for_direction
-hb_font_get_glyph_advances_func_t
 hb_font_get_glyph_contour_point
 hb_font_get_glyph_contour_point_for_origin
-hb_font_get_glyph_contour_point_func_t
 hb_font_get_glyph_extents
 hb_font_get_glyph_extents_for_origin
-hb_font_get_glyph_extents_func_t
 hb_font_get_glyph_from_name
-hb_font_get_glyph_from_name_func_t
 hb_font_get_glyph_h_advance
-hb_font_get_glyph_h_advance_func_t
+hb_font_get_glyph_v_advance
 hb_font_get_glyph_h_advances
-hb_font_get_glyph_h_advances_func_t
+hb_font_get_glyph_v_advances
 hb_font_get_glyph_h_kerning
-hb_font_get_glyph_h_kerning_func_t
-hb_font_get_glyph_h_origin
-hb_font_get_glyph_h_origin_func_t
 hb_font_get_glyph_kerning_for_direction
-hb_font_get_glyph_kerning_func_t
-hb_font_get_glyph_name
-hb_font_get_glyph_name_func_t
-hb_font_get_glyph_origin_for_direction
-hb_font_get_glyph_origin_func_t
-hb_font_get_glyph_v_advance
-hb_font_get_glyph_v_advance_func_t
-hb_font_get_glyph_v_advances
-hb_font_get_glyph_v_advances_func_t
+hb_font_get_glyph_h_origin
 hb_font_get_glyph_v_origin
-hb_font_get_glyph_v_origin_func_t
+hb_font_get_glyph_origin_for_direction
+hb_font_get_glyph_name
+hb_font_draw_glyph
+hb_font_paint_glyph
 hb_font_get_nominal_glyph
-hb_font_get_nominal_glyph_func_t
 hb_font_get_nominal_glyphs
-hb_font_get_nominal_glyphs_func_t
+hb_font_get_variation_glyph
+hb_font_set_parent
 hb_font_get_parent
+hb_font_set_ppem
 hb_font_get_ppem
+hb_font_set_ptem
 hb_font_get_ptem
+hb_font_set_scale
 hb_font_get_scale
+hb_font_get_synthetic_bold
+hb_font_set_synthetic_bold
+hb_font_set_synthetic_slant
 hb_font_get_synthetic_slant
-hb_font_get_user_data
-hb_font_get_variation_glyph
-hb_font_get_variation_glyph_func_t
+hb_font_set_variations
+hb_font_set_variation
+HB_FONT_NO_VAR_NAMED_INSTANCE
+hb_font_set_var_named_instance
+hb_font_get_var_named_instance
+hb_font_set_var_coords_design
 hb_font_get_var_coords_design
+hb_font_set_var_coords_normalized
 hb_font_get_var_coords_normalized
 hb_font_glyph_from_string
 hb_font_glyph_to_string
-hb_font_is_immutable
-hb_font_make_immutable
-hb_font_reference
-hb_font_set_face
+hb_font_get_serial
+hb_font_changed
 hb_font_set_funcs
 hb_font_set_funcs_data
-hb_font_set_parent
-hb_font_set_ppem
-hb_font_set_ptem
-hb_font_set_scale
-hb_font_set_synthetic_slant
-hb_font_set_user_data
-hb_font_set_variations
-hb_font_set_var_coords_design
-hb_font_set_var_coords_normalized
-hb_font_set_var_named_instance
 hb_font_subtract_glyph_origin_for_direction
+hb_font_funcs_create
+hb_font_funcs_get_empty
+hb_font_funcs_reference
+hb_font_funcs_destroy
+hb_font_funcs_set_user_data
+hb_font_funcs_get_user_data
+hb_font_funcs_make_immutable
+hb_font_funcs_is_immutable
+hb_font_get_glyph_contour_point_func_t
+hb_font_funcs_set_glyph_contour_point_func
+hb_font_get_glyph_extents_func_t
+hb_font_funcs_set_glyph_extents_func
+hb_font_get_glyph_from_name_func_t
+hb_font_funcs_set_glyph_from_name_func
+hb_font_get_glyph_advance_func_t
+hb_font_get_glyph_h_advance_func_t
+hb_font_funcs_set_glyph_h_advance_func
+hb_font_get_glyph_v_advance_func_t
+hb_font_funcs_set_glyph_v_advance_func
+hb_font_get_glyph_advances_func_t
+hb_font_get_glyph_h_advances_func_t
+hb_font_funcs_set_glyph_h_advances_func
+hb_font_get_glyph_v_advances_func_t
+hb_font_funcs_set_glyph_v_advances_func
+hb_font_get_glyph_kerning_func_t
+hb_font_get_glyph_h_kerning_func_t
+hb_font_funcs_set_glyph_h_kerning_func
+hb_font_get_glyph_origin_func_t
+hb_font_get_glyph_h_origin_func_t
+hb_font_funcs_set_glyph_h_origin_func
+hb_font_get_glyph_v_origin_func_t
+hb_font_funcs_set_glyph_v_origin_func
+hb_font_get_glyph_name_func_t
+hb_font_funcs_set_glyph_name_func
+hb_font_draw_glyph_func_t
+hb_font_funcs_set_draw_glyph_func
+hb_font_paint_glyph_func_t
+hb_font_funcs_set_paint_glyph_func
+hb_font_get_nominal_glyph_func_t
+hb_font_funcs_set_nominal_glyph_func
+hb_font_get_nominal_glyphs_func_t
+hb_font_funcs_set_nominal_glyphs_func
+hb_font_get_variation_glyph_func_t
+hb_font_funcs_set_variation_glyph_func
+hb_font_funcs_t
 hb_font_t
 hb_reference_table_func_t
-hb_font_funcs_set_font_h_extents_func
-hb_font_funcs_set_font_v_extents_func
-hb_font_get_extents_for_direction
 hb_font_get_font_extents_func_t
 hb_font_get_font_h_extents_func_t
+hb_font_funcs_set_font_h_extents_func
 hb_font_get_font_v_extents_func_t
+hb_font_funcs_set_font_v_extents_func
 hb_font_get_h_extents
 hb_font_get_v_extents
+hb_font_get_extents_for_direction
 hb_font_extents_t
 hb_glyph_extents_t
-<SUBSECTION Private>
-hb_font_get_var_coords_design
-hb_font_draw_glyph
 </SECTION>
 
 <SECTION>
@@ -388,6 +515,7 @@ hb_ft_font_unlock_face
 hb_ft_font_set_load_flags
 hb_ft_font_get_load_flags
 hb_ft_font_set_funcs
+hb_ft_hb_font_changed
 </SECTION>
 
 <SECTION>
@@ -419,27 +547,33 @@ hb_icu_script_to_script
 
 <SECTION>
 <FILE>hb-map</FILE>
-HB_MAP_VALUE_INVALID
+hb_map_create
 hb_map_allocation_successful
+hb_map_copy
 hb_map_clear
-hb_map_create
-hb_map_del
-hb_map_destroy
-hb_map_get
 hb_map_get_empty
-hb_map_get_population
+hb_map_reference
+hb_map_destroy
+hb_map_set_user_data
 hb_map_get_user_data
+hb_map_set
+hb_map_get
+hb_map_del
 hb_map_has
+hb_map_get_population
 hb_map_is_empty
-hb_map_reference
-hb_map_set
-hb_map_set_user_data
+hb_map_is_equal
+hb_map_hash
+hb_map_update
+hb_map_next
+hb_map_keys
+hb_map_values
+HB_MAP_VALUE_INVALID
 hb_map_t
 </SECTION>
 
 <SECTION>
 <FILE>hb-ot-color</FILE>
-hb_color_t
 HB_COLOR
 hb_color_get_alpha
 hb_color_get_blue
@@ -449,16 +583,19 @@ hb_ot_color_glyph_get_layers
 hb_ot_color_glyph_reference_png
 hb_ot_color_glyph_reference_svg
 hb_ot_color_has_layers
+hb_ot_color_has_paint
+hb_ot_color_glyph_has_paint
 hb_ot_color_has_palettes
 hb_ot_color_has_png
 hb_ot_color_has_svg
-hb_ot_color_layer_t
 hb_ot_color_palette_color_get_name_id
-hb_ot_color_palette_flags_t
 hb_ot_color_palette_get_colors
 hb_ot_color_palette_get_count
 hb_ot_color_palette_get_flags
 hb_ot_color_palette_get_name_id
+hb_color_t
+hb_ot_color_layer_t
+hb_ot_color_palette_flags_t
 </SECTION>
 
 <SECTION>
@@ -468,48 +605,40 @@ hb_ot_font_set_funcs
 
 <SECTION>
 <FILE>hb-ot-name</FILE>
-hb_ot_name_id_t
-HB_OT_NAME_ID_INVALID
-hb_ot_name_entry_t
 hb_ot_name_list_names
 hb_ot_name_get_utf16
 hb_ot_name_get_utf32
 hb_ot_name_get_utf8
+hb_ot_name_id_t
+hb_ot_name_id_predefined_t
+hb_ot_name_entry_t
 </SECTION>
 
 <SECTION>
 <FILE>hb-ot-layout</FILE>
-HB_OT_MAX_TAGS_PER_LANGUAGE
-HB_OT_MAX_TAGS_PER_SCRIPT
-HB_OT_TAG_DEFAULT_LANGUAGE
-HB_OT_TAG_DEFAULT_SCRIPT
 hb_ot_tag_to_language
 hb_ot_tag_to_script
 hb_ot_tags_from_script_and_language
 hb_ot_tags_to_script_and_language
-HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX
-HB_OT_LAYOUT_NO_FEATURE_INDEX
-HB_OT_LAYOUT_NO_SCRIPT_INDEX
-HB_OT_LAYOUT_NO_VARIATIONS_INDEX
-HB_OT_TAG_BASE
-HB_OT_TAG_GDEF
-HB_OT_TAG_GPOS
-HB_OT_TAG_GSUB
-HB_OT_TAG_JSTF
-hb_ot_layout_baseline_tag_t
 hb_ot_layout_collect_lookups
 hb_ot_layout_collect_features
+hb_ot_layout_collect_features_map
 hb_ot_layout_feature_get_characters
 hb_ot_layout_feature_get_lookups
 hb_ot_layout_feature_get_name_ids
 hb_ot_layout_feature_with_variations_get_lookups
 hb_ot_layout_get_attach_points
+hb_ot_layout_get_font_extents
+hb_ot_layout_get_font_extents2
+hb_ot_layout_get_horizontal_baseline_tag_for_script
 hb_ot_layout_get_baseline
+hb_ot_layout_get_baseline2
+hb_ot_layout_get_baseline_with_fallback
+hb_ot_layout_get_baseline_with_fallback2
 hb_ot_layout_get_glyph_class
 hb_ot_layout_get_glyphs_in_class
 hb_ot_layout_get_ligature_carets
 hb_ot_layout_get_size_params
-hb_ot_layout_glyph_class_t
 hb_ot_layout_has_glyph_classes
 hb_ot_layout_has_positioning
 hb_ot_layout_has_substitution
@@ -519,12 +648,14 @@ hb_ot_layout_language_get_feature_tags
 hb_ot_layout_language_get_required_feature
 hb_ot_layout_lookup_collect_glyphs
 hb_ot_layout_lookup_get_glyph_alternates
+hb_ot_layout_lookup_get_optical_bound
 hb_ot_layout_lookup_substitute_closure
 hb_ot_layout_lookups_substitute_closure
 hb_ot_layout_lookup_would_substitute
 hb_ot_layout_script_find_language
 hb_ot_layout_script_get_language_tags
 hb_ot_layout_script_select_language
+hb_ot_layout_script_select_language2
 hb_ot_layout_table_find_feature_variations
 hb_ot_layout_table_get_feature_tags
 hb_ot_layout_table_get_script_tags
@@ -532,24 +663,25 @@ hb_ot_layout_table_get_lookup_count
 hb_ot_layout_table_select_script
 hb_ot_shape_plan_collect_lookups
 hb_ot_layout_language_get_required_feature_index
-<SUBSECTION Private>
-Xhb_ot_layout_lookup_enumerate_sequences
-Xhb_ot_layout_lookup_position
-Xhb_ot_layout_lookup_substitute
-hb_ot_layout_glyph_sequence_t
-hb_ot_layout_glyph_sequence_func_t
+HB_OT_MAX_TAGS_PER_LANGUAGE
+HB_OT_MAX_TAGS_PER_SCRIPT
+HB_OT_TAG_DEFAULT_LANGUAGE
+HB_OT_TAG_DEFAULT_SCRIPT
+HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX
+HB_OT_LAYOUT_NO_FEATURE_INDEX
+HB_OT_LAYOUT_NO_SCRIPT_INDEX
+HB_OT_LAYOUT_NO_VARIATIONS_INDEX
+HB_OT_TAG_BASE
+HB_OT_TAG_GDEF
+HB_OT_TAG_GPOS
+HB_OT_TAG_GSUB
+HB_OT_TAG_JSTF
+hb_ot_layout_baseline_tag_t
+hb_ot_layout_glyph_class_t
 </SECTION>
 
 <SECTION>
 <FILE>hb-ot-math</FILE>
-HB_OT_TAG_MATH
-HB_OT_TAG_MATH_SCRIPT
-hb_ot_math_constant_t
-hb_ot_math_kern_t
-hb_ot_math_kern_entry_t
-hb_ot_math_glyph_variant_t
-hb_ot_math_glyph_part_flags_t
-hb_ot_math_glyph_part_t
 hb_ot_math_has_data
 hb_ot_math_get_constant
 hb_ot_math_get_glyph_italics_correction
@@ -560,22 +692,31 @@ hb_ot_math_is_glyph_extended_shape
 hb_ot_math_get_glyph_variants
 hb_ot_math_get_min_connector_overlap
 hb_ot_math_get_glyph_assembly
+HB_OT_TAG_MATH
+HB_OT_TAG_MATH_SCRIPT
+hb_ot_math_constant_t
+hb_ot_math_kern_t
+hb_ot_math_kern_entry_t
+hb_ot_math_glyph_variant_t
+hb_ot_math_glyph_part_flags_t
+hb_ot_math_glyph_part_t
 </SECTION>
 
 <SECTION>
 <FILE>hb-ot-meta</FILE>
-hb_ot_meta_tag_t
 hb_ot_meta_get_entry_tags
 hb_ot_meta_reference_entry
+hb_ot_meta_tag_t
 </SECTION>
 
 <SECTION>
 <FILE>hb-ot-metrics</FILE>
-hb_ot_metrics_tag_t
 hb_ot_metrics_get_position
+hb_ot_metrics_get_position_with_fallback
 hb_ot_metrics_get_variation
 hb_ot_metrics_get_x_variation
 hb_ot_metrics_get_y_variation
+hb_ot_metrics_tag_t
 </SECTION>
 
 <SECTION>
@@ -585,14 +726,7 @@ hb_ot_shape_glyphs_closure
 
 <SECTION>
 <FILE>hb-ot-var</FILE>
-HB_OT_TAG_VAR_AXIS_ITALIC
-HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE
-HB_OT_TAG_VAR_AXIS_SLANT
-HB_OT_TAG_VAR_AXIS_WEIGHT
-HB_OT_TAG_VAR_AXIS_WIDTH
 hb_ot_var_has_data
-hb_ot_var_axis_flags_t
-hb_ot_var_axis_info_t
 hb_ot_var_find_axis_info
 hb_ot_var_get_axis_count
 hb_ot_var_get_axis_infos
@@ -602,48 +736,60 @@ hb_ot_var_named_instance_get_postscript_name_id
 hb_ot_var_named_instance_get_design_coords
 hb_ot_var_normalize_variations
 hb_ot_var_normalize_coords
+HB_OT_TAG_VAR_AXIS_ITALIC
+HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE
+HB_OT_TAG_VAR_AXIS_SLANT
+HB_OT_TAG_VAR_AXIS_WEIGHT
+HB_OT_TAG_VAR_AXIS_WIDTH
+hb_ot_var_axis_flags_t
+hb_ot_var_axis_info_t
 </SECTION>
 
 <SECTION>
 <FILE>hb-set</FILE>
-HB_SET_VALUE_INVALID
-hb_set_add
-hb_set_add_range
+hb_set_create
 hb_set_allocation_successful
 hb_set_copy
+hb_set_get_empty
+hb_set_reference
+hb_set_destroy
+hb_set_set_user_data
+hb_set_get_user_data
 hb_set_clear
-hb_set_create
+hb_set_set
+hb_set_has
+hb_set_add
+hb_set_add_range
+hb_set_add_sorted_array
 hb_set_del
 hb_set_del_range
-hb_set_destroy
-hb_set_get_empty
 hb_set_get_max
 hb_set_get_min
 hb_set_get_population
-hb_set_get_user_data
-hb_set_has
+hb_set_is_empty
+hb_set_hash
+hb_set_subtract
 hb_set_intersect
+hb_set_union
+hb_set_symmetric_difference
 hb_set_invert
-hb_set_is_empty
+hb_set_is_inverted
 hb_set_is_equal
 hb_set_is_subset
 hb_set_next
 hb_set_next_range
+hb_set_next_many
 hb_set_previous
 hb_set_previous_range
-hb_set_reference
-hb_set_set
-hb_set_set_user_data
-hb_set_subtract
-hb_set_symmetric_difference
+HB_SET_VALUE_INVALID
 hb_set_t
-hb_set_union
 </SECTION>
 
 <SECTION>
 <FILE>hb-shape</FILE>
 hb_shape
 hb_shape_full
+hb_shape_justify
 hb_shape_list_shapers
 </SECTION>
 
@@ -653,50 +799,50 @@ hb_shape_plan_create
 hb_shape_plan_create_cached
 hb_shape_plan_create2
 hb_shape_plan_create_cached2
-hb_shape_plan_destroy
-hb_shape_plan_execute
 hb_shape_plan_get_empty
-hb_shape_plan_get_shaper
-hb_shape_plan_get_user_data
 hb_shape_plan_reference
+hb_shape_plan_destroy
 hb_shape_plan_set_user_data
+hb_shape_plan_get_user_data
+hb_shape_plan_execute
+hb_shape_plan_get_shaper
 hb_shape_plan_t
 </SECTION>
 
 <SECTION>
 <FILE>hb-unicode</FILE>
-HB_UNICODE_MAX
+hb_unicode_general_category
 hb_unicode_combining_class
-hb_unicode_combining_class_func_t
-hb_unicode_combining_class_t
+hb_unicode_mirroring
+hb_unicode_script
 hb_unicode_compose
-hb_unicode_compose_func_t
 hb_unicode_decompose
-hb_unicode_decompose_func_t
 hb_unicode_funcs_create
-hb_unicode_funcs_destroy
-hb_unicode_funcs_get_default
 hb_unicode_funcs_get_empty
-hb_unicode_funcs_get_parent
+hb_unicode_funcs_reference
+hb_unicode_funcs_destroy
+hb_unicode_funcs_set_user_data
 hb_unicode_funcs_get_user_data
-hb_unicode_funcs_is_immutable
 hb_unicode_funcs_make_immutable
-hb_unicode_funcs_reference
-hb_unicode_funcs_set_combining_class_func
-hb_unicode_funcs_set_compose_func
-hb_unicode_funcs_set_decompose_func
+hb_unicode_funcs_is_immutable
+hb_unicode_funcs_get_default
+hb_unicode_funcs_get_parent
+hb_unicode_general_category_func_t
 hb_unicode_funcs_set_general_category_func
+hb_unicode_combining_class_func_t
+hb_unicode_funcs_set_combining_class_func
+hb_unicode_mirroring_func_t
 hb_unicode_funcs_set_mirroring_func
+hb_unicode_script_func_t
 hb_unicode_funcs_set_script_func
-hb_unicode_funcs_set_user_data
-hb_unicode_funcs_t
-hb_unicode_general_category
-hb_unicode_general_category_func_t
+hb_unicode_compose_func_t
+hb_unicode_funcs_set_compose_func
+hb_unicode_decompose_func_t
+hb_unicode_funcs_set_decompose_func
+HB_UNICODE_MAX
+hb_unicode_combining_class_t
 hb_unicode_general_category_t
-hb_unicode_mirroring
-hb_unicode_mirroring_func_t
-hb_unicode_script
-hb_unicode_script_func_t
+hb_unicode_funcs_t
 </SECTION>
 
 <SECTION>
@@ -708,13 +854,13 @@ hb_uniscribe_font_get_logfontw
 <SECTION>
 <FILE>hb-version</FILE>
 HB_VERSION_ATLEAST
+hb_version
+hb_version_atleast
+hb_version_string
 HB_VERSION_MAJOR
 HB_VERSION_MICRO
 HB_VERSION_MINOR
 HB_VERSION_STRING
-hb_version
-hb_version_atleast
-hb_version_string
 </SECTION>
 
 <SECTION>
@@ -725,18 +871,53 @@ hb_style_get_value
 
 <SECTION>
 <FILE>hb-subset</FILE>
-hb_subset_flags_t
-hb_subset_input_t
-hb_subset_sets_t
 hb_subset_input_create_or_fail
 hb_subset_input_reference
 hb_subset_input_destroy
 hb_subset_input_set_user_data
 hb_subset_input_get_user_data
-hb_subset_input_get_flags
+hb_subset_input_keep_everything
 hb_subset_input_set_flags
+hb_subset_input_get_flags
 hb_subset_input_unicode_set
 hb_subset_input_glyph_set
 hb_subset_input_set
+hb_subset_input_old_to_new_glyph_mapping
+hb_subset_input_pin_axis_location
+hb_subset_input_pin_axis_to_default
 hb_subset_or_fail
+hb_subset_plan_create_or_fail
+hb_subset_plan_reference
+hb_subset_plan_destroy
+hb_subset_plan_set_user_data
+hb_subset_plan_get_user_data
+hb_subset_plan_execute_or_fail
+hb_subset_plan_unicode_to_old_glyph_mapping
+hb_subset_plan_new_to_old_glyph_mapping
+hb_subset_plan_old_to_new_glyph_mapping
+hb_subset_preprocess
+hb_subset_flags_t
+hb_subset_input_t
+hb_subset_sets_t
+hb_subset_plan_t
+<SUBSECTION Private>
+hb_link_t
+hb_object_t
+hb_subset_repack_or_fail
+hb_subset_input_override_name_table
+hb_subset_input_set_axis_range
+</SECTION>
+
+<SECTION>
+<FILE>hb-cairo</FILE>
+hb_cairo_font_face_create_for_font
+hb_cairo_font_face_get_font
+hb_cairo_font_face_create_for_face
+hb_cairo_font_face_get_face
+hb_cairo_font_init_func_t
+hb_cairo_font_face_set_font_init_func
+hb_cairo_scaled_font_get_font
+hb_cairo_font_face_set_scale_factor
+hb_cairo_font_face_get_scale_factor
+hb_cairo_glyphs_from_buffer
 </SECTION>
index ba96d0e..7a93ae1 100644 (file)
           Set the script, language and direction of the buffer.
        </p></li></ol></div>
 <pre class="programlisting">
+      // If you know the direction, script, and language
       hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
       hb_buffer_set_script(buf, HB_SCRIPT_LATIN);
       hb_buffer_set_language(buf, hb_language_from_string("en", -1));
+
+      // If you don't know the direction, script, and language
+      hb_buffer_guess_segment_properties(buffer);
     </pre>
 <div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem" value="3"><p>
           Create a face and a font from a font file.
index 73a22a7..1b25dbe 100644 (file)
@@ -15,6 +15,8 @@
 <table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
 <td width="100%" align="left" class="shortcuts"><span id="nav_index"><a class="shortcut" href="#idxL">L</a>
                      <span class="dim">|</span> 
+                  <a class="shortcut" href="#idxO">O</a>
+                     <span class="dim">|</span> 
                   <a class="shortcut" href="#idxU">U</a></span></td>
 <td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
 <td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
 <a class="link" href="harfbuzz-hb-common.html#HB-LANGUAGE-INVALID:CAPS" title="HB_LANGUAGE_INVALID">HB_LANGUAGE_INVALID</a>, macro in <a class="link" href="harfbuzz-hb-common.html" title="hb-common">hb-common</a>
 </dt>
 <dd></dd>
+<a name="idxO"></a><h3 class="title">O</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-has-substitution" title="hb_ot_layout_has_substitution ()">hb_ot_layout_has_substitution</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-language-find-feature" title="hb_ot_layout_language_find_feature ()">hb_ot_layout_language_find_feature</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-language-get-feature-indexes" title="hb_ot_layout_language_get_feature_indexes ()">hb_ot_layout_language_get_feature_indexes</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-language-get-feature-tags" title="hb_ot_layout_language_get_feature_tags ()">hb_ot_layout_language_get_feature_tags</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-language-get-required-feature-index" title="hb_ot_layout_language_get_required_feature_index ()">hb_ot_layout_language_get_required_feature_index</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-script-find-language" title="hb_ot_layout_script_find_language ()">hb_ot_layout_script_find_language</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-script-get-language-tags" title="hb_ot_layout_script_get_language_tags ()">hb_ot_layout_script_get_language_tags</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-table-get-feature-tags" title="hb_ot_layout_table_get_feature_tags ()">hb_ot_layout_table_get_feature_tags</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-tags-from-script" title="hb_ot_tags_from_script ()">hb_ot_tags_from_script</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-tag-from-language" title="hb_ot_tag_from_language ()">hb_ot_tag_from_language</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
 <a name="idxU"></a><h3 class="title">U</h3>
 <dt>
 <a class="link" href="harfbuzz-hb-common.html#HB-UNTAG:CAPS" title="HB_UNTAG()">HB_UNTAG</a>, macro in <a class="link" href="harfbuzz-hb-common.html" title="hb-common">hb-common</a>
index 0eccb3b..58e1d71 100644 (file)
 <a class="link" href="harfbuzz-hb-graphite2.html#hb-graphite2-face-get-gr-face" title="hb_graphite2_face_get_gr_face ()">hb_graphite2_face_get_gr_face</a>, function in <a class="link" href="harfbuzz-hb-graphite2.html" title="hb-graphite2">hb-graphite2</a>
 </dt>
 <dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-graphite2.html#hb-graphite2-font-get-gr-font" title="hb_graphite2_font_get_gr_font ()">hb_graphite2_font_get_gr_font</a>, function in <a class="link" href="harfbuzz-hb-graphite2.html" title="hb-graphite2">hb-graphite2</a>
+</dt>
+<dd></dd>
 <a name="idxO"></a><h3 class="title">O</h3>
 <dt>
 <a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-size-params" title="hb_ot_layout_get_size_params ()">hb_ot_layout_get_size_params</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
index 0c7bb34..066efec 100644 (file)
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-font-funcs-set-glyph-func" title="hb_font_funcs_set_glyph_func ()">hb_font_funcs_set_glyph_func</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-h-advance-func" title="hb_font_funcs_set_glyph_h_advance_func ()">hb_font_funcs_set_glyph_h_advance_func</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
 </dt>
 <dd></dd>
index 2a5080b..e7ab090 100644 (file)
@@ -13,7 +13,9 @@
 </head>
 <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
 <table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
-<td width="100%" align="left" class="shortcuts"><span id="nav_index"><a class="shortcut" href="#idxS">S</a></span></td>
+<td width="100%" align="left" class="shortcuts"><span id="nav_index"><a class="shortcut" href="#idxO">O</a>
+                     <span class="dim">|</span> 
+                  <a class="shortcut" href="#idxS">S</a></span></td>
 <td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
 <td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
 <td><a accesskey="p" href="api-index-1-4-2.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
 <div class="index">
 <div class="titlepage"><div><div><h2 class="title">
 <a name="api-index-1-4-0"></a>Index of new symbols in 1.4.0</h2></div></div></div>
-<a name="idx"></a><a name="idxS"></a><h3 class="title">S</h3>
+<a name="idx"></a><a name="idxO"></a><h3 class="title">O</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-feature-with-variations-get-lookups" title="hb_ot_layout_feature_with_variations_get_lookups ()">hb_ot_layout_feature_with_variations_get_lookups</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-table-find-feature-variations" title="hb_ot_layout_table_find_feature_variations ()">hb_ot_layout_table_find_feature_variations</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<a name="idxS"></a><h3 class="title">S</h3>
 <dt>
 <a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-create2" title="hb_shape_plan_create2 ()">hb_shape_plan_create2</a>, function in <a class="link" href="harfbuzz-hb-shape-plan.html" title="hb-shape-plan">hb-shape-plan</a>
 </dt>
index 2f231f9..b2b02bb 100644 (file)
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-var-find-axis" title="hb_ot_var_find_axis ()">hb_ot_var_find_axis</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-var-get-axes" title="hb_ot_var_get_axes ()">hb_ot_var_get_axes</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-ot-var.html#hb-ot-var-get-axis-count" title="hb_ot_var_get_axis_count ()">hb_ot_var_get_axis_count</a>, function in <a class="link" href="harfbuzz-hb-ot-var.html" title="hb-ot-var">hb-ot-var</a>
 </dt>
 <dd></dd>
index b2932dc..9f776bf 100644 (file)
@@ -6,7 +6,7 @@
 <meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
 <link rel="home" href="index.html" title="HarfBuzz Manual">
 <link rel="up" href="reference-manual.html" title="Part II. Reference manual">
-<link rel="prev" href="api-index-1-7-5.html" title="Index of new symbols in 1.7.5">
+<link rel="prev" href="api-index-1-7-7.html" title="Index of new symbols in 1.7.7">
 <link rel="next" href="api-index-1-6-0.html" title="Index of new symbols in 1.6.0">
 <meta name="generator" content="GTK-Doc V1.32 (XML mode)">
 <link rel="stylesheet" href="style.css" type="text/css">
@@ -16,7 +16,7 @@
 <td width="100%" align="left" class="shortcuts"><span id="nav_index"><a class="shortcut" href="#idxC">C</a></span></td>
 <td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
 <td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
-<td><a accesskey="p" href="api-index-1-7-5.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="p" href="api-index-1-7-7.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
 <td><a accesskey="n" href="api-index-1-6-0.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
 </tr></table>
 <div class="index">
index c2375f2..7636927 100644 (file)
@@ -7,7 +7,7 @@
 <link rel="home" href="index.html" title="HarfBuzz Manual">
 <link rel="up" href="reference-manual.html" title="Part II. Reference manual">
 <link rel="prev" href="api-index-1-8-0.html" title="Index of new symbols in 1.8.0">
-<link rel="next" href="api-index-1-7-5.html" title="Index of new symbols in 1.7.5">
+<link rel="next" href="api-index-1-7-2.html" title="Index of new symbols in 1.7.2">
 <meta name="generator" content="GTK-Doc V1.32 (XML mode)">
 <link rel="stylesheet" href="style.css" type="text/css">
 </head>
@@ -21,7 +21,7 @@
 <td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
 <td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
 <td><a accesskey="p" href="api-index-1-8-0.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
-<td><a accesskey="n" href="api-index-1-7-5.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+<td><a accesskey="n" href="api-index-1-7-2.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
 </tr></table>
 <div class="index">
 <div class="titlepage"><div><div><h2 class="title">
index a543f49..ffed2b7 100644 (file)
@@ -6,7 +6,7 @@
 <meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
 <link rel="home" href="index.html" title="HarfBuzz Manual">
 <link rel="up" href="reference-manual.html" title="Part II. Reference manual">
-<link rel="prev" href="deprecated-api-index.html" title="Index of deprecated API">
+<link rel="prev" href="api-index-4-0-0.html" title="Index of new symbols in 4.0.0">
 <link rel="next" href="api-index-3-3-0.html" title="Index of new symbols in 3.3.0">
 <meta name="generator" content="GTK-Doc V1.32 (XML mode)">
 <link rel="stylesheet" href="style.css" type="text/css">
@@ -16,7 +16,7 @@
 <td width="100%" align="left" class="shortcuts"><span id="nav_index"><a class="shortcut" href="#idxO">O</a></span></td>
 <td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
 <td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
-<td><a accesskey="p" href="deprecated-api-index.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="p" href="api-index-4-0-0.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
 <td><a accesskey="n" href="api-index-3-3-0.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
 </tr></table>
 <div class="index">
diff --git a/docs/html/api-index-4-0-0.html b/docs/html/api-index-4-0-0.html
new file mode 100644 (file)
index 0000000..9c3fdbe
--- /dev/null
@@ -0,0 +1,187 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Index of new symbols in 4.0.0: HarfBuzz Manual</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
+<link rel="home" href="index.html" title="HarfBuzz Manual">
+<link rel="up" href="reference-manual.html" title="Part II. Reference manual">
+<link rel="prev" href="api-index-4-1-0.html" title="Index of new symbols in 4.1.0">
+<link rel="next" href="api-index-3-4-0.html" title="Index of new symbols in 3.4.0">
+<meta name="generator" content="GTK-Doc V1.32 (XML mode)">
+<link rel="stylesheet" href="style.css" type="text/css">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
+<td width="100%" align="left" class="shortcuts"><span id="nav_index"><a class="shortcut" href="#idxD">D</a>
+                     <span class="dim">|</span> 
+                  <a class="shortcut" href="#idxF">F</a>
+                     <span class="dim">|</span> 
+                  <a class="shortcut" href="#idxO">O</a>
+                     <span class="dim">|</span> 
+                  <a class="shortcut" href="#idxS">S</a></span></td>
+<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
+<td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
+<td><a accesskey="p" href="api-index-4-1-0.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="api-index-3-4-0.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+</tr></table>
+<div class="index">
+<div class="titlepage"><div><div><h2 class="title">
+<a name="api-index-4-0-0"></a>Index of new symbols in 4.0.0</h2></div></div></div>
+<a name="idx"></a><a name="idxD"></a><h3 class="title">D</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-close-path" title="hb_draw_close_path ()">hb_draw_close_path</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-close-path-func-t" title="hb_draw_close_path_func_t ()">hb_draw_close_path_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-cubic-to" title="hb_draw_cubic_to ()">hb_draw_cubic_to</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-cubic-to-func-t" title="hb_draw_cubic_to_func_t ()">hb_draw_cubic_to_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-create" title="hb_draw_funcs_create ()">hb_draw_funcs_create</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-destroy" title="hb_draw_funcs_destroy ()">hb_draw_funcs_destroy</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-is-immutable" title="hb_draw_funcs_is_immutable ()">hb_draw_funcs_is_immutable</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-make-immutable" title="hb_draw_funcs_make_immutable ()">hb_draw_funcs_make_immutable</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-reference" title="hb_draw_funcs_reference ()">hb_draw_funcs_reference</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-close-path-func" title="hb_draw_funcs_set_close_path_func ()">hb_draw_funcs_set_close_path_func</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-cubic-to-func" title="hb_draw_funcs_set_cubic_to_func ()">hb_draw_funcs_set_cubic_to_func</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-line-to-func" title="hb_draw_funcs_set_line_to_func ()">hb_draw_funcs_set_line_to_func</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-move-to-func" title="hb_draw_funcs_set_move_to_func ()">hb_draw_funcs_set_move_to_func</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-quadratic-to-func" title="hb_draw_funcs_set_quadratic_to_func ()">hb_draw_funcs_set_quadratic_to_func</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t">hb_draw_funcs_t</a>, typedef in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-line-to" title="hb_draw_line_to ()">hb_draw_line_to</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-line-to-func-t" title="hb_draw_line_to_func_t ()">hb_draw_line_to_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-move-to" title="hb_draw_move_to ()">hb_draw_move_to</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-move-to-func-t" title="hb_draw_move_to_func_t ()">hb_draw_move_to_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-quadratic-to" title="hb_draw_quadratic_to ()">hb_draw_quadratic_to</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-quadratic-to-func-t" title="hb_draw_quadratic_to_func_t ()">hb_draw_quadratic_to_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-state-t" title="hb_draw_state_t">hb_draw_state_t</a>, struct in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<a name="idxF"></a><h3 class="title">F</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-font-funcs-set-glyph-shape-func" title="hb_font_funcs_set_glyph_shape_func ()">hb_font_funcs_set_glyph_shape_func</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-font-get-glyph-shape" title="hb_font_get_glyph_shape ()">hb_font_get_glyph_shape</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-font-get-glyph-shape-func-t" title="hb_font_get_glyph_shape_func_t ()">hb_font_get_glyph_shape_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<a name="idxO"></a><h3 class="title">O</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-baseline-with-fallback" title="hb_ot_layout_get_baseline_with_fallback ()">hb_ot_layout_get_baseline_with_fallback</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-horizontal-baseline-tag-for-script" title="hb_ot_layout_get_horizontal_baseline_tag_for_script ()">hb_ot_layout_get_horizontal_baseline_tag_for_script</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-metrics.html#hb-ot-metrics-get-position-with-fallback" title="hb_ot_metrics_get_position_with_fallback ()">hb_ot_metrics_get_position_with_fallback</a>, function in <a class="link" href="harfbuzz-hb-ot-metrics.html" title="hb-ot-metrics">hb-ot-metrics</a>
+</dt>
+<dd></dd>
+<a name="idxS"></a><h3 class="title">S</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-create-or-fail" title="hb_subset_plan_create_or_fail ()">hb_subset_plan_create_or_fail</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-destroy" title="hb_subset_plan_destroy ()">hb_subset_plan_destroy</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-execute-or-fail" title="hb_subset_plan_execute_or_fail ()">hb_subset_plan_execute_or_fail</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-get-user-data" title="hb_subset_plan_get_user_data ()">hb_subset_plan_get_user_data</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-new-to-old-glyph-mapping" title="hb_subset_plan_new_to_old_glyph_mapping ()">hb_subset_plan_new_to_old_glyph_mapping</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-old-to-new-glyph-mapping" title="hb_subset_plan_old_to_new_glyph_mapping ()">hb_subset_plan_old_to_new_glyph_mapping</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-reference" title="hb_subset_plan_reference ()">hb_subset_plan_reference</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-set-user-data" title="hb_subset_plan_set_user_data ()">hb_subset_plan_set_user_data</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-unicode-to-old-glyph-mapping" title="hb_subset_plan_unicode_to_old_glyph_mapping ()">hb_subset_plan_unicode_to_old_glyph_mapping</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+</div>
+<div class="footer">
+<hr>Generated by GTK-Doc V1.32</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/html/api-index-4-1-0.html b/docs/html/api-index-4-1-0.html
new file mode 100644 (file)
index 0000000..1407c46
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Index of new symbols in 4.1.0: HarfBuzz Manual</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
+<link rel="home" href="index.html" title="HarfBuzz Manual">
+<link rel="up" href="reference-manual.html" title="Part II. Reference manual">
+<link rel="prev" href="api-index-4-2-0.html" title="Index of new symbols in 4.2.0">
+<link rel="next" href="api-index-4-0-0.html" title="Index of new symbols in 4.0.0">
+<meta name="generator" content="GTK-Doc V1.32 (XML mode)">
+<link rel="stylesheet" href="style.css" type="text/css">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
+<td width="100%" align="left" class="shortcuts"><span id="nav_index"><a class="shortcut" href="#idxS">S</a></span></td>
+<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
+<td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
+<td><a accesskey="p" href="api-index-4-2-0.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="api-index-4-0-0.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+</tr></table>
+<div class="index">
+<div class="titlepage"><div><div><h2 class="title">
+<a name="api-index-4-1-0"></a>Index of new symbols in 4.1.0</h2></div></div></div>
+<a name="idx"></a><a name="idxS"></a><h3 class="title">S</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-add-sorted-array" title="hb_set_add_sorted_array ()">hb_set_add_sorted_array</a>, function in <a class="link" href="harfbuzz-hb-set.html" title="hb-set">hb-set</a>
+</dt>
+<dd></dd>
+</div>
+<div class="footer">
+<hr>Generated by GTK-Doc V1.32</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/html/api-index-4-2-0.html b/docs/html/api-index-4-2-0.html
new file mode 100644 (file)
index 0000000..07bca63
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Index of new symbols in 4.2.0: HarfBuzz Manual</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
+<link rel="home" href="index.html" title="HarfBuzz Manual">
+<link rel="up" href="reference-manual.html" title="Part II. Reference manual">
+<link rel="prev" href="api-index-4-3-0.html" title="Index of new symbols in 4.3.0">
+<link rel="next" href="api-index-4-1-0.html" title="Index of new symbols in 4.1.0">
+<meta name="generator" content="GTK-Doc V1.32 (XML mode)">
+<link rel="stylesheet" href="style.css" type="text/css">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
+<td width="100%" align="left" class="shortcuts"><span id="nav_index"><a class="shortcut" href="#idxS">S</a></span></td>
+<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
+<td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
+<td><a accesskey="p" href="api-index-4-3-0.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="api-index-4-1-0.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+</tr></table>
+<div class="index">
+<div class="titlepage"><div><div><h2 class="title">
+<a name="api-index-4-2-0"></a>Index of new symbols in 4.2.0</h2></div></div></div>
+<a name="idx"></a><a name="idxS"></a><h3 class="title">S</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-next-many" title="hb_set_next_many ()">hb_set_next_many</a>, function in <a class="link" href="harfbuzz-hb-set.html" title="hb-set">hb-set</a>
+</dt>
+<dd></dd>
+</div>
+<div class="footer">
+<hr>Generated by GTK-Doc V1.32</div>
+</body>
+</html>
\ No newline at end of file
similarity index 59%
rename from docs/html/api-index-1-7-5.html
rename to docs/html/api-index-4-3-0.html
index 243f9da..efba5ee 100644 (file)
@@ -2,27 +2,31 @@
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-<title>Index of new symbols in 1.7.5: HarfBuzz Manual</title>
+<title>Index of new symbols in 4.3.0: HarfBuzz Manual</title>
 <meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
 <link rel="home" href="index.html" title="HarfBuzz Manual">
 <link rel="up" href="reference-manual.html" title="Part II. Reference manual">
-<link rel="prev" href="api-index-1-7-7.html" title="Index of new symbols in 1.7.7">
-<link rel="next" href="api-index-1-7-2.html" title="Index of new symbols in 1.7.2">
+<link rel="prev" href="api-index-4-4-0.html" title="Index of new symbols in 4.4.0">
+<link rel="next" href="api-index-4-2-0.html" title="Index of new symbols in 4.2.0">
 <meta name="generator" content="GTK-Doc V1.32 (XML mode)">
 <link rel="stylesheet" href="style.css" type="text/css">
 </head>
 <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
 <table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
-<td width="100%" align="left" class="shortcuts"></td>
+<td width="100%" align="left" class="shortcuts"><span id="nav_index"><a class="shortcut" href="#idxM">M</a></span></td>
 <td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
 <td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
-<td><a accesskey="p" href="api-index-1-7-7.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
-<td><a accesskey="n" href="api-index-1-7-2.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+<td><a accesskey="p" href="api-index-4-4-0.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="api-index-4-2-0.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
 </tr></table>
 <div class="index">
 <div class="titlepage"><div><div><h2 class="title">
-<a name="api-index-1-7-5"></a>Index of new symbols in 1.7.5</h2></div></div></div>
-<a name="idx"></a>
+<a name="api-index-4-3-0"></a>Index of new symbols in 4.3.0</h2></div></div></div>
+<a name="idx"></a><a name="idxM"></a><h3 class="title">M</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-is-equal" title="hb_map_is_equal ()">hb_map_is_equal</a>, function in <a class="link" href="harfbuzz-hb-map.html" title="hb-map">hb-map</a>
+</dt>
+<dd></dd>
 </div>
 <div class="footer">
 <hr>Generated by GTK-Doc V1.32</div>
diff --git a/docs/html/api-index-4-4-0.html b/docs/html/api-index-4-4-0.html
new file mode 100644 (file)
index 0000000..f67ffe3
--- /dev/null
@@ -0,0 +1,60 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Index of new symbols in 4.4.0: HarfBuzz Manual</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
+<link rel="home" href="index.html" title="HarfBuzz Manual">
+<link rel="up" href="reference-manual.html" title="Part II. Reference manual">
+<link rel="prev" href="api-index-5-0-0.html" title="Index of new symbols in 5.0.0">
+<link rel="next" href="api-index-4-3-0.html" title="Index of new symbols in 4.3.0">
+<meta name="generator" content="GTK-Doc V1.32 (XML mode)">
+<link rel="stylesheet" href="style.css" type="text/css">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
+<td width="100%" align="left" class="shortcuts"><span id="nav_index"><a class="shortcut" href="#idxF">F</a>
+                     <span class="dim">|</span> 
+                  <a class="shortcut" href="#idxM">M</a>
+                     <span class="dim">|</span> 
+                  <a class="shortcut" href="#idxS">S</a></span></td>
+<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
+<td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
+<td><a accesskey="p" href="api-index-5-0-0.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="api-index-4-3-0.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+</tr></table>
+<div class="index">
+<div class="titlepage"><div><div><h2 class="title">
+<a name="api-index-4-4-0"></a>Index of new symbols in 4.4.0</h2></div></div></div>
+<a name="idx"></a><a name="idxF"></a><h3 class="title">F</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-changed" title="hb_font_changed ()">hb_font_changed</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-serial" title="hb_font_get_serial ()">hb_font_get_serial</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ft.html#hb-ft-hb-font-changed" title="hb_ft_hb_font_changed ()">hb_ft_hb_font_changed</a>, function in <a class="link" href="harfbuzz-hb-ft.html" title="hb-ft">hb-ft</a>
+</dt>
+<dd></dd>
+<a name="idxM"></a><h3 class="title">M</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-copy" title="hb_map_copy ()">hb_map_copy</a>, function in <a class="link" href="harfbuzz-hb-map.html" title="hb-map">hb-map</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-hash" title="hb_map_hash ()">hb_map_hash</a>, function in <a class="link" href="harfbuzz-hb-map.html" title="hb-map">hb-map</a>
+</dt>
+<dd></dd>
+<a name="idxS"></a><h3 class="title">S</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-hash" title="hb_set_hash ()">hb_set_hash</a>, function in <a class="link" href="harfbuzz-hb-set.html" title="hb-set">hb-set</a>
+</dt>
+<dd></dd>
+</div>
+<div class="footer">
+<hr>Generated by GTK-Doc V1.32</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/html/api-index-5-0-0.html b/docs/html/api-index-5-0-0.html
new file mode 100644 (file)
index 0000000..71f8f25
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Index of new symbols in 5.0.0: HarfBuzz Manual</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
+<link rel="home" href="index.html" title="HarfBuzz Manual">
+<link rel="up" href="reference-manual.html" title="Part II. Reference manual">
+<link rel="prev" href="api-index-5-3-0.html" title="Index of new symbols in 5.3.0">
+<link rel="next" href="api-index-4-4-0.html" title="Index of new symbols in 4.4.0">
+<meta name="generator" content="GTK-Doc V1.32 (XML mode)">
+<link rel="stylesheet" href="style.css" type="text/css">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
+<td width="100%" align="left" class="shortcuts"><span id="nav_index"><a class="shortcut" href="#idxL">L</a></span></td>
+<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
+<td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
+<td><a accesskey="p" href="api-index-5-3-0.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="api-index-4-4-0.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+</tr></table>
+<div class="index">
+<div class="titlepage"><div><div><h2 class="title">
+<a name="api-index-5-0-0"></a>Index of new symbols in 5.0.0</h2></div></div></div>
+<a name="idx"></a><a name="idxL"></a><h3 class="title">L</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-common.html#hb-language-matches" title="hb_language_matches ()">hb_language_matches</a>, function in <a class="link" href="harfbuzz-hb-common.html" title="hb-common">hb-common</a>
+</dt>
+<dd></dd>
+</div>
+<div class="footer">
+<hr>Generated by GTK-Doc V1.32</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/html/api-index-5-3-0.html b/docs/html/api-index-5-3-0.html
new file mode 100644 (file)
index 0000000..5f4e744
--- /dev/null
@@ -0,0 +1,41 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Index of new symbols in 5.3.0: HarfBuzz Manual</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
+<link rel="home" href="index.html" title="HarfBuzz Manual">
+<link rel="up" href="reference-manual.html" title="Part II. Reference manual">
+<link rel="prev" href="api-index-6-0-0.html" title="Index of new symbols in 6.0.0">
+<link rel="next" href="api-index-5-0-0.html" title="Index of new symbols in 5.0.0">
+<meta name="generator" content="GTK-Doc V1.32 (XML mode)">
+<link rel="stylesheet" href="style.css" type="text/css">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
+<td width="100%" align="left" class="shortcuts"><span id="nav_index"><a class="shortcut" href="#idxF">F</a>
+                     <span class="dim">|</span> 
+                  <a class="shortcut" href="#idxO">O</a></span></td>
+<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
+<td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
+<td><a accesskey="p" href="api-index-6-0-0.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="api-index-5-0-0.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+</tr></table>
+<div class="index">
+<div class="titlepage"><div><div><h2 class="title">
+<a name="api-index-5-3-0"></a>Index of new symbols in 5.3.0</h2></div></div></div>
+<a name="idx"></a><a name="idxF"></a><h3 class="title">F</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-builder-sort-tables" title="hb_face_builder_sort_tables ()">hb_face_builder_sort_tables</a>, function in <a class="link" href="harfbuzz-hb-face.html" title="hb-face">hb-face</a>
+</dt>
+<dd></dd>
+<a name="idxO"></a><h3 class="title">O</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-lookup-get-optical-bound" title="hb_ot_layout_lookup_get_optical_bound ()">hb_ot_layout_lookup_get_optical_bound</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+</div>
+<div class="footer">
+<hr>Generated by GTK-Doc V1.32</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/html/api-index-6-0-0.html b/docs/html/api-index-6-0-0.html
new file mode 100644 (file)
index 0000000..c5b47be
--- /dev/null
@@ -0,0 +1,42 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Index of new symbols in 6.0.0: HarfBuzz Manual</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
+<link rel="home" href="index.html" title="HarfBuzz Manual">
+<link rel="up" href="reference-manual.html" title="Part II. Reference manual">
+<link rel="prev" href="api-index-7-0-0.html" title="Index of new symbols in 7.0.0">
+<link rel="next" href="api-index-5-3-0.html" title="Index of new symbols in 5.3.0">
+<meta name="generator" content="GTK-Doc V1.32 (XML mode)">
+<link rel="stylesheet" href="style.css" type="text/css">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
+<td width="100%" align="left" class="shortcuts"><span id="nav_index"><a class="shortcut" href="#idxS">S</a></span></td>
+<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
+<td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
+<td><a accesskey="p" href="api-index-7-0-0.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="api-index-5-3-0.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+</tr></table>
+<div class="index">
+<div class="titlepage"><div><div><h2 class="title">
+<a name="api-index-6-0-0"></a>Index of new symbols in 6.0.0</h2></div></div></div>
+<a name="idx"></a><a name="idxS"></a><h3 class="title">S</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-pin-axis-location" title="hb_subset_input_pin_axis_location ()">hb_subset_input_pin_axis_location</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-pin-axis-to-default" title="hb_subset_input_pin_axis_to_default ()">hb_subset_input_pin_axis_to_default</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-preprocess" title="hb_subset_preprocess ()">hb_subset_preprocess</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+</div>
+<div class="footer">
+<hr>Generated by GTK-Doc V1.32</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/html/api-index-7-0-0.html b/docs/html/api-index-7-0-0.html
new file mode 100644 (file)
index 0000000..f5744c4
--- /dev/null
@@ -0,0 +1,420 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Index of new symbols in 7.0.0: HarfBuzz Manual</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
+<link rel="home" href="index.html" title="HarfBuzz Manual">
+<link rel="up" href="reference-manual.html" title="Part II. Reference manual">
+<link rel="prev" href="api-index-7-1-0.html" title="Index of new symbols in 7.1.0">
+<link rel="next" href="api-index-6-0-0.html" title="Index of new symbols in 6.0.0">
+<meta name="generator" content="GTK-Doc V1.32 (XML mode)">
+<link rel="stylesheet" href="style.css" type="text/css">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
+<td width="100%" align="left" class="shortcuts"><span id="nav_index"><a class="shortcut" href="#idxC">C</a>
+                     <span class="dim">|</span> 
+                  <a class="shortcut" href="#idxD">D</a>
+                     <span class="dim">|</span> 
+                  <a class="shortcut" href="#idxF">F</a>
+                     <span class="dim">|</span> 
+                  <a class="shortcut" href="#idxM">M</a>
+                     <span class="dim">|</span> 
+                  <a class="shortcut" href="#idxO">O</a>
+                     <span class="dim">|</span> 
+                  <a class="shortcut" href="#idxP">P</a>
+                     <span class="dim">|</span> 
+                  <a class="shortcut" href="#idxS">S</a></span></td>
+<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
+<td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
+<td><a accesskey="p" href="api-index-7-1-0.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="api-index-6-0-0.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+</tr></table>
+<div class="index">
+<div class="titlepage"><div><div><h2 class="title">
+<a name="api-index-7-0-0"></a>Index of new symbols in 7.0.0</h2></div></div></div>
+<a name="idx"></a><a name="idxC"></a><h3 class="title">C</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-create-for-face" title="hb_cairo_font_face_create_for_face ()">hb_cairo_font_face_create_for_face</a>, function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-create-for-font" title="hb_cairo_font_face_create_for_font ()">hb_cairo_font_face_create_for_font</a>, function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-get-face" title="hb_cairo_font_face_get_face ()">hb_cairo_font_face_get_face</a>, function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-get-font" title="hb_cairo_font_face_get_font ()">hb_cairo_font_face_get_font</a>, function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-get-scale-factor" title="hb_cairo_font_face_get_scale_factor ()">hb_cairo_font_face_get_scale_factor</a>, function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-set-font-init-func" title="hb_cairo_font_face_set_font_init_func ()">hb_cairo_font_face_set_font_init_func</a>, function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-set-scale-factor" title="hb_cairo_font_face_set_scale_factor ()">hb_cairo_font_face_set_scale_factor</a>, function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-init-func-t" title="hb_cairo_font_init_func_t ()">hb_cairo_font_init_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-glyphs-from-buffer" title="hb_cairo_glyphs_from_buffer ()">hb_cairo_glyphs_from_buffer</a>, function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-scaled-font-get-font" title="hb_cairo_scaled_font_get_font ()">hb_cairo_scaled_font_get_font</a>, function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-color-line-get-color-stops" title="hb_color_line_get_color_stops ()">hb_color_line_get_color_stops</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-color-line-get-color-stops-func-t" title="hb_color_line_get_color_stops_func_t ()">hb_color_line_get_color_stops_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-color-line-get-extend" title="hb_color_line_get_extend ()">hb_color_line_get_extend</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-color-line-get-extend-func-t" title="hb_color_line_get_extend_func_t ()">hb_color_line_get_extend_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-color-line-t" title="hb_color_line_t">hb_color_line_t</a>, typedef in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-color-stop-t" title="hb_color_stop_t">hb_color_stop_t</a>, struct in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<a name="idxD"></a><h3 class="title">D</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-get-empty" title="hb_draw_funcs_get_empty ()">hb_draw_funcs_get_empty</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-get-user-data" title="hb_draw_funcs_get_user_data ()">hb_draw_funcs_get_user_data</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-user-data" title="hb_draw_funcs_set_user_data ()">hb_draw_funcs_set_user_data</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<a name="idxF"></a><h3 class="title">F</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-collect-nominal-glyph-mapping" title="hb_face_collect_nominal_glyph_mapping ()">hb_face_collect_nominal_glyph_mapping</a>, function in <a class="link" href="harfbuzz-hb-face.html" title="hb-face">hb-face</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-draw-glyph" title="hb_font_draw_glyph ()">hb_font_draw_glyph</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-draw-glyph-func-t" title="hb_font_draw_glyph_func_t ()">hb_font_draw_glyph_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-draw-glyph-func" title="hb_font_funcs_set_draw_glyph_func ()">hb_font_funcs_set_draw_glyph_func</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-paint-glyph-func" title="hb_font_funcs_set_paint_glyph_func ()">hb_font_funcs_set_paint_glyph_func</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-synthetic-bold" title="hb_font_get_synthetic_bold ()">hb_font_get_synthetic_bold</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-var-named-instance" title="hb_font_get_var_named_instance ()">hb_font_get_var_named_instance</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-font.html#HB-FONT-NO-VAR-NAMED-INSTANCE:CAPS" title="HB_FONT_NO_VAR_NAMED_INSTANCE">HB_FONT_NO_VAR_NAMED_INSTANCE</a>, macro in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph" title="hb_font_paint_glyph ()">hb_font_paint_glyph</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph-func-t" title="hb_font_paint_glyph_func_t ()">hb_font_paint_glyph_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-set-synthetic-bold" title="hb_font_set_synthetic_bold ()">hb_font_set_synthetic_bold</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<a name="idxM"></a><h3 class="title">M</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-keys" title="hb_map_keys ()">hb_map_keys</a>, function in <a class="link" href="harfbuzz-hb-map.html" title="hb-map">hb-map</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-next" title="hb_map_next ()">hb_map_next</a>, function in <a class="link" href="harfbuzz-hb-map.html" title="hb-map">hb-map</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-update" title="hb_map_update ()">hb_map_update</a>, function in <a class="link" href="harfbuzz-hb-map.html" title="hb-map">hb-map</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-values" title="hb_map_values ()">hb_map_values</a>, function in <a class="link" href="harfbuzz-hb-map.html" title="hb-map">hb-map</a>
+</dt>
+<dd></dd>
+<a name="idxO"></a><h3 class="title">O</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-color.html#hb-ot-color-glyph-has-paint" title="hb_ot_color_glyph_has_paint ()">hb_ot_color_glyph_has_paint</a>, function in <a class="link" href="harfbuzz-hb-ot-color.html" title="hb-ot-color">hb-ot-color</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-color.html#hb-ot-color-has-paint" title="hb_ot_color_has_paint ()">hb_ot_color_has_paint</a>, function in <a class="link" href="harfbuzz-hb-ot-color.html" title="hb-ot-color">hb-ot-color</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-script-select-language2" title="hb_ot_layout_script_select_language2 ()">hb_ot_layout_script_select_language2</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-name.html#hb-ot-name-id-predefined-t" title="enum hb_ot_name_id_predefined_t">hb_ot_name_id_predefined_t</a>, enum in <a class="link" href="harfbuzz-hb-ot-name.html" title="hb-ot-name">hb-ot-name</a>
+</dt>
+<dd></dd>
+<a name="idxP"></a><h3 class="title">P</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-color" title="hb_paint_color ()">hb_paint_color</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-color-func-t" title="hb_paint_color_func_t ()">hb_paint_color_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-composite-mode-t" title="enum hb_paint_composite_mode_t">hb_paint_composite_mode_t</a>, enum in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-custom-palette-color" title="hb_paint_custom_palette_color ()">hb_paint_custom_palette_color</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-custom-palette-color-func-t" title="hb_paint_custom_palette_color_func_t ()">hb_paint_custom_palette_color_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-extend-t" title="enum hb_paint_extend_t">hb_paint_extend_t</a>, enum in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-create" title="hb_paint_funcs_create ()">hb_paint_funcs_create</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-destroy" title="hb_paint_funcs_destroy ()">hb_paint_funcs_destroy</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-get-empty" title="hb_paint_funcs_get_empty ()">hb_paint_funcs_get_empty</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-get-user-data" title="hb_paint_funcs_get_user_data ()">hb_paint_funcs_get_user_data</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-is-immutable" title="hb_paint_funcs_is_immutable ()">hb_paint_funcs_is_immutable</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-make-immutable" title="hb_paint_funcs_make_immutable ()">hb_paint_funcs_make_immutable</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-reference" title="hb_paint_funcs_reference ()">hb_paint_funcs_reference</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-color-func" title="hb_paint_funcs_set_color_func ()">hb_paint_funcs_set_color_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-custom-palette-color-func" title="hb_paint_funcs_set_custom_palette_color_func ()">hb_paint_funcs_set_custom_palette_color_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-image-func" title="hb_paint_funcs_set_image_func ()">hb_paint_funcs_set_image_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-linear-gradient-func" title="hb_paint_funcs_set_linear_gradient_func ()">hb_paint_funcs_set_linear_gradient_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-pop-clip-func" title="hb_paint_funcs_set_pop_clip_func ()">hb_paint_funcs_set_pop_clip_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-pop-group-func" title="hb_paint_funcs_set_pop_group_func ()">hb_paint_funcs_set_pop_group_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-pop-transform-func" title="hb_paint_funcs_set_pop_transform_func ()">hb_paint_funcs_set_pop_transform_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-clip-glyph-func" title="hb_paint_funcs_set_push_clip_glyph_func ()">hb_paint_funcs_set_push_clip_glyph_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-clip-rectangle-func" title="hb_paint_funcs_set_push_clip_rectangle_func ()">hb_paint_funcs_set_push_clip_rectangle_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-group-func" title="hb_paint_funcs_set_push_group_func ()">hb_paint_funcs_set_push_group_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-transform-func" title="hb_paint_funcs_set_push_transform_func ()">hb_paint_funcs_set_push_transform_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-radial-gradient-func" title="hb_paint_funcs_set_radial_gradient_func ()">hb_paint_funcs_set_radial_gradient_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-sweep-gradient-func" title="hb_paint_funcs_set_sweep_gradient_func ()">hb_paint_funcs_set_sweep_gradient_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-user-data" title="hb_paint_funcs_set_user_data ()">hb_paint_funcs_set_user_data</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t">hb_paint_funcs_t</a>, typedef in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-image" title="hb_paint_image ()">hb_paint_image</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#HB-PAINT-IMAGE-FORMAT-BGRA:CAPS" title="HB_PAINT_IMAGE_FORMAT_BGRA">HB_PAINT_IMAGE_FORMAT_BGRA</a>, macro in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#HB-PAINT-IMAGE-FORMAT-PNG:CAPS" title="HB_PAINT_IMAGE_FORMAT_PNG">HB_PAINT_IMAGE_FORMAT_PNG</a>, macro in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#HB-PAINT-IMAGE-FORMAT-SVG:CAPS" title="HB_PAINT_IMAGE_FORMAT_SVG">HB_PAINT_IMAGE_FORMAT_SVG</a>, macro in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-image-func-t" title="hb_paint_image_func_t ()">hb_paint_image_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-linear-gradient" title="hb_paint_linear_gradient ()">hb_paint_linear_gradient</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-linear-gradient-func-t" title="hb_paint_linear_gradient_func_t ()">hb_paint_linear_gradient_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-clip" title="hb_paint_pop_clip ()">hb_paint_pop_clip</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-clip-func-t" title="hb_paint_pop_clip_func_t ()">hb_paint_pop_clip_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-group" title="hb_paint_pop_group ()">hb_paint_pop_group</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-group-func-t" title="hb_paint_pop_group_func_t ()">hb_paint_pop_group_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-transform" title="hb_paint_pop_transform ()">hb_paint_pop_transform</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-transform-func-t" title="hb_paint_pop_transform_func_t ()">hb_paint_pop_transform_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-clip-glyph" title="hb_paint_push_clip_glyph ()">hb_paint_push_clip_glyph</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-clip-glyph-func-t" title="hb_paint_push_clip_glyph_func_t ()">hb_paint_push_clip_glyph_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-clip-rectangle" title="hb_paint_push_clip_rectangle ()">hb_paint_push_clip_rectangle</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-clip-rectangle-func-t" title="hb_paint_push_clip_rectangle_func_t ()">hb_paint_push_clip_rectangle_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-group" title="hb_paint_push_group ()">hb_paint_push_group</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-group-func-t" title="hb_paint_push_group_func_t ()">hb_paint_push_group_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-transform" title="hb_paint_push_transform ()">hb_paint_push_transform</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-transform-func-t" title="hb_paint_push_transform_func_t ()">hb_paint_push_transform_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-radial-gradient" title="hb_paint_radial_gradient ()">hb_paint_radial_gradient</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-radial-gradient-func-t" title="hb_paint_radial_gradient_func_t ()">hb_paint_radial_gradient_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-sweep-gradient" title="hb_paint_sweep_gradient ()">hb_paint_sweep_gradient</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-sweep-gradient-func-t" title="hb_paint_sweep_gradient_func_t ()">hb_paint_sweep_gradient_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<a name="idxS"></a><h3 class="title">S</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-is-inverted" title="hb_set_is_inverted ()">hb_set_is_inverted</a>, function in <a class="link" href="harfbuzz-hb-set.html" title="hb-set">hb-set</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-keep-everything" title="hb_subset_input_keep_everything ()">hb_subset_input_keep_everything</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+</div>
+<div class="footer">
+<hr>Generated by GTK-Doc V1.32</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/html/api-index-7-1-0.html b/docs/html/api-index-7-1-0.html
new file mode 100644 (file)
index 0000000..0312dca
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Index of new symbols in 7.1.0: HarfBuzz Manual</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
+<link rel="home" href="index.html" title="HarfBuzz Manual">
+<link rel="up" href="reference-manual.html" title="Part II. Reference manual">
+<link rel="prev" href="api-index-7-3-0.html" title="Index of new symbols in 7.3.0">
+<link rel="next" href="api-index-7-0-0.html" title="Index of new symbols in 7.0.0">
+<meta name="generator" content="GTK-Doc V1.32 (XML mode)">
+<link rel="stylesheet" href="style.css" type="text/css">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
+<td width="100%" align="left" class="shortcuts"><span id="nav_index"><a class="shortcut" href="#idxF">F</a></span></td>
+<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
+<td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
+<td><a accesskey="p" href="api-index-7-3-0.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="api-index-7-0-0.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+</tr></table>
+<div class="index">
+<div class="titlepage"><div><div><h2 class="title">
+<a name="api-index-7-1-0"></a>Index of new symbols in 7.1.0</h2></div></div></div>
+<a name="idx"></a><a name="idxF"></a><h3 class="title">F</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-set-variation" title="hb_font_set_variation ()">hb_font_set_variation</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+</div>
+<div class="footer">
+<hr>Generated by GTK-Doc V1.32</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/html/api-index-7-3-0.html b/docs/html/api-index-7-3-0.html
new file mode 100644 (file)
index 0000000..a430a06
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Index of new symbols in 7.3.0: HarfBuzz Manual</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
+<link rel="home" href="index.html" title="HarfBuzz Manual">
+<link rel="up" href="reference-manual.html" title="Part II. Reference manual">
+<link rel="prev" href="api-index-8-0-0.html" title="Index of new symbols in 8.0.0">
+<link rel="next" href="api-index-7-1-0.html" title="Index of new symbols in 7.1.0">
+<meta name="generator" content="GTK-Doc V1.32 (XML mode)">
+<link rel="stylesheet" href="style.css" type="text/css">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
+<td width="100%" align="left" class="shortcuts"><span id="nav_index"><a class="shortcut" href="#idxS">S</a></span></td>
+<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
+<td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
+<td><a accesskey="p" href="api-index-8-0-0.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="api-index-7-1-0.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+</tr></table>
+<div class="index">
+<div class="titlepage"><div><div><h2 class="title">
+<a name="api-index-7-3-0"></a>Index of new symbols in 7.3.0</h2></div></div></div>
+<a name="idx"></a><a name="idxS"></a><h3 class="title">S</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-old-to-new-glyph-mapping" title="hb_subset_input_old_to_new_glyph_mapping ()">hb_subset_input_old_to_new_glyph_mapping</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+</div>
+<div class="footer">
+<hr>Generated by GTK-Doc V1.32</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/html/api-index-8-0-0.html b/docs/html/api-index-8-0-0.html
new file mode 100644 (file)
index 0000000..4e9d15a
--- /dev/null
@@ -0,0 +1,53 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Index of new symbols in 8.0.0: HarfBuzz Manual</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
+<link rel="home" href="index.html" title="HarfBuzz Manual">
+<link rel="up" href="reference-manual.html" title="Part II. Reference manual">
+<link rel="prev" href="api-index-8-1-0.html" title="Index of new symbols in 8.1.0">
+<link rel="next" href="api-index-7-3-0.html" title="Index of new symbols in 7.3.0">
+<meta name="generator" content="GTK-Doc V1.32 (XML mode)">
+<link rel="stylesheet" href="style.css" type="text/css">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
+<td width="100%" align="left" class="shortcuts"><span id="nav_index"><a class="shortcut" href="#idxC">C</a>
+                     <span class="dim">|</span> 
+                  <a class="shortcut" href="#idxO">O</a></span></td>
+<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
+<td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
+<td><a accesskey="p" href="api-index-8-1-0.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="api-index-7-3-0.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+</tr></table>
+<div class="index">
+<div class="titlepage"><div><div><h2 class="title">
+<a name="api-index-8-0-0"></a>Index of new symbols in 8.0.0</h2></div></div></div>
+<a name="idx"></a><a name="idxC"></a><h3 class="title">C</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-common.html#HB-CODEPOINT-INVALID:CAPS" title="HB_CODEPOINT_INVALID">HB_CODEPOINT_INVALID</a>, macro in <a class="link" href="harfbuzz-hb-common.html" title="hb-common">hb-common</a>
+</dt>
+<dd></dd>
+<a name="idxO"></a><h3 class="title">O</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-baseline2" title="hb_ot_layout_get_baseline2 ()">hb_ot_layout_get_baseline2</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-baseline-with-fallback2" title="hb_ot_layout_get_baseline_with_fallback2 ()">hb_ot_layout_get_baseline_with_fallback2</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-font-extents" title="hb_ot_layout_get_font_extents ()">hb_ot_layout_get_font_extents</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-font-extents2" title="hb_ot_layout_get_font_extents2 ()">hb_ot_layout_get_font_extents2</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+</div>
+<div class="footer">
+<hr>Generated by GTK-Doc V1.32</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/html/api-index-8-1-0.html b/docs/html/api-index-8-1-0.html
new file mode 100644 (file)
index 0000000..02ca54c
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Index of new symbols in 8.1.0: HarfBuzz Manual</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
+<link rel="home" href="index.html" title="HarfBuzz Manual">
+<link rel="up" href="reference-manual.html" title="Part II. Reference manual">
+<link rel="prev" href="api-index-8-2-0.html" title="Index of new symbols in 8.2.0">
+<link rel="next" href="api-index-8-0-0.html" title="Index of new symbols in 8.0.0">
+<meta name="generator" content="GTK-Doc V1.32 (XML mode)">
+<link rel="stylesheet" href="style.css" type="text/css">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
+<td width="100%" align="left" class="shortcuts"><span id="nav_index"><a class="shortcut" href="#idxO">O</a></span></td>
+<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
+<td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
+<td><a accesskey="p" href="api-index-8-2-0.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="api-index-8-0-0.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+</tr></table>
+<div class="index">
+<div class="titlepage"><div><div><h2 class="title">
+<a name="api-index-8-1-0"></a>Index of new symbols in 8.1.0</h2></div></div></div>
+<a name="idx"></a><a name="idxO"></a><h3 class="title">O</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-collect-features-map" title="hb_ot_layout_collect_features_map ()">hb_ot_layout_collect_features_map</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+</div>
+<div class="footer">
+<hr>Generated by GTK-Doc V1.32</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/html/api-index-8-2-0.html b/docs/html/api-index-8-2-0.html
new file mode 100644 (file)
index 0000000..69760f6
--- /dev/null
@@ -0,0 +1,42 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Index of new symbols in 8.2.0: HarfBuzz Manual</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
+<link rel="home" href="index.html" title="HarfBuzz Manual">
+<link rel="up" href="reference-manual.html" title="Part II. Reference manual">
+<link rel="prev" href="deprecated-api-index.html" title="Index of deprecated API">
+<link rel="next" href="api-index-8-1-0.html" title="Index of new symbols in 8.1.0">
+<meta name="generator" content="GTK-Doc V1.32 (XML mode)">
+<link rel="stylesheet" href="style.css" type="text/css">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
+<td width="100%" align="left" class="shortcuts"><span id="nav_index"><a class="shortcut" href="#idxP">P</a></span></td>
+<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
+<td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
+<td><a accesskey="p" href="deprecated-api-index.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="api-index-8-1-0.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+</tr></table>
+<div class="index">
+<div class="titlepage"><div><div><h2 class="title">
+<a name="api-index-8-2-0"></a>Index of new symbols in 8.2.0</h2></div></div></div>
+<a name="idx"></a><a name="idxP"></a><h3 class="title">P</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-color-glyph" title="hb_paint_color_glyph ()">hb_paint_color_glyph</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-color-glyph-func-t" title="hb_paint_color_glyph_func_t ()">hb_paint_color_glyph_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-color-glyph-func" title="hb_paint_funcs_set_color_glyph_func ()">hb_paint_funcs_set_color_glyph_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+</div>
+<div class="footer">
+<hr>Generated by GTK-Doc V1.32</div>
+</body>
+</html>
\ No newline at end of file
index 4cbdff0..4e778fb 100644 (file)
@@ -25,6 +25,8 @@
                      <span class="dim">|</span> 
                   <a class="shortcut" href="#idxG">G</a>
                      <span class="dim">|</span> 
+                  <a class="shortcut" href="#idxH">H</a>
+                     <span class="dim">|</span> 
                   <a class="shortcut" href="#idxI">I</a>
                      <span class="dim">|</span> 
                   <a class="shortcut" href="#idxL">L</a>
 <dd></dd>
 <a name="idxC"></a><h3 class="title">C</h3>
 <dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-create-for-face" title="hb_cairo_font_face_create_for_face ()">hb_cairo_font_face_create_for_face</a>, function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-create-for-font" title="hb_cairo_font_face_create_for_font ()">hb_cairo_font_face_create_for_font</a>, function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-get-face" title="hb_cairo_font_face_get_face ()">hb_cairo_font_face_get_face</a>, function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-get-font" title="hb_cairo_font_face_get_font ()">hb_cairo_font_face_get_font</a>, function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-get-scale-factor" title="hb_cairo_font_face_get_scale_factor ()">hb_cairo_font_face_get_scale_factor</a>, function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-set-font-init-func" title="hb_cairo_font_face_set_font_init_func ()">hb_cairo_font_face_set_font_init_func</a>, function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-set-scale-factor" title="hb_cairo_font_face_set_scale_factor ()">hb_cairo_font_face_set_scale_factor</a>, function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-init-func-t" title="hb_cairo_font_init_func_t ()">hb_cairo_font_init_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-glyphs-from-buffer" title="hb_cairo_glyphs_from_buffer ()">hb_cairo_glyphs_from_buffer</a>, function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-scaled-font-get-font" title="hb_cairo_scaled_font_get_font ()">hb_cairo_scaled_font_get_font</a>, function in <a class="link" href="harfbuzz-hb-cairo.html" title="hb-cairo">hb-cairo</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-common.html#HB-CODEPOINT-INVALID:CAPS" title="HB_CODEPOINT_INVALID">HB_CODEPOINT_INVALID</a>, macro in <a class="link" href="harfbuzz-hb-common.html" title="hb-common">hb-common</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t">hb_codepoint_t</a>, typedef in <a class="link" href="harfbuzz-hb-common.html" title="hb-common">hb-common</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-color-line-get-color-stops" title="hb_color_line_get_color_stops ()">hb_color_line_get_color_stops</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-color-line-get-color-stops-func-t" title="hb_color_line_get_color_stops_func_t ()">hb_color_line_get_color_stops_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-color-line-get-extend" title="hb_color_line_get_extend ()">hb_color_line_get_extend</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-color-line-get-extend-func-t" title="hb_color_line_get_extend_func_t ()">hb_color_line_get_extend_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-color-line-t" title="hb_color_line_t">hb_color_line_t</a>, typedef in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-color-stop-t" title="hb_color_stop_t">hb_color_stop_t</a>, struct in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-ot-color.html#hb-color-t" title="hb_color_t">hb_color_t</a>, typedef in <a class="link" href="harfbuzz-hb-ot-color.html" title="hb-ot-color">hb-ot-color</a>
 </dt>
 <dd></dd>
 <a class="link" href="harfbuzz-hb-directwrite.html#hb-directwrite-face-get-font-face" title="hb_directwrite_face_get_font_face ()">hb_directwrite_face_get_font_face</a>, function in <a class="link" href="harfbuzz-hb-directwrite.html" title="hb-directwrite">hb-directwrite</a>
 </dt>
 <dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-close-path" title="hb_draw_close_path ()">hb_draw_close_path</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-close-path-func-t" title="hb_draw_close_path_func_t ()">hb_draw_close_path_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-cubic-to" title="hb_draw_cubic_to ()">hb_draw_cubic_to</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-cubic-to-func-t" title="hb_draw_cubic_to_func_t ()">hb_draw_cubic_to_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-create" title="hb_draw_funcs_create ()">hb_draw_funcs_create</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-destroy" title="hb_draw_funcs_destroy ()">hb_draw_funcs_destroy</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-get-empty" title="hb_draw_funcs_get_empty ()">hb_draw_funcs_get_empty</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-get-user-data" title="hb_draw_funcs_get_user_data ()">hb_draw_funcs_get_user_data</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-is-immutable" title="hb_draw_funcs_is_immutable ()">hb_draw_funcs_is_immutable</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-make-immutable" title="hb_draw_funcs_make_immutable ()">hb_draw_funcs_make_immutable</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-reference" title="hb_draw_funcs_reference ()">hb_draw_funcs_reference</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-close-path-func" title="hb_draw_funcs_set_close_path_func ()">hb_draw_funcs_set_close_path_func</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-cubic-to-func" title="hb_draw_funcs_set_cubic_to_func ()">hb_draw_funcs_set_cubic_to_func</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-line-to-func" title="hb_draw_funcs_set_line_to_func ()">hb_draw_funcs_set_line_to_func</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-move-to-func" title="hb_draw_funcs_set_move_to_func ()">hb_draw_funcs_set_move_to_func</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-quadratic-to-func" title="hb_draw_funcs_set_quadratic_to_func ()">hb_draw_funcs_set_quadratic_to_func</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-user-data" title="hb_draw_funcs_set_user_data ()">hb_draw_funcs_set_user_data</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t">hb_draw_funcs_t</a>, typedef in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-line-to" title="hb_draw_line_to ()">hb_draw_line_to</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-line-to-func-t" title="hb_draw_line_to_func_t ()">hb_draw_line_to_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-move-to" title="hb_draw_move_to ()">hb_draw_move_to</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-move-to-func-t" title="hb_draw_move_to_func_t ()">hb_draw_move_to_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-quadratic-to" title="hb_draw_quadratic_to ()">hb_draw_quadratic_to</a>, function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-quadratic-to-func-t" title="hb_draw_quadratic_to_func_t ()">hb_draw_quadratic_to_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#HB-DRAW-STATE-DEFAULT:CAPS" title="HB_DRAW_STATE_DEFAULT">HB_DRAW_STATE_DEFAULT</a>, macro in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-state-t" title="hb_draw_state_t">hb_draw_state_t</a>, struct in <a class="link" href="harfbuzz-hb-draw.html" title="hb-draw">hb-draw</a>
+</dt>
+<dd></dd>
 <a name="idxF"></a><h3 class="title">F</h3>
 <dt>
 <a class="link" href="harfbuzz-hb-face.html#hb-face-builder-add-table" title="hb_face_builder_add_table ()">hb_face_builder_add_table</a>, function in <a class="link" href="harfbuzz-hb-face.html" title="hb-face">hb-face</a>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-builder-sort-tables" title="hb_face_builder_sort_tables ()">hb_face_builder_sort_tables</a>, function in <a class="link" href="harfbuzz-hb-face.html" title="hb-face">hb-face</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-collect-nominal-glyph-mapping" title="hb_face_collect_nominal_glyph_mapping ()">hb_face_collect_nominal_glyph_mapping</a>, function in <a class="link" href="harfbuzz-hb-face.html" title="hb-face">hb-face</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-face.html#hb-face-collect-unicodes" title="hb_face_collect_unicodes ()">hb_face_collect_unicodes</a>, function in <a class="link" href="harfbuzz-hb-face.html" title="hb-face">hb-face</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-changed" title="hb_font_changed ()">hb_font_changed</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-font.html#hb-font-create" title="hb_font_create ()">hb_font_create</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-draw-glyph" title="hb_font_draw_glyph ()">hb_font_draw_glyph</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-draw-glyph-func-t" title="hb_font_draw_glyph_func_t ()">hb_font_draw_glyph_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-font.html#hb-font-extents-t" title="hb_font_extents_t">hb_font_extents_t</a>, struct in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-draw-glyph-func" title="hb_font_funcs_set_draw_glyph_func ()">hb_font_funcs_set_draw_glyph_func</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-font-h-extents-func" title="hb_font_funcs_set_font_h_extents_func ()">hb_font_funcs_set_font_h_extents_func</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-font-funcs-set-glyph-func" title="hb_font_funcs_set_glyph_func ()">hb_font_funcs_set_glyph_func</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-h-advances-func" title="hb_font_funcs_set_glyph_h_advances_func ()">hb_font_funcs_set_glyph_h_advances_func</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-font-funcs-set-glyph-shape-func" title="hb_font_funcs_set_glyph_shape_func ()">hb_font_funcs_set_glyph_shape_func</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-v-advances-func" title="hb_font_funcs_set_glyph_v_advances_func ()">hb_font_funcs_set_glyph_v_advances_func</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-paint-glyph-func" title="hb_font_funcs_set_paint_glyph_func ()">hb_font_funcs_set_paint_glyph_func</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-user-data" title="hb_font_funcs_set_user_data ()">hb_font_funcs_set_user_data</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-font-get-glyph-shape" title="hb_font_get_glyph_shape ()">hb_font_get_glyph_shape</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-font-get-glyph-shape-func-t" title="hb_font_get_glyph_shape_func_t ()">hb_font_get_glyph_shape_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-advance" title="hb_font_get_glyph_v_advance ()">hb_font_get_glyph_v_advance</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-serial" title="hb_font_get_serial ()">hb_font_get_serial</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-synthetic-bold" title="hb_font_get_synthetic_bold ()">hb_font_get_synthetic_bold</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-font.html#hb-font-get-synthetic-slant" title="hb_font_get_synthetic_slant ()">hb_font_get_synthetic_slant</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-var-named-instance" title="hb_font_get_var_named_instance ()">hb_font_get_var_named_instance</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-font.html#hb-font-get-v-extents" title="hb_font_get_v_extents ()">hb_font_get_v_extents</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-font.html#HB-FONT-NO-VAR-NAMED-INSTANCE:CAPS" title="HB_FONT_NO_VAR_NAMED_INSTANCE">HB_FONT_NO_VAR_NAMED_INSTANCE</a>, macro in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph" title="hb_font_paint_glyph ()">hb_font_paint_glyph</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph-func-t" title="hb_font_paint_glyph_func_t ()">hb_font_paint_glyph_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-font.html#hb-font-reference" title="hb_font_reference ()">hb_font_reference</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-set-synthetic-bold" title="hb_font_set_synthetic_bold ()">hb_font_set_synthetic_bold</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-font.html#hb-font-set-synthetic-slant" title="hb_font_set_synthetic_slant ()">hb_font_set_synthetic_slant</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-set-variation" title="hb_font_set_variation ()">hb_font_set_variation</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-font.html#hb-font-set-variations" title="hb_font_set_variations ()">hb_font_set_variations</a>, function in <a class="link" href="harfbuzz-hb-font.html" title="hb-font">hb-font</a>
 </dt>
 <dd></dd>
 <a class="link" href="harfbuzz-hb-ft.html#hb-ft-font-unlock-face" title="hb_ft_font_unlock_face ()">hb_ft_font_unlock_face</a>, function in <a class="link" href="harfbuzz-hb-ft.html" title="hb-ft">hb-ft</a>
 </dt>
 <dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ft.html#hb-ft-hb-font-changed" title="hb_ft_hb_font_changed ()">hb_ft_hb_font_changed</a>, function in <a class="link" href="harfbuzz-hb-ft.html" title="hb-ft">hb-ft</a>
+</dt>
+<dd></dd>
 <a name="idxG"></a><h3 class="title">G</h3>
 <dt>
 <a class="link" href="harfbuzz-hb-gdi.html#hb-gdi-face-create" title="hb_gdi_face_create ()">hb_gdi_face_create</a>, function in <a class="link" href="harfbuzz-hb-gdi.html" title="hb-gdi">hb-gdi</a>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-graphite2.html#hb-graphite2-font-get-gr-font" title="hb_graphite2_font_get_gr_font ()">hb_graphite2_font_get_gr_font</a>, function in <a class="link" href="harfbuzz-hb-graphite2.html" title="hb-graphite2">hb-graphite2</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-graphite2.html#HB-GRAPHITE2-TAG-SILF:CAPS" title="HB_GRAPHITE2_TAG_SILF">HB_GRAPHITE2_TAG_SILF</a>, macro in <a class="link" href="harfbuzz-hb-graphite2.html" title="hb-graphite2">hb-graphite2</a>
 </dt>
 <dd></dd>
+<a name="idxH"></a><h3 class="title">H</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-features.html#HB-HAS-FREETYPE:CAPS" title="HB_HAS_FREETYPE">HB_HAS_FREETYPE</a>, macro in <a class="link" href="harfbuzz-hb-features.html" title="hb-features">hb-features</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-features.html#HB-HAS-GLIB:CAPS" title="HB_HAS_GLIB">HB_HAS_GLIB</a>, macro in <a class="link" href="harfbuzz-hb-features.html" title="hb-features">hb-features</a>
+</dt>
+<dd></dd>
 <a name="idxI"></a><h3 class="title">I</h3>
 <dt>
 <a class="link" href="harfbuzz-hb-icu.html#hb-icu-get-unicode-funcs" title="hb_icu_get_unicode_funcs ()">hb_icu_get_unicode_funcs</a>, function in <a class="link" href="harfbuzz-hb-icu.html" title="hb-icu">hb-icu</a>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-common.html#hb-language-matches" title="hb_language_matches ()">hb_language_matches</a>, function in <a class="link" href="harfbuzz-hb-common.html" title="hb-common">hb-common</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-common.html#hb-language-t" title="hb_language_t">hb_language_t</a>, typedef in <a class="link" href="harfbuzz-hb-common.html" title="hb-common">hb-common</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-copy" title="hb_map_copy ()">hb_map_copy</a>, function in <a class="link" href="harfbuzz-hb-map.html" title="hb-map">hb-map</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-map.html#hb-map-create" title="hb_map_create ()">hb_map_create</a>, function in <a class="link" href="harfbuzz-hb-map.html" title="hb-map">hb-map</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-hash" title="hb_map_hash ()">hb_map_hash</a>, function in <a class="link" href="harfbuzz-hb-map.html" title="hb-map">hb-map</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-map.html#hb-map-is-empty" title="hb_map_is_empty ()">hb_map_is_empty</a>, function in <a class="link" href="harfbuzz-hb-map.html" title="hb-map">hb-map</a>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-is-equal" title="hb_map_is_equal ()">hb_map_is_equal</a>, function in <a class="link" href="harfbuzz-hb-map.html" title="hb-map">hb-map</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-keys" title="hb_map_keys ()">hb_map_keys</a>, function in <a class="link" href="harfbuzz-hb-map.html" title="hb-map">hb-map</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-next" title="hb_map_next ()">hb_map_next</a>, function in <a class="link" href="harfbuzz-hb-map.html" title="hb-map">hb-map</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-map.html#hb-map-reference" title="hb_map_reference ()">hb_map_reference</a>, function in <a class="link" href="harfbuzz-hb-map.html" title="hb-map">hb-map</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-update" title="hb_map_update ()">hb_map_update</a>, function in <a class="link" href="harfbuzz-hb-map.html" title="hb-map">hb-map</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-values" title="hb_map_values ()">hb_map_values</a>, function in <a class="link" href="harfbuzz-hb-map.html" title="hb-map">hb-map</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-map.html#HB-MAP-VALUE-INVALID:CAPS" title="HB_MAP_VALUE_INVALID">HB_MAP_VALUE_INVALID</a>, macro in <a class="link" href="harfbuzz-hb-map.html" title="hb-map">hb-map</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-ot-color.html#hb-ot-color-glyph-has-paint" title="hb_ot_color_glyph_has_paint ()">hb_ot_color_glyph_has_paint</a>, function in <a class="link" href="harfbuzz-hb-ot-color.html" title="hb-ot-color">hb-ot-color</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-ot-color.html#hb-ot-color-glyph-reference-png" title="hb_ot_color_glyph_reference_png ()">hb_ot_color_glyph_reference_png</a>, function in <a class="link" href="harfbuzz-hb-ot-color.html" title="hb-ot-color">hb-ot-color</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-ot-color.html#hb-ot-color-has-paint" title="hb_ot_color_has_paint ()">hb_ot_color_has_paint</a>, function in <a class="link" href="harfbuzz-hb-ot-color.html" title="hb-ot-color">hb-ot-color</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-ot-color.html#hb-ot-color-has-palettes" title="hb_ot_color_has_palettes ()">hb_ot_color_has_palettes</a>, function in <a class="link" href="harfbuzz-hb-ot-color.html" title="hb-ot-color">hb-ot-color</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-collect-features-map" title="hb_ot_layout_collect_features_map ()">hb_ot_layout_collect_features_map</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-collect-lookups" title="hb_ot_layout_collect_lookups ()">hb_ot_layout_collect_lookups</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-baseline2" title="hb_ot_layout_get_baseline2 ()">hb_ot_layout_get_baseline2</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-baseline-with-fallback" title="hb_ot_layout_get_baseline_with_fallback ()">hb_ot_layout_get_baseline_with_fallback</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-baseline-with-fallback2" title="hb_ot_layout_get_baseline_with_fallback2 ()">hb_ot_layout_get_baseline_with_fallback2</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-font-extents" title="hb_ot_layout_get_font_extents ()">hb_ot_layout_get_font_extents</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-font-extents2" title="hb_ot_layout_get_font_extents2 ()">hb_ot_layout_get_font_extents2</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-glyphs-in-class" title="hb_ot_layout_get_glyphs_in_class ()">hb_ot_layout_get_glyphs_in_class</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-horizontal-baseline-tag-for-script" title="hb_ot_layout_get_horizontal_baseline_tag_for_script ()">hb_ot_layout_get_horizontal_baseline_tag_for_script</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-ligature-carets" title="hb_ot_layout_get_ligature_carets ()">hb_ot_layout_get_ligature_carets</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-lookup-get-optical-bound" title="hb_ot_layout_lookup_get_optical_bound ()">hb_ot_layout_lookup_get_optical_bound</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-lookup-substitute-closure" title="hb_ot_layout_lookup_substitute_closure ()">hb_ot_layout_lookup_substitute_closure</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-script-find-language" title="hb_ot_layout_script_find_language ()">hb_ot_layout_script_find_language</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-script-get-language-tags" title="hb_ot_layout_script_get_language_tags ()">hb_ot_layout_script_get_language_tags</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-script-select-language2" title="hb_ot_layout_script_select_language2 ()">hb_ot_layout_script_select_language2</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-layout-table-choose-script" title="hb_ot_layout_table_choose_script ()">hb_ot_layout_table_choose_script</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-table-find-feature-variations" title="hb_ot_layout_table_find_feature_variations ()">hb_ot_layout_table_find_feature_variations</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-ot-metrics.html#hb-ot-metrics-get-position-with-fallback" title="hb_ot_metrics_get_position_with_fallback ()">hb_ot_metrics_get_position_with_fallback</a>, function in <a class="link" href="harfbuzz-hb-ot-metrics.html" title="hb-ot-metrics">hb-ot-metrics</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-ot-metrics.html#hb-ot-metrics-get-variation" title="hb_ot_metrics_get_variation ()">hb_ot_metrics_get_variation</a>, function in <a class="link" href="harfbuzz-hb-ot-metrics.html" title="hb-ot-metrics">hb-ot-metrics</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-ot-name.html#hb-ot-name-id-predefined-t" title="enum hb_ot_name_id_predefined_t">hb_ot_name_id_predefined_t</a>, enum in <a class="link" href="harfbuzz-hb-ot-name.html" title="hb-ot-name">hb-ot-name</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-ot-name.html#hb-ot-name-id-t" title="hb_ot_name_id_t">hb_ot_name_id_t</a>, typedef in <a class="link" href="harfbuzz-hb-ot-name.html" title="hb-ot-name">hb-ot-name</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-tags-from-script" title="hb_ot_tags_from_script ()">hb_ot_tags_from_script</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-tags-from-script-and-language" title="hb_ot_tags_from_script_and_language ()">hb_ot_tags_from_script_and_language</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-tag-from-language" title="hb_ot_tag_from_language ()">hb_ot_tag_from_language</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-ot-layout.html#HB-OT-TAG-GDEF:CAPS" title="HB_OT_TAG_GDEF">HB_OT_TAG_GDEF</a>, macro in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-var-find-axis" title="hb_ot_var_find_axis ()">hb_ot_var_find_axis</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-ot-var.html#hb-ot-var-find-axis-info" title="hb_ot_var_find_axis_info ()">hb_ot_var_find_axis_info</a>, function in <a class="link" href="harfbuzz-hb-ot-var.html" title="hb-ot-var">hb-ot-var</a>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-var-get-axes" title="hb_ot_var_get_axes ()">hb_ot_var_get_axes</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-ot-var.html#hb-ot-var-get-axis-count" title="hb_ot_var_get_axis_count ()">hb_ot_var_get_axis_count</a>, function in <a class="link" href="harfbuzz-hb-ot-var.html" title="hb-ot-var">hb-ot-var</a>
 </dt>
 <dd></dd>
 <dd></dd>
 <a name="idxP"></a><h3 class="title">P</h3>
 <dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-color" title="hb_paint_color ()">hb_paint_color</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-color-func-t" title="hb_paint_color_func_t ()">hb_paint_color_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-color-glyph" title="hb_paint_color_glyph ()">hb_paint_color_glyph</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-color-glyph-func-t" title="hb_paint_color_glyph_func_t ()">hb_paint_color_glyph_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-composite-mode-t" title="enum hb_paint_composite_mode_t">hb_paint_composite_mode_t</a>, enum in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-custom-palette-color" title="hb_paint_custom_palette_color ()">hb_paint_custom_palette_color</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-custom-palette-color-func-t" title="hb_paint_custom_palette_color_func_t ()">hb_paint_custom_palette_color_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-extend-t" title="enum hb_paint_extend_t">hb_paint_extend_t</a>, enum in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-create" title="hb_paint_funcs_create ()">hb_paint_funcs_create</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-destroy" title="hb_paint_funcs_destroy ()">hb_paint_funcs_destroy</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-get-empty" title="hb_paint_funcs_get_empty ()">hb_paint_funcs_get_empty</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-get-user-data" title="hb_paint_funcs_get_user_data ()">hb_paint_funcs_get_user_data</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-is-immutable" title="hb_paint_funcs_is_immutable ()">hb_paint_funcs_is_immutable</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-make-immutable" title="hb_paint_funcs_make_immutable ()">hb_paint_funcs_make_immutable</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-reference" title="hb_paint_funcs_reference ()">hb_paint_funcs_reference</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-color-func" title="hb_paint_funcs_set_color_func ()">hb_paint_funcs_set_color_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-color-glyph-func" title="hb_paint_funcs_set_color_glyph_func ()">hb_paint_funcs_set_color_glyph_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-custom-palette-color-func" title="hb_paint_funcs_set_custom_palette_color_func ()">hb_paint_funcs_set_custom_palette_color_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-image-func" title="hb_paint_funcs_set_image_func ()">hb_paint_funcs_set_image_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-linear-gradient-func" title="hb_paint_funcs_set_linear_gradient_func ()">hb_paint_funcs_set_linear_gradient_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-pop-clip-func" title="hb_paint_funcs_set_pop_clip_func ()">hb_paint_funcs_set_pop_clip_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-pop-group-func" title="hb_paint_funcs_set_pop_group_func ()">hb_paint_funcs_set_pop_group_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-pop-transform-func" title="hb_paint_funcs_set_pop_transform_func ()">hb_paint_funcs_set_pop_transform_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-clip-glyph-func" title="hb_paint_funcs_set_push_clip_glyph_func ()">hb_paint_funcs_set_push_clip_glyph_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-clip-rectangle-func" title="hb_paint_funcs_set_push_clip_rectangle_func ()">hb_paint_funcs_set_push_clip_rectangle_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-group-func" title="hb_paint_funcs_set_push_group_func ()">hb_paint_funcs_set_push_group_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-transform-func" title="hb_paint_funcs_set_push_transform_func ()">hb_paint_funcs_set_push_transform_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-radial-gradient-func" title="hb_paint_funcs_set_radial_gradient_func ()">hb_paint_funcs_set_radial_gradient_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-sweep-gradient-func" title="hb_paint_funcs_set_sweep_gradient_func ()">hb_paint_funcs_set_sweep_gradient_func</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-user-data" title="hb_paint_funcs_set_user_data ()">hb_paint_funcs_set_user_data</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t">hb_paint_funcs_t</a>, typedef in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-image" title="hb_paint_image ()">hb_paint_image</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#HB-PAINT-IMAGE-FORMAT-BGRA:CAPS" title="HB_PAINT_IMAGE_FORMAT_BGRA">HB_PAINT_IMAGE_FORMAT_BGRA</a>, macro in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#HB-PAINT-IMAGE-FORMAT-PNG:CAPS" title="HB_PAINT_IMAGE_FORMAT_PNG">HB_PAINT_IMAGE_FORMAT_PNG</a>, macro in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#HB-PAINT-IMAGE-FORMAT-SVG:CAPS" title="HB_PAINT_IMAGE_FORMAT_SVG">HB_PAINT_IMAGE_FORMAT_SVG</a>, macro in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-image-func-t" title="hb_paint_image_func_t ()">hb_paint_image_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-linear-gradient" title="hb_paint_linear_gradient ()">hb_paint_linear_gradient</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-linear-gradient-func-t" title="hb_paint_linear_gradient_func_t ()">hb_paint_linear_gradient_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-clip" title="hb_paint_pop_clip ()">hb_paint_pop_clip</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-clip-func-t" title="hb_paint_pop_clip_func_t ()">hb_paint_pop_clip_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-group" title="hb_paint_pop_group ()">hb_paint_pop_group</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-group-func-t" title="hb_paint_pop_group_func_t ()">hb_paint_pop_group_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-transform" title="hb_paint_pop_transform ()">hb_paint_pop_transform</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-transform-func-t" title="hb_paint_pop_transform_func_t ()">hb_paint_pop_transform_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-clip-glyph" title="hb_paint_push_clip_glyph ()">hb_paint_push_clip_glyph</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-clip-glyph-func-t" title="hb_paint_push_clip_glyph_func_t ()">hb_paint_push_clip_glyph_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-clip-rectangle" title="hb_paint_push_clip_rectangle ()">hb_paint_push_clip_rectangle</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-clip-rectangle-func-t" title="hb_paint_push_clip_rectangle_func_t ()">hb_paint_push_clip_rectangle_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-group" title="hb_paint_push_group ()">hb_paint_push_group</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-group-func-t" title="hb_paint_push_group_func_t ()">hb_paint_push_group_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-transform" title="hb_paint_push_transform ()">hb_paint_push_transform</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-transform-func-t" title="hb_paint_push_transform_func_t ()">hb_paint_push_transform_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-radial-gradient" title="hb_paint_radial_gradient ()">hb_paint_radial_gradient</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-radial-gradient-func-t" title="hb_paint_radial_gradient_func_t ()">hb_paint_radial_gradient_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-sweep-gradient" title="hb_paint_sweep_gradient ()">hb_paint_sweep_gradient</a>, function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-sweep-gradient-func-t" title="hb_paint_sweep_gradient_func_t ()">hb_paint_sweep_gradient_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-paint.html" title="hb-paint">hb-paint</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t">hb_position_t</a>, typedef in <a class="link" href="harfbuzz-hb-common.html" title="hb-common">hb-common</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-add-sorted-array" title="hb_set_add_sorted_array ()">hb_set_add_sorted_array</a>, function in <a class="link" href="harfbuzz-hb-set.html" title="hb-set">hb-set</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-set.html#hb-set-allocation-successful" title="hb_set_allocation_successful ()">hb_set_allocation_successful</a>, function in <a class="link" href="harfbuzz-hb-set.html" title="hb-set">hb-set</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-hash" title="hb_set_hash ()">hb_set_hash</a>, function in <a class="link" href="harfbuzz-hb-set.html" title="hb-set">hb-set</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-set.html#hb-set-intersect" title="hb_set_intersect ()">hb_set_intersect</a>, function in <a class="link" href="harfbuzz-hb-set.html" title="hb-set">hb-set</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-is-inverted" title="hb_set_is_inverted ()">hb_set_is_inverted</a>, function in <a class="link" href="harfbuzz-hb-set.html" title="hb-set">hb-set</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-set.html#hb-set-is-subset" title="hb_set_is_subset ()">hb_set_is_subset</a>, function in <a class="link" href="harfbuzz-hb-set.html" title="hb-set">hb-set</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-next-many" title="hb_set_next_many ()">hb_set_next_many</a>, function in <a class="link" href="harfbuzz-hb-set.html" title="hb-set">hb-set</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-set.html#hb-set-next-range" title="hb_set_next_range ()">hb_set_next_range</a>, function in <a class="link" href="harfbuzz-hb-set.html" title="hb-set">hb-set</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-shape.html#hb-shape-justify" title="hb_shape_justify ()">hb_shape_justify</a>, function in <a class="link" href="harfbuzz-hb-shape.html" title="hb-shape">hb-shape</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-shape.html#hb-shape-list-shapers" title="hb_shape_list_shapers ()">hb_shape_list_shapers</a>, function in <a class="link" href="harfbuzz-hb-shape.html" title="hb-shape">hb-shape</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-keep-everything" title="hb_subset_input_keep_everything ()">hb_subset_input_keep_everything</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-old-to-new-glyph-mapping" title="hb_subset_input_old_to_new_glyph_mapping ()">hb_subset_input_old_to_new_glyph_mapping</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-pin-axis-location" title="hb_subset_input_pin_axis_location ()">hb_subset_input_pin_axis_location</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-pin-axis-to-default" title="hb_subset_input_pin_axis_to_default ()">hb_subset_input_pin_axis_to_default</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-reference" title="hb_subset_input_reference ()">hb_subset_input_reference</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-create-or-fail" title="hb_subset_plan_create_or_fail ()">hb_subset_plan_create_or_fail</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-destroy" title="hb_subset_plan_destroy ()">hb_subset_plan_destroy</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-execute-or-fail" title="hb_subset_plan_execute_or_fail ()">hb_subset_plan_execute_or_fail</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-get-user-data" title="hb_subset_plan_get_user_data ()">hb_subset_plan_get_user_data</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-new-to-old-glyph-mapping" title="hb_subset_plan_new_to_old_glyph_mapping ()">hb_subset_plan_new_to_old_glyph_mapping</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-old-to-new-glyph-mapping" title="hb_subset_plan_old_to_new_glyph_mapping ()">hb_subset_plan_old_to_new_glyph_mapping</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-reference" title="hb_subset_plan_reference ()">hb_subset_plan_reference</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-set-user-data" title="hb_subset_plan_set_user_data ()">hb_subset_plan_set_user_data</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-t" title="hb_subset_plan_t">hb_subset_plan_t</a>, typedef in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-unicode-to-old-glyph-mapping" title="hb_subset_plan_unicode_to_old_glyph_mapping ()">hb_subset_plan_unicode_to_old_glyph_mapping</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-preprocess" title="hb_subset_preprocess ()">hb_subset_preprocess</a>, function in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-subset.html#hb-subset-sets-t" title="enum hb_subset_sets_t">hb_subset_sets_t</a>, enum in <a class="link" href="harfbuzz-hb-subset.html" title="hb-subset">hb-subset</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#HB-UNICODE-COMBINING-CLASS-CCC133:CAPS" title="HB_UNICODE_COMBINING_CLASS_CCC133">HB_UNICODE_COMBINING_CLASS_CCC133</a>, macro in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-combining-class-func-t" title="hb_unicode_combining_class_func_t ()">hb_unicode_combining_class_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-unicode.html" title="hb-unicode">hb-unicode</a>
 </dt>
 <dd></dd>
index cda3f06..ccf9daf 100644 (file)
 <span class="refentrytitle"><a href="harfbuzz-hb-common.html">hb-common</a></span><span class="refpurpose"> — Common data types</span>
 </dt>
 <dt>
+<span class="refentrytitle"><a href="harfbuzz-hb-features.html">hb-features</a></span><span class="refpurpose"> — Feature detection</span>
+</dt>
+<dt>
+<span class="refentrytitle"><a href="harfbuzz-hb-draw.html">hb-draw</a></span><span class="refpurpose"> — Glyph drawing</span>
+</dt>
+<dt>
+<span class="refentrytitle"><a href="harfbuzz-hb-paint.html">hb-paint</a></span><span class="refpurpose"> — Glyph painting</span>
+</dt>
+<dt>
 <span class="refentrytitle"><a href="harfbuzz-hb-deprecated.html">hb-deprecated</a></span><span class="refpurpose"> — Deprecated API</span>
 </dt>
 <dt>
index 2333c5b..9fb382c 100644 (file)
@@ -7,7 +7,7 @@
 <link rel="home" href="index.html" title="HarfBuzz Manual">
 <link rel="up" href="reference-manual.html" title="Part II. Reference manual">
 <link rel="prev" href="api-index-full.html" title="API Index">
-<link rel="next" href="api-index-3-4-0.html" title="Index of new symbols in 3.4.0">
+<link rel="next" href="api-index-8-2-0.html" title="Index of new symbols in 8.2.0">
 <meta name="generator" content="GTK-Doc V1.32 (XML mode)">
 <link rel="stylesheet" href="style.css" type="text/css">
 </head>
@@ -17,6 +17,8 @@
                      <span class="dim">|</span> 
                   <a class="shortcut" href="#idxF">F</a>
                      <span class="dim">|</span> 
+                  <a class="shortcut" href="#idxG">G</a>
+                     <span class="dim">|</span> 
                   <a class="shortcut" href="#idxM">M</a>
                      <span class="dim">|</span> 
                   <a class="shortcut" href="#idxO">O</a>
@@ -27,7 +29,7 @@
 <td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
 <td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
 <td><a accesskey="p" href="api-index-full.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
-<td><a accesskey="n" href="api-index-3-4-0.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+<td><a accesskey="n" href="api-index-8-2-0.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
 </tr></table>
 <div class="index">
 <div class="titlepage"><div><div><h2 class="title">
 <dd></dd>
 <a name="idxF"></a><h3 class="title">F</h3>
 <dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-font-funcs-set-glyph-func" title="hb_font_funcs_set_glyph_func ()">hb_font_funcs_set_glyph_func</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-font-funcs-set-glyph-shape-func" title="hb_font_funcs_set_glyph_shape_func ()">hb_font_funcs_set_glyph_shape_func</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-deprecated.html#hb-font-funcs-set-glyph-v-kerning-func" title="hb_font_funcs_set_glyph_v_kerning_func ()">hb_font_funcs_set_glyph_v_kerning_func</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
 </dt>
 <dd></dd>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-font-get-glyph-shape" title="hb_font_get_glyph_shape ()">hb_font_get_glyph_shape</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-font-get-glyph-shape-func-t" title="hb_font_get_glyph_shape_func_t ()">hb_font_get_glyph_shape_func_t</a>, user_function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-deprecated.html#hb-font-get-glyph-v-kerning" title="hb_font_get_glyph_v_kerning ()">hb_font_get_glyph_v_kerning</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
 </dt>
 <dd></dd>
 <a class="link" href="harfbuzz-hb-deprecated.html#hb-font-get-glyph-v-kerning-func-t" title="hb_font_get_glyph_v_kerning_func_t">hb_font_get_glyph_v_kerning_func_t</a>, typedef in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
 </dt>
 <dd></dd>
+<a name="idxG"></a><h3 class="title">G</h3>
+<dt>
+<a class="link" href="harfbuzz-hb-graphite2.html#hb-graphite2-font-get-gr-font" title="hb_graphite2_font_get_gr_font ()">hb_graphite2_font_get_gr_font</a>, function in <a class="link" href="harfbuzz-hb-graphite2.html" title="hb-graphite2">hb-graphite2</a>
+</dt>
+<dd></dd>
 <a name="idxM"></a><h3 class="title">M</h3>
 <dt>
 <a class="link" href="harfbuzz-hb-deprecated.html#HB-MATH-GLYPH-PART-FLAG-EXTENDER:CAPS" title="HB_MATH_GLYPH_PART_FLAG_EXTENDER">HB_MATH_GLYPH_PART_FLAG_EXTENDER</a>, macro in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
 <dd></dd>
 <a name="idxO"></a><h3 class="title">O</h3>
 <dt>
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-script-find-language" title="hb_ot_layout_script_find_language ()">hb_ot_layout_script_find_language</a>, function in <a class="link" href="harfbuzz-hb-ot-layout.html" title="hb-ot-layout">hb-ot-layout</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-layout-table-choose-script" title="hb_ot_layout_table_choose_script ()">hb_ot_layout_table_choose_script</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-deprecated.html#HB-OT-MATH-SCRIPT:CAPS" title="HB_OT_MATH_SCRIPT">HB_OT_MATH_SCRIPT</a>, macro in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-tags-from-script" title="hb_ot_tags_from_script ()">hb_ot_tags_from_script</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-tag-from-language" title="hb_ot_tag_from_language ()">hb_ot_tag_from_language</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-var-axis-t" title="hb_ot_var_axis_t">hb_ot_var_axis_t</a>, struct in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-var-find-axis" title="hb_ot_var_find_axis ()">hb_ot_var_find_axis</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-var-get-axes" title="hb_ot_var_get_axes ()">hb_ot_var_get_axes</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-deprecated.html#HB-OT-VAR-NO-AXIS-INDEX:CAPS" title="HB_OT_VAR_NO_AXIS_INDEX">HB_OT_VAR_NO_AXIS_INDEX</a>, macro in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
 </dt>
 <dd></dd>
 <dd></dd>
 <a name="idxU"></a><h3 class="title">U</h3>
 <dt>
+<a class="link" href="harfbuzz-hb-deprecated.html#HB-UNICODE-COMBINING-CLASS-CCC133:CAPS" title="HB_UNICODE_COMBINING_CLASS_CCC133">HB_UNICODE_COMBINING_CLASS_CCC133</a>, macro in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="harfbuzz-hb-deprecated.html#hb-unicode-decompose-compatibility" title="hb_unicode_decompose_compatibility ()">hb_unicode_decompose_compatibility</a>, function in <a class="link" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">hb-deprecated</a>
 </dt>
 <dd></dd>
index 38c9422..fdf8d98 100644 (file)
       <code class="function">hb_font_get_glyph_from_name_func_t</code>: returns
       the glyph index that corresponds to a given glyph name.
     </p></li>
+<li class="listitem"><p>
+      <code class="function">hb_font_draw_glyph_func_t</code>: gets the outlines
+      of a glyph (by calling #hb_draw_funcs_t callbacks).
+    </p></li>
+<li class="listitem"><p>
+      <code class="function">hb_font_paint_glyph_func_t</code>: paints a glyph
+      (by calling #hb_paint_funcs_t callbacks).
+    </p></li>
 </ul></div>
 <p>
       You can create new font-functions by calling
index b857d3b..2fca0ef 100644 (file)
@@ -7,7 +7,7 @@
 <link rel="home" href="index.html" title="HarfBuzz Manual">
 <link rel="up" href="fonts-and-faces.html" title="Fonts, faces, and output">
 <link rel="prev" href="fonts-and-faces-native-opentype.html" title="Font objects and HarfBuzz's native OpenType implementation">
-<link rel="next" href="shaping-and-shape-plans.html" title="Shaping and shape plans">
+<link rel="next" href="glyphs-and-rendering.html" title="Glyphs and rendering">
 <meta name="generator" content="GTK-Doc V1.32 (XML mode)">
 <link rel="stylesheet" href="style.css" type="text/css">
 </head>
@@ -17,7 +17,7 @@
 <td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
 <td><a accesskey="u" href="fonts-and-faces.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
 <td><a accesskey="p" href="fonts-and-faces-native-opentype.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
-<td><a accesskey="n" href="shaping-and-shape-plans.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+<td><a accesskey="n" href="glyphs-and-rendering.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
 </tr></table>
 <div class="section">
 <div class="titlepage"><div><div><h2 class="title" style="clear: both">
       range actually implemented in the font's variation axis. After
       all, a font might only provide lighter-than-regular weights, and
       setting a heavier value on the <code class="literal">wght</code> axis will
-      not change that. 
+      not change that.
     </p>
 <p>
       Once your variation settings are specified on your font object,
       however, shaping with a variable font is just like shaping a
       static font.
     </p>
+<p>
+      In addition to providing the variation axes themselves, fonts may also
+      pre-define certain variation coordinates as named instances. HarfBuzz
+      makes these coordinates (and their associated names) available via
+      <code class="function">hb_ot_var_named_instance_get_design_coords()</code> and
+      <code class="function">hb_ot_var_named_instance_get_subfamily_name_id()</code>.
+    </p>
+<p>
+      Applications should treat named instances like multiple independent,
+      static fonts.
+    </p>
 </div>
 <div class="footer">
 <hr>Generated by GTK-Doc V1.32</div>
index 841f255..b1a5d4c 100644 (file)
@@ -27,6 +27,7 @@
 <dt><span class="section"><a href="fonts-and-faces-custom-functions.html">Customizing font functions</a></span></dt>
 <dt><span class="section"><a href="fonts-and-faces-native-opentype.html">Font objects and HarfBuzz's native OpenType implementation</a></span></dt>
 <dt><span class="section"><a href="fonts-and-faces-variable.html">Working with OpenType Variable Fonts</a></span></dt>
+<dt><span class="section"><a href="glyphs-and-rendering.html">Glyphs and rendering</a></span></dt>
 </dl></div>
 <p>
       In the previous chapter, we saw how to set up a buffer and fill
@@ -77,7 +78,7 @@
       shaping. The typeface must be set to a specific point size in
       order for some details (such as hinting) to work. In addition,
       if the font file in question is an OpenType Variable Font, then
-      you may need to specify one or variation-axis settings (or a
+      you may need to specify one or more variation-axis settings (or a
       named instance) in order to get the output you need.
     </p>
 <p>
diff --git a/docs/html/glyphs-and-rendering.html b/docs/html/glyphs-and-rendering.html
new file mode 100644 (file)
index 0000000..a484e5e
--- /dev/null
@@ -0,0 +1,66 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Glyphs and rendering: HarfBuzz Manual</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
+<link rel="home" href="index.html" title="HarfBuzz Manual">
+<link rel="up" href="fonts-and-faces.html" title="Fonts, faces, and output">
+<link rel="prev" href="fonts-and-faces-variable.html" title="Working with OpenType Variable Fonts">
+<link rel="next" href="shaping-and-shape-plans.html" title="Shaping and shape plans">
+<meta name="generator" content="GTK-Doc V1.32 (XML mode)">
+<link rel="stylesheet" href="style.css" type="text/css">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
+<td width="100%" align="left" class="shortcuts"></td>
+<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
+<td><a accesskey="u" href="fonts-and-faces.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
+<td><a accesskey="p" href="fonts-and-faces-variable.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="shaping-and-shape-plans.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+</tr></table>
+<div class="section">
+<div class="titlepage"><div><div><h2 class="title" style="clear: both">
+<a name="glyphs-and-rendering"></a>Glyphs and rendering</h2></div></div></div>
+<p>
+      The main purpose of HarfBuzz is shaping, which creates a list of positioned
+      glyphs as output. The remaining task for text layout is to convert this list
+      into rendered output. While HarfBuzz does not handle rasterization of glyphs
+      per se, it does have APIs that provide access to the font data that is needed
+      to perform this task.
+    </p>
+<p>
+      Traditionally, the shapes of glyphs in scalable fonts are provided as quadratic
+      or cubic Beziér curves defining outlines to be filled. To obtain the outlines
+      for a glyph, call <code class="function">hb_font_draw_glyph()</code> and pass a
+      <span class="type">hb_draw_funcs_t</span> struct. The callbacks in that struct will be called
+      for each segment of the outline. Note that this API provides access to outlines
+      as they are defined in the font, without applying hinting to fit the curves
+      to the pixel grid.
+    </p>
+<p>
+      Fonts may provide pre-rendered images for glyphs instead of or in addition to
+      outlines. This is most common for fonts that contain colored glyphs, such as
+      Emoji. To access these images, use <code class="function">hb_ot_color_reference_png()</code>
+      or <code class="function">hb_ot_color_reference_svg()</code>.
+    </p>
+<p>
+      Another way in which fonts provide colored glyphs is via paint graphs that
+      combine glyph outlines with gradients and allow for transformations and
+      compositing. In its simplest form, this can be presented as a series of
+      layers that are rendered on top of each other, each with its own color.
+      HarfBuzz has the <code class="function">hb_ot_color_glyph_get_layers()</code> to
+      access glyph data in this form.
+    </p>
+<p>
+      In the general case, you have to use <code class="function">hb_font_paint_glyph()</code>
+      and pass a <span class="type">hb_paint_funcs_t</span> struct with callbacks to obtain paint
+      graphs for glyphs that have them. The <code class="function">hb_font_paint_glyph()</code>
+      API can handle outline and image glyphs as well, so it provides a unified API for
+      access to glyph rendering information.
+    </p>
+</div>
+<div class="footer">
+<hr>Generated by GTK-Doc V1.32</div>
+</body>
+</html>
\ No newline at end of file
index 822fb52..0ac93c9 100644 (file)
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="returnvalue">hb_blob_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-blob.html#hb-blob-destroy" title="hb_blob_destroy ()">hb_blob_destroy</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-blob.html#hb-blob-get-empty" title="hb_blob_get_empty ()">hb_blob_get_empty</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">const <span class="returnvalue">char</span> *
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="returnvalue">hb_blob_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-blob.html#hb-blob-get-data" title="hb_blob_get_data ()">hb_blob_get_data</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-blob.html#hb-blob-reference" title="hb_blob_reference ()">hb_blob_reference</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">char</span> *
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-blob.html#hb-blob-get-data-writable" title="hb_blob_get_data_writable ()">hb_blob_get_data_writable</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-blob.html#hb-blob-destroy" title="hb_blob_destroy ()">hb_blob_destroy</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="returnvalue">hb_blob_t</span></a> *
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-blob.html#hb-blob-get-empty" title="hb_blob_get_empty ()">hb_blob_get_empty</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-blob.html#hb-blob-set-user-data" title="hb_blob_set_user_data ()">hb_blob_set_user_data</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">unsigned <span class="returnvalue">int</span>
+<td class="function_type">
+<span class="returnvalue">void</span> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-blob.html#hb-blob-get-length" title="hb_blob_get_length ()">hb_blob_get_length</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-blob.html#hb-blob-get-user-data" title="hb_blob_get_user_data ()">hb_blob_get_user_data</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span> *
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-blob.html#hb-blob-get-user-data" title="hb_blob_get_user_data ()">hb_blob_get_user_data</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-blob.html#hb-blob-make-immutable" title="hb_blob_make_immutable ()">hb_blob_make_immutable</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 </td>
 </tr>
 <tr>
-<td class="function_type">
-<span class="returnvalue">void</span>
+<td class="function_type">const <span class="returnvalue">char</span> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-blob.html#hb-blob-make-immutable" title="hb_blob_make_immutable ()">hb_blob_make_immutable</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-blob.html#hb-blob-get-data" title="hb_blob_get_data ()">hb_blob_get_data</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="returnvalue">hb_blob_t</span></a> *
+<span class="returnvalue">char</span> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-blob.html#hb-blob-reference" title="hb_blob_reference ()">hb_blob_reference</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-blob.html#hb-blob-get-data-writable" title="hb_blob_get_data_writable ()">hb_blob_get_data_writable</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<td class="function_type">unsigned <span class="returnvalue">int</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-blob.html#hb-blob-set-user-data" title="hb_blob_set_user_data ()">hb_blob_set_user_data</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-blob.html#hb-blob-get-length" title="hb_blob_get_length ()">hb_blob_get_length</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 </tbody>
@@ -473,18 +473,29 @@ hb_blob_copy_writable_or_fail (<em class="parameter"><code><a class="link" href=
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-blob-destroy"></a><h3>hb_blob_destroy ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_blob_destroy (<em class="parameter"><code><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a> *blob</code></em>);</pre>
-<p>Decreases the reference count on <em class="parameter"><code>blob</code></em>
-, and if it reaches zero, destroys
-<em class="parameter"><code>blob</code></em>
-, freeing all memory, possibly calling the destroy-callback the blob
-was created for if it has not been called already.</p>
+<a name="hb-blob-get-empty"></a><h3>hb_blob_get_empty ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="returnvalue">hb_blob_t</span></a> *
+hb_blob_get_empty (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
+<p>Returns the singleton empty blob.</p>
+<p>See TODO:link object types for more information.</p>
+<div class="refsect3">
+<a name="hb-blob-get-empty.returns"></a><h4>Returns</h4>
+<p>The empty blob. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-blob-reference"></a><h3>hb_blob_reference ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="returnvalue">hb_blob_t</span></a> *
+hb_blob_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a> *blob</code></em>);</pre>
+<p>Increases the reference count on <em class="parameter"><code>blob</code></em>
+.</p>
 <p>See TODO:link object types for more information.</p>
 <p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
-<a name="hb-blob-destroy.parameters"></a><h4>Parameters</h4>
+<a name="hb-blob-reference.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -498,57 +509,55 @@ was created for if it has not been called already.</p>
 </tr></tbody>
 </table></div>
 </div>
+<div class="refsect3">
+<a name="hb-blob-reference.returns"></a><h4>Returns</h4>
+<p> <em class="parameter"><code>blob</code></em>
+.</p>
+</div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-blob-get-data"></a><h3>hb_blob_get_data ()</h3>
-<pre class="programlisting">const <span class="returnvalue">char</span> *
-hb_blob_get_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a> *blob</code></em>,
-                  <em class="parameter"><code>unsigned <span class="type">int</span> *length</code></em>);</pre>
-<p>Fetches the data from a blob.</p>
+<a name="hb-blob-destroy"></a><h3>hb_blob_destroy ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_blob_destroy (<em class="parameter"><code><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a> *blob</code></em>);</pre>
+<p>Decreases the reference count on <em class="parameter"><code>blob</code></em>
+, and if it reaches zero, destroys
+<em class="parameter"><code>blob</code></em>
+, freeing all memory, possibly calling the destroy-callback the blob
+was created for if it has not been called already.</p>
+<p>See TODO:link object types for more information.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
-<a name="hb-blob-get-data.parameters"></a><h4>Parameters</h4>
+<a name="hb-blob-destroy.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody>
-<tr>
+<tbody><tr>
 <td class="parameter_name"><p>blob</p></td>
 <td class="parameter_description"><p>a blob.</p></td>
 <td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>length</p></td>
-<td class="parameter_description"><p>The length in bytes of the data retrieved. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-</tbody>
+</tr></tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-blob-get-data.returns"></a><h4>Returns</h4>
-<p>the byte data of <em class="parameter"><code>blob</code></em>
-. </p>
-<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=length]</span></p>
-</div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-blob-get-data-writable"></a><h3>hb_blob_get_data_writable ()</h3>
-<pre class="programlisting"><span class="returnvalue">char</span> *
-hb_blob_get_data_writable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a> *blob</code></em>,
-                           <em class="parameter"><code>unsigned <span class="type">int</span> *length</code></em>);</pre>
-<p>Tries to make blob data writable (possibly copying it) and
-return pointer to data.</p>
-<p>Fails if blob has been made immutable, or if memory allocation
-fails.</p>
+<a name="hb-blob-set-user-data"></a><h3>hb_blob_set_user_data ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_blob_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a> *blob</code></em>,
+                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
+                       <em class="parameter"><code><span class="type">void</span> *data</code></em>,
+                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
+                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
+<p>Attaches a user-data key/data pair to the specified blob.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
-<a name="hb-blob-get-data-writable.parameters"></a><h4>Parameters</h4>
+<a name="hb-blob-set-user-data.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -558,64 +567,36 @@ fails.</p>
 <tbody>
 <tr>
 <td class="parameter_name"><p>blob</p></td>
-<td class="parameter_description"><p>a blob.</p></td>
+<td class="parameter_description"><p>An <a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a></p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>length</p></td>
-<td class="parameter_description"><p>output length of the writable data. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The user-data key to set</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
-</tbody>
-</table></div>
-</div>
-<div class="refsect3">
-<a name="hb-blob-get-data-writable.returns"></a><h4>Returns</h4>
-<p>Writable blob data,
-or <code class="literal">NULL</code> if failed. </p>
-<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=length]</span></p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-blob-get-empty"></a><h3>hb_blob_get_empty ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="returnvalue">hb_blob_t</span></a> *
-hb_blob_get_empty (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
-<p>Returns the singleton empty blob.</p>
-<p>See TODO:link object types for more information.</p>
-<div class="refsect3">
-<a name="hb-blob-get-empty.returns"></a><h4>Returns</h4>
-<p>The empty blob. </p>
-<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-blob-get-length"></a><h3>hb_blob_get_length ()</h3>
-<pre class="programlisting">unsigned <span class="returnvalue">int</span>
-hb_blob_get_length (<em class="parameter"><code><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a> *blob</code></em>);</pre>
-<p>Fetches the length of a blob's data.</p>
-<div class="refsect3">
-<a name="hb-blob-get-length.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody><tr>
-<td class="parameter_name"><p>blob</p></td>
-<td class="parameter_description"><p>a blob.</p></td>
+<tr>
+<td class="parameter_name"><p>data</p></td>
+<td class="parameter_description"><p>A pointer to the user data to set</p></td>
 <td class="parameter_annotations"> </td>
-</tr></tbody>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>replace</p></td>
+<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-blob-get-length.returns"></a><h4>Returns</h4>
-<p> the length of <em class="parameter"><code>blob</code></em>
-data in bytes.</p>
+<a name="hb-blob-set-user-data.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
@@ -623,7 +604,7 @@ data in bytes.</p>
 <div class="refsect2">
 <a name="hb-blob-get-user-data"></a><h3>hb_blob_get_user_data ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span> *
-hb_blob_get_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a> *blob</code></em>,
+hb_blob_get_user_data (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a> *blob</code></em>,
                        <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>);</pre>
 <p>Fetches the user data associated with the specified key,
 attached to the specified font-functions structure.</p>
@@ -659,6 +640,29 @@ attached to the specified font-functions structure.</p>
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-blob-make-immutable"></a><h3>hb_blob_make_immutable ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_blob_make_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a> *blob</code></em>);</pre>
+<p>Makes a blob immutable.</p>
+<div class="refsect3">
+<a name="hb-blob-make-immutable.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>blob</p></td>
+<td class="parameter_description"><p>a blob</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-blob-is-immutable"></a><h3>hb_blob_is_immutable ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 hb_blob_is_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a> *blob</code></em>);</pre>
@@ -687,110 +691,106 @@ is immutable, <code class="literal">false</code> otherwise</p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-blob-make-immutable"></a><h3>hb_blob_make_immutable ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_blob_make_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a> *blob</code></em>);</pre>
-<p>Makes a blob immutable.</p>
+<a name="hb-blob-get-data"></a><h3>hb_blob_get_data ()</h3>
+<pre class="programlisting">const <span class="returnvalue">char</span> *
+hb_blob_get_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a> *blob</code></em>,
+                  <em class="parameter"><code>unsigned <span class="type">int</span> *length</code></em>);</pre>
+<p>Fetches the data from a blob.</p>
 <div class="refsect3">
-<a name="hb-blob-make-immutable.parameters"></a><h4>Parameters</h4>
+<a name="hb-blob-get-data.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody><tr>
+<tbody>
+<tr>
 <td class="parameter_name"><p>blob</p></td>
-<td class="parameter_description"><p>a blob</p></td>
+<td class="parameter_description"><p>a blob.</p></td>
 <td class="parameter_annotations"> </td>
-</tr></tbody>
+</tr>
+<tr>
+<td class="parameter_name"><p>length</p></td>
+<td class="parameter_description"><p>The length in bytes of the data retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+</tbody>
 </table></div>
 </div>
+<div class="refsect3">
+<a name="hb-blob-get-data.returns"></a><h4>Returns</h4>
+<p>the byte data of <em class="parameter"><code>blob</code></em>
+. </p>
+<p><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>][<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=length]</span></p>
+</div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-blob-reference"></a><h3>hb_blob_reference ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="returnvalue">hb_blob_t</span></a> *
-hb_blob_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a> *blob</code></em>);</pre>
-<p>Increases the reference count on <em class="parameter"><code>blob</code></em>
-.</p>
-<p>See TODO:link object types for more information.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<a name="hb-blob-get-data-writable"></a><h3>hb_blob_get_data_writable ()</h3>
+<pre class="programlisting"><span class="returnvalue">char</span> *
+hb_blob_get_data_writable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a> *blob</code></em>,
+                           <em class="parameter"><code>unsigned <span class="type">int</span> *length</code></em>);</pre>
+<p>Tries to make blob data writable (possibly copying it) and
+return pointer to data.</p>
+<p>Fails if blob has been made immutable, or if memory allocation
+fails.</p>
 <div class="refsect3">
-<a name="hb-blob-reference.parameters"></a><h4>Parameters</h4>
+<a name="hb-blob-get-data-writable.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody><tr>
+<tbody>
+<tr>
 <td class="parameter_name"><p>blob</p></td>
 <td class="parameter_description"><p>a blob.</p></td>
 <td class="parameter_annotations"> </td>
-</tr></tbody>
+</tr>
+<tr>
+<td class="parameter_name"><p>length</p></td>
+<td class="parameter_description"><p>output length of the writable data. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+</tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-blob-reference.returns"></a><h4>Returns</h4>
-<p> <em class="parameter"><code>blob</code></em>
-.</p>
+<a name="hb-blob-get-data-writable.returns"></a><h4>Returns</h4>
+<p>Writable blob data,
+or <code class="literal">NULL</code> if failed. </p>
+<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=length]</span></p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-blob-set-user-data"></a><h3>hb_blob_set_user_data ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_blob_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a> *blob</code></em>,
-                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
-                       <em class="parameter"><code><span class="type">void</span> *data</code></em>,
-                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
-                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
-<p>Attaches a user-data key/data pair to the specified blob.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<a name="hb-blob-get-length"></a><h3>hb_blob_get_length ()</h3>
+<pre class="programlisting">unsigned <span class="returnvalue">int</span>
+hb_blob_get_length (<em class="parameter"><code><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a> *blob</code></em>);</pre>
+<p>Fetches the length of a blob's data.</p>
 <div class="refsect3">
-<a name="hb-blob-set-user-data.parameters"></a><h4>Parameters</h4>
+<a name="hb-blob-get-length.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody>
-<tr>
+<tbody><tr>
 <td class="parameter_name"><p>blob</p></td>
-<td class="parameter_description"><p>An <a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a></p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>key</p></td>
-<td class="parameter_description"><p>The user-data key to set</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>data</p></td>
-<td class="parameter_description"><p>A pointer to the user data to set</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>replace</p></td>
-<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
+<td class="parameter_description"><p>a blob.</p></td>
 <td class="parameter_annotations"> </td>
-</tr>
-</tbody>
+</tr></tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-blob-set-user-data.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
+<a name="hb-blob-get-length.returns"></a><h4>Returns</h4>
+<p> the length of <em class="parameter"><code>blob</code></em>
+data in bytes.</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
@@ -825,7 +825,7 @@ really know what you are doing,</p></li>
 copy of data solely for the purpose of passing to
 HarfBuzz and doing that just once (no reuse!),</p></li>
 <li class="listitem"><p>If the font is <code class="function">mmap()</code>ed, it's okay to use
-<em class="parameter"><code>HB_MEMORY_READONLY_MAY_MAKE_WRITABLE</code></em>
+<em class="parameter"><code>HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE</code></em>
 , however, using that mode
 correctly is very tricky.  Use <em class="parameter"><code>HB_MEMORY_MODE_READONLY</code></em>
  instead.</p></li>
index 7c12c6b..1c04554 100644 (file)
 </tr>
 <tr>
 <td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-allocation-successful" title="hb_buffer_allocation_successful ()">hb_buffer_allocation_successful</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
 <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="returnvalue">hb_buffer_t</span></a> *
 </td>
 <td class="function_name">
@@ -60,7 +68,7 @@
 <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="returnvalue">hb_buffer_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-reference" title="hb_buffer_reference ()">hb_buffer_reference</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-get-empty" title="hb_buffer_get_empty ()">hb_buffer_get_empty</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
@@ -68,7 +76,7 @@
 <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="returnvalue">hb_buffer_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-get-empty" title="hb_buffer_get_empty ()">hb_buffer_get_empty</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-reference" title="hb_buffer_reference ()">hb_buffer_reference</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-reset" title="hb_buffer_reset ()">hb_buffer_reset</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-set-user-data" title="hb_buffer_set_user_data ()">hb_buffer_set_user_data</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-get-user-data" title="hb_buffer_get_user_data ()">hb_buffer_get_user_data</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-clear-contents" title="hb_buffer_clear_contents ()">hb_buffer_clear_contents</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-reset" title="hb_buffer_reset ()">hb_buffer_reset</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-pre-allocate" title="hb_buffer_pre_allocate ()">hb_buffer_pre_allocate</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-clear-contents" title="hb_buffer_clear_contents ()">hb_buffer_clear_contents</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-allocation-successful" title="hb_buffer_allocation_successful ()">hb_buffer_allocation_successful</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-pre-allocate" title="hb_buffer_pre_allocate ()">hb_buffer_pre_allocate</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-info-t" title="hb_glyph_info_t"><span class="returnvalue">hb_glyph_info_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-set-user-data" title="hb_buffer_set_user_data ()">hb_buffer_set_user_data</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-get-glyph-infos" title="hb_buffer_get_glyph_infos ()">hb_buffer_get_glyph_infos</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span> *
+<a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-flags-t" title="enum hb_glyph_flags_t"><span class="returnvalue">hb_glyph_flags_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-get-user-data" title="hb_buffer_get_user_data ()">hb_buffer_get_user_data</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-info-get-glyph-flags" title="hb_glyph_info_get_glyph_flags ()">hb_glyph_info_get_glyph_flags</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-info-t" title="hb_glyph_info_t"><span class="returnvalue">hb_glyph_info_t</span></a> *
+<a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-position-t" title="hb_glyph_position_t"><span class="returnvalue">hb_glyph_position_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-get-glyph-infos" title="hb_buffer_get_glyph_infos ()">hb_buffer_get_glyph_infos</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-get-glyph-positions" title="hb_buffer_get_glyph_positions ()">hb_buffer_get_glyph_positions</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-position-t" title="hb_glyph_position_t"><span class="returnvalue">hb_glyph_position_t</span></a> *
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-get-glyph-positions" title="hb_buffer_get_glyph_positions ()">hb_buffer_get_glyph_positions</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-has-positions" title="hb_buffer_has_positions ()">hb_buffer_has_positions</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-has-positions" title="hb_buffer_has_positions ()">hb_buffer_has_positions</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-set-invisible-glyph" title="hb_buffer_set_invisible_glyph ()">hb_buffer_set_invisible_glyph</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-set-invisible-glyph" title="hb_buffer_set_invisible_glyph ()">hb_buffer_set_invisible_glyph</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-set-not-found-glyph" title="hb_buffer_set_not_found_glyph ()">hb_buffer_set_not_found_glyph</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-set-not-found-glyph" title="hb_buffer_set_not_found_glyph ()">hb_buffer_set_not_found_glyph</a> <span class="c_punctuation">()</span>
-</td>
-</tr>
-<tr>
-<td class="function_type">
-<span class="returnvalue">void</span>
-</td>
-<td class="function_name">
 <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-set-replacement-codepoint" title="hb_buffer_set_replacement_codepoint ()">hb_buffer_set_replacement_codepoint</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
-</td>
-<td class="function_name">
-<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-set-message-func" title="hb_buffer_set_message_func ()">hb_buffer_set_message_func</a> <span class="c_punctuation">()</span>
-</td>
-</tr>
-<tr>
-<td class="function_type">
-<a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-flags-t" title="enum hb_glyph_flags_t"><span class="returnvalue">hb_glyph_flags_t</span></a>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-info-get-glyph-flags" title="hb_glyph_info_get_glyph_flags ()">hb_glyph_info_get_glyph_flags</a> <span class="c_punctuation">()</span>
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-message-func-t" title="hb_buffer_message_func_t ()">*hb_buffer_message_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-message-func-t" title="hb_buffer_message_func_t ()">*hb_buffer_message_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-set-message-func" title="hb_buffer_set_message_func ()">hb_buffer_set_message_func</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 </tbody>
 <p>Buffers serve a dual role in HarfBuzz; before shaping, they hold
 the input characters that are passed to <a class="link" href="harfbuzz-hb-shape.html#hb-shape" title="hb_shape ()"><code class="function">hb_shape()</code></a>, and after
 shaping they hold the output glyphs.</p>
+<p>The input buffer is a sequence of Unicode codepoints, with
+associated attributes such as direction and script.  The output
+buffer is a sequence of glyphs, with associated attributes such
+as position and cluster.</p>
 </div>
 <div class="refsect1">
 <a name="harfbuzz-hb-buffer.functions_details"></a><h2>Functions</h2>
@@ -636,7 +640,6 @@ shaping they hold the output glyphs.</p>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="returnvalue">hb_buffer_t</span></a> *
 hb_buffer_create (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
 <p>Creates a new <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> with all properties to defaults.</p>
-<p><span class="annotation">[Xconstructor]</span></p>
 <div class="refsect3">
 <a name="hb-buffer-create.returns"></a><h4>Returns</h4>
 <p>A newly allocated <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> with a reference count of 1. The initial
@@ -650,6 +653,34 @@ be allocated, a special <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-buffer-allocation-successful"></a><h3>hb_buffer_allocation_successful ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_buffer_allocation_successful (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
+<p>Check if allocating memory for the buffer succeeded.</p>
+<div class="refsect3">
+<a name="hb-buffer-allocation-successful.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>buffer</p></td>
+<td class="parameter_description"><p>An <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-buffer-allocation-successful.returns"></a><h4>Returns</h4>
+<p><code class="literal">true</code> if <em class="parameter"><code>buffer</code></em>
+memory allocation succeeded, <code class="literal">false</code> otherwise.</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-buffer-create-similar"></a><h3>hb_buffer_create_similar ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="returnvalue">hb_buffer_t</span></a> *
 hb_buffer_create_similar (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *src</code></em>);</pre>
@@ -680,6 +711,19 @@ difference is that the buffer is configured similarly to <em class="parameter"><
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-buffer-get-empty"></a><h3>hb_buffer_get_empty ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="returnvalue">hb_buffer_t</span></a> *
+hb_buffer_get_empty (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
+<p>Fetches an empty <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a>.</p>
+<div class="refsect3">
+<a name="hb-buffer-get-empty.returns"></a><h4>Returns</h4>
+<p>The empty buffer. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-buffer-reference"></a><h3>hb_buffer_reference ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="returnvalue">hb_buffer_t</span></a> *
 hb_buffer_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
@@ -712,19 +756,6 @@ being destroyed until a matching call to <a class="link" href="harfbuzz-hb-buffe
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-buffer-get-empty"></a><h3>hb_buffer_get_empty ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="returnvalue">hb_buffer_t</span></a> *
-hb_buffer_get_empty (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
-<p>Fetches an empty <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a>.</p>
-<div class="refsect3">
-<a name="hb-buffer-get-empty.returns"></a><h4>Returns</h4>
-<p>The empty buffer. </p>
-<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
 <a name="hb-buffer-destroy"></a><h3>hb_buffer_destroy ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
 hb_buffer_destroy (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
@@ -754,6 +785,99 @@ Decreases the reference count on <em class="parameter"><code>buffer</code></em>
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-buffer-set-user-data"></a><h3>hb_buffer_set_user_data ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_buffer_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>,
+                         <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
+                         <em class="parameter"><code><span class="type">void</span> *data</code></em>,
+                         <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
+                         <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
+<p>Attaches a user-data key/data pair to the specified buffer.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-buffer-set-user-data.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>buffer</p></td>
+<td class="parameter_description"><p>An <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The user-data key</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>data</p></td>
+<td class="parameter_description"><p>A pointer to the user data</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>replace</p></td>
+<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-buffer-set-user-data.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-buffer-get-user-data"></a><h3>hb_buffer_get_user_data ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span> *
+hb_buffer_get_user_data (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>,
+                         <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>);</pre>
+<p>Fetches the user data associated with the specified key,
+attached to the specified buffer.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-buffer-get-user-data.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>buffer</p></td>
+<td class="parameter_description"><p>An <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The user-data key to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-buffer-get-user-data.returns"></a><h4>Returns</h4>
+<p>A pointer to the user data. </p>
+<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-buffer-reset"></a><h3>hb_buffer_reset ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
 hb_buffer_reset (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
@@ -840,34 +964,6 @@ memory allocation succeeded, <code class="literal">false</code> otherwise</p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-buffer-allocation-successful"></a><h3>hb_buffer_allocation_successful ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_buffer_allocation_successful (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
-<p>Check if allocating memory for the buffer succeeded.</p>
-<div class="refsect3">
-<a name="hb-buffer-allocation-successful.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody><tr>
-<td class="parameter_name"><p>buffer</p></td>
-<td class="parameter_description"><p>An <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a></p></td>
-<td class="parameter_annotations"> </td>
-</tr></tbody>
-</table></div>
-</div>
-<div class="refsect3">
-<a name="hb-buffer-allocation-successful.returns"></a><h4>Returns</h4>
-<p><code class="literal">true</code> if <em class="parameter"><code>buffer</code></em>
-memory allocation succeeded, <code class="literal">false</code> otherwise.</p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
 <a name="hb-buffer-add"></a><h3>hb_buffer_add ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
 hb_buffer_add (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>,
@@ -941,7 +1037,9 @@ for example, to do cross-run Arabic shaping or properly handle combining
 marks at stat of run.</p>
 <p>This function does not check the validity of <em class="parameter"><code>text</code></em>
 , it is up to the caller
-to ensure it contains a valid Unicode code points.</p>
+to ensure it contains a valid Unicode scalar values.  In contrast,
+<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-add-utf32" title="hb_buffer_add_utf32 ()"><code class="function">hb_buffer_add_utf32()</code></a> can be used that takes similar input but performs
+sanity-check on the input.</p>
 <div class="refsect3">
 <a name="hb-buffer-add-codepoints.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
@@ -1268,6 +1366,29 @@ hb_buffer_set_content_type (<em class="parameter"><code><a class="link" href="ha
 <p>Sets the type of <em class="parameter"><code>buffer</code></em>
  contents. Buffers are either empty, contain
 characters (before shaping), or contain glyphs (the result of shaping).</p>
+<p>You rarely need to call this function, since a number of other
+functions transition the content type for you. Namely:</p>
+<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
+<li class="listitem"><p>A newly created buffer starts with content type
+<a class="link" href="harfbuzz-hb-buffer.html#HB-BUFFER-CONTENT-TYPE-INVALID:CAPS"><code class="literal">HB_BUFFER_CONTENT_TYPE_INVALID</code></a>. Calling <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-reset" title="hb_buffer_reset ()"><code class="function">hb_buffer_reset()</code></a>,
+<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-clear-contents" title="hb_buffer_clear_contents ()"><code class="function">hb_buffer_clear_contents()</code></a>, as well as calling <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-set-length" title="hb_buffer_set_length ()"><code class="function">hb_buffer_set_length()</code></a>
+with an argument of zero all set the buffer content type to invalid
+as well.</p></li>
+<li class="listitem"><p>Calling <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-add-utf8" title="hb_buffer_add_utf8 ()"><code class="function">hb_buffer_add_utf8()</code></a>, <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-add-utf16" title="hb_buffer_add_utf16 ()"><code class="function">hb_buffer_add_utf16()</code></a>,
+<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-add-utf32" title="hb_buffer_add_utf32 ()"><code class="function">hb_buffer_add_utf32()</code></a>, <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-add-codepoints" title="hb_buffer_add_codepoints ()"><code class="function">hb_buffer_add_codepoints()</code></a> and
+<a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-add-latin1" title="hb_buffer_add_latin1 ()"><code class="function">hb_buffer_add_latin1()</code></a> expect that buffer is either empty and
+have a content type of invalid, or that buffer content type is
+<a class="link" href="harfbuzz-hb-buffer.html#HB-BUFFER-CONTENT-TYPE-UNICODE:CAPS"><code class="literal">HB_BUFFER_CONTENT_TYPE_UNICODE</code></a>, and they also set the content
+type to Unicode if they added anything to an empty buffer.</p></li>
+<li class="listitem"><p>Finally <a class="link" href="harfbuzz-hb-shape.html#hb-shape" title="hb_shape ()"><code class="function">hb_shape()</code></a> and <a class="link" href="harfbuzz-hb-shape.html#hb-shape-full" title="hb_shape_full ()"><code class="function">hb_shape_full()</code></a> expect that the buffer
+is either empty and have content type of invalid, or that buffer
+content type is <a class="link" href="harfbuzz-hb-buffer.html#HB-BUFFER-CONTENT-TYPE-UNICODE:CAPS"><code class="literal">HB_BUFFER_CONTENT_TYPE_UNICODE</code></a>, and upon
+success they set the buffer content type to
+<a class="link" href="harfbuzz-hb-buffer.html#HB-BUFFER-CONTENT-TYPE-GLYPHS:CAPS"><code class="literal">HB_BUFFER_CONTENT_TYPE_GLYPHS</code></a>.</p></li>
+</ul></div>
+<p>The above transitions are designed such that one can use a buffer
+in a loop of "reset : add-text : shape" without needing to ever
+modify the content type manually.</p>
 <div class="refsect3">
 <a name="hb-buffer-set-content-type.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
@@ -1296,7 +1417,7 @@ characters (before shaping), or contain glyphs (the result of shaping).</p>
 <div class="refsect2">
 <a name="hb-buffer-get-content-type"></a><h3>hb_buffer_get_content_type ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-content-type-t" title="enum hb_buffer_content_type_t"><span class="returnvalue">hb_buffer_content_type_t</span></a>
-hb_buffer_get_content_type (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
+hb_buffer_get_content_type (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
 <p>Fetches the type of <em class="parameter"><code>buffer</code></em>
  contents. Buffers are either empty, contain
 characters (before shaping), or contain glyphs (the result of shaping).</p>
@@ -1365,7 +1486,7 @@ direction.</p>
 <div class="refsect2">
 <a name="hb-buffer-get-direction"></a><h3>hb_buffer_get_direction ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="returnvalue">hb_direction_t</span></a>
-hb_buffer_get_direction (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
+hb_buffer_get_direction (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
 <p>See <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-set-direction" title="hb_buffer_set_direction ()"><code class="function">hb_buffer_set_direction()</code></a></p>
 <div class="refsect3">
 <a name="hb-buffer-get-direction.parameters"></a><h4>Parameters</h4>
@@ -1432,7 +1553,7 @@ corresponding script from an ISO 15924 script tag.</p>
 <div class="refsect2">
 <a name="hb-buffer-get-script"></a><h3>hb_buffer_get_script ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="returnvalue">hb_script_t</span></a>
-hb_buffer_get_script (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
+hb_buffer_get_script (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
 <p>Fetches the script of <em class="parameter"><code>buffer</code></em>
 .</p>
 <div class="refsect3">
@@ -1500,7 +1621,7 @@ different concepts and should not be confused with each other.</p>
 <div class="refsect2">
 <a name="hb-buffer-get-language"></a><h3>hb_buffer_get_language ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-language-t" title="hb_language_t"><span class="returnvalue">hb_language_t</span></a>
-hb_buffer_get_language (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
+hb_buffer_get_language (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
 <p>See <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-set-language" title="hb_buffer_set_language ()"><code class="function">hb_buffer_set_language()</code></a>.</p>
 <div class="refsect3">
 <a name="hb-buffer-get-language.parameters"></a><h4>Parameters</h4>
@@ -1561,7 +1682,7 @@ hb_buffer_set_flags (<em class="parameter"><code><a class="link" href="harfbuzz-
 <div class="refsect2">
 <a name="hb-buffer-get-flags"></a><h3>hb_buffer_get_flags ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-flags-t" title="enum hb_buffer_flags_t"><span class="returnvalue">hb_buffer_flags_t</span></a>
-hb_buffer_get_flags (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
+hb_buffer_get_flags (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
 <p>Fetches the <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-flags-t" title="enum hb_buffer_flags_t"><span class="type">hb_buffer_flags_t</span></a> of <em class="parameter"><code>buffer</code></em>
 .</p>
 <div class="refsect3">
@@ -1623,7 +1744,7 @@ during shaping.</p>
 <div class="refsect2">
 <a name="hb-buffer-get-cluster-level"></a><h3>hb_buffer_get_cluster_level ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-cluster-level-t" title="enum hb_buffer_cluster_level_t"><span class="returnvalue">hb_buffer_cluster_level_t</span></a>
-hb_buffer_get_cluster_level (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
+hb_buffer_get_cluster_level (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
 <p>Fetches the cluster level of a buffer. The <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-cluster-level-t" title="enum hb_buffer_cluster_level_t"><span class="type">hb_buffer_cluster_level_t</span></a>
 dictates one aspect of how HarfBuzz will treat non-base characters 
 during shaping.</p>
@@ -1691,7 +1812,7 @@ memory allocation succeeded, <code class="literal">false</code> otherwise.</p>
 <div class="refsect2">
 <a name="hb-buffer-get-length"></a><h3>hb_buffer_get_length ()</h3>
 <pre class="programlisting">unsigned <span class="returnvalue">int</span>
-hb_buffer_get_length (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
+hb_buffer_get_length (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
 <p>Returns the number of items in the buffer.</p>
 <div class="refsect3">
 <a name="hb-buffer-get-length.parameters"></a><h4>Parameters</h4>
@@ -1753,7 +1874,7 @@ hb_buffer_set_segment_properties (<em class="parameter"><code><a class="link" hr
 <div class="refsect2">
 <a name="hb-buffer-get-segment-properties"></a><h3>hb_buffer_get_segment_properties ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_buffer_get_segment_properties (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>,
+hb_buffer_get_segment_properties (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>,
                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-segment-properties-t" title="hb_segment_properties_t"><span class="type">hb_segment_properties_t</span></a> *props</code></em>);</pre>
 <p>Sets <em class="parameter"><code>props</code></em>
  to the <a class="link" href="harfbuzz-hb-buffer.html#hb-segment-properties-t" title="hb_segment_properties_t"><span class="type">hb_segment_properties_t</span></a> of <em class="parameter"><code>buffer</code></em>
@@ -1859,7 +1980,7 @@ hb_buffer_set_unicode_funcs (<em class="parameter"><code><a class="link" href="h
 <div class="refsect2">
 <a name="hb-buffer-get-unicode-funcs"></a><h3>hb_buffer_get_unicode_funcs ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="returnvalue">hb_unicode_funcs_t</span></a> *
-hb_buffer_get_unicode_funcs (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
+hb_buffer_get_unicode_funcs (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
 <p>Fetches the Unicode-functions structure of a buffer.</p>
 <div class="refsect3">
 <a name="hb-buffer-get-unicode-funcs.parameters"></a><h4>Parameters</h4>
@@ -1884,99 +2005,6 @@ hb_buffer_get_unicode_funcs (<em class="parameter"><code><a class="link" href="h
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-buffer-set-user-data"></a><h3>hb_buffer_set_user_data ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_buffer_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>,
-                         <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
-                         <em class="parameter"><code><span class="type">void</span> *data</code></em>,
-                         <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
-                         <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
-<p>Attaches a user-data key/data pair to the specified buffer.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
-<div class="refsect3">
-<a name="hb-buffer-set-user-data.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>buffer</p></td>
-<td class="parameter_description"><p>An <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a></p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>key</p></td>
-<td class="parameter_description"><p>The user-data key</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>data</p></td>
-<td class="parameter_description"><p>A pointer to the user data</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>replace</p></td>
-<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-</tbody>
-</table></div>
-</div>
-<div class="refsect3">
-<a name="hb-buffer-set-user-data.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-buffer-get-user-data"></a><h3>hb_buffer_get_user_data ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span> *
-hb_buffer_get_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>,
-                         <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>);</pre>
-<p>Fetches the user data associated with the specified key,
-attached to the specified buffer.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
-<div class="refsect3">
-<a name="hb-buffer-get-user-data.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>buffer</p></td>
-<td class="parameter_description"><p>An <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a></p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>key</p></td>
-<td class="parameter_description"><p>The user-data key to query</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-</tbody>
-</table></div>
-</div>
-<div class="refsect3">
-<a name="hb-buffer-get-user-data.returns"></a><h4>Returns</h4>
-<p>A pointer to the user data. </p>
-<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
 <a name="hb-buffer-get-glyph-infos"></a><h3>hb_buffer_get_glyph_infos ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-info-t" title="hb_glyph_info_t"><span class="returnvalue">hb_glyph_info_t</span></a> *
 hb_buffer_get_glyph_infos (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>,
@@ -2018,6 +2046,34 @@ The value valid as long as buffer has not been modified. </p>
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-glyph-info-get-glyph-flags"></a><h3>hb_glyph_info_get_glyph_flags ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-flags-t" title="enum hb_glyph_flags_t"><span class="returnvalue">hb_glyph_flags_t</span></a>
+hb_glyph_info_get_glyph_flags (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-info-t" title="hb_glyph_info_t"><span class="type">hb_glyph_info_t</span></a> *info</code></em>);</pre>
+<p>Returns glyph flags encoded within a <a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-info-t" title="hb_glyph_info_t"><span class="type">hb_glyph_info_t</span></a>.</p>
+<div class="refsect3">
+<a name="hb-glyph-info-get-glyph-flags.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>info</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-info-t" title="hb_glyph_info_t"><span class="type">hb_glyph_info_t</span></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-glyph-info-get-glyph-flags.returns"></a><h4>Returns</h4>
+<p>The <a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-flags-t" title="enum hb_glyph_flags_t"><span class="type">hb_glyph_flags_t</span></a> encoded within <em class="parameter"><code>info</code></em>
+</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-1-5-0.html#api-index-1.5.0">1.5.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-buffer-get-glyph-positions"></a><h3>hb_buffer_get_glyph_positions ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-position-t" title="hb_glyph_position_t"><span class="returnvalue">hb_glyph_position_t</span></a> *
 hb_buffer_get_glyph_positions (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>,
@@ -2094,34 +2150,6 @@ has position array, <code class="literal">false</code> otherwise.</p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-buffer-get-invisible-glyph"></a><h3>hb_buffer_get_invisible_glyph ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
-hb_buffer_get_invisible_glyph (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
-<p>See <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-set-invisible-glyph" title="hb_buffer_set_invisible_glyph ()"><code class="function">hb_buffer_set_invisible_glyph()</code></a>.</p>
-<div class="refsect3">
-<a name="hb-buffer-get-invisible-glyph.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody><tr>
-<td class="parameter_name"><p>buffer</p></td>
-<td class="parameter_description"><p>An <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a></p></td>
-<td class="parameter_annotations"> </td>
-</tr></tbody>
-</table></div>
-</div>
-<div class="refsect3">
-<a name="hb-buffer-get-invisible-glyph.returns"></a><h4>Returns</h4>
-<p>The <em class="parameter"><code>buffer</code></em>
-invisible <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a></p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-2-0-0.html#api-index-2.0.0">2.0.0</a></p>
-</div>
-<hr>
-<div class="refsect2">
 <a name="hb-buffer-set-invisible-glyph"></a><h3>hb_buffer_set_invisible_glyph ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
 hb_buffer_set_invisible_glyph (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>,
@@ -2156,12 +2184,12 @@ verbatim.</p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-buffer-get-not-found-glyph"></a><h3>hb_buffer_get_not_found_glyph ()</h3>
+<a name="hb-buffer-get-invisible-glyph"></a><h3>hb_buffer_get_invisible_glyph ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
-hb_buffer_get_not_found_glyph (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
-<p>See <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-set-not-found-glyph" title="hb_buffer_set_not_found_glyph ()"><code class="function">hb_buffer_set_not_found_glyph()</code></a>.</p>
+hb_buffer_get_invisible_glyph (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
+<p>See <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-set-invisible-glyph" title="hb_buffer_set_invisible_glyph ()"><code class="function">hb_buffer_set_invisible_glyph()</code></a>.</p>
 <div class="refsect3">
-<a name="hb-buffer-get-not-found-glyph.parameters"></a><h4>Parameters</h4>
+<a name="hb-buffer-get-invisible-glyph.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -2176,11 +2204,11 @@ hb_buffer_get_not_found_glyph (<em class="parameter"><code><a class="link" href=
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-buffer-get-not-found-glyph.returns"></a><h4>Returns</h4>
+<a name="hb-buffer-get-invisible-glyph.returns"></a><h4>Returns</h4>
 <p>The <em class="parameter"><code>buffer</code></em>
-not-found <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a></p>
+invisible <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a></p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-3-1-0.html#api-index-3.1.0">3.1.0</a></p>
+<p class="since">Since: <a class="link" href="api-index-2-0-0.html#api-index-2.0.0">2.0.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
@@ -2190,7 +2218,7 @@ hb_buffer_set_not_found_glyph (<em class="parameter"><code><a class="link" href=
                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> not_found</code></em>);</pre>
 <p>Sets the <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> that replaces characters not found in
 the font during shaping.</p>
-<p>The not-found glyph defaults to zero, sometimes knows as the
+<p>The not-found glyph defaults to zero, sometimes known as the
 ".notdef" glyph.  This API allows for differentiating the two.</p>
 <div class="refsect3">
 <a name="hb-buffer-set-not-found-glyph.parameters"></a><h4>Parameters</h4>
@@ -2218,6 +2246,34 @@ the font during shaping.</p>
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-buffer-get-not-found-glyph"></a><h3>hb_buffer_get_not_found_glyph ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
+hb_buffer_get_not_found_glyph (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
+<p>See <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-set-not-found-glyph" title="hb_buffer_set_not_found_glyph ()"><code class="function">hb_buffer_set_not_found_glyph()</code></a>.</p>
+<div class="refsect3">
+<a name="hb-buffer-get-not-found-glyph.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>buffer</p></td>
+<td class="parameter_description"><p>An <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-buffer-get-not-found-glyph.returns"></a><h4>Returns</h4>
+<p>The <em class="parameter"><code>buffer</code></em>
+not-found <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-3-1-0.html#api-index-3.1.0">3.1.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-buffer-set-replacement-codepoint"></a><h3>hb_buffer_set_replacement_codepoint ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
 hb_buffer_set_replacement_codepoint (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>,
@@ -2254,7 +2310,7 @@ when adding text to <em class="parameter"><code>buffer</code></em>
 <div class="refsect2">
 <a name="hb-buffer-get-replacement-codepoint"></a><h3>hb_buffer_get_replacement_codepoint ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
-hb_buffer_get_replacement_codepoint (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
+hb_buffer_get_replacement_codepoint (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>);</pre>
 <p>Fetches the <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> that replaces invalid entries for a given encoding
 when adding text to <em class="parameter"><code>buffer</code></em>
 .</p>
@@ -2451,14 +2507,14 @@ write serialized buffer into. </p></td>
 </tr>
 <tr>
 <td class="parameter_name"><p>buf_consumed</p></td>
-<td class="parameter_description"><p>if not <code class="literal">NULL</code>, will be set to the number of byes written into <em class="parameter"><code>buf</code></em>
+<td class="parameter_description"><p>if not <code class="literal">NULL</code>, will be set to the number of bytes written into <em class="parameter"><code>buf</code></em>
 . </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="NULL may be passed instead of a pointer to a location."><span class="acronym">optional</span></acronym>]</span></td>
 </tr>
 <tr>
 <td class="parameter_name"><p>font</p></td>
 <td class="parameter_description"><p>the <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> used to shape this buffer, needed to
-read glyph names and extents. If <code class="literal">NULL</code>, and empty font will be used. </p></td>
+read glyph names and extents. If <code class="literal">NULL</code>, an empty font will be used. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
 </tr>
 <tr>
@@ -2499,7 +2555,7 @@ hb_buffer_serialize_glyphs (<em class="parameter"><code><a class="link" href="ha
 useful for showing the contents of the buffer, for example during debugging.
 There are currently two supported serialization formats:</p>
 <div class="refsect3">
-<a name="id-1.3.3.3.7.53.5"></a><h4>text</h4>
+<a name="id-1.3.3.3.7.54.5"></a><h4>text</h4>
 <p>A human-readable, plain text format.
 The serialized glyphs will look something like:</p>
 <p><code class="literal">
@@ -2526,7 +2582,7 @@ The serialized glyphs will look something like:</p>
 </ul></div>
 </div>
 <div class="refsect3">
-<a name="id-1.3.3.3.7.53.6"></a><h4>json</h4>
+<a name="id-1.3.3.3.7.54.6"></a><h4>json</h4>
 <p>A machine-readable, structured format.
 The serialized glyphs will look something like:</p>
 <p><code class="literal">
@@ -2587,14 +2643,14 @@ write serialized buffer into. </p></td>
 </tr>
 <tr>
 <td class="parameter_name"><p>buf_consumed</p></td>
-<td class="parameter_description"><p>if not <code class="literal">NULL</code>, will be set to the number of byes written into <em class="parameter"><code>buf</code></em>
+<td class="parameter_description"><p>if not <code class="literal">NULL</code>, will be set to the number of bytes written into <em class="parameter"><code>buf</code></em>
 . </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="NULL may be passed instead of a pointer to a location."><span class="acronym">optional</span></acronym>]</span></td>
 </tr>
 <tr>
 <td class="parameter_name"><p>font</p></td>
 <td class="parameter_description"><p>the <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> used to shape this buffer, needed to
-read glyph names and extents. If <code class="literal">NULL</code>, and empty font will be used. </p></td>
+read glyph names and extents. If <code class="literal">NULL</code>, an empty font will be used. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
 </tr>
 <tr>
@@ -2677,8 +2733,8 @@ consumed one. </p></td>
 </div>
 <div class="refsect3">
 <a name="hb-buffer-deserialize-glyphs.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if <em class="parameter"><code>buf</code></em>
-is not fully consumed, <code class="literal">false</code> otherwise.</p>
+<p> <code class="literal">true</code> if parse was successful, <code class="literal">false</code> if an error
+occurred.</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-7.html#api-index-0.9.7">0.9.7</a></p>
 </div>
@@ -2700,7 +2756,7 @@ when the buffer contains Unicode codepoints (i.e., before shaping). This is
 useful for showing the contents of the buffer, for example during debugging.
 There are currently two supported serialization formats:</p>
 <div class="refsect3">
-<a name="id-1.3.3.3.7.55.5"></a><h4>text</h4>
+<a name="id-1.3.3.3.7.56.5"></a><h4>text</h4>
 <p>A human-readable, plain text format.
 The serialized codepoints will look something like:</p>
 <p><code class="literal">
@@ -2715,7 +2771,7 @@ will be indicated with a <code class="literal">=</code> then <a class="link" hre
 </ul></div>
 </div>
 <div class="refsect3">
-<a name="id-1.3.3.3.7.55.6"></a><h4>json</h4>
+<a name="id-1.3.3.3.7.56.6"></a><h4>json</h4>
 <p>A machine-readable, structured format.
 The serialized codepoints will be a list of objects with the following
 properties:</p>
@@ -2769,7 +2825,7 @@ write serialized buffer into. </p></td>
 </tr>
 <tr>
 <td class="parameter_name"><p>buf_consumed</p></td>
-<td class="parameter_description"><p>if not <code class="literal">NULL</code>, will be set to the number of byes written into <em class="parameter"><code>buf</code></em>
+<td class="parameter_description"><p>if not <code class="literal">NULL</code>, will be set to the number of bytes written into <em class="parameter"><code>buf</code></em>
 . </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="NULL may be passed instead of a pointer to a location."><span class="acronym">optional</span></acronym>]</span></td>
 </tr>
@@ -2847,8 +2903,8 @@ consumed one. </p></td>
 </div>
 <div class="refsect3">
 <a name="hb-buffer-deserialize-unicode.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if <em class="parameter"><code>buf</code></em>
-is not fully consumed, <code class="literal">false</code> otherwise.</p>
+<p> <code class="literal">true</code> if parse was successful, <code class="literal">false</code> if an error
+occurred.</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-2-7-3.html#api-index-2.7.3">2.7.3</a></p>
 </div>
@@ -3083,7 +3139,7 @@ callers if just comparing two buffers is needed.</p>
 </tr>
 <tr>
 <td class="parameter_name"><p>dottedcircle_glyph</p></td>
-<td class="parameter_description"><p>glyph id of U+25CC DOTTED CIRCLE, or (hb_codepont_t) -1.</p></td>
+<td class="parameter_description"><p>glyph id of U+25CC DOTTED CIRCLE, or (hb_codepoint_t) -1.</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
@@ -3098,79 +3154,6 @@ callers if just comparing two buffers is needed.</p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-buffer-set-message-func"></a><h3>hb_buffer_set_message_func ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_buffer_set_message_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>,
-                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-message-func-t" title="hb_buffer_message_func_t ()"><span class="type">hb_buffer_message_func_t</span></a> func</code></em>,
-                            <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-message-func-t" title="hb_buffer_message_func_t ()"><span class="type">hb_buffer_message_func_t</span></a>.</p>
-<div class="refsect3">
-<a name="hb-buffer-set-message-func.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>buffer</p></td>
-<td class="parameter_description"><p>An <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a></p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>func</p></td>
-<td class="parameter_description"><p>Callback function. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
-. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
-</tr>
-</tbody>
-</table></div>
-</div>
-<p class="since">Since: <a class="link" href="api-index-1-1-3.html#api-index-1.1.3">1.1.3</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-glyph-info-get-glyph-flags"></a><h3>hb_glyph_info_get_glyph_flags ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-flags-t" title="enum hb_glyph_flags_t"><span class="returnvalue">hb_glyph_flags_t</span></a>
-hb_glyph_info_get_glyph_flags (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-info-t" title="hb_glyph_info_t"><span class="type">hb_glyph_info_t</span></a> *info</code></em>);</pre>
-<p>Returns glyph flags encoded within a <a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-info-t" title="hb_glyph_info_t"><span class="type">hb_glyph_info_t</span></a>.</p>
-<div class="refsect3">
-<a name="hb-glyph-info-get-glyph-flags.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody><tr>
-<td class="parameter_name"><p>info</p></td>
-<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-info-t" title="hb_glyph_info_t"><span class="type">hb_glyph_info_t</span></a></p></td>
-<td class="parameter_annotations"> </td>
-</tr></tbody>
-</table></div>
-</div>
-<div class="refsect3">
-<a name="hb-glyph-info-get-glyph-flags.returns"></a><h4>Returns</h4>
-<p>The <a class="link" href="harfbuzz-hb-buffer.html#hb-glyph-flags-t" title="enum hb_glyph_flags_t"><span class="type">hb_glyph_flags_t</span></a> encoded within <em class="parameter"><code>info</code></em>
-</p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-1-5-0.html#api-index-1.5.0">1.5.0</a></p>
-</div>
-<hr>
-<div class="refsect2">
 <a name="hb-buffer-message-func-t"></a><h3>hb_buffer_message_func_t ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 <span class="c_punctuation">(</span>*hb_buffer_message_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>,
@@ -3221,6 +3204,51 @@ is shaped with</p></td>
 </div>
 <p class="since">Since: <a class="link" href="api-index-1-1-3.html#api-index-1.1.3">1.1.3</a></p>
 </div>
+<hr>
+<div class="refsect2">
+<a name="hb-buffer-set-message-func"></a><h3>hb_buffer_set_message_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_buffer_set_message_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>,
+                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-message-func-t" title="hb_buffer_message_func_t ()"><span class="type">hb_buffer_message_func_t</span></a> func</code></em>,
+                            <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-message-func-t" title="hb_buffer_message_func_t ()"><span class="type">hb_buffer_message_func_t</span></a>.</p>
+<div class="refsect3">
+<a name="hb-buffer-set-message-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>buffer</p></td>
+<td class="parameter_description"><p>An <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>Callback function. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-1-1-3.html#api-index-1.1.3">1.1.3</a></p>
+</div>
 </div>
 <div class="refsect1">
 <a name="harfbuzz-hb-buffer.other_details"></a><h2>Types and Values</h2>
@@ -3339,7 +3367,7 @@ allow selecting more fine-grained cluster handling.</p></td>
                                   layout, by avoiding re-shaping of each line
                                   after line-breaking, by limiting the
                                   reshaping to a small piece around the
-                                  breaking positin only, even if the breaking
+                                  breaking position only, even if the breaking
                                   position carries the
                                   <a class="link" href="harfbuzz-hb-buffer.html#HB-GLYPH-FLAG-UNSAFE-TO-BREAK:CAPS"><span class="type">HB_GLYPH_FLAG_UNSAFE_TO_BREAK</span></a> or when
                                   hyphenation or other text transformation
@@ -3357,7 +3385,7 @@ allow selecting more fine-grained cluster handling.</p></td>
                                   from there, and repeat.
                                   At the start of next line a similar algorithm can
                                   be implemented. That is: 1. Iterate forward from
-                                  the line-break position untill the first cluster
+                                  the line-break position until the first cluster
                                   start position that is NOT unsafe-to-concat, 2.
                                   shape the segment from beginning of the line to
                                   that position, 3. check whether the resulting
@@ -3377,7 +3405,27 @@ allow selecting more fine-grained cluster handling.</p></td>
                                   clusters.
                                   The <a class="link" href="harfbuzz-hb-buffer.html#HB-GLYPH-FLAG-UNSAFE-TO-BREAK:CAPS"><span class="type">HB_GLYPH_FLAG_UNSAFE_TO_BREAK</span></a> flag will
                                   always imply this flag.
-                                  Since: 3.3.0</p>
+                          To use this flag, you must enable the buffer flag
+                          <em class="parameter"><code>HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT</code></em>
+ during
+                          shaping, otherwise the buffer flag will not be
+                          reliably produced.
+                                  Since: 4.0.0</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-GLYPH-FLAG-SAFE-TO-INSERT-TATWEEL:CAPS"></a>HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL</p></td>
+<td class="enum_member_description">
+<p>In scripts that use elongation (Arabic,
+                                  Mongolian, Syriac, etc.), this flag signifies
+                                  that it is safe to insert a U+0640 TATWEEL
+                                  character before this cluster for elongation.
+                                  This flag does not determine the
+                                  script-specific elongation places, but only
+                                  when it is safe to do the elongation without
+                                  interrupting text shaping.
+                                  Since: 5.1.0</p>
 </td>
 <td class="enum_member_annotations"> </td>
 </tr>
@@ -3569,6 +3617,33 @@ be modified to show the failed output. Since: 3.4.0</p>
 </td>
 <td class="enum_member_annotations"> </td>
 </tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-BUFFER-FLAG-PRODUCE-UNSAFE-TO-CONCAT:CAPS"></a>HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT</p></td>
+<td class="enum_member_description">
+<p>flag indicating that the <em class="parameter"><code>HB_GLYPH_FLAG_UNSAFE_TO_CONCAT</code></em>
+
+glyph-flag should be produced by the shaper. By default
+it will not be produced since it incurs a cost. Since: 4.0.0</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-BUFFER-FLAG-PRODUCE-SAFE-TO-INSERT-TATWEEL:CAPS"></a>HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL</p></td>
+<td class="enum_member_description">
+<p>flag indicating that the <em class="parameter"><code>HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL</code></em>
+
+glyph-flag should be produced by the shaper. By default
+it will not be produced. Since: 5.1.0</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-BUFFER-FLAG-DEFINED:CAPS"></a>HB_BUFFER_FLAG_DEFINED</p></td>
+<td class="enum_member_description">
+<p>All currently defined flags: Since: 4.4.0</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
 </tbody>
 </table></div>
 </div>
@@ -3783,6 +3858,13 @@ glyph offsets will reflect absolute glyph positions. Since: 1.8.0</p>
 </td>
 <td class="enum_member_annotations"> </td>
 </tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-BUFFER-SERIALIZE-FLAG-DEFINED:CAPS"></a>HB_BUFFER_SERIALIZE_FLAG_DEFINED</p></td>
+<td class="enum_member_description">
+<p>All currently defined flags. Since: 4.4.0</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
 </tbody>
 </table></div>
 </div>
diff --git a/docs/html/harfbuzz-hb-cairo.html b/docs/html/harfbuzz-hb-cairo.html
new file mode 100644 (file)
index 0000000..1281c3d
--- /dev/null
@@ -0,0 +1,628 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>hb-cairo: HarfBuzz Manual</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
+<link rel="home" href="index.html" title="HarfBuzz Manual">
+<link rel="up" href="integration-api.html" title="Integration API">
+<link rel="prev" href="harfbuzz-hb-directwrite.html" title="hb-directwrite">
+<link rel="next" href="style-api.html" title="Style API">
+<meta name="generator" content="GTK-Doc V1.32 (XML mode)">
+<link rel="stylesheet" href="style.css" type="text/css">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
+<td width="100%" align="left" class="shortcuts">
+<a href="#" class="shortcut">Top</a><span id="nav_description">  <span class="dim">|</span> 
+                  <a href="#harfbuzz-hb-cairo.description" class="shortcut">Description</a></span>
+</td>
+<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
+<td><a accesskey="u" href="integration-api.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
+<td><a accesskey="p" href="harfbuzz-hb-directwrite.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="style-api.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+</tr></table>
+<div class="refentry">
+<a name="harfbuzz-hb-cairo"></a><div class="titlepage"></div>
+<div class="refnamediv"><table width="100%"><tr>
+<td valign="top">
+<h2><span class="refentrytitle"><a name="harfbuzz-hb-cairo.top_of_page"></a>hb-cairo</span></h2>
+<p>hb-cairo — Cairo integration</p>
+</td>
+<td class="gallery_image" valign="top" align="right"></td>
+</tr></table></div>
+<div class="refsect1">
+<a name="harfbuzz-hb-cairo.functions"></a><h2>Functions</h2>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="functions_proto_type">
+<col class="functions_proto_name">
+</colgroup>
+<tbody>
+<tr>
+<td class="function_type">
+<span class="returnvalue">cairo_font_face_t</span> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-create-for-font" title="hb_cairo_font_face_create_for_font ()">hb_cairo_font_face_create_for_font</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="returnvalue">hb_font_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-get-font" title="hb_cairo_font_face_get_font ()">hb_cairo_font_face_get_font</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">cairo_font_face_t</span> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-create-for-face" title="hb_cairo_font_face_create_for_face ()">hb_cairo_font_face_create_for_face</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-get-face" title="hb_cairo_font_face_get_face ()">hb_cairo_font_face_get_face</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="returnvalue">hb_font_t</span></a> *
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-init-func-t" title="hb_cairo_font_init_func_t ()">*hb_cairo_font_init_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-set-font-init-func" title="hb_cairo_font_face_set_font_init_func ()">hb_cairo_font_face_set_font_init_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="returnvalue">hb_font_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-scaled-font-get-font" title="hb_cairo_scaled_font_get_font ()">hb_cairo_scaled_font_get_font</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-set-scale-factor" title="hb_cairo_font_face_set_scale_factor ()">hb_cairo_font_face_set_scale_factor</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">unsigned <span class="returnvalue">int</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-get-scale-factor" title="hb_cairo_font_face_get_scale_factor ()">hb_cairo_font_face_get_scale_factor</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-glyphs-from-buffer" title="hb_cairo_glyphs_from_buffer ()">hb_cairo_glyphs_from_buffer</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect1">
+<a name="harfbuzz-hb-cairo.includes"></a><h2>Includes</h2>
+<pre class="synopsis">#include &lt;hb-cairo.h&gt;
+</pre>
+</div>
+<div class="refsect1">
+<a name="harfbuzz-hb-cairo.description"></a><h2>Description</h2>
+<p>Functions for using HarfBuzz with the cairo library.</p>
+<p>HarfBuzz supports using cairo for rendering.</p>
+</div>
+<div class="refsect1">
+<a name="harfbuzz-hb-cairo.functions_details"></a><h2>Functions</h2>
+<div class="refsect2">
+<a name="hb-cairo-font-face-create-for-font"></a><h3>hb_cairo_font_face_create_for_font ()</h3>
+<pre class="programlisting"><span class="returnvalue">cairo_font_face_t</span> *
+hb_cairo_font_face_create_for_font (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
+<p>Creates a <span class="type">cairo_font_face_t</span> for rendering text according
+to <em class="parameter"><code>font</code></em>
+.</p>
+<p>Note that the scale of <em class="parameter"><code>font</code></em>
+ does not affect the rendering,
+but the variations and slant that are set on <em class="parameter"><code>font</code></em>
+ do.</p>
+<div class="refsect3">
+<a name="hb-cairo-font-face-create-for-font.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-cairo-font-face-create-for-font.returns"></a><h4>Returns</h4>
+<p>a newly created <span class="type">cairo_font_face_t</span>. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-cairo-font-face-get-font"></a><h3>hb_cairo_font_face_get_font ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="returnvalue">hb_font_t</span></a> *
+hb_cairo_font_face_get_font (<em class="parameter"><code><span class="type">cairo_font_face_t</span> *font_face</code></em>);</pre>
+<p>Gets the <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> that <em class="parameter"><code>font_face</code></em>
+ was created from.</p>
+<div class="refsect3">
+<a name="hb-cairo-font-face-get-font.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>font_face</p></td>
+<td class="parameter_description"><p>a <span class="type">cairo_font_face_t</span></p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-cairo-font-face-get-font.returns"></a><h4>Returns</h4>
+<p>the <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> that <em class="parameter"><code>font_face</code></em>
+was created from. </p>
+<p><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>][<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-cairo-font-face-create-for-face"></a><h3>hb_cairo_font_face_create_for_face ()</h3>
+<pre class="programlisting"><span class="returnvalue">cairo_font_face_t</span> *
+hb_cairo_font_face_create_for_face (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
+<p>Creates a <span class="type">cairo_font_face_t</span> for rendering text according
+to <em class="parameter"><code>face</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-cairo-font-face-create-for-face.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>face</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-cairo-font-face-create-for-face.returns"></a><h4>Returns</h4>
+<p>a newly created <span class="type">cairo_font_face_t</span>. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-cairo-font-face-get-face"></a><h3>hb_cairo_font_face_get_face ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
+hb_cairo_font_face_get_face (<em class="parameter"><code><span class="type">cairo_font_face_t</span> *font_face</code></em>);</pre>
+<p>Gets the <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> associated with <em class="parameter"><code>font_face</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-cairo-font-face-get-face.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>font_face</p></td>
+<td class="parameter_description"><p>a <span class="type">cairo_font_face_t</span></p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-cairo-font-face-get-face.returns"></a><h4>Returns</h4>
+<p>the <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> associated with <em class="parameter"><code>font_face</code></em>
+. </p>
+<p><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>][<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-cairo-font-init-func-t"></a><h3>hb_cairo_font_init_func_t ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="returnvalue">hb_font_t</span></a> *
+<span class="c_punctuation">(</span>*hb_cairo_font_init_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                              <em class="parameter"><code><span class="type">cairo_scaled_font_t</span> *scaled_font</code></em>,
+                              <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>The type of a virtual method to be called when a cairo
+face created using <a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-create-for-face" title="hb_cairo_font_face_create_for_face ()"><code class="function">hb_cairo_font_face_create_for_face()</code></a>
+creates an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> for a <span class="type">cairo_scaled_font_t</span>.</p>
+<div class="refsect3">
+<a name="hb-cairo-font-init-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> being created</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>scaled_font</p></td>
+<td class="parameter_description"><p>The respective <span class="type">cairo_scaled_font_t</span></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data accompanying this method</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-cairo-font-init-func-t.returns"></a><h4>Returns</h4>
+<p> the <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> value to use; in most cases same as <em class="parameter"><code>font</code></em>
+</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-cairo-font-face-set-font-init-func"></a><h3>hb_cairo_font_face_set_font_init_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_cairo_font_face_set_font_init_func (<em class="parameter"><code><span class="type">cairo_font_face_t</span> *font_face</code></em>,
+                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-init-func-t" title="hb_cairo_font_init_func_t ()"><span class="type">hb_cairo_font_init_func_t</span></a> func</code></em>,
+                                       <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Set the virtual method to be called when a cairo
+face created using <a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-create-for-face" title="hb_cairo_font_face_create_for_face ()"><code class="function">hb_cairo_font_face_create_for_face()</code></a>
+creates an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> for a <span class="type">cairo_scaled_font_t</span>.</p>
+<div class="refsect3">
+<a name="hb-cairo-font-face-set-font-init-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>font_face</p></td>
+<td class="parameter_description"><p>a <span class="type">cairo_font_face_t</span></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The virtual method to use</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>user data accompanying the method</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-cairo-scaled-font-get-font"></a><h3>hb_cairo_scaled_font_get_font ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="returnvalue">hb_font_t</span></a> *
+hb_cairo_scaled_font_get_font (<em class="parameter"><code><span class="type">cairo_scaled_font_t</span> *scaled_font</code></em>);</pre>
+<p>Gets the <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> associated with <em class="parameter"><code>scaled_font</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-cairo-scaled-font-get-font.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>scaled_font</p></td>
+<td class="parameter_description"><p>a <span class="type">cairo_scaled_font_t</span></p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-cairo-scaled-font-get-font.returns"></a><h4>Returns</h4>
+<p>the <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> associated with <em class="parameter"><code>scaled_font</code></em>
+. </p>
+<p><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>][<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-cairo-font-face-set-scale-factor"></a><h3>hb_cairo_font_face_set_scale_factor ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_cairo_font_face_set_scale_factor (<em class="parameter"><code><span class="type">cairo_font_face_t</span> *font_face</code></em>,
+                                     <em class="parameter"><code>unsigned <span class="type">int</span> scale_factor</code></em>);</pre>
+<p>Sets the scale factor of the <em class="parameter"><code>font_face</code></em>
+. Default scale
+factor is zero.</p>
+<p>When a <span class="type">cairo_font_face_t</span> is created from a <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> using
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-create-for-face" title="hb_cairo_font_face_create_for_face ()"><code class="function">hb_cairo_font_face_create_for_face()</code></a>, such face will create
+<a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> objects during scaled-font creation.  The scale
+factor defines how the scale set on such <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> objects
+relates to the font-matrix (as such font size) of the cairo
+scaled-font.</p>
+<p>If the scale-factor is zero (default), then the scale of the
+<a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object will be left at default, which is the UPEM
+value of the respective <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a>.</p>
+<p>If the scale-factor is set to non-zero, then the X and Y scale
+of the <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object will be respectively set to the
+<em class="parameter"><code>scale_factor</code></em>
+ times the xx and yy elements of the scale-matrix
+of the cairo scaled-font being created.</p>
+<p>When using the <a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-glyphs-from-buffer" title="hb_cairo_glyphs_from_buffer ()"><code class="function">hb_cairo_glyphs_from_buffer()</code></a> API to convert the
+HarfBuzz glyph buffer that resulted from shaping with such a <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a>,
+if the scale-factor was non-zero, you can pass it directly to
+that API as both X and Y scale factors.</p>
+<p>If the scale-factor was zero however, or the cairo face was
+created using the alternative constructor
+<a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-create-for-font" title="hb_cairo_font_face_create_for_font ()"><code class="function">hb_cairo_font_face_create_for_font()</code></a>, you need to calculate the
+correct X/Y scale-factors to pass to <a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-glyphs-from-buffer" title="hb_cairo_glyphs_from_buffer ()"><code class="function">hb_cairo_glyphs_from_buffer()</code></a>
+by dividing the <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> X/Y scale-factors by the
+cairo scaled-font's scale-matrix XX/YY components respectively
+and use those values.  Or if you know that relationship offhand
+(because you set the scale of the <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> yourself), use
+the conversion rate involved.</p>
+<div class="refsect3">
+<a name="hb-cairo-font-face-set-scale-factor.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>scale_factor</p></td>
+<td class="parameter_description"><p>The scale factor to use. See below</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>font_face</p></td>
+<td class="parameter_description"><p>a <span class="type">cairo_font_face_t</span></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-cairo-font-face-get-scale-factor"></a><h3>hb_cairo_font_face_get_scale_factor ()</h3>
+<pre class="programlisting">unsigned <span class="returnvalue">int</span>
+hb_cairo_font_face_get_scale_factor (<em class="parameter"><code><span class="type">cairo_font_face_t</span> *font_face</code></em>);</pre>
+<p>Gets the scale factor set on the <em class="parameter"><code>font_face</code></em>
+. Defaults to zero.
+See <a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-set-scale-factor" title="hb_cairo_font_face_set_scale_factor ()"><code class="function">hb_cairo_font_face_set_scale_factor()</code></a> for details.</p>
+<div class="refsect3">
+<a name="hb-cairo-font-face-get-scale-factor.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>font_face</p></td>
+<td class="parameter_description"><p>a <span class="type">cairo_font_face_t</span></p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-cairo-font-face-get-scale-factor.returns"></a><h4>Returns</h4>
+<p> the scale factor of <em class="parameter"><code>font_face</code></em>
+</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-cairo-glyphs-from-buffer"></a><h3>hb_cairo_glyphs_from_buffer ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_cairo_glyphs_from_buffer (<em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> utf8_clusters</code></em>,
+                             <em class="parameter"><code><span class="type">double</span> x_scale_factor</code></em>,
+                             <em class="parameter"><code><span class="type">double</span> y_scale_factor</code></em>,
+                             <em class="parameter"><code><span class="type">double</span> x</code></em>,
+                             <em class="parameter"><code><span class="type">double</span> y</code></em>,
+                             <em class="parameter"><code>const <span class="type">char</span> *utf8</code></em>,
+                             <em class="parameter"><code><span class="type">int</span> utf8_len</code></em>,
+                             <em class="parameter"><code><span class="type">cairo_glyph_t</span> **glyphs</code></em>,
+                             <em class="parameter"><code>unsigned <span class="type">int</span> *num_glyphs</code></em>,
+                             <em class="parameter"><code><span class="type">cairo_text_cluster_t</span> **clusters</code></em>,
+                             <em class="parameter"><code>unsigned <span class="type">int</span> *num_clusters</code></em>,
+                             <em class="parameter"><code><span class="type">cairo_text_cluster_flags_t</span> *cluster_flags</code></em>);</pre>
+<p>Extracts information from <em class="parameter"><code>buffer</code></em>
+ in a form that can be
+passed to <code class="function">cairo_show_text_glyphs()</code> or <code class="function">cairo_show_glyphs()</code>.
+This API is modeled after <code class="function">cairo_scaled_font_text_to_glyphs()</code> and
+cairo_user_scaled_font_text_to_glyphs_func_t.</p>
+<p>The <em class="parameter"><code>num_glyphs</code></em>
+ argument should be preset to the number of glyph entries available
+in the <em class="parameter"><code>glyphs</code></em>
+ buffer. If the <em class="parameter"><code>glyphs</code></em>
+ buffer is <code class="literal">NULL</code>, the value of
+<em class="parameter"><code>num_glyphs</code></em>
+ must be zero.  If the provided glyph array is too short for
+the conversion (or for convenience), a new glyph array may be allocated
+using <code class="function">cairo_glyph_allocate()</code> and placed in <em class="parameter"><code>glyphs</code></em>
+.  Upon return,
+<em class="parameter"><code>num_glyphs</code></em>
+ should contain the number of generated glyphs.  If the value
+<em class="parameter"><code>glyphs</code></em>
+ points at has changed after the call, the caller will free the
+allocated glyph array using <code class="function">cairo_glyph_free()</code>.  The caller will also free
+the original value of <em class="parameter"><code>glyphs</code></em>
+, so this function shouldn't do so.</p>
+<p>If <em class="parameter"><code>clusters</code></em>
+ is not <code class="literal">NULL</code>, then <em class="parameter"><code>num_clusters</code></em>
+ and <em class="parameter"><code>cluster_flags</code></em>
+
+should not be either, and <em class="parameter"><code>utf8</code></em>
+ must be provided, and cluster
+mapping will be computed. The semantics of how
+cluster array allocation works is similar to the glyph array.  That is,
+if <em class="parameter"><code>clusters</code></em>
+ initially points to a non-<code class="literal">NULL</code> value, that array may be used
+as a cluster buffer, and <em class="parameter"><code>num_clusters</code></em>
+ points to the number of cluster
+entries available there.  If the provided cluster array is too short for
+the conversion (or for convenience), a new cluster array may be allocated
+using <code class="function">cairo_text_cluster_allocate()</code> and placed in <em class="parameter"><code>clusters</code></em>
+.  In this case,
+the original value of <em class="parameter"><code>clusters</code></em>
+ will still be freed by the caller.  Upon
+return, <em class="parameter"><code>num_clusters</code></em>
+ will contain the number of generated clusters.
+If the value <em class="parameter"><code>clusters</code></em>
+ points at has changed after the call, the caller
+will free the allocated cluster array using <code class="function">cairo_text_cluster_free()</code>.</p>
+<p>See <a class="link" href="harfbuzz-hb-cairo.html#hb-cairo-font-face-set-scale-factor" title="hb_cairo_font_face_set_scale_factor ()"><code class="function">hb_cairo_font_face_set_scale_factor()</code></a> for the details of
+the <em class="parameter"><code>scale_factor</code></em>
+ argument.</p>
+<p>The returned <em class="parameter"><code>glyphs</code></em>
+ vector actually has <code class="literal">@num_glyphs + 1</code> entries in
+it and the x,y values of the extra entry at the end add up the advance
+x,y of all the glyphs in the <em class="parameter"><code>buffer</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-cairo-glyphs-from-buffer.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>buffer</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> containing glyphs</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>utf8_clusters</p></td>
+<td class="parameter_description"><p><code class="literal">true</code> if <em class="parameter"><code>buffer</code></em>
+clusters are in bytes, instead of characters</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x_scale_factor</p></td>
+<td class="parameter_description"><p>scale factor to divide <a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> Y values by</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y_scale_factor</p></td>
+<td class="parameter_description"><p>scale factor to divide <a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> X values by</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x</p></td>
+<td class="parameter_description"><p>X position to place first glyph</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y</p></td>
+<td class="parameter_description"><p>Y position to place first glyph</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>utf8</p></td>
+<td class="parameter_description"><p>the text that was shaped in <em class="parameter"><code>buffer</code></em>
+. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>utf8_len</p></td>
+<td class="parameter_description"><p>the length of <em class="parameter"><code>utf8</code></em>
+in bytes</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>glyphs</p></td>
+<td class="parameter_description"><p>return location for an array of <span class="type">cairo_glyph_t</span>. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>num_glyphs</p></td>
+<td class="parameter_description"><p>return location for the length of <em class="parameter"><code>glyphs</code></em>
+. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for input and for returning results. Default is transfer full."><span class="acronym">inout</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>clusters</p></td>
+<td class="parameter_description"><p>return location for an array of cluster positions. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>num_clusters</p></td>
+<td class="parameter_description"><p>return location for the length of <em class="parameter"><code>clusters</code></em>
+. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for input and for returning results. Default is transfer full."><span class="acronym">inout</span></acronym>][<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>cluster_flags</p></td>
+<td class="parameter_description"><p>return location for cluster flags. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+</div>
+</div>
+<div class="footer">
+<hr>Generated by GTK-Doc V1.32</div>
+</body>
+</html>
\ No newline at end of file
index 2f34bbd..afd6c75 100644 (file)
@@ -7,7 +7,7 @@
 <link rel="home" href="index.html" title="HarfBuzz Manual">
 <link rel="up" href="core-api.html" title="Core API">
 <link rel="prev" href="harfbuzz-hb-buffer.html" title="hb-buffer">
-<link rel="next" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">
+<link rel="next" href="harfbuzz-hb-features.html" title="hb-features">
 <meta name="generator" content="GTK-Doc V1.32 (XML mode)">
 <link rel="stylesheet" href="style.css" type="text/css">
 </head>
@@ -20,7 +20,7 @@
 <td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
 <td><a accesskey="u" href="core-api.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
 <td><a accesskey="p" href="harfbuzz-hb-buffer.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
-<td><a accesskey="n" href="harfbuzz-hb-deprecated.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+<td><a accesskey="n" href="harfbuzz-hb-features.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
 </tr></table>
 <div class="refentry">
 <a name="harfbuzz-hb-common"></a><div class="titlepage"></div>
 </colgroup>
 <tbody>
 <tr>
+<td class="define_keyword">#define</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-common.html#HB-TAG:CAPS" title="HB_TAG()">HB_TAG</a><span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="define_keyword">#define</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-common.html#HB-UNTAG:CAPS" title="HB_UNTAG()">HB_UNTAG</a><span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
 <td class="function_type">
 <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="returnvalue">hb_tag_t</span></a>
 </td>
 </td>
 </tr>
 <tr>
-<td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="returnvalue">hb_script_t</span></a>
+<td class="define_keyword">#define</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-common.html#HB-DIRECTION-REVERSE:CAPS" title="HB_DIRECTION_REVERSE()">HB_DIRECTION_REVERSE</a><span class="c_punctuation">()</span>
 </td>
+</tr>
+<tr>
+<td class="define_keyword">#define</td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-common.html#hb-script-from-iso15924-tag" title="hb_script_from_iso15924_tag ()">hb_script_from_iso15924_tag</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-common.html#HB-DIRECTION-IS-BACKWARD:CAPS" title="HB_DIRECTION_IS_BACKWARD()">HB_DIRECTION_IS_BACKWARD</a><span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="define_keyword">#define</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-common.html#HB-DIRECTION-IS-FORWARD:CAPS" title="HB_DIRECTION_IS_FORWARD()">HB_DIRECTION_IS_FORWARD</a><span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="define_keyword">#define</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-common.html#HB-DIRECTION-IS-HORIZONTAL:CAPS" title="HB_DIRECTION_IS_HORIZONTAL()">HB_DIRECTION_IS_HORIZONTAL</a><span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="define_keyword">#define</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-common.html#HB-DIRECTION-IS-VALID:CAPS" title="HB_DIRECTION_IS_VALID()">HB_DIRECTION_IS_VALID</a><span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="define_keyword">#define</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-common.html#HB-DIRECTION-IS-VERTICAL:CAPS" title="HB_DIRECTION_IS_VERTICAL()">HB_DIRECTION_IS_VERTICAL</a><span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="returnvalue">hb_script_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-common.html#hb-script-from-string" title="hb_script_from_string ()">hb_script_from_string</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-script-from-iso15924-tag" title="hb_script_from_iso15924_tag ()">hb_script_from_iso15924_tag</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 </tr>
 <tr>
 <td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="returnvalue">hb_script_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-common.html#hb-script-from-string" title="hb_script_from_string ()">hb_script_from_string</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
 <a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="returnvalue">hb_direction_t</span></a>
 </td>
 <td class="function_name">
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
+<a class="link" href="harfbuzz-hb-common.html#hb-language-matches" title="hb_language_matches ()">hb_language_matches</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
 <a class="link" href="harfbuzz-hb-common.html#hb-feature-from-string" title="hb_feature_from_string ()">hb_feature_from_string</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()">*hb_destroy_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
-<tr>
-<td class="define_keyword">#define</td>
-<td class="function_name">
-<a class="link" href="harfbuzz-hb-common.html#HB-TAG:CAPS" title="HB_TAG()">HB_TAG</a><span class="c_punctuation">()</span>
-</td>
-</tr>
-<tr>
-<td class="define_keyword">#define</td>
-<td class="function_name">
-<a class="link" href="harfbuzz-hb-common.html#HB-UNTAG:CAPS" title="HB_UNTAG()">HB_UNTAG</a><span class="c_punctuation">()</span>
-</td>
-</tr>
-<tr>
-<td class="define_keyword">#define</td>
-<td class="function_name">
-<a class="link" href="harfbuzz-hb-common.html#HB-DIRECTION-REVERSE:CAPS" title="HB_DIRECTION_REVERSE()">HB_DIRECTION_REVERSE</a><span class="c_punctuation">()</span>
-</td>
-</tr>
-<tr>
-<td class="define_keyword">#define</td>
-<td class="function_name">
-<a class="link" href="harfbuzz-hb-common.html#HB-DIRECTION-IS-BACKWARD:CAPS" title="HB_DIRECTION_IS_BACKWARD()">HB_DIRECTION_IS_BACKWARD</a><span class="c_punctuation">()</span>
-</td>
-</tr>
-<tr>
-<td class="define_keyword">#define</td>
-<td class="function_name">
-<a class="link" href="harfbuzz-hb-common.html#HB-DIRECTION-IS-FORWARD:CAPS" title="HB_DIRECTION_IS_FORWARD()">HB_DIRECTION_IS_FORWARD</a><span class="c_punctuation">()</span>
-</td>
-</tr>
-<tr>
-<td class="define_keyword">#define</td>
-<td class="function_name">
-<a class="link" href="harfbuzz-hb-common.html#HB-DIRECTION-IS-HORIZONTAL:CAPS" title="HB_DIRECTION_IS_HORIZONTAL()">HB_DIRECTION_IS_HORIZONTAL</a><span class="c_punctuation">()</span>
-</td>
-</tr>
-<tr>
-<td class="define_keyword">#define</td>
-<td class="function_name">
-<a class="link" href="harfbuzz-hb-common.html#HB-DIRECTION-IS-VALID:CAPS" title="HB_DIRECTION_IS_VALID()">HB_DIRECTION_IS_VALID</a><span class="c_punctuation">()</span>
-</td>
-</tr>
-<tr>
-<td class="define_keyword">#define</td>
-<td class="function_name">
-<a class="link" href="harfbuzz-hb-common.html#HB-DIRECTION-IS-VERTICAL:CAPS" title="HB_DIRECTION_IS_VERTICAL()">HB_DIRECTION_IS_VERTICAL</a><span class="c_punctuation">()</span>
-</td>
-</tr>
 </tbody>
 </table></div>
 </div>
 <td class="function_name"><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t">hb_codepoint_t</a></td>
 </tr>
 <tr>
+<td class="define_keyword">#define</td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-common.html#HB-CODEPOINT-INVALID:CAPS" title="HB_CODEPOINT_INVALID">HB_CODEPOINT_INVALID</a></td>
+</tr>
+<tr>
 <td class="datatype_keyword">enum</td>
 <td class="function_name"><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t">hb_direction_t</a></td>
 </tr>
 <div class="refsect1">
 <a name="harfbuzz-hb-common.functions_details"></a><h2>Functions</h2>
 <div class="refsect2">
+<a name="HB-TAG:CAPS"></a><h3>HB_TAG()</h3>
+<pre class="programlisting">#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint32_t)(c1)&amp;0xFF)&lt;&lt;24)|(((uint32_t)(c2)&amp;0xFF)&lt;&lt;16)|(((uint32_t)(c3)&amp;0xFF)&lt;&lt;8)|((uint32_t)(c4)&amp;0xFF)))
+</pre>
+<p>Constructs an <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> from four character literals.</p>
+<div class="refsect3">
+<a name="HB-TAG.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>c1</p></td>
+<td class="parameter_description"><p>1st character of the tag</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>c2</p></td>
+<td class="parameter_description"><p>2nd character of the tag</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>c3</p></td>
+<td class="parameter_description"><p>3rd character of the tag</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>c4</p></td>
+<td class="parameter_description"><p>4th character of the tag</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+</div>
+<hr>
+<div class="refsect2">
+<a name="HB-UNTAG:CAPS"></a><h3>HB_UNTAG()</h3>
+<pre class="programlisting">#define HB_UNTAG(tag)   (uint8_t)(((tag)&gt;&gt;24)&amp;0xFF), (uint8_t)(((tag)&gt;&gt;16)&amp;0xFF), (uint8_t)(((tag)&gt;&gt;8)&amp;0xFF), (uint8_t)((tag)&amp;0xFF)
+</pre>
+<p>Extracts four character literals from an <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a>.</p>
+<div class="refsect3">
+<a name="HB-UNTAG.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>tag</p></td>
+<td class="parameter_description"><p>an <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-6-0.html#api-index-0.6.0">0.6.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-tag-from-string"></a><h3>hb_tag_from_string ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="returnvalue">hb_tag_t</span></a>
 hb_tag_from_string (<em class="parameter"><code>const <span class="type">char</span> *str</code></em>,
@@ -449,12 +523,13 @@ hb_direction_to_string (<em class="parameter"><code><a class="link" href="harfbu
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-script-from-iso15924-tag"></a><h3>hb_script_from_iso15924_tag ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="returnvalue">hb_script_t</span></a>
-hb_script_from_iso15924_tag (<em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> tag</code></em>);</pre>
-<p>Converts an ISO 15924 script tag to a corresponding <a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a>.</p>
+<a name="HB-DIRECTION-REVERSE:CAPS"></a><h3>HB_DIRECTION_REVERSE()</h3>
+<pre class="programlisting">#define HB_DIRECTION_REVERSE(dir) ((hb_direction_t) (((unsigned int) (dir)) ^ 1))
+</pre>
+<p>Reverses a text direction. Requires that the direction
+be valid.</p>
 <div class="refsect3">
-<a name="hb-script-from-iso15924-tag.parameters"></a><h4>Parameters</h4>
+<a name="HB-DIRECTION-REVERSE.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -462,54 +537,150 @@ hb_script_from_iso15924_tag (<em class="parameter"><code><a class="link" href="h
 <col width="200px" class="parameters_annotations">
 </colgroup>
 <tbody><tr>
-<td class="parameter_name"><p>tag</p></td>
-<td class="parameter_description"><p>an <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> representing an ISO 15924 tag.</p></td>
+<td class="parameter_name"><p>dir</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> to reverse</p></td>
 <td class="parameter_annotations"> </td>
 </tr></tbody>
 </table></div>
 </div>
+</div>
+<hr>
+<div class="refsect2">
+<a name="HB-DIRECTION-IS-BACKWARD:CAPS"></a><h3>HB_DIRECTION_IS_BACKWARD()</h3>
+<pre class="programlisting">#define HB_DIRECTION_IS_BACKWARD(dir) ((((unsigned int) (dir)) &amp; ~2U) == 5)
+</pre>
+<p>Tests whether a text direction moves backward (from right to left, or from
+bottom to top). Requires that the direction be valid.</p>
 <div class="refsect3">
-<a name="hb-script-from-iso15924-tag.returns"></a><h4>Returns</h4>
-<p>An <a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> corresponding to the ISO 15924 tag.</p>
+<a name="HB-DIRECTION-IS-BACKWARD.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>dir</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> to test</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-script-from-string"></a><h3>hb_script_from_string ()</h3>
+<a name="HB-DIRECTION-IS-FORWARD:CAPS"></a><h3>HB_DIRECTION_IS_FORWARD()</h3>
+<pre class="programlisting">#define HB_DIRECTION_IS_FORWARD(dir) ((((unsigned int) (dir)) &amp; ~2U) == 4)
+</pre>
+<p>Tests whether a text direction moves forward (from left to right, or from
+top to bottom). Requires that the direction be valid.</p>
+<div class="refsect3">
+<a name="HB-DIRECTION-IS-FORWARD.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>dir</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> to test</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+</div>
+<hr>
+<div class="refsect2">
+<a name="HB-DIRECTION-IS-HORIZONTAL:CAPS"></a><h3>HB_DIRECTION_IS_HORIZONTAL()</h3>
+<pre class="programlisting">#define HB_DIRECTION_IS_HORIZONTAL(dir) ((((unsigned int) (dir)) &amp; ~1U) == 4)
+</pre>
+<p>Tests whether a text direction is horizontal. Requires
+that the direction be valid.</p>
+<div class="refsect3">
+<a name="HB-DIRECTION-IS-HORIZONTAL.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>dir</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> to test</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+</div>
+<hr>
+<div class="refsect2">
+<a name="HB-DIRECTION-IS-VALID:CAPS"></a><h3>HB_DIRECTION_IS_VALID()</h3>
+<pre class="programlisting">#define HB_DIRECTION_IS_VALID(dir) ((((unsigned int) (dir)) &amp; ~3U) == 4)
+</pre>
+<p>Tests whether a text direction is valid.</p>
+<div class="refsect3">
+<a name="HB-DIRECTION-IS-VALID.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>dir</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> to test</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+</div>
+<hr>
+<div class="refsect2">
+<a name="HB-DIRECTION-IS-VERTICAL:CAPS"></a><h3>HB_DIRECTION_IS_VERTICAL()</h3>
+<pre class="programlisting">#define HB_DIRECTION_IS_VERTICAL(dir) ((((unsigned int) (dir)) &amp; ~1U) == 6)
+</pre>
+<p>Tests whether a text direction is vertical. Requires
+that the direction be valid.</p>
+<div class="refsect3">
+<a name="HB-DIRECTION-IS-VERTICAL.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>dir</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> to test</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-script-from-iso15924-tag"></a><h3>hb_script_from_iso15924_tag ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="returnvalue">hb_script_t</span></a>
-hb_script_from_string (<em class="parameter"><code>const <span class="type">char</span> *str</code></em>,
-                       <em class="parameter"><code><span class="type">int</span> len</code></em>);</pre>
-<p>Converts a string <em class="parameter"><code>str</code></em>
- representing an ISO 15924 script tag to a
-corresponding <a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a>. Shorthand for <a class="link" href="harfbuzz-hb-common.html#hb-tag-from-string" title="hb_tag_from_string ()"><code class="function">hb_tag_from_string()</code></a> then
-<a class="link" href="harfbuzz-hb-common.html#hb-script-from-iso15924-tag" title="hb_script_from_iso15924_tag ()"><code class="function">hb_script_from_iso15924_tag()</code></a>.</p>
+hb_script_from_iso15924_tag (<em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> tag</code></em>);</pre>
+<p>Converts an ISO 15924 script tag to a corresponding <a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-script-from-string.parameters"></a><h4>Parameters</h4>
+<a name="hb-script-from-iso15924-tag.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>str</p></td>
-<td class="parameter_description"><p>a string representing an
-ISO 15924 tag. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=len][<acronym title="Generics and defining elements of containers and arrays."><span class="acronym">element-type</span></acronym> uint8_t]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>len</p></td>
-<td class="parameter_description"><p>length of the <em class="parameter"><code>str</code></em>
-, or -1 if it is <code class="literal">NULL</code>-terminated.</p></td>
+<tbody><tr>
+<td class="parameter_name"><p>tag</p></td>
+<td class="parameter_description"><p>an <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> representing an ISO 15924 tag.</p></td>
 <td class="parameter_annotations"> </td>
-</tr>
-</tbody>
+</tr></tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-script-from-string.returns"></a><h4>Returns</h4>
+<a name="hb-script-from-iso15924-tag.returns"></a><h4>Returns</h4>
 <p>An <a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> corresponding to the ISO 15924 tag.</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
@@ -532,12 +703,52 @@ hb_script_to_iso15924_tag (<em class="parameter"><code><a class="link" href="har
 <td class="parameter_name"><p>script</p></td>
 <td class="parameter_description"><p>an <a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> to convert.</p></td>
 <td class="parameter_annotations"> </td>
-</tr></tbody>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-script-to-iso15924-tag.returns"></a><h4>Returns</h4>
+<p>An <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> representing an ISO 15924 script tag.</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-script-from-string"></a><h3>hb_script_from_string ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="returnvalue">hb_script_t</span></a>
+hb_script_from_string (<em class="parameter"><code>const <span class="type">char</span> *str</code></em>,
+                       <em class="parameter"><code><span class="type">int</span> len</code></em>);</pre>
+<p>Converts a string <em class="parameter"><code>str</code></em>
+ representing an ISO 15924 script tag to a
+corresponding <a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a>. Shorthand for <a class="link" href="harfbuzz-hb-common.html#hb-tag-from-string" title="hb_tag_from_string ()"><code class="function">hb_tag_from_string()</code></a> then
+<a class="link" href="harfbuzz-hb-common.html#hb-script-from-iso15924-tag" title="hb_script_from_iso15924_tag ()"><code class="function">hb_script_from_iso15924_tag()</code></a>.</p>
+<div class="refsect3">
+<a name="hb-script-from-string.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>str</p></td>
+<td class="parameter_description"><p>a string representing an
+ISO 15924 tag. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=len][<acronym title="Generics and defining elements of containers and arrays."><span class="acronym">element-type</span></acronym> uint8_t]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>len</p></td>
+<td class="parameter_description"><p>length of the <em class="parameter"><code>str</code></em>
+, or -1 if it is <code class="literal">NULL</code>-terminated.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-script-to-iso15924-tag.returns"></a><h4>Returns</h4>
-<p>An <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> representing an ISO 15924 script tag.</p>
+<a name="hb-script-from-string.returns"></a><h4>Returns</h4>
+<p>An <a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> corresponding to the ISO 15924 tag.</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
@@ -666,6 +877,43 @@ an <a class="link" href="harfbuzz-hb-common.html#hb-language-t" title="hb_langua
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-language-matches"></a><h3>hb_language_matches ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_language_matches (<em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-language-t" title="hb_language_t"><span class="type">hb_language_t</span></a> language</code></em>,
+                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-language-t" title="hb_language_t"><span class="type">hb_language_t</span></a> specific</code></em>);</pre>
+<p>Check whether a second language tag is the same or a more
+specific version of the provided language tag.  For example,
+"fa_IR.utf8" is a more specific tag for "fa" or for "fa_IR".</p>
+<div class="refsect3">
+<a name="hb-language-matches.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>language</p></td>
+<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-common.html#hb-language-t" title="hb_language_t"><span class="type">hb_language_t</span></a> to work on</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>specific</p></td>
+<td class="parameter_description"><p>Another <a class="link" href="harfbuzz-hb-common.html#hb-language-t" title="hb_language_t"><span class="type">hb_language_t</span></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-language-matches.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if languages match, <code class="literal">false</code> otherwise.</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-5-0-0.html#api-index-5.0.0">5.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-feature-from-string"></a><h3>hb_feature_from_string ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 hb_feature_from_string (<em class="parameter"><code>const <span class="type">char</span> *str</code></em>,
@@ -961,7 +1209,7 @@ allocating big enough size for <em class="parameter"><code>buf</code></em>
 <tr>
 <td class="parameter_name"><p>buf</p></td>
 <td class="parameter_description"><p>output string. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=size][<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=size][<acronym title="Out parameter, where caller must allocate storage."><span class="acronym">out caller-allocates</span></acronym>]</span></td>
 </tr>
 <tr>
 <td class="parameter_name"><p>size</p></td>
@@ -996,205 +1244,6 @@ allocating big enough size for <em class="parameter"><code>buf</code></em>
 </table></div>
 </div>
 </div>
-<hr>
-<div class="refsect2">
-<a name="HB-TAG:CAPS"></a><h3>HB_TAG()</h3>
-<pre class="programlisting">#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint32_t)(c1)&amp;0xFF)&lt;&lt;24)|(((uint32_t)(c2)&amp;0xFF)&lt;&lt;16)|(((uint32_t)(c3)&amp;0xFF)&lt;&lt;8)|((uint32_t)(c4)&amp;0xFF)))
-</pre>
-<p>Constructs an <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> from four character literals.</p>
-<div class="refsect3">
-<a name="HB-TAG.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>c1</p></td>
-<td class="parameter_description"><p>1st character of the tag</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>c2</p></td>
-<td class="parameter_description"><p>2nd character of the tag</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>c3</p></td>
-<td class="parameter_description"><p>3rd character of the tag</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>c4</p></td>
-<td class="parameter_description"><p>4th character of the tag</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-</tbody>
-</table></div>
-</div>
-</div>
-<hr>
-<div class="refsect2">
-<a name="HB-UNTAG:CAPS"></a><h3>HB_UNTAG()</h3>
-<pre class="programlisting">#define HB_UNTAG(tag)   (uint8_t)(((tag)&gt;&gt;24)&amp;0xFF), (uint8_t)(((tag)&gt;&gt;16)&amp;0xFF), (uint8_t)(((tag)&gt;&gt;8)&amp;0xFF), (uint8_t)((tag)&amp;0xFF)
-</pre>
-<p>Extracts four character literals from an <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a>.</p>
-<div class="refsect3">
-<a name="HB-UNTAG.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody><tr>
-<td class="parameter_name"><p>tag</p></td>
-<td class="parameter_description"><p>an <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a></p></td>
-<td class="parameter_annotations"> </td>
-</tr></tbody>
-</table></div>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-6-0.html#api-index-0.6.0">0.6.0</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="HB-DIRECTION-REVERSE:CAPS"></a><h3>HB_DIRECTION_REVERSE()</h3>
-<pre class="programlisting">#define HB_DIRECTION_REVERSE(dir) ((hb_direction_t) (((unsigned int) (dir)) ^ 1))
-</pre>
-<p>Reverses a text direction. Requires that the direction
-be valid.</p>
-<div class="refsect3">
-<a name="HB-DIRECTION-REVERSE.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody><tr>
-<td class="parameter_name"><p>dir</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> to reverse</p></td>
-<td class="parameter_annotations"> </td>
-</tr></tbody>
-</table></div>
-</div>
-</div>
-<hr>
-<div class="refsect2">
-<a name="HB-DIRECTION-IS-BACKWARD:CAPS"></a><h3>HB_DIRECTION_IS_BACKWARD()</h3>
-<pre class="programlisting">#define HB_DIRECTION_IS_BACKWARD(dir) ((((unsigned int) (dir)) &amp; ~2U) == 5)
-</pre>
-<p>Tests whether a text direction moves backward (from right to left, or from
-bottom to top). Requires that the direction be valid.</p>
-<div class="refsect3">
-<a name="HB-DIRECTION-IS-BACKWARD.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody><tr>
-<td class="parameter_name"><p>dir</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> to test</p></td>
-<td class="parameter_annotations"> </td>
-</tr></tbody>
-</table></div>
-</div>
-</div>
-<hr>
-<div class="refsect2">
-<a name="HB-DIRECTION-IS-FORWARD:CAPS"></a><h3>HB_DIRECTION_IS_FORWARD()</h3>
-<pre class="programlisting">#define HB_DIRECTION_IS_FORWARD(dir) ((((unsigned int) (dir)) &amp; ~2U) == 4)
-</pre>
-<p>Tests whether a text direction moves forward (from left to right, or from
-top to bottom). Requires that the direction be valid.</p>
-<div class="refsect3">
-<a name="HB-DIRECTION-IS-FORWARD.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody><tr>
-<td class="parameter_name"><p>dir</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> to test</p></td>
-<td class="parameter_annotations"> </td>
-</tr></tbody>
-</table></div>
-</div>
-</div>
-<hr>
-<div class="refsect2">
-<a name="HB-DIRECTION-IS-HORIZONTAL:CAPS"></a><h3>HB_DIRECTION_IS_HORIZONTAL()</h3>
-<pre class="programlisting">#define HB_DIRECTION_IS_HORIZONTAL(dir) ((((unsigned int) (dir)) &amp; ~1U) == 4)
-</pre>
-<p>Tests whether a text direction is horizontal. Requires
-that the direction be valid.</p>
-<div class="refsect3">
-<a name="HB-DIRECTION-IS-HORIZONTAL.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody><tr>
-<td class="parameter_name"><p>dir</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> to test</p></td>
-<td class="parameter_annotations"> </td>
-</tr></tbody>
-</table></div>
-</div>
-</div>
-<hr>
-<div class="refsect2">
-<a name="HB-DIRECTION-IS-VALID:CAPS"></a><h3>HB_DIRECTION_IS_VALID()</h3>
-<pre class="programlisting">#define HB_DIRECTION_IS_VALID(dir) ((((unsigned int) (dir)) &amp; ~3U) == 4)
-</pre>
-<p>Tests whether a text direction is valid.</p>
-<div class="refsect3">
-<a name="HB-DIRECTION-IS-VALID.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody><tr>
-<td class="parameter_name"><p>dir</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> to test</p></td>
-<td class="parameter_annotations"> </td>
-</tr></tbody>
-</table></div>
-</div>
-</div>
-<hr>
-<div class="refsect2">
-<a name="HB-DIRECTION-IS-VERTICAL:CAPS"></a><h3>HB_DIRECTION_IS_VERTICAL()</h3>
-<pre class="programlisting">#define HB_DIRECTION_IS_VERTICAL(dir) ((((unsigned int) (dir)) &amp; ~1U) == 6)
-</pre>
-<p>Tests whether a text direction is vertical. Requires
-that the direction be valid.</p>
-<div class="refsect3">
-<a name="HB-DIRECTION-IS-VERTICAL.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody><tr>
-<td class="parameter_name"><p>dir</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> to test</p></td>
-<td class="parameter_annotations"> </td>
-</tr></tbody>
-</table></div>
-</div>
-</div>
 </div>
 <div class="refsect1">
 <a name="harfbuzz-hb-common.other_details"></a><h2>Types and Values</h2>
@@ -1214,6 +1263,14 @@ used to hold glyph IDs.</p>
 </div>
 <hr>
 <div class="refsect2">
+<a name="HB-CODEPOINT-INVALID:CAPS"></a><h3>HB_CODEPOINT_INVALID</h3>
+<pre class="programlisting">#define HB_CODEPOINT_INVALID ((hb_codepoint_t) -1)
+</pre>
+<p>Unused <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> value.</p>
+<p class="since">Since: <a class="link" href="api-index-8-0-0.html#api-index-8.0.0">8.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-direction-t"></a><h3>enum hb_direction_t</h3>
 <p>The direction of a text segment or buffer.</p>
 <p>A segment can also be tested for horizontal or vertical
@@ -2548,6 +2605,20 @@ to the four-letter values defined by <a class="ulink" href="https://unicode.org/
 <td class="enum_member_annotations"> </td>
 </tr>
 <tr>
+<td class="enum_member_name"><p><a name="HB-SCRIPT-KAWI:CAPS"></a>HB_SCRIPT_KAWI</p></td>
+<td class="enum_member_description">
+<p><code class="literal">Kawi</code>, Since: 5.2.0</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-SCRIPT-NAG-MUNDARI:CAPS"></a>HB_SCRIPT_NAG_MUNDARI</p></td>
+<td class="enum_member_description">
+<p><code class="literal">Nagm</code>, Since: 5.2.0</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
 <td class="enum_member_name"><p><a name="HB-SCRIPT-INVALID:CAPS"></a>HB_SCRIPT_INVALID</p></td>
 <td class="enum_member_description">
 <p>No script set</p>
index 2564146..281902a 100644 (file)
@@ -6,7 +6,7 @@
 <meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
 <link rel="home" href="index.html" title="HarfBuzz Manual">
 <link rel="up" href="core-api.html" title="Core API">
-<link rel="prev" href="harfbuzz-hb-common.html" title="hb-common">
+<link rel="prev" href="harfbuzz-hb-paint.html" title="hb-paint">
 <link rel="next" href="harfbuzz-hb-face.html" title="hb-face">
 <meta name="generator" content="GTK-Doc V1.32 (XML mode)">
 <link rel="stylesheet" href="style.css" type="text/css">
@@ -19,7 +19,7 @@
 </td>
 <td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
 <td><a accesskey="u" href="core-api.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
-<td><a accesskey="p" href="harfbuzz-hb-common.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="p" href="harfbuzz-hb-paint.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
 <td><a accesskey="n" href="harfbuzz-hb-face.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
 </tr></table>
 <div class="refentry">
 <tbody>
 <tr>
 <td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-font-funcs-set-glyph-func" title="hb_font_funcs_set_glyph_func ()">hb_font_funcs_set_glyph_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-layout-table-choose-script" title="hb_ot_layout_table_choose_script ()">hb_ot_layout_table_choose_script</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
 <a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-layout-table-find-script" title="hb_ot_layout_table_find_script ()">hb_ot_layout_table_find_script</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="returnvalue">hb_tag_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-tag-from-language" title="hb_ot_tag_from_language ()">hb_ot_tag_from_language</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-tags-from-script" title="hb_ot_tags_from_script ()">hb_ot_tags_from_script</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-var-find-axis" title="hb_ot_var_find_axis ()">hb_ot_var_find_axis</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">unsigned <span class="returnvalue">int</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-var-get-axes" title="hb_ot_var_get_axes ()">hb_ot_var_get_axes</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
 <td class="function_type">unsigned <span class="returnvalue">int</span>
 </td>
 <td class="function_name">
 </tr>
 <tr>
 <td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-font-get-glyph-shape" title="hb_font_get_glyph_shape ()">hb_font_get_glyph_shape</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-deprecated.html#hb-font-get-glyph-shape-func-t" title="hb_font_get_glyph_shape_func_t ()">*hb_font_get_glyph_shape_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-deprecated.html#hb-font-funcs-set-glyph-shape-func" title="hb_font_funcs_set_glyph_shape_func ()">hb_font_funcs_set_glyph_shape_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
 <a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
 </td>
 <td class="function_name">
 <td class="function_name"><a class="link" href="harfbuzz-hb-deprecated.html#HB-UNICODE-MAX-DECOMPOSITION-LEN:CAPS" title="HB_UNICODE_MAX_DECOMPOSITION_LEN">HB_UNICODE_MAX_DECOMPOSITION_LEN</a></td>
 </tr>
 <tr>
+<td class="define_keyword">#define</td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-deprecated.html#HB-UNICODE-COMBINING-CLASS-CCC133:CAPS" title="HB_UNICODE_COMBINING_CLASS_CCC133">HB_UNICODE_COMBINING_CLASS_CCC133</a></td>
+</tr>
+<tr>
 <td class="typedef_keyword">typedef</td>
 <td class="function_name"><a class="link" href="harfbuzz-hb-deprecated.html#hb-font-get-glyph-v-kerning-func-t" title="hb_font_get_glyph_v_kerning_func_t">hb_font_get_glyph_v_kerning_func_t</a></td>
 </tr>
@@ -178,6 +253,53 @@ were deemed unnecessary.</p>
 <div class="refsect1">
 <a name="harfbuzz-hb-deprecated.functions_details"></a><h2>Functions</h2>
 <div class="refsect2">
+<a name="hb-font-funcs-set-glyph-func"></a><h3>hb_font_funcs_set_glyph_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_funcs_set_glyph_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-deprecated.html#hb-font-get-glyph-func-t" title="hb_font_get_glyph_func_t ()"><span class="type">hb_font_get_glyph_func_t</span></a> func</code></em>,
+                              <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<div class="warning"><p><code class="literal">hb_font_funcs_set_glyph_func</code> has been deprecated since version 1.2.3 and should not be used in newly-written code.</p></div>
+<p>Deprecated.  Use <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-nominal-glyph-func" title="hb_font_funcs_set_nominal_glyph_func ()"><code class="function">hb_font_funcs_set_nominal_glyph_func()</code></a> and
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-variation-glyph-func" title="hb_font_funcs_set_variation_glyph_func ()"><code class="function">hb_font_funcs_set_variation_glyph_func()</code></a> instead.</p>
+<div class="refsect3">
+<a name="hb-font-funcs-set-glyph-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>The font-functions structure</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>callback function. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-font-get-glyph-func-t"></a><h3>hb_font_get_glyph_func_t ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 <span class="c_punctuation">(</span>*hb_font_get_glyph_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
@@ -240,6 +362,55 @@ user data pointer</p></td>
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-ot-layout-table-choose-script"></a><h3>hb_ot_layout_table_choose_script ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_ot_layout_table_choose_script (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
+                                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> table_tag</code></em>,
+                                  <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> *script_tags</code></em>,
+                                  <em class="parameter"><code>unsigned <span class="type">int</span> *script_index</code></em>,
+                                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> *chosen_script</code></em>);</pre>
+<div class="warning"><p><code class="literal">hb_ot_layout_table_choose_script</code> is deprecated and should not be used in newly-written code.</p></div>
+<p>Deprecated since 2.0.0</p>
+<div class="refsect3">
+<a name="hb-ot-layout-table-choose-script.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>face</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> to work upon</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>table_tag</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-ot-layout.html#HB-OT-TAG-GSUB:CAPS" title="HB_OT_TAG_GSUB"><span class="type">HB_OT_TAG_GSUB</span></a> or <a class="link" href="harfbuzz-hb-ot-layout.html#HB-OT-TAG-GPOS:CAPS" title="HB_OT_TAG_GPOS"><span class="type">HB_OT_TAG_GPOS</span></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>script_tags</p></td>
+<td class="parameter_description"><p>Array of <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> script tags</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>script_index</p></td>
+<td class="parameter_description"><p>The index of the chosen script. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>chosen_script</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> of the chosen script. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-ot-layout-table-find-script"></a><h3>hb_ot_layout_table_find_script ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 hb_ot_layout_table_find_script (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
@@ -287,6 +458,171 @@ or GPOS table.</p>
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-ot-tag-from-language"></a><h3>hb_ot_tag_from_language ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="returnvalue">hb_tag_t</span></a>
+hb_ot_tag_from_language (<em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-language-t" title="hb_language_t"><span class="type">hb_language_t</span></a> language</code></em>);</pre>
+<div class="warning">
+<p><code class="literal">hb_ot_tag_from_language</code> has been deprecated since version 2.0.0 and should not be used in newly-written code.</p>
+<p>use <a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-tags-from-script-and-language" title="hb_ot_tags_from_script_and_language ()"><code class="function">hb_ot_tags_from_script_and_language()</code></a> instead</p>
+</div>
+<p>Converts an <a class="link" href="harfbuzz-hb-common.html#hb-language-t" title="hb_language_t"><span class="type">hb_language_t</span></a> to an <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a>.</p>
+<div class="refsect3">
+<a name="hb-ot-tag-from-language.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>language</p></td>
+<td class="parameter_description"><p>an <a class="link" href="harfbuzz-hb-common.html#hb-language-t" title="hb_language_t"><span class="type">hb_language_t</span></a> to convert.</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-6-0.html#api-index-0.6.0">0.6.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-ot-tags-from-script"></a><h3>hb_ot_tags_from_script ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_ot_tags_from_script (<em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> script</code></em>,
+                        <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> *script_tag_1</code></em>,
+                        <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> *script_tag_2</code></em>);</pre>
+<div class="warning">
+<p><code class="literal">hb_ot_tags_from_script</code> has been deprecated since version 2.0.0 and should not be used in newly-written code.</p>
+<p>use <a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-tags-from-script-and-language" title="hb_ot_tags_from_script_and_language ()"><code class="function">hb_ot_tags_from_script_and_language()</code></a> instead</p>
+</div>
+<p>Converts an <a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> to script tags.</p>
+<div class="refsect3">
+<a name="hb-ot-tags-from-script.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>script</p></td>
+<td class="parameter_description"><p>an <a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> to convert.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>script_tag_1</p></td>
+<td class="parameter_description"><p>output <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a>. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>script_tag_2</p></td>
+<td class="parameter_description"><p>output <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a>. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-6-0.html#api-index-0.6.0">0.6.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-ot-var-find-axis"></a><h3>hb_ot_var_find_axis ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_ot_var_find_axis (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
+                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> axis_tag</code></em>,
+                     <em class="parameter"><code>unsigned <span class="type">int</span> *axis_index</code></em>,
+                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-var-axis-t" title="hb_ot_var_axis_t"><span class="type">hb_ot_var_axis_t</span></a> *axis_info</code></em>);</pre>
+<div class="warning">
+<p><code class="literal">hb_ot_var_find_axis</code> has been deprecated since version 2.2.0 and should not be used in newly-written code.</p>
+<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>use <a class="link" href="harfbuzz-hb-ot-var.html#hb-ot-var-find-axis-info" title="hb_ot_var_find_axis_info ()"><code class="function">hb_ot_var_find_axis_info()</code></a> instead</p></li></ul></div>
+</div>
+<p>Fetches the variation-axis information corresponding to the specified axis tag
+in the specified face.</p>
+<div class="refsect3">
+<a name="hb-ot-var-find-axis.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>face</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> to work upon</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>axis_tag</p></td>
+<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> of the variation axis to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>axis_index</p></td>
+<td class="parameter_description"><p>The index of the variation axis</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>axis_info</p></td>
+<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-ot-var.html#hb-ot-var-axis-info-t" title="hb_ot_var_axis_info_t"><span class="type">hb_ot_var_axis_info_t</span></a> of the axis tag queried. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-1-4-2.html#api-index-1.4.2">1.4.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-ot-var-get-axes"></a><h3>hb_ot_var_get_axes ()</h3>
+<pre class="programlisting">unsigned <span class="returnvalue">int</span>
+hb_ot_var_get_axes (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
+                    <em class="parameter"><code>unsigned <span class="type">int</span> start_offset</code></em>,
+                    <em class="parameter"><code>unsigned <span class="type">int</span> *axes_count</code></em>,
+                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-deprecated.html#hb-ot-var-axis-t" title="hb_ot_var_axis_t"><span class="type">hb_ot_var_axis_t</span></a> *axes_array</code></em>);</pre>
+<div class="warning">
+<p><code class="literal">hb_ot_var_get_axes</code> has been deprecated since version 2.2.0 and should not be used in newly-written code.</p>
+<p>use <a class="link" href="harfbuzz-hb-ot-var.html#hb-ot-var-get-axis-infos" title="hb_ot_var_get_axis_infos ()"><code class="function">hb_ot_var_get_axis_infos()</code></a> instead</p>
+</div>
+<p>Fetches a list of all variation axes in the specified face. The list returned will begin
+at the offset provided.</p>
+<div class="refsect3">
+<a name="hb-ot-var-get-axes.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>face</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> to work upon</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>start_offset</p></td>
+<td class="parameter_description"><p>offset of the first lookup to retrieve</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>axes_count</p></td>
+<td class="parameter_description"><p>Input = the maximum number of variation axes to return;
+Output = the actual number of variation axes returned (may be zero). </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for input and for returning results. Default is transfer full."><span class="acronym">inout</span></acronym>][<acronym title="NULL may be passed instead of a pointer to a location."><span class="acronym">optional</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>axes_array</p></td>
+<td class="parameter_description"><p>The array of variation axes found. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Out parameter, where caller must allocate storage."><span class="acronym">out caller-allocates</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=axes_count]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-1-4-2.html#api-index-1.4.2">1.4.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-unicode-eastasian-width-func-t"></a><h3>hb_unicode_eastasian_width_func_t ()</h3>
 <pre class="programlisting">unsigned <span class="returnvalue">int</span>
 <span class="c_punctuation">(</span>*hb_unicode_eastasian_width_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
@@ -600,6 +936,168 @@ is not needed anymore. </p></td>
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-font-get-glyph-shape"></a><h3>hb_font_get_glyph_shape ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_get_glyph_shape (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                         <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                         <em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>,
+                         <em class="parameter"><code><span class="type">void</span> *draw_data</code></em>);</pre>
+<div class="warning">
+<p><code class="literal">hb_font_get_glyph_shape</code> has been deprecated since version 7.0.0 and should not be used in newly-written code.</p>
+<p>Use <a class="link" href="harfbuzz-hb-font.html#hb-font-draw-glyph" title="hb_font_draw_glyph ()"><code class="function">hb_font_draw_glyph()</code></a> instead</p>
+</div>
+<p>Fetches the glyph shape that corresponds to a glyph in the specified <em class="parameter"><code>font</code></em>
+.
+The shape is returned by way of calls to the callbacks of the <em class="parameter"><code>dfuncs</code></em>
+
+objects, with <em class="parameter"><code>draw_data</code></em>
+ passed to them.</p>
+<div class="refsect3">
+<a name="hb-font-get-glyph-shape.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> to draw to</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>draw_data</p></td>
+<td class="parameter_description"><p>User data to pass to draw callbacks</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-font-get-glyph-shape-func-t"></a><h3>hb_font_get_glyph_shape_func_t ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+<span class="c_punctuation">(</span>*hb_font_get_glyph_shape_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                   <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *draw_funcs</code></em>,
+                                   <em class="parameter"><code><span class="type">void</span> *draw_data</code></em>,
+                                   <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<div class="warning">
+<p><code class="literal">hb_font_get_glyph_shape_func_t</code> has been deprecated since version 7.0.0 and should not be used in newly-written code.</p>
+<p>Use <a class="link" href="harfbuzz-hb-font.html#hb-font-draw-glyph-func-t" title="hb_font_draw_glyph_func_t ()"><span class="type">hb_font_draw_glyph_func_t</span></a> instead</p>
+</div>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
+<div class="refsect3">
+<a name="hb-font-get-glyph-shape-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>font_data</p></td>
+<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
+user data pointer</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>draw_funcs</p></td>
+<td class="parameter_description"><p>The draw functions to send the shape data to</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>draw_data</p></td>
+<td class="parameter_description"><p>The data accompanying the draw functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-font-funcs-set-glyph-shape-func"></a><h3>hb_font_funcs_set_glyph_shape_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_funcs_set_glyph_shape_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-deprecated.html#hb-font-get-glyph-shape-func-t" title="hb_font_get_glyph_shape_func_t ()"><span class="type">hb_font_get_glyph_shape_func_t</span></a> func</code></em>,
+                                    <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<div class="warning">
+<p><code class="literal">hb_font_funcs_set_glyph_shape_func</code> has been deprecated since version 7.0.0 and should not be used in newly-written code.</p>
+<p>Use <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-draw-glyph-func" title="hb_font_funcs_set_draw_glyph_func ()"><code class="function">hb_font_funcs_set_draw_glyph_func()</code></a> instead</p>
+</div>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-deprecated.html#hb-font-get-glyph-shape-func-t" title="hb_font_get_glyph_shape_func_t ()"><span class="type">hb_font_get_glyph_shape_func_t</span></a>,
+which is the same as <a class="link" href="harfbuzz-hb-font.html#hb-font-draw-glyph-func-t" title="hb_font_draw_glyph_func_t ()"><span class="type">hb_font_draw_glyph_func_t</span></a>.</p>
+<div class="refsect3">
+<a name="hb-font-funcs-set-glyph-shape-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-font-get-glyph-v-kerning"></a><h3>hb_font_get_glyph_v_kerning ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
 hb_font_get_glyph_v_kerning (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
@@ -760,6 +1258,14 @@ usage is no longer supported. Use <a class="link" href="harfbuzz-hb-common.html#
 </div>
 <hr>
 <div class="refsect2">
+<a name="HB-UNICODE-COMBINING-CLASS-CCC133:CAPS"></a><h3>HB_UNICODE_COMBINING_CLASS_CCC133</h3>
+<pre class="programlisting">#define HB_UNICODE_COMBINING_CLASS_CCC133 133
+</pre>
+<div class="warning"><p><code class="literal">HB_UNICODE_COMBINING_CLASS_CCC133</code> has been deprecated since version 7.2.0 and should not be used in newly-written code.</p></div>
+<p>[Tibetan]</p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-font-get-glyph-v-kerning-func-t"></a><h3>hb_font_get_glyph_v_kerning_func_t</h3>
 <pre class="programlisting">typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t;
 </pre>
index cfca7a3..8876cf3 100644 (file)
@@ -7,7 +7,7 @@
 <link rel="home" href="index.html" title="HarfBuzz Manual">
 <link rel="up" href="integration-api.html" title="Integration API">
 <link rel="prev" href="harfbuzz-hb-gdi.html" title="hb-gdi">
-<link rel="next" href="style-api.html" title="Style API">
+<link rel="next" href="harfbuzz-hb-cairo.html" title="hb-cairo">
 <meta name="generator" content="GTK-Doc V1.32 (XML mode)">
 <link rel="stylesheet" href="style.css" type="text/css">
 </head>
@@ -20,7 +20,7 @@
 <td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
 <td><a accesskey="u" href="integration-api.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
 <td><a accesskey="p" href="harfbuzz-hb-gdi.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
-<td><a accesskey="n" href="style-api.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+<td><a accesskey="n" href="harfbuzz-hb-cairo.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
 </tr></table>
 <div class="refentry">
 <a name="harfbuzz-hb-directwrite"></a><div class="titlepage"></div>
diff --git a/docs/html/harfbuzz-hb-draw.html b/docs/html/harfbuzz-hb-draw.html
new file mode 100644 (file)
index 0000000..2e45008
--- /dev/null
@@ -0,0 +1,1378 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>hb-draw: HarfBuzz Manual</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
+<link rel="home" href="index.html" title="HarfBuzz Manual">
+<link rel="up" href="core-api.html" title="Core API">
+<link rel="prev" href="harfbuzz-hb-features.html" title="hb-features">
+<link rel="next" href="harfbuzz-hb-paint.html" title="hb-paint">
+<meta name="generator" content="GTK-Doc V1.32 (XML mode)">
+<link rel="stylesheet" href="style.css" type="text/css">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
+<td width="100%" align="left" class="shortcuts">
+<a href="#" class="shortcut">Top</a><span id="nav_description">  <span class="dim">|</span> 
+                  <a href="#harfbuzz-hb-draw.description" class="shortcut">Description</a></span>
+</td>
+<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
+<td><a accesskey="u" href="core-api.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
+<td><a accesskey="p" href="harfbuzz-hb-features.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="harfbuzz-hb-paint.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+</tr></table>
+<div class="refentry">
+<a name="harfbuzz-hb-draw"></a><div class="titlepage"></div>
+<div class="refnamediv"><table width="100%"><tr>
+<td valign="top">
+<h2><span class="refentrytitle"><a name="harfbuzz-hb-draw.top_of_page"></a>hb-draw</span></h2>
+<p>hb-draw — Glyph drawing</p>
+</td>
+<td class="gallery_image" valign="top" align="right"></td>
+</tr></table></div>
+<div class="refsect1">
+<a name="harfbuzz-hb-draw.functions"></a><h2>Functions</h2>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="functions_proto_type">
+<col class="functions_proto_name">
+</colgroup>
+<tbody>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="returnvalue">hb_draw_funcs_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-create" title="hb_draw_funcs_create ()">hb_draw_funcs_create</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="returnvalue">hb_draw_funcs_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-get-empty" title="hb_draw_funcs_get_empty ()">hb_draw_funcs_get_empty</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="returnvalue">hb_draw_funcs_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-reference" title="hb_draw_funcs_reference ()">hb_draw_funcs_reference</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-destroy" title="hb_draw_funcs_destroy ()">hb_draw_funcs_destroy</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-user-data" title="hb_draw_funcs_set_user_data ()">hb_draw_funcs_set_user_data</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-get-user-data" title="hb_draw_funcs_get_user_data ()">hb_draw_funcs_get_user_data</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-make-immutable" title="hb_draw_funcs_make_immutable ()">hb_draw_funcs_make_immutable</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-is-immutable" title="hb_draw_funcs_is_immutable ()">hb_draw_funcs_is_immutable</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-draw.html#hb-draw-move-to-func-t" title="hb_draw_move_to_func_t ()">*hb_draw_move_to_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-move-to-func" title="hb_draw_funcs_set_move_to_func ()">hb_draw_funcs_set_move_to_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-draw.html#hb-draw-line-to-func-t" title="hb_draw_line_to_func_t ()">*hb_draw_line_to_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-line-to-func" title="hb_draw_funcs_set_line_to_func ()">hb_draw_funcs_set_line_to_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-draw.html#hb-draw-quadratic-to-func-t" title="hb_draw_quadratic_to_func_t ()">*hb_draw_quadratic_to_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-quadratic-to-func" title="hb_draw_funcs_set_quadratic_to_func ()">hb_draw_funcs_set_quadratic_to_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-draw.html#hb-draw-cubic-to-func-t" title="hb_draw_cubic_to_func_t ()">*hb_draw_cubic_to_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-cubic-to-func" title="hb_draw_funcs_set_cubic_to_func ()">hb_draw_funcs_set_cubic_to_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-draw.html#hb-draw-close-path-func-t" title="hb_draw_close_path_func_t ()">*hb_draw_close_path_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-close-path-func" title="hb_draw_funcs_set_close_path_func ()">hb_draw_funcs_set_close_path_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-move-to" title="hb_draw_move_to ()">hb_draw_move_to</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-line-to" title="hb_draw_line_to ()">hb_draw_line_to</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-quadratic-to" title="hb_draw_quadratic_to ()">hb_draw_quadratic_to</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-cubic-to" title="hb_draw_cubic_to ()">hb_draw_cubic_to</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-close-path" title="hb_draw_close_path ()">hb_draw_close_path</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect1">
+<a name="harfbuzz-hb-draw.other"></a><h2>Types and Values</h2>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="other_proto_type">
+<col class="other_proto_name">
+</colgroup>
+<tbody>
+<tr>
+<td class="define_keyword">#define</td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-draw.html#HB-DRAW-STATE-DEFAULT:CAPS" title="HB_DRAW_STATE_DEFAULT">HB_DRAW_STATE_DEFAULT</a></td>
+</tr>
+<tr>
+<td class="typedef_keyword">typedef</td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t">hb_draw_funcs_t</a></td>
+</tr>
+<tr>
+<td class="datatype_keyword"> </td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-draw.html#hb-draw-state-t" title="hb_draw_state_t">hb_draw_state_t</a></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect1">
+<a name="harfbuzz-hb-draw.includes"></a><h2>Includes</h2>
+<pre class="synopsis">#include &lt;hb.h&gt;
+</pre>
+</div>
+<div class="refsect1">
+<a name="harfbuzz-hb-draw.description"></a><h2>Description</h2>
+<p>Functions for drawing (extracting) glyph shapes.</p>
+<p>The <a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> struct can be used with <a class="link" href="harfbuzz-hb-font.html#hb-font-draw-glyph" title="hb_font_draw_glyph ()"><code class="function">hb_font_draw_glyph()</code></a>.</p>
+</div>
+<div class="refsect1">
+<a name="harfbuzz-hb-draw.functions_details"></a><h2>Functions</h2>
+<div class="refsect2">
+<a name="hb-draw-funcs-create"></a><h3>hb_draw_funcs_create ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="returnvalue">hb_draw_funcs_t</span></a> *
+hb_draw_funcs_create (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
+<p>Creates a new draw callbacks object.</p>
+<div class="refsect3">
+<a name="hb-draw-funcs-create.returns"></a><h4>Returns</h4>
+<p>A newly allocated <a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> with a reference count of 1. The initial
+reference count should be released with hb_draw_funcs_destroy when you are
+done using the <a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a>. This function never returns <code class="literal">NULL</code>. If
+memory cannot be allocated, a special singleton <a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> object will
+be returned. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-funcs-get-empty"></a><h3>hb_draw_funcs_get_empty ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="returnvalue">hb_draw_funcs_t</span></a> *
+hb_draw_funcs_get_empty (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
+<p>Fetches the singleton empty draw-functions structure.</p>
+<div class="refsect3">
+<a name="hb-draw-funcs-get-empty.returns"></a><h4>Returns</h4>
+<p>The empty draw-functions structure. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-funcs-reference"></a><h3>hb_draw_funcs_reference ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="returnvalue">hb_draw_funcs_t</span></a> *
+hb_draw_funcs_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>);</pre>
+<p>Increases the reference count on <em class="parameter"><code>dfuncs</code></em>
+ by one.</p>
+<p>This prevents <em class="parameter"><code>dfuncs</code></em>
+ from being destroyed until a matching
+call to <a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-destroy" title="hb_draw_funcs_destroy ()"><code class="function">hb_draw_funcs_destroy()</code></a> is made.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-draw-funcs-reference.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>draw functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-draw-funcs-reference.returns"></a><h4>Returns</h4>
+<p>The referenced <a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a>. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-funcs-destroy"></a><h3>hb_draw_funcs_destroy ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_draw_funcs_destroy (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>);</pre>
+<p>Deallocate the <em class="parameter"><code>dfuncs</code></em>
+.
+Decreases the reference count on <em class="parameter"><code>dfuncs</code></em>
+ by one. If the result is zero, then
+<em class="parameter"><code>dfuncs</code></em>
+ and all associated resources are freed. See <a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-reference" title="hb_draw_funcs_reference ()"><code class="function">hb_draw_funcs_reference()</code></a>.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-draw-funcs-destroy.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>draw functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-funcs-set-user-data"></a><h3>hb_draw_funcs_set_user_data ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_draw_funcs_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
+                             <em class="parameter"><code><span class="type">void</span> *data</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
+<p>Attaches a user-data key/data pair to the specified draw-functions structure.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-draw-funcs-set-user-data.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>The draw-functions structure</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The user-data key</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>data</p></td>
+<td class="parameter_description"><p>A pointer to the user data</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>replace</p></td>
+<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-draw-funcs-set-user-data.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-funcs-get-user-data"></a><h3>hb_draw_funcs_get_user_data ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span> *
+hb_draw_funcs_get_user_data (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>);</pre>
+<p>Fetches the user-data associated with the specified key,
+attached to the specified draw-functions structure.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-draw-funcs-get-user-data.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>The draw-functions structure</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The user-data key to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-draw-funcs-get-user-data.returns"></a><h4>Returns</h4>
+<p>A pointer to the user data. </p>
+<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-funcs-make-immutable"></a><h3>hb_draw_funcs_make_immutable ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_draw_funcs_make_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>);</pre>
+<p>Makes <em class="parameter"><code>dfuncs</code></em>
+ object immutable.</p>
+<div class="refsect3">
+<a name="hb-draw-funcs-make-immutable.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>draw functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-funcs-is-immutable"></a><h3>hb_draw_funcs_is_immutable ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_draw_funcs_is_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>);</pre>
+<p>Checks whether <em class="parameter"><code>dfuncs</code></em>
+ is immutable.</p>
+<div class="refsect3">
+<a name="hb-draw-funcs-is-immutable.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>draw functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-draw-funcs-is-immutable.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if <em class="parameter"><code>dfuncs</code></em>
+is immutable, <code class="literal">false</code> otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-move-to-func-t"></a><h3>hb_draw_move_to_func_t ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+<span class="c_punctuation">(</span>*hb_draw_move_to_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>,
+                           <em class="parameter"><code><span class="type">void</span> *draw_data</code></em>,
+                           <em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-state-t" title="hb_draw_state_t"><span class="type">hb_draw_state_t</span></a> *st</code></em>,
+                           <em class="parameter"><code><span class="type">float</span> to_x</code></em>,
+                           <em class="parameter"><code><span class="type">float</span> to_y</code></em>,
+                           <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> to perform a "move-to" draw
+operation.</p>
+<div class="refsect3">
+<a name="hb-draw-move-to-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>draw functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>draw_data</p></td>
+<td class="parameter_description"><p>The data accompanying the draw functions in <a class="link" href="harfbuzz-hb-font.html#hb-font-draw-glyph" title="hb_font_draw_glyph ()"><code class="function">hb_font_draw_glyph()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>st</p></td>
+<td class="parameter_description"><p>current draw state</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>to_x</p></td>
+<td class="parameter_description"><p>X component of target point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>to_y</p></td>
+<td class="parameter_description"><p>Y component of target point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed to <a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-move-to-func" title="hb_draw_funcs_set_move_to_func ()"><code class="function">hb_draw_funcs_set_move_to_func()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-funcs-set-move-to-func"></a><h3>hb_draw_funcs_set_move_to_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_draw_funcs_set_move_to_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-move-to-func-t" title="hb_draw_move_to_func_t ()"><span class="type">hb_draw_move_to_func_t</span></a> func</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets move-to callback to the draw functions object.</p>
+<div class="refsect3">
+<a name="hb-draw-funcs-set-move-to-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>draw functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>move-to callback. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-line-to-func-t"></a><h3>hb_draw_line_to_func_t ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+<span class="c_punctuation">(</span>*hb_draw_line_to_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>,
+                           <em class="parameter"><code><span class="type">void</span> *draw_data</code></em>,
+                           <em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-state-t" title="hb_draw_state_t"><span class="type">hb_draw_state_t</span></a> *st</code></em>,
+                           <em class="parameter"><code><span class="type">float</span> to_x</code></em>,
+                           <em class="parameter"><code><span class="type">float</span> to_y</code></em>,
+                           <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> to perform a "line-to" draw
+operation.</p>
+<div class="refsect3">
+<a name="hb-draw-line-to-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>draw functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>draw_data</p></td>
+<td class="parameter_description"><p>The data accompanying the draw functions in <a class="link" href="harfbuzz-hb-font.html#hb-font-draw-glyph" title="hb_font_draw_glyph ()"><code class="function">hb_font_draw_glyph()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>st</p></td>
+<td class="parameter_description"><p>current draw state</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>to_x</p></td>
+<td class="parameter_description"><p>X component of target point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>to_y</p></td>
+<td class="parameter_description"><p>Y component of target point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed to <a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-line-to-func" title="hb_draw_funcs_set_line_to_func ()"><code class="function">hb_draw_funcs_set_line_to_func()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-funcs-set-line-to-func"></a><h3>hb_draw_funcs_set_line_to_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_draw_funcs_set_line_to_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-line-to-func-t" title="hb_draw_line_to_func_t ()"><span class="type">hb_draw_line_to_func_t</span></a> func</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets line-to callback to the draw functions object.</p>
+<div class="refsect3">
+<a name="hb-draw-funcs-set-line-to-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>draw functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>line-to callback. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-quadratic-to-func-t"></a><h3>hb_draw_quadratic_to_func_t ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+<span class="c_punctuation">(</span>*hb_draw_quadratic_to_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *draw_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-state-t" title="hb_draw_state_t"><span class="type">hb_draw_state_t</span></a> *st</code></em>,
+                                <em class="parameter"><code><span class="type">float</span> control_x</code></em>,
+                                <em class="parameter"><code><span class="type">float</span> control_y</code></em>,
+                                <em class="parameter"><code><span class="type">float</span> to_x</code></em>,
+                                <em class="parameter"><code><span class="type">float</span> to_y</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> to perform a "quadratic-to" draw
+operation.</p>
+<div class="refsect3">
+<a name="hb-draw-quadratic-to-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>draw functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>draw_data</p></td>
+<td class="parameter_description"><p>The data accompanying the draw functions in <a class="link" href="harfbuzz-hb-font.html#hb-font-draw-glyph" title="hb_font_draw_glyph ()"><code class="function">hb_font_draw_glyph()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>st</p></td>
+<td class="parameter_description"><p>current draw state</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>control_x</p></td>
+<td class="parameter_description"><p>X component of control point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>control_y</p></td>
+<td class="parameter_description"><p>Y component of control point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>to_x</p></td>
+<td class="parameter_description"><p>X component of target point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>to_y</p></td>
+<td class="parameter_description"><p>Y component of target point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed to <a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-quadratic-to-func" title="hb_draw_funcs_set_quadratic_to_func ()"><code class="function">hb_draw_funcs_set_quadratic_to_func()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-funcs-set-quadratic-to-func"></a><h3>hb_draw_funcs_set_quadratic_to_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_draw_funcs_set_quadratic_to_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>,
+                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-quadratic-to-func-t" title="hb_draw_quadratic_to_func_t ()"><span class="type">hb_draw_quadratic_to_func_t</span></a> func</code></em>,
+                                     <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets quadratic-to callback to the draw functions object.</p>
+<div class="refsect3">
+<a name="hb-draw-funcs-set-quadratic-to-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>draw functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>quadratic-to callback. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-cubic-to-func-t"></a><h3>hb_draw_cubic_to_func_t ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+<span class="c_punctuation">(</span>*hb_draw_cubic_to_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>,
+                            <em class="parameter"><code><span class="type">void</span> *draw_data</code></em>,
+                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-state-t" title="hb_draw_state_t"><span class="type">hb_draw_state_t</span></a> *st</code></em>,
+                            <em class="parameter"><code><span class="type">float</span> control1_x</code></em>,
+                            <em class="parameter"><code><span class="type">float</span> control1_y</code></em>,
+                            <em class="parameter"><code><span class="type">float</span> control2_x</code></em>,
+                            <em class="parameter"><code><span class="type">float</span> control2_y</code></em>,
+                            <em class="parameter"><code><span class="type">float</span> to_x</code></em>,
+                            <em class="parameter"><code><span class="type">float</span> to_y</code></em>,
+                            <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> to perform a "cubic-to" draw
+operation.</p>
+<div class="refsect3">
+<a name="hb-draw-cubic-to-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>draw functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>draw_data</p></td>
+<td class="parameter_description"><p>The data accompanying the draw functions in <a class="link" href="harfbuzz-hb-font.html#hb-font-draw-glyph" title="hb_font_draw_glyph ()"><code class="function">hb_font_draw_glyph()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>st</p></td>
+<td class="parameter_description"><p>current draw state</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>control1_x</p></td>
+<td class="parameter_description"><p>X component of first control point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>control1_y</p></td>
+<td class="parameter_description"><p>Y component of first control point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>control2_x</p></td>
+<td class="parameter_description"><p>X component of second control point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>control2_y</p></td>
+<td class="parameter_description"><p>Y component of second control point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>to_x</p></td>
+<td class="parameter_description"><p>X component of target point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>to_y</p></td>
+<td class="parameter_description"><p>Y component of target point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed to <a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-cubic-to-func" title="hb_draw_funcs_set_cubic_to_func ()"><code class="function">hb_draw_funcs_set_cubic_to_func()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-funcs-set-cubic-to-func"></a><h3>hb_draw_funcs_set_cubic_to_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_draw_funcs_set_cubic_to_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>,
+                                 <em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-cubic-to-func-t" title="hb_draw_cubic_to_func_t ()"><span class="type">hb_draw_cubic_to_func_t</span></a> func</code></em>,
+                                 <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                 <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets cubic-to callback to the draw functions object.</p>
+<div class="refsect3">
+<a name="hb-draw-funcs-set-cubic-to-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>draw functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>cubic-to callback. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-close-path-func-t"></a><h3>hb_draw_close_path_func_t ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+<span class="c_punctuation">(</span>*hb_draw_close_path_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>,
+                              <em class="parameter"><code><span class="type">void</span> *draw_data</code></em>,
+                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-state-t" title="hb_draw_state_t"><span class="type">hb_draw_state_t</span></a> *st</code></em>,
+                              <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> to perform a "close-path" draw
+operation.</p>
+<div class="refsect3">
+<a name="hb-draw-close-path-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>draw functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>draw_data</p></td>
+<td class="parameter_description"><p>The data accompanying the draw functions in <a class="link" href="harfbuzz-hb-font.html#hb-font-draw-glyph" title="hb_font_draw_glyph ()"><code class="function">hb_font_draw_glyph()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>st</p></td>
+<td class="parameter_description"><p>current draw state</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed to <a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-set-close-path-func" title="hb_draw_funcs_set_close_path_func ()"><code class="function">hb_draw_funcs_set_close_path_func()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-funcs-set-close-path-func"></a><h3>hb_draw_funcs_set_close_path_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_draw_funcs_set_close_path_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-close-path-func-t" title="hb_draw_close_path_func_t ()"><span class="type">hb_draw_close_path_func_t</span></a> func</code></em>,
+                                   <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets close-path callback to the draw functions object.</p>
+<div class="refsect3">
+<a name="hb-draw-funcs-set-close-path-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>draw functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>close-path callback. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-move-to"></a><h3>hb_draw_move_to ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_draw_move_to (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>,
+                 <em class="parameter"><code><span class="type">void</span> *draw_data</code></em>,
+                 <em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-state-t" title="hb_draw_state_t"><span class="type">hb_draw_state_t</span></a> *st</code></em>,
+                 <em class="parameter"><code><span class="type">float</span> to_x</code></em>,
+                 <em class="parameter"><code><span class="type">float</span> to_y</code></em>);</pre>
+<p>Perform a "move-to" draw operation.</p>
+<div class="refsect3">
+<a name="hb-draw-move-to.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>draw functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>draw_data</p></td>
+<td class="parameter_description"><p>associated draw data passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>st</p></td>
+<td class="parameter_description"><p>current draw state</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>to_x</p></td>
+<td class="parameter_description"><p>X component of target point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>to_y</p></td>
+<td class="parameter_description"><p>Y component of target point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-line-to"></a><h3>hb_draw_line_to ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_draw_line_to (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>,
+                 <em class="parameter"><code><span class="type">void</span> *draw_data</code></em>,
+                 <em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-state-t" title="hb_draw_state_t"><span class="type">hb_draw_state_t</span></a> *st</code></em>,
+                 <em class="parameter"><code><span class="type">float</span> to_x</code></em>,
+                 <em class="parameter"><code><span class="type">float</span> to_y</code></em>);</pre>
+<p>Perform a "line-to" draw operation.</p>
+<div class="refsect3">
+<a name="hb-draw-line-to.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>draw functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>draw_data</p></td>
+<td class="parameter_description"><p>associated draw data passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>st</p></td>
+<td class="parameter_description"><p>current draw state</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>to_x</p></td>
+<td class="parameter_description"><p>X component of target point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>to_y</p></td>
+<td class="parameter_description"><p>Y component of target point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-quadratic-to"></a><h3>hb_draw_quadratic_to ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_draw_quadratic_to (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>,
+                      <em class="parameter"><code><span class="type">void</span> *draw_data</code></em>,
+                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-state-t" title="hb_draw_state_t"><span class="type">hb_draw_state_t</span></a> *st</code></em>,
+                      <em class="parameter"><code><span class="type">float</span> control_x</code></em>,
+                      <em class="parameter"><code><span class="type">float</span> control_y</code></em>,
+                      <em class="parameter"><code><span class="type">float</span> to_x</code></em>,
+                      <em class="parameter"><code><span class="type">float</span> to_y</code></em>);</pre>
+<p>Perform a "quadratic-to" draw operation.</p>
+<div class="refsect3">
+<a name="hb-draw-quadratic-to.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>draw functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>draw_data</p></td>
+<td class="parameter_description"><p>associated draw data passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>st</p></td>
+<td class="parameter_description"><p>current draw state</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>control_x</p></td>
+<td class="parameter_description"><p>X component of control point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>control_y</p></td>
+<td class="parameter_description"><p>Y component of control point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>to_x</p></td>
+<td class="parameter_description"><p>X component of target point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>to_y</p></td>
+<td class="parameter_description"><p>Y component of target point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-cubic-to"></a><h3>hb_draw_cubic_to ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_draw_cubic_to (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>,
+                  <em class="parameter"><code><span class="type">void</span> *draw_data</code></em>,
+                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-state-t" title="hb_draw_state_t"><span class="type">hb_draw_state_t</span></a> *st</code></em>,
+                  <em class="parameter"><code><span class="type">float</span> control1_x</code></em>,
+                  <em class="parameter"><code><span class="type">float</span> control1_y</code></em>,
+                  <em class="parameter"><code><span class="type">float</span> control2_x</code></em>,
+                  <em class="parameter"><code><span class="type">float</span> control2_y</code></em>,
+                  <em class="parameter"><code><span class="type">float</span> to_x</code></em>,
+                  <em class="parameter"><code><span class="type">float</span> to_y</code></em>);</pre>
+<p>Perform a "cubic-to" draw operation.</p>
+<div class="refsect3">
+<a name="hb-draw-cubic-to.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>draw functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>draw_data</p></td>
+<td class="parameter_description"><p>associated draw data passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>st</p></td>
+<td class="parameter_description"><p>current draw state</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>control1_x</p></td>
+<td class="parameter_description"><p>X component of first control point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>control1_y</p></td>
+<td class="parameter_description"><p>Y component of first control point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>control2_x</p></td>
+<td class="parameter_description"><p>X component of second control point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>control2_y</p></td>
+<td class="parameter_description"><p>Y component of second control point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>to_x</p></td>
+<td class="parameter_description"><p>X component of target point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>to_y</p></td>
+<td class="parameter_description"><p>Y component of target point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-close-path"></a><h3>hb_draw_close_path ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_draw_close_path (<em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>,
+                    <em class="parameter"><code><span class="type">void</span> *draw_data</code></em>,
+                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-state-t" title="hb_draw_state_t"><span class="type">hb_draw_state_t</span></a> *st</code></em>);</pre>
+<p>Perform a "close-path" draw operation.</p>
+<div class="refsect3">
+<a name="hb-draw-close-path.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p>draw functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>draw_data</p></td>
+<td class="parameter_description"><p>associated draw data passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>st</p></td>
+<td class="parameter_description"><p>current draw state</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+</div>
+<div class="refsect1">
+<a name="harfbuzz-hb-draw.other_details"></a><h2>Types and Values</h2>
+<div class="refsect2">
+<a name="HB-DRAW-STATE-DEFAULT:CAPS"></a><h3>HB_DRAW_STATE_DEFAULT</h3>
+<pre class="programlisting">#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}}
+</pre>
+<p>The default <a class="link" href="harfbuzz-hb-draw.html#hb-draw-state-t" title="hb_draw_state_t"><span class="type">hb_draw_state_t</span></a> at the start of glyph drawing.</p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-funcs-t"></a><h3>hb_draw_funcs_t</h3>
+<pre class="programlisting">typedef struct hb_draw_funcs_t hb_draw_funcs_t;
+</pre>
+<p>Glyph draw callbacks.</p>
+<p><a class="link" href="harfbuzz-hb-draw.html#hb-draw-move-to-func-t" title="hb_draw_move_to_func_t ()"><span class="type">hb_draw_move_to_func_t</span></a>, <a class="link" href="harfbuzz-hb-draw.html#hb-draw-line-to-func-t" title="hb_draw_line_to_func_t ()"><span class="type">hb_draw_line_to_func_t</span></a> and
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-cubic-to-func-t" title="hb_draw_cubic_to_func_t ()"><span class="type">hb_draw_cubic_to_func_t</span></a> calls are necessary to be defined but we translate
+<a class="link" href="harfbuzz-hb-draw.html#hb-draw-quadratic-to-func-t" title="hb_draw_quadratic_to_func_t ()"><span class="type">hb_draw_quadratic_to_func_t</span></a> calls to <a class="link" href="harfbuzz-hb-draw.html#hb-draw-cubic-to-func-t" title="hb_draw_cubic_to_func_t ()"><span class="type">hb_draw_cubic_to_func_t</span></a> if the
+callback isn't defined.</p>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-draw-state-t"></a><h3>hb_draw_state_t</h3>
+<pre class="programlisting">typedef struct {
+  hb_bool_t path_open;
+
+  float path_start_x;
+  float path_start_y;
+
+  float current_x;
+  float current_y;
+} hb_draw_state_t;
+</pre>
+<p>Current drawing state.</p>
+<div class="refsect3">
+<a name="hb-draw-state-t.members"></a><h4>Members</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="300px" class="struct_members_name">
+<col class="struct_members_description">
+<col width="200px" class="struct_members_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="struct_member_name"><p><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> <em class="structfield"><code><a name="hb-draw-state-t.path-open"></a>path_open</code></em>;</p></td>
+<td class="struct_member_description"><p>Whether there is an open path</p></td>
+<td class="struct_member_annotations"> </td>
+</tr>
+<tr>
+<td class="struct_member_name"><p><span class="type">float</span> <em class="structfield"><code><a name="hb-draw-state-t.path-start-x"></a>path_start_x</code></em>;</p></td>
+<td class="struct_member_description"><p>X component of the start of current path</p></td>
+<td class="struct_member_annotations"> </td>
+</tr>
+<tr>
+<td class="struct_member_name"><p><span class="type">float</span> <em class="structfield"><code><a name="hb-draw-state-t.path-start-y"></a>path_start_y</code></em>;</p></td>
+<td class="struct_member_description"><p>Y component of the start of current path</p></td>
+<td class="struct_member_annotations"> </td>
+</tr>
+<tr>
+<td class="struct_member_name"><p><span class="type">float</span> <em class="structfield"><code><a name="hb-draw-state-t.current-x"></a>current_x</code></em>;</p></td>
+<td class="struct_member_description"><p>X component of current point</p></td>
+<td class="struct_member_annotations"> </td>
+</tr>
+<tr>
+<td class="struct_member_name"><p><span class="type">float</span> <em class="structfield"><code><a name="hb-draw-state-t.current-y"></a>current_y</code></em>;</p></td>
+<td class="struct_member_description"><p>Y component of current point</p></td>
+<td class="struct_member_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+</div>
+</div>
+<div class="footer">
+<hr>Generated by GTK-Doc V1.32</div>
+</body>
+</html>
\ No newline at end of file
index 3f28c1e..c7d5cba 100644 (file)
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-face.html#hb-face-destroy" title="hb_face_destroy ()">hb_face_destroy</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-get-empty" title="hb_face_get_empty ()">hb_face_get_empty</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-face.html#hb-face-get-empty" title="hb_face_get_empty ()">hb_face_get_empty</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-reference" title="hb_face_reference ()">hb_face_reference</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">unsigned <span class="returnvalue">int</span>
+<td class="function_type">
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-face.html#hb-face-get-table-tags" title="hb_face_get_table_tags ()">hb_face_get_table_tags</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-destroy" title="hb_face_destroy ()">hb_face_destroy</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">unsigned <span class="returnvalue">int</span>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-face.html#hb-face-get-glyph-count" title="hb_face_get_glyph_count ()">hb_face_get_glyph_count</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-set-user-data" title="hb_face_set_user_data ()">hb_face_set_user_data</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">unsigned <span class="returnvalue">int</span>
+<td class="function_type">
+<span class="returnvalue">void</span> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-face.html#hb-face-get-index" title="hb_face_get_index ()">hb_face_get_index</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-get-user-data" title="hb_face_get_user_data ()">hb_face_get_user_data</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">unsigned <span class="returnvalue">int</span>
+<td class="function_type">
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-face.html#hb-face-get-upem" title="hb_face_get_upem ()">hb_face_get_upem</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-make-immutable" title="hb_face_make_immutable ()">hb_face_make_immutable</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span> *
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-face.html#hb-face-get-user-data" title="hb_face_get_user_data ()">hb_face_get_user_data</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-is-immutable" title="hb_face_is_immutable ()">hb_face_is_immutable</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<td class="function_type">unsigned <span class="returnvalue">int</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-face.html#hb-face-is-immutable" title="hb_face_is_immutable ()">hb_face_is_immutable</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-get-table-tags" title="hb_face_get_table_tags ()">hb_face_get_table_tags</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-face.html#hb-face-make-immutable" title="hb_face_make_immutable ()">hb_face_make_immutable</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-set-glyph-count" title="hb_face_set_glyph_count ()">hb_face_set_glyph_count</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">
-<a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
+<td class="function_type">unsigned <span class="returnvalue">int</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-face.html#hb-face-reference" title="hb_face_reference ()">hb_face_reference</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-get-glyph-count" title="hb_face_get_glyph_count ()">hb_face_get_glyph_count</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="returnvalue">hb_blob_t</span></a> *
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-face.html#hb-face-reference-blob" title="hb_face_reference_blob ()">hb_face_reference_blob</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-set-index" title="hb_face_set_index ()">hb_face_set_index</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">
-<a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="returnvalue">hb_blob_t</span></a> *
+<td class="function_type">unsigned <span class="returnvalue">int</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-face.html#hb-face-reference-table" title="hb_face_reference_table ()">hb_face_reference_table</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-get-index" title="hb_face_get_index ()">hb_face_get_index</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-face.html#hb-face-set-glyph-count" title="hb_face_set_glyph_count ()">hb_face_set_glyph_count</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-set-upem" title="hb_face_set_upem ()">hb_face_set_upem</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">
-<span class="returnvalue">void</span>
+<td class="function_type">unsigned <span class="returnvalue">int</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-face.html#hb-face-set-index" title="hb_face_set_index ()">hb_face_set_index</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-get-upem" title="hb_face_get_upem ()">hb_face_get_upem</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="returnvalue">hb_blob_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-face.html#hb-face-set-upem" title="hb_face_set_upem ()">hb_face_set_upem</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-reference-blob" title="hb_face_reference_blob ()">hb_face_reference_blob</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="returnvalue">hb_blob_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-face.html#hb-face-set-user-data" title="hb_face_set_user_data ()">hb_face_set_user_data</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-reference-table" title="hb_face_reference_table ()">hb_face_reference_table</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
+<a class="link" href="harfbuzz-hb-face.html#hb-face-collect-nominal-glyph-mapping" title="hb_face_collect_nominal_glyph_mapping ()">hb_face_collect_nominal_glyph_mapping</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
 <a class="link" href="harfbuzz-hb-face.html#hb-face-collect-variation-selectors" title="hb_face_collect_variation_selectors ()">hb_face_collect_variation_selectors</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <a class="link" href="harfbuzz-hb-face.html#hb-face-builder-add-table" title="hb_face_builder_add_table ()">hb_face_builder_add_table</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-face.html#hb-face-builder-sort-tables" title="hb_face_builder_sort_tables ()">hb_face_builder_sort_tables</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
 </tbody>
 </table></div>
 </div>
@@ -254,6 +270,11 @@ font family.</p>
 <p>More precisely, 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.</p>
+<p>A font face can be created from a binary blob using <a class="link" href="harfbuzz-hb-face.html#hb-face-create" title="hb_face_create ()"><code class="function">hb_face_create()</code></a>.
+The face index is used to select a face from a binary blob that contains
+multiple faces.  For example, a binary blob that contains both a regular
+and a bold face can be used to create two font faces, one for each face
+index.</p>
 </div>
 <div class="refsect1">
 <a name="harfbuzz-hb-face.functions_details"></a><h2>Functions</h2>
@@ -293,7 +314,7 @@ hb_face_create (<em class="parameter"><code><a class="link" href="harfbuzz-hb-bl
 <p>Constructs a new face object from the specified blob and
 a face index into that blob.</p>
 <p>The face index is used for blobs of file formats such as TTC and
-and DFont that can contain more than one face.  Face indices within
+DFont that can contain more than one face.  Face indices within
 such collections are zero-based.</p>
 <div class="note">Note: If the blob font format is not a collection, <em class="parameter"><code>index</code></em>
 is ignored.  Otherwise, only the lower 16-bits of <em class="parameter"><code>index</code></em> are used.
@@ -301,7 +322,6 @@ The unmodified <em class="parameter"><code>index</code></em> can be accessed via
 <div class="note">Note: The high 16-bits of <em class="parameter"><code>index</code></em>, if non-zero, are used by
 <a class="link" href="harfbuzz-hb-font.html#hb-font-create" title="hb_font_create ()"><code class="function">hb_font_create()</code></a> to load named-instances in variable fonts.  See
 <a class="link" href="harfbuzz-hb-font.html#hb-font-create" title="hb_font_create ()"><code class="function">hb_font_create()</code></a> for details.</div>
-<p><span class="annotation">[Xconstructor]</span></p>
 <div class="refsect3">
 <a name="hb-face-create.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
@@ -385,32 +405,6 @@ is not needed anymore. </p></td>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-face-destroy"></a><h3>hb_face_destroy ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_face_destroy (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
-<p>Decreases the reference count on a face object. When the
-reference count reaches zero, the face is destroyed,
-freeing all memory.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
-<div class="refsect3">
-<a name="hb-face-destroy.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody><tr>
-<td class="parameter_name"><p>face</p></td>
-<td class="parameter_description"><p>A face object</p></td>
-<td class="parameter_annotations"> </td>
-</tr></tbody>
-</table></div>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
 <a name="hb-face-get-empty"></a><h3>hb_face_get_empty ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
 hb_face_get_empty (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
@@ -424,61 +418,13 @@ hb_face_get_empty (<em class="parameter"><code><span class="type">void</span></c
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-face-get-table-tags"></a><h3>hb_face_get_table_tags ()</h3>
-<pre class="programlisting">unsigned <span class="returnvalue">int</span>
-hb_face_get_table_tags (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
-                        <em class="parameter"><code>unsigned <span class="type">int</span> start_offset</code></em>,
-                        <em class="parameter"><code>unsigned <span class="type">int</span> *table_count</code></em>,
-                        <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> *table_tags</code></em>);</pre>
-<p>Fetches a list of all table tags for a face, if possible. The list returned will
-begin at the offset provided</p>
-<div class="refsect3">
-<a name="hb-face-get-table-tags.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>face</p></td>
-<td class="parameter_description"><p>A face object</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>start_offset</p></td>
-<td class="parameter_description"><p>The index of first table tag to retrieve</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>table_count</p></td>
-<td class="parameter_description"><p>Input = the maximum number of table tags to return;
-Output = the actual number of table tags returned (may be zero). </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for input and for returning results. Default is transfer full."><span class="acronym">inout</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>table_tags</p></td>
-<td class="parameter_description"><p>The array of table tags found. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=table_count]</span></td>
-</tr>
-</tbody>
-</table></div>
-</div>
-<div class="refsect3">
-<a name="hb-face-get-table-tags.returns"></a><h4>Returns</h4>
-<p> Total number of tables, or zero if it is not possible to list</p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-1-6-0.html#api-index-1.6.0">1.6.0</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-face-get-glyph-count"></a><h3>hb_face_get_glyph_count ()</h3>
-<pre class="programlisting">unsigned <span class="returnvalue">int</span>
-hb_face_get_glyph_count (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
-<p>Fetches the glyph-count value of the specified face object.</p>
+<a name="hb-face-reference"></a><h3>hb_face_reference ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
+hb_face_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
+<p>Increases the reference count on a face object.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
-<a name="hb-face-get-glyph-count.parameters"></a><h4>Parameters</h4>
+<a name="hb-face-reference.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -493,21 +439,23 @@ hb_face_get_glyph_count (<em class="parameter"><code>const <a class="link" href=
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-face-get-glyph-count.returns"></a><h4>Returns</h4>
-<p> The glyph-count value of <em class="parameter"><code>face</code></em>
-</p>
+<a name="hb-face-reference.returns"></a><h4>Returns</h4>
+<p> The <em class="parameter"><code>face</code></em>
+object</p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-7.html#api-index-0.9.7">0.9.7</a></p>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-face-get-index"></a><h3>hb_face_get_index ()</h3>
-<pre class="programlisting">unsigned <span class="returnvalue">int</span>
-hb_face_get_index (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
-<p>Fetches the face-index corresponding to the given face.</p>
-<div class="note">Note: face indices within a collection are zero-based.</div>
+<a name="hb-face-destroy"></a><h3>hb_face_destroy ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_face_destroy (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
+<p>Decreases the reference count on a face object. When the
+reference count reaches zero, the face is destroyed,
+freeing all memory.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
-<a name="hb-face-get-index.parameters"></a><h4>Parameters</h4>
+<a name="hb-face-destroy.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -521,38 +469,60 @@ hb_face_get_index (<em class="parameter"><code>const <a class="link" href="harfb
 </tr></tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-face-get-index.returns"></a><h4>Returns</h4>
-<p> The index of <em class="parameter"><code>face</code></em>
-.</p>
-</div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-face-get-upem"></a><h3>hb_face_get_upem ()</h3>
-<pre class="programlisting">unsigned <span class="returnvalue">int</span>
-hb_face_get_upem (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
-<p>Fetches the units-per-em (upem) value of the specified face object.</p>
+<a name="hb-face-set-user-data"></a><h3>hb_face_set_user_data ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_face_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
+                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
+                       <em class="parameter"><code><span class="type">void</span> *data</code></em>,
+                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
+                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
+<p>Attaches a user-data key/data pair to the given face object.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
-<a name="hb-face-get-upem.parameters"></a><h4>Parameters</h4>
+<a name="hb-face-set-user-data.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody><tr>
+<tbody>
+<tr>
 <td class="parameter_name"><p>face</p></td>
 <td class="parameter_description"><p>A face object</p></td>
 <td class="parameter_annotations"> </td>
-</tr></tbody>
+</tr>
+<tr>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The user-data key to set</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>data</p></td>
+<td class="parameter_description"><p>A pointer to the user data</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>replace</p></td>
+<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-face-get-upem.returns"></a><h4>Returns</h4>
-<p> The upem value of <em class="parameter"><code>face</code></em>
-</p>
+<a name="hb-face-set-user-data.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
@@ -596,12 +566,12 @@ attached to the specified face object.</p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-face-is-immutable"></a><h3>hb_face_is_immutable ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_face_is_immutable (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
-<p>Tests whether the given face object is immutable.</p>
+<a name="hb-face-make-immutable"></a><h3>hb_face_make_immutable ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_face_make_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
+<p>Makes the given face object immutable.</p>
 <div class="refsect3">
-<a name="hb-face-is-immutable.parameters"></a><h4>Parameters</h4>
+<a name="hb-face-make-immutable.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -615,75 +585,16 @@ hb_face_is_immutable (<em class="parameter"><code>const <a class="link" href="ha
 </tr></tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-face-is-immutable.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> is <em class="parameter"><code>face</code></em>
-is immutable, <code class="literal">false</code> otherwise</p>
-</div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-face-make-immutable"></a><h3>hb_face_make_immutable ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_face_make_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
-<p>Makes the given face object immutable.</p>
-<div class="refsect3">
-<a name="hb-face-make-immutable.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody><tr>
-<td class="parameter_name"><p>face</p></td>
-<td class="parameter_description"><p>A face object</p></td>
-<td class="parameter_annotations"> </td>
-</tr></tbody>
-</table></div>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-face-reference"></a><h3>hb_face_reference ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
-hb_face_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
-<p>Increases the reference count on a face object.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
-<div class="refsect3">
-<a name="hb-face-reference.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody><tr>
-<td class="parameter_name"><p>face</p></td>
-<td class="parameter_description"><p>A face object</p></td>
-<td class="parameter_annotations"> </td>
-</tr></tbody>
-</table></div>
-</div>
-<div class="refsect3">
-<a name="hb-face-reference.returns"></a><h4>Returns</h4>
-<p> The <em class="parameter"><code>face</code></em>
-object</p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-face-reference-blob"></a><h3>hb_face_reference_blob ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="returnvalue">hb_blob_t</span></a> *
-hb_face_reference_blob (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
-<p>Fetches a pointer to the binary blob that contains the
-specified face. Returns an empty blob if referencing face data is not
-possible.</p>
+<a name="hb-face-is-immutable"></a><h3>hb_face_is_immutable ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_face_is_immutable (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
+<p>Tests whether the given face object is immutable.</p>
 <div class="refsect3">
-<a name="hb-face-reference-blob.parameters"></a><h4>Parameters</h4>
+<a name="hb-face-is-immutable.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -698,23 +609,24 @@ possible.</p>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-face-reference-blob.returns"></a><h4>Returns</h4>
-<p>A pointer to the blob for <em class="parameter"><code>face</code></em>
-. </p>
-<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+<a name="hb-face-is-immutable.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> is <em class="parameter"><code>face</code></em>
+is immutable, <code class="literal">false</code> otherwise</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-face-reference-table"></a><h3>hb_face_reference_table ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="returnvalue">hb_blob_t</span></a> *
-hb_face_reference_table (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
-                         <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> tag</code></em>);</pre>
-<p>Fetches a reference to the specified table within
-the specified face.</p>
+<a name="hb-face-get-table-tags"></a><h3>hb_face_get_table_tags ()</h3>
+<pre class="programlisting">unsigned <span class="returnvalue">int</span>
+hb_face_get_table_tags (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
+                        <em class="parameter"><code>unsigned <span class="type">int</span> start_offset</code></em>,
+                        <em class="parameter"><code>unsigned <span class="type">int</span> *table_count</code></em>,
+                        <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> *table_tags</code></em>);</pre>
+<p>Fetches a list of all table tags for a face, if possible. The list returned will
+begin at the offset provided</p>
 <div class="refsect3">
-<a name="hb-face-reference-table.parameters"></a><h4>Parameters</h4>
+<a name="hb-face-get-table-tags.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -728,21 +640,29 @@ the specified face.</p>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>tag</p></td>
-<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> of the table to query</p></td>
+<td class="parameter_name"><p>start_offset</p></td>
+<td class="parameter_description"><p>The index of first table tag to retrieve</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
+<tr>
+<td class="parameter_name"><p>table_count</p></td>
+<td class="parameter_description"><p>Input = the maximum number of table tags to return;
+Output = the actual number of table tags returned (may be zero). </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for input and for returning results. Default is transfer full."><span class="acronym">inout</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>table_tags</p></td>
+<td class="parameter_description"><p>The array of table tags found. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=table_count]</span></td>
+</tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-face-reference-table.returns"></a><h4>Returns</h4>
-<p>A pointer to the <em class="parameter"><code>tag</code></em>
-table within <em class="parameter"><code>face</code></em>
-. </p>
-<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+<a name="hb-face-get-table-tags.returns"></a><h4>Returns</h4>
+<p> Total number of tables, or zero if it is not possible to list</p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-1-6-0.html#api-index-1.6.0">1.6.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
@@ -751,6 +671,7 @@ table within <em class="parameter"><code>face</code></em>
 hb_face_set_glyph_count (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
                          <em class="parameter"><code>unsigned <span class="type">int</span> glyph_count</code></em>);</pre>
 <p>Sets the glyph count for a face object to the specified value.</p>
+<p>This API is used in rare circumstances.</p>
 <div class="refsect3">
 <a name="hb-face-set-glyph-count.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
@@ -777,6 +698,34 @@ hb_face_set_glyph_count (<em class="parameter"><code><a class="link" href="harfb
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-face-get-glyph-count"></a><h3>hb_face_get_glyph_count ()</h3>
+<pre class="programlisting">unsigned <span class="returnvalue">int</span>
+hb_face_get_glyph_count (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
+<p>Fetches the glyph-count value of the specified face object.</p>
+<div class="refsect3">
+<a name="hb-face-get-glyph-count.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>face</p></td>
+<td class="parameter_description"><p>A face object</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-face-get-glyph-count.returns"></a><h4>Returns</h4>
+<p> The glyph-count value of <em class="parameter"><code>face</code></em>
+</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-7.html#api-index-0.9.7">0.9.7</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-face-set-index"></a><h3>hb_face_set_index ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
 hb_face_set_index (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
@@ -812,11 +761,41 @@ This only changes the value returned by <a class="link" href="harfbuzz-hb-face.h
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-face-get-index"></a><h3>hb_face_get_index ()</h3>
+<pre class="programlisting">unsigned <span class="returnvalue">int</span>
+hb_face_get_index (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
+<p>Fetches the face-index corresponding to the given face.</p>
+<div class="note">Note: face indices within a collection are zero-based.</div>
+<div class="refsect3">
+<a name="hb-face-get-index.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>face</p></td>
+<td class="parameter_description"><p>A face object</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-face-get-index.returns"></a><h4>Returns</h4>
+<p> The index of <em class="parameter"><code>face</code></em>
+.</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-face-set-upem"></a><h3>hb_face_set_upem ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
 hb_face_set_upem (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
                   <em class="parameter"><code>unsigned <span class="type">int</span> upem</code></em>);</pre>
 <p>Sets the units-per-em (upem) for a face object to the specified value.</p>
+<p>This API is used in rare circumstances.</p>
 <div class="refsect3">
 <a name="hb-face-set-upem.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
@@ -843,56 +822,101 @@ hb_face_set_upem (<em class="parameter"><code><a class="link" href="harfbuzz-hb-
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-face-set-user-data"></a><h3>hb_face_set_user_data ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_face_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
-                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
-                       <em class="parameter"><code><span class="type">void</span> *data</code></em>,
-                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
-                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
-<p>Attaches a user-data key/data pair to the given face object.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<a name="hb-face-get-upem"></a><h3>hb_face_get_upem ()</h3>
+<pre class="programlisting">unsigned <span class="returnvalue">int</span>
+hb_face_get_upem (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
+<p>Fetches the units-per-em (UPEM) value of the specified face object.</p>
+<p>Typical UPEM values for fonts are 1000, or 2048, but any value
+in between 16 and 16,384 is allowed for OpenType fonts.</p>
 <div class="refsect3">
-<a name="hb-face-set-user-data.parameters"></a><h4>Parameters</h4>
+<a name="hb-face-get-upem.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody>
-<tr>
+<tbody><tr>
 <td class="parameter_name"><p>face</p></td>
 <td class="parameter_description"><p>A face object</p></td>
 <td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>key</p></td>
-<td class="parameter_description"><p>The user-data key to set</p></td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-face-get-upem.returns"></a><h4>Returns</h4>
+<p> The upem value of <em class="parameter"><code>face</code></em>
+</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-face-reference-blob"></a><h3>hb_face_reference_blob ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="returnvalue">hb_blob_t</span></a> *
+hb_face_reference_blob (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
+<p>Fetches a pointer to the binary blob that contains the
+specified face. Returns an empty blob if referencing face data is not
+possible.</p>
+<div class="refsect3">
+<a name="hb-face-reference-blob.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>face</p></td>
+<td class="parameter_description"><p>A face object</p></td>
 <td class="parameter_annotations"> </td>
-</tr>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-face-reference-blob.returns"></a><h4>Returns</h4>
+<p>A pointer to the blob for <em class="parameter"><code>face</code></em>
+. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-face-reference-table"></a><h3>hb_face_reference_table ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="returnvalue">hb_blob_t</span></a> *
+hb_face_reference_table (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
+                         <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> tag</code></em>);</pre>
+<p>Fetches a reference to the specified table within
+the specified face.</p>
+<div class="refsect3">
+<a name="hb-face-reference-table.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
 <tr>
-<td class="parameter_name"><p>data</p></td>
-<td class="parameter_description"><p>A pointer to the user data</p></td>
+<td class="parameter_name"><p>face</p></td>
+<td class="parameter_description"><p>A face object</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>replace</p></td>
-<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
+<td class="parameter_name"><p>tag</p></td>
+<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> of the table to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-face-set-user-data.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
+<a name="hb-face-reference-table.returns"></a><h4>Returns</h4>
+<p>A pointer to the <em class="parameter"><code>tag</code></em>
+table within <em class="parameter"><code>face</code></em>
+. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
@@ -922,8 +946,8 @@ them to the <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t
 </tr>
 <tr>
 <td class="parameter_name"><p>out</p></td>
-<td class="parameter_description"><p>The set to add Unicode characters to</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_description"><p>The set to add Unicode characters to</p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
@@ -932,6 +956,46 @@ them to the <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-face-collect-nominal-glyph-mapping"></a><h3>hb_face_collect_nominal_glyph_mapping ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_face_collect_nominal_glyph_mapping (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
+                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *mapping</code></em>,
+                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *unicodes</code></em>);</pre>
+<p>Collects the mapping from Unicode characters to nominal glyphs of the <em class="parameter"><code>face</code></em>
+,
+and optionally all of the Unicode characters covered by <em class="parameter"><code>face</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-face-collect-nominal-glyph-mapping.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>face</p></td>
+<td class="parameter_description"><p>A face object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>mapping</p></td>
+<td class="parameter_description"><p>The map to add Unicode-to-glyph mapping to. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>unicodes</p></td>
+<td class="parameter_description"><p>The set to add Unicode characters to, or <code class="literal">NULL</code>. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>][<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-face-collect-variation-selectors"></a><h3>hb_face_collect_variation_selectors ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
 hb_face_collect_variation_selectors (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
@@ -956,8 +1020,8 @@ them to the <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t
 </tr>
 <tr>
 <td class="parameter_name"><p>out</p></td>
-<td class="parameter_description"><p>The set to add Variation Selector characters to</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_description"><p>The set to add Variation Selector characters to</p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
@@ -997,8 +1061,8 @@ them to the <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t
 </tr>
 <tr>
 <td class="parameter_name"><p>out</p></td>
-<td class="parameter_description"><p>The set to add Unicode characters to</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_description"><p>The set to add Unicode characters to</p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
@@ -1061,6 +1125,40 @@ be created using <a class="link" href="harfbuzz-hb-face.html#hb-face-builder-cre
 </div>
 <p class="since">Since: <a class="link" href="api-index-1-9-0.html#api-index-1.9.0">1.9.0</a></p>
 </div>
+<hr>
+<div class="refsect2">
+<a name="hb-face-builder-sort-tables"></a><h3>hb_face_builder_sort_tables ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_face_builder_sort_tables (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
+                             <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> *tags</code></em>);</pre>
+<p>Set the ordering of tables for serialization. Any tables not
+specified in the tags list will be ordered after the tables in
+tags, ordered by the default sort ordering.</p>
+<div class="refsect3">
+<a name="hb-face-builder-sort-tables.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>face</p></td>
+<td class="parameter_description"><p>A face object created with <a class="link" href="harfbuzz-hb-face.html#hb-face-builder-create" title="hb_face_builder_create ()"><code class="function">hb_face_builder_create()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>tags</p></td>
+<td class="parameter_description"><p>ordered list of table tags terminated by
+<a class="link" href="harfbuzz-hb-common.html#HB-TAG-NONE:CAPS" title="HB_TAG_NONE"><code class="literal">HB_TAG_NONE</code></a>. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> zero-terminated=1]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-5-3-0.html#api-index-5.3.0">5.3.0</a></p>
+</div>
 </div>
 <div class="refsect1">
 <a name="harfbuzz-hb-face.other_details"></a><h2>Types and Values</h2>
diff --git a/docs/html/harfbuzz-hb-features.html b/docs/html/harfbuzz-hb-features.html
new file mode 100644 (file)
index 0000000..29e3025
--- /dev/null
@@ -0,0 +1,86 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>hb-features: HarfBuzz Manual</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
+<link rel="home" href="index.html" title="HarfBuzz Manual">
+<link rel="up" href="core-api.html" title="Core API">
+<link rel="prev" href="harfbuzz-hb-common.html" title="hb-common">
+<link rel="next" href="harfbuzz-hb-draw.html" title="hb-draw">
+<meta name="generator" content="GTK-Doc V1.32 (XML mode)">
+<link rel="stylesheet" href="style.css" type="text/css">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
+<td width="100%" align="left" class="shortcuts">
+<a href="#" class="shortcut">Top</a><span id="nav_description">  <span class="dim">|</span> 
+                  <a href="#harfbuzz-hb-features.description" class="shortcut">Description</a></span>
+</td>
+<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
+<td><a accesskey="u" href="core-api.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
+<td><a accesskey="p" href="harfbuzz-hb-common.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="harfbuzz-hb-draw.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+</tr></table>
+<div class="refentry">
+<a name="harfbuzz-hb-features"></a><div class="titlepage"></div>
+<div class="refnamediv"><table width="100%"><tr>
+<td valign="top">
+<h2><span class="refentrytitle"><a name="harfbuzz-hb-features.top_of_page"></a>hb-features</span></h2>
+<p>hb-features — Feature detection</p>
+</td>
+<td class="gallery_image" valign="top" align="right"></td>
+</tr></table></div>
+<div class="refsect1">
+<a name="harfbuzz-hb-features.other"></a><h2>Types and Values</h2>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="other_proto_type">
+<col class="other_proto_name">
+</colgroup>
+<tbody>
+<tr>
+<td class="define_keyword">#define</td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-features.html#HB-HAS-FREETYPE:CAPS" title="HB_HAS_FREETYPE">HB_HAS_FREETYPE</a></td>
+</tr>
+<tr>
+<td class="define_keyword">#define</td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-features.html#HB-HAS-GLIB:CAPS" title="HB_HAS_GLIB">HB_HAS_GLIB</a></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect1">
+<a name="harfbuzz-hb-features.includes"></a><h2>Includes</h2>
+<pre class="synopsis">#include &lt;hb-features.h&gt;
+</pre>
+</div>
+<div class="refsect1">
+<a name="harfbuzz-hb-features.description"></a><h2>Description</h2>
+<p>Macros for detecting optional HarfBuzz features at build time.</p>
+</div>
+<div class="refsect1">
+<a name="harfbuzz-hb-features.functions_details"></a><h2>Functions</h2>
+<p></p>
+</div>
+<div class="refsect1">
+<a name="harfbuzz-hb-features.other_details"></a><h2>Types and Values</h2>
+<div class="refsect2">
+<a name="HB-HAS-FREETYPE:CAPS"></a><h3>HB_HAS_FREETYPE</h3>
+<pre class="programlisting">#define HB_HAS_FREETYPE 1
+</pre>
+<p>Defined if Harfbuzz has been built with Freetype support.</p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="HB-HAS-GLIB:CAPS"></a><h3>HB_HAS_GLIB</h3>
+<pre class="programlisting">#define HB_HAS_GLIB 1
+</pre>
+<p>Defined if Harfbuzz has been built with GLib support.</p>
+</div>
+</div>
+</div>
+<div class="footer">
+<hr>Generated by GTK-Doc V1.32</div>
+</body>
+</html>
\ No newline at end of file
index de1f8a2..c8c87f2 100644 (file)
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="returnvalue">hb_font_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-destroy" title="hb_font_destroy ()">hb_font_destroy</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-empty" title="hb_font_get_empty ()">hb_font_get_empty</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="returnvalue">hb_font_funcs_t</span></a> *
+<a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="returnvalue">hb_font_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-create" title="hb_font_funcs_create ()">hb_font_funcs_create</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-reference" title="hb_font_reference ()">hb_font_reference</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-destroy" title="hb_font_funcs_destroy ()">hb_font_funcs_destroy</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-destroy" title="hb_font_destroy ()">hb_font_destroy</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="returnvalue">hb_font_funcs_t</span></a> *
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-get-empty" title="hb_font_funcs_get_empty ()">hb_font_funcs_get_empty</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-set-user-data" title="hb_font_set_user_data ()">hb_font_set_user_data</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-get-user-data" title="hb_font_funcs_get_user_data ()">hb_font_funcs_get_user_data</a> <span class="c_punctuation">()</span>
-</td>
-</tr>
-<tr>
-<td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-</td>
-<td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-is-immutable" title="hb_font_funcs_is_immutable ()">hb_font_funcs_is_immutable</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-user-data" title="hb_font_get_user_data ()">hb_font_get_user_data</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-make-immutable" title="hb_font_funcs_make_immutable ()">hb_font_funcs_make_immutable</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-make-immutable" title="hb_font_make_immutable ()">hb_font_make_immutable</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="returnvalue">hb_font_funcs_t</span></a> *
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-reference" title="hb_font_funcs_reference ()">hb_font_funcs_reference</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-is-immutable" title="hb_font_is_immutable ()">hb_font_is_immutable</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-contour-point-func" title="hb_font_funcs_set_glyph_contour_point_func ()">hb_font_funcs_set_glyph_contour_point_func</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-set-face" title="hb_font_set_face ()">hb_font_set_face</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-extents-func" title="hb_font_funcs_set_glyph_extents_func ()">hb_font_funcs_set_glyph_extents_func</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-face" title="hb_font_get_face ()">hb_font_get_face</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-from-name-func" title="hb_font_funcs_set_glyph_from_name_func ()">hb_font_funcs_set_glyph_from_name_func</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph" title="hb_font_get_glyph ()">hb_font_get_glyph</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-h-advance-func" title="hb_font_funcs_set_glyph_h_advance_func ()">hb_font_funcs_set_glyph_h_advance_func</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-advance-for-direction" title="hb_font_get_glyph_advance_for_direction ()">hb_font_get_glyph_advance_for_direction</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-h-advances-func" title="hb_font_funcs_set_glyph_h_advances_func ()">hb_font_funcs_set_glyph_h_advances_func</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-advances-for-direction" title="hb_font_get_glyph_advances_for_direction ()">hb_font_get_glyph_advances_for_direction</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-h-kerning-func" title="hb_font_funcs_set_glyph_h_kerning_func ()">hb_font_funcs_set_glyph_h_kerning_func</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-contour-point" title="hb_font_get_glyph_contour_point ()">hb_font_get_glyph_contour_point</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-h-origin-func" title="hb_font_funcs_set_glyph_h_origin_func ()">hb_font_funcs_set_glyph_h_origin_func</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-contour-point-for-origin" title="hb_font_get_glyph_contour_point_for_origin ()">hb_font_get_glyph_contour_point_for_origin</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-name-func" title="hb_font_funcs_set_glyph_name_func ()">hb_font_funcs_set_glyph_name_func</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-extents" title="hb_font_get_glyph_extents ()">hb_font_get_glyph_extents</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-v-advance-func" title="hb_font_funcs_set_glyph_v_advance_func ()">hb_font_funcs_set_glyph_v_advance_func</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-extents-for-origin" title="hb_font_get_glyph_extents_for_origin ()">hb_font_get_glyph_extents_for_origin</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-v-advances-func" title="hb_font_funcs_set_glyph_v_advances_func ()">hb_font_funcs_set_glyph_v_advances_func</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-from-name" title="hb_font_get_glyph_from_name ()">hb_font_get_glyph_from_name</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-v-origin-func" title="hb_font_funcs_set_glyph_v_origin_func ()">hb_font_funcs_set_glyph_v_origin_func</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-advance" title="hb_font_get_glyph_h_advance ()">hb_font_get_glyph_h_advance</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-nominal-glyph-func" title="hb_font_funcs_set_nominal_glyph_func ()">hb_font_funcs_set_nominal_glyph_func</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-advance" title="hb_font_get_glyph_v_advance ()">hb_font_get_glyph_v_advance</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-nominal-glyphs-func" title="hb_font_funcs_set_nominal_glyphs_func ()">hb_font_funcs_set_nominal_glyphs_func</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-advances" title="hb_font_get_glyph_h_advances ()">hb_font_get_glyph_h_advances</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-user-data" title="hb_font_funcs_set_user_data ()">hb_font_funcs_set_user_data</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-advances" title="hb_font_get_glyph_v_advances ()">hb_font_get_glyph_v_advances</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-variation-glyph-func" title="hb_font_funcs_set_variation_glyph_func ()">hb_font_funcs_set_variation_glyph_func</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-kerning" title="hb_font_get_glyph_h_kerning ()">hb_font_get_glyph_h_kerning</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="returnvalue">hb_font_t</span></a> *
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-empty" title="hb_font_get_empty ()">hb_font_get_empty</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-kerning-for-direction" title="hb_font_get_glyph_kerning_for_direction ()">hb_font_get_glyph_kerning_for_direction</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-face" title="hb_font_get_face ()">hb_font_get_face</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-origin" title="hb_font_get_glyph_h_origin ()">hb_font_get_glyph_h_origin</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph" title="hb_font_get_glyph ()">hb_font_get_glyph</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-origin" title="hb_font_get_glyph_v_origin ()">hb_font_get_glyph_v_origin</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-advance-for-direction" title="hb_font_get_glyph_advance_for_direction ()">hb_font_get_glyph_advance_for_direction</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-origin-for-direction" title="hb_font_get_glyph_origin_for_direction ()">hb_font_get_glyph_origin_for_direction</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-advance-func-t" title="hb_font_get_glyph_advance_func_t ()">*hb_font_get_glyph_advance_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-name" title="hb_font_get_glyph_name ()">hb_font_get_glyph_name</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-advances-for-direction" title="hb_font_get_glyph_advances_for_direction ()">hb_font_get_glyph_advances_for_direction</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-draw-glyph" title="hb_font_draw_glyph ()">hb_font_draw_glyph</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-advances-func-t" title="hb_font_get_glyph_advances_func_t ()">*hb_font_get_glyph_advances_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph" title="hb_font_paint_glyph ()">hb_font_paint_glyph</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-contour-point" title="hb_font_get_glyph_contour_point ()">hb_font_get_glyph_contour_point</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-nominal-glyph" title="hb_font_get_nominal_glyph ()">hb_font_get_nominal_glyph</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<td class="function_type">unsigned <span class="returnvalue">int</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-contour-point-for-origin" title="hb_font_get_glyph_contour_point_for_origin ()">hb_font_get_glyph_contour_point_for_origin</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-nominal-glyphs" title="hb_font_get_nominal_glyphs ()">hb_font_get_nominal_glyphs</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-contour-point-func-t" title="hb_font_get_glyph_contour_point_func_t ()">*hb_font_get_glyph_contour_point_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-variation-glyph" title="hb_font_get_variation_glyph ()">hb_font_get_variation_glyph</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-extents" title="hb_font_get_glyph_extents ()">hb_font_get_glyph_extents</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-set-parent" title="hb_font_set_parent ()">hb_font_set_parent</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="returnvalue">hb_font_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-extents-for-origin" title="hb_font_get_glyph_extents_for_origin ()">hb_font_get_glyph_extents_for_origin</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-parent" title="hb_font_get_parent ()">hb_font_get_parent</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-extents-func-t" title="hb_font_get_glyph_extents_func_t ()">*hb_font_get_glyph_extents_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-set-ppem" title="hb_font_set_ppem ()">hb_font_set_ppem</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-from-name" title="hb_font_get_glyph_from_name ()">hb_font_get_glyph_from_name</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-ppem" title="hb_font_get_ppem ()">hb_font_get_ppem</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-from-name-func-t" title="hb_font_get_glyph_from_name_func_t ()">*hb_font_get_glyph_from_name_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-set-ptem" title="hb_font_set_ptem ()">hb_font_set_ptem</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
+<span class="returnvalue">float</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-advance" title="hb_font_get_glyph_h_advance ()">hb_font_get_glyph_h_advance</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-ptem" title="hb_font_get_ptem ()">hb_font_get_ptem</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-advances" title="hb_font_get_glyph_h_advances ()">hb_font_get_glyph_h_advances</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-set-scale" title="hb_font_set_scale ()">hb_font_set_scale</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-kerning" title="hb_font_get_glyph_h_kerning ()">hb_font_get_glyph_h_kerning</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-scale" title="hb_font_get_scale ()">hb_font_get_scale</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-origin" title="hb_font_get_glyph_h_origin ()">hb_font_get_glyph_h_origin</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-synthetic-bold" title="hb_font_get_synthetic_bold ()">hb_font_get_synthetic_bold</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-kerning-for-direction" title="hb_font_get_glyph_kerning_for_direction ()">hb_font_get_glyph_kerning_for_direction</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-set-synthetic-bold" title="hb_font_set_synthetic_bold ()">hb_font_set_synthetic_bold</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-kerning-func-t" title="hb_font_get_glyph_kerning_func_t ()">*hb_font_get_glyph_kerning_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-set-synthetic-slant" title="hb_font_set_synthetic_slant ()">hb_font_set_synthetic_slant</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">float</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-name" title="hb_font_get_glyph_name ()">hb_font_get_glyph_name</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-synthetic-slant" title="hb_font_get_synthetic_slant ()">hb_font_get_synthetic_slant</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-name-func-t" title="hb_font_get_glyph_name_func_t ()">*hb_font_get_glyph_name_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-set-variations" title="hb_font_set_variations ()">hb_font_set_variations</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-origin-for-direction" title="hb_font_get_glyph_origin_for_direction ()">hb_font_get_glyph_origin_for_direction</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-set-variation" title="hb_font_set_variation ()">hb_font_set_variation</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-origin-func-t" title="hb_font_get_glyph_origin_func_t ()">*hb_font_get_glyph_origin_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-set-var-named-instance" title="hb_font_set_var_named_instance ()">hb_font_set_var_named_instance</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
+<td class="function_type">unsigned <span class="returnvalue">int</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-advance" title="hb_font_get_glyph_v_advance ()">hb_font_get_glyph_v_advance</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-var-named-instance" title="hb_font_get_var_named_instance ()">hb_font_get_var_named_instance</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-advances" title="hb_font_get_glyph_v_advances ()">hb_font_get_glyph_v_advances</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-set-var-coords-design" title="hb_font_set_var_coords_design ()">hb_font_set_var_coords_design</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<td class="function_type">const <span class="returnvalue">float</span> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-origin" title="hb_font_get_glyph_v_origin ()">hb_font_get_glyph_v_origin</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-var-coords-design" title="hb_font_get_var_coords_design ()">hb_font_get_var_coords_design</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-nominal-glyph" title="hb_font_get_nominal_glyph ()">hb_font_get_nominal_glyph</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-set-var-coords-normalized" title="hb_font_set_var_coords_normalized ()">hb_font_set_var_coords_normalized</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">const <span class="returnvalue">int</span> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-var-coords-normalized" title="hb_font_get_var_coords_normalized ()">hb_font_get_var_coords_normalized</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-nominal-glyph-func-t" title="hb_font_get_nominal_glyph_func_t ()">*hb_font_get_nominal_glyph_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-glyph-from-string" title="hb_font_glyph_from_string ()">hb_font_glyph_from_string</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">unsigned <span class="returnvalue">int</span>
+<td class="function_type">
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-nominal-glyphs" title="hb_font_get_nominal_glyphs ()">hb_font_get_nominal_glyphs</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-glyph-to-string" title="hb_font_glyph_to_string ()">hb_font_glyph_to_string</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">unsigned <span class="returnvalue">int</span>
 </td>
 <td class="function_name">
-<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-nominal-glyphs-func-t" title="hb_font_get_nominal_glyphs_func_t ()">*hb_font_get_nominal_glyphs_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-serial" title="hb_font_get_serial ()">hb_font_get_serial</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="returnvalue">hb_font_t</span></a> *
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-parent" title="hb_font_get_parent ()">hb_font_get_parent</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-changed" title="hb_font_changed ()">hb_font_changed</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-ppem" title="hb_font_get_ppem ()">hb_font_get_ppem</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-set-funcs" title="hb_font_set_funcs ()">hb_font_set_funcs</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">float</span>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-ptem" title="hb_font_get_ptem ()">hb_font_get_ptem</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-set-funcs-data" title="hb_font_set_funcs_data ()">hb_font_set_funcs_data</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-scale" title="hb_font_get_scale ()">hb_font_get_scale</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-subtract-glyph-origin-for-direction" title="hb_font_subtract_glyph_origin_for_direction ()">hb_font_subtract_glyph_origin_for_direction</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">float</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="returnvalue">hb_font_funcs_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-synthetic-slant" title="hb_font_get_synthetic_slant ()">hb_font_get_synthetic_slant</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-create" title="hb_font_funcs_create ()">hb_font_funcs_create</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span> *
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="returnvalue">hb_font_funcs_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-user-data" title="hb_font_get_user_data ()">hb_font_get_user_data</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-get-empty" title="hb_font_funcs_get_empty ()">hb_font_funcs_get_empty</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="returnvalue">hb_font_funcs_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-variation-glyph" title="hb_font_get_variation_glyph ()">hb_font_get_variation_glyph</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-reference" title="hb_font_funcs_reference ()">hb_font_funcs_reference</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-variation-glyph-func-t" title="hb_font_get_variation_glyph_func_t ()">*hb_font_get_variation_glyph_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-destroy" title="hb_font_funcs_destroy ()">hb_font_funcs_destroy</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">const <span class="returnvalue">float</span> *
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-var-coords-design" title="hb_font_get_var_coords_design ()">hb_font_get_var_coords_design</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-user-data" title="hb_font_funcs_set_user_data ()">hb_font_funcs_set_user_data</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">const <span class="returnvalue">int</span> *
+<td class="function_type">
+<span class="returnvalue">void</span> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-var-coords-normalized" title="hb_font_get_var_coords_normalized ()">hb_font_get_var_coords_normalized</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-get-user-data" title="hb_font_funcs_get_user_data ()">hb_font_funcs_get_user_data</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-glyph-from-string" title="hb_font_glyph_from_string ()">hb_font_glyph_from_string</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-make-immutable" title="hb_font_funcs_make_immutable ()">hb_font_funcs_make_immutable</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-glyph-to-string" title="hb_font_glyph_to_string ()">hb_font_glyph_to_string</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-is-immutable" title="hb_font_funcs_is_immutable ()">hb_font_funcs_is_immutable</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-is-immutable" title="hb_font_is_immutable ()">hb_font_is_immutable</a> <span class="c_punctuation">()</span>
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-contour-point-func-t" title="hb_font_get_glyph_contour_point_func_t ()">*hb_font_get_glyph_contour_point_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-make-immutable" title="hb_font_make_immutable ()">hb_font_make_immutable</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-contour-point-func" title="hb_font_funcs_set_glyph_contour_point_func ()">hb_font_funcs_set_glyph_contour_point_func</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="returnvalue">hb_font_t</span></a> *
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-reference" title="hb_font_reference ()">hb_font_reference</a> <span class="c_punctuation">()</span>
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-extents-func-t" title="hb_font_get_glyph_extents_func_t ()">*hb_font_get_glyph_extents_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-set-face" title="hb_font_set_face ()">hb_font_set_face</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-extents-func" title="hb_font_funcs_set_glyph_extents_func ()">hb_font_funcs_set_glyph_extents_func</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-set-funcs" title="hb_font_set_funcs ()">hb_font_set_funcs</a> <span class="c_punctuation">()</span>
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-from-name-func-t" title="hb_font_get_glyph_from_name_func_t ()">*hb_font_get_glyph_from_name_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-set-funcs-data" title="hb_font_set_funcs_data ()">hb_font_set_funcs_data</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-from-name-func" title="hb_font_funcs_set_glyph_from_name_func ()">hb_font_funcs_set_glyph_from_name_func</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-set-parent" title="hb_font_set_parent ()">hb_font_set_parent</a> <span class="c_punctuation">()</span>
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-advance-func-t" title="hb_font_get_glyph_advance_func_t ()">*hb_font_get_glyph_advance_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-set-ppem" title="hb_font_set_ppem ()">hb_font_set_ppem</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-h-advance-func" title="hb_font_funcs_set_glyph_h_advance_func ()">hb_font_funcs_set_glyph_h_advance_func</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-set-ptem" title="hb_font_set_ptem ()">hb_font_set_ptem</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-v-advance-func" title="hb_font_funcs_set_glyph_v_advance_func ()">hb_font_funcs_set_glyph_v_advance_func</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-set-scale" title="hb_font_set_scale ()">hb_font_set_scale</a> <span class="c_punctuation">()</span>
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-advances-func-t" title="hb_font_get_glyph_advances_func_t ()">*hb_font_get_glyph_advances_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-set-synthetic-slant" title="hb_font_set_synthetic_slant ()">hb_font_set_synthetic_slant</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-h-advances-func" title="hb_font_funcs_set_glyph_h_advances_func ()">hb_font_funcs_set_glyph_h_advances_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-v-advances-func" title="hb_font_funcs_set_glyph_v_advances_func ()">hb_font_funcs_set_glyph_v_advances_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-kerning-func-t" title="hb_font_get_glyph_kerning_func_t ()">*hb_font_get_glyph_kerning_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-h-kerning-func" title="hb_font_funcs_set_glyph_h_kerning_func ()">hb_font_funcs_set_glyph_h_kerning_func</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-set-user-data" title="hb_font_set_user_data ()">hb_font_set_user_data</a> <span class="c_punctuation">()</span>
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-origin-func-t" title="hb_font_get_glyph_origin_func_t ()">*hb_font_get_glyph_origin_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-set-variations" title="hb_font_set_variations ()">hb_font_set_variations</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-h-origin-func" title="hb_font_funcs_set_glyph_h_origin_func ()">hb_font_funcs_set_glyph_h_origin_func</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-set-var-coords-design" title="hb_font_set_var_coords_design ()">hb_font_set_var_coords_design</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-v-origin-func" title="hb_font_funcs_set_glyph_v_origin_func ()">hb_font_funcs_set_glyph_v_origin_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-name-func-t" title="hb_font_get_glyph_name_func_t ()">*hb_font_get_glyph_name_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-set-var-coords-normalized" title="hb_font_set_var_coords_normalized ()">hb_font_set_var_coords_normalized</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-name-func" title="hb_font_funcs_set_glyph_name_func ()">hb_font_funcs_set_glyph_name_func</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-set-var-named-instance" title="hb_font_set_var_named_instance ()">hb_font_set_var_named_instance</a> <span class="c_punctuation">()</span>
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-draw-glyph-func-t" title="hb_font_draw_glyph_func_t ()">*hb_font_draw_glyph_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-subtract-glyph-origin-for-direction" title="hb_font_subtract_glyph_origin_for_direction ()">hb_font_subtract_glyph_origin_for_direction</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-draw-glyph-func" title="hb_font_funcs_set_draw_glyph_func ()">hb_font_funcs_set_draw_glyph_func</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="returnvalue">hb_blob_t</span></a> *
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-reference-table-func-t" title="hb_reference_table_func_t ()">*hb_reference_table_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph-func-t" title="hb_font_paint_glyph_func_t ()">*hb_font_paint_glyph_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-font-h-extents-func" title="hb_font_funcs_set_font_h_extents_func ()">hb_font_funcs_set_font_h_extents_func</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-paint-glyph-func" title="hb_font_funcs_set_paint_glyph_func ()">hb_font_funcs_set_paint_glyph_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-nominal-glyph-func-t" title="hb_font_get_nominal_glyph_func_t ()">*hb_font_get_nominal_glyph_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-font-v-extents-func" title="hb_font_funcs_set_font_v_extents_func ()">hb_font_funcs_set_font_v_extents_func</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-nominal-glyph-func" title="hb_font_funcs_set_nominal_glyph_func ()">hb_font_funcs_set_nominal_glyph_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">unsigned <span class="returnvalue">int</span>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-nominal-glyphs-func-t" title="hb_font_get_nominal_glyphs_func_t ()">*hb_font_get_nominal_glyphs_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-font.html#hb-font-get-extents-for-direction" title="hb_font_get_extents_for_direction ()">hb_font_get_extents_for_direction</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-nominal-glyphs-func" title="hb_font_funcs_set_nominal_glyphs_func ()">hb_font_funcs_set_nominal_glyphs_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-font-get-variation-glyph-func-t" title="hb_font_get_variation_glyph_func_t ()">*hb_font_get_variation_glyph_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-variation-glyph-func" title="hb_font_funcs_set_variation_glyph_func ()">hb_font_funcs_set_variation_glyph_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="returnvalue">hb_blob_t</span></a> *
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-font.html#hb-reference-table-func-t" title="hb_reference_table_func_t ()">*hb_reference_table_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 </tr>
 <tr>
 <td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-font-h-extents-func" title="hb_font_funcs_set_font_h_extents_func ()">hb_font_funcs_set_font_h_extents_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-set-font-v-extents-func" title="hb_font_funcs_set_font_v_extents_func ()">hb_font_funcs_set_font_v_extents_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
 <a class="link" href="harfbuzz-hb-font.html#hb-font-get-v-extents" title="hb_font_get_v_extents ()">hb_font_get_v_extents</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-font.html#hb-font-get-extents-for-direction" title="hb_font_get_extents_for_direction ()">hb_font_get_extents_for_direction</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
 </tbody>
 </table></div>
 </div>
 </colgroup>
 <tbody>
 <tr>
-<td class="typedef_keyword">typedef</td>
-<td class="function_name"><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t">hb_font_funcs_t</a></td>
+<td class="define_keyword">#define</td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-font.html#HB-FONT-NO-VAR-NAMED-INSTANCE:CAPS" title="HB_FONT_NO_VAR_NAMED_INSTANCE">HB_FONT_NO_VAR_NAMED_INSTANCE</a></td>
 </tr>
 <tr>
 <td class="typedef_keyword">typedef</td>
 </tr>
 <tr>
 <td class="typedef_keyword">typedef</td>
-<td class="function_name"><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-advances-func-t" title="hb_font_get_glyph_h_advances_func_t">hb_font_get_glyph_h_advances_func_t</a></td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-advance-func-t" title="hb_font_get_glyph_v_advance_func_t">hb_font_get_glyph_v_advance_func_t</a></td>
 </tr>
 <tr>
 <td class="typedef_keyword">typedef</td>
-<td class="function_name"><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-kerning-func-t" title="hb_font_get_glyph_h_kerning_func_t">hb_font_get_glyph_h_kerning_func_t</a></td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-advances-func-t" title="hb_font_get_glyph_h_advances_func_t">hb_font_get_glyph_h_advances_func_t</a></td>
 </tr>
 <tr>
 <td class="typedef_keyword">typedef</td>
-<td class="function_name"><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-origin-func-t" title="hb_font_get_glyph_h_origin_func_t">hb_font_get_glyph_h_origin_func_t</a></td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-advances-func-t" title="hb_font_get_glyph_v_advances_func_t">hb_font_get_glyph_v_advances_func_t</a></td>
 </tr>
 <tr>
 <td class="typedef_keyword">typedef</td>
-<td class="function_name"><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-advance-func-t" title="hb_font_get_glyph_v_advance_func_t">hb_font_get_glyph_v_advance_func_t</a></td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-kerning-func-t" title="hb_font_get_glyph_h_kerning_func_t">hb_font_get_glyph_h_kerning_func_t</a></td>
 </tr>
 <tr>
 <td class="typedef_keyword">typedef</td>
-<td class="function_name"><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-advances-func-t" title="hb_font_get_glyph_v_advances_func_t">hb_font_get_glyph_v_advances_func_t</a></td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-origin-func-t" title="hb_font_get_glyph_h_origin_func_t">hb_font_get_glyph_h_origin_func_t</a></td>
 </tr>
 <tr>
 <td class="typedef_keyword">typedef</td>
 </tr>
 <tr>
 <td class="typedef_keyword">typedef</td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t">hb_font_funcs_t</a></td>
+</tr>
+<tr>
+<td class="typedef_keyword">typedef</td>
 <td class="function_name"><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t">hb_font_t</a></td>
 </tr>
 <tr>
@@ -871,6 +969,10 @@ of font functions is defined by the virtual methods in
 <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a>.</p>
 <p>HarfBuzz provides a built-in set of lightweight default
 functions for each method in <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a>.</p>
+<p>The default font functions are implemented in terms of the
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> methods of the parent font object.  This allows
+client programs to override only the methods they need to, and
+otherwise inherit the parent font's implementation, if any.</p>
 </div>
 <div class="refsect1">
 <a name="harfbuzz-hb-font.functions_details"></a><h2>Functions</h2>
@@ -941,7 +1043,6 @@ has non-zero top 16-bits, those bits minus one are passed to
 of a variable font, instead of the default-instance.  This allows
 specifying which named-instance to load by default when creating the
 face.</div>
-<p><span class="annotation">[Xconstructor]</span></p>
 <div class="refsect3">
 <a name="hb-font-create.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
@@ -996,15 +1097,26 @@ replicating the parent's properties.</p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-destroy"></a><h3>hb_font_destroy ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_destroy (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
-<p>Decreases the reference count on the given font object. When the
-reference count reaches zero, the font is destroyed,
-freeing all memory.</p>
+<a name="hb-font-get-empty"></a><h3>hb_font_get_empty ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="returnvalue">hb_font_t</span></a> *
+hb_font_get_empty (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
+<p>Fetches the empty font object.</p>
+<div class="refsect3">
+<a name="hb-font-get-empty.returns"></a><h4>Returns</h4>
+<p>The empty font object. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-font-reference"></a><h3>hb_font_reference ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="returnvalue">hb_font_t</span></a> *
+hb_font_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
+<p>Increases the reference count on the given font object.</p>
 <p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
-<a name="hb-font-destroy.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-reference.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1018,33 +1130,25 @@ freeing all memory.</p>
 </tr></tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-font-funcs-create"></a><h3>hb_font_funcs_create ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="returnvalue">hb_font_funcs_t</span></a> *
-hb_font_funcs_create (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
-<p>Creates a new <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> structure of font functions.</p>
-<p><span class="annotation">[Xconstructor]</span></p>
 <div class="refsect3">
-<a name="hb-font-funcs-create.returns"></a><h4>Returns</h4>
-<p>The font-functions structure. </p>
+<a name="hb-font-reference.returns"></a><h4>Returns</h4>
+<p>The <em class="parameter"><code>font</code></em>
+object. </p>
 <p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-destroy"></a><h3>hb_font_funcs_destroy ()</h3>
+<a name="hb-font-destroy"></a><h3>hb_font_destroy ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_funcs_destroy (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>);</pre>
-<p>Decreases the reference count on a font-functions structure. When
-the reference count reaches zero, the font-functions structure is
-destroyed, freeing all memory.</p>
+hb_font_destroy (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
+<p>Decreases the reference count on the given font object. When the
+reference count reaches zero, the font is destroyed,
+freeing all memory.</p>
 <p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
-<a name="hb-font-funcs-destroy.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-destroy.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1052,8 +1156,8 @@ destroyed, freeing all memory.</p>
 <col width="200px" class="parameters_annotations">
 </colgroup>
 <tbody><tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>The font-functions structure</p></td>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr></tbody>
 </table></div>
@@ -1062,28 +1166,17 @@ destroyed, freeing all memory.</p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-get-empty"></a><h3>hb_font_funcs_get_empty ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="returnvalue">hb_font_funcs_t</span></a> *
-hb_font_funcs_get_empty (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
-<p>Fetches an empty font-functions structure.</p>
-<div class="refsect3">
-<a name="hb-font-funcs-get-empty.returns"></a><h4>Returns</h4>
-<p>The font-functions structure. </p>
-<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-font-funcs-get-user-data"></a><h3>hb_font_funcs_get_user_data ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span> *
-hb_font_funcs_get_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
-                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>);</pre>
-<p>Fetches the user data associated with the specified key,
-attached to the specified font-functions structure.</p>
+<a name="hb-font-set-user-data"></a><h3>hb_font_set_user_data ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_font_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
+                       <em class="parameter"><code><span class="type">void</span> *data</code></em>,
+                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
+                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
+<p>Attaches a user-data key/data pair to the specified font object.</p>
 <p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
-<a name="hb-font-funcs-get-user-data.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-set-user-data.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1092,61 +1185,87 @@ attached to the specified font-functions structure.</p>
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>The font-functions structure</p></td>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
 <td class="parameter_name"><p>key</p></td>
-<td class="parameter_description"><p>The user-data key to query</p></td>
+<td class="parameter_description"><p>The user-data key</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>data</p></td>
+<td class="parameter_description"><p>A pointer to the user data</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>replace</p></td>
+<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-funcs-get-user-data.returns"></a><h4>Returns</h4>
-<p>A pointer to the user data. </p>
-<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
+<a name="hb-font-set-user-data.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-is-immutable"></a><h3>hb_font_funcs_is_immutable ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_font_funcs_is_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>);</pre>
-<p>Tests whether a font-functions structure is immutable.</p>
+<a name="hb-font-get-user-data"></a><h3>hb_font_get_user_data ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span> *
+hb_font_get_user_data (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>);</pre>
+<p>Fetches the user-data object associated with the specified key,
+attached to the specified font object.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
-<a name="hb-font-funcs-is-immutable.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-user-data.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody><tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>The font-functions structure</p></td>
+<tbody>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
-</tr></tbody>
+</tr>
+<tr>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The user-data key to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-funcs-is-immutable.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if <em class="parameter"><code>ffuncs</code></em>
-is immutable, <code class="literal">false</code> otherwise</p>
+<a name="hb-font-get-user-data.returns"></a><h4>Returns</h4>
+<p>Pointer to the user data. </p>
+<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-make-immutable"></a><h3>hb_font_funcs_make_immutable ()</h3>
+<a name="hb-font-make-immutable"></a><h3>hb_font_make_immutable ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_funcs_make_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>);</pre>
-<p>Makes a font-functions structure immutable.</p>
+hb_font_make_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
+<p>Makes <em class="parameter"><code>font</code></em>
+ immutable.</p>
 <div class="refsect3">
-<a name="hb-font-funcs-make-immutable.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-make-immutable.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1154,8 +1273,8 @@ hb_font_funcs_make_immutable (<em class="parameter"><code><a class="link" href="
 <col width="200px" class="parameters_annotations">
 </colgroup>
 <tbody><tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>The font-functions structure</p></td>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr></tbody>
 </table></div>
@@ -1164,13 +1283,12 @@ hb_font_funcs_make_immutable (<em class="parameter"><code><a class="link" href="
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-reference"></a><h3>hb_font_funcs_reference ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="returnvalue">hb_font_funcs_t</span></a> *
-hb_font_funcs_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>);</pre>
-<p>Increases the reference count on a font-functions structure.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<a name="hb-font-is-immutable"></a><h3>hb_font_is_immutable ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_font_is_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
+<p>Tests whether a font object is immutable.</p>
 <div class="refsect3">
-<a name="hb-font-funcs-reference.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-is-immutable.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1178,30 +1296,30 @@ hb_font_funcs_reference (<em class="parameter"><code><a class="link" href="harfb
 <col width="200px" class="parameters_annotations">
 </colgroup>
 <tbody><tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>The font-functions structure</p></td>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr></tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-funcs-reference.returns"></a><h4>Returns</h4>
-<p> The font-functions structure</p>
+<a name="hb-font-is-immutable.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if <em class="parameter"><code>font</code></em>
+is immutable, <code class="literal">false</code> otherwise</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-set-glyph-contour-point-func"></a><h3>hb_font_funcs_set_glyph_contour_point_func ()</h3>
+<a name="hb-font-set-face"></a><h3>hb_font_set_face ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_funcs_set_glyph_contour_point_func
-                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-contour-point-func-t" title="hb_font_get_glyph_contour_point_func_t ()"><span class="type">hb_font_get_glyph_contour_point_func_t</span></a> func</code></em>,
-                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-contour-point-func-t" title="hb_font_get_glyph_contour_point_func_t ()"><span class="type">hb_font_get_glyph_contour_point_func_t</span></a>.</p>
+hb_font_set_face (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
+<p>Sets <em class="parameter"><code>face</code></em>
+ as the font-face value of <em class="parameter"><code>font</code></em>
+.</p>
 <div class="refsect3">
-<a name="hb-font-funcs-set-glyph-contour-point-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-set-face.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1210,89 +1328,63 @@ hb_font_funcs_set_glyph_contour_point_func
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>func</p></td>
-<td class="parameter_description"><p>The callback function to assign. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
-</p></td>
+<td class="parameter_name"><p>face</p></td>
+<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> to assign</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
-<tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
-</tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-1-4-3.html#api-index-1.4.3">1.4.3</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-set-glyph-extents-func"></a><h3>hb_font_funcs_set_glyph_extents_func ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_funcs_set_glyph_extents_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
-                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-extents-func-t" title="hb_font_get_glyph_extents_func_t ()"><span class="type">hb_font_get_glyph_extents_func_t</span></a> func</code></em>,
-                                      <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-extents-func-t" title="hb_font_get_glyph_extents_func_t ()"><span class="type">hb_font_get_glyph_extents_func_t</span></a>.</p>
+<a name="hb-font-get-face"></a><h3>hb_font_get_face ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
+hb_font_get_face (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
+<p>Fetches the face associated with the specified font object.</p>
 <div class="refsect3">
-<a name="hb-font-funcs-set-glyph-extents-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-face.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>A font-function structure</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>func</p></td>
-<td class="parameter_description"><p>The callback function to assign. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
-</p></td>
+<tbody><tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
-</tr>
-</tbody>
+</tr></tbody>
 </table></div>
 </div>
+<div class="refsect3">
+<a name="hb-font-get-face.returns"></a><h4>Returns</h4>
+<p>The <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> value. </p>
+<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
+</div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-set-glyph-from-name-func"></a><h3>hb_font_funcs_set_glyph_from_name_func ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_funcs_set_glyph_from_name_func
-                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-from-name-func-t" title="hb_font_get_glyph_from_name_func_t ()"><span class="type">hb_font_get_glyph_from_name_func_t</span></a> func</code></em>,
-                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-from-name-func-t" title="hb_font_get_glyph_from_name_func_t ()"><span class="type">hb_font_get_glyph_from_name_func_t</span></a>.</p>
+<a name="hb-font-get-glyph"></a><h3>hb_font_get_glyph ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_font_get_glyph (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>,
+                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> variation_selector</code></em>,
+                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *glyph</code></em>);</pre>
+<p>Fetches the glyph ID for a Unicode code point in the specified
+font, with an optional variation selector.</p>
+<p>If <em class="parameter"><code>variation_selector</code></em>
+ is 0, calls <a class="link" href="harfbuzz-hb-font.html#hb-font-get-nominal-glyph" title="hb_font_get_nominal_glyph ()"><code class="function">hb_font_get_nominal_glyph()</code></a>;
+otherwise calls <a class="link" href="harfbuzz-hb-font.html#hb-font-get-variation-glyph" title="hb_font_get_variation_glyph ()"><code class="function">hb_font_get_variation_glyph()</code></a>.</p>
 <div class="refsect3">
-<a name="hb-font-funcs-set-glyph-from-name-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1301,44 +1393,51 @@ hb_font_funcs_set_glyph_from_name_func
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>func</p></td>
-<td class="parameter_description"><p>The callback function to assign. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+<td class="parameter_name"><p>unicode</p></td>
+<td class="parameter_description"><p>The Unicode code point to query</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
-</p></td>
+<td class="parameter_name"><p>variation_selector</p></td>
+<td class="parameter_description"><p>A variation-selector code point</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
 </div>
+<div class="refsect3">
+<a name="hb-font-get-glyph.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
+</div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-set-glyph-h-advance-func"></a><h3>hb_font_funcs_set_glyph_h_advance_func ()</h3>
+<a name="hb-font-get-glyph-advance-for-direction"></a><h3>hb_font_get_glyph_advance_for_direction ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_funcs_set_glyph_h_advance_func
-                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-advance-func-t" title="hb_font_get_glyph_h_advance_func_t"><span class="type">hb_font_get_glyph_h_advance_func_t</span></a> func</code></em>,
-                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-advance-func-t" title="hb_font_get_glyph_h_advance_func_t"><span class="type">hb_font_get_glyph_h_advance_func_t</span></a>.</p>
+hb_font_get_glyph_advance_for_direction
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *x</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *y</code></em>);</pre>
+<p>Fetches the advance for a glyph ID from the specified font,
+in a text segment of the specified direction.</p>
+<p>Calls the appropriate direction-specific variant (horizontal
+or vertical) depending on the value of <em class="parameter"><code>direction</code></em>
+.</p>
 <div class="refsect3">
-<a name="hb-font-funcs-set-glyph-h-advance-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-advance-for-direction.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1347,26 +1446,29 @@ hb_font_funcs_set_glyph_h_advance_func
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>func</p></td>
-<td class="parameter_description"><p>The callback function to assign. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
-</p></td>
+<td class="parameter_name"><p>direction</p></td>
+<td class="parameter_description"><p>The direction of the text segment</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+<td class="parameter_name"><p>x</p></td>
+<td class="parameter_description"><p>The horizontal advance retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y</p></td>
+<td class="parameter_description"><p>The vertical advance retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
@@ -1375,16 +1477,23 @@ is not needed anymore. </p></td>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-set-glyph-h-advances-func"></a><h3>hb_font_funcs_set_glyph_h_advances_func ()</h3>
+<a name="hb-font-get-glyph-advances-for-direction"></a><h3>hb_font_get_glyph_advances_for_direction ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_funcs_set_glyph_h_advances_func
-                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-advances-func-t" title="hb_font_get_glyph_h_advances_func_t"><span class="type">hb_font_get_glyph_h_advances_func_t</span></a> func</code></em>,
-                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-advances-func-t" title="hb_font_get_glyph_h_advances_func_t"><span class="type">hb_font_get_glyph_h_advances_func_t</span></a>.</p>
+hb_font_get_glyph_advances_for_direction
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
+                                <em class="parameter"><code>unsigned <span class="type">int</span> count</code></em>,
+                                <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *first_glyph</code></em>,
+                                <em class="parameter"><code><span class="type">unsigned </span> glyph_stride</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *first_advance</code></em>,
+                                <em class="parameter"><code><span class="type">unsigned </span> advance_stride</code></em>);</pre>
+<p>Fetches the advances for a sequence of glyph IDs in the specified
+font, in a text segment of the specified direction.</p>
+<p>Calls the appropriate direction-specific variant (horizontal
+or vertical) depending on the value of <em class="parameter"><code>direction</code></em>
+.</p>
 <div class="refsect3">
-<a name="hb-font-funcs-set-glyph-h-advances-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-advances-for-direction.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1393,26 +1502,39 @@ hb_font_funcs_set_glyph_h_advances_func
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>func</p></td>
-<td class="parameter_description"><p>The callback function to assign. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+<td class="parameter_name"><p>direction</p></td>
+<td class="parameter_description"><p>The direction of the text segment</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
-</p></td>
+<td class="parameter_name"><p>count</p></td>
+<td class="parameter_description"><p>The number of glyph IDs in the sequence queried</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+<td class="parameter_name"><p>first_glyph</p></td>
+<td class="parameter_description"><p>The first glyph ID to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>glyph_stride</p></td>
+<td class="parameter_description"><p>The stride between successive glyph IDs</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>first_advance</p></td>
+<td class="parameter_description"><p>The first advance retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>advance_stride</p></td>
+<td class="parameter_description"><p>The stride between successive advances. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
@@ -1421,16 +1543,17 @@ is not needed anymore. </p></td>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-set-glyph-h-kerning-func"></a><h3>hb_font_funcs_set_glyph_h_kerning_func ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_funcs_set_glyph_h_kerning_func
-                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-kerning-func-t" title="hb_font_get_glyph_h_kerning_func_t"><span class="type">hb_font_get_glyph_h_kerning_func_t</span></a> func</code></em>,
-                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-kerning-func-t" title="hb_font_get_glyph_h_kerning_func_t"><span class="type">hb_font_get_glyph_h_kerning_func_t</span></a>.</p>
+<a name="hb-font-get-glyph-contour-point"></a><h3>hb_font_get_glyph_contour_point ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_font_get_glyph_contour_point (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                 <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                                 <em class="parameter"><code>unsigned <span class="type">int</span> point_index</code></em>,
+                                 <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *x</code></em>,
+                                 <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *y</code></em>);</pre>
+<p>Fetches the (x,y) coordinates of a specified contour-point index
+in the specified glyph, within the specified font.</p>
 <div class="refsect3">
-<a name="hb-font-funcs-set-glyph-h-kerning-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-contour-point.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1439,43 +1562,58 @@ hb_font_funcs_set_glyph_h_kerning_func
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>func</p></td>
-<td class="parameter_description"><p>The callback function to assign. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
-</p></td>
+<td class="parameter_name"><p>point_index</p></td>
+<td class="parameter_description"><p>The contour-point index to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+<td class="parameter_name"><p>x</p></td>
+<td class="parameter_description"><p>The X value retrieved for the contour point. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y</p></td>
+<td class="parameter_description"><p>The Y value retrieved for the contour point. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
 </div>
+<div class="refsect3">
+<a name="hb-font-get-glyph-contour-point.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
+</div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-set-glyph-h-origin-func"></a><h3>hb_font_funcs_set_glyph_h_origin_func ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_funcs_set_glyph_h_origin_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
-                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-origin-func-t" title="hb_font_get_glyph_h_origin_func_t"><span class="type">hb_font_get_glyph_h_origin_func_t</span></a> func</code></em>,
-                                       <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-origin-func-t" title="hb_font_get_glyph_h_origin_func_t"><span class="type">hb_font_get_glyph_h_origin_func_t</span></a>.</p>
+<a name="hb-font-get-glyph-contour-point-for-origin"></a><h3>hb_font_get_glyph_contour_point_for_origin ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_font_get_glyph_contour_point_for_origin
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                                <em class="parameter"><code>unsigned <span class="type">int</span> point_index</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *x</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *y</code></em>);</pre>
+<p>Fetches the (X,Y) coordinates of a specified contour-point index
+in the specified glyph ID in the specified font, with respect
+to the origin in a text segment in the specified direction.</p>
+<p>Calls the appropriate direction-specific variant (horizontal
+or vertical) depending on the value of <em class="parameter"><code>direction</code></em>
+.</p>
 <div class="refsect3">
-<a name="hb-font-funcs-set-glyph-h-origin-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-contour-point-for-origin.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1484,43 +1622,55 @@ hb_font_funcs_set_glyph_h_origin_func (<em class="parameter"><code><a class="lin
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>func</p></td>
-<td class="parameter_description"><p>The callback function to assign. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
-</p></td>
+<td class="parameter_name"><p>point_index</p></td>
+<td class="parameter_description"><p>The contour-point index to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+<td class="parameter_name"><p>direction</p></td>
+<td class="parameter_description"><p>The direction of the text segment</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x</p></td>
+<td class="parameter_description"><p>The X value retrieved for the contour point. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y</p></td>
+<td class="parameter_description"><p>The Y value retrieved for the contour point. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
 </div>
+<div class="refsect3">
+<a name="hb-font-get-glyph-contour-point-for-origin.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
+</div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-set-glyph-name-func"></a><h3>hb_font_funcs_set_glyph_name_func ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_funcs_set_glyph_name_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
-                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-name-func-t" title="hb_font_get_glyph_name_func_t ()"><span class="type">hb_font_get_glyph_name_func_t</span></a> func</code></em>,
-                                   <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-name-func-t" title="hb_font_get_glyph_name_func_t ()"><span class="type">hb_font_get_glyph_name_func_t</span></a>.</p>
+<a name="hb-font-get-glyph-extents"></a><h3>hb_font_get_glyph_extents ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_font_get_glyph_extents (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                           <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                           <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-glyph-extents-t" title="hb_glyph_extents_t"><span class="type">hb_glyph_extents_t</span></a> *extents</code></em>);</pre>
+<p>Fetches the <a class="link" href="harfbuzz-hb-font.html#hb-glyph-extents-t" title="hb_glyph_extents_t"><span class="type">hb_glyph_extents_t</span></a> data for a glyph ID
+in the specified font.</p>
 <div class="refsect3">
-<a name="hb-font-funcs-set-glyph-name-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-extents.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1529,44 +1679,45 @@ hb_font_funcs_set_glyph_name_func (<em class="parameter"><code><a class="link" h
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>func</p></td>
-<td class="parameter_description"><p>The callback function to assign. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
-</p></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+<td class="parameter_name"><p>extents</p></td>
+<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-font.html#hb-glyph-extents-t" title="hb_glyph_extents_t"><span class="type">hb_glyph_extents_t</span></a> retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
 </div>
+<div class="refsect3">
+<a name="hb-font-get-glyph-extents.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
+</div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-set-glyph-v-advance-func"></a><h3>hb_font_funcs_set_glyph_v_advance_func ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_funcs_set_glyph_v_advance_func
-                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-advance-func-t" title="hb_font_get_glyph_v_advance_func_t"><span class="type">hb_font_get_glyph_v_advance_func_t</span></a> func</code></em>,
-                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-advance-func-t" title="hb_font_get_glyph_v_advance_func_t"><span class="type">hb_font_get_glyph_v_advance_func_t</span></a>.</p>
+<a name="hb-font-get-glyph-extents-for-origin"></a><h3>hb_font_get_glyph_extents_for_origin ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_font_get_glyph_extents_for_origin (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
+                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-glyph-extents-t" title="hb_glyph_extents_t"><span class="type">hb_glyph_extents_t</span></a> *extents</code></em>);</pre>
+<p>Fetches the <a class="link" href="harfbuzz-hb-font.html#hb-glyph-extents-t" title="hb_glyph_extents_t"><span class="type">hb_glyph_extents_t</span></a> data for a glyph ID
+in the specified font, with respect to the origin in
+a text segment in the specified direction.</p>
+<p>Calls the appropriate direction-specific variant (horizontal
+or vertical) depending on the value of <em class="parameter"><code>direction</code></em>
+.</p>
 <div class="refsect3">
-<a name="hb-font-funcs-set-glyph-v-advance-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-extents-for-origin.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1575,44 +1726,47 @@ hb_font_funcs_set_glyph_v_advance_func
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>func</p></td>
-<td class="parameter_description"><p>The callback function to assign. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
-</p></td>
+<td class="parameter_name"><p>direction</p></td>
+<td class="parameter_description"><p>The direction of the text segment</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+<td class="parameter_name"><p>extents</p></td>
+<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-font.html#hb-glyph-extents-t" title="hb_glyph_extents_t"><span class="type">hb_glyph_extents_t</span></a> retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
 </div>
+<div class="refsect3">
+<a name="hb-font-get-glyph-extents-for-origin.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
+</div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-set-glyph-v-advances-func"></a><h3>hb_font_funcs_set_glyph_v_advances_func ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_funcs_set_glyph_v_advances_func
-                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-advances-func-t" title="hb_font_get_glyph_v_advances_func_t"><span class="type">hb_font_get_glyph_v_advances_func_t</span></a> func</code></em>,
-                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-advances-func-t" title="hb_font_get_glyph_v_advances_func_t"><span class="type">hb_font_get_glyph_v_advances_func_t</span></a>.</p>
+<a name="hb-font-get-glyph-from-name"></a><h3>hb_font_get_glyph_from_name ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_font_get_glyph_from_name (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                             <em class="parameter"><code>const <span class="type">char</span> *name</code></em>,
+                             <em class="parameter"><code><span class="type">int</span> len</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *glyph</code></em>);</pre>
+<p>Fetches the glyph ID that corresponds to a name string in the specified <em class="parameter"><code>font</code></em>
+.</p>
+<div class="note">Note: <em class="parameter"><code>len</code></em> == -1 means the name string is null-terminated.</div>
 <div class="refsect3">
-<a name="hb-font-funcs-set-glyph-v-advances-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-from-name.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1621,43 +1775,44 @@ hb_font_funcs_set_glyph_v_advances_func
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>func</p></td>
-<td class="parameter_description"><p>The callback function to assign. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+<td class="parameter_name"><p>name</p></td>
+<td class="parameter_description"><p>The name string to query. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=len]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
-</p></td>
+<td class="parameter_name"><p>len</p></td>
+<td class="parameter_description"><p>The length of the name queried</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-1-8-6.html#api-index-1.8.6">1.8.6</a></p>
+<div class="refsect3">
+<a name="hb-font-get-glyph-from-name.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-set-glyph-v-origin-func"></a><h3>hb_font_funcs_set_glyph_v_origin_func ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_funcs_set_glyph_v_origin_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
-                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-origin-func-t" title="hb_font_get_glyph_v_origin_func_t"><span class="type">hb_font_get_glyph_v_origin_func_t</span></a> func</code></em>,
-                                       <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-origin-func-t" title="hb_font_get_glyph_v_origin_func_t"><span class="type">hb_font_get_glyph_v_origin_func_t</span></a>.</p>
+<a name="hb-font-get-glyph-h-advance"></a><h3>hb_font_get_glyph_h_advance ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
+hb_font_get_glyph_h_advance (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>);</pre>
+<p>Fetches the advance for a glyph ID in the specified font,
+for horizontal text segments.</p>
 <div class="refsect3">
-<a name="hb-font-funcs-set-glyph-v-origin-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-h-advance.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1666,43 +1821,36 @@ hb_font_funcs_set_glyph_v_origin_func (<em class="parameter"><code><a class="lin
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>func</p></td>
-<td class="parameter_description"><p>The callback function to assign. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
-</p></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
-<tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
-</tr>
 </tbody>
 </table></div>
 </div>
+<div class="refsect3">
+<a name="hb-font-get-glyph-h-advance.returns"></a><h4>Returns</h4>
+<p> The advance of <em class="parameter"><code>glyph</code></em>
+within <em class="parameter"><code>font</code></em>
+</p>
+</div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-set-nominal-glyph-func"></a><h3>hb_font_funcs_set_nominal_glyph_func ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_funcs_set_nominal_glyph_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
-                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-nominal-glyph-func-t" title="hb_font_get_nominal_glyph_func_t ()"><span class="type">hb_font_get_nominal_glyph_func_t</span></a> func</code></em>,
-                                      <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-nominal-glyph-func-t" title="hb_font_get_nominal_glyph_func_t ()"><span class="type">hb_font_get_nominal_glyph_func_t</span></a>.</p>
+<a name="hb-font-get-glyph-v-advance"></a><h3>hb_font_get_glyph_v_advance ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
+hb_font_get_glyph_v_advance (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>);</pre>
+<p>Fetches the advance for a glyph ID in the specified font,
+for vertical text segments.</p>
 <div class="refsect3">
-<a name="hb-font-funcs-set-nominal-glyph-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-v-advance.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1711,43 +1859,40 @@ hb_font_funcs_set_nominal_glyph_func (<em class="parameter"><code><a class="link
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>func</p></td>
-<td class="parameter_description"><p>The callback function to assign. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
-</p></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
-<tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
-</tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-1-2-3.html#api-index-1.2.3">1.2.3</a></p>
+<div class="refsect3">
+<a name="hb-font-get-glyph-v-advance.returns"></a><h4>Returns</h4>
+<p> The advance of <em class="parameter"><code>glyph</code></em>
+within <em class="parameter"><code>font</code></em>
+</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-set-nominal-glyphs-func"></a><h3>hb_font_funcs_set_nominal_glyphs_func ()</h3>
+<a name="hb-font-get-glyph-h-advances"></a><h3>hb_font_get_glyph_h_advances ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_funcs_set_nominal_glyphs_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
-                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-nominal-glyphs-func-t" title="hb_font_get_nominal_glyphs_func_t ()"><span class="type">hb_font_get_nominal_glyphs_func_t</span></a> func</code></em>,
-                                       <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-nominal-glyphs-func-t" title="hb_font_get_nominal_glyphs_func_t ()"><span class="type">hb_font_get_nominal_glyphs_func_t</span></a>.</p>
+hb_font_get_glyph_h_advances (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                              <em class="parameter"><code>unsigned <span class="type">int</span> count</code></em>,
+                              <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *first_glyph</code></em>,
+                              <em class="parameter"><code><span class="type">unsigned </span> glyph_stride</code></em>,
+                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *first_advance</code></em>,
+                              <em class="parameter"><code><span class="type">unsigned </span> advance_stride</code></em>);</pre>
+<p>Fetches the advances for a sequence of glyph IDs in the specified
+font, for horizontal text segments.</p>
 <div class="refsect3">
-<a name="hb-font-funcs-set-nominal-glyphs-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-h-advances.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1756,45 +1901,54 @@ hb_font_funcs_set_nominal_glyphs_func (<em class="parameter"><code><a class="lin
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>func</p></td>
-<td class="parameter_description"><p>The callback function to assign. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+<td class="parameter_name"><p>count</p></td>
+<td class="parameter_description"><p>The number of glyph IDs in the sequence queried</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
-</p></td>
+<td class="parameter_name"><p>first_glyph</p></td>
+<td class="parameter_description"><p>The first glyph ID to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+<td class="parameter_name"><p>glyph_stride</p></td>
+<td class="parameter_description"><p>The stride between successive glyph IDs</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>first_advance</p></td>
+<td class="parameter_description"><p>The first advance retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>advance_stride</p></td>
+<td class="parameter_description"><p>The stride between successive advances</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-2-0-0.html#api-index-2.0.0">2.0.0</a></p>
+<p class="since">Since: <a class="link" href="api-index-1-8-6.html#api-index-1.8.6">1.8.6</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-set-user-data"></a><h3>hb_font_funcs_set_user_data ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_font_funcs_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
-                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
-                             <em class="parameter"><code><span class="type">void</span> *data</code></em>,
-                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
-                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
-<p>Attaches a user-data key/data pair to the specified font-functions structure.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<a name="hb-font-get-glyph-v-advances"></a><h3>hb_font_get_glyph_v_advances ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_get_glyph_v_advances (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                              <em class="parameter"><code>unsigned <span class="type">int</span> count</code></em>,
+                              <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *first_glyph</code></em>,
+                              <em class="parameter"><code><span class="type">unsigned </span> glyph_stride</code></em>,
+                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *first_advance</code></em>,
+                              <em class="parameter"><code><span class="type">unsigned </span> advance_stride</code></em>);</pre>
+<p>Fetches the advances for a sequence of glyph IDs in the specified
+font, for vertical text segments.</p>
 <div class="refsect3">
-<a name="hb-font-funcs-set-user-data.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-v-advances.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1803,52 +1957,53 @@ hb_font_funcs_set_user_data (<em class="parameter"><code><a class="link" href="h
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>The font-functions structure</p></td>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>key</p></td>
-<td class="parameter_description"><p>The user-data key to set</p></td>
+<td class="parameter_name"><p>count</p></td>
+<td class="parameter_description"><p>The number of glyph IDs in the sequence queried</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>data</p></td>
-<td class="parameter_description"><p>A pointer to the user data set</p></td>
+<td class="parameter_name"><p>first_glyph</p></td>
+<td class="parameter_description"><p>The first glyph ID to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+<td class="parameter_name"><p>glyph_stride</p></td>
+<td class="parameter_description"><p>The stride between successive glyph IDs</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>replace</p></td>
-<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_name"><p>first_advance</p></td>
+<td class="parameter_description"><p>The first advance retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>advance_stride</p></td>
+<td class="parameter_description"><p>The stride between successive advances. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-font-funcs-set-user-data.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-1-8-6.html#api-index-1.8.6">1.8.6</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-funcs-set-variation-glyph-func"></a><h3>hb_font_funcs_set_variation_glyph_func ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_funcs_set_variation_glyph_func
-                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-variation-glyph-func-t" title="hb_font_get_variation_glyph_func_t ()"><span class="type">hb_font_get_variation_glyph_func_t</span></a> func</code></em>,
-                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-variation-glyph-func-t" title="hb_font_get_variation_glyph_func_t ()"><span class="type">hb_font_get_variation_glyph_func_t</span></a>.</p>
+<a name="hb-font-get-glyph-h-kerning"></a><h3>hb_font_get_glyph_h_kerning ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
+hb_font_get_glyph_h_kerning (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> left_glyph</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> right_glyph</code></em>);</pre>
+<p>Fetches the kerning-adjustment value for a glyph-pair in
+the specified font, for horizontal text segments.</p>
+<div class="note">It handles legacy kerning only (as returned by the corresponding
+<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> function).</div>
 <div class="refsect3">
-<a name="hb-font-funcs-set-variation-glyph-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-h-kerning.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1857,88 +2012,148 @@ hb_font_funcs_set_variation_glyph_func
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>ffuncs</p></td>
-<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>func</p></td>
-<td class="parameter_description"><p>The callback function to assign. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+<td class="parameter_name"><p>left_glyph</p></td>
+<td class="parameter_description"><p>The glyph ID of the left glyph in the glyph pair</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
-</p></td>
+<td class="parameter_name"><p>right_glyph</p></td>
+<td class="parameter_description"><p>The glyph ID of the right glyph in the glyph pair</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
-<tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
-</tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-1-2-3.html#api-index-1.2.3">1.2.3</a></p>
+<div class="refsect3">
+<a name="hb-font-get-glyph-h-kerning.returns"></a><h4>Returns</h4>
+<p> The kerning adjustment value</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-empty"></a><h3>hb_font_get_empty ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="returnvalue">hb_font_t</span></a> *
-hb_font_get_empty (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
-<p>Fetches the empty font object.</p>
+<a name="hb-font-get-glyph-kerning-for-direction"></a><h3>hb_font_get_glyph_kerning_for_direction ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_get_glyph_kerning_for_direction
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> first_glyph</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> second_glyph</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *x</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *y</code></em>);</pre>
+<p>Fetches the kerning-adjustment value for a glyph-pair in the specified font.</p>
+<p>Calls the appropriate direction-specific variant (horizontal
+or vertical) depending on the value of <em class="parameter"><code>direction</code></em>
+.</p>
 <div class="refsect3">
-<a name="hb-font-get-empty.returns"></a><h4>Returns</h4>
-<p>The empty font object. </p>
-<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+<a name="hb-font-get-glyph-kerning-for-direction.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>first_glyph</p></td>
+<td class="parameter_description"><p>The glyph ID of the first glyph in the glyph pair to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>second_glyph</p></td>
+<td class="parameter_description"><p>The glyph ID of the second glyph in the glyph pair to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>direction</p></td>
+<td class="parameter_description"><p>The direction of the text segment</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x</p></td>
+<td class="parameter_description"><p>The horizontal kerning-adjustment value retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y</p></td>
+<td class="parameter_description"><p>The vertical kerning-adjustment value retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-face"></a><h3>hb_font_get_face ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
-hb_font_get_face (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
-<p>Fetches the face associated with the specified font object.</p>
+<a name="hb-font-get-glyph-h-origin"></a><h3>hb_font_get_glyph_h_origin ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_font_get_glyph_h_origin (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *x</code></em>,
+                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *y</code></em>);</pre>
+<p>Fetches the (X,Y) coordinates of the origin for a glyph ID
+in the specified font, for horizontal text segments.</p>
 <div class="refsect3">
-<a name="hb-font-get-face.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-h-origin.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody><tr>
+<tbody>
+<tr>
 <td class="parameter_name"><p>font</p></td>
 <td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
-</tr></tbody>
+</tr>
+<tr>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x</p></td>
+<td class="parameter_description"><p>The X coordinate of the origin. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y</p></td>
+<td class="parameter_description"><p>The Y coordinate of the origin. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+</tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-get-face.returns"></a><h4>Returns</h4>
-<p>The <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> value. </p>
-<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
+<a name="hb-font-get-glyph-h-origin.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph"></a><h3>hb_font_get_glyph ()</h3>
+<a name="hb-font-get-glyph-v-origin"></a><h3>hb_font_get_glyph_v_origin ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_font_get_glyph (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>,
-                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> variation_selector</code></em>,
-                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *glyph</code></em>);</pre>
-<p>Fetches the glyph ID for a Unicode code point in the specified
-font, with an optional variation selector.</p>
-<p>If <em class="parameter"><code>variation_selector</code></em>
- is 0, calls <a class="link" href="harfbuzz-hb-font.html#hb-font-get-nominal-glyph" title="hb_font_get_nominal_glyph ()"><code class="function">hb_font_get_nominal_glyph()</code></a>;
-otherwise calls <a class="link" href="harfbuzz-hb-font.html#hb-font-get-variation-glyph" title="hb_font_get_variation_glyph ()"><code class="function">hb_font_get_variation_glyph()</code></a>.</p>
+hb_font_get_glyph_v_origin (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *x</code></em>,
+                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *y</code></em>);</pre>
+<p>Fetches the (X,Y) coordinates of the origin for a glyph ID
+in the specified font, for vertical text segments.</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-v-origin.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1952,46 +2167,46 @@ otherwise calls <a class="link" href="harfbuzz-hb-font.html#hb-font-get-variatio
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>unicode</p></td>
-<td class="parameter_description"><p>The Unicode code point to query</p></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>variation_selector</p></td>
-<td class="parameter_description"><p>A variation-selector code point</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_name"><p>x</p></td>
+<td class="parameter_description"><p>The X coordinate of the origin. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID retrieved. </p></td>
+<td class="parameter_name"><p>y</p></td>
+<td class="parameter_description"><p>The Y coordinate of the origin. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-get-glyph.returns"></a><h4>Returns</h4>
+<a name="hb-font-get-glyph-v-origin.returns"></a><h4>Returns</h4>
 <p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-advance-for-direction"></a><h3>hb_font_get_glyph_advance_for_direction ()</h3>
+<a name="hb-font-get-glyph-origin-for-direction"></a><h3>hb_font_get_glyph_origin_for_direction ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_get_glyph_advance_for_direction
+hb_font_get_glyph_origin_for_direction
                                (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
                                 <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
                                 <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
                                 <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *x</code></em>,
                                 <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *y</code></em>);</pre>
-<p>Fetches the advance for a glyph ID from the specified font,
-in a text segment of the specified direction.</p>
+<p>Fetches the (X,Y) coordinates of the origin for a glyph in
+the specified font.</p>
 <p>Calls the appropriate direction-specific variant (horizontal
 or vertical) depending on the value of <em class="parameter"><code>direction</code></em>
 .</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph-advance-for-direction.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-origin-for-direction.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -2016,12 +2231,12 @@ or vertical) depending on the value of <em class="parameter"><code>direction</co
 </tr>
 <tr>
 <td class="parameter_name"><p>x</p></td>
-<td class="parameter_description"><p>The horizontal advance retrieved. </p></td>
+<td class="parameter_description"><p>The X coordinate retrieved for the origin. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 <tr>
 <td class="parameter_name"><p>y</p></td>
-<td class="parameter_description"><p>The vertical advance retrieved. </p></td>
+<td class="parameter_description"><p>The Y coordinate retrieved for the origin. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
@@ -2031,17 +2246,18 @@ or vertical) depending on the value of <em class="parameter"><code>direction</co
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-advance-func-t"></a><h3>hb_font_get_glyph_advance_func_t ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
-<span class="c_punctuation">(</span>*hb_font_get_glyph_advance_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                     <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
-                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
-                                     <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
-<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
-<p>This method should retrieve the advance for a specified glyph. The
-method must return an <a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a>.</p>
+<a name="hb-font-get-glyph-name"></a><h3>hb_font_get_glyph_name ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_font_get_glyph_name (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                        <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                        <em class="parameter"><code><span class="type">char</span> *name</code></em>,
+                        <em class="parameter"><code>unsigned <span class="type">int</span> size</code></em>);</pre>
+<p>Fetches the glyph-name string for a glyph ID in the specified <em class="parameter"><code>font</code></em>
+.</p>
+<p>According to the OpenType specification, glyph names are limited to 63
+characters and can only contain (a subset of) ASCII.</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph-advance-func-t.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-name.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -2055,50 +2271,45 @@ method must return an <a class="link" href="harfbuzz-hb-common.html#hb-position-
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>font_data</p></td>
-<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
-user data pointer</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
 <td class="parameter_name"><p>glyph</p></td>
 <td class="parameter_description"><p>The glyph ID to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_name"><p>name</p></td>
+<td class="parameter_description"><p>Name string retrieved for the glyph ID. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=size]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>size</p></td>
+<td class="parameter_description"><p>Length of the glyph-name string retrieved</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-get-glyph-advance-func-t.returns"></a><h4>Returns</h4>
-<p> The advance of <em class="parameter"><code>glyph</code></em>
-within <em class="parameter"><code>font</code></em>
-</p>
+<a name="hb-font-get-glyph-name.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
 </div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-advances-for-direction"></a><h3>hb_font_get_glyph_advances_for_direction ()</h3>
+<a name="hb-font-draw-glyph"></a><h3>hb_font_draw_glyph ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_get_glyph_advances_for_direction
-                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
-                                <em class="parameter"><code>unsigned <span class="type">int</span> count</code></em>,
-                                <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *first_glyph</code></em>,
-                                <em class="parameter"><code><span class="type">unsigned </span> glyph_stride</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *first_advance</code></em>,
-                                <em class="parameter"><code><span class="type">unsigned </span> advance_stride</code></em>);</pre>
-<p>Fetches the advances for a sequence of glyph IDs in the specified
-font, in a text segment of the specified direction.</p>
-<p>Calls the appropriate direction-specific variant (horizontal
-or vertical) depending on the value of <em class="parameter"><code>direction</code></em>
+hb_font_draw_glyph (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *dfuncs</code></em>,
+                    <em class="parameter"><code><span class="type">void</span> *draw_data</code></em>);</pre>
+<p>Draws the outline that corresponds to a glyph in the specified <em class="parameter"><code>font</code></em>
 .</p>
+<p>The outline is returned by way of calls to the callbacks of the <em class="parameter"><code>dfuncs</code></em>
+
+objects, with <em class="parameter"><code>draw_data</code></em>
+ passed to them.</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph-advances-for-direction.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-draw-glyph.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -2112,56 +2323,47 @@ or vertical) depending on the value of <em class="parameter"><code>direction</co
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>direction</p></td>
-<td class="parameter_description"><p>The direction of the text segment</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>count</p></td>
-<td class="parameter_description"><p>The number of glyph IDs in the sequence queried</p></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>first_glyph</p></td>
-<td class="parameter_description"><p>The first glyph ID to query</p></td>
+<td class="parameter_name"><p>dfuncs</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> to draw to</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>glyph_stride</p></td>
-<td class="parameter_description"><p>The stride between successive glyph IDs</p></td>
+<td class="parameter_name"><p>draw_data</p></td>
+<td class="parameter_description"><p>User data to pass to draw callbacks</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
-<tr>
-<td class="parameter_name"><p>first_advance</p></td>
-<td class="parameter_description"><p>The first advance retrieved. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>advance_stride</p></td>
-<td class="parameter_description"><p>The stride between successive advances. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-1-8-6.html#api-index-1.8.6">1.8.6</a></p>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-advances-func-t"></a><h3>hb_font_get_glyph_advances_func_t ()</h3>
+<a name="hb-font-paint-glyph"></a><h3>hb_font_paint_glyph ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-<span class="c_punctuation">(</span>*hb_font_get_glyph_advances_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                      <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
-                                      <em class="parameter"><code>unsigned <span class="type">int</span> count</code></em>,
-                                      <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *first_glyph</code></em>,
-                                      <em class="parameter"><code><span class="type">unsigned </span> glyph_stride</code></em>,
-                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *first_advance</code></em>,
-                                      <em class="parameter"><code><span class="type">unsigned </span> advance_stride</code></em>,
-                                      <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
-<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
-<p>This method should retrieve the advances for a sequence of glyphs.</p>
-<div class="refsect3">
-<a name="hb-font-get-glyph-advances-func-t.parameters"></a><h4>Parameters</h4>
+hb_font_paint_glyph (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *pfuncs</code></em>,
+                     <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                     <em class="parameter"><code>unsigned <span class="type">int</span> palette_index</code></em>,
+                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-ot-color.html#hb-color-t" title="hb_color_t"><span class="type">hb_color_t</span></a> foreground</code></em>);</pre>
+<p>Paints the glyph.</p>
+<p>The painting instructions are returned by way of calls to
+the callbacks of the <em class="parameter"><code>funcs</code></em>
+ object, with <em class="parameter"><code>paint_data</code></em>
+ passed
+to them.</p>
+<p>If the font has color palettes (see <a class="link" href="harfbuzz-hb-ot-color.html#hb-ot-color-has-palettes" title="hb_ot_color_has_palettes ()"><code class="function">hb_ot_color_has_palettes()</code></a>),
+then <em class="parameter"><code>palette_index</code></em>
+ selects the palette to use. If the font only
+has one palette, this will be 0.</p>
+<div class="refsect3">
+<a name="hb-font-paint-glyph.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -2175,58 +2377,49 @@ or vertical) depending on the value of <em class="parameter"><code>direction</co
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>font_data</p></td>
-<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
-user data pointer</p></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>count</p></td>
-<td class="parameter_description"><p>The number of glyph IDs in the sequence queried</p></td>
+<td class="parameter_name"><p>pfuncs</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> to paint with</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>first_glyph</p></td>
-<td class="parameter_description"><p>The first glyph ID to query</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>glyph_stride</p></td>
-<td class="parameter_description"><p>The stride between successive glyph IDs</p></td>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>User data to pass to paint callbacks</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>first_advance</p></td>
-<td class="parameter_description"><p>The first advance retrieved. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>advance_stride</p></td>
-<td class="parameter_description"><p>The stride between successive advances</p></td>
+<td class="parameter_name"><p>palette_index</p></td>
+<td class="parameter_description"><p>The index of the font's color palette to use</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_name"><p>foreground</p></td>
+<td class="parameter_description"><p>The foreground color, unpremultipled</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-contour-point"></a><h3>hb_font_get_glyph_contour_point ()</h3>
+<a name="hb-font-get-nominal-glyph"></a><h3>hb_font_get_nominal_glyph ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_font_get_glyph_contour_point (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                 <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
-                                 <em class="parameter"><code>unsigned <span class="type">int</span> point_index</code></em>,
-                                 <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *x</code></em>,
-                                 <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *y</code></em>);</pre>
-<p>Fetches the (x,y) coordinates of a specified contour-point index
-in the specified glyph, within the specified font.</p>
+hb_font_get_nominal_glyph (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                           <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>,
+                           <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *glyph</code></em>);</pre>
+<p>Fetches the nominal glyph ID for a Unicode code point in the
+specified font.</p>
+<p>This version of the function should not be used to fetch glyph IDs
+for code points modified by variation selectors. For variation-selector
+support, user <a class="link" href="harfbuzz-hb-font.html#hb-font-get-variation-glyph" title="hb_font_get_variation_glyph ()"><code class="function">hb_font_get_variation_glyph()</code></a> or use <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph" title="hb_font_get_glyph ()"><code class="function">hb_font_get_glyph()</code></a>.</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph-contour-point.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-nominal-glyph.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -2240,53 +2433,39 @@ in the specified glyph, within the specified font.</p>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID to query</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>point_index</p></td>
-<td class="parameter_description"><p>The contour-point index to query</p></td>
+<td class="parameter_name"><p>unicode</p></td>
+<td class="parameter_description"><p>The Unicode code point to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>x</p></td>
-<td class="parameter_description"><p>The X value retrieved for the contour point. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>y</p></td>
-<td class="parameter_description"><p>The Y value retrieved for the contour point. </p></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID retrieved. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-get-glyph-contour-point.returns"></a><h4>Returns</h4>
+<a name="hb-font-get-nominal-glyph.returns"></a><h4>Returns</h4>
 <p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-1-2-3.html#api-index-1.2.3">1.2.3</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-contour-point-for-origin"></a><h3>hb_font_get_glyph_contour_point_for_origin ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_font_get_glyph_contour_point_for_origin
-                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
-                                <em class="parameter"><code>unsigned <span class="type">int</span> point_index</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *x</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *y</code></em>);</pre>
-<p>Fetches the (X,Y) coordinates of a specified contour-point index
-in the specified glyph ID in the specified font, with respect
-to the origin in a text segment in the specified direction.</p>
-<p>Calls the appropriate direction-specific variant (horizontal
-or vertical) depending on the value of <em class="parameter"><code>direction</code></em>
-.</p>
+<a name="hb-font-get-nominal-glyphs"></a><h3>hb_font_get_nominal_glyphs ()</h3>
+<pre class="programlisting">unsigned <span class="returnvalue">int</span>
+hb_font_get_nominal_glyphs (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                            <em class="parameter"><code>unsigned <span class="type">int</span> count</code></em>,
+                            <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *first_unicode</code></em>,
+                            <em class="parameter"><code>unsigned <span class="type">int</span> unicode_stride</code></em>,
+                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *first_glyph</code></em>,
+                            <em class="parameter"><code>unsigned <span class="type">int</span> glyph_stride</code></em>);</pre>
+<p>Fetches the nominal glyph IDs for a sequence of Unicode code points. Glyph
+IDs must be returned in a <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> output parameter. Stops at the
+first unsupported glyph ID.</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph-contour-point-for-origin.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-nominal-glyphs.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -2300,57 +2479,52 @@ or vertical) depending on the value of <em class="parameter"><code>direction</co
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_name"><p>count</p></td>
+<td class="parameter_description"><p>number of code points to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>point_index</p></td>
-<td class="parameter_description"><p>The contour-point index to query</p></td>
+<td class="parameter_name"><p>first_unicode</p></td>
+<td class="parameter_description"><p>The first Unicode code point to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>direction</p></td>
-<td class="parameter_description"><p>The direction of the text segment</p></td>
+<td class="parameter_name"><p>unicode_stride</p></td>
+<td class="parameter_description"><p>The stride between successive code points</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>x</p></td>
-<td class="parameter_description"><p>The X value retrieved for the contour point. </p></td>
+<td class="parameter_name"><p>first_glyph</p></td>
+<td class="parameter_description"><p>The first glyph ID retrieved. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>y</p></td>
-<td class="parameter_description"><p>The Y value retrieved for the contour point. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+<td class="parameter_name"><p>glyph_stride</p></td>
+<td class="parameter_description"><p>The stride between successive glyph IDs</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-get-glyph-contour-point-for-origin.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
+<a name="hb-font-get-nominal-glyphs.returns"></a><h4>Returns</h4>
+<p> the number of code points processed</p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-2-6-3.html#api-index-2.6.3">2.6.3</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-contour-point-func-t"></a><h3>hb_font_get_glyph_contour_point_func_t ()</h3>
+<a name="hb-font-get-variation-glyph"></a><h3>hb_font_get_variation_glyph ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-<span class="c_punctuation">(</span>*hb_font_get_glyph_contour_point_func_t<span class="c_punctuation">)</span>
-                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
-                                <em class="parameter"><code>unsigned <span class="type">int</span> point_index</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *x</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *y</code></em>,
-                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
-<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
-<p>This method should retrieve the (X,Y) coordinates (in font units) for a
-specified contour point in a glyph. Each coordinate must be returned as
-an <a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> output parameter.</p>
+hb_font_get_variation_glyph (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> variation_selector</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *glyph</code></em>);</pre>
+<p>Fetches the glyph ID for a Unicode code point when followed by
+by the specified variation-selector code point, in the specified
+font.</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph-contour-point-func-t.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-variation-glyph.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -2364,55 +2538,39 @@ an <a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_positi
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>font_data</p></td>
-<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
-user data pointer</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_name"><p>unicode</p></td>
+<td class="parameter_description"><p>The Unicode code point to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>point_index</p></td>
-<td class="parameter_description"><p>The contour-point index to query</p></td>
+<td class="parameter_name"><p>variation_selector</p></td>
+<td class="parameter_description"><p>The  variation-selector code point to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>x</p></td>
-<td class="parameter_description"><p>The X value retrieved for the contour point. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>y</p></td>
-<td class="parameter_description"><p>The Y value retrieved for the contour point. </p></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID retrieved. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
-<tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-get-glyph-contour-point-func-t.returns"></a><h4>Returns</h4>
+<a name="hb-font-get-variation-glyph.returns"></a><h4>Returns</h4>
 <p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
 </div>
+<p class="since">Since: <a class="link" href="api-index-1-2-3.html#api-index-1.2.3">1.2.3</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-extents"></a><h3>hb_font_get_glyph_extents ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_font_get_glyph_extents (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                           <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
-                           <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-glyph-extents-t" title="hb_glyph_extents_t"><span class="type">hb_glyph_extents_t</span></a> *extents</code></em>);</pre>
-<p>Fetches the <a class="link" href="harfbuzz-hb-font.html#hb-glyph-extents-t" title="hb_glyph_extents_t"><span class="type">hb_glyph_extents_t</span></a> data for a glyph ID
-in the specified font.</p>
+<a name="hb-font-set-parent"></a><h3>hb_font_set_parent ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_set_parent (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *parent</code></em>);</pre>
+<p>Sets the parent font of <em class="parameter"><code>font</code></em>
+.</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph-extents.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-set-parent.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -2426,90 +2584,57 @@ in the specified font.</p>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_name"><p>parent</p></td>
+<td class="parameter_description"><p>The parent font object to assign</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
-<tr>
-<td class="parameter_name"><p>extents</p></td>
-<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-font.html#hb-glyph-extents-t" title="hb_glyph_extents_t"><span class="type">hb_glyph_extents_t</span></a> retrieved. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
 </tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-font-get-glyph-extents.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-1-0-5.html#api-index-1.0.5">1.0.5</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-extents-for-origin"></a><h3>hb_font_get_glyph_extents_for_origin ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_font_get_glyph_extents_for_origin (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
-                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
-                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-glyph-extents-t" title="hb_glyph_extents_t"><span class="type">hb_glyph_extents_t</span></a> *extents</code></em>);</pre>
-<p>Fetches the <a class="link" href="harfbuzz-hb-font.html#hb-glyph-extents-t" title="hb_glyph_extents_t"><span class="type">hb_glyph_extents_t</span></a> data for a glyph ID
-in the specified font, with respect to the origin in
-a text segment in the specified direction.</p>
-<p>Calls the appropriate direction-specific variant (horizontal
-or vertical) depending on the value of <em class="parameter"><code>direction</code></em>
+<a name="hb-font-get-parent"></a><h3>hb_font_get_parent ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="returnvalue">hb_font_t</span></a> *
+hb_font_get_parent (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
+<p>Fetches the parent font of <em class="parameter"><code>font</code></em>
 .</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph-extents-for-origin.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-parent.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody>
-<tr>
+<tbody><tr>
 <td class="parameter_name"><p>font</p></td>
 <td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID to query</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>direction</p></td>
-<td class="parameter_description"><p>The direction of the text segment</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>extents</p></td>
-<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-font.html#hb-glyph-extents-t" title="hb_glyph_extents_t"><span class="type">hb_glyph_extents_t</span></a> retrieved. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-</tbody>
+</tr></tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-get-glyph-extents-for-origin.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
+<a name="hb-font-get-parent.returns"></a><h4>Returns</h4>
+<p>The parent font object. </p>
+<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-extents-func-t"></a><h3>hb_font_get_glyph_extents_func_t ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-<span class="c_punctuation">(</span>*hb_font_get_glyph_extents_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                     <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
-                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
-                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-glyph-extents-t" title="hb_glyph_extents_t"><span class="type">hb_glyph_extents_t</span></a> *extents</code></em>,
-                                     <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
-<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
-<p>This method should retrieve the extents for a specified glyph. Extents must be 
-returned in an <span class="type">hb_glyph_extents</span> output parameter.</p>
+<a name="hb-font-set-ppem"></a><h3>hb_font_set_ppem ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_set_ppem (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                  <em class="parameter"><code>unsigned <span class="type">int</span> x_ppem</code></em>,
+                  <em class="parameter"><code>unsigned <span class="type">int</span> y_ppem</code></em>);</pre>
+<p>Sets the horizontal and vertical pixels-per-em (PPEM) of a font.</p>
+<p>These values are used for pixel-size-specific adjustment to
+shaping and draw results, though for the most part they are
+unused and can be left unset.</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph-extents-func-t.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-set-ppem.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -2523,47 +2648,30 @@ returned in an <span class="type">hb_glyph_extents</span> output parameter.</p>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>font_data</p></td>
-<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
-user data pointer</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_name"><p>x_ppem</p></td>
+<td class="parameter_description"><p>Horizontal ppem value to assign</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>extents</p></td>
-<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-font.html#hb-glyph-extents-t" title="hb_glyph_extents_t"><span class="type">hb_glyph_extents_t</span></a> retrieved. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_name"><p>y_ppem</p></td>
+<td class="parameter_description"><p>Vertical ppem value to assign</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-font-get-glyph-extents-func-t.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
-</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-from-name"></a><h3>hb_font_get_glyph_from_name ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_font_get_glyph_from_name (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                             <em class="parameter"><code>const <span class="type">char</span> *name</code></em>,
-                             <em class="parameter"><code><span class="type">int</span> len</code></em>,
-                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *glyph</code></em>);</pre>
-<p>Fetches the glyph ID that corresponds to a name string in the specified <em class="parameter"><code>font</code></em>
-.</p>
-<div class="note">Note: <em class="parameter"><code>len</code></em> == -1 means the name string is null-terminated.</div>
+<a name="hb-font-get-ppem"></a><h3>hb_font_get_ppem ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_get_ppem (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                  <em class="parameter"><code>unsigned <span class="type">int</span> *x_ppem</code></em>,
+                  <em class="parameter"><code>unsigned <span class="type">int</span> *y_ppem</code></em>);</pre>
+<p>Fetches the horizontal and vertical points-per-em (ppem) of a font.</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph-from-name.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-ppem.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -2577,44 +2685,31 @@ hb_font_get_glyph_from_name (<em class="parameter"><code><a class="link" href="h
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>name</p></td>
-<td class="parameter_description"><p>The name string to query. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=len]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>len</p></td>
-<td class="parameter_description"><p>The length of the name queried</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_name"><p>x_ppem</p></td>
+<td class="parameter_description"><p>Horizontal ppem value. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID retrieved. </p></td>
+<td class="parameter_name"><p>y_ppem</p></td>
+<td class="parameter_description"><p>Vertical ppem value. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-font-get-glyph-from-name.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
-</div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-from-name-func-t"></a><h3>hb_font_get_glyph_from_name_func_t ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-<span class="c_punctuation">(</span>*hb_font_get_glyph_from_name_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                       <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
-                                       <em class="parameter"><code>const <span class="type">char</span> *name</code></em>,
-                                       <em class="parameter"><code><span class="type">int</span> len</code></em>,
-                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *glyph</code></em>,
-                                       <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
-<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
-<p>This method should retrieve the glyph ID that corresponds to a glyph-name
-string.</p>
+<a name="hb-font-set-ptem"></a><h3>hb_font_set_ptem ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_set_ptem (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                  <em class="parameter"><code><span class="type">float</span> ptem</code></em>);</pre>
+<p>Sets the "point size" of a font. Set to zero to unset.
+Used in CoreText to implement optical sizing.</p>
+<div class="note">Note: There are 72 points in an inch.</div>
 <div class="refsect3">
-<a name="hb-font-get-glyph-from-name-func-t.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-set-ptem.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -2628,91 +2723,73 @@ string.</p>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>font_data</p></td>
-<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
-user data pointer</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>name</p></td>
-<td class="parameter_description"><p>The name string to query. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=len]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>len</p></td>
-<td class="parameter_description"><p>The length of the name queried</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID retrieved. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_name"><p>ptem</p></td>
+<td class="parameter_description"><p>font size in points.</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-font-get-glyph-from-name-func-t.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
-</div>
+<p class="since">Since: <a class="link" href="api-index-1-6-0.html#api-index-1.6.0">1.6.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-h-advance"></a><h3>hb_font_get_glyph_h_advance ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
-hb_font_get_glyph_h_advance (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>);</pre>
-<p>Fetches the advance for a glyph ID in the specified font,
-for horizontal text segments.</p>
+<a name="hb-font-get-ptem"></a><h3>hb_font_get_ptem ()</h3>
+<pre class="programlisting"><span class="returnvalue">float</span>
+hb_font_get_ptem (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
+<p>Fetches the "point size" of a font. Used in CoreText to
+implement optical sizing.</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph-h-advance.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-ptem.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody>
-<tr>
+<tbody><tr>
 <td class="parameter_name"><p>font</p></td>
 <td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID to query</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-</tbody>
+</tr></tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-get-glyph-h-advance.returns"></a><h4>Returns</h4>
-<p> The advance of <em class="parameter"><code>glyph</code></em>
-within <em class="parameter"><code>font</code></em>
-</p>
+<a name="hb-font-get-ptem.returns"></a><h4>Returns</h4>
+<p> Point size.  A value of zero means "not set."</p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-1-6-0.html#api-index-1.6.0">1.6.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-h-advances"></a><h3>hb_font_get_glyph_h_advances ()</h3>
+<a name="hb-font-set-scale"></a><h3>hb_font_set_scale ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_get_glyph_h_advances (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                              <em class="parameter"><code>unsigned <span class="type">int</span> count</code></em>,
-                              <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *first_glyph</code></em>,
-                              <em class="parameter"><code><span class="type">unsigned </span> glyph_stride</code></em>,
-                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *first_advance</code></em>,
-                              <em class="parameter"><code><span class="type">unsigned </span> advance_stride</code></em>);</pre>
-<p>Fetches the advances for a sequence of glyph IDs in the specified
-font, for horizontal text segments.</p>
+hb_font_set_scale (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                   <em class="parameter"><code><span class="type">int</span> x_scale</code></em>,
+                   <em class="parameter"><code><span class="type">int</span> y_scale</code></em>);</pre>
+<p>Sets the horizontal and vertical scale of a font.</p>
+<p>The font scale is a number related to, but not the same as,
+font size. Typically the client establishes a scale factor
+to be used between the two. For example, 64, or 256, which
+would be the fractional-precision part of the font scale.
+This is necessary because <a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> values are integer
+types and you need to leave room for fractional values
+in there.</p>
+<p>For example, to set the font size to 20, with 64
+levels of fractional precision you would call
+<code class="literal">hb_font_set_scale(font, 20 * 64, 20 * 64)</code>.</p>
+<p>In the example above, even what font size 20 means is up to
+you. It might be 20 pixels, or 20 points, or 20 millimeters.
+HarfBuzz does not care about that.  You can set the point
+size of the font using <a class="link" href="harfbuzz-hb-font.html#hb-font-set-ptem" title="hb_font_set_ptem ()"><code class="function">hb_font_set_ptem()</code></a>, and the pixel
+size using <a class="link" href="harfbuzz-hb-font.html#hb-font-set-ppem" title="hb_font_set_ppem ()"><code class="function">hb_font_set_ppem()</code></a>.</p>
+<p>The choice of scale is yours but needs to be consistent between
+what you set here, and what you expect out of <a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a>
+as well has draw / paint API output values.</p>
+<p>Fonts default to a scale equal to the UPEM value of their face.
+A font with this setting is sometimes called an "unscaled" font.</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph-h-advances.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-set-scale.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -2726,48 +2803,30 @@ font, for horizontal text segments.</p>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>count</p></td>
-<td class="parameter_description"><p>The number of glyph IDs in the sequence queried</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>first_glyph</p></td>
-<td class="parameter_description"><p>The first glyph ID to query</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>glyph_stride</p></td>
-<td class="parameter_description"><p>The stride between successive glyph IDs</p></td>
+<td class="parameter_name"><p>x_scale</p></td>
+<td class="parameter_description"><p>Horizontal scale value to assign</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>first_advance</p></td>
-<td class="parameter_description"><p>The first advance retrieved. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>advance_stride</p></td>
-<td class="parameter_description"><p>The stride between successive advances</p></td>
+<td class="parameter_name"><p>y_scale</p></td>
+<td class="parameter_description"><p>Vertical scale value to assign</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-1-8-6.html#api-index-1.8.6">1.8.6</a></p>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-h-kerning"></a><h3>hb_font_get_glyph_h_kerning ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
-hb_font_get_glyph_h_kerning (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> left_glyph</code></em>,
-                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> right_glyph</code></em>);</pre>
-<p>Fetches the kerning-adjustment value for a glyph-pair in
-the specified font, for horizontal text segments.</p>
-<div class="note">It handles legacy kerning only (as returned by the corresponding
-<a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> function).</div>
+<a name="hb-font-get-scale"></a><h3>hb_font_get_scale ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_get_scale (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                   <em class="parameter"><code><span class="type">int</span> *x_scale</code></em>,
+                   <em class="parameter"><code><span class="type">int</span> *y_scale</code></em>);</pre>
+<p>Fetches the horizontal and vertical scale of a font.</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph-h-kerning.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-scale.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -2781,36 +2840,31 @@ the specified font, for horizontal text segments.</p>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>left_glyph</p></td>
-<td class="parameter_description"><p>The glyph ID of the left glyph in the glyph pair</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_name"><p>x_scale</p></td>
+<td class="parameter_description"><p>Horizontal scale value. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>right_glyph</p></td>
-<td class="parameter_description"><p>The glyph ID of the right glyph in the glyph pair</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_name"><p>y_scale</p></td>
+<td class="parameter_description"><p>Vertical scale value. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-font-get-glyph-h-kerning.returns"></a><h4>Returns</h4>
-<p> The kerning adjustment value</p>
-</div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-h-origin"></a><h3>hb_font_get_glyph_h_origin ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_font_get_glyph_h_origin (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
-                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *x</code></em>,
-                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *y</code></em>);</pre>
-<p>Fetches the (X,Y) coordinates of the origin for a glyph ID
-in the specified font, for horizontal text segments.</p>
+<a name="hb-font-get-synthetic-bold"></a><h3>hb_font_get_synthetic_bold ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_get_synthetic_bold (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                            <em class="parameter"><code><span class="type">float</span> *x_embolden</code></em>,
+                            <em class="parameter"><code><span class="type">float</span> *y_embolden</code></em>,
+                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> *in_place</code></em>);</pre>
+<p>Fetches the "synthetic boldness" parameters of a font.</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph-h-origin.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-synthetic-bold.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -2824,46 +2878,49 @@ in the specified font, for horizontal text segments.</p>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID to query</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_name"><p>x_embolden</p></td>
+<td class="parameter_description"><p>return location for horizontal value. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>x</p></td>
-<td class="parameter_description"><p>The X coordinate of the origin. </p></td>
+<td class="parameter_name"><p>y_embolden</p></td>
+<td class="parameter_description"><p>return location for vertical value. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>y</p></td>
-<td class="parameter_description"><p>The Y coordinate of the origin. </p></td>
+<td class="parameter_name"><p>in_place</p></td>
+<td class="parameter_description"><p>return location for in-place value. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-font-get-glyph-h-origin.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-kerning-for-direction"></a><h3>hb_font_get_glyph_kerning_for_direction ()</h3>
+<a name="hb-font-set-synthetic-bold"></a><h3>hb_font_set_synthetic_bold ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_get_glyph_kerning_for_direction
-                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> first_glyph</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> second_glyph</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *x</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *y</code></em>);</pre>
-<p>Fetches the kerning-adjustment value for a glyph-pair in the specified font.</p>
-<p>Calls the appropriate direction-specific variant (horizontal
-or vertical) depending on the value of <em class="parameter"><code>direction</code></em>
-.</p>
-<div class="refsect3">
-<a name="hb-font-get-glyph-kerning-for-direction.parameters"></a><h4>Parameters</h4>
+hb_font_set_synthetic_bold (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                            <em class="parameter"><code><span class="type">float</span> x_embolden</code></em>,
+                            <em class="parameter"><code><span class="type">float</span> y_embolden</code></em>,
+                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> in_place</code></em>);</pre>
+<p>Sets the "synthetic boldness" of a font.</p>
+<p>Positive values for <em class="parameter"><code>x_embolden</code></em>
+ / <em class="parameter"><code>y_embolden</code></em>
+ make a font
+bolder, negative values thinner. Typical values are in the
+0.01 to 0.05 range. The default value is zero.</p>
+<p>Synthetic boldness is applied by offsetting the contour
+points of the glyph shape.</p>
+<p>Synthetic boldness is applied when rendering a glyph via
+<a class="link" href="harfbuzz-hb-font.html#hb-font-draw-glyph" title="hb_font_draw_glyph ()"><code class="function">hb_font_draw_glyph()</code></a>.</p>
+<p>If <em class="parameter"><code>in_place</code></em>
+ is <code class="literal">false</code>, then glyph advance-widths are also
+adjusted, otherwise they are not.  The in-place mode is
+useful for simulating <a class="ulink" href="https://fonts.google.com/knowledge/glossary/grade" target="_top">font grading</a>.</p>
+<div class="refsect3">
+<a name="hb-font-set-synthetic-bold.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -2877,48 +2934,42 @@ or vertical) depending on the value of <em class="parameter"><code>direction</co
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>first_glyph</p></td>
-<td class="parameter_description"><p>The glyph ID of the first glyph in the glyph pair to query</p></td>
+<td class="parameter_name"><p>x_embolden</p></td>
+<td class="parameter_description"><p>the amount to embolden horizontally</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>second_glyph</p></td>
-<td class="parameter_description"><p>The glyph ID of the second glyph in the glyph pair to query</p></td>
+<td class="parameter_name"><p>y_embolden</p></td>
+<td class="parameter_description"><p>the amount to embolden vertically</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>direction</p></td>
-<td class="parameter_description"><p>The direction of the text segment</p></td>
+<td class="parameter_name"><p>in_place</p></td>
+<td class="parameter_description"><p>whether to embolden glyphs in-place</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
-<tr>
-<td class="parameter_name"><p>x</p></td>
-<td class="parameter_description"><p>The horizontal kerning-adjustment value retrieved. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>y</p></td>
-<td class="parameter_description"><p>The vertical kerning-adjustment value retrieved. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-kerning-func-t"></a><h3>hb_font_get_glyph_kerning_func_t ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
-<span class="c_punctuation">(</span>*hb_font_get_glyph_kerning_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                     <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
-                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> first_glyph</code></em>,
-                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> second_glyph</code></em>,
-                                     <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
-<p>This method should retrieve the kerning-adjustment value for a glyph-pair in
-the specified font, for horizontal text segments.</p>
+<a name="hb-font-set-synthetic-slant"></a><h3>hb_font_set_synthetic_slant ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_set_synthetic_slant (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                             <em class="parameter"><code><span class="type">float</span> slant</code></em>);</pre>
+<p>Sets the "synthetic slant" of a font.  By default is zero.
+Synthetic slant is the graphical skew applied to the font
+at rendering time.</p>
+<p>HarfBuzz needs to know this value to adjust shaping results,
+metrics, and style values to match the slanted rendering.</p>
+<div class="note">Note: The glyph shape fetched via the <a class="link" href="harfbuzz-hb-font.html#hb-font-draw-glyph" title="hb_font_draw_glyph ()"><code class="function">hb_font_draw_glyph()</code></a>
+function is slanted to reflect this value as well.</div>
+<div class="note">Note: The slant value is a ratio.  For example, a
+20% slant would be represented as a 0.2 value.</div>
 <div class="refsect3">
-<a name="hb-font-get-glyph-kerning-func-t.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-set-synthetic-slant.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -2932,93 +2983,57 @@ the specified font, for horizontal text segments.</p>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>font_data</p></td>
-<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
-user data pointer</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>first_glyph</p></td>
-<td class="parameter_description"><p>The glyph ID of the first glyph in the glyph pair</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>second_glyph</p></td>
-<td class="parameter_description"><p>The glyph ID of the second glyph in the glyph pair</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_name"><p>slant</p></td>
+<td class="parameter_description"><p>synthetic slant value.</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
+<p class="since">Since: <a class="link" href="api-index-3-3-0.html#api-index-3.3.0">3.3.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-name"></a><h3>hb_font_get_glyph_name ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_font_get_glyph_name (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                        <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
-                        <em class="parameter"><code><span class="type">char</span> *name</code></em>,
-                        <em class="parameter"><code>unsigned <span class="type">int</span> size</code></em>);</pre>
-<p>Fetches the glyph-name string for a glyph ID in the specified <em class="parameter"><code>font</code></em>
-.</p>
+<a name="hb-font-get-synthetic-slant"></a><h3>hb_font_get_synthetic_slant ()</h3>
+<pre class="programlisting"><span class="returnvalue">float</span>
+hb_font_get_synthetic_slant (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
+<p>Fetches the "synthetic slant" of a font.</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph-name.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-synthetic-slant.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody>
-<tr>
+<tbody><tr>
 <td class="parameter_name"><p>font</p></td>
 <td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID to query</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>name</p></td>
-<td class="parameter_description"><p>Name string retrieved for the glyph ID. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=size]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>size</p></td>
-<td class="parameter_description"><p>Length of the glyph-name string retrieved</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-</tbody>
+</tr></tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-get-glyph-name.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
+<a name="hb-font-get-synthetic-slant.returns"></a><h4>Returns</h4>
+<p> Synthetic slant.  By default is zero.</p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-3-3-0.html#api-index-3.3.0">3.3.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-name-func-t"></a><h3>hb_font_get_glyph_name_func_t ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-<span class="c_punctuation">(</span>*hb_font_get_glyph_name_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                  <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
-                                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
-                                  <em class="parameter"><code><span class="type">char</span> *name</code></em>,
-                                  <em class="parameter"><code>unsigned <span class="type">int</span> size</code></em>,
-                                  <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
-<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
-<p>This method should retrieve the glyph name that corresponds to a
-glyph ID. The name should be returned in a string output parameter.</p>
+<a name="hb-font-set-variations"></a><h3>hb_font_set_variations ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_set_variations (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                        <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-variation-t" title="hb_variation_t"><span class="type">hb_variation_t</span></a> *variations</code></em>,
+                        <em class="parameter"><code>unsigned <span class="type">int</span> variations_length</code></em>);</pre>
+<p>Applies a list of font-variation settings to a font.</p>
+<p>Note that this overrides all existing variations set on <em class="parameter"><code>font</code></em>
+.
+Axes not included in <em class="parameter"><code>variations</code></em>
+ will be effectively set to their
+default values.</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph-name-func-t.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-set-variations.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -3032,56 +3047,33 @@ glyph ID. The name should be returned in a string output parameter.</p>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>font_data</p></td>
-<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
-user data pointer</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID to query</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>name</p></td>
-<td class="parameter_description"><p>Name string retrieved for the glyph ID. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=size]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>size</p></td>
-<td class="parameter_description"><p>Length of the glyph-name string retrieved</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_name"><p>variations</p></td>
+<td class="parameter_description"><p>Array of variation settings to apply. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=variations_length]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_name"><p>variations_length</p></td>
+<td class="parameter_description"><p>Number of variations to apply</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-font-get-glyph-name-func-t.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
-</div>
+<p class="since">Since: <a class="link" href="api-index-1-4-2.html#api-index-1.4.2">1.4.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-origin-for-direction"></a><h3>hb_font_get_glyph_origin_for_direction ()</h3>
+<a name="hb-font-set-variation"></a><h3>hb_font_set_variation ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_get_glyph_origin_for_direction
-                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *x</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *y</code></em>);</pre>
-<p>Fetches the (X,Y) coordinates of the origin for a glyph in
-the specified font.</p>
-<p>Calls the appropriate direction-specific variant (horizontal
-or vertical) depending on the value of <em class="parameter"><code>direction</code></em>
-.</p>
-<div class="refsect3">
-<a name="hb-font-get-glyph-origin-for-direction.parameters"></a><h4>Parameters</h4>
+hb_font_set_variation (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> tag</code></em>,
+                       <em class="parameter"><code><span class="type">float</span> value</code></em>);</pre>
+<p>Change the value of one variation axis on the font.</p>
+<p>Note: This function is expensive to be called repeatedly.
+  If you want to set multiple variation axes at the same time,
+  use <a class="link" href="harfbuzz-hb-font.html#hb-font-set-variations" title="hb_font_set_variations ()"><code class="function">hb_font_set_variations()</code></a> instead.</p>
+<div class="refsect3">
+<a name="hb-font-set-variation.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -3095,46 +3087,29 @@ or vertical) depending on the value of <em class="parameter"><code>direction</co
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_name"><p>tag</p></td>
+<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> tag of the variation-axis name</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>direction</p></td>
-<td class="parameter_description"><p>The direction of the text segment</p></td>
+<td class="parameter_name"><p>value</p></td>
+<td class="parameter_description"><p>The value of the variation axis</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
-<tr>
-<td class="parameter_name"><p>x</p></td>
-<td class="parameter_description"><p>The X coordinate retrieved for the origin. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>y</p></td>
-<td class="parameter_description"><p>The Y coordinate retrieved for the origin. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-7-1-0.html#api-index-7.1.0">7.1.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-origin-func-t"></a><h3>hb_font_get_glyph_origin_func_t ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-<span class="c_punctuation">(</span>*hb_font_get_glyph_origin_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                    <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
-                                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
-                                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *x</code></em>,
-                                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *y</code></em>,
-                                    <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
-<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
-<p>This method should retrieve the (X,Y) coordinates (in font units) of the
-origin for a glyph. Each coordinate must be returned in an <a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a>
-output parameter.</p>
+<a name="hb-font-set-var-named-instance"></a><h3>hb_font_set_var_named_instance ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_set_var_named_instance (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                <em class="parameter"><code>unsigned <span class="type">int</span> instance_index</code></em>);</pre>
+<p>Sets design coords of a font from a named-instance index.</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph-origin-func-t.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-set-var-named-instance.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -3144,95 +3119,62 @@ output parameter.</p>
 <tbody>
 <tr>
 <td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>font_data</p></td>
-<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
-user data pointer</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_description"><p>a font.</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>x</p></td>
-<td class="parameter_description"><p>The X coordinate of the origin. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>y</p></td>
-<td class="parameter_description"><p>The Y coordinate of the origin. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_name"><p>instance_index</p></td>
+<td class="parameter_description"><p>named instance index.</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-font-get-glyph-origin-func-t.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
-</div>
+<p class="since">Since: <a class="link" href="api-index-2-6-0.html#api-index-2.6.0">2.6.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-v-advance"></a><h3>hb_font_get_glyph_v_advance ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
-hb_font_get_glyph_v_advance (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>);</pre>
-<p>Fetches the advance for a glyph ID in the specified font,
-for vertical text segments.</p>
+<a name="hb-font-get-var-named-instance"></a><h3>hb_font_get_var_named_instance ()</h3>
+<pre class="programlisting">unsigned <span class="returnvalue">int</span>
+hb_font_get_var_named_instance (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
+<p>Returns the currently-set named-instance index of the font.</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph-v-advance.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-var-named-instance.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody>
-<tr>
+<tbody><tr>
 <td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_description"><p>a font.</p></td>
 <td class="parameter_annotations"> </td>
-</tr>
-</tbody>
+</tr></tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-get-glyph-v-advance.returns"></a><h4>Returns</h4>
-<p> The advance of <em class="parameter"><code>glyph</code></em>
-within <em class="parameter"><code>font</code></em>
-</p>
+<a name="hb-font-get-var-named-instance.returns"></a><h4>Returns</h4>
+<p> Named-instance index or <a class="link" href="harfbuzz-hb-font.html#HB-FONT-NO-VAR-NAMED-INSTANCE:CAPS" title="HB_FONT_NO_VAR_NAMED_INSTANCE"><code class="literal">HB_FONT_NO_VAR_NAMED_INSTANCE</code></a>.</p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-v-advances"></a><h3>hb_font_get_glyph_v_advances ()</h3>
+<a name="hb-font-set-var-coords-design"></a><h3>hb_font_set_var_coords_design ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_get_glyph_v_advances (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                              <em class="parameter"><code>unsigned <span class="type">int</span> count</code></em>,
-                              <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *first_glyph</code></em>,
-                              <em class="parameter"><code><span class="type">unsigned </span> glyph_stride</code></em>,
-                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *first_advance</code></em>,
-                              <em class="parameter"><code><span class="type">unsigned </span> advance_stride</code></em>);</pre>
-<p>Fetches the advances for a sequence of glyph IDs in the specified
-font, for vertical text segments.</p>
+hb_font_set_var_coords_design (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                               <em class="parameter"><code>const <span class="type">float</span> *coords</code></em>,
+                               <em class="parameter"><code>unsigned <span class="type">int</span> coords_length</code></em>);</pre>
+<p>Applies a list of variation coordinates (in design-space units)
+to a font.</p>
+<p>Note that this overrides all existing variations set on <em class="parameter"><code>font</code></em>
+.
+Axes not included in <em class="parameter"><code>coords</code></em>
+ will be effectively set to their
+default values.</p>
 <div class="refsect3">
-<a name="hb-font-get-glyph-v-advances.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-set-var-coords-design.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -3246,47 +3188,78 @@ font, for vertical text segments.</p>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>count</p></td>
-<td class="parameter_description"><p>The number of glyph IDs in the sequence queried</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_name"><p>coords</p></td>
+<td class="parameter_description"><p>Array of variation coordinates to apply. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=coords_length]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>first_glyph</p></td>
-<td class="parameter_description"><p>The first glyph ID to query</p></td>
+<td class="parameter_name"><p>coords_length</p></td>
+<td class="parameter_description"><p>Number of coordinates to apply</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-1-4-2.html#api-index-1.4.2">1.4.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-font-get-var-coords-design"></a><h3>hb_font_get_var_coords_design ()</h3>
+<pre class="programlisting">const <span class="returnvalue">float</span> *
+hb_font_get_var_coords_design (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                               <em class="parameter"><code>unsigned <span class="type">int</span> *length</code></em>);</pre>
+<p>Fetches the list of variation coordinates (in design-space units) currently
+set on a font.</p>
+<p>Note that this returned array may only contain values for some
+(or none) of the axes; omitted axes effectively have their default
+values.</p>
+<p>Return value is valid as long as variation coordinates of the font
+are not modified.</p>
+<div class="refsect3">
+<a name="hb-font-get-var-coords-design.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
 <tr>
-<td class="parameter_name"><p>glyph_stride</p></td>
-<td class="parameter_description"><p>The stride between successive glyph IDs</p></td>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>first_advance</p></td>
-<td class="parameter_description"><p>The first advance retrieved. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>advance_stride</p></td>
-<td class="parameter_description"><p>The stride between successive advances. </p></td>
+<td class="parameter_name"><p>length</p></td>
+<td class="parameter_description"><p>Number of coordinates retrieved. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-1-8-6.html#api-index-1.8.6">1.8.6</a></p>
+<div class="refsect3">
+<a name="hb-font-get-var-coords-design.returns"></a><h4>Returns</h4>
+<p> coordinates array</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-3-3-0.html#api-index-3.3.0">3.3.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-v-origin"></a><h3>hb_font_get_glyph_v_origin ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_font_get_glyph_v_origin (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
-                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *x</code></em>,
-                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *y</code></em>);</pre>
-<p>Fetches the (X,Y) coordinates of the origin for a glyph ID
-in the specified font, for vertical text segments.</p>
+<a name="hb-font-set-var-coords-normalized"></a><h3>hb_font_set_var_coords_normalized ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_set_var_coords_normalized (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                   <em class="parameter"><code>const <span class="type">int</span> *coords</code></em>,
+                                   <em class="parameter"><code>unsigned <span class="type">int</span> coords_length</code></em>);</pre>
+<p>Applies a list of variation coordinates (in normalized units)
+to a font.</p>
+<p>Note that this overrides all existing variations set on <em class="parameter"><code>font</code></em>
+.
+Axes not included in <em class="parameter"><code>coords</code></em>
+ will be effectively set to their
+default values.</p>
+<div class="note">Note: Coordinates should be normalized to 2.14.</div>
 <div class="refsect3">
-<a name="hb-font-get-glyph-v-origin.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-set-var-coords-normalized.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -3300,43 +3273,34 @@ in the specified font, for vertical text segments.</p>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID to query</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>x</p></td>
-<td class="parameter_description"><p>The X coordinate of the origin. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+<td class="parameter_name"><p>coords</p></td>
+<td class="parameter_description"><p>Array of variation coordinates to apply. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=coords_length]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>y</p></td>
-<td class="parameter_description"><p>The Y coordinate of the origin. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+<td class="parameter_name"><p>coords_length</p></td>
+<td class="parameter_description"><p>Number of coordinates to apply</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-font-get-glyph-v-origin.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-1-4-2.html#api-index-1.4.2">1.4.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-nominal-glyph"></a><h3>hb_font_get_nominal_glyph ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_font_get_nominal_glyph (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                           <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>,
-                           <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *glyph</code></em>);</pre>
-<p>Fetches the nominal glyph ID for a Unicode code point in the
-specified font.</p>
-<p>This version of the function should not be used to fetch glyph IDs
-for code points modified by variation selectors. For variation-selector
-support, user <a class="link" href="harfbuzz-hb-font.html#hb-font-get-variation-glyph" title="hb_font_get_variation_glyph ()"><code class="function">hb_font_get_variation_glyph()</code></a> or use <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph" title="hb_font_get_glyph ()"><code class="function">hb_font_get_glyph()</code></a>.</p>
+<a name="hb-font-get-var-coords-normalized"></a><h3>hb_font_get_var_coords_normalized ()</h3>
+<pre class="programlisting">const <span class="returnvalue">int</span> *
+hb_font_get_var_coords_normalized (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                   <em class="parameter"><code>unsigned <span class="type">int</span> *length</code></em>);</pre>
+<p>Fetches the list of normalized variation coordinates currently
+set on a font.</p>
+<p>Note that this returned array may only contain values for some
+(or none) of the axes; omitted axes effectively have zero values.</p>
+<p>Return value is valid as long as variation coordinates of the font
+are not modified.</p>
 <div class="refsect3">
-<a name="hb-font-get-nominal-glyph.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-var-coords-normalized.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -3350,38 +3314,33 @@ support, user <a class="link" href="harfbuzz-hb-font.html#hb-font-get-variation-
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>unicode</p></td>
-<td class="parameter_description"><p>The Unicode code point to query</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID retrieved. </p></td>
+<td class="parameter_name"><p>length</p></td>
+<td class="parameter_description"><p>Number of coordinates retrieved. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-get-nominal-glyph.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
+<a name="hb-font-get-var-coords-normalized.returns"></a><h4>Returns</h4>
+<p> coordinates array</p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-1-2-3.html#api-index-1.2.3">1.2.3</a></p>
+<p class="since">Since: <a class="link" href="api-index-1-4-2.html#api-index-1.4.2">1.4.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-nominal-glyph-func-t"></a><h3>hb_font_get_nominal_glyph_func_t ()</h3>
+<a name="hb-font-glyph-from-string"></a><h3>hb_font_glyph_from_string ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-<span class="c_punctuation">(</span>*hb_font_get_nominal_glyph_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                     <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
-                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>,
-                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *glyph</code></em>,
-                                     <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
-<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
-<p>This method should retrieve the nominal glyph ID for a specified Unicode code
-point. Glyph IDs must be returned in a <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> output parameter.</p>
+hb_font_glyph_from_string (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                           <em class="parameter"><code>const <span class="type">char</span> *s</code></em>,
+                           <em class="parameter"><code><span class="type">int</span> len</code></em>,
+                           <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *glyph</code></em>);</pre>
+<p>Fetches the glyph ID from <em class="parameter"><code>font</code></em>
+ that matches the specified string.
+Strings of the format <code class="literal">gidDDD</code> or <code class="literal">uniUUUU</code> are parsed automatically.</p>
+<div class="note">Note: <em class="parameter"><code>len</code></em> == -1 means the string is null-terminated.</div>
 <div class="refsect3">
-<a name="hb-font-get-nominal-glyph-func-t.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-glyph-from-string.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -3395,48 +3354,49 @@ point. Glyph IDs must be returned in a <a class="link" href="harfbuzz-hb-common.
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>font_data</p></td>
-<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
-user data pointer</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_name"><p>s</p></td>
+<td class="parameter_description"><p>string to query. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=len][<acronym title="Generics and defining elements of containers and arrays."><span class="acronym">element-type</span></acronym> uint8_t]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>unicode</p></td>
-<td class="parameter_description"><p>The Unicode code point to query</p></td>
+<td class="parameter_name"><p>len</p></td>
+<td class="parameter_description"><p>The length of the string <em class="parameter"><code>s</code></em>
+</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
 <td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID retrieved. </p></td>
+<td class="parameter_description"><p>The glyph ID corresponding to the string requested. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
-<tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-get-nominal-glyph-func-t.returns"></a><h4>Returns</h4>
+<a name="hb-font-glyph-from-string.returns"></a><h4>Returns</h4>
 <p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
 </div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-nominal-glyphs"></a><h3>hb_font_get_nominal_glyphs ()</h3>
-<pre class="programlisting">unsigned <span class="returnvalue">int</span>
-hb_font_get_nominal_glyphs (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                            <em class="parameter"><code>unsigned <span class="type">int</span> count</code></em>,
-                            <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *first_unicode</code></em>,
-                            <em class="parameter"><code>unsigned <span class="type">int</span> unicode_stride</code></em>,
-                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *first_glyph</code></em>,
-                            <em class="parameter"><code>unsigned <span class="type">int</span> glyph_stride</code></em>);</pre>
-<p>Fetches the nominal glyph IDs for a sequence of Unicode code points. Glyph
-IDs must be returned in a <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> output parameter.</p>
+<a name="hb-font-glyph-to-string"></a><h3>hb_font_glyph_to_string ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_glyph_to_string (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                         <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                         <em class="parameter"><code><span class="type">char</span> *s</code></em>,
+                         <em class="parameter"><code>unsigned <span class="type">int</span> size</code></em>);</pre>
+<p>Fetches the name of the specified glyph ID in <em class="parameter"><code>font</code></em>
+ and returns
+it in string <em class="parameter"><code>s</code></em>
+.</p>
+<p>If the glyph ID has no name in <em class="parameter"><code>font</code></em>
+, a string of the form <code class="literal">gidDDD</code> is
+generated, with <code class="literal">DDD</code> being the glyph ID.</p>
+<p>According to the OpenType specification, glyph names are limited to 63
+characters and can only contain (a subset of) ASCII.</p>
 <div class="refsect3">
-<a name="hb-font-get-nominal-glyphs.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-glyph-to-string.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -3450,122 +3410,66 @@ IDs must be returned in a <a class="link" href="harfbuzz-hb-common.html#hb-codep
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>count</p></td>
-<td class="parameter_description"><p>number of code points to query</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>first_unicode</p></td>
-<td class="parameter_description"><p>The first Unicode code point to query</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>unicode_stride</p></td>
-<td class="parameter_description"><p>The stride between successive code points</p></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>first_glyph</p></td>
-<td class="parameter_description"><p>The first glyph ID retrieved. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+<td class="parameter_name"><p>s</p></td>
+<td class="parameter_description"><p>The string containing the glyph name. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=size]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>glyph_stride</p></td>
-<td class="parameter_description"><p>The stride between successive glyph IDs</p></td>
+<td class="parameter_name"><p>size</p></td>
+<td class="parameter_description"><p>Length of string <em class="parameter"><code>s</code></em>
+</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-font-get-nominal-glyphs.returns"></a><h4>Returns</h4>
-<p> the number of code points processed</p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-2-6-3.html#api-index-2.6.3">2.6.3</a></p>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-nominal-glyphs-func-t"></a><h3>hb_font_get_nominal_glyphs_func_t ()</h3>
+<a name="hb-font-get-serial"></a><h3>hb_font_get_serial ()</h3>
 <pre class="programlisting">unsigned <span class="returnvalue">int</span>
-<span class="c_punctuation">(</span>*hb_font_get_nominal_glyphs_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                      <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
-                                      <em class="parameter"><code>unsigned <span class="type">int</span> count</code></em>,
-                                      <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *first_unicode</code></em>,
-                                      <em class="parameter"><code>unsigned <span class="type">int</span> unicode_stride</code></em>,
-                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *first_glyph</code></em>,
-                                      <em class="parameter"><code>unsigned <span class="type">int</span> glyph_stride</code></em>,
-                                      <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
-<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
-<p>This method should retrieve the nominal glyph IDs for a sequence of
-Unicode code points. Glyph IDs must be returned in a <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a>
-output parameter.</p>
+hb_font_get_serial (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
+<p>Returns the internal serial number of the font. The serial
+number is increased every time a setting on the font is
+changed, using a setter function.</p>
 <div class="refsect3">
-<a name="hb-font-get-nominal-glyphs-func-t.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-serial.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody>
-<tr>
+<tbody><tr>
 <td class="parameter_name"><p>font</p></td>
 <td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>font_data</p></td>
-<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
-user data pointer</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>count</p></td>
-<td class="parameter_description"><p>number of code points to query</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>first_unicode</p></td>
-<td class="parameter_description"><p>The first Unicode code point to query</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>unicode_stride</p></td>
-<td class="parameter_description"><p>The stride between successive code points</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>first_glyph</p></td>
-<td class="parameter_description"><p>The first glyph ID retrieved. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>glyph_stride</p></td>
-<td class="parameter_description"><p>The stride between successive glyph IDs</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-</tbody>
+</tr></tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-get-nominal-glyphs-func-t.returns"></a><h4>Returns</h4>
-<p> the number of code points processed</p>
+<a name="hb-font-get-serial.returns"></a><h4>Returns</h4>
+<p> serial number</p>
 </div>
+<p class="since">Since: <a class="link" href="api-index-4-4-0.html#api-index-4.4.0">4.4.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-parent"></a><h3>hb_font_get_parent ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="returnvalue">hb_font_t</span></a> *
-hb_font_get_parent (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
-<p>Fetches the parent font of <em class="parameter"><code>font</code></em>
-.</p>
+<a name="hb-font-changed"></a><h3>hb_font_changed ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_changed (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
+<p>Notifies the <em class="parameter"><code>font</code></em>
+ that underlying font data has changed.
+This has the effect of increasing the serial as returned
+by <a class="link" href="harfbuzz-hb-font.html#hb-font-get-serial" title="hb_font_get_serial ()"><code class="function">hb_font_get_serial()</code></a>, which invalidates internal caches.</p>
 <div class="refsect3">
-<a name="hb-font-get-parent.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-changed.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -3579,23 +3483,22 @@ hb_font_get_parent (<em class="parameter"><code><a class="link" href="harfbuzz-h
 </tr></tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-font-get-parent.returns"></a><h4>Returns</h4>
-<p>The parent font object. </p>
-<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-4-4-0.html#api-index-4.4.0">4.4.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-ppem"></a><h3>hb_font_get_ppem ()</h3>
+<a name="hb-font-set-funcs"></a><h3>hb_font_set_funcs ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_get_ppem (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                  <em class="parameter"><code>unsigned <span class="type">int</span> *x_ppem</code></em>,
-                  <em class="parameter"><code>unsigned <span class="type">int</span> *y_ppem</code></em>);</pre>
-<p>Fetches the horizontal and vertical points-per-em (ppem) of a font.</p>
+hb_font_set_funcs (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *klass</code></em>,
+                   <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
+                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Replaces the font-functions structure attached to a font, updating
+the font's user-data with <em class="parameter"><code>font</code></em>
+-data and the <em class="parameter"><code>destroy</code></em>
+ callback.</p>
 <div class="refsect3">
-<a name="hb-font-get-ppem.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-set-funcs.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -3609,14 +3512,21 @@ hb_font_get_ppem (<em class="parameter"><code><a class="link" href="harfbuzz-hb-
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>x_ppem</p></td>
-<td class="parameter_description"><p>Horizontal ppem value. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+<td class="parameter_name"><p>klass</p></td>
+<td class="parameter_description"><p>The font-functions structure. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> font_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>y_ppem</p></td>
-<td class="parameter_description"><p>Vertical ppem value. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+<td class="parameter_name"><p>font_data</p></td>
+<td class="parameter_description"><p>Data to attach to <em class="parameter"><code>font</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>font_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
@@ -3625,42 +3535,62 @@ hb_font_get_ppem (<em class="parameter"><code><a class="link" href="harfbuzz-hb-
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-ptem"></a><h3>hb_font_get_ptem ()</h3>
-<pre class="programlisting"><span class="returnvalue">float</span>
-hb_font_get_ptem (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
-<p>Fetches the "point size" of a font. Used in CoreText to
-implement optical sizing.</p>
+<a name="hb-font-set-funcs-data"></a><h3>hb_font_set_funcs_data ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_set_funcs_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                        <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
+                        <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Replaces the user data attached to a font, updating the font's
+<em class="parameter"><code>destroy</code></em>
+ callback.</p>
 <div class="refsect3">
-<a name="hb-font-get-ptem.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-set-funcs-data.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody><tr>
+<tbody>
+<tr>
 <td class="parameter_name"><p>font</p></td>
 <td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
-</tr></tbody>
+</tr>
+<tr>
+<td class="parameter_name"><p>font_data</p></td>
+<td class="parameter_description"><p>Data to attach to <em class="parameter"><code>font</code></em>
+. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>font_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-font-get-ptem.returns"></a><h4>Returns</h4>
-<p> Point size.  A value of zero means "not set."</p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-1-6-0.html#api-index-1.6.0">1.6.0</a></p>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-scale"></a><h3>hb_font_get_scale ()</h3>
+<a name="hb-font-subtract-glyph-origin-for-direction"></a><h3>hb_font_subtract_glyph_origin_for_direction ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_get_scale (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                   <em class="parameter"><code><span class="type">int</span> *x_scale</code></em>,
-                   <em class="parameter"><code><span class="type">int</span> *y_scale</code></em>);</pre>
-<p>Fetches the horizontal and vertical scale of a font.</p>
+hb_font_subtract_glyph_origin_for_direction
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *x</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *y</code></em>);</pre>
+<p>Subtracts the origin coordinates from an (X,Y) point coordinate,
+in the specified glyph ID in the specified font.</p>
+<p>Calls the appropriate direction-specific variant (horizontal
+or vertical) depending on the value of <em class="parameter"><code>direction</code></em>
+.</p>
 <div class="refsect3">
-<a name="hb-font-get-scale.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-subtract-glyph-origin-for-direction.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -3674,14 +3604,26 @@ hb_font_get_scale (<em class="parameter"><code><a class="link" href="harfbuzz-hb
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>x_scale</p></td>
-<td class="parameter_description"><p>Horizontal scale value. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>y_scale</p></td>
-<td class="parameter_description"><p>Vertical scale value. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+<td class="parameter_name"><p>direction</p></td>
+<td class="parameter_description"><p>The direction of the text segment</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x</p></td>
+<td class="parameter_description"><p>Input = The original X coordinate
+Output = The X coordinate minus the X-coordinate of the origin. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for input and for returning results. Default is transfer full."><span class="acronym">inout</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y</p></td>
+<td class="parameter_description"><p>Input = The original Y coordinate
+Output = The Y coordinate minus the Y-coordinate of the origin. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for input and for returning results. Default is transfer full."><span class="acronym">inout</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
@@ -3690,12 +3632,39 @@ hb_font_get_scale (<em class="parameter"><code><a class="link" href="harfbuzz-hb
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-synthetic-slant"></a><h3>hb_font_get_synthetic_slant ()</h3>
-<pre class="programlisting"><span class="returnvalue">float</span>
-hb_font_get_synthetic_slant (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
-<p>Fetches the "synthetic slant" of a font.</p>
+<a name="hb-font-funcs-create"></a><h3>hb_font_funcs_create ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="returnvalue">hb_font_funcs_t</span></a> *
+hb_font_funcs_create (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
+<p>Creates a new <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> structure of font functions.</p>
 <div class="refsect3">
-<a name="hb-font-get-synthetic-slant.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-funcs-create.returns"></a><h4>Returns</h4>
+<p>The font-functions structure. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-font-funcs-get-empty"></a><h3>hb_font_funcs_get_empty ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="returnvalue">hb_font_funcs_t</span></a> *
+hb_font_funcs_get_empty (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
+<p>Fetches an empty font-functions structure.</p>
+<div class="refsect3">
+<a name="hb-font-funcs-get-empty.returns"></a><h4>Returns</h4>
+<p>The font-functions structure. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-font-funcs-reference"></a><h3>hb_font_funcs_reference ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="returnvalue">hb_font_funcs_t</span></a> *
+hb_font_funcs_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>);</pre>
+<p>Increases the reference count on a font-functions structure.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-font-funcs-reference.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -3703,69 +3672,57 @@ hb_font_get_synthetic_slant (<em class="parameter"><code><a class="link" href="h
 <col width="200px" class="parameters_annotations">
 </colgroup>
 <tbody><tr>
-<td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>The font-functions structure</p></td>
 <td class="parameter_annotations"> </td>
 </tr></tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-get-synthetic-slant.returns"></a><h4>Returns</h4>
-<p> Synthetic slant.  By default is zero.</p>
+<a name="hb-font-funcs-reference.returns"></a><h4>Returns</h4>
+<p> The font-functions structure</p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-3-3-0.html#api-index-3.3.0">3.3.0</a></p>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-user-data"></a><h3>hb_font_get_user_data ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span> *
-hb_font_get_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>);</pre>
-<p>Fetches the user-data object associated with the specified key,
-attached to the specified font object.</p>
+<a name="hb-font-funcs-destroy"></a><h3>hb_font_funcs_destroy ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_funcs_destroy (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>);</pre>
+<p>Decreases the reference count on a font-functions structure. When
+the reference count reaches zero, the font-functions structure is
+destroyed, freeing all memory.</p>
 <p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
-<a name="hb-font-get-user-data.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-funcs-destroy.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<tbody><tr>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>The font-functions structure</p></td>
 <td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>key</p></td>
-<td class="parameter_description"><p>The user-data key to query</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-</tbody>
+</tr></tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-font-get-user-data.returns"></a><h4>Returns</h4>
-<p>Pointer to the user data. </p>
-<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
-</div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-variation-glyph"></a><h3>hb_font_get_variation_glyph ()</h3>
+<a name="hb-font-funcs-set-user-data"></a><h3>hb_font_funcs_set_user_data ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_font_get_variation_glyph (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>,
-                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> variation_selector</code></em>,
-                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *glyph</code></em>);</pre>
-<p>Fetches the glyph ID for a Unicode code point when followed by
-by the specified variation-selector code point, in the specified
-font.</p>
+hb_font_funcs_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
+                             <em class="parameter"><code><span class="type">void</span> *data</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
+<p>Attaches a user-data key/data pair to the specified font-functions structure.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
-<a name="hb-font-get-variation-glyph.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-funcs-set-user-data.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -3774,50 +3731,51 @@ font.</p>
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>The font-functions structure</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>unicode</p></td>
-<td class="parameter_description"><p>The Unicode code point to query</p></td>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The user-data key to set</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>variation_selector</p></td>
-<td class="parameter_description"><p>The  variation-selector code point to query</p></td>
+<td class="parameter_name"><p>data</p></td>
+<td class="parameter_description"><p>A pointer to the user data set</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID retrieved. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>replace</p></td>
+<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-get-variation-glyph.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
+<a name="hb-font-funcs-set-user-data.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-1-2-3.html#api-index-1.2.3">1.2.3</a></p>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-variation-glyph-func-t"></a><h3>hb_font_get_variation_glyph_func_t ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-<span class="c_punctuation">(</span>*hb_font_get_variation_glyph_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                       <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
-                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>,
-                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> variation_selector</code></em>,
-                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *glyph</code></em>,
-                                       <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
-<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
-<p>This method should retrieve the glyph ID for a specified Unicode code point
-followed by a specified Variation Selector code point. Glyph IDs must be
-returned in a <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> output parameter.</p>
+<a name="hb-font-funcs-get-user-data"></a><h3>hb_font_funcs_get_user_data ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span> *
+hb_font_funcs_get_user_data (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>);</pre>
+<p>Fetches the user data associated with the specified key,
+attached to the specified font-functions structure.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
-<a name="hb-font-get-variation-glyph-func-t.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-funcs-get-user-data.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -3826,139 +3784,94 @@ returned in a <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" titl
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>font_data</p></td>
-<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
-user data pointer</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>unicode</p></td>
-<td class="parameter_description"><p>The Unicode code point to query</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>variation_selector</p></td>
-<td class="parameter_description"><p>The  variation-selector code point to query</p></td>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>The font-functions structure</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID retrieved. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The user-data key to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-get-variation-glyph-func-t.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
+<a name="hb-font-funcs-get-user-data.returns"></a><h4>Returns</h4>
+<p>A pointer to the user data. </p>
+<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
 </div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-var-coords-design"></a><h3>hb_font_get_var_coords_design ()</h3>
-<pre class="programlisting">const <span class="returnvalue">float</span> *
-hb_font_get_var_coords_design (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                               <em class="parameter"><code>unsigned <span class="type">int</span> *length</code></em>);</pre>
-<p>Fetches the list of variation coordinates (in design-space units) currently
-set on a font.</p>
-<p>Note that this returned array may only contain values for some
-(or none) of the axes; omitted axes effectively have their default
-values.</p>
-<p>Return value is valid as long as variation coordinates of the font
-are not modified.</p>
+<a name="hb-font-funcs-make-immutable"></a><h3>hb_font_funcs_make_immutable ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_funcs_make_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>);</pre>
+<p>Makes a font-functions structure immutable.</p>
 <div class="refsect3">
-<a name="hb-font-get-var-coords-design.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-funcs-make-immutable.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<tbody><tr>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>The font-functions structure</p></td>
 <td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>length</p></td>
-<td class="parameter_description"><p>Number of coordinates retrieved. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-</tbody>
+</tr></tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-font-get-var-coords-design.returns"></a><h4>Returns</h4>
-<p> coordinates array</p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-3-3-0.html#api-index-3.3.0">3.3.0</a></p>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-var-coords-normalized"></a><h3>hb_font_get_var_coords_normalized ()</h3>
-<pre class="programlisting">const <span class="returnvalue">int</span> *
-hb_font_get_var_coords_normalized (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                   <em class="parameter"><code>unsigned <span class="type">int</span> *length</code></em>);</pre>
-<p>Fetches the list of normalized variation coordinates currently
-set on a font.</p>
-<p>Note that this returned array may only contain values for some
-(or none) of the axes; omitted axes effectively have zero values.</p>
-<p>Return value is valid as long as variation coordinates of the font
-are not modified.</p>
+<a name="hb-font-funcs-is-immutable"></a><h3>hb_font_funcs_is_immutable ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_font_funcs_is_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>);</pre>
+<p>Tests whether a font-functions structure is immutable.</p>
 <div class="refsect3">
-<a name="hb-font-get-var-coords-normalized.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-funcs-is-immutable.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<tbody><tr>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>The font-functions structure</p></td>
 <td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>length</p></td>
-<td class="parameter_description"><p>Number of coordinates retrieved. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-</tbody>
+</tr></tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-get-var-coords-normalized.returns"></a><h4>Returns</h4>
-<p> coordinates array</p>
+<a name="hb-font-funcs-is-immutable.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if <em class="parameter"><code>ffuncs</code></em>
+is immutable, <code class="literal">false</code> otherwise</p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-1-4-2.html#api-index-1.4.2">1.4.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-glyph-from-string"></a><h3>hb_font_glyph_from_string ()</h3>
+<a name="hb-font-get-glyph-contour-point-func-t"></a><h3>hb_font_get_glyph_contour_point_func_t ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_font_glyph_from_string (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                           <em class="parameter"><code>const <span class="type">char</span> *s</code></em>,
-                           <em class="parameter"><code><span class="type">int</span> len</code></em>,
-                           <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *glyph</code></em>);</pre>
-<p>Fetches the glyph ID from <em class="parameter"><code>font</code></em>
- that matches the specified string.
-Strings of the format <code class="literal">gidDDD</code> or <code class="literal">uniUUUU</code> are parsed automatically.</p>
-<div class="note">Note: <em class="parameter"><code>len</code></em> == -1 means the string is null-terminated.</div>
+<span class="c_punctuation">(</span>*hb_font_get_glyph_contour_point_func_t<span class="c_punctuation">)</span>
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                                <em class="parameter"><code>unsigned <span class="type">int</span> point_index</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *x</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *y</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
+<p>This method should retrieve the (X,Y) coordinates (in font units) for a
+specified contour point in a glyph. Each coordinate must be returned as
+an <a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> output parameter.</p>
 <div class="refsect3">
-<a name="hb-font-glyph-from-string.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-contour-point-func-t.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -3972,47 +3885,56 @@ Strings of the format <code class="literal">gidDDD</code> or <code class="litera
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>s</p></td>
-<td class="parameter_description"><p>string to query. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=len][<acronym title="Generics and defining elements of containers and arrays."><span class="acronym">element-type</span></acronym> uint8_t]</span></td>
+<td class="parameter_name"><p>font_data</p></td>
+<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
+user data pointer</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>len</p></td>
-<td class="parameter_description"><p>The length of the string <em class="parameter"><code>s</code></em>
-</p></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID corresponding to the string requested. </p></td>
+<td class="parameter_name"><p>point_index</p></td>
+<td class="parameter_description"><p>The contour-point index to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x</p></td>
+<td class="parameter_description"><p>The X value retrieved for the contour point. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y</p></td>
+<td class="parameter_description"><p>The Y value retrieved for the contour point. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-glyph-from-string.returns"></a><h4>Returns</h4>
+<a name="hb-font-get-glyph-contour-point-func-t.returns"></a><h4>Returns</h4>
 <p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-glyph-to-string"></a><h3>hb_font_glyph_to_string ()</h3>
+<a name="hb-font-funcs-set-glyph-contour-point-func"></a><h3>hb_font_funcs_set_glyph_contour_point_func ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_glyph_to_string (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                         <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
-                         <em class="parameter"><code><span class="type">char</span> *s</code></em>,
-                         <em class="parameter"><code>unsigned <span class="type">int</span> size</code></em>);</pre>
-<p>Fetches the name of the specified glyph ID in <em class="parameter"><code>font</code></em>
- and returns
-it in string <em class="parameter"><code>s</code></em>
-.</p>
-<p>If the glyph ID has no name in <em class="parameter"><code>font</code></em>
-, a string of the form <code class="literal">gidDDD</code> is
-generated, with <code class="literal">DDD</code> being the glyph ID.</p>
+hb_font_funcs_set_glyph_contour_point_func
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-contour-point-func-t" title="hb_font_get_glyph_contour_point_func_t ()"><span class="type">hb_font_get_glyph_contour_point_func_t</span></a> func</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-contour-point-func-t" title="hb_font_get_glyph_contour_point_func_t ()"><span class="type">hb_font_get_glyph_contour_point_func_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-font-glyph-to-string.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-funcs-set-glyph-contour-point-func.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -4021,26 +3943,27 @@ generated, with <code class="literal">DDD</code> being the glyph ID.</p>
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>A font-function structure</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>s</p></td>
-<td class="parameter_description"><p>The string containing the glyph name. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=size]</span></td>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>size</p></td>
-<td class="parameter_description"><p>Length of string <em class="parameter"><code>s</code></em>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
 </p></td>
 <td class="parameter_annotations"> </td>
 </tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
 </tbody>
 </table></div>
 </div>
@@ -4048,97 +3971,177 @@ generated, with <code class="literal">DDD</code> being the glyph ID.</p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-is-immutable"></a><h3>hb_font_is_immutable ()</h3>
+<a name="hb-font-get-glyph-extents-func-t"></a><h3>hb_font_get_glyph_extents_func_t ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_font_is_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
-<p>Tests whether a font object is immutable.</p>
+<span class="c_punctuation">(</span>*hb_font_get_glyph_extents_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                     <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
+                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-glyph-extents-t" title="hb_glyph_extents_t"><span class="type">hb_glyph_extents_t</span></a> *extents</code></em>,
+                                     <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
+<p>This method should retrieve the extents for a specified glyph. Extents must be 
+returned in an <span class="type">hb_glyph_extents</span> output parameter.</p>
 <div class="refsect3">
-<a name="hb-font-is-immutable.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-extents-func-t.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody><tr>
+<tbody>
+<tr>
 <td class="parameter_name"><p>font</p></td>
 <td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
-</tr></tbody>
+</tr>
+<tr>
+<td class="parameter_name"><p>font_data</p></td>
+<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
+user data pointer</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>extents</p></td>
+<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-font.html#hb-glyph-extents-t" title="hb_glyph_extents_t"><span class="type">hb_glyph_extents_t</span></a> retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-is-immutable.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if <em class="parameter"><code>font</code></em>
-is immutable, <code class="literal">false</code> otherwise</p>
+<a name="hb-font-get-glyph-extents-func-t.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-make-immutable"></a><h3>hb_font_make_immutable ()</h3>
+<a name="hb-font-funcs-set-glyph-extents-func"></a><h3>hb_font_funcs_set_glyph_extents_func ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_make_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
-<p>Makes <em class="parameter"><code>font</code></em>
- immutable.</p>
+hb_font_funcs_set_glyph_extents_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-extents-func-t" title="hb_font_get_glyph_extents_func_t ()"><span class="type">hb_font_get_glyph_extents_func_t</span></a> func</code></em>,
+                                      <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-extents-func-t" title="hb_font_get_glyph_extents_func_t ()"><span class="type">hb_font_get_glyph_extents_func_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-font-make-immutable.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-funcs-set-glyph-extents-func.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody><tr>
-<td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<tbody>
+<tr>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>A font-function structure</p></td>
 <td class="parameter_annotations"> </td>
-</tr></tbody>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
 </table></div>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-reference"></a><h3>hb_font_reference ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="returnvalue">hb_font_t</span></a> *
-hb_font_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
-<p>Increases the reference count on the given font object.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<a name="hb-font-get-glyph-from-name-func-t"></a><h3>hb_font_get_glyph_from_name_func_t ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="c_punctuation">(</span>*hb_font_get_glyph_from_name_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                       <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
+                                       <em class="parameter"><code>const <span class="type">char</span> *name</code></em>,
+                                       <em class="parameter"><code><span class="type">int</span> len</code></em>,
+                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *glyph</code></em>,
+                                       <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
+<p>This method should retrieve the glyph ID that corresponds to a glyph-name
+string.</p>
 <div class="refsect3">
-<a name="hb-font-reference.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-from-name-func-t.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody><tr>
+<tbody>
+<tr>
 <td class="parameter_name"><p>font</p></td>
 <td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
-</tr></tbody>
+</tr>
+<tr>
+<td class="parameter_name"><p>font_data</p></td>
+<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
+user data pointer</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>name</p></td>
+<td class="parameter_description"><p>The name string to query. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=len]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>len</p></td>
+<td class="parameter_description"><p>The length of the name queried</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-reference.returns"></a><h4>Returns</h4>
-<p>The <em class="parameter"><code>font</code></em>
-object. </p>
-<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+<a name="hb-font-get-glyph-from-name-func-t.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-set-face"></a><h3>hb_font_set_face ()</h3>
+<a name="hb-font-funcs-set-glyph-from-name-func"></a><h3>hb_font_funcs_set_glyph_from_name_func ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_set_face (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
-<p>Sets <em class="parameter"><code>face</code></em>
- as the font-face value of <em class="parameter"><code>font</code></em>
-.</p>
+hb_font_funcs_set_glyph_from_name_func
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-from-name-func-t" title="hb_font_get_glyph_from_name_func_t ()"><span class="type">hb_font_get_glyph_from_name_func_t</span></a> func</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-from-name-func-t" title="hb_font_get_glyph_from_name_func_t ()"><span class="type">hb_font_get_glyph_from_name_func_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-font-set-face.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-funcs-set-glyph-from-name-func.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -4147,34 +4150,549 @@ hb_font_set_face (<em class="parameter"><code><a class="link" href="harfbuzz-hb-
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>A font-function structure</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>face</p></td>
-<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> to assign</p></td>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-1-4-3.html#api-index-1.4.3">1.4.3</a></p>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-font-get-glyph-advance-func-t"></a><h3>hb_font_get_glyph_advance_func_t ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
+<span class="c_punctuation">(</span>*hb_font_get_glyph_advance_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                     <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
+                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                                     <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
+<p>This method should retrieve the advance for a specified glyph. The
+method must return an <a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a>.</p>
+<div class="refsect3">
+<a name="hb-font-get-glyph-advance-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>font_data</p></td>
+<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
+user data pointer</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-font-get-glyph-advance-func-t.returns"></a><h4>Returns</h4>
+<p> The advance of <em class="parameter"><code>glyph</code></em>
+within <em class="parameter"><code>font</code></em>
+</p>
+</div>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-font-funcs-set-glyph-h-advance-func"></a><h3>hb_font_funcs_set_glyph_h_advance_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_funcs_set_glyph_h_advance_func
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-advance-func-t" title="hb_font_get_glyph_h_advance_func_t"><span class="type">hb_font_get_glyph_h_advance_func_t</span></a> func</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-advance-func-t" title="hb_font_get_glyph_h_advance_func_t"><span class="type">hb_font_get_glyph_h_advance_func_t</span></a>.</p>
+<div class="refsect3">
+<a name="hb-font-funcs-set-glyph-h-advance-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-font-funcs-set-glyph-v-advance-func"></a><h3>hb_font_funcs_set_glyph_v_advance_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_funcs_set_glyph_v_advance_func
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-advance-func-t" title="hb_font_get_glyph_v_advance_func_t"><span class="type">hb_font_get_glyph_v_advance_func_t</span></a> func</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-advance-func-t" title="hb_font_get_glyph_v_advance_func_t"><span class="type">hb_font_get_glyph_v_advance_func_t</span></a>.</p>
+<div class="refsect3">
+<a name="hb-font-funcs-set-glyph-v-advance-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-font-get-glyph-advances-func-t"></a><h3>hb_font_get_glyph_advances_func_t ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+<span class="c_punctuation">(</span>*hb_font_get_glyph_advances_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                      <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
+                                      <em class="parameter"><code>unsigned <span class="type">int</span> count</code></em>,
+                                      <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *first_glyph</code></em>,
+                                      <em class="parameter"><code><span class="type">unsigned </span> glyph_stride</code></em>,
+                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *first_advance</code></em>,
+                                      <em class="parameter"><code><span class="type">unsigned </span> advance_stride</code></em>,
+                                      <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
+<p>This method should retrieve the advances for a sequence of glyphs.</p>
+<div class="refsect3">
+<a name="hb-font-get-glyph-advances-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>font_data</p></td>
+<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
+user data pointer</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>count</p></td>
+<td class="parameter_description"><p>The number of glyph IDs in the sequence queried</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>first_glyph</p></td>
+<td class="parameter_description"><p>The first glyph ID to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>glyph_stride</p></td>
+<td class="parameter_description"><p>The stride between successive glyph IDs</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>first_advance</p></td>
+<td class="parameter_description"><p>The first advance retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>advance_stride</p></td>
+<td class="parameter_description"><p>The stride between successive advances</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-font-funcs-set-glyph-h-advances-func"></a><h3>hb_font_funcs_set_glyph_h_advances_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_funcs_set_glyph_h_advances_func
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-advances-func-t" title="hb_font_get_glyph_h_advances_func_t"><span class="type">hb_font_get_glyph_h_advances_func_t</span></a> func</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-advances-func-t" title="hb_font_get_glyph_h_advances_func_t"><span class="type">hb_font_get_glyph_h_advances_func_t</span></a>.</p>
+<div class="refsect3">
+<a name="hb-font-funcs-set-glyph-h-advances-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-1-8-6.html#api-index-1.8.6">1.8.6</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-font-funcs-set-glyph-v-advances-func"></a><h3>hb_font_funcs_set_glyph_v_advances_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_funcs_set_glyph_v_advances_func
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-advances-func-t" title="hb_font_get_glyph_v_advances_func_t"><span class="type">hb_font_get_glyph_v_advances_func_t</span></a> func</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-advances-func-t" title="hb_font_get_glyph_v_advances_func_t"><span class="type">hb_font_get_glyph_v_advances_func_t</span></a>.</p>
+<div class="refsect3">
+<a name="hb-font-funcs-set-glyph-v-advances-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-1-8-6.html#api-index-1.8.6">1.8.6</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-font-get-glyph-kerning-func-t"></a><h3>hb_font_get_glyph_kerning_func_t ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
+<span class="c_punctuation">(</span>*hb_font_get_glyph_kerning_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                     <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
+                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> first_glyph</code></em>,
+                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> second_glyph</code></em>,
+                                     <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>This method should retrieve the kerning-adjustment value for a glyph-pair in
+the specified font, for horizontal text segments.</p>
+<div class="refsect3">
+<a name="hb-font-get-glyph-kerning-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>font_data</p></td>
+<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
+user data pointer</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>first_glyph</p></td>
+<td class="parameter_description"><p>The glyph ID of the first glyph in the glyph pair</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>second_glyph</p></td>
+<td class="parameter_description"><p>The glyph ID of the second glyph in the glyph pair</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-font-funcs-set-glyph-h-kerning-func"></a><h3>hb_font_funcs_set_glyph_h_kerning_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_funcs_set_glyph_h_kerning_func
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-kerning-func-t" title="hb_font_get_glyph_h_kerning_func_t"><span class="type">hb_font_get_glyph_h_kerning_func_t</span></a> func</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-kerning-func-t" title="hb_font_get_glyph_h_kerning_func_t"><span class="type">hb_font_get_glyph_h_kerning_func_t</span></a>.</p>
+<div class="refsect3">
+<a name="hb-font-funcs-set-glyph-h-kerning-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-font-get-glyph-origin-func-t"></a><h3>hb_font_get_glyph_origin_func_t ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="c_punctuation">(</span>*hb_font_get_glyph_origin_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                    <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
+                                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *x</code></em>,
+                                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *y</code></em>,
+                                    <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
+<p>This method should retrieve the (X,Y) coordinates (in font units) of the
+origin for a glyph. Each coordinate must be returned in an <a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a>
+output parameter.</p>
+<div class="refsect3">
+<a name="hb-font-get-glyph-origin-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>font_data</p></td>
+<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
+user data pointer</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x</p></td>
+<td class="parameter_description"><p>The X coordinate of the origin. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y</p></td>
+<td class="parameter_description"><p>The Y coordinate of the origin. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-font-get-glyph-origin-func-t.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
+</div>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-font-funcs-set-glyph-h-origin-func"></a><h3>hb_font_funcs_set_glyph_h_origin_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_funcs_set_glyph_h_origin_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-origin-func-t" title="hb_font_get_glyph_h_origin_func_t"><span class="type">hb_font_get_glyph_h_origin_func_t</span></a> func</code></em>,
+                                       <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-h-origin-func-t" title="hb_font_get_glyph_h_origin_func_t"><span class="type">hb_font_get_glyph_h_origin_func_t</span></a>.</p>
+<div class="refsect3">
+<a name="hb-font-funcs-set-glyph-h-origin-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>A font-function structure</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-set-funcs"></a><h3>hb_font_set_funcs ()</h3>
+<a name="hb-font-funcs-set-glyph-v-origin-func"></a><h3>hb_font_funcs_set_glyph_v_origin_func ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_set_funcs (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *klass</code></em>,
-                   <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
-                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Replaces the font-functions structure attached to a font, updating
-the font's user-data with <em class="parameter"><code>font</code></em>
--data and the <em class="parameter"><code>destroy</code></em>
- callback.</p>
+hb_font_funcs_set_glyph_v_origin_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-origin-func-t" title="hb_font_get_glyph_v_origin_func_t"><span class="type">hb_font_get_glyph_v_origin_func_t</span></a> func</code></em>,
+                                       <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-v-origin-func-t" title="hb_font_get_glyph_v_origin_func_t"><span class="type">hb_font_get_glyph_v_origin_func_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-font-set-funcs.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-funcs-set-glyph-v-origin-func.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -4183,24 +4701,24 @@ the font's user-data with <em class="parameter"><code>font</code></em>
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>A font-function structure</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>klass</p></td>
-<td class="parameter_description"><p>The font-functions structure. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> font_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>font_data</p></td>
-<td class="parameter_description"><p>Data to attach to <em class="parameter"><code>font</code></em>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
 </p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
 <td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>font_data</code></em>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
 is not needed anymore. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
 </tr>
@@ -4211,16 +4729,19 @@ is not needed anymore. </p></td>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-set-funcs-data"></a><h3>hb_font_set_funcs_data ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_set_funcs_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                        <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
-                        <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Replaces the user data attached to a font, updating the font's
-<em class="parameter"><code>destroy</code></em>
- callback.</p>
+<a name="hb-font-get-glyph-name-func-t"></a><h3>hb_font_get_glyph_name_func_t ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="c_punctuation">(</span>*hb_font_get_glyph_name_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                  <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
+                                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                                  <em class="parameter"><code><span class="type">char</span> *name</code></em>,
+                                  <em class="parameter"><code>unsigned <span class="type">int</span> size</code></em>,
+                                  <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
+<p>This method should retrieve the glyph name that corresponds to a
+glyph ID. The name should be returned in a string output parameter.</p>
 <div class="refsect3">
-<a name="hb-font-set-funcs-data.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-glyph-name-func-t.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -4235,31 +4756,49 @@ hb_font_set_funcs_data (<em class="parameter"><code><a class="link" href="harfbu
 </tr>
 <tr>
 <td class="parameter_name"><p>font_data</p></td>
-<td class="parameter_description"><p>Data to attach to <em class="parameter"><code>font</code></em>
-</p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
+user data pointer</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>font_data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>name</p></td>
+<td class="parameter_description"><p>Name string retrieved for the glyph ID. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=size]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>size</p></td>
+<td class="parameter_description"><p>Length of the glyph-name string retrieved</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<div class="refsect3">
+<a name="hb-font-get-glyph-name-func-t.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
+</div>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-set-parent"></a><h3>hb_font_set_parent ()</h3>
+<a name="hb-font-funcs-set-glyph-name-func"></a><h3>hb_font_funcs_set_glyph_name_func ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_set_parent (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *parent</code></em>);</pre>
-<p>Sets the parent font of <em class="parameter"><code>font</code></em>
-.</p>
+hb_font_funcs_set_glyph_name_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-name-func-t" title="hb_font_get_glyph_name_func_t ()"><span class="type">hb_font_get_glyph_name_func_t</span></a> func</code></em>,
+                                   <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-glyph-name-func-t" title="hb_font_get_glyph_name_func_t ()"><span class="type">hb_font_get_glyph_name_func_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-font-set-parent.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-funcs-set-glyph-name-func.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -4268,30 +4807,45 @@ hb_font_set_parent (<em class="parameter"><code><a class="link" href="harfbuzz-h
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>A font-function structure</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>parent</p></td>
-<td class="parameter_description"><p>The parent font object to assign</p></td>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-1-0-5.html#api-index-1.0.5">1.0.5</a></p>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-set-ppem"></a><h3>hb_font_set_ppem ()</h3>
+<a name="hb-font-draw-glyph-func-t"></a><h3>hb_font_draw_glyph_func_t ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_set_ppem (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                  <em class="parameter"><code>unsigned <span class="type">int</span> x_ppem</code></em>,
-                  <em class="parameter"><code>unsigned <span class="type">int</span> y_ppem</code></em>);</pre>
-<p>Sets the horizontal and vertical pixels-per-em (ppem) of a font.</p>
+<span class="c_punctuation">(</span>*hb_font_draw_glyph_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                              <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
+                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-draw.html#hb-draw-funcs-t" title="hb_draw_funcs_t"><span class="type">hb_draw_funcs_t</span></a> *draw_funcs</code></em>,
+                              <em class="parameter"><code><span class="type">void</span> *draw_data</code></em>,
+                              <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
 <div class="refsect3">
-<a name="hb-font-set-ppem.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-draw-glyph-func-t.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -4305,31 +4859,47 @@ hb_font_set_ppem (<em class="parameter"><code><a class="link" href="harfbuzz-hb-
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>x_ppem</p></td>
-<td class="parameter_description"><p>Horizontal ppem value to assign</p></td>
+<td class="parameter_name"><p>font_data</p></td>
+<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
+user data pointer</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>y_ppem</p></td>
-<td class="parameter_description"><p>Vertical ppem value to assign</p></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>draw_funcs</p></td>
+<td class="parameter_description"><p>The draw functions to send the shape data to</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>draw_data</p></td>
+<td class="parameter_description"><p>The data accompanying the draw functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-set-ptem"></a><h3>hb_font_set_ptem ()</h3>
+<a name="hb-font-funcs-set-draw-glyph-func"></a><h3>hb_font_funcs_set_draw_glyph_func ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_set_ptem (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                  <em class="parameter"><code><span class="type">float</span> ptem</code></em>);</pre>
-<p>Sets the "point size" of a font. Set to zero to unset.
-Used in CoreText to implement optical sizing.</p>
-<div class="note">Note: There are 72 points in an inch.</div>
+hb_font_funcs_set_draw_glyph_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-draw-glyph-func-t" title="hb_font_draw_glyph_func_t ()"><span class="type">hb_font_draw_glyph_func_t</span></a> func</code></em>,
+                                   <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-draw-glyph-func-t" title="hb_font_draw_glyph_func_t ()"><span class="type">hb_font_draw_glyph_func_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-font-set-ptem.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-funcs-set-draw-glyph-func.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -4338,30 +4908,47 @@ Used in CoreText to implement optical sizing.</p>
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>A font-function structure</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>ptem</p></td>
-<td class="parameter_description"><p>font size in points.</p></td>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-1-6-0.html#api-index-1.6.0">1.6.0</a></p>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-set-scale"></a><h3>hb_font_set_scale ()</h3>
+<a name="hb-font-paint-glyph-func-t"></a><h3>hb_font_paint_glyph_func_t ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_set_scale (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                   <em class="parameter"><code><span class="type">int</span> x_scale</code></em>,
-                   <em class="parameter"><code><span class="type">int</span> y_scale</code></em>);</pre>
-<p>Sets the horizontal and vertical scale of a font.</p>
+<span class="c_punctuation">(</span>*hb_font_paint_glyph_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                               <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
+                               <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                               <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *paint_funcs</code></em>,
+                               <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                               <em class="parameter"><code>unsigned <span class="type">int</span> palette_index</code></em>,
+                               <em class="parameter"><code><a class="link" href="harfbuzz-hb-ot-color.html#hb-color-t" title="hb_color_t"><span class="type">hb_color_t</span></a> foreground</code></em>,
+                               <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
 <div class="refsect3">
-<a name="hb-font-set-scale.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-paint-glyph-func-t.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -4375,35 +4962,57 @@ hb_font_set_scale (<em class="parameter"><code><a class="link" href="harfbuzz-hb
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>x_scale</p></td>
-<td class="parameter_description"><p>Horizontal scale value to assign</p></td>
+<td class="parameter_name"><p>font_data</p></td>
+<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
+user data pointer</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>y_scale</p></td>
-<td class="parameter_description"><p>Vertical scale value to assign</p></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_funcs</p></td>
+<td class="parameter_description"><p>The paint functions to use</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>The data accompanying the paint functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>palette_index</p></td>
+<td class="parameter_description"><p>The color palette to use</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>foreground</p></td>
+<td class="parameter_description"><p>The foreground color</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-set-synthetic-slant"></a><h3>hb_font_set_synthetic_slant ()</h3>
+<a name="hb-font-funcs-set-paint-glyph-func"></a><h3>hb_font_funcs_set_paint_glyph_func ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_set_synthetic_slant (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                             <em class="parameter"><code><span class="type">float</span> slant</code></em>);</pre>
-<p>Sets the "synthetic slant" of a font.  By default is zero.
-Synthetic slant is the graphical skew that the renderer
-applies to the font at rendering time.</p>
-<p>HarfBuzz needs to know this value to adjust shaping results,
-metrics, and style values to match the slanted rendering.</p>
-<div class="note">Note: The slant value is a ratio.  For example, a
-20% slant would be represented as a 0.2 value.</div>
+hb_font_funcs_set_paint_glyph_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph-func-t" title="hb_font_paint_glyph_func_t ()"><span class="type">hb_font_paint_glyph_func_t</span></a> func</code></em>,
+                                    <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph-func-t" title="hb_font_paint_glyph_func_t ()"><span class="type">hb_font_paint_glyph_func_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-font-set-synthetic-slant.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-funcs-set-paint-glyph-func.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -4412,33 +5021,46 @@ metrics, and style values to match the slanted rendering.</p>
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>A font-function structure</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>slant</p></td>
-<td class="parameter_description"><p>synthetic slant value.</p></td>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is no longer needed. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-3-3-0.html#api-index-3.3.0">3.3.0</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-font-set-user-data"></a><h3>hb_font_set_user_data ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_font_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
-                       <em class="parameter"><code><span class="type">void</span> *data</code></em>,
-                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
-                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
-<p>Attaches a user-data key/data pair to the specified font object.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-font-get-nominal-glyph-func-t"></a><h3>hb_font_get_nominal_glyph_func_t ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="c_punctuation">(</span>*hb_font_get_nominal_glyph_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                     <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
+                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>,
+                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *glyph</code></em>,
+                                     <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
+<p>This method should retrieve the nominal glyph ID for a specified Unicode code
+point. Glyph IDs must be returned in a <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> output parameter.</p>
 <div class="refsect3">
-<a name="hb-font-set-user-data.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-nominal-glyph-func-t.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -4452,50 +5074,45 @@ hb_font_set_user_data (<em class="parameter"><code><a class="link" href="harfbuz
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>key</p></td>
-<td class="parameter_description"><p>The user-data key</p></td>
+<td class="parameter_name"><p>font_data</p></td>
+<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
+user data pointer</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>data</p></td>
-<td class="parameter_description"><p>A pointer to the user data</p></td>
+<td class="parameter_name"><p>unicode</p></td>
+<td class="parameter_description"><p>The Unicode code point to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>replace</p></td>
-<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-set-user-data.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
+<a name="hb-font-get-nominal-glyph-func-t.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-set-variations"></a><h3>hb_font_set_variations ()</h3>
+<a name="hb-font-funcs-set-nominal-glyph-func"></a><h3>hb_font_funcs_set_nominal_glyph_func ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_set_variations (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                        <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-variation-t" title="hb_variation_t"><span class="type">hb_variation_t</span></a> *variations</code></em>,
-                        <em class="parameter"><code>unsigned <span class="type">int</span> variations_length</code></em>);</pre>
-<p>Applies a list of font-variation settings to a font.</p>
-<p>Note that this overrides all existing variations set on <em class="parameter"><code>font</code></em>
-.
-Axes not included in <em class="parameter"><code>variations</code></em>
- will be effectively set to their
-default values.</p>
+hb_font_funcs_set_nominal_glyph_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-nominal-glyph-func-t" title="hb_font_get_nominal_glyph_func_t ()"><span class="type">hb_font_get_nominal_glyph_func_t</span></a> func</code></em>,
+                                      <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-nominal-glyph-func-t" title="hb_font_get_nominal_glyph_func_t ()"><span class="type">hb_font_get_nominal_glyph_func_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-font-set-variations.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-funcs-set-nominal-glyph-func.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -4504,41 +5121,50 @@ default values.</p>
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>A font-function structure</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>variations</p></td>
-<td class="parameter_description"><p>Array of variation settings to apply. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=variations_length]</span></td>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>variations_length</p></td>
-<td class="parameter_description"><p>Number of variations to apply</p></td>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-1-4-2.html#api-index-1.4.2">1.4.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-1-2-3.html#api-index-1.2.3">1.2.3</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-set-var-coords-design"></a><h3>hb_font_set_var_coords_design ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_set_var_coords_design (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                               <em class="parameter"><code>const <span class="type">float</span> *coords</code></em>,
-                               <em class="parameter"><code>unsigned <span class="type">int</span> coords_length</code></em>);</pre>
-<p>Applies a list of variation coordinates (in design-space units)
-to a font.</p>
-<p>Note that this overrides all existing variations set on <em class="parameter"><code>font</code></em>
-.
-Axes not included in <em class="parameter"><code>coords</code></em>
- will be effectively set to their
-default values.</p>
+<a name="hb-font-get-nominal-glyphs-func-t"></a><h3>hb_font_get_nominal_glyphs_func_t ()</h3>
+<pre class="programlisting">unsigned <span class="returnvalue">int</span>
+<span class="c_punctuation">(</span>*hb_font_get_nominal_glyphs_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                      <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
+                                      <em class="parameter"><code>unsigned <span class="type">int</span> count</code></em>,
+                                      <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *first_unicode</code></em>,
+                                      <em class="parameter"><code>unsigned <span class="type">int</span> unicode_stride</code></em>,
+                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *first_glyph</code></em>,
+                                      <em class="parameter"><code>unsigned <span class="type">int</span> glyph_stride</code></em>,
+                                      <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
+<p>This method should retrieve the nominal glyph IDs for a sequence of
+Unicode code points. Glyph IDs must be returned in a <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a>
+output parameter.</p>
 <div class="refsect3">
-<a name="hb-font-set-var-coords-design.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-nominal-glyphs-func-t.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -4552,37 +5178,60 @@ default values.</p>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>coords</p></td>
-<td class="parameter_description"><p>Array of variation coordinates to apply. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=coords_length]</span></td>
+<td class="parameter_name"><p>font_data</p></td>
+<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
+user data pointer</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>coords_length</p></td>
-<td class="parameter_description"><p>Number of coordinates to apply</p></td>
+<td class="parameter_name"><p>count</p></td>
+<td class="parameter_description"><p>number of code points to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>first_unicode</p></td>
+<td class="parameter_description"><p>The first Unicode code point to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>unicode_stride</p></td>
+<td class="parameter_description"><p>The stride between successive code points</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>first_glyph</p></td>
+<td class="parameter_description"><p>The first glyph ID retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>glyph_stride</p></td>
+<td class="parameter_description"><p>The stride between successive glyph IDs</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-1-4-2.html#api-index-1.4.2">1.4.2</a></p>
+<div class="refsect3">
+<a name="hb-font-get-nominal-glyphs-func-t.returns"></a><h4>Returns</h4>
+<p> the number of code points processed</p>
+</div>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-set-var-coords-normalized"></a><h3>hb_font_set_var_coords_normalized ()</h3>
+<a name="hb-font-funcs-set-nominal-glyphs-func"></a><h3>hb_font_funcs_set_nominal_glyphs_func ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_set_var_coords_normalized (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                   <em class="parameter"><code>const <span class="type">int</span> *coords</code></em>,
-                                   <em class="parameter"><code>unsigned <span class="type">int</span> coords_length</code></em>);</pre>
-<p>Applies a list of variation coordinates (in normalized units)
-to a font.</p>
-<p>Note that this overrides all existing variations set on <em class="parameter"><code>font</code></em>
-.
-Axes not included in <em class="parameter"><code>coords</code></em>
- will be effectively set to their
-default values.</p>
-<div class="note">Note: Coordinates should be normalized to 2.14.</div>
+hb_font_funcs_set_nominal_glyphs_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-nominal-glyphs-func-t" title="hb_font_get_nominal_glyphs_func_t ()"><span class="type">hb_font_get_nominal_glyphs_func_t</span></a> func</code></em>,
+                                       <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-nominal-glyphs-func-t" title="hb_font_get_nominal_glyphs_func_t ()"><span class="type">hb_font_get_nominal_glyphs_func_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-font-set-var-coords-normalized.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-funcs-set-nominal-glyphs-func.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -4591,34 +5240,48 @@ default values.</p>
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>A font-function structure</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>coords</p></td>
-<td class="parameter_description"><p>Array of variation coordinates to apply. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=coords_length]</span></td>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>coords_length</p></td>
-<td class="parameter_description"><p>Number of coordinates to apply</p></td>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-1-4-2.html#api-index-1.4.2">1.4.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-2-0-0.html#api-index-2.0.0">2.0.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-set-var-named-instance"></a><h3>hb_font_set_var_named_instance ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_set_var_named_instance (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                <em class="parameter"><code><span class="type">unsigned </span> instance_index</code></em>);</pre>
-<p>Sets design coords of a font from a named instance index.</p>
+<a name="hb-font-get-variation-glyph-func-t"></a><h3>hb_font_get_variation_glyph_func_t ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="c_punctuation">(</span>*hb_font_get_variation_glyph_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                       <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
+                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>,
+                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> variation_selector</code></em>,
+                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *glyph</code></em>,
+                                       <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
+<p>This method should retrieve the glyph ID for a specified Unicode code point
+followed by a specified Variation Selector code point. Glyph IDs must be
+returned in a <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> output parameter.</p>
 <div class="refsect3">
-<a name="hb-font-set-var-named-instance.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-variation-glyph-func-t.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -4628,36 +5291,55 @@ hb_font_set_var_named_instance (<em class="parameter"><code><a class="link" href
 <tbody>
 <tr>
 <td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p>a font.</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>instance_index</p></td>
-<td class="parameter_description"><p>named instance index.</p></td>
+<td class="parameter_name"><p>font_data</p></td>
+<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
+user data pointer</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>unicode</p></td>
+<td class="parameter_description"><p>The Unicode code point to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>variation_selector</p></td>
+<td class="parameter_description"><p>The  variation-selector code point to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph ID retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-2-6-0.html#api-index-2.6.0">2.6.0</a></p>
+<div class="refsect3">
+<a name="hb-font-get-variation-glyph-func-t.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
+</div>
 </div>
 <hr>
-<div class="refsect2">
-<a name="hb-font-subtract-glyph-origin-for-direction"></a><h3>hb_font_subtract_glyph_origin_for_direction ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_subtract_glyph_origin_for_direction
-                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *x</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *y</code></em>);</pre>
-<p>Subtracts the origin coordinates from an (X,Y) point coordinate,
-in the specified glyph ID in the specified font.</p>
-<p>Calls the appropriate direction-specific variant (horizontal
-or vertical) depending on the value of <em class="parameter"><code>direction</code></em>
-.</p>
+<div class="refsect2">
+<a name="hb-font-funcs-set-variation-glyph-func"></a><h3>hb_font_funcs_set_variation_glyph_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_funcs_set_variation_glyph_func
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-get-variation-glyph-func-t" title="hb_font_get_variation_glyph_func_t ()"><span class="type">hb_font_get_variation_glyph_func_t</span></a> func</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-font.html#hb-font-get-variation-glyph-func-t" title="hb_font_get_variation_glyph_func_t ()"><span class="type">hb_font_get_variation_glyph_func_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-font-subtract-glyph-origin-for-direction.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-funcs-set-variation-glyph-func.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -4666,36 +5348,31 @@ or vertical) depending on the value of <em class="parameter"><code>direction</co
 </colgroup>
 <tbody>
 <tr>
-<td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<td class="parameter_name"><p>ffuncs</p></td>
+<td class="parameter_description"><p>A font-function structure</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>glyph</p></td>
-<td class="parameter_description"><p>The glyph ID to query</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>direction</p></td>
-<td class="parameter_description"><p>The direction of the text segment</p></td>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>x</p></td>
-<td class="parameter_description"><p>Input = The original X coordinate
-Output = The X coordinate minus the X-coordinate of the origin. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for input and for returning results. Default is transfer full."><span class="acronym">inout</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>y</p></td>
-<td class="parameter_description"><p>Input = The original Y coordinate
-Output = The Y coordinate minus the Y-coordinate of the origin. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for input and for returning results. Default is transfer full."><span class="acronym">inout</span></acronym>]</span></td>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-1-2-3.html#api-index-1.2.3">1.2.3</a></p>
 </div>
 <hr>
 <div class="refsect2">
@@ -4743,6 +5420,49 @@ table within <em class="parameter"><code>face</code></em>
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-font-get-font-extents-func-t"></a><h3>hb_font_get_font_extents_func_t ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="c_punctuation">(</span>*hb_font_get_font_extents_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                    <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
+                                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-extents-t" title="hb_font_extents_t"><span class="type">hb_font_extents_t</span></a> *extents</code></em>,
+                                    <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>This method should retrieve the extents for a font.</p>
+<div class="refsect3">
+<a name="hb-font-get-font-extents-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>font_data</p></td>
+<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
+user data pointer</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>extents</p></td>
+<td class="parameter_description"><p>The font extents retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-font-funcs-set-font-h-extents-func"></a><h3>hb_font_funcs_set_font_h_extents_func ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
 hb_font_funcs_set_font_h_extents_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> *ffuncs</code></em>,
@@ -4833,56 +5553,14 @@ is not needed anymore. </p></td>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-extents-for-direction"></a><h3>hb_font_get_extents_for_direction ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_font_get_extents_for_direction (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
-                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-extents-t" title="hb_font_extents_t"><span class="type">hb_font_extents_t</span></a> *extents</code></em>);</pre>
-<p>Fetches the extents for a font in a text segment of the
-specified direction.</p>
-<p>Calls the appropriate direction-specific variant (horizontal
-or vertical) depending on the value of <em class="parameter"><code>direction</code></em>
-.</p>
-<div class="refsect3">
-<a name="hb-font-get-extents-for-direction.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>direction</p></td>
-<td class="parameter_description"><p>The direction of the text segment</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>extents</p></td>
-<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-font.html#hb-font-extents-t" title="hb_font_extents_t"><span class="type">hb_font_extents_t</span></a> retrieved. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-</tbody>
-</table></div>
-</div>
-<p class="since">Since: <a class="link" href="api-index-1-1-3.html#api-index-1.1.3">1.1.3</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-font-get-font-extents-func-t"></a><h3>hb_font_get_font_extents_func_t ()</h3>
+<a name="hb-font-get-h-extents"></a><h3>hb_font_get_h_extents ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-<span class="c_punctuation">(</span>*hb_font_get_font_extents_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                                    <em class="parameter"><code><span class="type">void</span> *font_data</code></em>,
-                                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-extents-t" title="hb_font_extents_t"><span class="type">hb_font_extents_t</span></a> *extents</code></em>,
-                                    <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
-<p>This method should retrieve the extents for a font.</p>
+hb_font_get_h_extents (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-extents-t" title="hb_font_extents_t"><span class="type">hb_font_extents_t</span></a> *extents</code></em>);</pre>
+<p>Fetches the extents for a specified font, for horizontal
+text segments.</p>
 <div class="refsect3">
-<a name="hb-font-get-font-extents-func-t.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-h-extents.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -4896,35 +5574,29 @@ or vertical) depending on the value of <em class="parameter"><code>direction</co
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>font_data</p></td>
-<td class="parameter_description"><p><em class="parameter"><code>font</code></em>
-user data pointer</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
 <td class="parameter_name"><p>extents</p></td>
 <td class="parameter_description"><p>The font extents retrieved. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
-<tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
 </tbody>
 </table></div>
 </div>
+<div class="refsect3">
+<a name="hb-font-get-h-extents.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-1-1-3.html#api-index-1.1.3">1.1.3</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-h-extents"></a><h3>hb_font_get_h_extents ()</h3>
+<a name="hb-font-get-v-extents"></a><h3>hb_font_get_v_extents ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_font_get_h_extents (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+hb_font_get_v_extents (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
                        <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-extents-t" title="hb_font_extents_t"><span class="type">hb_font_extents_t</span></a> *extents</code></em>);</pre>
-<p>Fetches the extents for a specified font, for horizontal
+<p>Fetches the extents for a specified font, for vertical
 text segments.</p>
 <div class="refsect3">
-<a name="hb-font-get-h-extents.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-v-extents.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -4946,21 +5618,25 @@ text segments.</p>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-font-get-h-extents.returns"></a><h4>Returns</h4>
+<a name="hb-font-get-v-extents.returns"></a><h4>Returns</h4>
 <p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-1-1-3.html#api-index-1.1.3">1.1.3</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-v-extents"></a><h3>hb_font_get_v_extents ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_font_get_v_extents (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-extents-t" title="hb_font_extents_t"><span class="type">hb_font_extents_t</span></a> *extents</code></em>);</pre>
-<p>Fetches the extents for a specified font, for vertical
-text segments.</p>
+<a name="hb-font-get-extents-for-direction"></a><h3>hb_font_get_extents_for_direction ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_font_get_extents_for_direction (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-extents-t" title="hb_font_extents_t"><span class="type">hb_font_extents_t</span></a> *extents</code></em>);</pre>
+<p>Fetches the extents for a font in a text segment of the
+specified direction.</p>
+<p>Calls the appropriate direction-specific variant (horizontal
+or vertical) depending on the value of <em class="parameter"><code>direction</code></em>
+.</p>
 <div class="refsect3">
-<a name="hb-font-get-v-extents.parameters"></a><h4>Parameters</h4>
+<a name="hb-font-get-extents-for-direction.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -4974,34 +5650,31 @@ text segments.</p>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
+<td class="parameter_name"><p>direction</p></td>
+<td class="parameter_description"><p>The direction of the text segment</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
 <td class="parameter_name"><p>extents</p></td>
-<td class="parameter_description"><p>The font extents retrieved. </p></td>
+<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-font.html#hb-font-extents-t" title="hb_font_extents_t"><span class="type">hb_font_extents_t</span></a> retrieved. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-font-get-v-extents.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
-</div>
 <p class="since">Since: <a class="link" href="api-index-1-1-3.html#api-index-1.1.3">1.1.3</a></p>
 </div>
 </div>
 <div class="refsect1">
 <a name="harfbuzz-hb-font.other_details"></a><h2>Types and Values</h2>
 <div class="refsect2">
-<a name="hb-font-funcs-t"></a><h3>hb_font_funcs_t</h3>
-<pre class="programlisting">typedef struct hb_font_funcs_t hb_font_funcs_t;
+<a name="HB-FONT-NO-VAR-NAMED-INSTANCE:CAPS"></a><h3>HB_FONT_NO_VAR_NAMED_INSTANCE</h3>
+<pre class="programlisting">#define HB_FONT_NO_VAR_NAMED_INSTANCE 0xFFFFFFFF
 </pre>
-<p>Data type containing a set of virtual methods used for
-working on <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> font objects.</p>
-<p>HarfBuzz provides a lightweight default function for each of
-
-the methods in <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a>. Client programs can implement
-their own replacements for the individual font functions, as
-needed, and replace the default by calling the setter for a
-method.</p>
+<p>Constant signifying that a font does not have any
+named-instance index set.  This is the default of
+a font.</p>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
@@ -5015,6 +5688,16 @@ an <a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_positi
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-font-get-glyph-v-advance-func-t"></a><h3>hb_font_get_glyph_v_advance_func_t</h3>
+<pre class="programlisting">typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t;
+</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
+<p>This method should retrieve the advance for a specified glyph, in
+vertical-direction text segments. Advances must be returned in
+an <a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> output parameter.</p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-font-get-glyph-h-advances-func-t"></a><h3>hb_font_get_glyph_h_advances_func_t</h3>
 <pre class="programlisting">typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_h_advances_func_t;
 </pre>
@@ -5024,6 +5707,15 @@ horizontal-direction text segments.</p>
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-font-get-glyph-v-advances-func-t"></a><h3>hb_font_get_glyph_v_advances_func_t</h3>
+<pre class="programlisting">typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_v_advances_func_t;
+</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
+<p>This method should retrieve the advances for a sequence of glyphs, in
+vertical-direction text segments.</p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-font-get-glyph-h-kerning-func-t"></a><h3>hb_font_get_glyph_h_kerning_func_t</h3>
 <pre class="programlisting">typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
 </pre>
@@ -5043,25 +5735,6 @@ coordinate must be returned in an <a class="link" href="harfbuzz-hb-common.html#
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-font-get-glyph-v-advance-func-t"></a><h3>hb_font_get_glyph_v_advance_func_t</h3>
-<pre class="programlisting">typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t;
-</pre>
-<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
-<p>This method should retrieve the advance for a specified glyph, in
-vertical-direction text segments. Advances must be returned in
-an <a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> output parameter.</p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-font-get-glyph-v-advances-func-t"></a><h3>hb_font_get_glyph_v_advances_func_t</h3>
-<pre class="programlisting">typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_v_advances_func_t;
-</pre>
-<p>A virtual method for the <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a> of an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p>
-<p>This method should retrieve the advances for a sequence of glyphs, in
-vertical-direction text segments.</p>
-</div>
-<hr>
-<div class="refsect2">
 <a name="hb-font-get-glyph-v-origin-func-t"></a><h3>hb_font_get_glyph_v_origin_func_t</h3>
 <pre class="programlisting">typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t;
 </pre>
@@ -5072,6 +5745,20 @@ must be returned in an <a class="link" href="harfbuzz-hb-common.html#hb-position
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-font-funcs-t"></a><h3>hb_font_funcs_t</h3>
+<pre class="programlisting">typedef struct hb_font_funcs_t hb_font_funcs_t;
+</pre>
+<p>Data type containing a set of virtual methods used for
+working on <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> font objects.</p>
+<p>HarfBuzz provides a lightweight default function for each of
+
+the methods in <a class="link" href="harfbuzz-hb-font.html#hb-font-funcs-t" title="hb_font_funcs_t"><span class="type">hb_font_funcs_t</span></a>. Client programs can implement
+their own replacements for the individual font functions, as
+needed, and replace the default by calling the setter for a
+method.</p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-font-t"></a><h3>hb_font_t</h3>
 <pre class="programlisting">typedef struct hb_font_t hb_font_t;
 </pre>
index d5705d4..78b5e69 100644 (file)
 <a class="link" href="harfbuzz-hb-ft.html#hb-ft-font-set-funcs" title="hb_ft_font_set_funcs ()">hb_ft_font_set_funcs</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-ft.html#hb-ft-hb-font-changed" title="hb_ft_hb_font_changed ()">hb_ft_hb_font_changed</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
 </tbody>
 </table></div>
 </div>
@@ -159,6 +167,9 @@ functions are not thread-safe either.</div>
 hb_ft_face_create (<em class="parameter"><code><span class="type">FT_Face</span> ft_face</code></em>,
                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
 <p>Creates an <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> face object from the specified FT_Face.</p>
+<p>Note that this is using the FT_Face object just to get at the underlying
+font data, and fonts created from the returned <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> will use the native
+HarfBuzz font implementation, unless you call <a class="link" href="harfbuzz-hb-ft.html#hb-ft-font-set-funcs" title="hb_ft_font_set_funcs ()"><code class="function">hb_ft_font_set_funcs()</code></a> on them.</p>
 <p>This variant of the function does not provide any life-cycle management.</p>
 <p>Most client programs should use <a class="link" href="harfbuzz-hb-ft.html#hb-ft-face-create-referenced" title="hb_ft_face_create_referenced ()"><code class="function">hb_ft_face_create_referenced()</code></a>
 (or, perhaps, <a class="link" href="harfbuzz-hb-ft.html#hb-ft-face-create-cached" title="hb_ft_face_create_cached ()"><code class="function">hb_ft_face_create_cached()</code></a>) instead. </p>
@@ -201,6 +212,9 @@ after the <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
 hb_ft_face_create_cached (<em class="parameter"><code><span class="type">FT_Face</span> ft_face</code></em>);</pre>
 <p>Creates an <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> face object from the specified FT_Face.</p>
+<p>Note that this is using the FT_Face object just to get at the underlying
+font data, and fonts created from the returned <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> will use the native
+HarfBuzz font implementation, unless you call <a class="link" href="harfbuzz-hb-ft.html#hb-ft-font-set-funcs" title="hb_ft_font_set_funcs ()"><code class="function">hb_ft_font_set_funcs()</code></a> on them.</p>
 <p>This variant of the function caches the newly created <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a>
 face object, using the <em class="parameter"><code>generic</code></em>
  pointer of <em class="parameter"><code>ft_face</code></em>
@@ -240,6 +254,9 @@ reference counted.</p>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
 hb_ft_face_create_referenced (<em class="parameter"><code><span class="type">FT_Face</span> ft_face</code></em>);</pre>
 <p>Creates an <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> face object from the specified FT_Face.</p>
+<p>Note that this is using the FT_Face object just to get at the underlying
+font data, and fonts created from the returned <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> will use the native
+HarfBuzz font implementation, unless you call <a class="link" href="harfbuzz-hb-ft.html#hb-ft-font-set-funcs" title="hb_ft_font_set_funcs ()"><code class="function">hb_ft_font_set_funcs()</code></a> on them.</p>
 <p>This is the preferred variant of the hb_ft_face_create*
 function family, because it calls <code class="function">FT_Reference_Face()</code> on <em class="parameter"><code>ft_face</code></em>
 ,
@@ -396,6 +413,9 @@ variation-axis settings on the FT_Face.</p>
 hb_ft_font_get_face (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
 <p>Fetches the FT_Face associated with the specified <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a>
 font object.</p>
+<p>This function works with <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> objects created by
+<a class="link" href="harfbuzz-hb-ft.html#hb-ft-font-create" title="hb_ft_font_create ()"><code class="function">hb_ft_font_create()</code></a> or <a class="link" href="harfbuzz-hb-ft.html#hb-ft-font-create-referenced" title="hb_ft_font_create_referenced ()"><code class="function">hb_ft_font_create_referenced()</code></a>.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
 <a name="hb-ft-font-get-face.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
@@ -424,8 +444,12 @@ font object.</p>
 <pre class="programlisting"><span class="returnvalue">FT_Face</span>
 hb_ft_font_lock_face (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
 <p>Gets the FT_Face associated with <em class="parameter"><code>font</code></em>
-, This face will be kept around until
-you call <a class="link" href="harfbuzz-hb-ft.html#hb-ft-font-unlock-face" title="hb_ft_font_unlock_face ()"><code class="function">hb_ft_font_unlock_face()</code></a>.</p>
+.</p>
+<p>This face will be kept around and access to the FT_Face object
+from other HarfBuzz API wil be blocked until you call <a class="link" href="harfbuzz-hb-ft.html#hb-ft-font-unlock-face" title="hb_ft_font_unlock_face ()"><code class="function">hb_ft_font_unlock_face()</code></a>.</p>
+<p>This function works with <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> objects created by
+<a class="link" href="harfbuzz-hb-ft.html#hb-ft-font-create" title="hb_ft_font_create ()"><code class="function">hb_ft_font_create()</code></a> or <a class="link" href="harfbuzz-hb-ft.html#hb-ft-font-create-referenced" title="hb_ft_font_create_referenced ()"><code class="function">hb_ft_font_create_referenced()</code></a>.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
 <a name="hb-ft-font-lock-face.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
@@ -445,7 +469,7 @@ you call <a class="link" href="harfbuzz-hb-ft.html#hb-ft-font-unlock-face" title
 <a name="hb-ft-font-lock-face.returns"></a><h4>Returns</h4>
 <p>the FT_Face associated with <em class="parameter"><code>font</code></em>
 or <code class="literal">NULL</code>. </p>
-<p><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></p>
+<p><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>][<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-2-6-5.html#api-index-2.6.5">2.6.5</a></p>
 </div>
@@ -455,6 +479,7 @@ or <code class="literal">NULL</code>. </p>
 <pre class="programlisting"><span class="returnvalue">void</span>
 hb_ft_font_unlock_face (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
 <p>Releases an FT_Face previously obtained with <a class="link" href="harfbuzz-hb-ft.html#hb-ft-font-lock-face" title="hb_ft_font_lock_face ()"><code class="function">hb_ft_font_lock_face()</code></a>.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
 <a name="hb-ft-font-unlock-face.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
@@ -481,6 +506,8 @@ hb_ft_font_set_load_flags (<em class="parameter"><code><a class="link" href="har
 <p>Sets the FT_Load_Glyph load flags for the specified <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a>.</p>
 <p>For more information, see 
 https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html<span class="type">ft_load_xxx</span></p>
+<p>This function works with <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> objects created by
+<a class="link" href="harfbuzz-hb-ft.html#hb-ft-font-create" title="hb_ft_font_create ()"><code class="function">hb_ft_font_create()</code></a> or <a class="link" href="harfbuzz-hb-ft.html#hb-ft-font-create-referenced" title="hb_ft_font_create_referenced ()"><code class="function">hb_ft_font_create_referenced()</code></a>.</p>
 <div class="refsect3">
 <a name="hb-ft-font-set-load-flags.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
@@ -513,6 +540,8 @@ hb_ft_font_get_load_flags (<em class="parameter"><code><a class="link" href="har
 <p>Fetches the FT_Load_Glyph load flags of the specified <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a>.</p>
 <p>For more information, see 
 https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html<span class="type">ft_load_xxx</span></p>
+<p>This function works with <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> objects created by
+<a class="link" href="harfbuzz-hb-ft.html#hb-ft-font-create" title="hb_ft_font_create ()"><code class="function">hb_ft_font_create()</code></a> or <a class="link" href="harfbuzz-hb-ft.html#hb-ft-font-create-referenced" title="hb_ft_font_create_referenced ()"><code class="function">hb_ft_font_create_referenced()</code></a>.</p>
 <div class="refsect3">
 <a name="hb-ft-font-get-load-flags.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
@@ -530,7 +559,7 @@ https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html<span c
 </div>
 <div class="refsect3">
 <a name="hb-ft-font-get-load-flags.returns"></a><h4>Returns</h4>
-<p> FT_Load_Glyph flags found</p>
+<p> FT_Load_Glyph flags found, or 0</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-1-0-5.html#api-index-1.0.5">1.0.5</a></p>
 </div>
@@ -546,9 +575,12 @@ existing <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t
 functions even if that <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> face object was initially
 created with <a class="link" href="harfbuzz-hb-face.html#hb-face-create" title="hb_face_create ()"><code class="function">hb_face_create()</code></a>, and therefore was not
 initially configured to use FreeType font functions.</p>
-<p>An <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> face object created with <a class="link" href="harfbuzz-hb-ft.html#hb-ft-face-create" title="hb_ft_face_create ()"><code class="function">hb_ft_face_create()</code></a>
+<p>An <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object created with <a class="link" href="harfbuzz-hb-ft.html#hb-ft-font-create" title="hb_ft_font_create ()"><code class="function">hb_ft_font_create()</code></a>
 is preconfigured for FreeType font functions and does not
 require this function to be used.</p>
+<p>Note that if you modify the underlying <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> after
+calling this function, you need to call <a class="link" href="harfbuzz-hb-ft.html#hb-ft-hb-font-changed" title="hb_ft_hb_font_changed ()"><code class="function">hb_ft_hb_font_changed()</code></a>
+to update the underlying FT_Face.</p>
 <div class="note">Note: Internally, this function creates an FT_Face.
 </div>
 <div class="refsect3">
@@ -568,6 +600,41 @@ require this function to be used.</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-1-0-5.html#api-index-1.0.5">1.0.5</a></p>
 </div>
+<hr>
+<div class="refsect2">
+<a name="hb-ft-hb-font-changed"></a><h3>hb_ft_hb_font_changed ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_ft_hb_font_changed (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
+<p>Refreshes the state of the underlying FT_Face of <em class="parameter"><code>font</code></em>
+ when the hb_font_t
+<em class="parameter"><code>font</code></em>
+ has changed.
+This function should be called after changing the size or
+variation-axis settings on the <em class="parameter"><code>font</code></em>
+.
+This call is fast if nothing has changed on <em class="parameter"><code>font</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-ft-hb-font-changed.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to work upon</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-ft-hb-font-changed.returns"></a><h4>Returns</h4>
+<p> true if changed, false otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-4-0.html#api-index-4.4.0">4.4.0</a></p>
+</div>
 </div>
 </div>
 <div class="footer">
index 8d2e314..b1f1936 100644 (file)
 <col width="150px" class="functions_proto_type">
 <col class="functions_proto_name">
 </colgroup>
-<tbody><tr>
+<tbody>
+<tr>
 <td class="function_type">
 <span class="returnvalue">gr_face</span> *
 </td>
 <td class="function_name">
 <a class="link" href="harfbuzz-hb-graphite2.html#hb-graphite2-face-get-gr-face" title="hb_graphite2_face_get_gr_face ()">hb_graphite2_face_get_gr_face</a> <span class="c_punctuation">()</span>
 </td>
-</tr></tbody>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">gr_font</span> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-graphite2.html#hb-graphite2-font-get-gr-font" title="hb_graphite2_font_get_gr_font ()">hb_graphite2_font_get_gr_font</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+</tbody>
 </table></div>
 </div>
 <div class="refsect1">
@@ -81,6 +91,7 @@ not enable <code class="literal">graphite2</code> shaping.</p>
 hb_graphite2_face_get_gr_face (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
 <p>Fetches the Graphite2 gr_face corresponding to the specified
 <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> face object.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
 <a name="hb-graphite2-face-get-gr-face.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
@@ -103,6 +114,37 @@ to query</p></td>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-10.html#api-index-0.9.10">0.9.10</a></p>
 </div>
+<hr>
+<div class="refsect2">
+<a name="hb-graphite2-font-get-gr-font"></a><h3>hb_graphite2_font_get_gr_font ()</h3>
+<pre class="programlisting"><span class="returnvalue">gr_font</span> *
+hb_graphite2_font_get_gr_font (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
+<div class="warning"><p><code class="literal">hb_graphite2_font_get_gr_font</code> has been deprecated since version 1.4.2 and should not be used in newly-written code.</p></div>
+<p>Always returns <code class="literal">NULL</code>. Use <a class="link" href="harfbuzz-hb-graphite2.html#hb-graphite2-face-get-gr-face" title="hb_graphite2_face_get_gr_face ()"><code class="function">hb_graphite2_face_get_gr_face()</code></a> instead.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-graphite2-font-get-gr-font.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p>An <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-graphite2-font-get-gr-font.returns"></a><h4>Returns</h4>
+<p>Graphite2 font associated with <em class="parameter"><code>font</code></em>
+. </p>
+<p><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-10.html#api-index-0.9.10">0.9.10</a></p>
+</div>
 </div>
 <div class="refsect1">
 <a name="harfbuzz-hb-graphite2.other_details"></a><h2>Types and Values</h2>
index c49a42b..b49427c 100644 (file)
 <tbody>
 <tr>
 <td class="function_type">
+<a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-map.html#hb-map-create" title="hb_map_create ()">hb_map_create</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
 </tr>
 <tr>
 <td class="function_type">
+<a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-map.html#hb-map-copy" title="hb_map_copy ()">hb_map_copy</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
 <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-map.html#hb-map-create" title="hb_map_create ()">hb_map_create</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-get-empty" title="hb_map_get_empty ()">hb_map_get_empty</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-map.html#hb-map-del" title="hb_map_del ()">hb_map_del</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-reference" title="hb_map_reference ()">hb_map_reference</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-map.html#hb-map-get" title="hb_map_get ()">hb_map_get</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-set-user-data" title="hb_map_set_user_data ()">hb_map_set_user_data</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
+<span class="returnvalue">void</span> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-map.html#hb-map-get-empty" title="hb_map_get_empty ()">hb_map_get_empty</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-get-user-data" title="hb_map_get_user_data ()">hb_map_get_user_data</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">unsigned <span class="returnvalue">int</span>
+<td class="function_type">
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-map.html#hb-map-get-population" title="hb_map_get_population ()">hb_map_get_population</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-set" title="hb_map_set ()">hb_map_set</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span> *
+<a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-map.html#hb-map-get-user-data" title="hb_map_get_user_data ()">hb_map_get_user_data</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-get" title="hb_map_get ()">hb_map_get</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-map.html#hb-map-del" title="hb_map_del ()">hb_map_del</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 </td>
 </tr>
 <tr>
+<td class="function_type">unsigned <span class="returnvalue">int</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-map.html#hb-map-get-population" title="hb_map_get_population ()">hb_map_get_population</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
 <td class="function_type">
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-map.html#hb-map-reference" title="hb_map_reference ()">hb_map_reference</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-is-equal" title="hb_map_is_equal ()">hb_map_is_equal</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">unsigned <span class="returnvalue">int</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-map.html#hb-map-hash" title="hb_map_hash ()">hb_map_hash</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-map.html#hb-map-set" title="hb_map_set ()">hb_map_set</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-update" title="hb_map_update ()">hb_map_update</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-map.html#hb-map-set-user-data" title="hb_map_set_user_data ()">hb_map_set_user_data</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-map.html#hb-map-next" title="hb_map_next ()">hb_map_next</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-map.html#hb-map-keys" title="hb_map_keys ()">hb_map_keys</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-map.html#hb-map-values" title="hb_map_values ()">hb_map_values</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 </tbody>
@@ -186,6 +241,19 @@ use if desired.</p>
 <div class="refsect1">
 <a name="harfbuzz-hb-map.functions_details"></a><h2>Functions</h2>
 <div class="refsect2">
+<a name="hb-map-create"></a><h3>hb_map_create ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
+hb_map_create (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
+<p>Creates a new, initially empty map.</p>
+<div class="refsect3">
+<a name="hb-map-create.returns"></a><h4>Returns</h4>
+<p>The new <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a>. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-1-7-7.html#api-index-1.7.7">1.7.7</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-map-allocation-successful"></a><h3>hb_map_allocation_successful ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 hb_map_allocation_successful (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>);</pre>
@@ -213,6 +281,35 @@ hb_map_allocation_successful (<em class="parameter"><code>const <a class="link"
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-map-copy"></a><h3>hb_map_copy ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
+hb_map_copy (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>);</pre>
+<p>Allocate a copy of <em class="parameter"><code>map</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-map-copy.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>map</p></td>
+<td class="parameter_description"><p>A map</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-map-copy.returns"></a><h4>Returns</h4>
+<p>Newly-allocated map. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-4-0.html#api-index-4.4.0">4.4.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-map-clear"></a><h3>hb_map_clear ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
 hb_map_clear (<em class="parameter"><code><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>);</pre>
@@ -237,49 +334,44 @@ hb_map_clear (<em class="parameter"><code><a class="link" href="harfbuzz-hb-map.
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-map-create"></a><h3>hb_map_create ()</h3>
+<a name="hb-map-get-empty"></a><h3>hb_map_get_empty ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
-hb_map_create (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
-<p>Creates a new, initially empty map.</p>
-<p><span class="annotation">[Xconstructor]</span></p>
+hb_map_get_empty (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
+<p>Fetches the singleton empty <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-map-create.returns"></a><h4>Returns</h4>
-<p>The new <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a>. </p>
+<a name="hb-map-get-empty.returns"></a><h4>Returns</h4>
+<p>The empty <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a>. </p>
 <p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-1-7-7.html#api-index-1.7.7">1.7.7</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-map-del"></a><h3>hb_map_del ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_map_del (<em class="parameter"><code><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>,
-            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> key</code></em>);</pre>
-<p>Removes <em class="parameter"><code>key</code></em>
- and its stored value from <em class="parameter"><code>map</code></em>
-.</p>
+<a name="hb-map-reference"></a><h3>hb_map_reference ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
+hb_map_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>);</pre>
+<p>Increases the reference count on a map.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
-<a name="hb-map-del.parameters"></a><h4>Parameters</h4>
+<a name="hb-map-reference.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody>
-<tr>
+<tbody><tr>
 <td class="parameter_name"><p>map</p></td>
 <td class="parameter_description"><p>A map</p></td>
 <td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>key</p></td>
-<td class="parameter_description"><p>The key to delete</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-</tbody>
+</tr></tbody>
 </table></div>
 </div>
+<div class="refsect3">
+<a name="hb-map-reference.returns"></a><h4>Returns</h4>
+<p>The map. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
 <p class="since">Since: <a class="link" href="api-index-1-7-7.html#api-index-1.7.7">1.7.7</a></p>
 </div>
 <hr>
@@ -310,15 +402,17 @@ destroyed, freeing all memory.</p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-map-get"></a><h3>hb_map_get ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
-hb_map_get (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>,
-            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> key</code></em>);</pre>
-<p>Fetches the value stored for <em class="parameter"><code>key</code></em>
- in <em class="parameter"><code>map</code></em>
-.</p>
+<a name="hb-map-set-user-data"></a><h3>hb_map_set_user_data ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_map_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>,
+                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
+                      <em class="parameter"><code><span class="type">void</span> *data</code></em>,
+                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
+                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
+<p>Attaches a user-data key/data pair to the specified map.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
-<a name="hb-map-get.parameters"></a><h4>Parameters</h4>
+<a name="hb-map-set-user-data.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -333,66 +427,123 @@ hb_map_get (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-
 </tr>
 <tr>
 <td class="parameter_name"><p>key</p></td>
-<td class="parameter_description"><p>The key to query</p></td>
+<td class="parameter_description"><p>The user-data key to set</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>data</p></td>
+<td class="parameter_description"><p>A pointer to the user data to set</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>replace</p></td>
+<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
+<div class="refsect3">
+<a name="hb-map-set-user-data.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
+</div>
 <p class="since">Since: <a class="link" href="api-index-1-7-7.html#api-index-1.7.7">1.7.7</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-map-get-empty"></a><h3>hb_map_get_empty ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
-hb_map_get_empty (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
-<p>Fetches the singleton empty <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a>.</p>
+<a name="hb-map-get-user-data"></a><h3>hb_map_get_user_data ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span> *
+hb_map_get_user_data (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>,
+                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>);</pre>
+<p>Fetches the user data associated with the specified key,
+attached to the specified map.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
-<a name="hb-map-get-empty.returns"></a><h4>Returns</h4>
-<p>The empty <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a>. </p>
-<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+<a name="hb-map-get-user-data.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>map</p></td>
+<td class="parameter_description"><p>A map</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The user-data key to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-map-get-user-data.returns"></a><h4>Returns</h4>
+<p>A pointer to the user data. </p>
+<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-1-7-7.html#api-index-1.7.7">1.7.7</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-map-get-population"></a><h3>hb_map_get_population ()</h3>
-<pre class="programlisting">unsigned <span class="returnvalue">int</span>
-hb_map_get_population (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>);</pre>
-<p>Returns the number of key-value pairs in the map.</p>
+<a name="hb-map-set"></a><h3>hb_map_set ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_map_set (<em class="parameter"><code><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>,
+            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> key</code></em>,
+            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> value</code></em>);</pre>
+<p>Stores <em class="parameter"><code>key</code></em>
+:<em class="parameter"><code>value</code></em>
+ in the map.</p>
 <div class="refsect3">
-<a name="hb-map-get-population.parameters"></a><h4>Parameters</h4>
+<a name="hb-map-set.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody><tr>
+<tbody>
+<tr>
 <td class="parameter_name"><p>map</p></td>
 <td class="parameter_description"><p>A map</p></td>
 <td class="parameter_annotations"> </td>
-</tr></tbody>
+</tr>
+<tr>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The key to store in the map</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>value</p></td>
+<td class="parameter_description"><p>The value to store for <em class="parameter"><code>key</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-map-get-population.returns"></a><h4>Returns</h4>
-<p> The population of <em class="parameter"><code>map</code></em>
-</p>
-</div>
 <p class="since">Since: <a class="link" href="api-index-1-7-7.html#api-index-1.7.7">1.7.7</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-map-get-user-data"></a><h3>hb_map_get_user_data ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span> *
-hb_map_get_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>,
-                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>);</pre>
-<p>Fetches the user data associated with the specified key,
-attached to the specified map.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<a name="hb-map-get"></a><h3>hb_map_get ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
+hb_map_get (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>,
+            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> key</code></em>);</pre>
+<p>Fetches the value stored for <em class="parameter"><code>key</code></em>
+ in <em class="parameter"><code>map</code></em>
+.</p>
 <div class="refsect3">
-<a name="hb-map-get-user-data.parameters"></a><h4>Parameters</h4>
+<a name="hb-map-get.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -407,16 +558,44 @@ attached to the specified map.</p>
 </tr>
 <tr>
 <td class="parameter_name"><p>key</p></td>
-<td class="parameter_description"><p>The user-data key to query</p></td>
+<td class="parameter_description"><p>The key to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
+<p class="since">Since: <a class="link" href="api-index-1-7-7.html#api-index-1.7.7">1.7.7</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-map-del"></a><h3>hb_map_del ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_map_del (<em class="parameter"><code><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>,
+            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> key</code></em>);</pre>
+<p>Removes <em class="parameter"><code>key</code></em>
+ and its stored value from <em class="parameter"><code>map</code></em>
+.</p>
 <div class="refsect3">
-<a name="hb-map-get-user-data.returns"></a><h4>Returns</h4>
-<p>A pointer to the user data. </p>
-<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
+<a name="hb-map-del.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>map</p></td>
+<td class="parameter_description"><p>A map</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The key to delete</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
 </div>
 <p class="since">Since: <a class="link" href="api-index-1-7-7.html#api-index-1.7.7">1.7.7</a></p>
 </div>
@@ -461,6 +640,34 @@ is found in <em class="parameter"><code>map</code></em>
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-map-get-population"></a><h3>hb_map_get_population ()</h3>
+<pre class="programlisting">unsigned <span class="returnvalue">int</span>
+hb_map_get_population (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>);</pre>
+<p>Returns the number of key-value pairs in the map.</p>
+<div class="refsect3">
+<a name="hb-map-get-population.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>map</p></td>
+<td class="parameter_description"><p>A map</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-map-get-population.returns"></a><h4>Returns</h4>
+<p> The population of <em class="parameter"><code>map</code></em>
+</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-1-7-7.html#api-index-1.7.7">1.7.7</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-map-is-empty"></a><h3>hb_map_is_empty ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 hb_map_is_empty (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>);</pre>
@@ -490,13 +697,51 @@ is empty</p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-map-reference"></a><h3>hb_map_reference ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
-hb_map_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>);</pre>
-<p>Increases the reference count on a map.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<a name="hb-map-is-equal"></a><h3>hb_map_is_equal ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_map_is_equal (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>,
+                 <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *other</code></em>);</pre>
+<p>Tests whether <em class="parameter"><code>map</code></em>
+ and <em class="parameter"><code>other</code></em>
+ are equal (contain the same
+elements).</p>
 <div class="refsect3">
-<a name="hb-map-reference.parameters"></a><h4>Parameters</h4>
+<a name="hb-map-is-equal.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>map</p></td>
+<td class="parameter_description"><p>A map</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>other</p></td>
+<td class="parameter_description"><p>Another map</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-map-is-equal.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if the two maps are equal, <code class="literal">false</code> otherwise.</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-3-0.html#api-index-4.3.0">4.3.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-map-hash"></a><h3>hb_map_hash ()</h3>
+<pre class="programlisting">unsigned <span class="returnvalue">int</span>
+hb_map_hash (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>);</pre>
+<p>Creates a hash representing <em class="parameter"><code>map</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-map-hash.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -511,24 +756,23 @@ hb_map_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-map-reference.returns"></a><h4>Returns</h4>
-<p>The map. </p>
-<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+<a name="hb-map-hash.returns"></a><h4>Returns</h4>
+<p>A hash of <em class="parameter"><code>map</code></em>
+.</p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-1-7-7.html#api-index-1.7.7">1.7.7</a></p>
+<p class="since">Since: <a class="link" href="api-index-4-4-0.html#api-index-4.4.0">4.4.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-map-set"></a><h3>hb_map_set ()</h3>
+<a name="hb-map-update"></a><h3>hb_map_update ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_map_set (<em class="parameter"><code><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>,
-            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> key</code></em>,
-            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> value</code></em>);</pre>
-<p>Stores <em class="parameter"><code>key</code></em>
-:<em class="parameter"><code>value</code></em>
- in the map.</p>
+hb_map_update (<em class="parameter"><code><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>,
+               <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *other</code></em>);</pre>
+<p>Add the contents of <em class="parameter"><code>other</code></em>
+ to <em class="parameter"><code>map</code></em>
+.</p>
 <div class="refsect3">
-<a name="hb-map-set.parameters"></a><h4>Parameters</h4>
+<a name="hb-map-update.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -542,34 +786,31 @@ hb_map_set (<em class="parameter"><code><a class="link" href="harfbuzz-hb-map.ht
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>key</p></td>
-<td class="parameter_description"><p>The key to store in the map</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>value</p></td>
-<td class="parameter_description"><p>The value to store for <em class="parameter"><code>key</code></em>
-</p></td>
+<td class="parameter_name"><p>other</p></td>
+<td class="parameter_description"><p>Another map</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-1-7-7.html#api-index-1.7.7">1.7.7</a></p>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-map-set-user-data"></a><h3>hb_map_set_user_data ()</h3>
+<a name="hb-map-next"></a><h3>hb_map_next ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_map_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>,
-                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
-                      <em class="parameter"><code><span class="type">void</span> *data</code></em>,
-                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
-                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
-<p>Attaches a user-data key/data pair to the specified map.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+hb_map_next (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>,
+             <em class="parameter"><code><span class="type">int</span> *idx</code></em>,
+             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *key</code></em>,
+             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *value</code></em>);</pre>
+<p>Fetches the next key/value pair in <em class="parameter"><code>map</code></em>
+.</p>
+<p>Set <em class="parameter"><code>idx</code></em>
+ to -1 to get started.</p>
+<p>If the map is modified during iteration, the behavior is undefined.</p>
+<p>The order in which the key/values are returned is undefined.</p>
 <div class="refsect3">
-<a name="hb-map-set-user-data.parameters"></a><h4>Parameters</h4>
+<a name="hb-map-next.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -583,41 +824,101 @@ hb_map_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
+<td class="parameter_name"><p>idx</p></td>
+<td class="parameter_description"><p>Iterator internal state. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for input and for returning results. Default is transfer full."><span class="acronym">inout</span></acronym>]</span></td>
+</tr>
+<tr>
 <td class="parameter_name"><p>key</p></td>
-<td class="parameter_description"><p>The user-data key to set</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_description"><p>Key retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>data</p></td>
-<td class="parameter_description"><p>A pointer to the user data to set</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_name"><p>value</p></td>
+<td class="parameter_description"><p>Value retrieved. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-map-next.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if there was a next value, <code class="literal">false</code> otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-map-keys"></a><h3>hb_map_keys ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_map_keys (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>,
+             <em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *keys</code></em>);</pre>
+<p>Add the keys of <em class="parameter"><code>map</code></em>
+ to <em class="parameter"><code>keys</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-map-keys.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
 <tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+<td class="parameter_name"><p>map</p></td>
+<td class="parameter_description"><p>A map</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>replace</p></td>
-<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
+<td class="parameter_name"><p>keys</p></td>
+<td class="parameter_description"><p>A set</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-map-values"></a><h3>hb_map_values ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_map_values (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *map</code></em>,
+               <em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *values</code></em>);</pre>
+<p>Add the values of <em class="parameter"><code>map</code></em>
+ to <em class="parameter"><code>values</code></em>
+.</p>
 <div class="refsect3">
-<a name="hb-map-set-user-data.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
+<a name="hb-map-values.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>map</p></td>
+<td class="parameter_description"><p>A map</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>values</p></td>
+<td class="parameter_description"><p>A set</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-1-7-7.html#api-index-1.7.7">1.7.7</a></p>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
 </div>
 </div>
 <div class="refsect1">
 <a name="harfbuzz-hb-map.other_details"></a><h2>Types and Values</h2>
 <div class="refsect2">
 <a name="HB-MAP-VALUE-INVALID:CAPS"></a><h3>HB_MAP_VALUE_INVALID</h3>
-<pre class="programlisting">#define HB_MAP_VALUE_INVALID ((hb_codepoint_t) -1)
+<pre class="programlisting">#define HB_MAP_VALUE_INVALID HB_CODEPOINT_INVALID
 </pre>
 <p>Unset <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> value.</p>
 <p class="since">Since: <a class="link" href="api-index-1-7-7.html#api-index-1.7.7">1.7.7</a></p>
index 62767d1..35c27c1 100644 (file)
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
+<a class="link" href="harfbuzz-hb-ot-color.html#hb-ot-color-has-paint" title="hb_ot_color_has_paint ()">hb_ot_color_has_paint</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-ot-color.html#hb-ot-color-glyph-has-paint" title="hb_ot_color_glyph_has_paint ()">hb_ot_color_glyph_has_paint</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
 <a class="link" href="harfbuzz-hb-ot-color.html#hb-ot-color-has-palettes" title="hb_ot_color_has_palettes ()">hb_ot_color_has_palettes</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
@@ -421,9 +437,9 @@ Output = the actual number of layers returned (may be zero). </p></td>
 hb_ot_color_glyph_reference_png (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
                                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>);</pre>
 <p>Fetches the PNG image for a glyph. This function takes a font object, not a face object,
-as input. To get an optimally sized PNG blob, the UPEM value must be set on the <em class="parameter"><code>font</code></em>
+as input. To get an optimally sized PNG blob, the PPEM values must be set on the <em class="parameter"><code>font</code></em>
 
-object. If UPEM is unset, the blob returned will be the largest PNG available.</p>
+object. If PPEM is unset, the blob returned will be the largest PNG available.</p>
 <p>If the glyph has no PNG image, the singleton empty blob is returned.</p>
 <div class="refsect3">
 <a name="hb-ot-color-glyph-reference-png.parameters"></a><h4>Parameters</h4>
@@ -496,7 +512,8 @@ hb_ot_color_glyph_reference_svg (<em class="parameter"><code><a class="link" hre
 <a name="hb-ot-color-has-layers"></a><h3>hb_ot_color_has_layers ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 hb_ot_color_has_layers (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
-<p>Tests whether a face includes any <code class="literal">COLR</code> color layers.</p>
+<p>Tests whether a face includes a <code class="literal">COLR</code> table
+with data according to COLRv0.</p>
 <div class="refsect3">
 <a name="hb-ot-color-has-layers.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
@@ -520,6 +537,71 @@ hb_ot_color_has_layers (<em class="parameter"><code><a class="link" href="harfbu
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-ot-color-has-paint"></a><h3>hb_ot_color_has_paint ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_ot_color_has_paint (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
+<p>Tests where a face includes a <code class="literal">COLR</code> table
+with data according to COLRv1.</p>
+<div class="refsect3">
+<a name="hb-ot-color-has-paint.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>face</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> to work upon</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-ot-color-has-paint.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-ot-color-glyph-has-paint"></a><h3>hb_ot_color_glyph_has_paint ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_ot_color_glyph_has_paint (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>);</pre>
+<p>Tests where a face includes COLRv1 paint
+data for <em class="parameter"><code>glyph</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-ot-color-glyph-has-paint.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>face</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> to work upon</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>The glyph index to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-ot-color-glyph-has-paint.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-ot-color-has-palettes"></a><h3>hb_ot_color_has_palettes ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 hb_ot_color_has_palettes (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>);</pre>
@@ -654,6 +736,9 @@ colors. If <em class="parameter"><code>colors</code></em>
 of total colors without storing any actual colors; this can be used
 for allocating a buffer of suitable size before calling
 <a class="link" href="harfbuzz-hb-ot-color.html#hb-ot-color-palette-get-colors" title="hb_ot_color_palette_get_colors ()"><code class="function">hb_ot_color_palette_get_colors()</code></a> a second time.</p>
+<p>The RGBA values in the palette are unpremultiplied. See the
+OpenType spec <a class="ulink" href="https://learn.microsoft.com/en-us/typography/opentype/spec/cpal" target="_top">CPAL</a>
+section for details.</p>
 <div class="refsect3">
 <a name="hb-ot-color-palette-get-colors.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
@@ -795,7 +880,7 @@ specific, themed names (e.g., "Spring", "Summer", "Fall", and "Winter").</p>
 <div class="refsect3">
 <a name="hb-ot-color-palette-get-name-id.returns"></a><h4>Returns</h4>
 <p> the Named ID found for the palette.
-If the requested palette has no name the result is <span class="type">HB_OT_NAME_ID_INVALID</span>.</p>
+If the requested palette has no name the result is <a class="link" href="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-INVALID:CAPS"><span class="type">HB_OT_NAME_ID_INVALID</span></a>.</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-2-1-0.html#api-index-2.1.0">2.1.0</a></p>
 </div>
@@ -819,6 +904,9 @@ channel RGB plus alpha transparency.</p>
 } hb_ot_color_layer_t;
 </pre>
 <p>Pairs of glyph and color index.</p>
+<p>A color index of 0xFFFF does not refer to a palette
+color, but indicates that the foreground color should
+be used.</p>
 <div class="refsect3">
 <a name="hb-ot-color-layer-t.members"></a><h4>Members</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
index a4380a9..aee4bc9 100644 (file)
 </td>
 </tr>
 <tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-collect-features-map" title="hb_ot_layout_collect_features_map ()">hb_ot_layout_collect_features_map</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
 <td class="function_type">unsigned <span class="returnvalue">int</span>
 </td>
 <td class="function_name">
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-font-extents" title="hb_ot_layout_get_font_extents ()">hb_ot_layout_get_font_extents</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-font-extents2" title="hb_ot_layout_get_font_extents2 ()">hb_ot_layout_get_font_extents2</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-baseline-tag-t" title="enum hb_ot_layout_baseline_tag_t"><span class="returnvalue">hb_ot_layout_baseline_tag_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-horizontal-baseline-tag-for-script" title="hb_ot_layout_get_horizontal_baseline_tag_for_script ()">hb_ot_layout_get_horizontal_baseline_tag_for_script</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
 <a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-baseline" title="hb_ot_layout_get_baseline ()">hb_ot_layout_get_baseline</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-baseline2" title="hb_ot_layout_get_baseline2 ()">hb_ot_layout_get_baseline2</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-baseline-with-fallback" title="hb_ot_layout_get_baseline_with_fallback ()">hb_ot_layout_get_baseline_with_fallback</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-baseline-with-fallback2" title="hb_ot_layout_get_baseline_with_fallback2 ()">hb_ot_layout_get_baseline_with_fallback2</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
 <a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-glyph-class-t" title="enum hb_ot_layout_glyph_class_t"><span class="returnvalue">hb_ot_layout_glyph_class_t</span></a>
 </td>
 <td class="function_name">
 </tr>
 <tr>
 <td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-lookup-get-optical-bound" title="hb_ot_layout_lookup_get_optical_bound ()">hb_ot_layout_lookup_get_optical_bound</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
 </td>
 </tr>
 <tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-script-find-language" title="hb_ot_layout_script_find_language ()">hb_ot_layout_script_find_language</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
 <td class="function_type">unsigned <span class="returnvalue">int</span>
 </td>
 <td class="function_name">
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
+<a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-script-select-language2" title="hb_ot_layout_script_select_language2 ()">hb_ot_layout_script_select_language2</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
 <a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-table-find-feature-variations" title="hb_ot_layout_table_find_feature_variations ()">hb_ot_layout_table_find_feature_variations</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 </div>
 <div class="refsect1">
 <a name="harfbuzz-hb-ot-layout.description"></a><h2>Description</h2>
-<p>Functions for querying OpenType Layout features in the font face.</p>
+<p>Functions for querying OpenType Layout features in the font face.
+See the <a class="ulink" href="http://www.microsoft.com/typography/otspec/" target="_top">OpenType specification</a>
+for details.</p>
 </div>
 <div class="refsect1">
 <a name="harfbuzz-hb-ot-layout.functions_details"></a><h2>Functions</h2>
@@ -491,8 +573,8 @@ hb_ot_tags_from_script_and_language (<em class="parameter"><code><a class="link"
 </tr>
 <tr>
 <td class="parameter_name"><p>language</p></td>
-<td class="parameter_description"><p>an <a class="link" href="harfbuzz-hb-common.html#hb-language-t" title="hb_language_t"><span class="type">hb_language_t</span></a> to convert.</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_description"><p>an <a class="link" href="harfbuzz-hb-common.html#hb-language-t" title="hb_language_t"><span class="type">hb_language_t</span></a> to convert. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
 </tr>
 <tr>
 <td class="parameter_name"><p>script_count</p></td>
@@ -609,18 +691,21 @@ list of features is provided, all features will be queried.</p>
 </tr>
 <tr>
 <td class="parameter_name"><p>scripts</p></td>
-<td class="parameter_description"><p>The array of scripts to collect lookups for</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_description"><p>The array of scripts to collect lookups for,
+terminated by <a class="link" href="harfbuzz-hb-common.html#HB-TAG-NONE:CAPS" title="HB_TAG_NONE"><code class="literal">HB_TAG_NONE</code></a>. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> zero-terminated=1]</span></td>
 </tr>
 <tr>
 <td class="parameter_name"><p>languages</p></td>
-<td class="parameter_description"><p>The array of languages to collect lookups for</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_description"><p>The array of languages to collect lookups for,
+terminated by <a class="link" href="harfbuzz-hb-common.html#HB-TAG-NONE:CAPS" title="HB_TAG_NONE"><code class="literal">HB_TAG_NONE</code></a>. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> zero-terminated=1]</span></td>
 </tr>
 <tr>
 <td class="parameter_name"><p>features</p></td>
-<td class="parameter_description"><p>The array of features to collect lookups for</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_description"><p>The array of features to collect lookups for,
+terminated by <a class="link" href="harfbuzz-hb-common.html#HB-TAG-NONE:CAPS" title="HB_TAG_NONE"><code class="literal">HB_TAG_NONE</code></a>. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> zero-terminated=1]</span></td>
 </tr>
 <tr>
 <td class="parameter_name"><p>lookup_indexes</p></td>
@@ -668,22 +753,25 @@ features is provided, all features will be queried.</p>
 </tr>
 <tr>
 <td class="parameter_name"><p>scripts</p></td>
-<td class="parameter_description"><p>The array of scripts to collect features for</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_description"><p>The array of scripts to collect features for,
+terminated by <a class="link" href="harfbuzz-hb-common.html#HB-TAG-NONE:CAPS" title="HB_TAG_NONE"><code class="literal">HB_TAG_NONE</code></a>. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> zero-terminated=1]</span></td>
 </tr>
 <tr>
 <td class="parameter_name"><p>languages</p></td>
-<td class="parameter_description"><p>The array of languages to collect features for</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_description"><p>The array of languages to collect features for,
+terminated by <a class="link" href="harfbuzz-hb-common.html#HB-TAG-NONE:CAPS" title="HB_TAG_NONE"><code class="literal">HB_TAG_NONE</code></a>. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> zero-terminated=1]</span></td>
 </tr>
 <tr>
 <td class="parameter_name"><p>features</p></td>
-<td class="parameter_description"><p>The array of features to collect</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_description"><p>The array of features to collect,
+terminated by <a class="link" href="harfbuzz-hb-common.html#HB-TAG-NONE:CAPS" title="HB_TAG_NONE"><code class="literal">HB_TAG_NONE</code></a>. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> zero-terminated=1]</span></td>
 </tr>
 <tr>
 <td class="parameter_name"><p>feature_indexes</p></td>
-<td class="parameter_description"><p>The array of feature indexes found for the query. </p></td>
+<td class="parameter_description"><p>The set of feature indexes found for the query. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
 </tbody>
@@ -693,6 +781,56 @@ features is provided, all features will be queried.</p>
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-ot-layout-collect-features-map"></a><h3>hb_ot_layout_collect_features_map ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_ot_layout_collect_features_map (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> table_tag</code></em>,
+                                   <em class="parameter"><code><span class="type">unsigned </span> script_index</code></em>,
+                                   <em class="parameter"><code><span class="type">unsigned </span> language_index</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> *feature_map</code></em>);</pre>
+<p>Fetches the mapping from feature tags to feature indexes for
+the specified script and language.</p>
+<div class="refsect3">
+<a name="hb-ot-layout-collect-features-map.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>face</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> to work upon</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>table_tag</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-ot-layout.html#HB-OT-TAG-GSUB:CAPS" title="HB_OT_TAG_GSUB"><span class="type">HB_OT_TAG_GSUB</span></a> or <a class="link" href="harfbuzz-hb-ot-layout.html#HB-OT-TAG-GPOS:CAPS" title="HB_OT_TAG_GPOS"><span class="type">HB_OT_TAG_GPOS</span></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>script_index</p></td>
+<td class="parameter_description"><p>The index of the requested script tag</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>language_index</p></td>
+<td class="parameter_description"><p>The index of the requested language tag</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>feature_map</p></td>
+<td class="parameter_description"><p>The map of feature tag to feature index. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-8-1-0.html#api-index-8.1.0">8.1.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-ot-layout-feature-get-characters"></a><h3>hb_ot_layout_feature_get_characters ()</h3>
 <pre class="programlisting">unsigned <span class="returnvalue">int</span>
 hb_ot_layout_feature_get_characters (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
@@ -961,6 +1099,7 @@ Output = the actual number of lookups returned (may be zero). </p></td>
 <a name="hb-ot-layout-feature-with-variations-get-lookups.returns"></a><h4>Returns</h4>
 <p> Total number of lookups.</p>
 </div>
+<p class="since">Since: <a class="link" href="api-index-1-4-0.html#api-index-1.4.0">1.4.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
@@ -1020,6 +1159,156 @@ Output = the actual number of attachment points returned (may be zero). </p></td
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-ot-layout-get-font-extents"></a><h3>hb_ot_layout_get_font_extents ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_ot_layout_get_font_extents (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                               <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
+                               <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> script_tag</code></em>,
+                               <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> language_tag</code></em>,
+                               <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-extents-t" title="hb_font_extents_t"><span class="type">hb_font_extents_t</span></a> *extents</code></em>);</pre>
+<p>Fetches script/language-specific font extents.  These values are
+looked up in the <code class="literal">BASE</code> table's <code class="literal">MinMax</code> records.</p>
+<p>If no such extents are found, the default extents for the font are
+fetched. As such, the return value of this function can for the
+most part be ignored.  Note that the per-script/language extents
+do not have a line-gap value, and the line-gap is set to zero in
+that case.</p>
+<div class="refsect3">
+<a name="hb-ot-layout-get-font-extents.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p>a font</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>direction</p></td>
+<td class="parameter_description"><p>text direction.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>script_tag</p></td>
+<td class="parameter_description"><p>script tag.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>language_tag</p></td>
+<td class="parameter_description"><p>language tag.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>extents</p></td>
+<td class="parameter_description"><p>font extents if found. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-ot-layout-get-font-extents.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if found script/language-specific font extents.</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-8-0-0.html#api-index-8.0.0">8.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-ot-layout-get-font-extents2"></a><h3>hb_ot_layout_get_font_extents2 ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_ot_layout_get_font_extents2 (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> script</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-language-t" title="hb_language_t"><span class="type">hb_language_t</span></a> language</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-extents-t" title="hb_font_extents_t"><span class="type">hb_font_extents_t</span></a> *extents</code></em>);</pre>
+<p>Fetches script/language-specific font extents.  These values are
+looked up in the <code class="literal">BASE</code> table's <code class="literal">MinMax</code> records.</p>
+<p>If no such extents are found, the default extents for the font are
+fetched. As such, the return value of this function can for the
+most part be ignored.  Note that the per-script/language extents
+do not have a line-gap value, and the line-gap is set to zero in
+that case.</p>
+<p>This function is like <a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-font-extents" title="hb_ot_layout_get_font_extents ()"><code class="function">hb_ot_layout_get_font_extents()</code></a> but takes
+<a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> and <a class="link" href="harfbuzz-hb-common.html#hb-language-t" title="hb_language_t"><span class="type">hb_language_t</span></a> instead of OpenType <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a>.</p>
+<div class="refsect3">
+<a name="hb-ot-layout-get-font-extents2.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p>a font</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>direction</p></td>
+<td class="parameter_description"><p>text direction.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>script</p></td>
+<td class="parameter_description"><p>script.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>language</p></td>
+<td class="parameter_description"><p>language. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>extents</p></td>
+<td class="parameter_description"><p>font extents if found. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-ot-layout-get-font-extents2.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if found script/language-specific font extents.</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-8-0-0.html#api-index-8.0.0">8.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-ot-layout-get-horizontal-baseline-tag-for-script"></a><h3>hb_ot_layout_get_horizontal_baseline_tag_for_script ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-baseline-tag-t" title="enum hb_ot_layout_baseline_tag_t"><span class="returnvalue">hb_ot_layout_baseline_tag_t</span></a>
+hb_ot_layout_get_horizontal_baseline_tag_for_script
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> script</code></em>);</pre>
+<p>Fetches the dominant horizontal baseline tag used by <em class="parameter"><code>script</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-ot-layout-get-horizontal-baseline-tag-for-script.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>script</p></td>
+<td class="parameter_description"><p>a script tag.</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-ot-layout-get-horizontal-baseline-tag-for-script.returns"></a><h4>Returns</h4>
+<p> dominant baseline tag for the <em class="parameter"><code>script</code></em>
+.</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-ot-layout-get-baseline"></a><h3>hb_ot_layout_get_baseline ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 hb_ot_layout_get_baseline (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
@@ -1066,7 +1355,7 @@ hb_ot_layout_get_baseline (<em class="parameter"><code><a class="link" href="har
 <tr>
 <td class="parameter_name"><p>coord</p></td>
 <td class="parameter_description"><p>baseline value if found. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
 </tr>
 </tbody>
 </table></div>
@@ -1079,6 +1368,183 @@ hb_ot_layout_get_baseline (<em class="parameter"><code><a class="link" href="har
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-ot-layout-get-baseline2"></a><h3>hb_ot_layout_get_baseline2 ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_ot_layout_get_baseline2 (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-baseline-tag-t" title="enum hb_ot_layout_baseline_tag_t"><span class="type">hb_ot_layout_baseline_tag_t</span></a> baseline_tag</code></em>,
+                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
+                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> script</code></em>,
+                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-language-t" title="hb_language_t"><span class="type">hb_language_t</span></a> language</code></em>,
+                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *coord</code></em>);</pre>
+<p>Fetches a baseline value from the face.</p>
+<p>This function is like <a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-baseline" title="hb_ot_layout_get_baseline ()"><code class="function">hb_ot_layout_get_baseline()</code></a> but takes
+<a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> and <a class="link" href="harfbuzz-hb-common.html#hb-language-t" title="hb_language_t"><span class="type">hb_language_t</span></a> instead of OpenType <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a>.</p>
+<div class="refsect3">
+<a name="hb-ot-layout-get-baseline2.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p>a font</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>baseline_tag</p></td>
+<td class="parameter_description"><p>a baseline tag</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>direction</p></td>
+<td class="parameter_description"><p>text direction.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>script</p></td>
+<td class="parameter_description"><p>script.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>language</p></td>
+<td class="parameter_description"><p>language, currently unused. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>coord</p></td>
+<td class="parameter_description"><p>baseline value if found. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-ot-layout-get-baseline2.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if found baseline value in the font.</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-8-0-0.html#api-index-8.0.0">8.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-ot-layout-get-baseline-with-fallback"></a><h3>hb_ot_layout_get_baseline_with_fallback ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_ot_layout_get_baseline_with_fallback
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-baseline-tag-t" title="enum hb_ot_layout_baseline_tag_t"><span class="type">hb_ot_layout_baseline_tag_t</span></a> baseline_tag</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> script_tag</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> language_tag</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *coord</code></em>);</pre>
+<p>Fetches a baseline value from the face, and synthesizes
+it if the font does not have it.</p>
+<div class="refsect3">
+<a name="hb-ot-layout-get-baseline-with-fallback.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p>a font</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>baseline_tag</p></td>
+<td class="parameter_description"><p>a baseline tag</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>direction</p></td>
+<td class="parameter_description"><p>text direction.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>script_tag</p></td>
+<td class="parameter_description"><p>script tag.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>language_tag</p></td>
+<td class="parameter_description"><p>language tag, currently unused.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>coord</p></td>
+<td class="parameter_description"><p>baseline value if found. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-ot-layout-get-baseline-with-fallback2"></a><h3>hb_ot_layout_get_baseline_with_fallback2 ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_ot_layout_get_baseline_with_fallback2
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-baseline-tag-t" title="enum hb_ot_layout_baseline_tag_t"><span class="type">hb_ot_layout_baseline_tag_t</span></a> baseline_tag</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> script</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-language-t" title="hb_language_t"><span class="type">hb_language_t</span></a> language</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *coord</code></em>);</pre>
+<p>Fetches a baseline value from the face, and synthesizes
+it if the font does not have it.</p>
+<p>This function is like <a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-baseline-with-fallback" title="hb_ot_layout_get_baseline_with_fallback ()"><code class="function">hb_ot_layout_get_baseline_with_fallback()</code></a> but takes
+<a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> and <a class="link" href="harfbuzz-hb-common.html#hb-language-t" title="hb_language_t"><span class="type">hb_language_t</span></a> instead of OpenType <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a>.</p>
+<div class="refsect3">
+<a name="hb-ot-layout-get-baseline-with-fallback2.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p>a font</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>baseline_tag</p></td>
+<td class="parameter_description"><p>a baseline tag</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>direction</p></td>
+<td class="parameter_description"><p>text direction.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>script</p></td>
+<td class="parameter_description"><p>script.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>language</p></td>
+<td class="parameter_description"><p>language, currently unused. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>coord</p></td>
+<td class="parameter_description"><p>baseline value if found. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-8-0-0.html#api-index-8.0.0">8.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-ot-layout-get-glyph-class"></a><h3>hb_ot_layout_get_glyph_class ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-ot-layout.html#hb-ot-layout-glyph-class-t" title="enum hb_ot_layout_glyph_class_t"><span class="returnvalue">hb_ot_layout_glyph_class_t</span></a>
 hb_ot_layout_get_glyph_class (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
@@ -1164,6 +1630,11 @@ hb_ot_layout_get_ligature_carets (<em class="parameter"><code><a class="link" hr
                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *caret_array</code></em>);</pre>
 <p>Fetches a list of the caret positions defined for a ligature glyph in the GDEF
 table of the font. The list returned will begin at the offset provided.</p>
+<p>Note that a ligature that is formed from n characters will have n-1
+caret positions. The first character is not represented in the array,
+since its caret position is the glyph position.</p>
+<p>The positions returned by this function are 'unshaped', and will have to
+be fixed up for kerning that may be applied to the ligature glyph.</p>
 <div class="refsect3">
 <a name="hb-ot-layout-get-ligature-carets.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
@@ -1354,6 +1825,7 @@ hb_ot_layout_has_substitution (<em class="parameter"><code><a class="link" href=
 <a name="hb-ot-layout-has-substitution.returns"></a><h4>Returns</h4>
 <p> <code class="literal">true</code> if data found, <code class="literal">false</code> otherwise</p>
 </div>
+<p class="since">Since: <a class="link" href="api-index-0-6-0.html#api-index-0.6.0">0.6.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
@@ -1413,6 +1885,7 @@ or GPOS table, underneath the specified script and language.</p>
 <a name="hb-ot-layout-language-find-feature.returns"></a><h4>Returns</h4>
 <p> <code class="literal">true</code> if the feature is found, <code class="literal">false</code> otherwise</p>
 </div>
+<p class="since">Since: <a class="link" href="api-index-0-6-0.html#api-index-0.6.0">0.6.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
@@ -1481,6 +1954,7 @@ Output: the actual number of feature tags returned (may be zero). </p></td>
 <a name="hb-ot-layout-language-get-feature-indexes.returns"></a><h4>Returns</h4>
 <p> Total number of features.</p>
 </div>
+<p class="since">Since: <a class="link" href="api-index-0-6-0.html#api-index-0.6.0">0.6.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
@@ -1549,6 +2023,7 @@ Output = the actual number of feature tags returned (may be zero). </p></td>
 <a name="hb-ot-layout-language-get-feature-tags.returns"></a><h4>Returns</h4>
 <p> Total number of feature tags.</p>
 </div>
+<p class="since">Since: <a class="link" href="api-index-0-6-0.html#api-index-0.6.0">0.6.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
@@ -1737,6 +2212,54 @@ Alternate glyphs associated with the glyph id. </p></td>
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-ot-layout-lookup-get-optical-bound"></a><h3>hb_ot_layout_lookup_get_optical_bound ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="returnvalue">hb_position_t</span></a>
+hb_ot_layout_lookup_get_optical_bound (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                       <em class="parameter"><code><span class="type">unsigned </span> lookup_index</code></em>,
+                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-direction-t" title="enum hb_direction_t"><span class="type">hb_direction_t</span></a> direction</code></em>,
+                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>);</pre>
+<p>Fetches the optical bound of a glyph positioned at the margin of text.
+The direction identifies which edge of the glyph to query.</p>
+<div class="refsect3">
+<a name="hb-ot-layout-lookup-get-optical-bound.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p>a font.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>lookup_index</p></td>
+<td class="parameter_description"><p>index of the feature lookup to query.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>direction</p></td>
+<td class="parameter_description"><p>edge of the glyph to query.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>a glyph id.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-ot-layout-lookup-get-optical-bound.returns"></a><h4>Returns</h4>
+<p> Adjustment value. Negative values mean the glyph will stick out of the margin.</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-5-3-0.html#api-index-5.3.0">5.3.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-ot-layout-lookup-substitute-closure"></a><h3>hb_ot_layout_lookup_substitute_closure ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
 hb_ot_layout_lookup_substitute_closure
@@ -1870,6 +2393,61 @@ in substitutions</p></td>
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-ot-layout-script-find-language"></a><h3>hb_ot_layout_script_find_language ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_ot_layout_script_find_language (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> table_tag</code></em>,
+                                   <em class="parameter"><code>unsigned <span class="type">int</span> script_index</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> language_tag</code></em>,
+                                   <em class="parameter"><code>unsigned <span class="type">int</span> *language_index</code></em>);</pre>
+<div class="warning"><p><code class="literal">hb_ot_layout_script_find_language</code> has been deprecated since version 2.0.0 and should not be used in newly-written code.</p></div>
+<p>Fetches the index of a given language tag in the specified face's GSUB table
+or GPOS table, underneath the specified script tag.</p>
+<div class="refsect3">
+<a name="hb-ot-layout-script-find-language.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>face</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> to work upon</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>table_tag</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-ot-layout.html#HB-OT-TAG-GSUB:CAPS" title="HB_OT_TAG_GSUB"><span class="type">HB_OT_TAG_GSUB</span></a> or <a class="link" href="harfbuzz-hb-ot-layout.html#HB-OT-TAG-GPOS:CAPS" title="HB_OT_TAG_GPOS"><span class="type">HB_OT_TAG_GPOS</span></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>script_index</p></td>
+<td class="parameter_description"><p>The index of the requested script tag</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>language_tag</p></td>
+<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> of the requested language</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>language_index</p></td>
+<td class="parameter_description"><p>The index of the requested language</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-ot-layout-script-find-language.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if the language tag is found, <code class="literal">false</code> otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-6-0.html#api-index-0.6.0">0.6.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-ot-layout-script-get-language-tags"></a><h3>hb_ot_layout_script_get_language_tags ()</h3>
 <pre class="programlisting">unsigned <span class="returnvalue">int</span>
 hb_ot_layout_script_get_language_tags (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
@@ -1927,6 +2505,7 @@ Output = the actual number of language tags returned (may be zero). </p></td>
 <a name="hb-ot-layout-script-get-language-tags.returns"></a><h4>Returns</h4>
 <p> Total number of language tags.</p>
 </div>
+<p class="since">Since: <a class="link" href="api-index-0-6-0.html#api-index-0.6.0">0.6.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
@@ -1995,6 +2574,79 @@ index.</p>
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-ot-layout-script-select-language2"></a><h3>hb_ot_layout_script_select_language2 ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_ot_layout_script_select_language2 (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
+                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> table_tag</code></em>,
+                                      <em class="parameter"><code>unsigned <span class="type">int</span> script_index</code></em>,
+                                      <em class="parameter"><code>unsigned <span class="type">int</span> language_count</code></em>,
+                                      <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> *language_tags</code></em>,
+                                      <em class="parameter"><code>unsigned <span class="type">int</span> *language_index</code></em>,
+                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> *chosen_language</code></em>);</pre>
+<p>Fetches the index of the first language tag fom <em class="parameter"><code>language_tags</code></em>
+ that is present
+in the specified face's GSUB or GPOS table, underneath the specified script
+index.</p>
+<p>If none of the given language tags is found, <code class="literal">false</code> is returned and
+<em class="parameter"><code>language_index</code></em>
+ is set to <a class="link" href="harfbuzz-hb-ot-layout.html#HB-OT-LAYOUT-DEFAULT-LANGUAGE-INDEX:CAPS" title="HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX"><span class="type">HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX</span></a> and
+<em class="parameter"><code>chosen_language</code></em>
+ is set to <a class="link" href="harfbuzz-hb-common.html#HB-TAG-NONE:CAPS" title="HB_TAG_NONE"><span class="type">HB_TAG_NONE</span></a>.</p>
+<div class="refsect3">
+<a name="hb-ot-layout-script-select-language2.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>face</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> to work upon</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>table_tag</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-ot-layout.html#HB-OT-TAG-GSUB:CAPS" title="HB_OT_TAG_GSUB"><span class="type">HB_OT_TAG_GSUB</span></a> or <a class="link" href="harfbuzz-hb-ot-layout.html#HB-OT-TAG-GPOS:CAPS" title="HB_OT_TAG_GPOS"><span class="type">HB_OT_TAG_GPOS</span></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>script_index</p></td>
+<td class="parameter_description"><p>The index of the requested script tag</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>language_count</p></td>
+<td class="parameter_description"><p>The number of languages in the specified script</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>language_tags</p></td>
+<td class="parameter_description"><p>The array of language tags</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>language_index</p></td>
+<td class="parameter_description"><p>The index of the chosen language. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>chosen_language</p></td>
+<td class="parameter_description"><p><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> of the chosen language. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-ot-layout-script-select-language2.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if one of the given language tags is found, <code class="literal">false</code> otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-ot-layout-table-find-feature-variations"></a><h3>hb_ot_layout_table_find_feature_variations ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 hb_ot_layout_table_find_feature_variations
@@ -2046,6 +2698,7 @@ or GPOS table, at the specified variation coordinates.</p>
 <a name="hb-ot-layout-table-find-feature-variations.returns"></a><h4>Returns</h4>
 <p> <code class="literal">true</code> if feature variations were found, <code class="literal">false</code> otherwise.</p>
 </div>
+<p class="since">Since: <a class="link" href="api-index-1-4-0.html#api-index-1.4.0">1.4.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
@@ -2056,7 +2709,9 @@ hb_ot_layout_table_get_feature_tags (<em class="parameter"><code><a class="link"
                                      <em class="parameter"><code>unsigned <span class="type">int</span> start_offset</code></em>,
                                      <em class="parameter"><code>unsigned <span class="type">int</span> *feature_count</code></em>,
                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> *feature_tags</code></em>);</pre>
-<p>Fetches a list of all feature tags in the given face's GSUB or GPOS table.</p>
+<p>Fetches a list of all feature tags in the given face's GSUB or GPOS table.
+Note that there might be duplicate feature tags, belonging to different
+script/language-system pairs of the table.</p>
 <div class="refsect3">
 <a name="hb-ot-layout-table-get-feature-tags.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
@@ -2099,6 +2754,7 @@ Output = the actual number of feature tags returned (may be zero). </p></td>
 <a name="hb-ot-layout-table-get-feature-tags.returns"></a><h4>Returns</h4>
 <p> Total number of feature tags.</p>
 </div>
+<p class="since">Since: <a class="link" href="api-index-0-6-0.html#api-index-0.6.0">0.6.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
@@ -2206,9 +2862,9 @@ hb_ot_layout_table_select_script (<em class="parameter"><code><a class="link" hr
 <p>If the table does not have any of the requested scripts, then <code class="literal">DFLT</code>,
 <code class="literal">dflt</code>, and <code class="literal">latn</code> tags are tried in that order. If the table still does not
 have any of these scripts, <em class="parameter"><code>script_index</code></em>
- and <em class="parameter"><code>chosen_script</code></em>
- are set to
-<a class="link" href="harfbuzz-hb-ot-layout.html#HB-OT-LAYOUT-NO-SCRIPT-INDEX:CAPS" title="HB_OT_LAYOUT_NO_SCRIPT_INDEX"><span class="type">HB_OT_LAYOUT_NO_SCRIPT_INDEX</span></a>.</p>
+ is set to
+<a class="link" href="harfbuzz-hb-ot-layout.html#HB-OT-LAYOUT-NO-SCRIPT-INDEX:CAPS" title="HB_OT_LAYOUT_NO_SCRIPT_INDEX"><span class="type">HB_OT_LAYOUT_NO_SCRIPT_INDEX</span></a> and <em class="parameter"><code>chosen_script</code></em>
+ is set to <a class="link" href="harfbuzz-hb-common.html#HB-TAG-NONE:CAPS" title="HB_TAG_NONE"><span class="type">HB_TAG_NONE</span></a>.</p>
 <div class="refsect3">
 <a name="hb-ot-layout-table-select-script.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
@@ -2350,6 +3006,7 @@ underneath the specified script and language.</p>
 <a name="hb-ot-layout-language-get-required-feature-index.returns"></a><h4>Returns</h4>
 <p> <code class="literal">true</code> if the feature is found, <code class="literal">false</code> otherwise</p>
 </div>
+<p class="since">Since: <a class="link" href="api-index-0-6-0.html#api-index-0.6.0">0.6.0</a></p>
 </div>
 </div>
 <div class="refsect1">
@@ -2496,6 +3153,13 @@ if the direction is horizontal or vertical, respectively.</p>
 <td class="enum_member_annotations"> </td>
 </tr>
 <tr>
+<td class="enum_member_name"><p><a name="HB-OT-LAYOUT-BASELINE-TAG-IDEO-FACE-CENTRAL:CAPS"></a>HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL</p></td>
+<td class="enum_member_description">
+<p>The center of the ideographic character face. Since: 4.0.0</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
 <td class="enum_member_name"><p><a name="HB-OT-LAYOUT-BASELINE-TAG-IDEO-EMBOX-BOTTOM-OR-LEFT:CAPS"></a>HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT</p></td>
 <td class="enum_member_description">
 <p>Ideographic em-box bottom or left edge,
@@ -2506,7 +3170,14 @@ if the direction is horizontal or vertical, respectively.</p>
 <tr>
 <td class="enum_member_name"><p><a name="HB-OT-LAYOUT-BASELINE-TAG-IDEO-EMBOX-TOP-OR-RIGHT:CAPS"></a>HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT</p></td>
 <td class="enum_member_description">
-<p>Ideographic em-box top or right edge baseline,
+<p>Ideographic em-box top or right edge baseline,</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-LAYOUT-BASELINE-TAG-IDEO-EMBOX-CENTRAL:CAPS"></a>HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL</p></td>
+<td class="enum_member_description">
+<p>The center of the ideographic em-box. Since: 4.0.0
 if the direction is horizontal or vertical, respectively.</p>
 </td>
 <td class="enum_member_annotations"> </td>
index de3fabc..8889c60 100644 (file)
@@ -212,7 +212,7 @@ hb_ot_math_get_constant (<em class="parameter"><code><a class="link" href="harfb
 is an <a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a>.</p>
 <p>However, if the requested constant is <a class="link" href="harfbuzz-hb-ot-math.html#HB-OT-MATH-CONSTANT-SCRIPT-PERCENT-SCALE-DOWN:CAPS"><span class="type">HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN</span></a>,
 <a class="link" href="harfbuzz-hb-ot-math.html#HB-OT-MATH-CONSTANT-SCRIPT-SCRIPT-PERCENT-SCALE-DOWN:CAPS"><span class="type">HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN</span></a> or
-<a class="link" href="harfbuzz-hb-ot-math.html#HB-OT-MATH-CONSTANT-SCRIPT-PERCENT-SCALE-DOWN:CAPS"><span class="type">HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN</span></a>, then the return value is
+<a class="link" href="harfbuzz-hb-ot-math.html#HB-OT-MATH-CONSTANT-RADICAL-DEGREE-BOTTOM-RAISE-PERCENT:CAPS"><span class="type">HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT</span></a>, then the return value is
 an integer between 0 and 100 representing that percentage.</p>
 <div class="refsect3">
 <a name="hb-ot-math-get-constant.parameters"></a><h4>Parameters</h4>
index 6662f42..d40fdd5 100644 (file)
 </tr>
 <tr>
 <td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-ot-metrics.html#hb-ot-metrics-get-position-with-fallback" title="hb_ot_metrics_get_position_with_fallback ()">hb_ot_metrics_get_position_with_fallback</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
 <span class="returnvalue">float</span>
 </td>
 <td class="function_name">
@@ -142,6 +150,47 @@ hb_ot_metrics_get_position (<em class="parameter"><code><a class="link" href="ha
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-ot-metrics-get-position-with-fallback"></a><h3>hb_ot_metrics_get_position_with_fallback ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_ot_metrics_get_position_with_fallback
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-ot-metrics.html#hb-ot-metrics-tag-t" title="enum hb_ot_metrics_tag_t"><span class="type">hb_ot_metrics_tag_t</span></a> metrics_tag</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-position-t" title="hb_position_t"><span class="type">hb_position_t</span></a> *position</code></em>);</pre>
+<p>Fetches metrics value corresponding to <em class="parameter"><code>metrics_tag</code></em>
+ from <em class="parameter"><code>font</code></em>
+,
+and synthesizes a value if it the value is missing in the font.</p>
+<div class="refsect3">
+<a name="hb-ot-metrics-get-position-with-fallback.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p>an <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> object.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>metrics_tag</p></td>
+<td class="parameter_description"><p>tag of metrics value you like to fetch.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>position</p></td>
+<td class="parameter_description"><p>result of metrics value from the font. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="NULL may be passed instead of a pointer to a location."><span class="acronym">optional</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-ot-metrics-get-variation"></a><h3>hb_ot_metrics_get_variation ()</h3>
 <pre class="programlisting"><span class="returnvalue">float</span>
 hb_ot_metrics_get_variation (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
index 0eb1f24..a925912 100644 (file)
 <td class="function_name"><a class="link" href="harfbuzz-hb-ot-name.html#hb-ot-name-id-t" title="hb_ot_name_id_t">hb_ot_name_id_t</a></td>
 </tr>
 <tr>
+<td class="datatype_keyword">enum</td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-ot-name.html#hb-ot-name-id-predefined-t" title="enum hb_ot_name_id_predefined_t">hb_ot_name_id_predefined_t</a></td>
+</tr>
+<tr>
 <td class="datatype_keyword"> </td>
 <td class="function_name"><a class="link" href="harfbuzz-hb-ot-name.html#hb-ot-name-entry-t" title="hb_ot_name_entry_t">hb_ot_name_entry_t</a></td>
 </tr>
@@ -329,9 +333,211 @@ text written to buffer. </p></td>
 <p>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.</p>
+<p class="since">Since: <a class="link" href="api-index-2-0-0.html#api-index-2.0.0">2.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-ot-name-id-predefined-t"></a><h3>enum hb_ot_name_id_predefined_t</h3>
+<p>An enum type representing the pre-defined name IDs.</p>
 <p>For more information on these fields, see the
 <a class="ulink" href="https://docs.microsoft.com/en-us/typography/opentype/spec/name#name-ids" target="_top">OpenType spec</a>.</p>
-<p class="since">Since: <a class="link" href="api-index-2-0-0.html#api-index-2.0.0">2.0.0</a></p>
+<div class="refsect3">
+<a name="hb-ot-name-id-predefined-t.members"></a><h4>Members</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="300px" class="enum_members_name">
+<col class="enum_members_description">
+<col width="200px" class="enum_members_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-COPYRIGHT:CAPS"></a>HB_OT_NAME_ID_COPYRIGHT</p></td>
+<td class="enum_member_description">
+<p>Copyright notice</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-FONT-FAMILY:CAPS"></a>HB_OT_NAME_ID_FONT_FAMILY</p></td>
+<td class="enum_member_description">
+<p>Font Family name</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-FONT-SUBFAMILY:CAPS"></a>HB_OT_NAME_ID_FONT_SUBFAMILY</p></td>
+<td class="enum_member_description">
+<p>Font Subfamily name</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-UNIQUE-ID:CAPS"></a>HB_OT_NAME_ID_UNIQUE_ID</p></td>
+<td class="enum_member_description">
+<p>Unique font identifier</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-FULL-NAME:CAPS"></a>HB_OT_NAME_ID_FULL_NAME</p></td>
+<td class="enum_member_description">
+<p>Full font name that reflects
+all family and relevant subfamily descriptors</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-VERSION-STRING:CAPS"></a>HB_OT_NAME_ID_VERSION_STRING</p></td>
+<td class="enum_member_description">
+<p>Version string</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-POSTSCRIPT-NAME:CAPS"></a>HB_OT_NAME_ID_POSTSCRIPT_NAME</p></td>
+<td class="enum_member_description">
+<p>PostScript name for the font</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-TRADEMARK:CAPS"></a>HB_OT_NAME_ID_TRADEMARK</p></td>
+<td class="enum_member_description">
+<p>Trademark</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-MANUFACTURER:CAPS"></a>HB_OT_NAME_ID_MANUFACTURER</p></td>
+<td class="enum_member_description">
+<p>Manufacturer Name</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-DESIGNER:CAPS"></a>HB_OT_NAME_ID_DESIGNER</p></td>
+<td class="enum_member_description">
+<p>Designer</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-DESCRIPTION:CAPS"></a>HB_OT_NAME_ID_DESCRIPTION</p></td>
+<td class="enum_member_description">
+<p>Description</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-VENDOR-URL:CAPS"></a>HB_OT_NAME_ID_VENDOR_URL</p></td>
+<td class="enum_member_description">
+<p>URL of font vendor</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-DESIGNER-URL:CAPS"></a>HB_OT_NAME_ID_DESIGNER_URL</p></td>
+<td class="enum_member_description">
+<p>URL of typeface designer</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-LICENSE:CAPS"></a>HB_OT_NAME_ID_LICENSE</p></td>
+<td class="enum_member_description">
+<p>License Description</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-LICENSE-URL:CAPS"></a>HB_OT_NAME_ID_LICENSE_URL</p></td>
+<td class="enum_member_description">
+<p>URL where additional licensing
+information can be found</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-TYPOGRAPHIC-FAMILY:CAPS"></a>HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY</p></td>
+<td class="enum_member_description">
+<p>Typographic Family name</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-TYPOGRAPHIC-SUBFAMILY:CAPS"></a>HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY</p></td>
+<td class="enum_member_description">
+<p>Typographic Subfamily name</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-MAC-FULL-NAME:CAPS"></a>HB_OT_NAME_ID_MAC_FULL_NAME</p></td>
+<td class="enum_member_description">
+<p>Compatible Full Name for MacOS</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-SAMPLE-TEXT:CAPS"></a>HB_OT_NAME_ID_SAMPLE_TEXT</p></td>
+<td class="enum_member_description">
+<p>Sample text</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-CID-FINDFONT-NAME:CAPS"></a>HB_OT_NAME_ID_CID_FINDFONT_NAME</p></td>
+<td class="enum_member_description">
+<p>PostScript CID findfont name</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-WWS-FAMILY:CAPS"></a>HB_OT_NAME_ID_WWS_FAMILY</p></td>
+<td class="enum_member_description">
+<p>WWS Family Name</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-WWS-SUBFAMILY:CAPS"></a>HB_OT_NAME_ID_WWS_SUBFAMILY</p></td>
+<td class="enum_member_description">
+<p>WWS Subfamily Name</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-LIGHT-BACKGROUND:CAPS"></a>HB_OT_NAME_ID_LIGHT_BACKGROUND</p></td>
+<td class="enum_member_description">
+<p>Light Background Palette</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-DARK-BACKGROUND:CAPS"></a>HB_OT_NAME_ID_DARK_BACKGROUND</p></td>
+<td class="enum_member_description">
+<p>Dark Background Palette</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-VARIATIONS-PS-PREFIX:CAPS"></a>HB_OT_NAME_ID_VARIATIONS_PS_PREFIX</p></td>
+<td class="enum_member_description">
+<p>Variations PostScript Name Prefix</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-OT-NAME-ID-INVALID:CAPS"></a>HB_OT_NAME_ID_INVALID</p></td>
+<td class="enum_member_description">
+<p>Value to represent a nonexistent name ID.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
diff --git a/docs/html/harfbuzz-hb-paint.html b/docs/html/harfbuzz-hb-paint.html
new file mode 100644 (file)
index 0000000..1dd4575
--- /dev/null
@@ -0,0 +1,3563 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>hb-paint: HarfBuzz Manual</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
+<link rel="home" href="index.html" title="HarfBuzz Manual">
+<link rel="up" href="core-api.html" title="Core API">
+<link rel="prev" href="harfbuzz-hb-draw.html" title="hb-draw">
+<link rel="next" href="harfbuzz-hb-deprecated.html" title="hb-deprecated">
+<meta name="generator" content="GTK-Doc V1.32 (XML mode)">
+<link rel="stylesheet" href="style.css" type="text/css">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
+<td width="100%" align="left" class="shortcuts">
+<a href="#" class="shortcut">Top</a><span id="nav_description">  <span class="dim">|</span> 
+                  <a href="#harfbuzz-hb-paint.description" class="shortcut">Description</a></span>
+</td>
+<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
+<td><a accesskey="u" href="core-api.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
+<td><a accesskey="p" href="harfbuzz-hb-draw.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="harfbuzz-hb-deprecated.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+</tr></table>
+<div class="refentry">
+<a name="harfbuzz-hb-paint"></a><div class="titlepage"></div>
+<div class="refnamediv"><table width="100%"><tr>
+<td valign="top">
+<h2><span class="refentrytitle"><a name="harfbuzz-hb-paint.top_of_page"></a>hb-paint</span></h2>
+<p>hb-paint — Glyph painting</p>
+</td>
+<td class="gallery_image" valign="top" align="right"></td>
+</tr></table></div>
+<div class="refsect1">
+<a name="harfbuzz-hb-paint.functions"></a><h2>Functions</h2>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="functions_proto_type">
+<col class="functions_proto_name">
+</colgroup>
+<tbody>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="returnvalue">hb_paint_funcs_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-create" title="hb_paint_funcs_create ()">hb_paint_funcs_create</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="returnvalue">hb_paint_funcs_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-get-empty" title="hb_paint_funcs_get_empty ()">hb_paint_funcs_get_empty</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="returnvalue">hb_paint_funcs_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-reference" title="hb_paint_funcs_reference ()">hb_paint_funcs_reference</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-destroy" title="hb_paint_funcs_destroy ()">hb_paint_funcs_destroy</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-user-data" title="hb_paint_funcs_set_user_data ()">hb_paint_funcs_set_user_data</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-get-user-data" title="hb_paint_funcs_get_user_data ()">hb_paint_funcs_get_user_data</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-make-immutable" title="hb_paint_funcs_make_immutable ()">hb_paint_funcs_make_immutable</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-is-immutable" title="hb_paint_funcs_is_immutable ()">hb_paint_funcs_is_immutable</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-transform-func-t" title="hb_paint_push_transform_func_t ()">*hb_paint_push_transform_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-transform-func" title="hb_paint_funcs_set_push_transform_func ()">hb_paint_funcs_set_push_transform_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-transform-func-t" title="hb_paint_pop_transform_func_t ()">*hb_paint_pop_transform_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-pop-transform-func" title="hb_paint_funcs_set_pop_transform_func ()">hb_paint_funcs_set_pop_transform_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-paint.html#hb-paint-color-glyph-func-t" title="hb_paint_color_glyph_func_t ()">*hb_paint_color_glyph_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-color-glyph-func" title="hb_paint_funcs_set_color_glyph_func ()">hb_paint_funcs_set_color_glyph_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-clip-glyph-func-t" title="hb_paint_push_clip_glyph_func_t ()">*hb_paint_push_clip_glyph_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-clip-glyph-func" title="hb_paint_funcs_set_push_clip_glyph_func ()">hb_paint_funcs_set_push_clip_glyph_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-clip-rectangle-func-t" title="hb_paint_push_clip_rectangle_func_t ()">*hb_paint_push_clip_rectangle_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-clip-rectangle-func" title="hb_paint_funcs_set_push_clip_rectangle_func ()">hb_paint_funcs_set_push_clip_rectangle_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-clip-func-t" title="hb_paint_pop_clip_func_t ()">*hb_paint_pop_clip_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-pop-clip-func" title="hb_paint_funcs_set_pop_clip_func ()">hb_paint_funcs_set_pop_clip_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-paint.html#hb-paint-color-func-t" title="hb_paint_color_func_t ()">*hb_paint_color_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-color-func" title="hb_paint_funcs_set_color_func ()">hb_paint_funcs_set_color_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-paint.html#hb-paint-image-func-t" title="hb_paint_image_func_t ()">*hb_paint_image_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-image-func" title="hb_paint_funcs_set_image_func ()">hb_paint_funcs_set_image_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">unsigned <span class="returnvalue">int</span>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-paint.html#hb-color-line-get-color-stops-func-t" title="hb_color_line_get_color_stops_func_t ()">*hb_color_line_get_color_stops_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">unsigned <span class="returnvalue">int</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-color-line-get-color-stops" title="hb_color_line_get_color_stops ()">hb_color_line_get_color_stops</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-extend-t" title="enum hb_paint_extend_t"><span class="returnvalue">hb_paint_extend_t</span></a>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-paint.html#hb-color-line-get-extend-func-t" title="hb_color_line_get_extend_func_t ()">*hb_color_line_get_extend_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-extend-t" title="enum hb_paint_extend_t"><span class="returnvalue">hb_paint_extend_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-color-line-get-extend" title="hb_color_line_get_extend ()">hb_color_line_get_extend</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-paint.html#hb-paint-linear-gradient-func-t" title="hb_paint_linear_gradient_func_t ()">*hb_paint_linear_gradient_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-linear-gradient-func" title="hb_paint_funcs_set_linear_gradient_func ()">hb_paint_funcs_set_linear_gradient_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-paint.html#hb-paint-radial-gradient-func-t" title="hb_paint_radial_gradient_func_t ()">*hb_paint_radial_gradient_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-radial-gradient-func" title="hb_paint_funcs_set_radial_gradient_func ()">hb_paint_funcs_set_radial_gradient_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-paint.html#hb-paint-sweep-gradient-func-t" title="hb_paint_sweep_gradient_func_t ()">*hb_paint_sweep_gradient_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-sweep-gradient-func" title="hb_paint_funcs_set_sweep_gradient_func ()">hb_paint_funcs_set_sweep_gradient_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-group-func-t" title="hb_paint_push_group_func_t ()">*hb_paint_push_group_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-group-func" title="hb_paint_funcs_set_push_group_func ()">hb_paint_funcs_set_push_group_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-group-func-t" title="hb_paint_pop_group_func_t ()">*hb_paint_pop_group_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-pop-group-func" title="hb_paint_funcs_set_pop_group_func ()">hb_paint_funcs_set_pop_group_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-paint.html#hb-paint-custom-palette-color-func-t" title="hb_paint_custom_palette_color_func_t ()">*hb_paint_custom_palette_color_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-custom-palette-color-func" title="hb_paint_funcs_set_custom_palette_color_func ()">hb_paint_funcs_set_custom_palette_color_func</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-transform" title="hb_paint_push_transform ()">hb_paint_push_transform</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-transform" title="hb_paint_pop_transform ()">hb_paint_pop_transform</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-color-glyph" title="hb_paint_color_glyph ()">hb_paint_color_glyph</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-clip-glyph" title="hb_paint_push_clip_glyph ()">hb_paint_push_clip_glyph</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-clip-rectangle" title="hb_paint_push_clip_rectangle ()">hb_paint_push_clip_rectangle</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-clip" title="hb_paint_pop_clip ()">hb_paint_pop_clip</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-color" title="hb_paint_color ()">hb_paint_color</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-image" title="hb_paint_image ()">hb_paint_image</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-linear-gradient" title="hb_paint_linear_gradient ()">hb_paint_linear_gradient</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-radial-gradient" title="hb_paint_radial_gradient ()">hb_paint_radial_gradient</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-sweep-gradient" title="hb_paint_sweep_gradient ()">hb_paint_sweep_gradient</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-group" title="hb_paint_push_group ()">hb_paint_push_group</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-group" title="hb_paint_pop_group ()">hb_paint_pop_group</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-paint.html#hb-paint-custom-palette-color" title="hb_paint_custom_palette_color ()">hb_paint_custom_palette_color</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect1">
+<a name="harfbuzz-hb-paint.other"></a><h2>Types and Values</h2>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="other_proto_type">
+<col class="other_proto_name">
+</colgroup>
+<tbody>
+<tr>
+<td class="typedef_keyword">typedef</td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t">hb_paint_funcs_t</a></td>
+</tr>
+<tr>
+<td class="define_keyword">#define</td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-paint.html#HB-PAINT-IMAGE-FORMAT-PNG:CAPS" title="HB_PAINT_IMAGE_FORMAT_PNG">HB_PAINT_IMAGE_FORMAT_PNG</a></td>
+</tr>
+<tr>
+<td class="define_keyword">#define</td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-paint.html#HB-PAINT-IMAGE-FORMAT-SVG:CAPS" title="HB_PAINT_IMAGE_FORMAT_SVG">HB_PAINT_IMAGE_FORMAT_SVG</a></td>
+</tr>
+<tr>
+<td class="define_keyword">#define</td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-paint.html#HB-PAINT-IMAGE-FORMAT-BGRA:CAPS" title="HB_PAINT_IMAGE_FORMAT_BGRA">HB_PAINT_IMAGE_FORMAT_BGRA</a></td>
+</tr>
+<tr>
+<td class="typedef_keyword">typedef</td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-paint.html#hb-color-line-t" title="hb_color_line_t">hb_color_line_t</a></td>
+</tr>
+<tr>
+<td class="datatype_keyword"> </td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-paint.html#hb-color-stop-t" title="hb_color_stop_t">hb_color_stop_t</a></td>
+</tr>
+<tr>
+<td class="datatype_keyword">enum</td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-paint.html#hb-paint-extend-t" title="enum hb_paint_extend_t">hb_paint_extend_t</a></td>
+</tr>
+<tr>
+<td class="datatype_keyword">enum</td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-paint.html#hb-paint-composite-mode-t" title="enum hb_paint_composite_mode_t">hb_paint_composite_mode_t</a></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect1">
+<a name="harfbuzz-hb-paint.includes"></a><h2>Includes</h2>
+<pre class="synopsis">#include &lt;hb.h&gt;
+</pre>
+</div>
+<div class="refsect1">
+<a name="harfbuzz-hb-paint.description"></a><h2>Description</h2>
+<p>Functions for painting glyphs.</p>
+<p>The main purpose of these functions is to paint (extract) color glyph layers
+from the COLRv1 table, but the API works for drawing ordinary outlines and
+images as well.</p>
+<p>The <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> struct can be used with <a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph" title="hb_font_paint_glyph ()"><code class="function">hb_font_paint_glyph()</code></a>.</p>
+</div>
+<div class="refsect1">
+<a name="harfbuzz-hb-paint.functions_details"></a><h2>Functions</h2>
+<div class="refsect2">
+<a name="hb-paint-funcs-create"></a><h3>hb_paint_funcs_create ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="returnvalue">hb_paint_funcs_t</span></a> *
+hb_paint_funcs_create (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
+<p>Creates a new <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> structure of paint functions.</p>
+<p>The initial reference count of 1 should be released with <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-destroy" title="hb_paint_funcs_destroy ()"><code class="function">hb_paint_funcs_destroy()</code></a>
+when you are done using the <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a>. This function never returns
+<code class="literal">NULL</code>. If memory cannot be allocated, a special singleton <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a>
+object will be returned.</p>
+<p>Returns value: (transfer full): the paint-functions structure</p>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-get-empty"></a><h3>hb_paint_funcs_get_empty ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="returnvalue">hb_paint_funcs_t</span></a> *
+hb_paint_funcs_get_empty (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
+<p>Fetches the singleton empty paint-functions structure.</p>
+<div class="refsect3">
+<a name="hb-paint-funcs-get-empty.returns"></a><h4>Returns</h4>
+<p>The empty paint-functions structure. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-reference"></a><h3>hb_paint_funcs_reference ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="returnvalue">hb_paint_funcs_t</span></a> *
+hb_paint_funcs_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>);</pre>
+<p>Increases the reference count on a paint-functions structure.</p>
+<p>This prevents <em class="parameter"><code>funcs</code></em>
+ from being destroyed until a matching
+call to <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-destroy" title="hb_paint_funcs_destroy ()"><code class="function">hb_paint_funcs_destroy()</code></a> is made.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-paint-funcs-reference.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>The paint-functions structure</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-paint-funcs-reference.returns"></a><h4>Returns</h4>
+<p> The paint-functions structure</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-destroy"></a><h3>hb_paint_funcs_destroy ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_funcs_destroy (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>);</pre>
+<p>Decreases the reference count on a paint-functions structure.</p>
+<p>When the reference count reaches zero, the structure
+is destroyed, freeing all memory.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-paint-funcs-destroy.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>The paint-functions structure</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-set-user-data"></a><h3>hb_paint_funcs_set_user_data ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_paint_funcs_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
+                              <em class="parameter"><code><span class="type">void</span> *data</code></em>,
+                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
+                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
+<p>Attaches a user-data key/data pair to the specified paint-functions structure.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-paint-funcs-set-user-data.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>The paint-functions structure</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The user-data key</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>data</p></td>
+<td class="parameter_description"><p>A pointer to the user data</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>replace</p></td>
+<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-paint-funcs-set-user-data.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-get-user-data"></a><h3>hb_paint_funcs_get_user_data ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span> *
+hb_paint_funcs_get_user_data (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>);</pre>
+<p>Fetches the user-data associated with the specified key,
+attached to the specified paint-functions structure.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-paint-funcs-get-user-data.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>The paint-functions structure</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The user-data key to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-paint-funcs-get-user-data.returns"></a><h4>Returns</h4>
+<p>A pointer to the user data. </p>
+<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-make-immutable"></a><h3>hb_paint_funcs_make_immutable ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_funcs_make_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>);</pre>
+<p>Makes a paint-functions structure immutable.</p>
+<p>After this call, all attempts to set one of the callbacks
+on <em class="parameter"><code>funcs</code></em>
+ will fail.</p>
+<div class="refsect3">
+<a name="hb-paint-funcs-make-immutable.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>The paint-functions structure</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-is-immutable"></a><h3>hb_paint_funcs_is_immutable ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_paint_funcs_is_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>);</pre>
+<p>Tests whether a paint-functions structure is immutable.</p>
+<div class="refsect3">
+<a name="hb-paint-funcs-is-immutable.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>The paint-functions structure</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-paint-funcs-is-immutable.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if <em class="parameter"><code>funcs</code></em>
+is immutable, <code class="literal">false</code> otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-push-transform-func-t"></a><h3>hb_paint_push_transform_func_t ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+<span class="c_punctuation">(</span>*hb_paint_push_transform_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                   <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                                   <em class="parameter"><code><span class="type">float</span> xx</code></em>,
+                                   <em class="parameter"><code><span class="type">float</span> yx</code></em>,
+                                   <em class="parameter"><code><span class="type">float</span> xy</code></em>,
+                                   <em class="parameter"><code><span class="type">float</span> yy</code></em>,
+                                   <em class="parameter"><code><span class="type">float</span> dx</code></em>,
+                                   <em class="parameter"><code><span class="type">float</span> dy</code></em>,
+                                   <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> to apply
+a transform to subsequent paint calls.</p>
+<p>This transform is applied after the current transform,
+and remains in effect until a matching call to
+the <span class="type">hb_paint_funcs_pop_transform_func_t</span> vfunc.</p>
+<div class="refsect3">
+<a name="hb-paint-push-transform-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>The data accompanying the paint functions in <a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph" title="hb_font_paint_glyph ()"><code class="function">hb_font_paint_glyph()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>xx</p></td>
+<td class="parameter_description"><p>xx component of the transform matrix</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>yx</p></td>
+<td class="parameter_description"><p>yx component of the transform matrix</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>xy</p></td>
+<td class="parameter_description"><p>xy component of the transform matrix</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>yy</p></td>
+<td class="parameter_description"><p>yy component of the transform matrix</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>dx</p></td>
+<td class="parameter_description"><p>dx component of the transform matrix</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>dy</p></td>
+<td class="parameter_description"><p>dy component of the transform matrix</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed to <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-transform-func" title="hb_paint_funcs_set_push_transform_func ()"><code class="function">hb_paint_funcs_set_push_transform_func()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-set-push-transform-func"></a><h3>hb_paint_funcs_set_push_transform_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_funcs_set_push_transform_func
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-transform-func-t" title="hb_paint_push_transform_func_t ()"><span class="type">hb_paint_push_transform_func_t</span></a> func</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the push-transform callback on the paint functions struct.</p>
+<div class="refsect3">
+<a name="hb-paint-funcs-set-push-transform-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>A paint functions struct</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The push-transform callback. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>Function to call when <em class="parameter"><code>user_data</code></em>
+is no longer needed. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-pop-transform-func-t"></a><h3>hb_paint_pop_transform_func_t ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+<span class="c_punctuation">(</span>*hb_paint_pop_transform_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                  <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                                  <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> to undo
+the effect of a prior call to the <span class="type">hb_paint_funcs_push_transform_func_t</span>
+vfunc.</p>
+<div class="refsect3">
+<a name="hb-paint-pop-transform-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>The data accompanying the paint functions in <a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph" title="hb_font_paint_glyph ()"><code class="function">hb_font_paint_glyph()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed to <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-pop-transform-func" title="hb_paint_funcs_set_pop_transform_func ()"><code class="function">hb_paint_funcs_set_pop_transform_func()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-set-pop-transform-func"></a><h3>hb_paint_funcs_set_pop_transform_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_funcs_set_pop_transform_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-transform-func-t" title="hb_paint_pop_transform_func_t ()"><span class="type">hb_paint_pop_transform_func_t</span></a> func</code></em>,
+                                       <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the pop-transform callback on the paint functions struct.</p>
+<div class="refsect3">
+<a name="hb-paint-funcs-set-pop-transform-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>A paint functions struct</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The pop-transform callback. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>Function to call when <em class="parameter"><code>user_data</code></em>
+is no longer needed. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-color-glyph-func-t"></a><h3>hb_paint_color_glyph_func_t ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="c_punctuation">(</span>*hb_paint_color_glyph_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> to render a color glyph by glyph index.</p>
+<div class="refsect3">
+<a name="hb-paint-color-glyph-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>The data accompanying the paint functions in <a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph" title="hb_font_paint_glyph ()"><code class="function">hb_font_paint_glyph()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>the glyph ID</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p>the font</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed to <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-color-glyph-func" title="hb_paint_funcs_set_color_glyph_func ()"><code class="function">hb_paint_funcs_set_color_glyph_func()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-paint-color-glyph-func-t.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if the glyph was painted, <code class="literal">false</code> otherwise.</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-8-2-0.html#api-index-8.2.0">8.2.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-set-color-glyph-func"></a><h3>hb_paint_funcs_set_color_glyph_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_funcs_set_color_glyph_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-color-glyph-func-t" title="hb_paint_color_glyph_func_t ()"><span class="type">hb_paint_color_glyph_func_t</span></a> func</code></em>,
+                                     <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the color-glyph callback on the paint functions struct.</p>
+<div class="refsect3">
+<a name="hb-paint-funcs-set-color-glyph-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>A paint functions struct</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The color-glyph callback. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>Function to call when <em class="parameter"><code>user_data</code></em>
+is no longer needed. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-8-2-0.html#api-index-8.2.0">8.2.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-push-clip-glyph-func-t"></a><h3>hb_paint_push_clip_glyph_func_t ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+<span class="c_punctuation">(</span>*hb_paint_push_clip_glyph_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                    <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                                    <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> to clip
+subsequent paint calls to the outline of a glyph.</p>
+<p>The coordinates of the glyph outline are interpreted according
+to the current transform.</p>
+<p>This clip is applied in addition to the current clip,
+and remains in effect until a matching call to
+the <span class="type">hb_paint_funcs_pop_clip_func_t</span> vfunc.</p>
+<div class="refsect3">
+<a name="hb-paint-push-clip-glyph-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>The data accompanying the paint functions in <a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph" title="hb_font_paint_glyph ()"><code class="function">hb_font_paint_glyph()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>the glyph ID</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p>the font</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed to <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-clip-glyph-func" title="hb_paint_funcs_set_push_clip_glyph_func ()"><code class="function">hb_paint_funcs_set_push_clip_glyph_func()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-set-push-clip-glyph-func"></a><h3>hb_paint_funcs_set_push_clip_glyph_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_funcs_set_push_clip_glyph_func
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-clip-glyph-func-t" title="hb_paint_push_clip_glyph_func_t ()"><span class="type">hb_paint_push_clip_glyph_func_t</span></a> func</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the push-clip-glyph callback on the paint functions struct.</p>
+<div class="refsect3">
+<a name="hb-paint-funcs-set-push-clip-glyph-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>A paint functions struct</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The push-clip-glyph callback. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>Function to call when <em class="parameter"><code>user_data</code></em>
+is no longer needed. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-push-clip-rectangle-func-t"></a><h3>hb_paint_push_clip_rectangle_func_t ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+<span class="c_punctuation">(</span>*hb_paint_push_clip_rectangle_func_t<span class="c_punctuation">)</span>
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                                <em class="parameter"><code><span class="type">float</span> xmin</code></em>,
+                                <em class="parameter"><code><span class="type">float</span> ymin</code></em>,
+                                <em class="parameter"><code><span class="type">float</span> xmax</code></em>,
+                                <em class="parameter"><code><span class="type">float</span> ymax</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> to clip
+subsequent paint calls to a rectangle.</p>
+<p>The coordinates of the rectangle are interpreted according
+to the current transform.</p>
+<p>This clip is applied in addition to the current clip,
+and remains in effect until a matching call to
+the <span class="type">hb_paint_funcs_pop_clip_func_t</span> vfunc.</p>
+<div class="refsect3">
+<a name="hb-paint-push-clip-rectangle-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>The data accompanying the paint functions in <a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph" title="hb_font_paint_glyph ()"><code class="function">hb_font_paint_glyph()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>xmin</p></td>
+<td class="parameter_description"><p>min X for the rectangle</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>ymin</p></td>
+<td class="parameter_description"><p>min Y for the rectangle</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>xmax</p></td>
+<td class="parameter_description"><p>max X for the rectangle</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>ymax</p></td>
+<td class="parameter_description"><p>max Y for the rectangle</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed to <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-clip-rectangle-func" title="hb_paint_funcs_set_push_clip_rectangle_func ()"><code class="function">hb_paint_funcs_set_push_clip_rectangle_func()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-set-push-clip-rectangle-func"></a><h3>hb_paint_funcs_set_push_clip_rectangle_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_funcs_set_push_clip_rectangle_func
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-clip-rectangle-func-t" title="hb_paint_push_clip_rectangle_func_t ()"><span class="type">hb_paint_push_clip_rectangle_func_t</span></a> func</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the push-clip-rect callback on the paint functions struct.</p>
+<div class="refsect3">
+<a name="hb-paint-funcs-set-push-clip-rectangle-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>A paint functions struct</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The push-clip-rectangle callback. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>Function to call when <em class="parameter"><code>user_data</code></em>
+is no longer needed. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-pop-clip-func-t"></a><h3>hb_paint_pop_clip_func_t ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+<span class="c_punctuation">(</span>*hb_paint_pop_clip_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                             <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                             <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> to undo
+the effect of a prior call to the <span class="type">hb_paint_funcs_push_clip_glyph_func_t</span>
+or <span class="type">hb_paint_funcs_push_clip_rectangle_func_t</span> vfuncs.</p>
+<div class="refsect3">
+<a name="hb-paint-pop-clip-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>The data accompanying the paint functions in <a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph" title="hb_font_paint_glyph ()"><code class="function">hb_font_paint_glyph()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed to <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-pop-clip-func" title="hb_paint_funcs_set_pop_clip_func ()"><code class="function">hb_paint_funcs_set_pop_clip_func()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-set-pop-clip-func"></a><h3>hb_paint_funcs_set_pop_clip_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_funcs_set_pop_clip_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-clip-func-t" title="hb_paint_pop_clip_func_t ()"><span class="type">hb_paint_pop_clip_func_t</span></a> func</code></em>,
+                                  <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the pop-clip callback on the paint functions struct.</p>
+<div class="refsect3">
+<a name="hb-paint-funcs-set-pop-clip-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>A paint functions struct</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The pop-clip callback. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>Function to call when <em class="parameter"><code>user_data</code></em>
+is no longer needed. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-color-func-t"></a><h3>hb_paint_color_func_t ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+<span class="c_punctuation">(</span>*hb_paint_color_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                          <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                          <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> is_foreground</code></em>,
+                          <em class="parameter"><code><a class="link" href="harfbuzz-hb-ot-color.html#hb-color-t" title="hb_color_t"><span class="type">hb_color_t</span></a> color</code></em>,
+                          <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> to paint a
+color everywhere within the current clip.</p>
+<div class="refsect3">
+<a name="hb-paint-color-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>The data accompanying the paint functions in <a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph" title="hb_font_paint_glyph ()"><code class="function">hb_font_paint_glyph()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>is_foreground</p></td>
+<td class="parameter_description"><p>whether the color is the foreground</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>color</p></td>
+<td class="parameter_description"><p>The color to use, unpremultiplied</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed to <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-color-func" title="hb_paint_funcs_set_color_func ()"><code class="function">hb_paint_funcs_set_color_func()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-set-color-func"></a><h3>hb_paint_funcs_set_color_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_funcs_set_color_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                               <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-color-func-t" title="hb_paint_color_func_t ()"><span class="type">hb_paint_color_func_t</span></a> func</code></em>,
+                               <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                               <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the paint-color callback on the paint functions struct.</p>
+<div class="refsect3">
+<a name="hb-paint-funcs-set-color-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>A paint functions struct</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The paint-color callback. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>Function to call when <em class="parameter"><code>user_data</code></em>
+is no longer needed. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-image-func-t"></a><h3>hb_paint_image_func_t ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="c_punctuation">(</span>*hb_paint_image_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                          <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                          <em class="parameter"><code><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a> *image</code></em>,
+                          <em class="parameter"><code>unsigned <span class="type">int</span> width</code></em>,
+                          <em class="parameter"><code>unsigned <span class="type">int</span> height</code></em>,
+                          <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> format</code></em>,
+                          <em class="parameter"><code><span class="type">float</span> slant</code></em>,
+                          <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-glyph-extents-t" title="hb_glyph_extents_t"><span class="type">hb_glyph_extents_t</span></a> *extents</code></em>,
+                          <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> to paint a glyph image.</p>
+<p>This method is called for glyphs with image blobs in the CBDT,
+sbix or SVG tables. The <em class="parameter"><code>format</code></em>
+ identifies the kind of data that
+is contained in <em class="parameter"><code>image</code></em>
+. Possible values include <a class="link" href="harfbuzz-hb-paint.html#HB-PAINT-IMAGE-FORMAT-PNG:CAPS" title="HB_PAINT_IMAGE_FORMAT_PNG"><span class="type">HB_PAINT_IMAGE_FORMAT_PNG</span></a>,
+<a class="link" href="harfbuzz-hb-paint.html#HB-PAINT-IMAGE-FORMAT-SVG:CAPS" title="HB_PAINT_IMAGE_FORMAT_SVG"><span class="type">HB_PAINT_IMAGE_FORMAT_SVG</span></a> and <a class="link" href="harfbuzz-hb-paint.html#HB-PAINT-IMAGE-FORMAT-BGRA:CAPS" title="HB_PAINT_IMAGE_FORMAT_BGRA"><span class="type">HB_PAINT_IMAGE_FORMAT_BGRA</span></a>.</p>
+<p>The image dimensions and glyph extents are provided if available,
+and should be used to size and position the image.</p>
+<div class="refsect3">
+<a name="hb-paint-image-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>The data accompanying the paint functions in <a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph" title="hb_font_paint_glyph ()"><code class="function">hb_font_paint_glyph()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>image</p></td>
+<td class="parameter_description"><p>the image data</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>width</p></td>
+<td class="parameter_description"><p>width of the raster image in pixels, or 0</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>height</p></td>
+<td class="parameter_description"><p>height of the raster image in pixels, or 0</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>format</p></td>
+<td class="parameter_description"><p>the image format as a tag</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>slant</p></td>
+<td class="parameter_description"><p>the synthetic slant ratio to be applied to the image during rendering</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>extents</p></td>
+<td class="parameter_description"><p>glyph extents for desired rendering. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed to <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-image-func" title="hb_paint_funcs_set_image_func ()"><code class="function">hb_paint_funcs_set_image_func()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-paint-image-func-t.returns"></a><h4>Returns</h4>
+<p> Whether the operation was successful.</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-set-image-func"></a><h3>hb_paint_funcs_set_image_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_funcs_set_image_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                               <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-image-func-t" title="hb_paint_image_func_t ()"><span class="type">hb_paint_image_func_t</span></a> func</code></em>,
+                               <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                               <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the paint-image callback on the paint functions struct.</p>
+<div class="refsect3">
+<a name="hb-paint-funcs-set-image-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>A paint functions struct</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The paint-image callback. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>Function to call when <em class="parameter"><code>user_data</code></em>
+is no longer needed. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-color-line-get-color-stops-func-t"></a><h3>hb_color_line_get_color_stops_func_t ()</h3>
+<pre class="programlisting">unsigned <span class="returnvalue">int</span>
+<span class="c_punctuation">(</span>*hb_color_line_get_color_stops_func_t<span class="c_punctuation">)</span>
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-color-line-t" title="hb_color_line_t"><span class="type">hb_color_line_t</span></a> *color_line</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *color_line_data</code></em>,
+                                <em class="parameter"><code>unsigned <span class="type">int</span> start</code></em>,
+                                <em class="parameter"><code>unsigned <span class="type">int</span> *count</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-color-stop-t" title="hb_color_stop_t"><span class="type">hb_color_stop_t</span></a> *color_stops</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-paint.html#hb-color-line-t" title="hb_color_line_t"><span class="type">hb_color_line_t</span></a> to fetch color stops.</p>
+<div class="refsect3">
+<a name="hb-color-line-get-color-stops-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>color_line</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-paint.html#hb-color-line-t" title="hb_color_line_t"><span class="type">hb_color_line_t</span></a> object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>color_line_data</p></td>
+<td class="parameter_description"><p>the data accompanying <em class="parameter"><code>color_line</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>start</p></td>
+<td class="parameter_description"><p>the index of the first color stop to return</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>count</p></td>
+<td class="parameter_description"><p>Input = the maximum number of feature tags to return;
+Output = the actual number of feature tags returned (may be zero). </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for input and for returning results. Default is transfer full."><span class="acronym">inout</span></acronym>][<acronym title="NULL may be passed instead of a pointer to a location."><span class="acronym">optional</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>color_stops</p></td>
+<td class="parameter_description"><p>Array of <a class="link" href="harfbuzz-hb-paint.html#hb-color-stop-t" title="hb_color_stop_t"><span class="type">hb_color_stop_t</span></a> to populate. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=count][<acronym title="NULL may be passed instead of a pointer to a location."><span class="acronym">optional</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>the data accompanying this method</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-color-line-get-color-stops-func-t.returns"></a><h4>Returns</h4>
+<p> the total number of color stops in <em class="parameter"><code>color_line</code></em>
+</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-color-line-get-color-stops"></a><h3>hb_color_line_get_color_stops ()</h3>
+<pre class="programlisting">unsigned <span class="returnvalue">int</span>
+hb_color_line_get_color_stops (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-color-line-t" title="hb_color_line_t"><span class="type">hb_color_line_t</span></a> *color_line</code></em>,
+                               <em class="parameter"><code>unsigned <span class="type">int</span> start</code></em>,
+                               <em class="parameter"><code>unsigned <span class="type">int</span> *count</code></em>,
+                               <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-color-stop-t" title="hb_color_stop_t"><span class="type">hb_color_stop_t</span></a> *color_stops</code></em>);</pre>
+<p>Fetches a list of color stops from the given color line object.</p>
+<p>Note that due to variations being applied, the returned color stops
+may be out of order. It is the callers responsibility to ensure that
+color stops are sorted by their offset before they are used.</p>
+<div class="refsect3">
+<a name="hb-color-line-get-color-stops.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>color_line</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-paint.html#hb-color-line-t" title="hb_color_line_t"><span class="type">hb_color_line_t</span></a> object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>start</p></td>
+<td class="parameter_description"><p>the index of the first color stop to return</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>count</p></td>
+<td class="parameter_description"><p>Input = the maximum number of feature tags to return;
+Output = the actual number of feature tags returned (may be zero). </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for input and for returning results. Default is transfer full."><span class="acronym">inout</span></acronym>][<acronym title="NULL may be passed instead of a pointer to a location."><span class="acronym">optional</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>color_stops</p></td>
+<td class="parameter_description"><p>Array of <a class="link" href="harfbuzz-hb-paint.html#hb-color-stop-t" title="hb_color_stop_t"><span class="type">hb_color_stop_t</span></a> to populate. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>][<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=count][<acronym title="NULL may be passed instead of a pointer to a location."><span class="acronym">optional</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-color-line-get-color-stops.returns"></a><h4>Returns</h4>
+<p> the total number of color stops in <em class="parameter"><code>color_line</code></em>
+</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-color-line-get-extend-func-t"></a><h3>hb_color_line_get_extend_func_t ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-paint.html#hb-paint-extend-t" title="enum hb_paint_extend_t"><span class="returnvalue">hb_paint_extend_t</span></a>
+<span class="c_punctuation">(</span>*hb_color_line_get_extend_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-color-line-t" title="hb_color_line_t"><span class="type">hb_color_line_t</span></a> *color_line</code></em>,
+                                    <em class="parameter"><code><span class="type">void</span> *color_line_data</code></em>,
+                                    <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <em class="parameter"><code>hb_color_line_t</code></em>
+ to fetches the extend mode.</p>
+<div class="refsect3">
+<a name="hb-color-line-get-extend-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>color_line</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-paint.html#hb-color-line-t" title="hb_color_line_t"><span class="type">hb_color_line_t</span></a> object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>color_line_data</p></td>
+<td class="parameter_description"><p>the data accompanying <em class="parameter"><code>color_line</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>the data accompanying this method</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-color-line-get-extend-func-t.returns"></a><h4>Returns</h4>
+<p> the extend mode of <em class="parameter"><code>color_line</code></em>
+</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-color-line-get-extend"></a><h3>hb_color_line_get_extend ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-paint.html#hb-paint-extend-t" title="enum hb_paint_extend_t"><span class="returnvalue">hb_paint_extend_t</span></a>
+hb_color_line_get_extend (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-color-line-t" title="hb_color_line_t"><span class="type">hb_color_line_t</span></a> *color_line</code></em>);</pre>
+<p>Fetches the extend mode of the color line object.</p>
+<div class="refsect3">
+<a name="hb-color-line-get-extend.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>color_line</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-paint.html#hb-color-line-t" title="hb_color_line_t"><span class="type">hb_color_line_t</span></a> object</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-color-line-get-extend.returns"></a><h4>Returns</h4>
+<p> the extend mode of <em class="parameter"><code>color_line</code></em>
+</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-linear-gradient-func-t"></a><h3>hb_paint_linear_gradient_func_t ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+<span class="c_punctuation">(</span>*hb_paint_linear_gradient_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                    <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-color-line-t" title="hb_color_line_t"><span class="type">hb_color_line_t</span></a> *color_line</code></em>,
+                                    <em class="parameter"><code><span class="type">float</span> x0</code></em>,
+                                    <em class="parameter"><code><span class="type">float</span> y0</code></em>,
+                                    <em class="parameter"><code><span class="type">float</span> x1</code></em>,
+                                    <em class="parameter"><code><span class="type">float</span> y1</code></em>,
+                                    <em class="parameter"><code><span class="type">float</span> x2</code></em>,
+                                    <em class="parameter"><code><span class="type">float</span> y2</code></em>,
+                                    <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> to paint a linear
+gradient everywhere within the current clip.</p>
+<p>The <em class="parameter"><code>color_line</code></em>
+ object contains information about the colors of the gradients.
+It is only valid for the duration of the callback, you cannot keep it around.</p>
+<p>The coordinates of the points are interpreted according
+to the current transform.</p>
+<p>See the OpenType spec <a class="ulink" href="https://learn.microsoft.com/en-us/typography/opentype/spec/colr" target="_top">COLR</a>
+section for details on how the points define the direction
+of the gradient, and how to interpret the <em class="parameter"><code>color_line</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-paint-linear-gradient-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>The data accompanying the paint functions in <a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph" title="hb_font_paint_glyph ()"><code class="function">hb_font_paint_glyph()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>color_line</p></td>
+<td class="parameter_description"><p>Color information for the gradient</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x0</p></td>
+<td class="parameter_description"><p>X coordinate of the first point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y0</p></td>
+<td class="parameter_description"><p>Y coordinate of the first point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x1</p></td>
+<td class="parameter_description"><p>X coordinate of the second point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y1</p></td>
+<td class="parameter_description"><p>Y coordinate of the second point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x2</p></td>
+<td class="parameter_description"><p>X coordinate of the third point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y2</p></td>
+<td class="parameter_description"><p>Y coordinate of the third point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed to <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-linear-gradient-func" title="hb_paint_funcs_set_linear_gradient_func ()"><code class="function">hb_paint_funcs_set_linear_gradient_func()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-set-linear-gradient-func"></a><h3>hb_paint_funcs_set_linear_gradient_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_funcs_set_linear_gradient_func
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-linear-gradient-func-t" title="hb_paint_linear_gradient_func_t ()"><span class="type">hb_paint_linear_gradient_func_t</span></a> func</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the linear-gradient callback on the paint functions struct.</p>
+<div class="refsect3">
+<a name="hb-paint-funcs-set-linear-gradient-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>A paint functions struct</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The linear-gradient callback. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>Function to call when <em class="parameter"><code>user_data</code></em>
+is no longer needed. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-radial-gradient-func-t"></a><h3>hb_paint_radial_gradient_func_t ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+<span class="c_punctuation">(</span>*hb_paint_radial_gradient_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                    <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-color-line-t" title="hb_color_line_t"><span class="type">hb_color_line_t</span></a> *color_line</code></em>,
+                                    <em class="parameter"><code><span class="type">float</span> x0</code></em>,
+                                    <em class="parameter"><code><span class="type">float</span> y0</code></em>,
+                                    <em class="parameter"><code><span class="type">float</span> r0</code></em>,
+                                    <em class="parameter"><code><span class="type">float</span> x1</code></em>,
+                                    <em class="parameter"><code><span class="type">float</span> y1</code></em>,
+                                    <em class="parameter"><code><span class="type">float</span> r1</code></em>,
+                                    <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> to paint a radial
+gradient everywhere within the current clip.</p>
+<p>The <em class="parameter"><code>color_line</code></em>
+ object contains information about the colors of the gradients.
+It is only valid for the duration of the callback, you cannot keep it around.</p>
+<p>The coordinates of the points are interpreted according
+to the current transform.</p>
+<p>See the OpenType spec <a class="ulink" href="https://learn.microsoft.com/en-us/typography/opentype/spec/colr" target="_top">COLR</a>
+section for details on how the points define the direction
+of the gradient, and how to interpret the <em class="parameter"><code>color_line</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-paint-radial-gradient-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>The data accompanying the paint functions in <a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph" title="hb_font_paint_glyph ()"><code class="function">hb_font_paint_glyph()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>color_line</p></td>
+<td class="parameter_description"><p>Color information for the gradient</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x0</p></td>
+<td class="parameter_description"><p>X coordinate of the first circle's center</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y0</p></td>
+<td class="parameter_description"><p>Y coordinate of the first circle's center</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>r0</p></td>
+<td class="parameter_description"><p>radius of the first circle</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x1</p></td>
+<td class="parameter_description"><p>X coordinate of the second circle's center</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y1</p></td>
+<td class="parameter_description"><p>Y coordinate of the second circle's center</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>r1</p></td>
+<td class="parameter_description"><p>radius of the second circle</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed to <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-radial-gradient-func" title="hb_paint_funcs_set_radial_gradient_func ()"><code class="function">hb_paint_funcs_set_radial_gradient_func()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-set-radial-gradient-func"></a><h3>hb_paint_funcs_set_radial_gradient_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_funcs_set_radial_gradient_func
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-radial-gradient-func-t" title="hb_paint_radial_gradient_func_t ()"><span class="type">hb_paint_radial_gradient_func_t</span></a> func</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the radial-gradient callback on the paint functions struct.</p>
+<div class="refsect3">
+<a name="hb-paint-funcs-set-radial-gradient-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>A paint functions struct</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The radial-gradient callback. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>Function to call when <em class="parameter"><code>user_data</code></em>
+is no longer needed. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-sweep-gradient-func-t"></a><h3>hb_paint_sweep_gradient_func_t ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+<span class="c_punctuation">(</span>*hb_paint_sweep_gradient_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                   <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-color-line-t" title="hb_color_line_t"><span class="type">hb_color_line_t</span></a> *color_line</code></em>,
+                                   <em class="parameter"><code><span class="type">float</span> x0</code></em>,
+                                   <em class="parameter"><code><span class="type">float</span> y0</code></em>,
+                                   <em class="parameter"><code><span class="type">float</span> start_angle</code></em>,
+                                   <em class="parameter"><code><span class="type">float</span> end_angle</code></em>,
+                                   <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> to paint a sweep
+gradient everywhere within the current clip.</p>
+<p>The <em class="parameter"><code>color_line</code></em>
+ object contains information about the colors of the gradients.
+It is only valid for the duration of the callback, you cannot keep it around.</p>
+<p>The coordinates of the points are interpreted according
+to the current transform.</p>
+<p>See the OpenType spec <a class="ulink" href="https://learn.microsoft.com/en-us/typography/opentype/spec/colr" target="_top">COLR</a>
+section for details on how the points define the direction
+of the gradient, and how to interpret the <em class="parameter"><code>color_line</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-paint-sweep-gradient-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>The data accompanying the paint functions in <a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph" title="hb_font_paint_glyph ()"><code class="function">hb_font_paint_glyph()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>color_line</p></td>
+<td class="parameter_description"><p>Color information for the gradient</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x0</p></td>
+<td class="parameter_description"><p>X coordinate of the circle's center</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y0</p></td>
+<td class="parameter_description"><p>Y coordinate of the circle's center</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>start_angle</p></td>
+<td class="parameter_description"><p>the start angle, in radians</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>end_angle</p></td>
+<td class="parameter_description"><p>the end angle, in radians</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed to <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-sweep-gradient-func" title="hb_paint_funcs_set_sweep_gradient_func ()"><code class="function">hb_paint_funcs_set_sweep_gradient_func()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-set-sweep-gradient-func"></a><h3>hb_paint_funcs_set_sweep_gradient_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_funcs_set_sweep_gradient_func
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-sweep-gradient-func-t" title="hb_paint_sweep_gradient_func_t ()"><span class="type">hb_paint_sweep_gradient_func_t</span></a> func</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the sweep-gradient callback on the paint functions struct.</p>
+<div class="refsect3">
+<a name="hb-paint-funcs-set-sweep-gradient-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>A paint functions struct</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The sweep-gradient callback. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>Function to call when <em class="parameter"><code>user_data</code></em>
+is no longer needed. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-push-group-func-t"></a><h3>hb_paint_push_group_func_t ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+<span class="c_punctuation">(</span>*hb_paint_push_group_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                               <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                               <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> to use
+an intermediate surface for subsequent paint calls.</p>
+<p>The drawing will be redirected to an intermediate surface
+until a matching call to the <span class="type">hb_paint_funcs_pop_group_func_t</span>
+vfunc.</p>
+<div class="refsect3">
+<a name="hb-paint-push-group-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>The data accompanying the paint functions in <a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph" title="hb_font_paint_glyph ()"><code class="function">hb_font_paint_glyph()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed to <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-group-func" title="hb_paint_funcs_set_push_group_func ()"><code class="function">hb_paint_funcs_set_push_group_func()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-set-push-group-func"></a><h3>hb_paint_funcs_set_push_group_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_funcs_set_push_group_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-push-group-func-t" title="hb_paint_push_group_func_t ()"><span class="type">hb_paint_push_group_func_t</span></a> func</code></em>,
+                                    <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the push-group callback on the paint functions struct.</p>
+<div class="refsect3">
+<a name="hb-paint-funcs-set-push-group-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>A paint functions struct</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The push-group callback. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>Function to call when <em class="parameter"><code>user_data</code></em>
+is no longer needed. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-pop-group-func-t"></a><h3>hb_paint_pop_group_func_t ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+<span class="c_punctuation">(</span>*hb_paint_pop_group_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                              <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-composite-mode-t" title="enum hb_paint_composite_mode_t"><span class="type">hb_paint_composite_mode_t</span></a> mode</code></em>,
+                              <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> to undo
+the effect of a prior call to the <span class="type">hb_paint_funcs_push_group_func_t</span>
+vfunc.</p>
+<p>This call stops the redirection to the intermediate surface,
+and then composites it on the previous surface, using the
+compositing mode passed to this call.</p>
+<div class="refsect3">
+<a name="hb-paint-pop-group-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>The data accompanying the paint functions in <a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph" title="hb_font_paint_glyph ()"><code class="function">hb_font_paint_glyph()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>mode</p></td>
+<td class="parameter_description"><p>the compositing mode to use</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed to <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-pop-group-func" title="hb_paint_funcs_set_pop_group_func ()"><code class="function">hb_paint_funcs_set_pop_group_func()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-set-pop-group-func"></a><h3>hb_paint_funcs_set_pop_group_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_funcs_set_pop_group_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-pop-group-func-t" title="hb_paint_pop_group_func_t ()"><span class="type">hb_paint_pop_group_func_t</span></a> func</code></em>,
+                                   <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the pop-group callback on the paint functions struct.</p>
+<div class="refsect3">
+<a name="hb-paint-funcs-set-pop-group-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>A paint functions struct</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The pop-group callback. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>Function to call when <em class="parameter"><code>user_data</code></em>
+is no longer needed. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-custom-palette-color-func-t"></a><h3>hb_paint_custom_palette_color_func_t ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="c_punctuation">(</span>*hb_paint_custom_palette_color_func_t<span class="c_punctuation">)</span>
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                                <em class="parameter"><code>unsigned <span class="type">int</span> color_index</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-ot-color.html#hb-color-t" title="hb_color_t"><span class="type">hb_color_t</span></a> *color</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> to fetch a color from the custom
+color palette.</p>
+<p>Custom palette colors override the colors from the fonts selected color
+palette. It is not necessary to override all palette entries; for entries
+that should be taken from the font palette, return <code class="literal">false</code>.</p>
+<p>This function might get called multiple times, but the custom palette is
+expected to remain unchanged for duration of a <a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph" title="hb_font_paint_glyph ()"><code class="function">hb_font_paint_glyph()</code></a> call.</p>
+<div class="refsect3">
+<a name="hb-paint-custom-palette-color-func-t.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions object</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>The data accompanying the paint functions in <a class="link" href="harfbuzz-hb-font.html#hb-font-paint-glyph" title="hb_font_paint_glyph ()"><code class="function">hb_font_paint_glyph()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>color_index</p></td>
+<td class="parameter_description"><p>the color index</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>color</p></td>
+<td class="parameter_description"><p>fetched color. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed to <a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-set-pop-group-func" title="hb_paint_funcs_set_pop_group_func ()"><code class="function">hb_paint_funcs_set_pop_group_func()</code></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-paint-custom-palette-color-func-t.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if found, <code class="literal">false</code> otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-funcs-set-custom-palette-color-func"></a><h3>hb_paint_funcs_set_custom_palette_color_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_funcs_set_custom_palette_color_func
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-custom-palette-color-func-t" title="hb_paint_custom_palette_color_func_t ()"><span class="type">hb_paint_custom_palette_color_func_t</span></a> func</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the custom-palette-color callback on the paint functions struct.</p>
+<div class="refsect3">
+<a name="hb-paint-funcs-set-custom-palette-color-func.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>A paint functions struct</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The custom-palette-color callback. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>Function to call when <em class="parameter"><code>user_data</code></em>
+is no longer needed. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-push-transform"></a><h3>hb_paint_push_transform ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_push_transform (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                         <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                         <em class="parameter"><code><span class="type">float</span> xx</code></em>,
+                         <em class="parameter"><code><span class="type">float</span> yx</code></em>,
+                         <em class="parameter"><code><span class="type">float</span> xy</code></em>,
+                         <em class="parameter"><code><span class="type">float</span> yy</code></em>,
+                         <em class="parameter"><code><span class="type">float</span> dx</code></em>,
+                         <em class="parameter"><code><span class="type">float</span> dy</code></em>);</pre>
+<p>Perform a "push-transform" paint operation.</p>
+<div class="refsect3">
+<a name="hb-paint-push-transform.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>associated data passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>xx</p></td>
+<td class="parameter_description"><p>xx component of the transform matrix</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>yx</p></td>
+<td class="parameter_description"><p>yx component of the transform matrix</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>xy</p></td>
+<td class="parameter_description"><p>xy component of the transform matrix</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>yy</p></td>
+<td class="parameter_description"><p>yy component of the transform matrix</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>dx</p></td>
+<td class="parameter_description"><p>dx component of the transform matrix</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>dy</p></td>
+<td class="parameter_description"><p>dy component of the transform matrix</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-pop-transform"></a><h3>hb_paint_pop_transform ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_pop_transform (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                        <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>);</pre>
+<p>Perform a "pop-transform" paint operation.</p>
+<div class="refsect3">
+<a name="hb-paint-pop-transform.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>associated data passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-color-glyph"></a><h3>hb_paint_color_glyph ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_paint_color_glyph (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                      <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
+<p>Perform a "color-glyph" paint operation.</p>
+<div class="refsect3">
+<a name="hb-paint-color-glyph.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>associated data passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>the glyph ID</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p>the font</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-8-2-0.html#api-index-8.2.0">8.2.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-push-clip-glyph"></a><h3>hb_paint_push_clip_glyph ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_push_clip_glyph (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                          <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                          <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> glyph</code></em>,
+                          <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>);</pre>
+<p>Perform a "push-clip-glyph" paint operation.</p>
+<div class="refsect3">
+<a name="hb-paint-push-clip-glyph.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>associated data passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>glyph</p></td>
+<td class="parameter_description"><p>the glyph ID</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p>the font</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-push-clip-rectangle"></a><h3>hb_paint_push_clip_rectangle ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_push_clip_rectangle (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                              <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                              <em class="parameter"><code><span class="type">float</span> xmin</code></em>,
+                              <em class="parameter"><code><span class="type">float</span> ymin</code></em>,
+                              <em class="parameter"><code><span class="type">float</span> xmax</code></em>,
+                              <em class="parameter"><code><span class="type">float</span> ymax</code></em>);</pre>
+<p>Perform a "push-clip-rect" paint operation.</p>
+<div class="refsect3">
+<a name="hb-paint-push-clip-rectangle.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>associated data passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>xmin</p></td>
+<td class="parameter_description"><p>min X for the rectangle</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>ymin</p></td>
+<td class="parameter_description"><p>min Y for the rectangle</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>xmax</p></td>
+<td class="parameter_description"><p>max X for the rectangle</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>ymax</p></td>
+<td class="parameter_description"><p>max Y for the rectangle</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-pop-clip"></a><h3>hb_paint_pop_clip ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_pop_clip (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                   <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>);</pre>
+<p>Perform a "pop-clip" paint operation.</p>
+<div class="refsect3">
+<a name="hb-paint-pop-clip.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>associated data passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-color"></a><h3>hb_paint_color ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_color (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> is_foreground</code></em>,
+                <em class="parameter"><code><a class="link" href="harfbuzz-hb-ot-color.html#hb-color-t" title="hb_color_t"><span class="type">hb_color_t</span></a> color</code></em>);</pre>
+<p>Perform a "color" paint operation.</p>
+<div class="refsect3">
+<a name="hb-paint-color.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>associated data passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>is_foreground</p></td>
+<td class="parameter_description"><p>whether the color is the foreground</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>color</p></td>
+<td class="parameter_description"><p>The color to use</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-image"></a><h3>hb_paint_image ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_image (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                <em class="parameter"><code><a class="link" href="harfbuzz-hb-blob.html#hb-blob-t" title="hb_blob_t"><span class="type">hb_blob_t</span></a> *image</code></em>,
+                <em class="parameter"><code>unsigned <span class="type">int</span> width</code></em>,
+                <em class="parameter"><code>unsigned <span class="type">int</span> height</code></em>,
+                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> format</code></em>,
+                <em class="parameter"><code><span class="type">float</span> slant</code></em>,
+                <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-glyph-extents-t" title="hb_glyph_extents_t"><span class="type">hb_glyph_extents_t</span></a> *extents</code></em>);</pre>
+<p>Perform a "image" paint operation.</p>
+<div class="refsect3">
+<a name="hb-paint-image.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>associated data passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>image</p></td>
+<td class="parameter_description"><p>image data</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>width</p></td>
+<td class="parameter_description"><p>width of the raster image in pixels, or 0</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>height</p></td>
+<td class="parameter_description"><p>height of the raster image in pixels, or 0</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>format</p></td>
+<td class="parameter_description"><p>the image format as a tag</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>slant</p></td>
+<td class="parameter_description"><p>the synthetic slant ratio to be applied to the image during rendering</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>extents</p></td>
+<td class="parameter_description"><p>the extents of the glyph. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-linear-gradient"></a><h3>hb_paint_linear_gradient ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_linear_gradient (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                          <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                          <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-color-line-t" title="hb_color_line_t"><span class="type">hb_color_line_t</span></a> *color_line</code></em>,
+                          <em class="parameter"><code><span class="type">float</span> x0</code></em>,
+                          <em class="parameter"><code><span class="type">float</span> y0</code></em>,
+                          <em class="parameter"><code><span class="type">float</span> x1</code></em>,
+                          <em class="parameter"><code><span class="type">float</span> y1</code></em>,
+                          <em class="parameter"><code><span class="type">float</span> x2</code></em>,
+                          <em class="parameter"><code><span class="type">float</span> y2</code></em>);</pre>
+<p>Perform a "linear-gradient" paint operation.</p>
+<div class="refsect3">
+<a name="hb-paint-linear-gradient.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>associated data passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>color_line</p></td>
+<td class="parameter_description"><p>Color information for the gradient</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x0</p></td>
+<td class="parameter_description"><p>X coordinate of the first point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y0</p></td>
+<td class="parameter_description"><p>Y coordinate of the first point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x1</p></td>
+<td class="parameter_description"><p>X coordinate of the second point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y1</p></td>
+<td class="parameter_description"><p>Y coordinate of the second point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x2</p></td>
+<td class="parameter_description"><p>X coordinate of the third point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y2</p></td>
+<td class="parameter_description"><p>Y coordinate of the third point</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-radial-gradient"></a><h3>hb_paint_radial_gradient ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_radial_gradient (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                          <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                          <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-color-line-t" title="hb_color_line_t"><span class="type">hb_color_line_t</span></a> *color_line</code></em>,
+                          <em class="parameter"><code><span class="type">float</span> x0</code></em>,
+                          <em class="parameter"><code><span class="type">float</span> y0</code></em>,
+                          <em class="parameter"><code><span class="type">float</span> r0</code></em>,
+                          <em class="parameter"><code><span class="type">float</span> x1</code></em>,
+                          <em class="parameter"><code><span class="type">float</span> y1</code></em>,
+                          <em class="parameter"><code><span class="type">float</span> r1</code></em>);</pre>
+<p>Perform a "radial-gradient" paint operation.</p>
+<div class="refsect3">
+<a name="hb-paint-radial-gradient.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>associated data passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>color_line</p></td>
+<td class="parameter_description"><p>Color information for the gradient</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x0</p></td>
+<td class="parameter_description"><p>X coordinate of the first circle's center</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y0</p></td>
+<td class="parameter_description"><p>Y coordinate of the first circle's center</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>r0</p></td>
+<td class="parameter_description"><p>radius of the first circle</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x1</p></td>
+<td class="parameter_description"><p>X coordinate of the second circle's center</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y1</p></td>
+<td class="parameter_description"><p>Y coordinate of the second circle's center</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>r1</p></td>
+<td class="parameter_description"><p>radius of the second circle</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-sweep-gradient"></a><h3>hb_paint_sweep_gradient ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_sweep_gradient (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                         <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                         <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-color-line-t" title="hb_color_line_t"><span class="type">hb_color_line_t</span></a> *color_line</code></em>,
+                         <em class="parameter"><code><span class="type">float</span> x0</code></em>,
+                         <em class="parameter"><code><span class="type">float</span> y0</code></em>,
+                         <em class="parameter"><code><span class="type">float</span> start_angle</code></em>,
+                         <em class="parameter"><code><span class="type">float</span> end_angle</code></em>);</pre>
+<p>Perform a "sweep-gradient" paint operation.</p>
+<div class="refsect3">
+<a name="hb-paint-sweep-gradient.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>associated data passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>color_line</p></td>
+<td class="parameter_description"><p>Color information for the gradient</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>x0</p></td>
+<td class="parameter_description"><p>X coordinate of the circle's center</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>y0</p></td>
+<td class="parameter_description"><p>Y coordinate of the circle's center</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>start_angle</p></td>
+<td class="parameter_description"><p>the start angle</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>end_angle</p></td>
+<td class="parameter_description"><p>the end angle</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-push-group"></a><h3>hb_paint_push_group ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_push_group (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                     <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>);</pre>
+<p>Perform a "push-group" paint operation.</p>
+<div class="refsect3">
+<a name="hb-paint-push-group.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>associated data passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-pop-group"></a><h3>hb_paint_pop_group ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_paint_pop_group (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                    <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-composite-mode-t" title="enum hb_paint_composite_mode_t"><span class="type">hb_paint_composite_mode_t</span></a> mode</code></em>);</pre>
+<p>Perform a "pop-group" paint operation.</p>
+<div class="refsect3">
+<a name="hb-paint-pop-group.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>associated data passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>mode</p></td>
+<td class="parameter_description"><p>the compositing mode to use</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-custom-palette-color"></a><h3>hb_paint_custom_palette_color ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_paint_custom_palette_color (<em class="parameter"><code><a class="link" href="harfbuzz-hb-paint.html#hb-paint-funcs-t" title="hb_paint_funcs_t"><span class="type">hb_paint_funcs_t</span></a> *funcs</code></em>,
+                               <em class="parameter"><code><span class="type">void</span> *paint_data</code></em>,
+                               <em class="parameter"><code>unsigned <span class="type">int</span> color_index</code></em>,
+                               <em class="parameter"><code><a class="link" href="harfbuzz-hb-ot-color.html#hb-color-t" title="hb_color_t"><span class="type">hb_color_t</span></a> *color</code></em>);</pre>
+<p>Gets the custom palette color for <em class="parameter"><code>color_index</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-paint-custom-palette-color.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>funcs</p></td>
+<td class="parameter_description"><p>paint functions</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>paint_data</p></td>
+<td class="parameter_description"><p>associated data passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>color_index</p></td>
+<td class="parameter_description"><p>color index</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>color</p></td>
+<td class="parameter_description"><p>fetched color. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-paint-custom-palette-color.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if found, <code class="literal">false</code> otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+</div>
+<div class="refsect1">
+<a name="harfbuzz-hb-paint.other_details"></a><h2>Types and Values</h2>
+<div class="refsect2">
+<a name="hb-paint-funcs-t"></a><h3>hb_paint_funcs_t</h3>
+<pre class="programlisting">typedef struct hb_paint_funcs_t hb_paint_funcs_t;
+</pre>
+<p>Glyph paint callbacks.</p>
+<p>The callbacks assume that the caller maintains a stack
+of current transforms, clips and intermediate surfaces,
+as evidenced by the pairs of push/pop callbacks. The
+push/pop calls will be properly nested, so it is fine
+to store the different kinds of object on a single stack.</p>
+<p>Not all callbacks are required for all kinds of glyphs.
+For rendering COLRv0 or non-color outline glyphs, the
+gradient callbacks are not needed, and the composite
+callback only needs to handle simple alpha compositing
+(<a class="link" href="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-SRC-OVER:CAPS"><span class="type">HB_PAINT_COMPOSITE_MODE_SRC_OVER</span></a>).</p>
+<p>The paint-image callback is only needed for glyphs
+with image blobs in the CBDT, sbix or SVG tables.</p>
+<p>The custom-palette-color callback is only necessary if
+you want to override colors from the font palette with
+custom colors.</p>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="HB-PAINT-IMAGE-FORMAT-PNG:CAPS"></a><h3>HB_PAINT_IMAGE_FORMAT_PNG</h3>
+<pre class="programlisting">#define HB_PAINT_IMAGE_FORMAT_PNG HB_TAG('p','n','g',' ')
+</pre>
+<p>Tag identifying PNG images in <a class="link" href="harfbuzz-hb-paint.html#hb-paint-image-func-t" title="hb_paint_image_func_t ()"><span class="type">hb_paint_image_func_t</span></a> callbacks.</p>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="HB-PAINT-IMAGE-FORMAT-SVG:CAPS"></a><h3>HB_PAINT_IMAGE_FORMAT_SVG</h3>
+<pre class="programlisting">#define HB_PAINT_IMAGE_FORMAT_SVG HB_TAG('s','v','g',' ')
+</pre>
+<p>Tag identifying SVG images in <a class="link" href="harfbuzz-hb-paint.html#hb-paint-image-func-t" title="hb_paint_image_func_t ()"><span class="type">hb_paint_image_func_t</span></a> callbacks.</p>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="HB-PAINT-IMAGE-FORMAT-BGRA:CAPS"></a><h3>HB_PAINT_IMAGE_FORMAT_BGRA</h3>
+<pre class="programlisting">#define HB_PAINT_IMAGE_FORMAT_BGRA HB_TAG('B','G','R','A')
+</pre>
+<p>Tag identifying raw pixel-data images in <a class="link" href="harfbuzz-hb-paint.html#hb-paint-image-func-t" title="hb_paint_image_func_t ()"><span class="type">hb_paint_image_func_t</span></a> callbacks.
+The data is in BGRA pre-multiplied sRGBA color-space format.</p>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-color-line-t"></a><h3>hb_color_line_t</h3>
+<pre class="programlisting">typedef struct hb_color_line_t hb_color_line_t;
+</pre>
+<p>A struct containing color information for a gradient.</p>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-color-stop-t"></a><h3>hb_color_stop_t</h3>
+<pre class="programlisting">typedef struct {
+  float offset;
+  hb_bool_t is_foreground;
+  hb_color_t color;
+} hb_color_stop_t;
+</pre>
+<p>Information about a color stop on a color line.</p>
+<p>Color lines typically have offsets ranging between 0 and 1,
+but that is not required.</p>
+<p>Note: despite <em class="parameter"><code>color</code></em>
+ being unpremultiplied here, interpolation in
+gradients shall happen in premultiplied space. See the OpenType spec
+<a class="ulink" href="https://learn.microsoft.com/en-us/typography/opentype/spec/colr" target="_top">COLR</a>
+section for details.</p>
+<div class="refsect3">
+<a name="hb-color-stop-t.members"></a><h4>Members</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="300px" class="struct_members_name">
+<col class="struct_members_description">
+<col width="200px" class="struct_members_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="struct_member_name"><p><span class="type">float</span> <em class="structfield"><code><a name="hb-color-stop-t.offset"></a>offset</code></em>;</p></td>
+<td class="struct_member_description"><p>the offset of the color stop</p></td>
+<td class="struct_member_annotations"> </td>
+</tr>
+<tr>
+<td class="struct_member_name"><p><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> <em class="structfield"><code><a name="hb-color-stop-t.is-foreground"></a>is_foreground</code></em>;</p></td>
+<td class="struct_member_description"><p>whether the color is the foreground</p></td>
+<td class="struct_member_annotations"> </td>
+</tr>
+<tr>
+<td class="struct_member_name"><p><a class="link" href="harfbuzz-hb-ot-color.html#hb-color-t" title="hb_color_t"><span class="type">hb_color_t</span></a> <em class="structfield"><code><a name="hb-color-stop-t.color"></a>color</code></em>;</p></td>
+<td class="struct_member_description"><p>the color, unpremultiplied</p></td>
+<td class="struct_member_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-extend-t"></a><h3>enum hb_paint_extend_t</h3>
+<p>The values of this enumeration determine how color values
+outside the minimum and maximum defined offset on a <a class="link" href="harfbuzz-hb-paint.html#hb-color-line-t" title="hb_color_line_t"><span class="type">hb_color_line_t</span></a>
+are determined.</p>
+<p>See the OpenType spec <a class="ulink" href="https://learn.microsoft.com/en-us/typography/opentype/spec/colr" target="_top">COLR</a>
+section for details.</p>
+<div class="refsect3">
+<a name="hb-paint-extend-t.members"></a><h4>Members</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="300px" class="enum_members_name">
+<col class="enum_members_description">
+<col width="200px" class="enum_members_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-EXTEND-PAD:CAPS"></a>HB_PAINT_EXTEND_PAD</p></td>
+<td class="enum_member_description">
+<p>Outside the defined interval,
+the color of the closest color stop is used.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-EXTEND-REPEAT:CAPS"></a>HB_PAINT_EXTEND_REPEAT</p></td>
+<td class="enum_member_description">
+<p>The color line is repeated over
+repeated multiples of the defined interval</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-EXTEND-REFLECT:CAPS"></a>HB_PAINT_EXTEND_REFLECT</p></td>
+<td class="enum_member_description">
+<p>The color line is repeated over
+repeated intervals, as for the repeat mode.
+However, in each repeated interval, the ordering of
+color stops is the reverse of the adjacent interval.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-paint-composite-mode-t"></a><h3>enum hb_paint_composite_mode_t</h3>
+<p>The values of this enumeration describe the compositing modes
+that can be used when combining temporary redirected drawing
+with the backdrop.</p>
+<p>See the OpenType spec <a class="ulink" href="https://learn.microsoft.com/en-us/typography/opentype/spec/colr" target="_top">COLR</a>
+section for details.</p>
+<div class="refsect3">
+<a name="hb-paint-composite-mode-t.members"></a><h4>Members</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="300px" class="enum_members_name">
+<col class="enum_members_description">
+<col width="200px" class="enum_members_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-CLEAR:CAPS"></a>HB_PAINT_COMPOSITE_MODE_CLEAR</p></td>
+<td class="enum_member_description">
+<p>clear destination layer (bounded)</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-SRC:CAPS"></a>HB_PAINT_COMPOSITE_MODE_SRC</p></td>
+<td class="enum_member_description">
+<p>replace destination layer (bounded)</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-DEST:CAPS"></a>HB_PAINT_COMPOSITE_MODE_DEST</p></td>
+<td class="enum_member_description">
+<p>ignore the source</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-SRC-OVER:CAPS"></a>HB_PAINT_COMPOSITE_MODE_SRC_OVER</p></td>
+<td class="enum_member_description">
+<p>draw source layer on top of destination layer
+(bounded)</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-DEST-OVER:CAPS"></a>HB_PAINT_COMPOSITE_MODE_DEST_OVER</p></td>
+<td class="enum_member_description">
+<p>draw destination on top of source</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-SRC-IN:CAPS"></a>HB_PAINT_COMPOSITE_MODE_SRC_IN</p></td>
+<td class="enum_member_description">
+<p>draw source where there was destination content
+(unbounded)</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-DEST-IN:CAPS"></a>HB_PAINT_COMPOSITE_MODE_DEST_IN</p></td>
+<td class="enum_member_description">
+<p>leave destination only where there was
+source content (unbounded)</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-SRC-OUT:CAPS"></a>HB_PAINT_COMPOSITE_MODE_SRC_OUT</p></td>
+<td class="enum_member_description">
+<p>draw source where there was no destination
+content (unbounded)</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-DEST-OUT:CAPS"></a>HB_PAINT_COMPOSITE_MODE_DEST_OUT</p></td>
+<td class="enum_member_description">
+<p>leave destination only where there was no
+source content</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-SRC-ATOP:CAPS"></a>HB_PAINT_COMPOSITE_MODE_SRC_ATOP</p></td>
+<td class="enum_member_description">
+<p>draw source on top of destination content and
+only there</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-DEST-ATOP:CAPS"></a>HB_PAINT_COMPOSITE_MODE_DEST_ATOP</p></td>
+<td class="enum_member_description">
+<p>leave destination on top of source content
+and only there (unbounded)</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-XOR:CAPS"></a>HB_PAINT_COMPOSITE_MODE_XOR</p></td>
+<td class="enum_member_description">
+<p>source and destination are shown where there is only
+one of them</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-PLUS:CAPS"></a>HB_PAINT_COMPOSITE_MODE_PLUS</p></td>
+<td class="enum_member_description">
+<p>source and destination layers are accumulated</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-SCREEN:CAPS"></a>HB_PAINT_COMPOSITE_MODE_SCREEN</p></td>
+<td class="enum_member_description">
+<p>source and destination are complemented and
+multiplied. This causes the result to be at least as light as the lighter
+inputs.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-OVERLAY:CAPS"></a>HB_PAINT_COMPOSITE_MODE_OVERLAY</p></td>
+<td class="enum_member_description">
+<p>multiplies or screens, depending on the
+lightness of the destination color.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-DARKEN:CAPS"></a>HB_PAINT_COMPOSITE_MODE_DARKEN</p></td>
+<td class="enum_member_description">
+<p>replaces the destination with the source if it
+is darker, otherwise keeps the source.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-LIGHTEN:CAPS"></a>HB_PAINT_COMPOSITE_MODE_LIGHTEN</p></td>
+<td class="enum_member_description">
+<p>replaces the destination with the source if it
+is lighter, otherwise keeps the source.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-COLOR-DODGE:CAPS"></a>HB_PAINT_COMPOSITE_MODE_COLOR_DODGE</p></td>
+<td class="enum_member_description">
+<p>brightens the destination color to reflect
+the source color.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-COLOR-BURN:CAPS"></a>HB_PAINT_COMPOSITE_MODE_COLOR_BURN</p></td>
+<td class="enum_member_description">
+<p>darkens the destination color to reflect
+the source color.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-HARD-LIGHT:CAPS"></a>HB_PAINT_COMPOSITE_MODE_HARD_LIGHT</p></td>
+<td class="enum_member_description">
+<p>Multiplies or screens, dependent on source
+color.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-SOFT-LIGHT:CAPS"></a>HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT</p></td>
+<td class="enum_member_description">
+<p>Darkens or lightens, dependent on source
+color.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-DIFFERENCE:CAPS"></a>HB_PAINT_COMPOSITE_MODE_DIFFERENCE</p></td>
+<td class="enum_member_description">
+<p>Takes the difference of the source and
+destination color.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-EXCLUSION:CAPS"></a>HB_PAINT_COMPOSITE_MODE_EXCLUSION</p></td>
+<td class="enum_member_description">
+<p>Produces an effect similar to difference, but
+with lower contrast.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-MULTIPLY:CAPS"></a>HB_PAINT_COMPOSITE_MODE_MULTIPLY</p></td>
+<td class="enum_member_description">
+<p>source and destination layers are multiplied.
+This causes the result to be at least as dark as the darker inputs.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-HSL-HUE:CAPS"></a>HB_PAINT_COMPOSITE_MODE_HSL_HUE</p></td>
+<td class="enum_member_description">
+<p>Creates a color with the hue of the source
+and the saturation and luminosity of the target.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-HSL-SATURATION:CAPS"></a>HB_PAINT_COMPOSITE_MODE_HSL_SATURATION</p></td>
+<td class="enum_member_description">
+<p>Creates a color with the saturation
+of the source and the hue and luminosity of the target. Painting with
+this mode onto a gray area produces no change.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-HSL-COLOR:CAPS"></a>HB_PAINT_COMPOSITE_MODE_HSL_COLOR</p></td>
+<td class="enum_member_description">
+<p>Creates a color with the hue and saturation
+of the source and the luminosity of the target. This preserves the gray
+levels of the target and is useful for coloring monochrome images or
+tinting color images.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-PAINT-COMPOSITE-MODE-HSL-LUMINOSITY:CAPS"></a>HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY</p></td>
+<td class="enum_member_description">
+<p>Creates a color with the luminosity of
+the source and the hue and saturation of the target. This produces an
+inverse effect to <em class="parameter"><code>HB_PAINT_COMPOSITE_MODE_HSL_COLOR</code></em>
+.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
+</div>
+</div>
+</div>
+<div class="footer">
+<hr>Generated by GTK-Doc V1.32</div>
+</body>
+</html>
\ No newline at end of file
index 4a60fa8..b372096 100644 (file)
 <tbody>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="returnvalue">hb_set_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-add" title="hb_set_add ()">hb_set_add</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-create" title="hb_set_create ()">hb_set_create</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-add-range" title="hb_set_add_range ()">hb_set_add_range</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-allocation-successful" title="hb_set_allocation_successful ()">hb_set_allocation_successful</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="returnvalue">hb_set_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-allocation-successful" title="hb_set_allocation_successful ()">hb_set_allocation_successful</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-copy" title="hb_set_copy ()">hb_set_copy</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="returnvalue">hb_set_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-copy" title="hb_set_copy ()">hb_set_copy</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-get-empty" title="hb_set_get_empty ()">hb_set_get_empty</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="returnvalue">hb_set_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-set.html#hb-set-reference" title="hb_set_reference ()">hb_set_reference</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-clear" title="hb_set_clear ()">hb_set_clear</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-destroy" title="hb_set_destroy ()">hb_set_destroy</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="returnvalue">hb_set_t</span></a> *
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-create" title="hb_set_create ()">hb_set_create</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-set-user-data" title="hb_set_set_user_data ()">hb_set_set_user_data</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<span class="returnvalue">void</span> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-del" title="hb_set_del ()">hb_set_del</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-get-user-data" title="hb_set_get_user_data ()">hb_set_get_user_data</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-del-range" title="hb_set_del_range ()">hb_set_del_range</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-clear" title="hb_set_clear ()">hb_set_clear</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-destroy" title="hb_set_destroy ()">hb_set_destroy</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-set" title="hb_set_set ()">hb_set_set</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="returnvalue">hb_set_t</span></a> *
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-get-empty" title="hb_set_get_empty ()">hb_set_get_empty</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-has" title="hb_set_has ()">hb_set_has</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-get-max" title="hb_set_get_max ()">hb_set_get_max</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-add" title="hb_set_add ()">hb_set_add</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-get-min" title="hb_set_get_min ()">hb_set_get_min</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-add-range" title="hb_set_add_range ()">hb_set_add_range</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">unsigned <span class="returnvalue">int</span>
+<td class="function_type">
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-get-population" title="hb_set_get_population ()">hb_set_get_population</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-add-sorted-array" title="hb_set_add_sorted_array ()">hb_set_add_sorted_array</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span> *
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-get-user-data" title="hb_set_get_user_data ()">hb_set_get_user_data</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-del" title="hb_set_del ()">hb_set_del</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-has" title="hb_set_has ()">hb_set_has</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-del-range" title="hb_set_del_range ()">hb_set_del_range</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-intersect" title="hb_set_intersect ()">hb_set_intersect</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-get-max" title="hb_set_get_max ()">hb_set_get_max</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-invert" title="hb_set_invert ()">hb_set_invert</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-get-min" title="hb_set_get_min ()">hb_set_get_min</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">unsigned <span class="returnvalue">int</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-set.html#hb-set-get-population" title="hb_set_get_population ()">hb_set_get_population</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 </td>
 </tr>
 <tr>
+<td class="function_type">unsigned <span class="returnvalue">int</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-set.html#hb-set-hash" title="hb_set_hash ()">hb_set_hash</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-is-equal" title="hb_set_is_equal ()">hb_set_is_equal</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-subtract" title="hb_set_subtract ()">hb_set_subtract</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-is-subset" title="hb_set_is_subset ()">hb_set_is_subset</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-intersect" title="hb_set_intersect ()">hb_set_intersect</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-next" title="hb_set_next ()">hb_set_next</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-union" title="hb_set_union ()">hb_set_union</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-next-range" title="hb_set_next_range ()">hb_set_next_range</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-symmetric-difference" title="hb_set_symmetric_difference ()">hb_set_symmetric_difference</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-previous" title="hb_set_previous ()">hb_set_previous</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-invert" title="hb_set_invert ()">hb_set_invert</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-previous-range" title="hb_set_previous_range ()">hb_set_previous_range</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-is-inverted" title="hb_set_is_inverted ()">hb_set_is_inverted</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="returnvalue">hb_set_t</span></a> *
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-reference" title="hb_set_reference ()">hb_set_reference</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-is-equal" title="hb_set_is_equal ()">hb_set_is_equal</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-set" title="hb_set_set ()">hb_set_set</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-is-subset" title="hb_set_is_subset ()">hb_set_is_subset</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-set-user-data" title="hb_set_set_user_data ()">hb_set_set_user_data</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-next" title="hb_set_next ()">hb_set_next</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-subtract" title="hb_set_subtract ()">hb_set_subtract</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-next-range" title="hb_set_next_range ()">hb_set_next_range</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">unsigned <span class="returnvalue">int</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-set.html#hb-set-next-many" title="hb_set_next_many ()">hb_set_next_many</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-symmetric-difference" title="hb_set_symmetric_difference ()">hb_set_symmetric_difference</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-previous" title="hb_set_previous ()">hb_set_previous</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-set.html#hb-set-union" title="hb_set_union ()">hb_set_union</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-set.html#hb-set-previous-range" title="hb_set_previous_range ()">hb_set_previous_range</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 </tbody>
@@ -314,83 +344,19 @@ or other integer values.</p>
 <div class="refsect1">
 <a name="harfbuzz-hb-set.functions_details"></a><h2>Functions</h2>
 <div class="refsect2">
-<a name="hb-set-add"></a><h3>hb_set_add ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_set_add (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
-            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> codepoint</code></em>);</pre>
-<p>Adds <em class="parameter"><code>codepoint</code></em>
- to <em class="parameter"><code>set</code></em>
-.</p>
+<a name="hb-set-create"></a><h3>hb_set_create ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="returnvalue">hb_set_t</span></a> *
+hb_set_create (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
+<p>Creates a new, initially empty set.</p>
 <div class="refsect3">
-<a name="hb-set-add.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>set</p></td>
-<td class="parameter_description"><p>A set</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>codepoint</p></td>
-<td class="parameter_description"><p>The element to add to <em class="parameter"><code>set</code></em>
-</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-</tbody>
-</table></div>
+<a name="hb-set-create.returns"></a><h4>Returns</h4>
+<p>The new <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a>. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-set-add-range"></a><h3>hb_set_add_range ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_set_add_range (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
-                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> first</code></em>,
-                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> last</code></em>);</pre>
-<p>Adds all of the elements from <em class="parameter"><code>first</code></em>
- to <em class="parameter"><code>last</code></em>
-
-(inclusive) to <em class="parameter"><code>set</code></em>
-.</p>
-<div class="refsect3">
-<a name="hb-set-add-range.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>set</p></td>
-<td class="parameter_description"><p>A set</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>first</p></td>
-<td class="parameter_description"><p>The first element to add to <em class="parameter"><code>set</code></em>
-</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>last</p></td>
-<td class="parameter_description"><p>The final element to add to <em class="parameter"><code>set</code></em>
-</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-</tbody>
-</table></div>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-7.html#api-index-0.9.7">0.9.7</a></p>
-</div>
-<hr>
-<div class="refsect2">
 <a name="hb-set-allocation-successful"></a><h3>hb_set_allocation_successful ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 hb_set_allocation_successful (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>);</pre>
@@ -440,18 +406,33 @@ hb_set_copy (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb
 </div>
 <div class="refsect3">
 <a name="hb-set-copy.returns"></a><h4>Returns</h4>
-<p> Newly-allocated set.</p>
+<p>Newly-allocated set. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-2-8-2.html#api-index-2.8.2">2.8.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-set-clear"></a><h3>hb_set_clear ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_set_clear (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>);</pre>
-<p>Clears out the contents of a set.</p>
+<a name="hb-set-get-empty"></a><h3>hb_set_get_empty ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="returnvalue">hb_set_t</span></a> *
+hb_set_get_empty (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
+<p>Fetches the singleton empty <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-set-clear.parameters"></a><h4>Parameters</h4>
+<a name="hb-set-get-empty.returns"></a><h4>Returns</h4>
+<p>The empty <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a>. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-set-reference"></a><h3>hb_set_reference ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="returnvalue">hb_set_t</span></a> *
+hb_set_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>);</pre>
+<p>Increases the reference count on a set.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-set-reference.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -465,35 +446,201 @@ hb_set_clear (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.
 </tr></tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-set-create"></a><h3>hb_set_create ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="returnvalue">hb_set_t</span></a> *
-hb_set_create (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
-<p>Creates a new, initially empty set.</p>
-<p><span class="annotation">[Xconstructor]</span></p>
 <div class="refsect3">
-<a name="hb-set-create.returns"></a><h4>Returns</h4>
-<p>The new <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a>. </p>
+<a name="hb-set-reference.returns"></a><h4>Returns</h4>
+<p>The set. </p>
 <p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-set-del"></a><h3>hb_set_del ()</h3>
+<a name="hb-set-destroy"></a><h3>hb_set_destroy ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_set_del (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
-            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> codepoint</code></em>);</pre>
-<p>Removes <em class="parameter"><code>codepoint</code></em>
- from <em class="parameter"><code>set</code></em>
-.</p>
-<div class="refsect3">
-<a name="hb-set-del.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
+hb_set_destroy (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>);</pre>
+<p>Decreases the reference count on a set. When
+the reference count reaches zero, the set is
+destroyed, freeing all memory.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-set-destroy.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>set</p></td>
+<td class="parameter_description"><p>A set</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-set-set-user-data"></a><h3>hb_set_set_user_data ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_set_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
+                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
+                      <em class="parameter"><code><span class="type">void</span> *data</code></em>,
+                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
+                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
+<p>Attaches a user-data key/data pair to the specified set.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-set-set-user-data.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>set</p></td>
+<td class="parameter_description"><p>A set</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The user-data key to set</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>data</p></td>
+<td class="parameter_description"><p>A pointer to the user data to set</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>replace</p></td>
+<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-set-set-user-data.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-set-get-user-data"></a><h3>hb_set_get_user_data ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span> *
+hb_set_get_user_data (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
+                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>);</pre>
+<p>Fetches the user data associated with the specified key,
+attached to the specified set.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-set-get-user-data.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>set</p></td>
+<td class="parameter_description"><p>A set</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The user-data key to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-set-get-user-data.returns"></a><h4>Returns</h4>
+<p>A pointer to the user data. </p>
+<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-set-clear"></a><h3>hb_set_clear ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_set_clear (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>);</pre>
+<p>Clears out the contents of a set.</p>
+<div class="refsect3">
+<a name="hb-set-clear.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>set</p></td>
+<td class="parameter_description"><p>A set</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-set-set"></a><h3>hb_set_set ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_set_set (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
+            <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *other</code></em>);</pre>
+<p>Makes the contents of <em class="parameter"><code>set</code></em>
+ equal to the contents of <em class="parameter"><code>other</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-set-set.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>set</p></td>
+<td class="parameter_description"><p>A set</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>other</p></td>
+<td class="parameter_description"><p>Another set</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-set-has"></a><h3>hb_set_has ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_set_has (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
+            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> codepoint</code></em>);</pre>
+<p>Tests whether <em class="parameter"><code>codepoint</code></em>
+ belongs to <em class="parameter"><code>set</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-set-has.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
@@ -506,8 +653,46 @@ hb_set_del (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.ht
 </tr>
 <tr>
 <td class="parameter_name"><p>codepoint</p></td>
-<td class="parameter_description"><p>Removes <em class="parameter"><code>codepoint</code></em>
-from <em class="parameter"><code>set</code></em>
+<td class="parameter_description"><p>The element to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-set-has.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if <em class="parameter"><code>codepoint</code></em>
+is in <em class="parameter"><code>set</code></em>
+, <code class="literal">false</code> otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-set-add"></a><h3>hb_set_add ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_set_add (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
+            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> codepoint</code></em>);</pre>
+<p>Adds <em class="parameter"><code>codepoint</code></em>
+ to <em class="parameter"><code>set</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-set-add.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>set</p></td>
+<td class="parameter_description"><p>A set</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>codepoint</p></td>
+<td class="parameter_description"><p>The element to add to <em class="parameter"><code>set</code></em>
 </p></td>
 <td class="parameter_annotations"> </td>
 </tr>
@@ -518,22 +703,18 @@ from <em class="parameter"><code>set</code></em>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-set-del-range"></a><h3>hb_set_del_range ()</h3>
+<a name="hb-set-add-range"></a><h3>hb_set_add_range ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_set_del_range (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
+hb_set_add_range (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> first</code></em>,
                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> last</code></em>);</pre>
-<p>Removes all of the elements from <em class="parameter"><code>first</code></em>
+<p>Adds all of the elements from <em class="parameter"><code>first</code></em>
  to <em class="parameter"><code>last</code></em>
 
-(inclusive) from <em class="parameter"><code>set</code></em>
+(inclusive) to <em class="parameter"><code>set</code></em>
 .</p>
-<p>If <em class="parameter"><code>last</code></em>
- is <a class="link" href="harfbuzz-hb-set.html#HB-SET-VALUE-INVALID:CAPS" title="HB_SET_VALUE_INVALID"><span class="type">HB_SET_VALUE_INVALID</span></a>, then all values
-greater than or equal to <em class="parameter"><code>first</code></em>
- are removed.</p>
 <div class="refsect3">
-<a name="hb-set-del-range.parameters"></a><h4>Parameters</h4>
+<a name="hb-set-add-range.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -548,13 +729,13 @@ greater than or equal to <em class="parameter"><code>first</code></em>
 </tr>
 <tr>
 <td class="parameter_name"><p>first</p></td>
-<td class="parameter_description"><p>The first element to remove from <em class="parameter"><code>set</code></em>
+<td class="parameter_description"><p>The first element to add to <em class="parameter"><code>set</code></em>
 </p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
 <td class="parameter_name"><p>last</p></td>
-<td class="parameter_description"><p>The final element to remove from <em class="parameter"><code>set</code></em>
+<td class="parameter_description"><p>The final element to add to <em class="parameter"><code>set</code></em>
 </p></td>
 <td class="parameter_annotations"> </td>
 </tr>
@@ -565,45 +746,130 @@ greater than or equal to <em class="parameter"><code>first</code></em>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-set-destroy"></a><h3>hb_set_destroy ()</h3>
+<a name="hb-set-add-sorted-array"></a><h3>hb_set_add_sorted_array ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_set_destroy (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>);</pre>
-<p>Decreases the reference count on a set. When
-the reference count reaches zero, the set is
-destroyed, freeing all memory.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+hb_set_add_sorted_array (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
+                         <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *sorted_codepoints</code></em>,
+                         <em class="parameter"><code>unsigned <span class="type">int</span> num_codepoints</code></em>);</pre>
+<p>Adds <em class="parameter"><code>num_codepoints</code></em>
+ codepoints to a set at once.
+The codepoints array must be in increasing order,
+with size at least <em class="parameter"><code>num_codepoints</code></em>
+.</p>
 <div class="refsect3">
-<a name="hb-set-destroy.parameters"></a><h4>Parameters</h4>
+<a name="hb-set-add-sorted-array.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody><tr>
+<tbody>
+<tr>
 <td class="parameter_name"><p>set</p></td>
 <td class="parameter_description"><p>A set</p></td>
 <td class="parameter_annotations"> </td>
-</tr></tbody>
+</tr>
+<tr>
+<td class="parameter_name"><p>sorted_codepoints</p></td>
+<td class="parameter_description"><p>Array of codepoints to add. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=num_codepoints]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>num_codepoints</p></td>
+<td class="parameter_description"><p>Length of <em class="parameter"><code>sorted_codepoints</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<p class="since">Since: <a class="link" href="api-index-4-1-0.html#api-index-4.1.0">4.1.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-set-get-empty"></a><h3>hb_set_get_empty ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="returnvalue">hb_set_t</span></a> *
-hb_set_get_empty (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
-<p>Fetches the singleton empty <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a>.</p>
+<a name="hb-set-del"></a><h3>hb_set_del ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_set_del (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
+            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> codepoint</code></em>);</pre>
+<p>Removes <em class="parameter"><code>codepoint</code></em>
+ from <em class="parameter"><code>set</code></em>
+.</p>
 <div class="refsect3">
-<a name="hb-set-get-empty.returns"></a><h4>Returns</h4>
-<p>The empty <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a>. </p>
-<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+<a name="hb-set-del.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>set</p></td>
+<td class="parameter_description"><p>A set</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>codepoint</p></td>
+<td class="parameter_description"><p>Removes <em class="parameter"><code>codepoint</code></em>
+from <em class="parameter"><code>set</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-set-del-range"></a><h3>hb_set_del_range ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_set_del_range (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
+                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> first</code></em>,
+                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> last</code></em>);</pre>
+<p>Removes all of the elements from <em class="parameter"><code>first</code></em>
+ to <em class="parameter"><code>last</code></em>
+
+(inclusive) from <em class="parameter"><code>set</code></em>
+.</p>
+<p>If <em class="parameter"><code>last</code></em>
+ is <a class="link" href="harfbuzz-hb-set.html#HB-SET-VALUE-INVALID:CAPS" title="HB_SET_VALUE_INVALID"><span class="type">HB_SET_VALUE_INVALID</span></a>, then all values
+greater than or equal to <em class="parameter"><code>first</code></em>
+ are removed.</p>
+<div class="refsect3">
+<a name="hb-set-del-range.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>set</p></td>
+<td class="parameter_description"><p>A set</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>first</p></td>
+<td class="parameter_description"><p>The first element to remove from <em class="parameter"><code>set</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>last</p></td>
+<td class="parameter_description"><p>The final element to remove from <em class="parameter"><code>set</code></em>
+</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-7.html#api-index-0.9.7">0.9.7</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-set-get-max"></a><h3>hb_set_get_max ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
 hb_set_get_max (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>);</pre>
@@ -690,15 +956,72 @@ hb_set_get_population (<em class="parameter"><code>const <a class="link" href="h
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-set-get-user-data"></a><h3>hb_set_get_user_data ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span> *
-hb_set_get_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
-                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>);</pre>
-<p>Fetches the user data associated with the specified key,
-attached to the specified set.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<a name="hb-set-is-empty"></a><h3>hb_set_is_empty ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_set_is_empty (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>);</pre>
+<p>Tests whether a set is empty (contains no elements).</p>
 <div class="refsect3">
-<a name="hb-set-get-user-data.parameters"></a><h4>Parameters</h4>
+<a name="hb-set-is-empty.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>set</p></td>
+<td class="parameter_description"><p>a set.</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-set-is-empty.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if <em class="parameter"><code>set</code></em>
+is empty</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-7.html#api-index-0.9.7">0.9.7</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-set-hash"></a><h3>hb_set_hash ()</h3>
+<pre class="programlisting">unsigned <span class="returnvalue">int</span>
+hb_set_hash (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>);</pre>
+<p>Creates a hash representing <em class="parameter"><code>set</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-set-hash.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>set</p></td>
+<td class="parameter_description"><p>A set</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-set-hash.returns"></a><h4>Returns</h4>
+<p>A hash of <em class="parameter"><code>set</code></em>
+.</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-4-0.html#api-index-4.4.0">4.4.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-set-subtract"></a><h3>hb_set_subtract ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_set_subtract (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
+                 <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *other</code></em>);</pre>
+<p>Subtracts the contents of <em class="parameter"><code>other</code></em>
+ from <em class="parameter"><code>set</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-set-subtract.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -712,31 +1035,27 @@ attached to the specified set.</p>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>key</p></td>
-<td class="parameter_description"><p>The user-data key to query</p></td>
+<td class="parameter_name"><p>other</p></td>
+<td class="parameter_description"><p>Another set</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-set-get-user-data.returns"></a><h4>Returns</h4>
-<p>A pointer to the user data. </p>
-<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
-</div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-set-has"></a><h3>hb_set_has ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_set_has (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
-            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> codepoint</code></em>);</pre>
-<p>Tests whether <em class="parameter"><code>codepoint</code></em>
- belongs to <em class="parameter"><code>set</code></em>
+<a name="hb-set-intersect"></a><h3>hb_set_intersect ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_set_intersect (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
+                  <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *other</code></em>);</pre>
+<p>Makes <em class="parameter"><code>set</code></em>
+ the intersection of <em class="parameter"><code>set</code></em>
+ and <em class="parameter"><code>other</code></em>
 .</p>
 <div class="refsect3">
-<a name="hb-set-has.parameters"></a><h4>Parameters</h4>
+<a name="hb-set-intersect.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -750,33 +1069,62 @@ hb_set_has (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>codepoint</p></td>
-<td class="parameter_description"><p>The element to query</p></td>
+<td class="parameter_name"><p>other</p></td>
+<td class="parameter_description"><p>Another set</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-set-union"></a><h3>hb_set_union ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_set_union (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
+              <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *other</code></em>);</pre>
+<p>Makes <em class="parameter"><code>set</code></em>
+ the union of <em class="parameter"><code>set</code></em>
+ and <em class="parameter"><code>other</code></em>
+.</p>
 <div class="refsect3">
-<a name="hb-set-has.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if <em class="parameter"><code>codepoint</code></em>
-is in <em class="parameter"><code>set</code></em>
-, <code class="literal">false</code> otherwise</p>
+<a name="hb-set-union.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>set</p></td>
+<td class="parameter_description"><p>A set</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>other</p></td>
+<td class="parameter_description"><p>Another set</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-set-intersect"></a><h3>hb_set_intersect ()</h3>
+<a name="hb-set-symmetric-difference"></a><h3>hb_set_symmetric_difference ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_set_intersect (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
-                  <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *other</code></em>);</pre>
+hb_set_symmetric_difference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
+                             <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *other</code></em>);</pre>
 <p>Makes <em class="parameter"><code>set</code></em>
- the intersection of <em class="parameter"><code>set</code></em>
- and <em class="parameter"><code>other</code></em>
+ the symmetric difference of <em class="parameter"><code>set</code></em>
+
+and <em class="parameter"><code>other</code></em>
 .</p>
 <div class="refsect3">
-<a name="hb-set-intersect.parameters"></a><h4>Parameters</h4>
+<a name="hb-set-symmetric-difference.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -825,12 +1173,12 @@ hb_set_invert (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-set-is-empty"></a><h3>hb_set_is_empty ()</h3>
+<a name="hb-set-is-inverted"></a><h3>hb_set_is_inverted ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_set_is_empty (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>);</pre>
-<p>Tests whether a set is empty (contains no elements).</p>
+hb_set_is_inverted (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>);</pre>
+<p>Returns whether the set is inverted.</p>
 <div class="refsect3">
-<a name="hb-set-is-empty.parameters"></a><h4>Parameters</h4>
+<a name="hb-set-is-inverted.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -839,17 +1187,16 @@ hb_set_is_empty (<em class="parameter"><code>const <a class="link" href="harfbuz
 </colgroup>
 <tbody><tr>
 <td class="parameter_name"><p>set</p></td>
-<td class="parameter_description"><p>a set.</p></td>
+<td class="parameter_description"><p>A set</p></td>
 <td class="parameter_annotations"> </td>
 </tr></tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-set-is-empty.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if <em class="parameter"><code>set</code></em>
-is empty</p>
+<a name="hb-set-is-inverted.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if the set is inverted, <code class="literal">false</code> otherwise</p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-7.html#api-index-0.9.7">0.9.7</a></p>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
@@ -1017,6 +1364,60 @@ Output = The last code point in the range. </p></td>
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-set-next-many"></a><h3>hb_set_next_many ()</h3>
+<pre class="programlisting">unsigned <span class="returnvalue">int</span>
+hb_set_next_many (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
+                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> codepoint</code></em>,
+                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *out</code></em>,
+                  <em class="parameter"><code>unsigned <span class="type">int</span> size</code></em>);</pre>
+<p>Finds the next element in <em class="parameter"><code>set</code></em>
+ that is greater than <em class="parameter"><code>codepoint</code></em>
+. Writes out
+codepoints to <em class="parameter"><code>out</code></em>
+, until either the set runs out of elements, or <em class="parameter"><code>size</code></em>
+
+codepoints are written, whichever comes first.</p>
+<div class="refsect3">
+<a name="hb-set-next-many.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>set</p></td>
+<td class="parameter_description"><p>A set</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>codepoint</p></td>
+<td class="parameter_description"><p>Outputting codepoints starting after this one.
+Use <a class="link" href="harfbuzz-hb-set.html#HB-SET-VALUE-INVALID:CAPS" title="HB_SET_VALUE_INVALID"><span class="type">HB_SET_VALUE_INVALID</span></a> to get started.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>out</p></td>
+<td class="parameter_description"><p>An array of codepoints to write to. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=size]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>size</p></td>
+<td class="parameter_description"><p>The maximum number of codepoints to write out.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-set-next-many.returns"></a><h4>Returns</h4>
+<p> the number of values written.</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-2-0.html#api-index-4.2.0">4.2.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-set-previous"></a><h3>hb_set_previous ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 hb_set_previous (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
@@ -1102,231 +1503,12 @@ Output = The first code point in the range. </p></td>
 </div>
 <p class="since">Since: <a class="link" href="api-index-1-8-0.html#api-index-1.8.0">1.8.0</a></p>
 </div>
-<hr>
-<div class="refsect2">
-<a name="hb-set-reference"></a><h3>hb_set_reference ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="returnvalue">hb_set_t</span></a> *
-hb_set_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>);</pre>
-<p>Increases the reference count on a set.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
-<div class="refsect3">
-<a name="hb-set-reference.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody><tr>
-<td class="parameter_name"><p>set</p></td>
-<td class="parameter_description"><p>A set</p></td>
-<td class="parameter_annotations"> </td>
-</tr></tbody>
-</table></div>
-</div>
-<div class="refsect3">
-<a name="hb-set-reference.returns"></a><h4>Returns</h4>
-<p>The set. </p>
-<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-set-set"></a><h3>hb_set_set ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_set_set (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
-            <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *other</code></em>);</pre>
-<p>Makes the contents of <em class="parameter"><code>set</code></em>
- equal to the contents of <em class="parameter"><code>other</code></em>
-.</p>
-<div class="refsect3">
-<a name="hb-set-set.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>set</p></td>
-<td class="parameter_description"><p>A set</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>other</p></td>
-<td class="parameter_description"><p>Another set</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-</tbody>
-</table></div>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-set-set-user-data"></a><h3>hb_set_set_user_data ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_set_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
-                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
-                      <em class="parameter"><code><span class="type">void</span> *data</code></em>,
-                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
-                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
-<p>Attaches a user-data key/data pair to the specified set.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
-<div class="refsect3">
-<a name="hb-set-set-user-data.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>set</p></td>
-<td class="parameter_description"><p>A set</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>key</p></td>
-<td class="parameter_description"><p>The user-data key to set</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>data</p></td>
-<td class="parameter_description"><p>A pointer to the user data to set</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>replace</p></td>
-<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-</tbody>
-</table></div>
-</div>
-<div class="refsect3">
-<a name="hb-set-set-user-data.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-set-subtract"></a><h3>hb_set_subtract ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_set_subtract (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
-                 <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *other</code></em>);</pre>
-<p>Subtracts the contents of <em class="parameter"><code>other</code></em>
- from <em class="parameter"><code>set</code></em>
-.</p>
-<div class="refsect3">
-<a name="hb-set-subtract.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>set</p></td>
-<td class="parameter_description"><p>A set</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>other</p></td>
-<td class="parameter_description"><p>Another set</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-</tbody>
-</table></div>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-set-symmetric-difference"></a><h3>hb_set_symmetric_difference ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_set_symmetric_difference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
-                             <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *other</code></em>);</pre>
-<p>Makes <em class="parameter"><code>set</code></em>
- the symmetric difference of <em class="parameter"><code>set</code></em>
-
-and <em class="parameter"><code>other</code></em>
-.</p>
-<div class="refsect3">
-<a name="hb-set-symmetric-difference.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>set</p></td>
-<td class="parameter_description"><p>A set</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>other</p></td>
-<td class="parameter_description"><p>Another set</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-</tbody>
-</table></div>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-set-union"></a><h3>hb_set_union ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_set_union (<em class="parameter"><code><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *set</code></em>,
-              <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> *other</code></em>);</pre>
-<p>Makes <em class="parameter"><code>set</code></em>
- the union of <em class="parameter"><code>set</code></em>
- and <em class="parameter"><code>other</code></em>
-.</p>
-<div class="refsect3">
-<a name="hb-set-union.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>set</p></td>
-<td class="parameter_description"><p>A set</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>other</p></td>
-<td class="parameter_description"><p>Another set</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-</tbody>
-</table></div>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
 </div>
 <div class="refsect1">
 <a name="harfbuzz-hb-set.other_details"></a><h2>Types and Values</h2>
 <div class="refsect2">
 <a name="HB-SET-VALUE-INVALID:CAPS"></a><h3>HB_SET_VALUE_INVALID</h3>
-<pre class="programlisting">#define HB_SET_VALUE_INVALID ((hb_codepoint_t) -1)
+<pre class="programlisting">#define HB_SET_VALUE_INVALID HB_CODEPOINT_INVALID
 </pre>
 <p>Unset <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="type">hb_set_t</span></a> value.</p>
 <p class="since">Since: <a class="link" href="api-index-0-9-21.html#api-index-0.9.21">0.9.21</a></p>
index 92f316c..11dda01 100644 (file)
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-t" title="hb_shape_plan_t"><span class="returnvalue">hb_shape_plan_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-destroy" title="hb_shape_plan_destroy ()">hb_shape_plan_destroy</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-get-empty" title="hb_shape_plan_get_empty ()">hb_shape_plan_get_empty</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-t" title="hb_shape_plan_t"><span class="returnvalue">hb_shape_plan_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-execute" title="hb_shape_plan_execute ()">hb_shape_plan_execute</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-reference" title="hb_shape_plan_reference ()">hb_shape_plan_reference</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-t" title="hb_shape_plan_t"><span class="returnvalue">hb_shape_plan_t</span></a> *
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-get-empty" title="hb_shape_plan_get_empty ()">hb_shape_plan_get_empty</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-destroy" title="hb_shape_plan_destroy ()">hb_shape_plan_destroy</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">const <span class="returnvalue">char</span> *
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-get-shaper" title="hb_shape_plan_get_shaper ()">hb_shape_plan_get_shaper</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-set-user-data" title="hb_shape_plan_set_user_data ()">hb_shape_plan_set_user_data</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-t" title="hb_shape_plan_t"><span class="returnvalue">hb_shape_plan_t</span></a> *
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-reference" title="hb_shape_plan_reference ()">hb_shape_plan_reference</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-execute" title="hb_shape_plan_execute ()">hb_shape_plan_execute</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
-<td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<td class="function_type">const <span class="returnvalue">char</span> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-set-user-data" title="hb_shape_plan_set_user_data ()">hb_shape_plan_set_user_data</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-get-shaper" title="hb_shape_plan_get_shaper ()">hb_shape_plan_get_shaper</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 </tbody>
@@ -175,7 +175,6 @@ hb_shape_plan_create (<em class="parameter"><code><a class="link" href="harfbuzz
 ,
 and <em class="parameter"><code>shaper_list</code></em>
 .</p>
-<p><span class="annotation">[Xconstructor]</span></p>
 <div class="refsect3">
 <a name="hb-shape-plan-create.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
@@ -298,7 +297,6 @@ Constructs a shaping plan for a combination of <em class="parameter"><code>face<
 and <em class="parameter"><code>shaper_list</code></em>
 , plus the variation-space coordinates <em class="parameter"><code>coords</code></em>
 .</p>
-<p><span class="annotation">[Xconstructor]</span></p>
 <div class="refsect3">
 <a name="hb-shape-plan-create2.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
@@ -429,6 +427,49 @@ variation-space coordinates <em class="parameter"><code>coords</code></em>
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-shape-plan-get-empty"></a><h3>hb_shape_plan_get_empty ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-t" title="hb_shape_plan_t"><span class="returnvalue">hb_shape_plan_t</span></a> *
+hb_shape_plan_get_empty (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
+<p>Fetches the singleton empty shaping plan.</p>
+<div class="refsect3">
+<a name="hb-shape-plan-get-empty.returns"></a><h4>Returns</h4>
+<p>The empty shaping plan. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-7.html#api-index-0.9.7">0.9.7</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-shape-plan-reference"></a><h3>hb_shape_plan_reference ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-t" title="hb_shape_plan_t"><span class="returnvalue">hb_shape_plan_t</span></a> *
+hb_shape_plan_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-t" title="hb_shape_plan_t"><span class="type">hb_shape_plan_t</span></a> *shape_plan</code></em>);</pre>
+<p>Increases the reference count on the given shaping plan.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-shape-plan-reference.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>shape_plan</p></td>
+<td class="parameter_description"><p>A shaping plan</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-shape-plan-reference.returns"></a><h4>Returns</h4>
+<p><em class="parameter"><code>shape_plan</code></em>
+. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-7.html#api-index-0.9.7">0.9.7</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-shape-plan-destroy"></a><h3>hb_shape_plan_destroy ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
 hb_shape_plan_destroy (<em class="parameter"><code><a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-t" title="hb_shape_plan_t"><span class="type">hb_shape_plan_t</span></a> *shape_plan</code></em>);</pre>
@@ -455,19 +496,17 @@ freeing all memory.</p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-shape-plan-execute"></a><h3>hb_shape_plan_execute ()</h3>
+<a name="hb-shape-plan-set-user-data"></a><h3>hb_shape_plan_set_user_data ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_shape_plan_execute (<em class="parameter"><code><a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-t" title="hb_shape_plan_t"><span class="type">hb_shape_plan_t</span></a> *shape_plan</code></em>,
-                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
-                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>,
-                       <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-feature-t" title="hb_feature_t"><span class="type">hb_feature_t</span></a> *features</code></em>,
-                       <em class="parameter"><code>unsigned <span class="type">int</span> num_features</code></em>);</pre>
-<p>Executes the given shaping plan on the specified buffer, using
-the given <em class="parameter"><code>font</code></em>
- and <em class="parameter"><code>features</code></em>
-.</p>
+hb_shape_plan_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-t" title="hb_shape_plan_t"><span class="type">hb_shape_plan_t</span></a> *shape_plan</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
+                             <em class="parameter"><code><span class="type">void</span> *data</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
+<p>Attaches a user-data key/data pair to the given shaping plan.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
-<a name="hb-shape-plan-execute.parameters"></a><h4>Parameters</h4>
+<a name="hb-shape-plan-set-user-data.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -481,80 +520,40 @@ the given <em class="parameter"><code>font</code></em>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>font</p></td>
-<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to use</p></td>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The user-data key to set</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>buffer</p></td>
-<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> to work upon</p></td>
+<td class="parameter_name"><p>data</p></td>
+<td class="parameter_description"><p>A pointer to the user data</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>features</p></td>
-<td class="parameter_description"><p>Features to enable. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=num_features]</span></td>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
 </tr>
 <tr>
-<td class="parameter_name"><p>num_features</p></td>
-<td class="parameter_description"><p>The number of features to enable</p></td>
+<td class="parameter_name"><p>replace</p></td>
+<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-shape-plan-execute.returns"></a><h4>Returns</h4>
+<a name="hb-shape-plan-set-user-data.returns"></a><h4>Returns</h4>
 <p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise.</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-7.html#api-index-0.9.7">0.9.7</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-shape-plan-get-empty"></a><h3>hb_shape_plan_get_empty ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-t" title="hb_shape_plan_t"><span class="returnvalue">hb_shape_plan_t</span></a> *
-hb_shape_plan_get_empty (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
-<p>Fetches the singleton empty shaping plan.</p>
-<div class="refsect3">
-<a name="hb-shape-plan-get-empty.returns"></a><h4>Returns</h4>
-<p>The empty shaping plan. </p>
-<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-7.html#api-index-0.9.7">0.9.7</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-shape-plan-get-shaper"></a><h3>hb_shape_plan_get_shaper ()</h3>
-<pre class="programlisting">const <span class="returnvalue">char</span> *
-hb_shape_plan_get_shaper (<em class="parameter"><code><a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-t" title="hb_shape_plan_t"><span class="type">hb_shape_plan_t</span></a> *shape_plan</code></em>);</pre>
-<p>Fetches the shaper from a given shaping plan.</p>
-<div class="refsect3">
-<a name="hb-shape-plan-get-shaper.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody><tr>
-<td class="parameter_name"><p>shape_plan</p></td>
-<td class="parameter_description"><p>A shaping plan</p></td>
-<td class="parameter_annotations"> </td>
-</tr></tbody>
-</table></div>
-</div>
-<div class="refsect3">
-<a name="hb-shape-plan-get-shaper.returns"></a><h4>Returns</h4>
-<p>The shaper. </p>
-<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-7.html#api-index-0.9.7">0.9.7</a></p>
-</div>
-<hr>
-<div class="refsect2">
 <a name="hb-shape-plan-get-user-data"></a><h3>hb_shape_plan_get_user_data ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span> *
-hb_shape_plan_get_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-t" title="hb_shape_plan_t"><span class="type">hb_shape_plan_t</span></a> *shape_plan</code></em>,
+hb_shape_plan_get_user_data (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-t" title="hb_shape_plan_t"><span class="type">hb_shape_plan_t</span></a> *shape_plan</code></em>,
                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>);</pre>
 <p>Fetches the user data associated with the specified key, 
 attached to the specified shaping plan.</p>
@@ -590,86 +589,85 @@ attached to the specified shaping plan.</p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-shape-plan-reference"></a><h3>hb_shape_plan_reference ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-t" title="hb_shape_plan_t"><span class="returnvalue">hb_shape_plan_t</span></a> *
-hb_shape_plan_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-t" title="hb_shape_plan_t"><span class="type">hb_shape_plan_t</span></a> *shape_plan</code></em>);</pre>
-<p>Increases the reference count on the given shaping plan.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<a name="hb-shape-plan-execute"></a><h3>hb_shape_plan_execute ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_shape_plan_execute (<em class="parameter"><code><a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-t" title="hb_shape_plan_t"><span class="type">hb_shape_plan_t</span></a> *shape_plan</code></em>,
+                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>,
+                       <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-feature-t" title="hb_feature_t"><span class="type">hb_feature_t</span></a> *features</code></em>,
+                       <em class="parameter"><code>unsigned <span class="type">int</span> num_features</code></em>);</pre>
+<p>Executes the given shaping plan on the specified buffer, using
+the given <em class="parameter"><code>font</code></em>
+ and <em class="parameter"><code>features</code></em>
+.</p>
 <div class="refsect3">
-<a name="hb-shape-plan-reference.parameters"></a><h4>Parameters</h4>
+<a name="hb-shape-plan-execute.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody><tr>
+<tbody>
+<tr>
 <td class="parameter_name"><p>shape_plan</p></td>
 <td class="parameter_description"><p>A shaping plan</p></td>
 <td class="parameter_annotations"> </td>
-</tr></tbody>
+</tr>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to use</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>buffer</p></td>
+<td class="parameter_description"><p>The <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> to work upon</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>features</p></td>
+<td class="parameter_description"><p>Features to enable. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=num_features]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>num_features</p></td>
+<td class="parameter_description"><p>The number of features to enable</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-shape-plan-reference.returns"></a><h4>Returns</h4>
-<p><em class="parameter"><code>shape_plan</code></em>
-. </p>
-<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+<a name="hb-shape-plan-execute.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise.</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-7.html#api-index-0.9.7">0.9.7</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-shape-plan-set-user-data"></a><h3>hb_shape_plan_set_user_data ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_shape_plan_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-t" title="hb_shape_plan_t"><span class="type">hb_shape_plan_t</span></a> *shape_plan</code></em>,
-                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
-                             <em class="parameter"><code><span class="type">void</span> *data</code></em>,
-                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
-                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
-<p>Attaches a user-data key/data pair to the given shaping plan.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<a name="hb-shape-plan-get-shaper"></a><h3>hb_shape_plan_get_shaper ()</h3>
+<pre class="programlisting">const <span class="returnvalue">char</span> *
+hb_shape_plan_get_shaper (<em class="parameter"><code><a class="link" href="harfbuzz-hb-shape-plan.html#hb-shape-plan-t" title="hb_shape_plan_t"><span class="type">hb_shape_plan_t</span></a> *shape_plan</code></em>);</pre>
+<p>Fetches the shaper from a given shaping plan.</p>
 <div class="refsect3">
-<a name="hb-shape-plan-set-user-data.parameters"></a><h4>Parameters</h4>
+<a name="hb-shape-plan-get-shaper.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody>
-<tr>
+<tbody><tr>
 <td class="parameter_name"><p>shape_plan</p></td>
 <td class="parameter_description"><p>A shaping plan</p></td>
 <td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>key</p></td>
-<td class="parameter_description"><p>The user-data key to set</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>data</p></td>
-<td class="parameter_description"><p>A pointer to the user data</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>replace</p></td>
-<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-</tbody>
+</tr></tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-shape-plan-set-user-data.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise.</p>
+<a name="hb-shape-plan-get-shaper.returns"></a><h4>Returns</h4>
+<p>The shaper. </p>
+<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-7.html#api-index-0.9.7">0.9.7</a></p>
 </div>
index 5ea14ea..2a5ab45 100644 (file)
 </td>
 </tr>
 <tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-shape.html#hb-shape-justify" title="hb_shape_justify ()">hb_shape_justify</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
 <td class="function_type">const <span class="returnvalue">char</span> **
 </td>
 <td class="function_name">
@@ -192,6 +200,100 @@ array of shapers to use or <code class="literal">NULL</code>. </p></td>
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-shape-justify"></a><h3>hb_shape_justify ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_shape_justify (<em class="parameter"><code><a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> *font</code></em>,
+                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> *buffer</code></em>,
+                  <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-common.html#hb-feature-t" title="hb_feature_t"><span class="type">hb_feature_t</span></a> *features</code></em>,
+                  <em class="parameter"><code>unsigned <span class="type">int</span> num_features</code></em>,
+                  <em class="parameter"><code>const <span class="type">char</span> * const *shaper_list</code></em>,
+                  <em class="parameter"><code><span class="type">float</span> min_target_advance</code></em>,
+                  <em class="parameter"><code><span class="type">float</span> max_target_advance</code></em>,
+                  <em class="parameter"><code><span class="type">float</span> *advance</code></em>,
+                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> *var_tag</code></em>,
+                  <em class="parameter"><code><span class="type">float</span> *var_value</code></em>);</pre>
+<p>See <a class="link" href="harfbuzz-hb-shape.html#hb-shape-full" title="hb_shape_full ()"><code class="function">hb_shape_full()</code></a> for basic details. If <em class="parameter"><code>shaper_list</code></em>
+ is not <code class="literal">NULL</code>, the specified
+shapers will be used in the given order, otherwise the default shapers list
+will be used.</p>
+<p>In addition, justify the shaping results such that the shaping results reach
+the target advance width/height, depending on the buffer direction.</p>
+<p>If the advance of the buffer shaped with <a class="link" href="harfbuzz-hb-shape.html#hb-shape-full" title="hb_shape_full ()"><code class="function">hb_shape_full()</code></a> is already known,
+put that in *advance. Otherwise set *advance to zero.</p>
+<p>This API is currently experimental and will probably change in the future.</p>
+<div class="refsect3">
+<a name="hb-shape-justify.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>font</p></td>
+<td class="parameter_description"><p>a mutable <a class="link" href="harfbuzz-hb-font.html#hb-font-t" title="hb_font_t"><span class="type">hb_font_t</span></a> to use for shaping</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>buffer</p></td>
+<td class="parameter_description"><p>an <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a> to shape</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>features</p></td>
+<td class="parameter_description"><p>an array of user
+specified <a class="link" href="harfbuzz-hb-common.html#hb-feature-t" title="hb_feature_t"><span class="type">hb_feature_t</span></a> or <code class="literal">NULL</code>. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> length=num_features][<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>num_features</p></td>
+<td class="parameter_description"><p>the length of <em class="parameter"><code>features</code></em>
+array</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>shaper_list</p></td>
+<td class="parameter_description"><p>a <code class="literal">NULL</code>-terminated
+array of shapers to use or <code class="literal">NULL</code>. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter points to an array of items."><span class="acronym">array</span></acronym> zero-terminated=1][<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>min_target_advance</p></td>
+<td class="parameter_description"><p>Minimum advance width/height to aim for.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>max_target_advance</p></td>
+<td class="parameter_description"><p>Maximum advance width/height to aim for.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>advance</p></td>
+<td class="parameter_description"><p>Input/output advance width/height of the buffer. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for input and for returning results. Default is transfer full."><span class="acronym">inout</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>var_tag</p></td>
+<td class="parameter_description"><p>Variation-axis tag used for justification. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>var_value</p></td>
+<td class="parameter_description"><p>Variation-axis value used to reach target justification. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-shape-justify.returns"></a><h4>Returns</h4>
+<p> false if all shapers failed, true otherwise</p>
+<p>XSince: EXPERIMENTAL</p>
+</div>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-shape-list-shapers"></a><h3>hb_shape_list_shapers ()</h3>
 <pre class="programlisting">const <span class="returnvalue">char</span> **
 hb_shape_list_shapers (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
index fa33cdd..cefa911 100644 (file)
@@ -146,7 +146,8 @@ Non-zero. Values can be interpreted as text size, in points.</p>
 <p>Used to vary between upright and slanted text. Values
 must be greater than -90 and less than +90. Values can be interpreted as
 the angle, in counter-clockwise degrees, of oblique slant from whatever the
-designer considers to be upright for that font design.</p>
+designer considers to be upright for that font design. Typical right-leaning
+Italic fonts have a negative slant angle (typically around -12)</p>
 </td>
 <td class="enum_member_annotations"> </td>
 </tr>
@@ -154,7 +155,8 @@ designer considers to be upright for that font design.</p>
 <td class="enum_member_name"><p><a name="HB-STYLE-TAG-SLANT-RATIO:CAPS"></a>HB_STYLE_TAG_SLANT_RATIO</p></td>
 <td class="enum_member_description">
 <p>same as <em class="parameter"><code>HB_STYLE_TAG_SLANT_ANGLE</code></em>
- expression as ratio.</p>
+ expression as ratio.
+Typical right-leaning Italic fonts have a positive slant ratio (typically around 0.2)</p>
 </td>
 <td class="enum_member_annotations"> </td>
 </tr>
index d8c0a4c..981957b 100644 (file)
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-subset.html#hb-subset-flags-t" title="enum hb_subset_flags_t"><span class="returnvalue">hb_subset_flags_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-get-flags" title="hb_subset_input_get_flags ()">hb_subset_input_get_flags</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-keep-everything" title="hb_subset_input_keep_everything ()">hb_subset_input_keep_everything</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 </tr>
 <tr>
 <td class="function_type">
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-flags-t" title="enum hb_subset_flags_t"><span class="returnvalue">hb_subset_flags_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-get-flags" title="hb_subset_input_get_flags ()">hb_subset_input_get_flags</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
 <a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="returnvalue">hb_set_t</span></a> *
 </td>
 <td class="function_name">
 </tr>
 <tr>
 <td class="function_type">
+<a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-old-to-new-glyph-mapping" title="hb_subset_input_old_to_new_glyph_mapping ()">hb_subset_input_old_to_new_glyph_mapping</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-pin-axis-location" title="hb_subset_input_pin_axis_location ()">hb_subset_input_pin_axis_location</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-pin-axis-to-default" title="hb_subset_input_pin_axis_to_default ()">hb_subset_input_pin_axis_to_default</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
 <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
 </td>
 <td class="function_name">
 <a class="link" href="harfbuzz-hb-subset.html#hb-subset-or-fail" title="hb_subset_or_fail ()">hb_subset_or_fail</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-t" title="hb_subset_plan_t"><span class="returnvalue">hb_subset_plan_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-create-or-fail" title="hb_subset_plan_create_or_fail ()">hb_subset_plan_create_or_fail</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-t" title="hb_subset_plan_t"><span class="returnvalue">hb_subset_plan_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-reference" title="hb_subset_plan_reference ()">hb_subset_plan_reference</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-destroy" title="hb_subset_plan_destroy ()">hb_subset_plan_destroy</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-set-user-data" title="hb_subset_plan_set_user_data ()">hb_subset_plan_set_user_data</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<span class="returnvalue">void</span> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-get-user-data" title="hb_subset_plan_get_user_data ()">hb_subset_plan_get_user_data</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-execute-or-fail" title="hb_subset_plan_execute_or_fail ()">hb_subset_plan_execute_or_fail</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-unicode-to-old-glyph-mapping" title="hb_subset_plan_unicode_to_old_glyph_mapping ()">hb_subset_plan_unicode_to_old_glyph_mapping</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-new-to-old-glyph-mapping" title="hb_subset_plan_new_to_old_glyph_mapping ()">hb_subset_plan_new_to_old_glyph_mapping</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-old-to-new-glyph-mapping" title="hb_subset_plan_old_to_new_glyph_mapping ()">hb_subset_plan_old_to_new_glyph_mapping</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
+<tr>
+<td class="function_type">
+<a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
+</td>
+<td class="function_name">
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-preprocess" title="hb_subset_preprocess ()">hb_subset_preprocess</a> <span class="c_punctuation">()</span>
+</td>
+</tr>
 </tbody>
 </table></div>
 </div>
 <td class="datatype_keyword">enum</td>
 <td class="function_name"><a class="link" href="harfbuzz-hb-subset.html#hb-subset-sets-t" title="enum hb_subset_sets_t">hb_subset_sets_t</a></td>
 </tr>
+<tr>
+<td class="typedef_keyword">typedef</td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-t" title="hb_subset_plan_t">hb_subset_plan_t</a></td>
+</tr>
 </tbody>
 </table></div>
 </div>
@@ -338,12 +454,15 @@ attached to the specified subset input object.</p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-subset-input-get-flags"></a><h3>hb_subset_input_get_flags ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-subset.html#hb-subset-flags-t" title="enum hb_subset_flags_t"><span class="returnvalue">hb_subset_flags_t</span></a>
-hb_subset_input_get_flags (<em class="parameter"><code><a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-t" title="hb_subset_input_t"><span class="type">hb_subset_input_t</span></a> *input</code></em>);</pre>
-<p>Gets all of the subsetting flags in the input object.</p>
+<a name="hb-subset-input-keep-everything"></a><h3>hb_subset_input_keep_everything ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_subset_input_keep_everything (<em class="parameter"><code><a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-t" title="hb_subset_input_t"><span class="type">hb_subset_input_t</span></a> *input</code></em>);</pre>
+<p>Configure input object to keep everything in the font face.
+That is, all Unicodes, glyphs, names, layout items,
+glyph names, etc.</p>
+<p>The input can be tailored afterwards by the caller.</p>
 <div class="refsect3">
-<a name="hb-subset-input-get-flags.parameters"></a><h4>Parameters</h4>
+<a name="hb-subset-input-keep-everything.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -352,16 +471,12 @@ hb_subset_input_get_flags (<em class="parameter"><code><a class="link" href="har
 </colgroup>
 <tbody><tr>
 <td class="parameter_name"><p>input</p></td>
-<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-t" title="hb_subset_input_t"><span class="type">hb_subset_input_t</span></a> object.</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-t" title="hb_subset_input_t"><span class="type">hb_subset_input_t</span></a> object</p></td>
 <td class="parameter_annotations"> </td>
 </tr></tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-subset-input-get-flags.returns"></a><h4>Returns</h4>
-<p> the subsetting flags bit field.</p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-2-9-0.html#api-index-2.9.0">2.9.0</a></p>
+<p class="since">Since: <a class="link" href="api-index-7-0-0.html#api-index-7.0.0">7.0.0</a></p>
 </div>
 <hr>
 <div class="refsect2">
@@ -397,6 +512,33 @@ field.</p>
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-subset-input-get-flags"></a><h3>hb_subset_input_get_flags ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-subset.html#hb-subset-flags-t" title="enum hb_subset_flags_t"><span class="returnvalue">hb_subset_flags_t</span></a>
+hb_subset_input_get_flags (<em class="parameter"><code><a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-t" title="hb_subset_input_t"><span class="type">hb_subset_input_t</span></a> *input</code></em>);</pre>
+<p>Gets all of the subsetting flags in the input object.</p>
+<div class="refsect3">
+<a name="hb-subset-input-get-flags.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>input</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-t" title="hb_subset_input_t"><span class="type">hb_subset_input_t</span></a> object.</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-subset-input-get-flags.returns"></a><h4>Returns</h4>
+<p> the subsetting flags bit field.</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-2-9-0.html#api-index-2.9.0">2.9.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-subset-input-unicode-set"></a><h3>hb_subset_input_unicode_set ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-set.html#hb-set-t" title="hb_set_t"><span class="returnvalue">hb_set_t</span></a> *
 hb_subset_input_unicode_set (<em class="parameter"><code><a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-t" title="hb_subset_input_t"><span class="type">hb_subset_input_t</span></a> *input</code></em>);</pre>
@@ -492,6 +634,142 @@ hb_subset_input_set (<em class="parameter"><code><a class="link" href="harfbuzz-
 </div>
 <hr>
 <div class="refsect2">
+<a name="hb-subset-input-old-to-new-glyph-mapping"></a><h3>hb_subset_input_old_to_new_glyph_mapping ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
+hb_subset_input_old_to_new_glyph_mapping
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-t" title="hb_subset_input_t"><span class="type">hb_subset_input_t</span></a> *input</code></em>);</pre>
+<p>Returns a map which can be used to provide an explicit mapping from old to new glyph
+id's in the produced subset. The caller should populate the map as desired.
+If this map is left empty then glyph ids will be automatically mapped to new
+values by the subsetter. If populated, the mapping must be unique. That
+is no two original glyph ids can be mapped to the same new id.
+Additionally, if a mapping is provided then the retain gids option cannot
+be enabled.</p>
+<p>Any glyphs that are retained in the subset which are not specified
+in this mapping will be assigned glyph ids after the highest glyph
+id in the mapping.</p>
+<p>Note: this will accept and apply non-monotonic mappings, however this
+may result in unsorted Coverage tables. Such fonts may not work for all
+use cases (for example ots will reject unsorted coverage tables). So it's
+recommended, if possible, to supply a monotonic mapping.</p>
+<div class="refsect3">
+<a name="hb-subset-input-old-to-new-glyph-mapping.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>input</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-t" title="hb_subset_input_t"><span class="type">hb_subset_input_t</span></a> object.</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-subset-input-old-to-new-glyph-mapping.returns"></a><h4>Returns</h4>
+<p>pointer to the <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> of the custom glyphs ID map. </p>
+<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-7-3-0.html#api-index-7.3.0">7.3.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-subset-input-pin-axis-location"></a><h3>hb_subset_input_pin_axis_location ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_subset_input_pin_axis_location (<em class="parameter"><code><a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-t" title="hb_subset_input_t"><span class="type">hb_subset_input_t</span></a> *input</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> axis_tag</code></em>,
+                                   <em class="parameter"><code><span class="type">float</span> axis_value</code></em>);</pre>
+<p>Pin an axis to a fixed location in the given subset input object.</p>
+<p>All axes in a font must be pinned. Additionally, <code class="literal">CFF2</code> table, if present,
+will be de-subroutinized.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-subset-input-pin-axis-location.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>input</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-t" title="hb_subset_input_t"><span class="type">hb_subset_input_t</span></a> object.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>face</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> object.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>axis_tag</p></td>
+<td class="parameter_description"><p>Tag of the axis to be pinned</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>axis_value</p></td>
+<td class="parameter_description"><p>Location on the axis to be pinned at</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-subset-input-pin-axis-location.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-6-0-0.html#api-index-6.0.0">6.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-subset-input-pin-axis-to-default"></a><h3>hb_subset_input_pin_axis_to_default ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_subset_input_pin_axis_to_default (<em class="parameter"><code><a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-t" title="hb_subset_input_t"><span class="type">hb_subset_input_t</span></a> *input</code></em>,
+                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
+                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-tag-t" title="hb_tag_t"><span class="type">hb_tag_t</span></a> axis_tag</code></em>);</pre>
+<p>Pin an axis to its default location in the given subset input object.</p>
+<p>All axes in a font must be pinned. Additionally, <code class="literal">CFF2</code> table, if present,
+will be de-subroutinized.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-subset-input-pin-axis-to-default.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>input</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-t" title="hb_subset_input_t"><span class="type">hb_subset_input_t</span></a> object.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>face</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> object.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>axis_tag</p></td>
+<td class="parameter_description"><p>Tag of the axis to be pinned</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-subset-input-pin-axis-to-default.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-6-0-0.html#api-index-6.0.0">6.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="hb-subset-or-fail"></a><h3>hb_subset_or_fail ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
 hb_subset_or_fail (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *source</code></em>,
@@ -522,6 +800,351 @@ if the subset operation fails.</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-2-9-0.html#api-index-2.9.0">2.9.0</a></p>
 </div>
+<hr>
+<div class="refsect2">
+<a name="hb-subset-plan-create-or-fail"></a><h3>hb_subset_plan_create_or_fail ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-t" title="hb_subset_plan_t"><span class="returnvalue">hb_subset_plan_t</span></a> *
+hb_subset_plan_create_or_fail (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *face</code></em>,
+                               <em class="parameter"><code>const <a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-t" title="hb_subset_input_t"><span class="type">hb_subset_input_t</span></a> *input</code></em>);</pre>
+<p>Computes a plan for subsetting the supplied face according
+to a provided input. The plan describes
+which tables and glyphs should be retained.</p>
+<div class="refsect3">
+<a name="hb-subset-plan-create-or-fail.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>face</p></td>
+<td class="parameter_description"><p>font face to create the plan for.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>input</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-subset.html#hb-subset-input-t" title="hb_subset_input_t"><span class="type">hb_subset_input_t</span></a> input.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-subset-plan-create-or-fail.returns"></a><h4>Returns</h4>
+<p>New subset plan. Destroy with
+<a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-destroy" title="hb_subset_plan_destroy ()"><code class="function">hb_subset_plan_destroy()</code></a>. If there is a failure creating the plan
+nullptr will be returned. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-subset-plan-reference"></a><h3>hb_subset_plan_reference ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-t" title="hb_subset_plan_t"><span class="returnvalue">hb_subset_plan_t</span></a> *
+hb_subset_plan_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-t" title="hb_subset_plan_t"><span class="type">hb_subset_plan_t</span></a> *plan</code></em>);</pre>
+<p>Increases the reference count on <em class="parameter"><code>plan</code></em>
+.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-subset-plan-reference.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>plan</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-t" title="hb_subset_plan_t"><span class="type">hb_subset_plan_t</span></a> object.</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-subset-plan-reference.returns"></a><h4>Returns</h4>
+<p> <em class="parameter"><code>plan</code></em>
+.</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-subset-plan-destroy"></a><h3>hb_subset_plan_destroy ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_subset_plan_destroy (<em class="parameter"><code><a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-t" title="hb_subset_plan_t"><span class="type">hb_subset_plan_t</span></a> *plan</code></em>);</pre>
+<p>Decreases the reference count on <em class="parameter"><code>plan</code></em>
+, and if it reaches zero, destroys
+<em class="parameter"><code>plan</code></em>
+, freeing all memory.</p>
+<div class="refsect3">
+<a name="hb-subset-plan-destroy.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>plan</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-t" title="hb_subset_plan_t"><span class="type">hb_subset_plan_t</span></a></p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-subset-plan-set-user-data"></a><h3>hb_subset_plan_set_user_data ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_subset_plan_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-t" title="hb_subset_plan_t"><span class="type">hb_subset_plan_t</span></a> *plan</code></em>,
+                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
+                              <em class="parameter"><code><span class="type">void</span> *data</code></em>,
+                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
+                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
+<p>Attaches a user-data key/data pair to the given subset plan object.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-subset-plan-set-user-data.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>plan</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-t" title="hb_subset_plan_t"><span class="type">hb_subset_plan_t</span></a> object.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The user-data key to set</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>data</p></td>
+<td class="parameter_description"><p>A pointer to the user data</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>replace</p></td>
+<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-subset-plan-set-user-data.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-subset-plan-get-user-data"></a><h3>hb_subset_plan_get_user_data ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span> *
+hb_subset_plan_get_user_data (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-t" title="hb_subset_plan_t"><span class="type">hb_subset_plan_t</span></a> *plan</code></em>,
+                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>);</pre>
+<p>Fetches the user data associated with the specified key,
+attached to the specified subset plan object.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-subset-plan-get-user-data.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="parameter_name"><p>plan</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-t" title="hb_subset_plan_t"><span class="type">hb_subset_plan_t</span></a> object.</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The user-data key to query</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-subset-plan-get-user-data.returns"></a><h4>Returns</h4>
+<p>A pointer to the user data. </p>
+<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-subset-plan-execute-or-fail"></a><h3>hb_subset_plan_execute_or_fail ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
+hb_subset_plan_execute_or_fail (<em class="parameter"><code><a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-t" title="hb_subset_plan_t"><span class="type">hb_subset_plan_t</span></a> *plan</code></em>);</pre>
+<p>Executes the provided subsetting <em class="parameter"><code>plan</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-subset-plan-execute-or-fail.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>plan</p></td>
+<td class="parameter_description"><p>a subsetting plan.</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-subset-plan-execute-or-fail.returns"></a><h4>Returns</h4>
+<p>on success returns a reference to generated font subset. If the subsetting operation fails
+returns nullptr.</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-subset-plan-unicode-to-old-glyph-mapping"></a><h3>hb_subset_plan_unicode_to_old_glyph_mapping ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
+hb_subset_plan_unicode_to_old_glyph_mapping
+                               (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-t" title="hb_subset_plan_t"><span class="type">hb_subset_plan_t</span></a> *plan</code></em>);</pre>
+<p>Returns the mapping between codepoints in the original font and the
+associated glyph id in the original font.</p>
+<div class="refsect3">
+<a name="hb-subset-plan-unicode-to-old-glyph-mapping.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>plan</p></td>
+<td class="parameter_description"><p>a subsetting plan.</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-subset-plan-unicode-to-old-glyph-mapping.returns"></a><h4>Returns</h4>
+<p>A pointer to the <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> of the mapping. </p>
+<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-subset-plan-new-to-old-glyph-mapping"></a><h3>hb_subset_plan_new_to_old_glyph_mapping ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
+hb_subset_plan_new_to_old_glyph_mapping
+                               (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-t" title="hb_subset_plan_t"><span class="type">hb_subset_plan_t</span></a> *plan</code></em>);</pre>
+<p>Returns the mapping between glyphs in the subset that will be produced by
+<em class="parameter"><code>plan</code></em>
+ and the glyph in the original font.</p>
+<div class="refsect3">
+<a name="hb-subset-plan-new-to-old-glyph-mapping.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>plan</p></td>
+<td class="parameter_description"><p>a subsetting plan.</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-subset-plan-new-to-old-glyph-mapping.returns"></a><h4>Returns</h4>
+<p>A pointer to the <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> of the mapping. </p>
+<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-subset-plan-old-to-new-glyph-mapping"></a><h3>hb_subset_plan_old_to_new_glyph_mapping ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="returnvalue">hb_map_t</span></a> *
+hb_subset_plan_old_to_new_glyph_mapping
+                               (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-subset.html#hb-subset-plan-t" title="hb_subset_plan_t"><span class="type">hb_subset_plan_t</span></a> *plan</code></em>);</pre>
+<p>Returns the mapping between glyphs in the original font to glyphs in the
+subset that will be produced by <em class="parameter"><code>plan</code></em>
+</p>
+<div class="refsect3">
+<a name="hb-subset-plan-old-to-new-glyph-mapping.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>plan</p></td>
+<td class="parameter_description"><p>a subsetting plan.</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-subset-plan-old-to-new-glyph-mapping.returns"></a><h4>Returns</h4>
+<p>A pointer to the <a class="link" href="harfbuzz-hb-map.html#hb-map-t" title="hb_map_t"><span class="type">hb_map_t</span></a> of the mapping. </p>
+<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-4-0-0.html#api-index-4.0.0">4.0.0</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-subset-preprocess"></a><h3>hb_subset_preprocess ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="returnvalue">hb_face_t</span></a> *
+hb_subset_preprocess (<em class="parameter"><code><a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> *source</code></em>);</pre>
+<p>Preprocesses the face and attaches data that will be needed by the
+subsetter. Future subsetting operations can then use the precomputed data
+to speed up the subsetting operation.</p>
+<p>See <a class="ulink" href="https://github.com/harfbuzz/harfbuzz/blob/main/docs/subset-preprocessing.md" target="_top">subset-preprocessing</a>
+for more information.</p>
+<p>Note: the preprocessed face may contain sub-blobs that reference the memory
+backing the source <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a>. Therefore in the case that this memory is not
+owned by the source face you will need to ensure that memory lives
+as long as the returned <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a>.</p>
+<div class="refsect3">
+<a name="hb-subset-preprocess.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody><tr>
+<td class="parameter_name"><p>source</p></td>
+<td class="parameter_description"><p>a <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a> object.</p></td>
+<td class="parameter_annotations"> </td>
+</tr></tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-subset-preprocess.returns"></a><h4>Returns</h4>
+<p> a new <a class="link" href="harfbuzz-hb-face.html#hb-face-t" title="hb_face_t"><span class="type">hb_face_t</span></a>.</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-6-0-0.html#api-index-6.0.0">6.0.0</a></p>
+</div>
 </div>
 <div class="refsect1">
 <a name="harfbuzz-hb-subset.other_details"></a><h2>Types and Values</h2>
@@ -617,6 +1240,14 @@ OS/2 will not be recalculated.</p>
 </td>
 <td class="enum_member_annotations"> </td>
 </tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-SUBSET-FLAGS-NO-LAYOUT-CLOSURE:CAPS"></a>HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE</p></td>
+<td class="enum_member_description">
+<p>If set don't perform glyph closure on layout
+substitution rules (GSUB). Since: 7.2.0.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
 </tbody>
 </table></div>
 </div>
@@ -694,11 +1325,27 @@ in the subset.</p>
 </td>
 <td class="enum_member_annotations"> </td>
 </tr>
+<tr>
+<td class="enum_member_name"><p><a name="HB-SUBSET-SETS-LAYOUT-SCRIPT-TAG:CAPS"></a>HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG</p></td>
+<td class="enum_member_description">
+<p>the set of layout script tags that will be retained
+in the subset. Defaults to all tags. Since: 5.0.0</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
 </tbody>
 </table></div>
 </div>
 <p class="since">Since: <a class="link" href="api-index-2-9-1.html#api-index-2.9.1">2.9.1</a></p>
 </div>
+<hr>
+<div class="refsect2">
+<a name="hb-subset-plan-t"></a><h3>hb_subset_plan_t</h3>
+<pre class="programlisting">typedef struct hb_subset_plan_t hb_subset_plan_t;
+</pre>
+<p>Contains information about how the subset operation will be executed.
+Such as mappings from the old glyph ids to the new ones in the subset.</p>
+</div>
 </div>
 </div>
 <div class="footer">
index 35276f3..c4a11d5 100644 (file)
 <tbody>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-combining-class-t" title="enum hb_unicode_combining_class_t"><span class="returnvalue">hb_unicode_combining_class_t</span></a>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category-t" title="enum hb_unicode_general_category_t"><span class="returnvalue">hb_unicode_general_category_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-combining-class" title="hb_unicode_combining_class ()">hb_unicode_combining_class</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category" title="hb_unicode_general_category ()">hb_unicode_general_category</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-combining-class-t" title="enum hb_unicode_combining_class_t"><span class="returnvalue">hb_unicode_combining_class_t</span></a>
 </td>
 <td class="function_name">
-<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-combining-class-func-t" title="hb_unicode_combining_class_func_t ()">*hb_unicode_combining_class_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-combining-class" title="hb_unicode_combining_class ()">hb_unicode_combining_class</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-compose" title="hb_unicode_compose ()">hb_unicode_compose</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-mirroring" title="hb_unicode_mirroring ()">hb_unicode_mirroring</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="returnvalue">hb_script_t</span></a>
 </td>
 <td class="function_name">
-<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-compose-func-t" title="hb_unicode_compose_func_t ()">*hb_unicode_compose_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-script" title="hb_unicode_script ()">hb_unicode_script</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
@@ -76,7 +76,7 @@
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-decompose" title="hb_unicode_decompose ()">hb_unicode_decompose</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-compose" title="hb_unicode_compose ()">hb_unicode_compose</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
@@ -84,7 +84,7 @@
 <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-decompose-func-t" title="hb_unicode_decompose_func_t ()">*hb_unicode_decompose_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-decompose" title="hb_unicode_decompose ()">hb_unicode_decompose</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="returnvalue">hb_unicode_funcs_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-destroy" title="hb_unicode_funcs_destroy ()">hb_unicode_funcs_destroy</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-get-empty" title="hb_unicode_funcs_get_empty ()">hb_unicode_funcs_get_empty</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="returnvalue">hb_unicode_funcs_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-get-default" title="hb_unicode_funcs_get_default ()">hb_unicode_funcs_get_default</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-reference" title="hb_unicode_funcs_reference ()">hb_unicode_funcs_reference</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="returnvalue">hb_unicode_funcs_t</span></a> *
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-get-empty" title="hb_unicode_funcs_get_empty ()">hb_unicode_funcs_get_empty</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-destroy" title="hb_unicode_funcs_destroy ()">hb_unicode_funcs_destroy</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="returnvalue">hb_unicode_funcs_t</span></a> *
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-get-parent" title="hb_unicode_funcs_get_parent ()">hb_unicode_funcs_get_parent</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-user-data" title="hb_unicode_funcs_set_user_data ()">hb_unicode_funcs_set_user_data</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-is-immutable" title="hb_unicode_funcs_is_immutable ()">hb_unicode_funcs_is_immutable</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-make-immutable" title="hb_unicode_funcs_make_immutable ()">hb_unicode_funcs_make_immutable</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-make-immutable" title="hb_unicode_funcs_make_immutable ()">hb_unicode_funcs_make_immutable</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-is-immutable" title="hb_unicode_funcs_is_immutable ()">hb_unicode_funcs_is_immutable</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="returnvalue">hb_unicode_funcs_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-reference" title="hb_unicode_funcs_reference ()">hb_unicode_funcs_reference</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-get-default" title="hb_unicode_funcs_get_default ()">hb_unicode_funcs_get_default</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="returnvalue">hb_unicode_funcs_t</span></a> *
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-combining-class-func" title="hb_unicode_funcs_set_combining_class_func ()">hb_unicode_funcs_set_combining_class_func</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-get-parent" title="hb_unicode_funcs_get_parent ()">hb_unicode_funcs_get_parent</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category-t" title="enum hb_unicode_general_category_t"><span class="returnvalue">hb_unicode_general_category_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-compose-func" title="hb_unicode_funcs_set_compose_func ()">hb_unicode_funcs_set_compose_func</a> <span class="c_punctuation">()</span>
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category-func-t" title="hb_unicode_general_category_func_t ()">*hb_unicode_general_category_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-decompose-func" title="hb_unicode_funcs_set_decompose_func ()">hb_unicode_funcs_set_decompose_func</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-general-category-func" title="hb_unicode_funcs_set_general_category_func ()">hb_unicode_funcs_set_general_category_func</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-combining-class-t" title="enum hb_unicode_combining_class_t"><span class="returnvalue">hb_unicode_combining_class_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-general-category-func" title="hb_unicode_funcs_set_general_category_func ()">hb_unicode_funcs_set_general_category_func</a> <span class="c_punctuation">()</span>
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-combining-class-func-t" title="hb_unicode_combining_class_func_t ()">*hb_unicode_combining_class_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-mirroring-func" title="hb_unicode_funcs_set_mirroring_func ()">hb_unicode_funcs_set_mirroring_func</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-combining-class-func" title="hb_unicode_funcs_set_combining_class_func ()">hb_unicode_funcs_set_combining_class_func</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">void</span>
+<a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-script-func" title="hb_unicode_funcs_set_script_func ()">hb_unicode_funcs_set_script_func</a> <span class="c_punctuation">()</span>
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-mirroring-func-t" title="hb_unicode_mirroring_func_t ()">*hb_unicode_mirroring_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-user-data" title="hb_unicode_funcs_set_user_data ()">hb_unicode_funcs_set_user_data</a> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-mirroring-func" title="hb_unicode_funcs_set_mirroring_func ()">hb_unicode_funcs_set_mirroring_func</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category-t" title="enum hb_unicode_general_category_t"><span class="returnvalue">hb_unicode_general_category_t</span></a>
+<a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="returnvalue">hb_script_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category" title="hb_unicode_general_category ()">hb_unicode_general_category</a> <span class="c_punctuation">()</span>
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-script-func-t" title="hb_unicode_script_func_t ()">*hb_unicode_script_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category-t" title="enum hb_unicode_general_category_t"><span class="returnvalue">hb_unicode_general_category_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category-func-t" title="hb_unicode_general_category_func_t ()">*hb_unicode_general_category_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-script-func" title="hb_unicode_funcs_set_script_func ()">hb_unicode_funcs_set_script_func</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-mirroring" title="hb_unicode_mirroring ()">hb_unicode_mirroring</a> <span class="c_punctuation">()</span>
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-compose-func-t" title="hb_unicode_compose_func_t ()">*hb_unicode_compose_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-mirroring-func-t" title="hb_unicode_mirroring_func_t ()">*hb_unicode_mirroring_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-compose-func" title="hb_unicode_funcs_set_compose_func ()">hb_unicode_funcs_set_compose_func</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="returnvalue">hb_script_t</span></a>
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
 </td>
 <td class="function_name">
-<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-script" title="hb_unicode_script ()">hb_unicode_script</a> <span class="c_punctuation">()</span>
+<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-decompose-func-t" title="hb_unicode_decompose_func_t ()">*hb_unicode_decompose_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
 </td>
 </tr>
 <tr>
 <td class="function_type">
-<a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="returnvalue">hb_script_t</span></a>
+<span class="returnvalue">void</span>
 </td>
 <td class="function_name">
-<span class="c_punctuation">(</span><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-script-func-t" title="hb_unicode_script_func_t ()">*hb_unicode_script_func_t</a><span class="c_punctuation">)</span> <span class="c_punctuation">()</span>
+<a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-decompose-func" title="hb_unicode_funcs_set_decompose_func ()">hb_unicode_funcs_set_decompose_func</a> <span class="c_punctuation">()</span>
 </td>
 </tr>
 </tbody>
 <td class="function_name"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-combining-class-t" title="enum hb_unicode_combining_class_t">hb_unicode_combining_class_t</a></td>
 </tr>
 <tr>
-<td class="typedef_keyword">typedef</td>
-<td class="function_name"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t">hb_unicode_funcs_t</a></td>
-</tr>
-<tr>
 <td class="datatype_keyword">enum</td>
 <td class="function_name"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category-t" title="enum hb_unicode_general_category_t">hb_unicode_general_category_t</a></td>
 </tr>
+<tr>
+<td class="typedef_keyword">typedef</td>
+<td class="function_name"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t">hb_unicode_funcs_t</a></td>
+</tr>
 </tbody>
 </table></div>
 </div>
@@ -313,15 +313,15 @@ defined by the virtual methods in <a class="link" href="harfbuzz-hb-unicode.html
 <div class="refsect1">
 <a name="harfbuzz-hb-unicode.functions_details"></a><h2>Functions</h2>
 <div class="refsect2">
-<a name="hb-unicode-combining-class"></a><h3>hb_unicode_combining_class ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-combining-class-t" title="enum hb_unicode_combining_class_t"><span class="returnvalue">hb_unicode_combining_class_t</span></a>
-hb_unicode_combining_class (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
-                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>);</pre>
-<p>Retrieves the Canonical Combining Class (ccc) property
+<a name="hb-unicode-general-category"></a><h3>hb_unicode_general_category ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category-t" title="enum hb_unicode_general_category_t"><span class="returnvalue">hb_unicode_general_category_t</span></a>
+hb_unicode_general_category (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>);</pre>
+<p>Retrieves the General Category (gc) property
 of code point <em class="parameter"><code>unicode</code></em>
 .</p>
 <div class="refsect3">
-<a name="hb-unicode-combining-class.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-general-category.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -343,24 +343,23 @@ of code point <em class="parameter"><code>unicode</code></em>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-unicode-combining-class.returns"></a><h4>Returns</h4>
-<p> The <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-combining-class-t" title="enum hb_unicode_combining_class_t"><span class="type">hb_unicode_combining_class_t</span></a> of <em class="parameter"><code>unicode</code></em>
+<a name="hb-unicode-general-category.returns"></a><h4>Returns</h4>
+<p> The <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category-t" title="enum hb_unicode_general_category_t"><span class="type">hb_unicode_general_category_t</span></a> of <em class="parameter"><code>unicode</code></em>
 </p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-combining-class-func-t"></a><h3>hb_unicode_combining_class_func_t ()</h3>
+<a name="hb-unicode-combining-class"></a><h3>hb_unicode_combining_class ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-combining-class-t" title="enum hb_unicode_combining_class_t"><span class="returnvalue">hb_unicode_combining_class_t</span></a>
-<span class="c_punctuation">(</span>*hb_unicode_combining_class_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
-                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>,
-                                      <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
-<p>A virtual method for the <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> structure.</p>
-<p>This method should retrieve the Canonical Combining Class (ccc)
-property for a specified Unicode code point.</p>
+hb_unicode_combining_class (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
+                            <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>);</pre>
+<p>Retrieves the Canonical Combining Class (ccc) property
+of code point <em class="parameter"><code>unicode</code></em>
+.</p>
 <div class="refsect3">
-<a name="hb-unicode-combining-class-func-t.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-combining-class.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -370,7 +369,7 @@ property for a specified Unicode code point.</p>
 <tbody>
 <tr>
 <td class="parameter_name"><p>ufuncs</p></td>
-<td class="parameter_description"><p>A Unicode-functions structure</p></td>
+<td class="parameter_description"><p>The Unicode-functions structure</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
@@ -378,35 +377,27 @@ property for a specified Unicode code point.</p>
 <td class="parameter_description"><p>The code point to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
-<tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-unicode-combining-class-func-t.returns"></a><h4>Returns</h4>
+<a name="hb-unicode-combining-class.returns"></a><h4>Returns</h4>
 <p> The <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-combining-class-t" title="enum hb_unicode_combining_class_t"><span class="type">hb_unicode_combining_class_t</span></a> of <em class="parameter"><code>unicode</code></em>
 </p>
 </div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-compose"></a><h3>hb_unicode_compose ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_unicode_compose (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
-                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> a</code></em>,
-                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> b</code></em>,
-                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *ab</code></em>);</pre>
-<p>Fetches the composition of a sequence of two Unicode
-code points.</p>
-<p>Calls the composition function of the specified
-Unicode-functions structure <em class="parameter"><code>ufuncs</code></em>
+<a name="hb-unicode-mirroring"></a><h3>hb_unicode_mirroring ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
+hb_unicode_mirroring (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
+                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>);</pre>
+<p>Retrieves the Bi-directional Mirroring Glyph code
+point defined for code point <em class="parameter"><code>unicode</code></em>
 .</p>
 <div class="refsect3">
-<a name="hb-unicode-compose.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-mirroring.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -420,50 +411,73 @@ Unicode-functions structure <em class="parameter"><code>ufuncs</code></em>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>a</p></td>
-<td class="parameter_description"><p>The first Unicode code point to compose</p></td>
+<td class="parameter_name"><p>unicode</p></td>
+<td class="parameter_description"><p>The code point to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
+</tbody>
+</table></div>
+</div>
+<div class="refsect3">
+<a name="hb-unicode-mirroring.returns"></a><h4>Returns</h4>
+<p> The <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> of the Mirroring Glyph for <em class="parameter"><code>unicode</code></em>
+</p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-unicode-script"></a><h3>hb_unicode_script ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="returnvalue">hb_script_t</span></a>
+hb_unicode_script (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
+                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>);</pre>
+<p>Retrieves the <a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> script to which code
+point <em class="parameter"><code>unicode</code></em>
+ belongs.</p>
+<div class="refsect3">
+<a name="hb-unicode-script.parameters"></a><h4>Parameters</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="150px" class="parameters_name">
+<col class="parameters_description">
+<col width="200px" class="parameters_annotations">
+</colgroup>
+<tbody>
 <tr>
-<td class="parameter_name"><p>b</p></td>
-<td class="parameter_description"><p>The second Unicode code point to compose</p></td>
+<td class="parameter_name"><p>ufuncs</p></td>
+<td class="parameter_description"><p>The Unicode-functions structure</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>ab</p></td>
-<td class="parameter_description"><p>The composition of <em class="parameter"><code>a</code></em>
-, <em class="parameter"><code>b</code></em>
-. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+<td class="parameter_name"><p>unicode</p></td>
+<td class="parameter_description"><p>The code point to query</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-unicode-compose.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if <em class="parameter"><code>a</code></em>
-and <em class="parameter"><code>b</code></em>
-composed, <code class="literal">false</code> otherwise</p>
+<a name="hb-unicode-script.returns"></a><h4>Returns</h4>
+<p> The <a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> of <em class="parameter"><code>unicode</code></em>
+</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-compose-func-t"></a><h3>hb_unicode_compose_func_t ()</h3>
+<a name="hb-unicode-compose"></a><h3>hb_unicode_compose ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-<span class="c_punctuation">(</span>*hb_unicode_compose_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
-                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> a</code></em>,
-                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> b</code></em>,
-                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *ab</code></em>,
-                              <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
-<p>A virtual method for the <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> structure.</p>
-<p>This method should compose a sequence of two input Unicode code
-points by canonical equivalence, returning the composed code
-point in a <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> output parameter (if successful).
-The method must return an <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> indicating the success
-of the composition.</p>
+hb_unicode_compose (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
+                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> a</code></em>,
+                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> b</code></em>,
+                    <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *ab</code></em>);</pre>
+<p>Fetches the composition of a sequence of two Unicode
+code points.</p>
+<p>Calls the composition function of the specified
+Unicode-functions structure <em class="parameter"><code>ufuncs</code></em>
+.</p>
 <div class="refsect3">
-<a name="hb-unicode-compose-func-t.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-compose.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -473,38 +487,36 @@ of the composition.</p>
 <tbody>
 <tr>
 <td class="parameter_name"><p>ufuncs</p></td>
-<td class="parameter_description"><p>A Unicode-functions structure</p></td>
+<td class="parameter_description"><p>The Unicode-functions structure</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
 <td class="parameter_name"><p>a</p></td>
-<td class="parameter_description"><p>The first code point to compose</p></td>
+<td class="parameter_description"><p>The first Unicode code point to compose</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
 <td class="parameter_name"><p>b</p></td>
-<td class="parameter_description"><p>The second code point to compose</p></td>
+<td class="parameter_description"><p>The second Unicode code point to compose</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
 <td class="parameter_name"><p>ab</p></td>
-<td class="parameter_description"><p>The composed code point. </p></td>
+<td class="parameter_description"><p>The composition of <em class="parameter"><code>a</code></em>
+, <em class="parameter"><code>b</code></em>
+. </p></td>
 <td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
 </tr>
-<tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>user data pointer passed by the caller</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-unicode-compose-func-t.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> is <em class="parameter"><code>a</code></em>
-,<em class="parameter"><code>b</code></em>
+<a name="hb-unicode-compose.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if <em class="parameter"><code>a</code></em>
+and <em class="parameter"><code>b</code></em>
 composed, <code class="literal">false</code> otherwise</p>
 </div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
@@ -561,70 +573,54 @@ was decomposed, <code class="literal">false</code> otherwise</p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-decompose-func-t"></a><h3>hb_unicode_decompose_func_t ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-<span class="c_punctuation">(</span>*hb_unicode_decompose_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> ab</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *a</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *b</code></em>,
-                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
-<p>A virtual method for the <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> structure.</p>
-<p>This method should decompose an input Unicode code point,
-returning the two decomposed code points in <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a>
-output parameters (if successful). The method must return an
-<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> indicating the success of the composition.</p>
+<a name="hb-unicode-funcs-create"></a><h3>hb_unicode_funcs_create ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="returnvalue">hb_unicode_funcs_t</span></a> *
+hb_unicode_funcs_create (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *parent</code></em>);</pre>
+<p>Creates a new <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> structure of Unicode functions.</p>
 <div class="refsect3">
-<a name="hb-unicode-decompose-func-t.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-funcs-create.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>ufuncs</p></td>
-<td class="parameter_description"><p>A Unicode-functions structure</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>ab</p></td>
-<td class="parameter_description"><p>The code point to decompose</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>a</p></td>
-<td class="parameter_description"><p>The first decomposed code point. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>b</p></td>
-<td class="parameter_description"><p>The second decomposed code point. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>user data pointer passed by the caller</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-</tbody>
+<tbody><tr>
+<td class="parameter_name"><p>parent</p></td>
+<td class="parameter_description"><p>Parent Unicode-functions structure. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr></tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-unicode-decompose-func-t.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if <em class="parameter"><code>ab</code></em>
-decomposed, <code class="literal">false</code> otherwise</p>
+<a name="hb-unicode-funcs-create.returns"></a><h4>Returns</h4>
+<p>The Unicode-functions structure. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
 </div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-funcs-create"></a><h3>hb_unicode_funcs_create ()</h3>
+<a name="hb-unicode-funcs-get-empty"></a><h3>hb_unicode_funcs_get_empty ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="returnvalue">hb_unicode_funcs_t</span></a> *
-hb_unicode_funcs_create (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *parent</code></em>);</pre>
-<p>Creates a new <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> structure of Unicode functions.</p>
-<p><span class="annotation">[Xconstructor]</span></p>
+hb_unicode_funcs_get_empty (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
+<p>Fetches the singleton empty Unicode-functions structure.</p>
 <div class="refsect3">
-<a name="hb-unicode-funcs-create.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-funcs-get-empty.returns"></a><h4>Returns</h4>
+<p>The empty Unicode-functions structure. </p>
+<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-unicode-funcs-reference"></a><h3>hb_unicode_funcs_reference ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="returnvalue">hb_unicode_funcs_t</span></a> *
+hb_unicode_funcs_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>);</pre>
+<p>Increases the reference count on a Unicode-functions structure.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+<div class="refsect3">
+<a name="hb-unicode-funcs-reference.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -632,14 +628,14 @@ hb_unicode_funcs_create (<em class="parameter"><code><a class="link" href="harfb
 <col width="200px" class="parameters_annotations">
 </colgroup>
 <tbody><tr>
-<td class="parameter_name"><p>parent</p></td>
-<td class="parameter_description"><p>Parent Unicode-functions structure. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+<td class="parameter_name"><p>ufuncs</p></td>
+<td class="parameter_description"><p>The Unicode-functions structure</p></td>
+<td class="parameter_annotations"> </td>
 </tr></tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-unicode-funcs-create.returns"></a><h4>Returns</h4>
+<a name="hb-unicode-funcs-reference.returns"></a><h4>Returns</h4>
 <p>The Unicode-functions structure. </p>
 <p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
 </div>
@@ -673,57 +669,56 @@ destroyed, freeing all memory.</p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-funcs-get-default"></a><h3>hb_unicode_funcs_get_default ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="returnvalue">hb_unicode_funcs_t</span></a> *
-hb_unicode_funcs_get_default (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
-<p>Fetches a pointer to the default Unicode-functions structure that is used
-when no functions are explicitly set on <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a>.</p>
-<div class="refsect3">
-<a name="hb-unicode-funcs-get-default.returns"></a><h4>Returns</h4>
-<p>a pointer to the <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> Unicode-functions structure. </p>
-<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-unicode-funcs-get-empty"></a><h3>hb_unicode_funcs_get_empty ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="returnvalue">hb_unicode_funcs_t</span></a> *
-hb_unicode_funcs_get_empty (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
-<p>Fetches the singleton empty Unicode-functions structure.</p>
-<div class="refsect3">
-<a name="hb-unicode-funcs-get-empty.returns"></a><h4>Returns</h4>
-<p>The empty Unicode-functions structure. </p>
-<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-unicode-funcs-get-parent"></a><h3>hb_unicode_funcs_get_parent ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="returnvalue">hb_unicode_funcs_t</span></a> *
-hb_unicode_funcs_get_parent (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>);</pre>
-<p>Fetches the parent of the Unicode-functions structure
-<em class="parameter"><code>ufuncs</code></em>
-.</p>
+<a name="hb-unicode-funcs-set-user-data"></a><h3>hb_unicode_funcs_set_user_data ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_unicode_funcs_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
+<p>Attaches a user-data key/data pair to the specified Unicode-functions structure.</p>
+<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
 <div class="refsect3">
-<a name="hb-unicode-funcs-get-parent.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-funcs-set-user-data.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
 <col class="parameters_description">
 <col width="200px" class="parameters_annotations">
 </colgroup>
-<tbody><tr>
+<tbody>
+<tr>
 <td class="parameter_name"><p>ufuncs</p></td>
 <td class="parameter_description"><p>The Unicode-functions structure</p></td>
 <td class="parameter_annotations"> </td>
-</tr></tbody>
+</tr>
+<tr>
+<td class="parameter_name"><p>key</p></td>
+<td class="parameter_description"><p>The user-data key</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>data</p></td>
+<td class="parameter_description"><p>A pointer to the user data</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>replace</p></td>
+<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+</tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-unicode-funcs-get-parent.returns"></a><h4>Returns</h4>
-<p> The parent Unicode-functions structure</p>
+<a name="hb-unicode-funcs-set-user-data.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
@@ -731,7 +726,7 @@ hb_unicode_funcs_get_parent (<em class="parameter"><code><a class="link" href="h
 <div class="refsect2">
 <a name="hb-unicode-funcs-get-user-data"></a><h3>hb_unicode_funcs_get_user_data ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span> *
-hb_unicode_funcs_get_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
+hb_unicode_funcs_get_user_data (<em class="parameter"><code>const <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
                                 <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>);</pre>
 <p>Fetches the user-data associated with the specified key,
 attached to the specified Unicode-functions structure.</p>
@@ -767,13 +762,13 @@ attached to the specified Unicode-functions structure.</p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-funcs-is-immutable"></a><h3>hb_unicode_funcs_is_immutable ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_unicode_funcs_is_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>);</pre>
-<p>Tests whether the specified Unicode-functions structure
-is immutable.</p>
+<a name="hb-unicode-funcs-make-immutable"></a><h3>hb_unicode_funcs_make_immutable ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_unicode_funcs_make_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>);</pre>
+<p>Makes the specified Unicode-functions structure
+immutable.</p>
 <div class="refsect3">
-<a name="hb-unicode-funcs-is-immutable.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-funcs-make-immutable.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -787,22 +782,17 @@ is immutable.</p>
 </tr></tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-unicode-funcs-is-immutable.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if <em class="parameter"><code>ufuncs</code></em>
-is immutable, <code class="literal">false</code> otherwise</p>
-</div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-funcs-make-immutable"></a><h3>hb_unicode_funcs_make_immutable ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_unicode_funcs_make_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>);</pre>
-<p>Makes the specified Unicode-functions structure
-immutable.</p>
+<a name="hb-unicode-funcs-is-immutable"></a><h3>hb_unicode_funcs_is_immutable ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+hb_unicode_funcs_is_immutable (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>);</pre>
+<p>Tests whether the specified Unicode-functions structure
+is immutable.</p>
 <div class="refsect3">
-<a name="hb-unicode-funcs-make-immutable.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-funcs-is-immutable.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -816,17 +806,37 @@ immutable.</p>
 </tr></tbody>
 </table></div>
 </div>
+<div class="refsect3">
+<a name="hb-unicode-funcs-is-immutable.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if <em class="parameter"><code>ufuncs</code></em>
+is immutable, <code class="literal">false</code> otherwise</p>
+</div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-funcs-reference"></a><h3>hb_unicode_funcs_reference ()</h3>
+<a name="hb-unicode-funcs-get-default"></a><h3>hb_unicode_funcs_get_default ()</h3>
 <pre class="programlisting"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="returnvalue">hb_unicode_funcs_t</span></a> *
-hb_unicode_funcs_reference (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>);</pre>
-<p>Increases the reference count on a Unicode-functions structure.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
+hb_unicode_funcs_get_default (<em class="parameter"><code><span class="type">void</span></code></em>);</pre>
+<p>Fetches a pointer to the default Unicode-functions structure that is used
+when no functions are explicitly set on <a class="link" href="harfbuzz-hb-buffer.html#hb-buffer-t" title="hb_buffer_t"><span class="type">hb_buffer_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-unicode-funcs-reference.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-funcs-get-default.returns"></a><h4>Returns</h4>
+<p>a pointer to the <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> Unicode-functions structure. </p>
+<p><span class="annotation">[<acronym title="Don't free data after the code is done."><span class="acronym">transfer none</span></acronym>]</span></p>
+</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+</div>
+<hr>
+<div class="refsect2">
+<a name="hb-unicode-funcs-get-parent"></a><h3>hb_unicode_funcs_get_parent ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="returnvalue">hb_unicode_funcs_t</span></a> *
+hb_unicode_funcs_get_parent (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>);</pre>
+<p>Fetches the parent of the Unicode-functions structure
+<em class="parameter"><code>ufuncs</code></em>
+.</p>
+<div class="refsect3">
+<a name="hb-unicode-funcs-get-parent.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -841,24 +851,23 @@ hb_unicode_funcs_reference (<em class="parameter"><code><a class="link" href="ha
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-unicode-funcs-reference.returns"></a><h4>Returns</h4>
-<p>The Unicode-functions structure. </p>
-<p><span class="annotation">[<acronym title="Free data after the code is done."><span class="acronym">transfer full</span></acronym>]</span></p>
+<a name="hb-unicode-funcs-get-parent.returns"></a><h4>Returns</h4>
+<p> The parent Unicode-functions structure</p>
 </div>
 <p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-funcs-set-combining-class-func"></a><h3>hb_unicode_funcs_set_combining_class_func ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_unicode_funcs_set_combining_class_func
-                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-combining-class-func-t" title="hb_unicode_combining_class_func_t ()"><span class="type">hb_unicode_combining_class_func_t</span></a> func</code></em>,
-                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-combining-class-func-t" title="hb_unicode_combining_class_func_t ()"><span class="type">hb_unicode_combining_class_func_t</span></a>.</p>
+<a name="hb-unicode-general-category-func-t"></a><h3>hb_unicode_general_category_func_t ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category-t" title="enum hb_unicode_general_category_t"><span class="returnvalue">hb_unicode_general_category_t</span></a>
+<span class="c_punctuation">(</span>*hb_unicode_general_category_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
+                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>,
+                                       <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> structure.</p>
+<p>This method should retrieve the General Category property for
+a specified Unicode code point.</p>
 <div class="refsect3">
-<a name="hb-unicode-funcs-set-combining-class-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-general-category-func-t.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -872,38 +881,36 @@ hb_unicode_funcs_set_combining_class_func
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>func</p></td>
-<td class="parameter_description"><p>The callback function to assign. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+<td class="parameter_name"><p>unicode</p></td>
+<td class="parameter_description"><p>The code point to query</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 <tr>
 <td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
-</p></td>
+<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
-<tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
-</tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<div class="refsect3">
+<a name="hb-unicode-general-category-func-t.returns"></a><h4>Returns</h4>
+<p> The <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category-t" title="enum hb_unicode_general_category_t"><span class="type">hb_unicode_general_category_t</span></a> of <em class="parameter"><code>unicode</code></em>
+</p>
+</div>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-funcs-set-compose-func"></a><h3>hb_unicode_funcs_set_compose_func ()</h3>
+<a name="hb-unicode-funcs-set-general-category-func"></a><h3>hb_unicode_funcs_set_general_category_func ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_unicode_funcs_set_compose_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
-                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-compose-func-t" title="hb_unicode_compose_func_t ()"><span class="type">hb_unicode_compose_func_t</span></a> func</code></em>,
-                                   <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-compose-func-t" title="hb_unicode_compose_func_t ()"><span class="type">hb_unicode_compose_func_t</span></a>.</p>
+hb_unicode_funcs_set_general_category_func
+                               (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category-func-t" title="hb_unicode_general_category_func_t ()"><span class="type">hb_unicode_general_category_func_t</span></a> func</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category-func-t" title="hb_unicode_general_category_func_t ()"><span class="type">hb_unicode_general_category_func_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-unicode-funcs-set-compose-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-funcs-set-general-category-func.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -940,15 +947,16 @@ is not needed anymore. </p></td>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-funcs-set-decompose-func"></a><h3>hb_unicode_funcs_set_decompose_func ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_unicode_funcs_set_decompose_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
-                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-decompose-func-t" title="hb_unicode_decompose_func_t ()"><span class="type">hb_unicode_decompose_func_t</span></a> func</code></em>,
-                                     <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-decompose-func-t" title="hb_unicode_decompose_func_t ()"><span class="type">hb_unicode_decompose_func_t</span></a>.</p>
+<a name="hb-unicode-combining-class-func-t"></a><h3>hb_unicode_combining_class_func_t ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-combining-class-t" title="enum hb_unicode_combining_class_t"><span class="returnvalue">hb_unicode_combining_class_t</span></a>
+<span class="c_punctuation">(</span>*hb_unicode_combining_class_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
+                                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>,
+                                      <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> structure.</p>
+<p>This method should retrieve the Canonical Combining Class (ccc)
+property for a specified Unicode code point.</p>
 <div class="refsect3">
-<a name="hb-unicode-funcs-set-decompose-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-combining-class-func-t.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -962,39 +970,36 @@ hb_unicode_funcs_set_decompose_func (<em class="parameter"><code><a class="link"
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>func</p></td>
-<td class="parameter_description"><p>The callback function to assign. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+<td class="parameter_name"><p>unicode</p></td>
+<td class="parameter_description"><p>The code point to query</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 <tr>
 <td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
-</p></td>
+<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
-<tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
-</tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<div class="refsect3">
+<a name="hb-unicode-combining-class-func-t.returns"></a><h4>Returns</h4>
+<p> The <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-combining-class-t" title="enum hb_unicode_combining_class_t"><span class="type">hb_unicode_combining_class_t</span></a> of <em class="parameter"><code>unicode</code></em>
+</p>
+</div>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-funcs-set-general-category-func"></a><h3>hb_unicode_funcs_set_general_category_func ()</h3>
+<a name="hb-unicode-funcs-set-combining-class-func"></a><h3>hb_unicode_funcs_set_combining_class_func ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_unicode_funcs_set_general_category_func
+hb_unicode_funcs_set_combining_class_func
                                (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category-func-t" title="hb_unicode_general_category_func_t ()"><span class="type">hb_unicode_general_category_func_t</span></a> func</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-combining-class-func-t" title="hb_unicode_combining_class_func_t ()"><span class="type">hb_unicode_combining_class_func_t</span></a> func</code></em>,
                                 <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
                                 <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category-func-t" title="hb_unicode_general_category_func_t ()"><span class="type">hb_unicode_general_category_func_t</span></a>.</p>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-combining-class-func-t" title="hb_unicode_combining_class_func_t ()"><span class="type">hb_unicode_combining_class_func_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-unicode-funcs-set-general-category-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-funcs-set-combining-class-func.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1031,15 +1036,19 @@ is not needed anymore. </p></td>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-funcs-set-mirroring-func"></a><h3>hb_unicode_funcs_set_mirroring_func ()</h3>
-<pre class="programlisting"><span class="returnvalue">void</span>
-hb_unicode_funcs_set_mirroring_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
-                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-mirroring-func-t" title="hb_unicode_mirroring_func_t ()"><span class="type">hb_unicode_mirroring_func_t</span></a> func</code></em>,
-                                     <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-mirroring-func-t" title="hb_unicode_mirroring_func_t ()"><span class="type">hb_unicode_mirroring_func_t</span></a>.</p>
+<a name="hb-unicode-mirroring-func-t"></a><h3>hb_unicode_mirroring_func_t ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
+<span class="c_punctuation">(</span>*hb_unicode_mirroring_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> structure.</p>
+<p>This method should retrieve the Bi-Directional Mirroring Glyph
+code point for a specified Unicode code point.</p>
+<div class="note">Note: If a code point does not have a specified
+Bi-Directional Mirroring Glyph defined, the method should
+return the original code point.</div>
 <div class="refsect3">
-<a name="hb-unicode-funcs-set-mirroring-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-mirroring-func-t.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1053,38 +1062,35 @@ hb_unicode_funcs_set_mirroring_func (<em class="parameter"><code><a class="link"
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>func</p></td>
-<td class="parameter_description"><p>The callback function to assign. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
+<td class="parameter_name"><p>unicode</p></td>
+<td class="parameter_description"><p>The code point to query</p></td>
+<td class="parameter_annotations"> </td>
 </tr>
 <tr>
 <td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
-</p></td>
+<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
-<tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
-</tr>
 </tbody>
 </table></div>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
+<div class="refsect3">
+<a name="hb-unicode-mirroring-func-t.returns"></a><h4>Returns</h4>
+<p> The <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> of the Mirroring Glyph for <em class="parameter"><code>unicode</code></em>
+</p>
+</div>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-funcs-set-script-func"></a><h3>hb_unicode_funcs_set_script_func ()</h3>
+<a name="hb-unicode-funcs-set-mirroring-func"></a><h3>hb_unicode_funcs_set_mirroring_func ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
-hb_unicode_funcs_set_script_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
-                                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-script-func-t" title="hb_unicode_script_func_t ()"><span class="type">hb_unicode_script_func_t</span></a> func</code></em>,
-                                  <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
-                                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
-<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-script-func-t" title="hb_unicode_script_func_t ()"><span class="type">hb_unicode_script_func_t</span></a>.</p>
+hb_unicode_funcs_set_mirroring_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
+                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-mirroring-func-t" title="hb_unicode_mirroring_func_t ()"><span class="type">hb_unicode_mirroring_func_t</span></a> func</code></em>,
+                                     <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-mirroring-func-t" title="hb_unicode_mirroring_func_t ()"><span class="type">hb_unicode_mirroring_func_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-unicode-funcs-set-script-func.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-funcs-set-mirroring-func.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1121,70 +1127,16 @@ is not needed anymore. </p></td>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-funcs-set-user-data"></a><h3>hb_unicode_funcs_set_user_data ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
-hb_unicode_funcs_set_user_data (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-user-data-key-t" title="hb_user_data_key_t"><span class="type">hb_user_data_key_t</span></a> *key</code></em>,
-                                <em class="parameter"><code><span class="type">void</span> *data</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> replace</code></em>);</pre>
-<p>Attaches a user-data key/data pair to the specified Unicode-functions structure.</p>
-<p><span class="annotation">[<acronym title="Exposed in C code, not necessarily available in other languages."><span class="acronym">skip</span></acronym>]</span></p>
-<div class="refsect3">
-<a name="hb-unicode-funcs-set-user-data.parameters"></a><h4>Parameters</h4>
-<div class="informaltable"><table class="informaltable" width="100%" border="0">
-<colgroup>
-<col width="150px" class="parameters_name">
-<col class="parameters_description">
-<col width="200px" class="parameters_annotations">
-</colgroup>
-<tbody>
-<tr>
-<td class="parameter_name"><p>ufuncs</p></td>
-<td class="parameter_description"><p>The Unicode-functions structure</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>key</p></td>
-<td class="parameter_description"><p>The user-data key</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>data</p></td>
-<td class="parameter_description"><p>A pointer to the user data</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-<tr>
-<td class="parameter_name"><p>destroy</p></td>
-<td class="parameter_description"><p>A callback to call when <em class="parameter"><code>data</code></em>
-is not needed anymore. </p></td>
-<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
-</tr>
-<tr>
-<td class="parameter_name"><p>replace</p></td>
-<td class="parameter_description"><p>Whether to replace an existing data with the same key</p></td>
-<td class="parameter_annotations"> </td>
-</tr>
-</tbody>
-</table></div>
-</div>
-<div class="refsect3">
-<a name="hb-unicode-funcs-set-user-data.returns"></a><h4>Returns</h4>
-<p> <code class="literal">true</code> if success, <code class="literal">false</code> otherwise</p>
-</div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
-</div>
-<hr>
-<div class="refsect2">
-<a name="hb-unicode-general-category"></a><h3>hb_unicode_general_category ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category-t" title="enum hb_unicode_general_category_t"><span class="returnvalue">hb_unicode_general_category_t</span></a>
-hb_unicode_general_category (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
-                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>);</pre>
-<p>Retrieves the General Category (gc) property
-of code point <em class="parameter"><code>unicode</code></em>
-.</p>
+<a name="hb-unicode-script-func-t"></a><h3>hb_unicode_script_func_t ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="returnvalue">hb_script_t</span></a>
+<span class="c_punctuation">(</span>*hb_unicode_script_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
+                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>,
+                             <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> structure.</p>
+<p>This method should retrieve the Script property for a 
+specified Unicode code point.</p>
 <div class="refsect3">
-<a name="hb-unicode-general-category.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-script-func-t.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1194,7 +1146,7 @@ of code point <em class="parameter"><code>unicode</code></em>
 <tbody>
 <tr>
 <td class="parameter_name"><p>ufuncs</p></td>
-<td class="parameter_description"><p>The Unicode-functions structure</p></td>
+<td class="parameter_description"><p>A Unicode-functions structure</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
@@ -1202,28 +1154,31 @@ of code point <em class="parameter"><code>unicode</code></em>
 <td class="parameter_description"><p>The code point to query</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-unicode-general-category.returns"></a><h4>Returns</h4>
-<p> The <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category-t" title="enum hb_unicode_general_category_t"><span class="type">hb_unicode_general_category_t</span></a> of <em class="parameter"><code>unicode</code></em>
+<a name="hb-unicode-script-func-t.returns"></a><h4>Returns</h4>
+<p> The <a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> of <em class="parameter"><code>unicode</code></em>
 </p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-general-category-func-t"></a><h3>hb_unicode_general_category_func_t ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category-t" title="enum hb_unicode_general_category_t"><span class="returnvalue">hb_unicode_general_category_t</span></a>
-<span class="c_punctuation">(</span>*hb_unicode_general_category_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
-                                       <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>,
-                                       <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
-<p>A virtual method for the <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> structure.</p>
-<p>This method should retrieve the General Category property for
-a specified Unicode code point.</p>
+<a name="hb-unicode-funcs-set-script-func"></a><h3>hb_unicode_funcs_set_script_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_unicode_funcs_set_script_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
+                                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-script-func-t" title="hb_unicode_script_func_t ()"><span class="type">hb_unicode_script_func_t</span></a> func</code></em>,
+                                  <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                  <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-script-func-t" title="hb_unicode_script_func_t ()"><span class="type">hb_unicode_script_func_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-unicode-general-category-func-t.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-funcs-set-script-func.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1237,35 +1192,44 @@ a specified Unicode code point.</p>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>unicode</p></td>
-<td class="parameter_description"><p>The code point to query</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
 </tr>
 <tr>
 <td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
 </tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-unicode-general-category-func-t.returns"></a><h4>Returns</h4>
-<p> The <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-general-category-t" title="enum hb_unicode_general_category_t"><span class="type">hb_unicode_general_category_t</span></a> of <em class="parameter"><code>unicode</code></em>
-</p>
-</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-mirroring"></a><h3>hb_unicode_mirroring ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
-hb_unicode_mirroring (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
-                      <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>);</pre>
-<p>Retrieves the Bi-directional Mirroring Glyph code
-point defined for code point <em class="parameter"><code>unicode</code></em>
-.</p>
+<a name="hb-unicode-compose-func-t"></a><h3>hb_unicode_compose_func_t ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="c_punctuation">(</span>*hb_unicode_compose_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
+                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> a</code></em>,
+                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> b</code></em>,
+                              <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *ab</code></em>,
+                              <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> structure.</p>
+<p>This method should compose a sequence of two input Unicode code
+points by canonical equivalence, returning the composed code
+point in a <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> output parameter (if successful).
+The method must return an <a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> indicating the success
+of the composition.</p>
 <div class="refsect3">
-<a name="hb-unicode-mirroring.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-compose-func-t.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1275,39 +1239,50 @@ point defined for code point <em class="parameter"><code>unicode</code></em>
 <tbody>
 <tr>
 <td class="parameter_name"><p>ufuncs</p></td>
-<td class="parameter_description"><p>The Unicode-functions structure</p></td>
+<td class="parameter_description"><p>A Unicode-functions structure</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>unicode</p></td>
-<td class="parameter_description"><p>The code point to query</p></td>
+<td class="parameter_name"><p>a</p></td>
+<td class="parameter_description"><p>The first code point to compose</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>b</p></td>
+<td class="parameter_description"><p>The second code point to compose</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>ab</p></td>
+<td class="parameter_description"><p>The composed code point. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>user data pointer passed by the caller</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-unicode-mirroring.returns"></a><h4>Returns</h4>
-<p> The <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> of the Mirroring Glyph for <em class="parameter"><code>unicode</code></em>
-</p>
+<a name="hb-unicode-compose-func-t.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> is <em class="parameter"><code>a</code></em>
+,<em class="parameter"><code>b</code></em>
+composed, <code class="literal">false</code> otherwise</p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-mirroring-func-t"></a><h3>hb_unicode_mirroring_func_t ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="returnvalue">hb_codepoint_t</span></a>
-<span class="c_punctuation">(</span>*hb_unicode_mirroring_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
-                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>,
-                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
-<p>A virtual method for the <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> structure.</p>
-<p>This method should retrieve the Bi-Directional Mirroring Glyph
-code point for a specified Unicode code point.</p>
-<div class="note">Note: If a code point does not have a specified
-Bi-Directional Mirroring Glyph defined, the method should
-return the original code point.</div>
+<a name="hb-unicode-funcs-set-compose-func"></a><h3>hb_unicode_funcs_set_compose_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_unicode_funcs_set_compose_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-compose-func-t" title="hb_unicode_compose_func_t ()"><span class="type">hb_unicode_compose_func_t</span></a> func</code></em>,
+                                   <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-compose-func-t" title="hb_unicode_compose_func_t ()"><span class="type">hb_unicode_compose_func_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-unicode-mirroring-func-t.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-funcs-set-compose-func.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1321,35 +1296,43 @@ return the original code point.</div>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>unicode</p></td>
-<td class="parameter_description"><p>The code point to query</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
 </tr>
 <tr>
 <td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
 </tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-unicode-mirroring-func-t.returns"></a><h4>Returns</h4>
-<p> The <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> of the Mirroring Glyph for <em class="parameter"><code>unicode</code></em>
-</p>
-</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-script"></a><h3>hb_unicode_script ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="returnvalue">hb_script_t</span></a>
-hb_unicode_script (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
-                   <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>);</pre>
-<p>Retrieves the <a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> script to which code
-point <em class="parameter"><code>unicode</code></em>
- belongs.</p>
+<a name="hb-unicode-decompose-func-t"></a><h3>hb_unicode_decompose_func_t ()</h3>
+<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="returnvalue">hb_bool_t</span></a>
+<span class="c_punctuation">(</span>*hb_unicode_decompose_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> ab</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *a</code></em>,
+                                <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> *b</code></em>,
+                                <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
+<p>A virtual method for the <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> structure.</p>
+<p>This method should decompose an input Unicode code point,
+returning the two decomposed code points in <a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a>
+output parameters (if successful). The method must return an
+<a class="link" href="harfbuzz-hb-common.html#hb-bool-t" title="hb_bool_t"><span class="type">hb_bool_t</span></a> indicating the success of the composition.</p>
 <div class="refsect3">
-<a name="hb-unicode-script.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-decompose-func-t.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1359,36 +1342,49 @@ point <em class="parameter"><code>unicode</code></em>
 <tbody>
 <tr>
 <td class="parameter_name"><p>ufuncs</p></td>
-<td class="parameter_description"><p>The Unicode-functions structure</p></td>
+<td class="parameter_description"><p>A Unicode-functions structure</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>unicode</p></td>
-<td class="parameter_description"><p>The code point to query</p></td>
+<td class="parameter_name"><p>ab</p></td>
+<td class="parameter_description"><p>The code point to decompose</p></td>
+<td class="parameter_annotations"> </td>
+</tr>
+<tr>
+<td class="parameter_name"><p>a</p></td>
+<td class="parameter_description"><p>The first decomposed code point. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>b</p></td>
+<td class="parameter_description"><p>The second decomposed code point. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="Parameter for returning results. Default is transfer full."><span class="acronym">out</span></acronym>]</span></td>
+</tr>
+<tr>
+<td class="parameter_name"><p>user_data</p></td>
+<td class="parameter_description"><p>user data pointer passed by the caller</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 </tbody>
 </table></div>
 </div>
 <div class="refsect3">
-<a name="hb-unicode-script.returns"></a><h4>Returns</h4>
-<p> The <a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> of <em class="parameter"><code>unicode</code></em>
-</p>
+<a name="hb-unicode-decompose-func-t.returns"></a><h4>Returns</h4>
+<p> <code class="literal">true</code> if <em class="parameter"><code>ab</code></em>
+decomposed, <code class="literal">false</code> otherwise</p>
 </div>
-<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-script-func-t"></a><h3>hb_unicode_script_func_t ()</h3>
-<pre class="programlisting"><a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="returnvalue">hb_script_t</span></a>
-<span class="c_punctuation">(</span>*hb_unicode_script_func_t<span class="c_punctuation">)</span> (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
-                             <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-codepoint-t" title="hb_codepoint_t"><span class="type">hb_codepoint_t</span></a> unicode</code></em>,
-                             <em class="parameter"><code><span class="type">void</span> *user_data</code></em>);</pre>
-<p>A virtual method for the <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> structure.</p>
-<p>This method should retrieve the Script property for a 
-specified Unicode code point.</p>
+<a name="hb-unicode-funcs-set-decompose-func"></a><h3>hb_unicode_funcs_set_decompose_func ()</h3>
+<pre class="programlisting"><span class="returnvalue">void</span>
+hb_unicode_funcs_set_decompose_func (<em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a> *ufuncs</code></em>,
+                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-decompose-func-t" title="hb_unicode_decompose_func_t ()"><span class="type">hb_unicode_decompose_func_t</span></a> func</code></em>,
+                                     <em class="parameter"><code><span class="type">void</span> *user_data</code></em>,
+                                     <em class="parameter"><code><a class="link" href="harfbuzz-hb-common.html#hb-destroy-func-t" title="hb_destroy_func_t ()"><span class="type">hb_destroy_func_t</span></a> destroy</code></em>);</pre>
+<p>Sets the implementation function for <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-decompose-func-t" title="hb_unicode_decompose_func_t ()"><span class="type">hb_unicode_decompose_func_t</span></a>.</p>
 <div class="refsect3">
-<a name="hb-unicode-script-func-t.parameters"></a><h4>Parameters</h4>
+<a name="hb-unicode-funcs-set-decompose-func.parameters"></a><h4>Parameters</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="150px" class="parameters_name">
@@ -1402,23 +1398,26 @@ specified Unicode code point.</p>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
-<td class="parameter_name"><p>unicode</p></td>
-<td class="parameter_description"><p>The code point to query</p></td>
-<td class="parameter_annotations"> </td>
+<td class="parameter_name"><p>func</p></td>
+<td class="parameter_description"><p>The callback function to assign. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="This parameter is a 'user_data', for callbacks; many bindings can pass NULL here."><span class="acronym">closure</span></acronym> user_data][<acronym title="This parameter is a 'destroy_data', for callbacks."><span class="acronym">destroy</span></acronym> destroy][<acronym title="The callback is valid until the GDestroyNotify argument is called."><span class="acronym">scope notified</span></acronym>]</span></td>
 </tr>
 <tr>
 <td class="parameter_name"><p>user_data</p></td>
-<td class="parameter_description"><p>User data pointer passed by the caller</p></td>
+<td class="parameter_description"><p>Data to pass to <em class="parameter"><code>func</code></em>
+</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
+<tr>
+<td class="parameter_name"><p>destroy</p></td>
+<td class="parameter_description"><p>The function to call when <em class="parameter"><code>user_data</code></em>
+is not needed anymore. </p></td>
+<td class="parameter_annotations"><span class="annotation">[<acronym title="NULL may be passed as the value in, out, in-out; or as a return value."><span class="acronym">nullable</span></acronym>]</span></td>
+</tr>
 </tbody>
 </table></div>
 </div>
-<div class="refsect3">
-<a name="hb-unicode-script-func-t.returns"></a><h4>Returns</h4>
-<p> The <a class="link" href="harfbuzz-hb-common.html#hb-script-t" title="enum hb_script_t"><span class="type">hb_script_t</span></a> of <em class="parameter"><code>unicode</code></em>
-</p>
-</div>
+<p class="since">Since: <a class="link" href="api-index-0-9-2.html#api-index-0.9.2">0.9.2</a></p>
 </div>
 </div>
 <div class="refsect1">
@@ -1728,9 +1727,9 @@ being returned from <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-co
 <td class="enum_member_annotations"> </td>
 </tr>
 <tr>
-<td class="enum_member_name"><p><a name="HB-UNICODE-COMBINING-CLASS-CCC133:CAPS"></a>HB_UNICODE_COMBINING_CLASS_CCC133</p></td>
+<td class="enum_member_name"><p><a name="HB-UNICODE-COMBINING-CLASS-CCC132:CAPS"></a>HB_UNICODE_COMBINING_CLASS_CCC132</p></td>
 <td class="enum_member_description">
-<p>[Tibetan]</p>
+<p>[Tibetan] Since: 7.2.0</p>
 </td>
 <td class="enum_member_annotations"> </td>
 </tr>
@@ -1852,19 +1851,6 @@ being returned from <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-co
 </div>
 <hr>
 <div class="refsect2">
-<a name="hb-unicode-funcs-t"></a><h3>hb_unicode_funcs_t</h3>
-<pre class="programlisting">typedef struct hb_unicode_funcs_t hb_unicode_funcs_t;
-</pre>
-<p>Data type containing a set of virtual methods used for
-accessing various Unicode character properties.</p>
-<p>HarfBuzz provides a default function for each of the
-methods in <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a>. Client programs can implement
-their own replacements for the individual Unicode functions, as
-needed, and replace the default by calling the setter for a
-method.</p>
-</div>
-<hr>
-<div class="refsect2">
 <a name="hb-unicode-general-category-t"></a><h3>enum hb_unicode_general_category_t</h3>
 <p>Data type for the "General_Category" (gc) property from
 the Unicode Character Database.</p>
@@ -2091,6 +2077,19 @@ the Unicode Character Database.</p>
 </table></div>
 </div>
 </div>
+<hr>
+<div class="refsect2">
+<a name="hb-unicode-funcs-t"></a><h3>hb_unicode_funcs_t</h3>
+<pre class="programlisting">typedef struct hb_unicode_funcs_t hb_unicode_funcs_t;
+</pre>
+<p>Data type containing a set of virtual methods used for
+accessing various Unicode character properties.</p>
+<p>HarfBuzz provides a default function for each of the
+methods in <a class="link" href="harfbuzz-hb-unicode.html#hb-unicode-funcs-t" title="hb_unicode_funcs_t"><span class="type">hb_unicode_funcs_t</span></a>. Client programs can implement
+their own replacements for the individual Unicode functions, as
+needed, and replace the default by calling the setter for a
+method.</p>
+</div>
 </div>
 </div>
 <div class="footer">
index faa4b58..77aafd0 100644 (file)
@@ -241,28 +241,28 @@ hb_version_string (<em class="parameter"><code><span class="type">void</span></c
 <a name="harfbuzz-hb-version.other_details"></a><h2>Types and Values</h2>
 <div class="refsect2">
 <a name="HB-VERSION-MAJOR:CAPS"></a><h3>HB_VERSION_MAJOR</h3>
-<pre class="programlisting">#define HB_VERSION_MAJOR 3
+<pre class="programlisting">#define HB_VERSION_MAJOR 8
 </pre>
 <p>The major component of the library version available at compile-time.</p>
 </div>
 <hr>
 <div class="refsect2">
 <a name="HB-VERSION-MICRO:CAPS"></a><h3>HB_VERSION_MICRO</h3>
-<pre class="programlisting">#define HB_VERSION_MICRO 0
+<pre class="programlisting">#define HB_VERSION_MICRO 2
 </pre>
 <p>The micro component of the library version available at compile-time.</p>
 </div>
 <hr>
 <div class="refsect2">
 <a name="HB-VERSION-MINOR:CAPS"></a><h3>HB_VERSION_MINOR</h3>
-<pre class="programlisting">#define HB_VERSION_MINOR 4
+<pre class="programlisting">#define HB_VERSION_MINOR 2
 </pre>
 <p>The minor component of the library version available at compile-time.</p>
 </div>
 <hr>
 <div class="refsect2">
 <a name="HB-VERSION-STRING:CAPS"></a><h3>HB_VERSION_STRING</h3>
-<pre class="programlisting">#define HB_VERSION_STRING "3.4.0"
+<pre class="programlisting">#define HB_VERSION_STRING "8.2.2"
 </pre>
 <p>A string literal containing the library version available at compile-time.</p>
 </div>
index 4427c2e..45c401a 100644 (file)
@@ -25,7 +25,7 @@
       </sub>
       <sub name="Shaping concepts" link="shaping-concepts.html">
         <sub name="Text shaping" link="shaping-concepts.html#text-shaping-concepts"/>
-        <sub name="Complex scripts" link="complex-scripts.html"/>
+        <sub name="Script-specific shaping" link="script-specific-shaping.html"/>
         <sub name="Shaping operations" link="shaping-operations.html"/>
         <sub name="Unicode character categories" link="unicode-character-categories.html"/>
         <sub name="Text runs" link="text-runs.html"/>
@@ -51,6 +51,7 @@
         <sub name="Customizing font functions" link="fonts-and-faces-custom-functions.html"/>
         <sub name="Font objects and HarfBuzz's native OpenType implementation" link="fonts-and-faces-native-opentype.html"/>
         <sub name="Working with OpenType Variable Fonts" link="fonts-and-faces-variable.html"/>
+        <sub name="Glyphs and rendering" link="glyphs-and-rendering.html"/>
       </sub>
       <sub name="Shaping and shape plans" link="shaping-and-shape-plans.html">
         <sub name="Shaping and buffer output" link="shaping-and-shape-plans.html#shaping-buffer-output"/>
@@ -81,6 +82,7 @@
       <sub name="Platform Integration Guide" link="integration.html">
         <sub name="GNOME integration, GLib, and GObject" link="integration.html#integration-glib"/>
         <sub name="FreeType integration" link="integration-freetype.html"/>
+        <sub name="Cairo integration" link="integration-cairo.html"/>
         <sub name="Uniscribe integration" link="integration-uniscribe.html"/>
         <sub name="Core Text integration" link="integration-coretext.html"/>
         <sub name="ICU integration" link="integration-icu.html"/>
@@ -92,6 +94,9 @@
         <sub name="hb-blob" link="harfbuzz-hb-blob.html"/>
         <sub name="hb-buffer" link="harfbuzz-hb-buffer.html"/>
         <sub name="hb-common" link="harfbuzz-hb-common.html"/>
+        <sub name="hb-features" link="harfbuzz-hb-features.html"/>
+        <sub name="hb-draw" link="harfbuzz-hb-draw.html"/>
+        <sub name="hb-paint" link="harfbuzz-hb-paint.html"/>
         <sub name="hb-deprecated" link="harfbuzz-hb-deprecated.html"/>
         <sub name="hb-face" link="harfbuzz-hb-face.html"/>
         <sub name="hb-font" link="harfbuzz-hb-font.html"/>
         <sub name="hb-uniscribe" link="harfbuzz-hb-uniscribe.html"/>
         <sub name="hb-gdi" link="harfbuzz-hb-gdi.html"/>
         <sub name="hb-directwrite" link="harfbuzz-hb-directwrite.html"/>
+        <sub name="hb-cairo" link="harfbuzz-hb-cairo.html"/>
       </sub>
       <sub name="Style API" link="style-api.html">
         <sub name="hb-style" link="harfbuzz-hb-style.html"/>
       </sub>
       <sub name="API Index" link="api-index-full.html"/>
       <sub name="Index of deprecated API" link="deprecated-api-index.html"/>
+      <sub name="Index of new symbols in 8.2.0" link="api-index-8-2-0.html"/>
+      <sub name="Index of new symbols in 8.1.0" link="api-index-8-1-0.html"/>
+      <sub name="Index of new symbols in 8.0.0" link="api-index-8-0-0.html"/>
+      <sub name="Index of new symbols in 7.3.0" link="api-index-7-3-0.html"/>
+      <sub name="Index of new symbols in 7.1.0" link="api-index-7-1-0.html"/>
+      <sub name="Index of new symbols in 7.0.0" link="api-index-7-0-0.html"/>
+      <sub name="Index of new symbols in 6.0.0" link="api-index-6-0-0.html"/>
+      <sub name="Index of new symbols in 5.3.0" link="api-index-5-3-0.html"/>
+      <sub name="Index of new symbols in 5.0.0" link="api-index-5-0-0.html"/>
+      <sub name="Index of new symbols in 4.4.0" link="api-index-4-4-0.html"/>
+      <sub name="Index of new symbols in 4.3.0" link="api-index-4-3-0.html"/>
+      <sub name="Index of new symbols in 4.2.0" link="api-index-4-2-0.html"/>
+      <sub name="Index of new symbols in 4.1.0" link="api-index-4-1-0.html"/>
+      <sub name="Index of new symbols in 4.0.0" link="api-index-4-0-0.html"/>
       <sub name="Index of new symbols in 3.4.0" link="api-index-3-4-0.html"/>
       <sub name="Index of new symbols in 3.3.0" link="api-index-3-3-0.html"/>
       <sub name="Index of new symbols in 3.1.0" link="api-index-3-1-0.html"/>
       <sub name="Index of new symbols in 1.8.1" link="api-index-1-8-1.html"/>
       <sub name="Index of new symbols in 1.8.0" link="api-index-1-8-0.html"/>
       <sub name="Index of new symbols in 1.7.7" link="api-index-1-7-7.html"/>
-      <sub name="Index of new symbols in 1.7.5" link="api-index-1-7-5.html"/>
       <sub name="Index of new symbols in 1.7.2" link="api-index-1-7-2.html"/>
       <sub name="Index of new symbols in 1.6.0" link="api-index-1-6-0.html"/>
       <sub name="Index of new symbols in 1.5.0" link="api-index-1-5-0.html"/>
     <keyword type="function" name="hb_blob_create_from_file_or_fail ()" link="harfbuzz-hb-blob.html#hb-blob-create-from-file-or-fail" since="2.8.2"/>
     <keyword type="function" name="hb_blob_create_sub_blob ()" link="harfbuzz-hb-blob.html#hb-blob-create-sub-blob" since="0.9.2"/>
     <keyword type="function" name="hb_blob_copy_writable_or_fail ()" link="harfbuzz-hb-blob.html#hb-blob-copy-writable-or-fail" since="1.8.0"/>
+    <keyword type="function" name="hb_blob_get_empty ()" link="harfbuzz-hb-blob.html#hb-blob-get-empty" since="0.9.2"/>
+    <keyword type="function" name="hb_blob_reference ()" link="harfbuzz-hb-blob.html#hb-blob-reference" since="0.9.2"/>
     <keyword type="function" name="hb_blob_destroy ()" link="harfbuzz-hb-blob.html#hb-blob-destroy" since="0.9.2"/>
+    <keyword type="function" name="hb_blob_set_user_data ()" link="harfbuzz-hb-blob.html#hb-blob-set-user-data" since="0.9.2"/>
+    <keyword type="function" name="hb_blob_get_user_data ()" link="harfbuzz-hb-blob.html#hb-blob-get-user-data" since="0.9.2"/>
+    <keyword type="function" name="hb_blob_make_immutable ()" link="harfbuzz-hb-blob.html#hb-blob-make-immutable" since="0.9.2"/>
+    <keyword type="function" name="hb_blob_is_immutable ()" link="harfbuzz-hb-blob.html#hb-blob-is-immutable" since="0.9.2"/>
     <keyword type="function" name="hb_blob_get_data ()" link="harfbuzz-hb-blob.html#hb-blob-get-data" since="0.9.2"/>
     <keyword type="function" name="hb_blob_get_data_writable ()" link="harfbuzz-hb-blob.html#hb-blob-get-data-writable" since="0.9.2"/>
-    <keyword type="function" name="hb_blob_get_empty ()" link="harfbuzz-hb-blob.html#hb-blob-get-empty" since="0.9.2"/>
     <keyword type="function" name="hb_blob_get_length ()" link="harfbuzz-hb-blob.html#hb-blob-get-length" since="0.9.2"/>
-    <keyword type="function" name="hb_blob_get_user_data ()" link="harfbuzz-hb-blob.html#hb-blob-get-user-data" since="0.9.2"/>
-    <keyword type="function" name="hb_blob_is_immutable ()" link="harfbuzz-hb-blob.html#hb-blob-is-immutable" since="0.9.2"/>
-    <keyword type="function" name="hb_blob_make_immutable ()" link="harfbuzz-hb-blob.html#hb-blob-make-immutable" since="0.9.2"/>
-    <keyword type="function" name="hb_blob_reference ()" link="harfbuzz-hb-blob.html#hb-blob-reference" since="0.9.2"/>
-    <keyword type="function" name="hb_blob_set_user_data ()" link="harfbuzz-hb-blob.html#hb-blob-set-user-data" since="0.9.2"/>
     <keyword type="typedef" name="hb_blob_t" link="harfbuzz-hb-blob.html#hb-blob-t"/>
     <keyword type="enum" name="enum hb_memory_mode_t" link="harfbuzz-hb-blob.html#hb-memory-mode-t"/>
     <keyword type="function" name="hb_buffer_create ()" link="harfbuzz-hb-buffer.html#hb-buffer-create" since="0.9.2"/>
+    <keyword type="function" name="hb_buffer_allocation_successful ()" link="harfbuzz-hb-buffer.html#hb-buffer-allocation-successful" since="0.9.2"/>
     <keyword type="function" name="hb_buffer_create_similar ()" link="harfbuzz-hb-buffer.html#hb-buffer-create-similar" since="3.3.0"/>
-    <keyword type="function" name="hb_buffer_reference ()" link="harfbuzz-hb-buffer.html#hb-buffer-reference" since="0.9.2"/>
     <keyword type="function" name="hb_buffer_get_empty ()" link="harfbuzz-hb-buffer.html#hb-buffer-get-empty" since="0.9.2"/>
+    <keyword type="function" name="hb_buffer_reference ()" link="harfbuzz-hb-buffer.html#hb-buffer-reference" since="0.9.2"/>
     <keyword type="function" name="hb_buffer_destroy ()" link="harfbuzz-hb-buffer.html#hb-buffer-destroy" since="0.9.2"/>
+    <keyword type="function" name="hb_buffer_set_user_data ()" link="harfbuzz-hb-buffer.html#hb-buffer-set-user-data" since="0.9.2"/>
+    <keyword type="function" name="hb_buffer_get_user_data ()" link="harfbuzz-hb-buffer.html#hb-buffer-get-user-data" since="0.9.2"/>
     <keyword type="function" name="hb_buffer_reset ()" link="harfbuzz-hb-buffer.html#hb-buffer-reset" since="0.9.2"/>
     <keyword type="function" name="hb_buffer_clear_contents ()" link="harfbuzz-hb-buffer.html#hb-buffer-clear-contents" since="0.9.11"/>
     <keyword type="function" name="hb_buffer_pre_allocate ()" link="harfbuzz-hb-buffer.html#hb-buffer-pre-allocate" since="0.9.2"/>
-    <keyword type="function" name="hb_buffer_allocation_successful ()" link="harfbuzz-hb-buffer.html#hb-buffer-allocation-successful" since="0.9.2"/>
     <keyword type="function" name="hb_buffer_add ()" link="harfbuzz-hb-buffer.html#hb-buffer-add" since="0.9.7"/>
     <keyword type="function" name="hb_buffer_add_codepoints ()" link="harfbuzz-hb-buffer.html#hb-buffer-add-codepoints" since="0.9.31"/>
     <keyword type="function" name="hb_buffer_add_utf32 ()" link="harfbuzz-hb-buffer.html#hb-buffer-add-utf32" since="0.9.2"/>
     <keyword type="function" name="hb_buffer_guess_segment_properties ()" link="harfbuzz-hb-buffer.html#hb-buffer-guess-segment-properties" since="0.9.7"/>
     <keyword type="function" name="hb_buffer_set_unicode_funcs ()" link="harfbuzz-hb-buffer.html#hb-buffer-set-unicode-funcs" since="0.9.2"/>
     <keyword type="function" name="hb_buffer_get_unicode_funcs ()" link="harfbuzz-hb-buffer.html#hb-buffer-get-unicode-funcs" since="0.9.2"/>
-    <keyword type="function" name="hb_buffer_set_user_data ()" link="harfbuzz-hb-buffer.html#hb-buffer-set-user-data" since="0.9.2"/>
-    <keyword type="function" name="hb_buffer_get_user_data ()" link="harfbuzz-hb-buffer.html#hb-buffer-get-user-data" since="0.9.2"/>
     <keyword type="function" name="hb_buffer_get_glyph_infos ()" link="harfbuzz-hb-buffer.html#hb-buffer-get-glyph-infos" since="0.9.2"/>
+    <keyword type="function" name="hb_glyph_info_get_glyph_flags ()" link="harfbuzz-hb-buffer.html#hb-glyph-info-get-glyph-flags" since="1.5.0"/>
     <keyword type="function" name="hb_buffer_get_glyph_positions ()" link="harfbuzz-hb-buffer.html#hb-buffer-get-glyph-positions" since="0.9.2"/>
     <keyword type="function" name="hb_buffer_has_positions ()" link="harfbuzz-hb-buffer.html#hb-buffer-has-positions" since="2.7.3"/>
-    <keyword type="function" name="hb_buffer_get_invisible_glyph ()" link="harfbuzz-hb-buffer.html#hb-buffer-get-invisible-glyph" since="2.0.0"/>
     <keyword type="function" name="hb_buffer_set_invisible_glyph ()" link="harfbuzz-hb-buffer.html#hb-buffer-set-invisible-glyph" since="2.0.0"/>
-    <keyword type="function" name="hb_buffer_get_not_found_glyph ()" link="harfbuzz-hb-buffer.html#hb-buffer-get-not-found-glyph" since="3.1.0"/>
+    <keyword type="function" name="hb_buffer_get_invisible_glyph ()" link="harfbuzz-hb-buffer.html#hb-buffer-get-invisible-glyph" since="2.0.0"/>
     <keyword type="function" name="hb_buffer_set_not_found_glyph ()" link="harfbuzz-hb-buffer.html#hb-buffer-set-not-found-glyph" since="3.1.0"/>
+    <keyword type="function" name="hb_buffer_get_not_found_glyph ()" link="harfbuzz-hb-buffer.html#hb-buffer-get-not-found-glyph" since="3.1.0"/>
     <keyword type="function" name="hb_buffer_set_replacement_codepoint ()" link="harfbuzz-hb-buffer.html#hb-buffer-set-replacement-codepoint" since="0.9.31"/>
     <keyword type="function" name="hb_buffer_get_replacement_codepoint ()" link="harfbuzz-hb-buffer.html#hb-buffer-get-replacement-codepoint" since="0.9.31"/>
     <keyword type="function" name="hb_buffer_normalize_glyphs ()" link="harfbuzz-hb-buffer.html#hb-buffer-normalize-glyphs" since="0.9.2"/>
     <keyword type="function" name="hb_segment_properties_hash ()" link="harfbuzz-hb-buffer.html#hb-segment-properties-hash" since="0.9.7"/>
     <keyword type="function" name="hb_segment_properties_overlay ()" link="harfbuzz-hb-buffer.html#hb-segment-properties-overlay" since="3.3.0"/>
     <keyword type="function" name="hb_buffer_diff ()" link="harfbuzz-hb-buffer.html#hb-buffer-diff" since="1.5.0"/>
-    <keyword type="function" name="hb_buffer_set_message_func ()" link="harfbuzz-hb-buffer.html#hb-buffer-set-message-func" since="1.1.3"/>
-    <keyword type="function" name="hb_glyph_info_get_glyph_flags ()" link="harfbuzz-hb-buffer.html#hb-glyph-info-get-glyph-flags" since="1.5.0"/>
     <keyword type="function" name="hb_buffer_message_func_t ()" link="harfbuzz-hb-buffer.html#hb-buffer-message-func-t" since="1.1.3"/>
+    <keyword type="function" name="hb_buffer_set_message_func ()" link="harfbuzz-hb-buffer.html#hb-buffer-set-message-func" since="1.1.3"/>
     <keyword type="macro" name="HB_SEGMENT_PROPERTIES_DEFAULT" link="harfbuzz-hb-buffer.html#HB-SEGMENT-PROPERTIES-DEFAULT:CAPS"/>
     <keyword type="macro" name="HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT" link="harfbuzz-hb-buffer.html#HB-BUFFER-REPLACEMENT-CODEPOINT-DEFAULT:CAPS" since="0.9.31"/>
     <keyword type="typedef" name="hb_buffer_t" link="harfbuzz-hb-buffer.html#hb-buffer-t"/>
     <keyword type="enum" name="enum hb_buffer_serialize_format_t" link="harfbuzz-hb-buffer.html#hb-buffer-serialize-format-t" since="0.9.2"/>
     <keyword type="enum" name="enum hb_buffer_serialize_flags_t" link="harfbuzz-hb-buffer.html#hb-buffer-serialize-flags-t" since="0.9.20"/>
     <keyword type="enum" name="enum hb_buffer_diff_flags_t" link="harfbuzz-hb-buffer.html#hb-buffer-diff-flags-t" since="1.5.0"/>
+    <keyword type="macro" name="HB_TAG()" link="harfbuzz-hb-common.html#HB-TAG:CAPS"/>
+    <keyword type="macro" name="HB_UNTAG()" link="harfbuzz-hb-common.html#HB-UNTAG:CAPS" since="0.6.0"/>
     <keyword type="function" name="hb_tag_from_string ()" link="harfbuzz-hb-common.html#hb-tag-from-string" since="0.9.2"/>
     <keyword type="function" name="hb_tag_to_string ()" link="harfbuzz-hb-common.html#hb-tag-to-string" since="0.9.5"/>
     <keyword type="function" name="hb_direction_from_string ()" link="harfbuzz-hb-common.html#hb-direction-from-string" since="0.9.2"/>
     <keyword type="function" name="hb_direction_to_string ()" link="harfbuzz-hb-common.html#hb-direction-to-string" since="0.9.2"/>
+    <keyword type="macro" name="HB_DIRECTION_REVERSE()" link="harfbuzz-hb-common.html#HB-DIRECTION-REVERSE:CAPS"/>
+    <keyword type="macro" name="HB_DIRECTION_IS_BACKWARD()" link="harfbuzz-hb-common.html#HB-DIRECTION-IS-BACKWARD:CAPS"/>
+    <keyword type="macro" name="HB_DIRECTION_IS_FORWARD()" link="harfbuzz-hb-common.html#HB-DIRECTION-IS-FORWARD:CAPS"/>
+    <keyword type="macro" name="HB_DIRECTION_IS_HORIZONTAL()" link="harfbuzz-hb-common.html#HB-DIRECTION-IS-HORIZONTAL:CAPS"/>
+    <keyword type="macro" name="HB_DIRECTION_IS_VALID()" link="harfbuzz-hb-common.html#HB-DIRECTION-IS-VALID:CAPS"/>
+    <keyword type="macro" name="HB_DIRECTION_IS_VERTICAL()" link="harfbuzz-hb-common.html#HB-DIRECTION-IS-VERTICAL:CAPS"/>
     <keyword type="function" name="hb_script_from_iso15924_tag ()" link="harfbuzz-hb-common.html#hb-script-from-iso15924-tag" since="0.9.2"/>
-    <keyword type="function" name="hb_script_from_string ()" link="harfbuzz-hb-common.html#hb-script-from-string" since="0.9.2"/>
     <keyword type="function" name="hb_script_to_iso15924_tag ()" link="harfbuzz-hb-common.html#hb-script-to-iso15924-tag" since="0.9.2"/>
+    <keyword type="function" name="hb_script_from_string ()" link="harfbuzz-hb-common.html#hb-script-from-string" since="0.9.2"/>
     <keyword type="function" name="hb_script_get_horizontal_direction ()" link="harfbuzz-hb-common.html#hb-script-get-horizontal-direction" since="0.9.2"/>
     <keyword type="function" name="hb_language_from_string ()" link="harfbuzz-hb-common.html#hb-language-from-string" since="0.9.2"/>
     <keyword type="function" name="hb_language_to_string ()" link="harfbuzz-hb-common.html#hb-language-to-string" since="0.9.2"/>
     <keyword type="function" name="hb_language_get_default ()" link="harfbuzz-hb-common.html#hb-language-get-default" since="0.9.2"/>
+    <keyword type="function" name="hb_language_matches ()" link="harfbuzz-hb-common.html#hb-language-matches" since="5.0.0"/>
     <keyword type="function" name="hb_feature_from_string ()" link="harfbuzz-hb-common.html#hb-feature-from-string" since="0.9.5"/>
     <keyword type="function" name="hb_feature_to_string ()" link="harfbuzz-hb-common.html#hb-feature-to-string" since="0.9.5"/>
     <keyword type="function" name="hb_variation_from_string ()" link="harfbuzz-hb-common.html#hb-variation-from-string" since="1.4.2"/>
     <keyword type="function" name="hb_variation_to_string ()" link="harfbuzz-hb-common.html#hb-variation-to-string" since="1.4.2"/>
     <keyword type="function" name="hb_destroy_func_t ()" link="harfbuzz-hb-common.html#hb-destroy-func-t"/>
-    <keyword type="macro" name="HB_TAG()" link="harfbuzz-hb-common.html#HB-TAG:CAPS"/>
-    <keyword type="macro" name="HB_UNTAG()" link="harfbuzz-hb-common.html#HB-UNTAG:CAPS" since="0.6.0"/>
-    <keyword type="macro" name="HB_DIRECTION_REVERSE()" link="harfbuzz-hb-common.html#HB-DIRECTION-REVERSE:CAPS"/>
-    <keyword type="macro" name="HB_DIRECTION_IS_BACKWARD()" link="harfbuzz-hb-common.html#HB-DIRECTION-IS-BACKWARD:CAPS"/>
-    <keyword type="macro" name="HB_DIRECTION_IS_FORWARD()" link="harfbuzz-hb-common.html#HB-DIRECTION-IS-FORWARD:CAPS"/>
-    <keyword type="macro" name="HB_DIRECTION_IS_HORIZONTAL()" link="harfbuzz-hb-common.html#HB-DIRECTION-IS-HORIZONTAL:CAPS"/>
-    <keyword type="macro" name="HB_DIRECTION_IS_VALID()" link="harfbuzz-hb-common.html#HB-DIRECTION-IS-VALID:CAPS"/>
-    <keyword type="macro" name="HB_DIRECTION_IS_VERTICAL()" link="harfbuzz-hb-common.html#HB-DIRECTION-IS-VERTICAL:CAPS"/>
     <keyword type="typedef" name="hb_bool_t" link="harfbuzz-hb-common.html#hb-bool-t"/>
     <keyword type="typedef" name="hb_codepoint_t" link="harfbuzz-hb-common.html#hb-codepoint-t"/>
+    <keyword type="macro" name="HB_CODEPOINT_INVALID" link="harfbuzz-hb-common.html#HB-CODEPOINT-INVALID:CAPS" since="8.0.0"/>
     <keyword type="enum" name="enum hb_direction_t" link="harfbuzz-hb-common.html#hb-direction-t"/>
     <keyword type="typedef" name="hb_language_t" link="harfbuzz-hb-common.html#hb-language-t"/>
     <keyword type="struct" name="hb_feature_t" link="harfbuzz-hb-common.html#hb-feature-t"/>
     <keyword type="macro" name="HB_LANGUAGE_INVALID" link="harfbuzz-hb-common.html#HB-LANGUAGE-INVALID:CAPS" since="0.6.0"/>
     <keyword type="macro" name="HB_FEATURE_GLOBAL_END" link="harfbuzz-hb-common.html#HB-FEATURE-GLOBAL-END:CAPS" since="2.0.0"/>
     <keyword type="macro" name="HB_FEATURE_GLOBAL_START" link="harfbuzz-hb-common.html#HB-FEATURE-GLOBAL-START:CAPS" since="2.0.0"/>
+    <keyword type="macro" name="HB_HAS_FREETYPE" link="harfbuzz-hb-features.html#HB-HAS-FREETYPE:CAPS"/>
+    <keyword type="macro" name="HB_HAS_GLIB" link="harfbuzz-hb-features.html#HB-HAS-GLIB:CAPS"/>
+    <keyword type="function" name="hb_draw_funcs_create ()" link="harfbuzz-hb-draw.html#hb-draw-funcs-create" since="4.0.0"/>
+    <keyword type="function" name="hb_draw_funcs_get_empty ()" link="harfbuzz-hb-draw.html#hb-draw-funcs-get-empty" since="7.0.0"/>
+    <keyword type="function" name="hb_draw_funcs_reference ()" link="harfbuzz-hb-draw.html#hb-draw-funcs-reference" since="4.0.0"/>
+    <keyword type="function" name="hb_draw_funcs_destroy ()" link="harfbuzz-hb-draw.html#hb-draw-funcs-destroy" since="4.0.0"/>
+    <keyword type="function" name="hb_draw_funcs_set_user_data ()" link="harfbuzz-hb-draw.html#hb-draw-funcs-set-user-data" since="7.0.0"/>
+    <keyword type="function" name="hb_draw_funcs_get_user_data ()" link="harfbuzz-hb-draw.html#hb-draw-funcs-get-user-data" since="7.0.0"/>
+    <keyword type="function" name="hb_draw_funcs_make_immutable ()" link="harfbuzz-hb-draw.html#hb-draw-funcs-make-immutable" since="4.0.0"/>
+    <keyword type="function" name="hb_draw_funcs_is_immutable ()" link="harfbuzz-hb-draw.html#hb-draw-funcs-is-immutable" since="4.0.0"/>
+    <keyword type="function" name="hb_draw_move_to_func_t ()" link="harfbuzz-hb-draw.html#hb-draw-move-to-func-t" since="4.0.0"/>
+    <keyword type="function" name="hb_draw_funcs_set_move_to_func ()" link="harfbuzz-hb-draw.html#hb-draw-funcs-set-move-to-func" since="4.0.0"/>
+    <keyword type="function" name="hb_draw_line_to_func_t ()" link="harfbuzz-hb-draw.html#hb-draw-line-to-func-t" since="4.0.0"/>
+    <keyword type="function" name="hb_draw_funcs_set_line_to_func ()" link="harfbuzz-hb-draw.html#hb-draw-funcs-set-line-to-func" since="4.0.0"/>
+    <keyword type="function" name="hb_draw_quadratic_to_func_t ()" link="harfbuzz-hb-draw.html#hb-draw-quadratic-to-func-t" since="4.0.0"/>
+    <keyword type="function" name="hb_draw_funcs_set_quadratic_to_func ()" link="harfbuzz-hb-draw.html#hb-draw-funcs-set-quadratic-to-func" since="4.0.0"/>
+    <keyword type="function" name="hb_draw_cubic_to_func_t ()" link="harfbuzz-hb-draw.html#hb-draw-cubic-to-func-t" since="4.0.0"/>
+    <keyword type="function" name="hb_draw_funcs_set_cubic_to_func ()" link="harfbuzz-hb-draw.html#hb-draw-funcs-set-cubic-to-func" since="4.0.0"/>
+    <keyword type="function" name="hb_draw_close_path_func_t ()" link="harfbuzz-hb-draw.html#hb-draw-close-path-func-t" since="4.0.0"/>
+    <keyword type="function" name="hb_draw_funcs_set_close_path_func ()" link="harfbuzz-hb-draw.html#hb-draw-funcs-set-close-path-func" since="4.0.0"/>
+    <keyword type="function" name="hb_draw_move_to ()" link="harfbuzz-hb-draw.html#hb-draw-move-to" since="4.0.0"/>
+    <keyword type="function" name="hb_draw_line_to ()" link="harfbuzz-hb-draw.html#hb-draw-line-to" since="4.0.0"/>
+    <keyword type="function" name="hb_draw_quadratic_to ()" link="harfbuzz-hb-draw.html#hb-draw-quadratic-to" since="4.0.0"/>
+    <keyword type="function" name="hb_draw_cubic_to ()" link="harfbuzz-hb-draw.html#hb-draw-cubic-to" since="4.0.0"/>
+    <keyword type="function" name="hb_draw_close_path ()" link="harfbuzz-hb-draw.html#hb-draw-close-path" since="4.0.0"/>
+    <keyword type="macro" name="HB_DRAW_STATE_DEFAULT" link="harfbuzz-hb-draw.html#HB-DRAW-STATE-DEFAULT:CAPS"/>
+    <keyword type="typedef" name="hb_draw_funcs_t" link="harfbuzz-hb-draw.html#hb-draw-funcs-t" since="4.0.0"/>
+    <keyword type="struct" name="hb_draw_state_t" link="harfbuzz-hb-draw.html#hb-draw-state-t" since="4.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_create ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-create" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_get_empty ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-get-empty" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_reference ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-reference" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_destroy ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-destroy" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_set_user_data ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-set-user-data" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_get_user_data ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-get-user-data" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_make_immutable ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-make-immutable" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_is_immutable ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-is-immutable" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_push_transform_func_t ()" link="harfbuzz-hb-paint.html#hb-paint-push-transform-func-t" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_set_push_transform_func ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-transform-func" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_pop_transform_func_t ()" link="harfbuzz-hb-paint.html#hb-paint-pop-transform-func-t" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_set_pop_transform_func ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-set-pop-transform-func" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_color_glyph_func_t ()" link="harfbuzz-hb-paint.html#hb-paint-color-glyph-func-t" since="8.2.0"/>
+    <keyword type="function" name="hb_paint_funcs_set_color_glyph_func ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-set-color-glyph-func" since="8.2.0"/>
+    <keyword type="function" name="hb_paint_push_clip_glyph_func_t ()" link="harfbuzz-hb-paint.html#hb-paint-push-clip-glyph-func-t" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_set_push_clip_glyph_func ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-clip-glyph-func" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_push_clip_rectangle_func_t ()" link="harfbuzz-hb-paint.html#hb-paint-push-clip-rectangle-func-t" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_set_push_clip_rectangle_func ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-clip-rectangle-func" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_pop_clip_func_t ()" link="harfbuzz-hb-paint.html#hb-paint-pop-clip-func-t" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_set_pop_clip_func ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-set-pop-clip-func" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_color_func_t ()" link="harfbuzz-hb-paint.html#hb-paint-color-func-t" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_set_color_func ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-set-color-func" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_image_func_t ()" link="harfbuzz-hb-paint.html#hb-paint-image-func-t" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_set_image_func ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-set-image-func" since="7.0.0"/>
+    <keyword type="function" name="hb_color_line_get_color_stops_func_t ()" link="harfbuzz-hb-paint.html#hb-color-line-get-color-stops-func-t" since="7.0.0"/>
+    <keyword type="function" name="hb_color_line_get_color_stops ()" link="harfbuzz-hb-paint.html#hb-color-line-get-color-stops" since="7.0.0"/>
+    <keyword type="function" name="hb_color_line_get_extend_func_t ()" link="harfbuzz-hb-paint.html#hb-color-line-get-extend-func-t" since="7.0.0"/>
+    <keyword type="function" name="hb_color_line_get_extend ()" link="harfbuzz-hb-paint.html#hb-color-line-get-extend" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_linear_gradient_func_t ()" link="harfbuzz-hb-paint.html#hb-paint-linear-gradient-func-t" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_set_linear_gradient_func ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-set-linear-gradient-func" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_radial_gradient_func_t ()" link="harfbuzz-hb-paint.html#hb-paint-radial-gradient-func-t" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_set_radial_gradient_func ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-set-radial-gradient-func" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_sweep_gradient_func_t ()" link="harfbuzz-hb-paint.html#hb-paint-sweep-gradient-func-t" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_set_sweep_gradient_func ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-set-sweep-gradient-func" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_push_group_func_t ()" link="harfbuzz-hb-paint.html#hb-paint-push-group-func-t" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_set_push_group_func ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-set-push-group-func" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_pop_group_func_t ()" link="harfbuzz-hb-paint.html#hb-paint-pop-group-func-t" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_set_pop_group_func ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-set-pop-group-func" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_custom_palette_color_func_t ()" link="harfbuzz-hb-paint.html#hb-paint-custom-palette-color-func-t" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_funcs_set_custom_palette_color_func ()" link="harfbuzz-hb-paint.html#hb-paint-funcs-set-custom-palette-color-func" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_push_transform ()" link="harfbuzz-hb-paint.html#hb-paint-push-transform" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_pop_transform ()" link="harfbuzz-hb-paint.html#hb-paint-pop-transform" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_color_glyph ()" link="harfbuzz-hb-paint.html#hb-paint-color-glyph" since="8.2.0"/>
+    <keyword type="function" name="hb_paint_push_clip_glyph ()" link="harfbuzz-hb-paint.html#hb-paint-push-clip-glyph" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_push_clip_rectangle ()" link="harfbuzz-hb-paint.html#hb-paint-push-clip-rectangle" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_pop_clip ()" link="harfbuzz-hb-paint.html#hb-paint-pop-clip" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_color ()" link="harfbuzz-hb-paint.html#hb-paint-color" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_image ()" link="harfbuzz-hb-paint.html#hb-paint-image" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_linear_gradient ()" link="harfbuzz-hb-paint.html#hb-paint-linear-gradient" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_radial_gradient ()" link="harfbuzz-hb-paint.html#hb-paint-radial-gradient" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_sweep_gradient ()" link="harfbuzz-hb-paint.html#hb-paint-sweep-gradient" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_push_group ()" link="harfbuzz-hb-paint.html#hb-paint-push-group" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_pop_group ()" link="harfbuzz-hb-paint.html#hb-paint-pop-group" since="7.0.0"/>
+    <keyword type="function" name="hb_paint_custom_palette_color ()" link="harfbuzz-hb-paint.html#hb-paint-custom-palette-color" since="7.0.0"/>
+    <keyword type="typedef" name="hb_paint_funcs_t" link="harfbuzz-hb-paint.html#hb-paint-funcs-t" since="7.0.0"/>
+    <keyword type="macro" name="HB_PAINT_IMAGE_FORMAT_PNG" link="harfbuzz-hb-paint.html#HB-PAINT-IMAGE-FORMAT-PNG:CAPS" since="7.0.0"/>
+    <keyword type="macro" name="HB_PAINT_IMAGE_FORMAT_SVG" link="harfbuzz-hb-paint.html#HB-PAINT-IMAGE-FORMAT-SVG:CAPS" since="7.0.0"/>
+    <keyword type="macro" name="HB_PAINT_IMAGE_FORMAT_BGRA" link="harfbuzz-hb-paint.html#HB-PAINT-IMAGE-FORMAT-BGRA:CAPS" since="7.0.0"/>
+    <keyword type="typedef" name="hb_color_line_t" link="harfbuzz-hb-paint.html#hb-color-line-t" since="7.0.0"/>
+    <keyword type="struct" name="hb_color_stop_t" link="harfbuzz-hb-paint.html#hb-color-stop-t" since="7.0.0"/>
+    <keyword type="enum" name="enum hb_paint_extend_t" link="harfbuzz-hb-paint.html#hb-paint-extend-t" since="7.0.0"/>
+    <keyword type="enum" name="enum hb_paint_composite_mode_t" link="harfbuzz-hb-paint.html#hb-paint-composite-mode-t" since="7.0.0"/>
+    <keyword type="function" name="hb_font_funcs_set_glyph_func ()" link="harfbuzz-hb-deprecated.html#hb-font-funcs-set-glyph-func" deprecated="1.2.3" since="0.9.2"/>
     <keyword type="function" name="hb_font_get_glyph_func_t ()" link="harfbuzz-hb-deprecated.html#hb-font-get-glyph-func-t" deprecated="1.2.3"/>
+    <keyword type="function" name="hb_ot_layout_table_choose_script ()" link="harfbuzz-hb-deprecated.html#hb-ot-layout-table-choose-script" deprecated=""/>
     <keyword type="function" name="hb_ot_layout_table_find_script ()" link="harfbuzz-hb-deprecated.html#hb-ot-layout-table-find-script"/>
+    <keyword type="function" name="hb_ot_tag_from_language ()" link="harfbuzz-hb-deprecated.html#hb-ot-tag-from-language" deprecated="2.0.0: use hb_ot_tags_from_script_and_language() instead" since="0.6.0"/>
+    <keyword type="function" name="hb_ot_tags_from_script ()" link="harfbuzz-hb-deprecated.html#hb-ot-tags-from-script" deprecated="2.0.0: use hb_ot_tags_from_script_and_language() instead" since="0.6.0"/>
+    <keyword type="function" name="hb_ot_var_find_axis ()" link="harfbuzz-hb-deprecated.html#hb-ot-var-find-axis" deprecated="2.2.0 - use hb_ot_var_find_axis_info() instead" since="1.4.2"/>
+    <keyword type="function" name="hb_ot_var_get_axes ()" link="harfbuzz-hb-deprecated.html#hb-ot-var-get-axes" deprecated="2.2.0: use hb_ot_var_get_axis_infos() instead" since="1.4.2"/>
     <keyword type="function" name="hb_unicode_eastasian_width_func_t ()" link="harfbuzz-hb-deprecated.html#hb-unicode-eastasian-width-func-t" deprecated="2.0.0"/>
     <keyword type="function" name="hb_unicode_eastasian_width ()" link="harfbuzz-hb-deprecated.html#hb-unicode-eastasian-width" deprecated="2.0.0" since="0.9.2"/>
     <keyword type="function" name="hb_unicode_funcs_set_eastasian_width_func ()" link="harfbuzz-hb-deprecated.html#hb-unicode-funcs-set-eastasian-width-func" deprecated="2.0.0" since="0.9.2"/>
     <keyword type="function" name="hb_unicode_decompose_compatibility ()" link="harfbuzz-hb-deprecated.html#hb-unicode-decompose-compatibility" deprecated="2.0.0" since="0.9.2"/>
     <keyword type="function" name="hb_unicode_funcs_set_decompose_compatibility_func ()" link="harfbuzz-hb-deprecated.html#hb-unicode-funcs-set-decompose-compatibility-func" deprecated="2.0.0" since="0.9.2"/>
     <keyword type="function" name="hb_font_funcs_set_glyph_v_kerning_func ()" link="harfbuzz-hb-deprecated.html#hb-font-funcs-set-glyph-v-kerning-func" deprecated="2.0.0" since="0.9.2"/>
+    <keyword type="function" name="hb_font_get_glyph_shape ()" link="harfbuzz-hb-deprecated.html#hb-font-get-glyph-shape" deprecated="7.0.0: Use hb_font_draw_glyph() instead" since="4.0.0"/>
+    <keyword type="function" name="hb_font_get_glyph_shape_func_t ()" link="harfbuzz-hb-deprecated.html#hb-font-get-glyph-shape-func-t" deprecated="7.0.0: Use #hb_font_draw_glyph_func_t instead" since="4.0.0"/>
+    <keyword type="function" name="hb_font_funcs_set_glyph_shape_func ()" link="harfbuzz-hb-deprecated.html#hb-font-funcs-set-glyph-shape-func" deprecated="7.0.0: Use hb_font_funcs_set_draw_glyph_func() instead" since="4.0.0"/>
     <keyword type="function" name="hb_font_get_glyph_v_kerning ()" link="harfbuzz-hb-deprecated.html#hb-font-get-glyph-v-kerning" deprecated="2.0.0" since="0.9.2"/>
     <keyword type="macro" name="HB_BUFFER_FLAGS_DEFAULT" link="harfbuzz-hb-deprecated.html#HB-BUFFER-FLAGS-DEFAULT:CAPS" deprecated="0.9.20"/>
     <keyword type="macro" name="HB_BUFFER_SERIALIZE_FLAGS_DEFAULT" link="harfbuzz-hb-deprecated.html#HB-BUFFER-SERIALIZE-FLAGS-DEFAULT:CAPS" deprecated="0.9.20"/>
     <keyword type="macro" name="HB_OT_VAR_NO_AXIS_INDEX" link="harfbuzz-hb-deprecated.html#HB-OT-VAR-NO-AXIS-INDEX:CAPS" deprecated="2.2.0" since="1.4.2"/>
     <keyword type="struct" name="hb_ot_var_axis_t" link="harfbuzz-hb-deprecated.html#hb-ot-var-axis-t" deprecated="2.2.0" since="1.4.2"/>
     <keyword type="macro" name="HB_UNICODE_MAX_DECOMPOSITION_LEN" link="harfbuzz-hb-deprecated.html#HB-UNICODE-MAX-DECOMPOSITION-LEN:CAPS" deprecated="2.0.0"/>
+    <keyword type="macro" name="HB_UNICODE_COMBINING_CLASS_CCC133" link="harfbuzz-hb-deprecated.html#HB-UNICODE-COMBINING-CLASS-CCC133:CAPS" deprecated="7.2.0"/>
     <keyword type="typedef" name="hb_font_get_glyph_v_kerning_func_t" link="harfbuzz-hb-deprecated.html#hb-font-get-glyph-v-kerning-func-t" deprecated=""/>
     <keyword type="function" name="hb_face_count ()" link="harfbuzz-hb-face.html#hb-face-count" since="1.7.7"/>
     <keyword type="function" name="hb_face_create ()" link="harfbuzz-hb-face.html#hb-face-create" since="0.9.2"/>
     <keyword type="function" name="hb_face_create_for_tables ()" link="harfbuzz-hb-face.html#hb-face-create-for-tables" since="0.9.2"/>
-    <keyword type="function" name="hb_face_destroy ()" link="harfbuzz-hb-face.html#hb-face-destroy" since="0.9.2"/>
     <keyword type="function" name="hb_face_get_empty ()" link="harfbuzz-hb-face.html#hb-face-get-empty" since="0.9.2"/>
+    <keyword type="function" name="hb_face_reference ()" link="harfbuzz-hb-face.html#hb-face-reference" since="0.9.2"/>
+    <keyword type="function" name="hb_face_destroy ()" link="harfbuzz-hb-face.html#hb-face-destroy" since="0.9.2"/>
+    <keyword type="function" name="hb_face_set_user_data ()" link="harfbuzz-hb-face.html#hb-face-set-user-data" since="0.9.2"/>
+    <keyword type="function" name="hb_face_get_user_data ()" link="harfbuzz-hb-face.html#hb-face-get-user-data" since="0.9.2"/>
+    <keyword type="function" name="hb_face_make_immutable ()" link="harfbuzz-hb-face.html#hb-face-make-immutable" since="0.9.2"/>
+    <keyword type="function" name="hb_face_is_immutable ()" link="harfbuzz-hb-face.html#hb-face-is-immutable" since="0.9.2"/>
     <keyword type="function" name="hb_face_get_table_tags ()" link="harfbuzz-hb-face.html#hb-face-get-table-tags" since="1.6.0"/>
+    <keyword type="function" name="hb_face_set_glyph_count ()" link="harfbuzz-hb-face.html#hb-face-set-glyph-count" since="0.9.7"/>
     <keyword type="function" name="hb_face_get_glyph_count ()" link="harfbuzz-hb-face.html#hb-face-get-glyph-count" since="0.9.7"/>
+    <keyword type="function" name="hb_face_set_index ()" link="harfbuzz-hb-face.html#hb-face-set-index" since="0.9.2"/>
     <keyword type="function" name="hb_face_get_index ()" link="harfbuzz-hb-face.html#hb-face-get-index" since="0.9.2"/>
+    <keyword type="function" name="hb_face_set_upem ()" link="harfbuzz-hb-face.html#hb-face-set-upem" since="0.9.2"/>
     <keyword type="function" name="hb_face_get_upem ()" link="harfbuzz-hb-face.html#hb-face-get-upem" since="0.9.2"/>
-    <keyword type="function" name="hb_face_get_user_data ()" link="harfbuzz-hb-face.html#hb-face-get-user-data" since="0.9.2"/>
-    <keyword type="function" name="hb_face_is_immutable ()" link="harfbuzz-hb-face.html#hb-face-is-immutable" since="0.9.2"/>
-    <keyword type="function" name="hb_face_make_immutable ()" link="harfbuzz-hb-face.html#hb-face-make-immutable" since="0.9.2"/>
-    <keyword type="function" name="hb_face_reference ()" link="harfbuzz-hb-face.html#hb-face-reference" since="0.9.2"/>
     <keyword type="function" name="hb_face_reference_blob ()" link="harfbuzz-hb-face.html#hb-face-reference-blob" since="0.9.2"/>
     <keyword type="function" name="hb_face_reference_table ()" link="harfbuzz-hb-face.html#hb-face-reference-table" since="0.9.2"/>
-    <keyword type="function" name="hb_face_set_glyph_count ()" link="harfbuzz-hb-face.html#hb-face-set-glyph-count" since="0.9.7"/>
-    <keyword type="function" name="hb_face_set_index ()" link="harfbuzz-hb-face.html#hb-face-set-index" since="0.9.2"/>
-    <keyword type="function" name="hb_face_set_upem ()" link="harfbuzz-hb-face.html#hb-face-set-upem" since="0.9.2"/>
-    <keyword type="function" name="hb_face_set_user_data ()" link="harfbuzz-hb-face.html#hb-face-set-user-data" since="0.9.2"/>
     <keyword type="function" name="hb_face_collect_unicodes ()" link="harfbuzz-hb-face.html#hb-face-collect-unicodes" since="1.9.0"/>
+    <keyword type="function" name="hb_face_collect_nominal_glyph_mapping ()" link="harfbuzz-hb-face.html#hb-face-collect-nominal-glyph-mapping" since="7.0.0"/>
     <keyword type="function" name="hb_face_collect_variation_selectors ()" link="harfbuzz-hb-face.html#hb-face-collect-variation-selectors" since="1.9.0"/>
     <keyword type="function" name="hb_face_collect_variation_unicodes ()" link="harfbuzz-hb-face.html#hb-face-collect-variation-unicodes" since="1.9.0"/>
     <keyword type="function" name="hb_face_builder_create ()" link="harfbuzz-hb-face.html#hb-face-builder-create" since="1.9.0"/>
     <keyword type="function" name="hb_face_builder_add_table ()" link="harfbuzz-hb-face.html#hb-face-builder-add-table" since="1.9.0"/>
+    <keyword type="function" name="hb_face_builder_sort_tables ()" link="harfbuzz-hb-face.html#hb-face-builder-sort-tables" since="5.3.0"/>
     <keyword type="typedef" name="hb_face_t" link="harfbuzz-hb-face.html#hb-face-t"/>
     <keyword type="function" name="hb_font_add_glyph_origin_for_direction ()" link="harfbuzz-hb-font.html#hb-font-add-glyph-origin-for-direction" since="0.9.2"/>
     <keyword type="function" name="hb_font_create ()" link="harfbuzz-hb-font.html#hb-font-create" since="0.9.2"/>
     <keyword type="function" name="hb_font_create_sub_font ()" link="harfbuzz-hb-font.html#hb-font-create-sub-font" since="0.9.2"/>
-    <keyword type="function" name="hb_font_destroy ()" link="harfbuzz-hb-font.html#hb-font-destroy" since="0.9.2"/>
-    <keyword type="function" name="hb_font_funcs_create ()" link="harfbuzz-hb-font.html#hb-font-funcs-create" since="0.9.2"/>
-    <keyword type="function" name="hb_font_funcs_destroy ()" link="harfbuzz-hb-font.html#hb-font-funcs-destroy" since="0.9.2"/>
-    <keyword type="function" name="hb_font_funcs_get_empty ()" link="harfbuzz-hb-font.html#hb-font-funcs-get-empty" since="0.9.2"/>
-    <keyword type="function" name="hb_font_funcs_get_user_data ()" link="harfbuzz-hb-font.html#hb-font-funcs-get-user-data" since="0.9.2"/>
-    <keyword type="function" name="hb_font_funcs_is_immutable ()" link="harfbuzz-hb-font.html#hb-font-funcs-is-immutable" since="0.9.2"/>
-    <keyword type="function" name="hb_font_funcs_make_immutable ()" link="harfbuzz-hb-font.html#hb-font-funcs-make-immutable" since="0.9.2"/>
-    <keyword type="function" name="hb_font_funcs_reference ()" link="harfbuzz-hb-font.html#hb-font-funcs-reference" since="0.9.2"/>
-    <keyword type="function" name="hb_font_funcs_set_glyph_contour_point_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-contour-point-func" since="0.9.2"/>
-    <keyword type="function" name="hb_font_funcs_set_glyph_extents_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-extents-func" since="0.9.2"/>
-    <keyword type="function" name="hb_font_funcs_set_glyph_from_name_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-from-name-func" since="0.9.2"/>
-    <keyword type="function" name="hb_font_funcs_set_glyph_h_advance_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-h-advance-func" since="0.9.2"/>
-    <keyword type="function" name="hb_font_funcs_set_glyph_h_advances_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-h-advances-func" since="1.8.6"/>
-    <keyword type="function" name="hb_font_funcs_set_glyph_h_kerning_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-h-kerning-func" since="0.9.2"/>
-    <keyword type="function" name="hb_font_funcs_set_glyph_h_origin_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-h-origin-func" since="0.9.2"/>
-    <keyword type="function" name="hb_font_funcs_set_glyph_name_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-name-func" since="0.9.2"/>
-    <keyword type="function" name="hb_font_funcs_set_glyph_v_advance_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-v-advance-func" since="0.9.2"/>
-    <keyword type="function" name="hb_font_funcs_set_glyph_v_advances_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-v-advances-func" since="1.8.6"/>
-    <keyword type="function" name="hb_font_funcs_set_glyph_v_origin_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-v-origin-func" since="0.9.2"/>
-    <keyword type="function" name="hb_font_funcs_set_nominal_glyph_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-nominal-glyph-func" since="1.2.3"/>
-    <keyword type="function" name="hb_font_funcs_set_nominal_glyphs_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-nominal-glyphs-func" since="2.0.0"/>
-    <keyword type="function" name="hb_font_funcs_set_user_data ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-user-data" since="0.9.2"/>
-    <keyword type="function" name="hb_font_funcs_set_variation_glyph_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-variation-glyph-func" since="1.2.3"/>
     <keyword type="function" name="hb_font_get_empty ()" link="harfbuzz-hb-font.html#hb-font-get-empty" since="0.9.2"/>
+    <keyword type="function" name="hb_font_reference ()" link="harfbuzz-hb-font.html#hb-font-reference" since="0.9.2"/>
+    <keyword type="function" name="hb_font_destroy ()" link="harfbuzz-hb-font.html#hb-font-destroy" since="0.9.2"/>
+    <keyword type="function" name="hb_font_set_user_data ()" link="harfbuzz-hb-font.html#hb-font-set-user-data" since="0.9.2"/>
+    <keyword type="function" name="hb_font_get_user_data ()" link="harfbuzz-hb-font.html#hb-font-get-user-data" since="0.9.2"/>
+    <keyword type="function" name="hb_font_make_immutable ()" link="harfbuzz-hb-font.html#hb-font-make-immutable" since="0.9.2"/>
+    <keyword type="function" name="hb_font_is_immutable ()" link="harfbuzz-hb-font.html#hb-font-is-immutable" since="0.9.2"/>
+    <keyword type="function" name="hb_font_set_face ()" link="harfbuzz-hb-font.html#hb-font-set-face" since="1.4.3"/>
     <keyword type="function" name="hb_font_get_face ()" link="harfbuzz-hb-font.html#hb-font-get-face" since="0.9.2"/>
     <keyword type="function" name="hb_font_get_glyph ()" link="harfbuzz-hb-font.html#hb-font-get-glyph" since="0.9.2"/>
     <keyword type="function" name="hb_font_get_glyph_advance_for_direction ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-advance-for-direction" since="0.9.2"/>
-    <keyword type="function" name="hb_font_get_glyph_advance_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-advance-func-t"/>
     <keyword type="function" name="hb_font_get_glyph_advances_for_direction ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-advances-for-direction" since="1.8.6"/>
-    <keyword type="function" name="hb_font_get_glyph_advances_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-advances-func-t"/>
     <keyword type="function" name="hb_font_get_glyph_contour_point ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-contour-point" since="0.9.2"/>
     <keyword type="function" name="hb_font_get_glyph_contour_point_for_origin ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-contour-point-for-origin" since="0.9.2"/>
-    <keyword type="function" name="hb_font_get_glyph_contour_point_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-contour-point-func-t"/>
     <keyword type="function" name="hb_font_get_glyph_extents ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-extents" since="0.9.2"/>
     <keyword type="function" name="hb_font_get_glyph_extents_for_origin ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-extents-for-origin" since="0.9.2"/>
-    <keyword type="function" name="hb_font_get_glyph_extents_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-extents-func-t"/>
     <keyword type="function" name="hb_font_get_glyph_from_name ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-from-name" since="0.9.2"/>
-    <keyword type="function" name="hb_font_get_glyph_from_name_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-from-name-func-t"/>
     <keyword type="function" name="hb_font_get_glyph_h_advance ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-h-advance" since="0.9.2"/>
+    <keyword type="function" name="hb_font_get_glyph_v_advance ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-v-advance" since="0.9.2"/>
     <keyword type="function" name="hb_font_get_glyph_h_advances ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-h-advances" since="1.8.6"/>
+    <keyword type="function" name="hb_font_get_glyph_v_advances ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-v-advances" since="1.8.6"/>
     <keyword type="function" name="hb_font_get_glyph_h_kerning ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-h-kerning" since="0.9.2"/>
-    <keyword type="function" name="hb_font_get_glyph_h_origin ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-h-origin" since="0.9.2"/>
     <keyword type="function" name="hb_font_get_glyph_kerning_for_direction ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-kerning-for-direction" since="0.9.2"/>
-    <keyword type="function" name="hb_font_get_glyph_kerning_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-kerning-func-t"/>
-    <keyword type="function" name="hb_font_get_glyph_name ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-name" since="0.9.2"/>
-    <keyword type="function" name="hb_font_get_glyph_name_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-name-func-t"/>
-    <keyword type="function" name="hb_font_get_glyph_origin_for_direction ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-origin-for-direction" since="0.9.2"/>
-    <keyword type="function" name="hb_font_get_glyph_origin_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-origin-func-t"/>
-    <keyword type="function" name="hb_font_get_glyph_v_advance ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-v-advance" since="0.9.2"/>
-    <keyword type="function" name="hb_font_get_glyph_v_advances ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-v-advances" since="1.8.6"/>
+    <keyword type="function" name="hb_font_get_glyph_h_origin ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-h-origin" since="0.9.2"/>
     <keyword type="function" name="hb_font_get_glyph_v_origin ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-v-origin" since="0.9.2"/>
+    <keyword type="function" name="hb_font_get_glyph_origin_for_direction ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-origin-for-direction" since="0.9.2"/>
+    <keyword type="function" name="hb_font_get_glyph_name ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-name" since="0.9.2"/>
+    <keyword type="function" name="hb_font_draw_glyph ()" link="harfbuzz-hb-font.html#hb-font-draw-glyph" since="7.0.0"/>
+    <keyword type="function" name="hb_font_paint_glyph ()" link="harfbuzz-hb-font.html#hb-font-paint-glyph" since="7.0.0"/>
     <keyword type="function" name="hb_font_get_nominal_glyph ()" link="harfbuzz-hb-font.html#hb-font-get-nominal-glyph" since="1.2.3"/>
-    <keyword type="function" name="hb_font_get_nominal_glyph_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-nominal-glyph-func-t"/>
     <keyword type="function" name="hb_font_get_nominal_glyphs ()" link="harfbuzz-hb-font.html#hb-font-get-nominal-glyphs" since="2.6.3"/>
-    <keyword type="function" name="hb_font_get_nominal_glyphs_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-nominal-glyphs-func-t"/>
+    <keyword type="function" name="hb_font_get_variation_glyph ()" link="harfbuzz-hb-font.html#hb-font-get-variation-glyph" since="1.2.3"/>
+    <keyword type="function" name="hb_font_set_parent ()" link="harfbuzz-hb-font.html#hb-font-set-parent" since="1.0.5"/>
     <keyword type="function" name="hb_font_get_parent ()" link="harfbuzz-hb-font.html#hb-font-get-parent" since="0.9.2"/>
+    <keyword type="function" name="hb_font_set_ppem ()" link="harfbuzz-hb-font.html#hb-font-set-ppem" since="0.9.2"/>
     <keyword type="function" name="hb_font_get_ppem ()" link="harfbuzz-hb-font.html#hb-font-get-ppem" since="0.9.2"/>
+    <keyword type="function" name="hb_font_set_ptem ()" link="harfbuzz-hb-font.html#hb-font-set-ptem" since="1.6.0"/>
     <keyword type="function" name="hb_font_get_ptem ()" link="harfbuzz-hb-font.html#hb-font-get-ptem" since="1.6.0"/>
+    <keyword type="function" name="hb_font_set_scale ()" link="harfbuzz-hb-font.html#hb-font-set-scale" since="0.9.2"/>
     <keyword type="function" name="hb_font_get_scale ()" link="harfbuzz-hb-font.html#hb-font-get-scale" since="0.9.2"/>
+    <keyword type="function" name="hb_font_get_synthetic_bold ()" link="harfbuzz-hb-font.html#hb-font-get-synthetic-bold" since="7.0.0"/>
+    <keyword type="function" name="hb_font_set_synthetic_bold ()" link="harfbuzz-hb-font.html#hb-font-set-synthetic-bold" since="7.0.0"/>
+    <keyword type="function" name="hb_font_set_synthetic_slant ()" link="harfbuzz-hb-font.html#hb-font-set-synthetic-slant" since="3.3.0"/>
     <keyword type="function" name="hb_font_get_synthetic_slant ()" link="harfbuzz-hb-font.html#hb-font-get-synthetic-slant" since="3.3.0"/>
-    <keyword type="function" name="hb_font_get_user_data ()" link="harfbuzz-hb-font.html#hb-font-get-user-data" since="0.9.2"/>
-    <keyword type="function" name="hb_font_get_variation_glyph ()" link="harfbuzz-hb-font.html#hb-font-get-variation-glyph" since="1.2.3"/>
-    <keyword type="function" name="hb_font_get_variation_glyph_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-variation-glyph-func-t"/>
+    <keyword type="function" name="hb_font_set_variations ()" link="harfbuzz-hb-font.html#hb-font-set-variations" since="1.4.2"/>
+    <keyword type="function" name="hb_font_set_variation ()" link="harfbuzz-hb-font.html#hb-font-set-variation" since="7.1.0"/>
+    <keyword type="function" name="hb_font_set_var_named_instance ()" link="harfbuzz-hb-font.html#hb-font-set-var-named-instance" since="2.6.0"/>
+    <keyword type="function" name="hb_font_get_var_named_instance ()" link="harfbuzz-hb-font.html#hb-font-get-var-named-instance" since="7.0.0"/>
+    <keyword type="function" name="hb_font_set_var_coords_design ()" link="harfbuzz-hb-font.html#hb-font-set-var-coords-design" since="1.4.2"/>
     <keyword type="function" name="hb_font_get_var_coords_design ()" link="harfbuzz-hb-font.html#hb-font-get-var-coords-design" since="3.3.0"/>
+    <keyword type="function" name="hb_font_set_var_coords_normalized ()" link="harfbuzz-hb-font.html#hb-font-set-var-coords-normalized" since="1.4.2"/>
     <keyword type="function" name="hb_font_get_var_coords_normalized ()" link="harfbuzz-hb-font.html#hb-font-get-var-coords-normalized" since="1.4.2"/>
     <keyword type="function" name="hb_font_glyph_from_string ()" link="harfbuzz-hb-font.html#hb-font-glyph-from-string" since="0.9.2"/>
     <keyword type="function" name="hb_font_glyph_to_string ()" link="harfbuzz-hb-font.html#hb-font-glyph-to-string" since="0.9.2"/>
-    <keyword type="function" name="hb_font_is_immutable ()" link="harfbuzz-hb-font.html#hb-font-is-immutable" since="0.9.2"/>
-    <keyword type="function" name="hb_font_make_immutable ()" link="harfbuzz-hb-font.html#hb-font-make-immutable" since="0.9.2"/>
-    <keyword type="function" name="hb_font_reference ()" link="harfbuzz-hb-font.html#hb-font-reference" since="0.9.2"/>
-    <keyword type="function" name="hb_font_set_face ()" link="harfbuzz-hb-font.html#hb-font-set-face" since="1.4.3"/>
+    <keyword type="function" name="hb_font_get_serial ()" link="harfbuzz-hb-font.html#hb-font-get-serial" since="4.4.0"/>
+    <keyword type="function" name="hb_font_changed ()" link="harfbuzz-hb-font.html#hb-font-changed" since="4.4.0"/>
     <keyword type="function" name="hb_font_set_funcs ()" link="harfbuzz-hb-font.html#hb-font-set-funcs" since="0.9.2"/>
     <keyword type="function" name="hb_font_set_funcs_data ()" link="harfbuzz-hb-font.html#hb-font-set-funcs-data" since="0.9.2"/>
-    <keyword type="function" name="hb_font_set_parent ()" link="harfbuzz-hb-font.html#hb-font-set-parent" since="1.0.5"/>
-    <keyword type="function" name="hb_font_set_ppem ()" link="harfbuzz-hb-font.html#hb-font-set-ppem" since="0.9.2"/>
-    <keyword type="function" name="hb_font_set_ptem ()" link="harfbuzz-hb-font.html#hb-font-set-ptem" since="1.6.0"/>
-    <keyword type="function" name="hb_font_set_scale ()" link="harfbuzz-hb-font.html#hb-font-set-scale" since="0.9.2"/>
-    <keyword type="function" name="hb_font_set_synthetic_slant ()" link="harfbuzz-hb-font.html#hb-font-set-synthetic-slant" since="3.3.0"/>
-    <keyword type="function" name="hb_font_set_user_data ()" link="harfbuzz-hb-font.html#hb-font-set-user-data" since="0.9.2"/>
-    <keyword type="function" name="hb_font_set_variations ()" link="harfbuzz-hb-font.html#hb-font-set-variations" since="1.4.2"/>
-    <keyword type="function" name="hb_font_set_var_coords_design ()" link="harfbuzz-hb-font.html#hb-font-set-var-coords-design" since="1.4.2"/>
-    <keyword type="function" name="hb_font_set_var_coords_normalized ()" link="harfbuzz-hb-font.html#hb-font-set-var-coords-normalized" since="1.4.2"/>
-    <keyword type="function" name="hb_font_set_var_named_instance ()" link="harfbuzz-hb-font.html#hb-font-set-var-named-instance" since="2.6.0"/>
     <keyword type="function" name="hb_font_subtract_glyph_origin_for_direction ()" link="harfbuzz-hb-font.html#hb-font-subtract-glyph-origin-for-direction" since="0.9.2"/>
+    <keyword type="function" name="hb_font_funcs_create ()" link="harfbuzz-hb-font.html#hb-font-funcs-create" since="0.9.2"/>
+    <keyword type="function" name="hb_font_funcs_get_empty ()" link="harfbuzz-hb-font.html#hb-font-funcs-get-empty" since="0.9.2"/>
+    <keyword type="function" name="hb_font_funcs_reference ()" link="harfbuzz-hb-font.html#hb-font-funcs-reference" since="0.9.2"/>
+    <keyword type="function" name="hb_font_funcs_destroy ()" link="harfbuzz-hb-font.html#hb-font-funcs-destroy" since="0.9.2"/>
+    <keyword type="function" name="hb_font_funcs_set_user_data ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-user-data" since="0.9.2"/>
+    <keyword type="function" name="hb_font_funcs_get_user_data ()" link="harfbuzz-hb-font.html#hb-font-funcs-get-user-data" since="0.9.2"/>
+    <keyword type="function" name="hb_font_funcs_make_immutable ()" link="harfbuzz-hb-font.html#hb-font-funcs-make-immutable" since="0.9.2"/>
+    <keyword type="function" name="hb_font_funcs_is_immutable ()" link="harfbuzz-hb-font.html#hb-font-funcs-is-immutable" since="0.9.2"/>
+    <keyword type="function" name="hb_font_get_glyph_contour_point_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-contour-point-func-t"/>
+    <keyword type="function" name="hb_font_funcs_set_glyph_contour_point_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-contour-point-func" since="0.9.2"/>
+    <keyword type="function" name="hb_font_get_glyph_extents_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-extents-func-t"/>
+    <keyword type="function" name="hb_font_funcs_set_glyph_extents_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-extents-func" since="0.9.2"/>
+    <keyword type="function" name="hb_font_get_glyph_from_name_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-from-name-func-t"/>
+    <keyword type="function" name="hb_font_funcs_set_glyph_from_name_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-from-name-func" since="0.9.2"/>
+    <keyword type="function" name="hb_font_get_glyph_advance_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-advance-func-t"/>
+    <keyword type="function" name="hb_font_funcs_set_glyph_h_advance_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-h-advance-func" since="0.9.2"/>
+    <keyword type="function" name="hb_font_funcs_set_glyph_v_advance_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-v-advance-func" since="0.9.2"/>
+    <keyword type="function" name="hb_font_get_glyph_advances_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-advances-func-t"/>
+    <keyword type="function" name="hb_font_funcs_set_glyph_h_advances_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-h-advances-func" since="1.8.6"/>
+    <keyword type="function" name="hb_font_funcs_set_glyph_v_advances_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-v-advances-func" since="1.8.6"/>
+    <keyword type="function" name="hb_font_get_glyph_kerning_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-kerning-func-t"/>
+    <keyword type="function" name="hb_font_funcs_set_glyph_h_kerning_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-h-kerning-func" since="0.9.2"/>
+    <keyword type="function" name="hb_font_get_glyph_origin_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-origin-func-t"/>
+    <keyword type="function" name="hb_font_funcs_set_glyph_h_origin_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-h-origin-func" since="0.9.2"/>
+    <keyword type="function" name="hb_font_funcs_set_glyph_v_origin_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-v-origin-func" since="0.9.2"/>
+    <keyword type="function" name="hb_font_get_glyph_name_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-glyph-name-func-t"/>
+    <keyword type="function" name="hb_font_funcs_set_glyph_name_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-glyph-name-func" since="0.9.2"/>
+    <keyword type="function" name="hb_font_draw_glyph_func_t ()" link="harfbuzz-hb-font.html#hb-font-draw-glyph-func-t" since="7.0.0"/>
+    <keyword type="function" name="hb_font_funcs_set_draw_glyph_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-draw-glyph-func" since="7.0.0"/>
+    <keyword type="function" name="hb_font_paint_glyph_func_t ()" link="harfbuzz-hb-font.html#hb-font-paint-glyph-func-t" since="7.0.0"/>
+    <keyword type="function" name="hb_font_funcs_set_paint_glyph_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-paint-glyph-func" since="7.0.0"/>
+    <keyword type="function" name="hb_font_get_nominal_glyph_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-nominal-glyph-func-t"/>
+    <keyword type="function" name="hb_font_funcs_set_nominal_glyph_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-nominal-glyph-func" since="1.2.3"/>
+    <keyword type="function" name="hb_font_get_nominal_glyphs_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-nominal-glyphs-func-t"/>
+    <keyword type="function" name="hb_font_funcs_set_nominal_glyphs_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-nominal-glyphs-func" since="2.0.0"/>
+    <keyword type="function" name="hb_font_get_variation_glyph_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-variation-glyph-func-t"/>
+    <keyword type="function" name="hb_font_funcs_set_variation_glyph_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-variation-glyph-func" since="1.2.3"/>
     <keyword type="function" name="hb_reference_table_func_t ()" link="harfbuzz-hb-font.html#hb-reference-table-func-t" since="0.9.2"/>
+    <keyword type="function" name="hb_font_get_font_extents_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-font-extents-func-t"/>
     <keyword type="function" name="hb_font_funcs_set_font_h_extents_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-font-h-extents-func" since="1.1.2"/>
     <keyword type="function" name="hb_font_funcs_set_font_v_extents_func ()" link="harfbuzz-hb-font.html#hb-font-funcs-set-font-v-extents-func" since="1.1.2"/>
-    <keyword type="function" name="hb_font_get_extents_for_direction ()" link="harfbuzz-hb-font.html#hb-font-get-extents-for-direction" since="1.1.3"/>
-    <keyword type="function" name="hb_font_get_font_extents_func_t ()" link="harfbuzz-hb-font.html#hb-font-get-font-extents-func-t"/>
     <keyword type="function" name="hb_font_get_h_extents ()" link="harfbuzz-hb-font.html#hb-font-get-h-extents" since="1.1.3"/>
     <keyword type="function" name="hb_font_get_v_extents ()" link="harfbuzz-hb-font.html#hb-font-get-v-extents" since="1.1.3"/>
-    <keyword type="typedef" name="hb_font_funcs_t" link="harfbuzz-hb-font.html#hb-font-funcs-t"/>
+    <keyword type="function" name="hb_font_get_extents_for_direction ()" link="harfbuzz-hb-font.html#hb-font-get-extents-for-direction" since="1.1.3"/>
+    <keyword type="macro" name="HB_FONT_NO_VAR_NAMED_INSTANCE" link="harfbuzz-hb-font.html#HB-FONT-NO-VAR-NAMED-INSTANCE:CAPS" since="7.0.0"/>
     <keyword type="typedef" name="hb_font_get_glyph_h_advance_func_t" link="harfbuzz-hb-font.html#hb-font-get-glyph-h-advance-func-t"/>
+    <keyword type="typedef" name="hb_font_get_glyph_v_advance_func_t" link="harfbuzz-hb-font.html#hb-font-get-glyph-v-advance-func-t"/>
     <keyword type="typedef" name="hb_font_get_glyph_h_advances_func_t" link="harfbuzz-hb-font.html#hb-font-get-glyph-h-advances-func-t"/>
+    <keyword type="typedef" name="hb_font_get_glyph_v_advances_func_t" link="harfbuzz-hb-font.html#hb-font-get-glyph-v-advances-func-t"/>
     <keyword type="typedef" name="hb_font_get_glyph_h_kerning_func_t" link="harfbuzz-hb-font.html#hb-font-get-glyph-h-kerning-func-t"/>
     <keyword type="typedef" name="hb_font_get_glyph_h_origin_func_t" link="harfbuzz-hb-font.html#hb-font-get-glyph-h-origin-func-t"/>
-    <keyword type="typedef" name="hb_font_get_glyph_v_advance_func_t" link="harfbuzz-hb-font.html#hb-font-get-glyph-v-advance-func-t"/>
-    <keyword type="typedef" name="hb_font_get_glyph_v_advances_func_t" link="harfbuzz-hb-font.html#hb-font-get-glyph-v-advances-func-t"/>
     <keyword type="typedef" name="hb_font_get_glyph_v_origin_func_t" link="harfbuzz-hb-font.html#hb-font-get-glyph-v-origin-func-t"/>
+    <keyword type="typedef" name="hb_font_funcs_t" link="harfbuzz-hb-font.html#hb-font-funcs-t"/>
     <keyword type="typedef" name="hb_font_t" link="harfbuzz-hb-font.html#hb-font-t"/>
     <keyword type="typedef" name="hb_font_get_font_h_extents_func_t" link="harfbuzz-hb-font.html#hb-font-get-font-h-extents-func-t"/>
     <keyword type="typedef" name="hb_font_get_font_v_extents_func_t" link="harfbuzz-hb-font.html#hb-font-get-font-v-extents-func-t"/>
     <keyword type="struct" name="hb_font_extents_t" link="harfbuzz-hb-font.html#hb-font-extents-t"/>
     <keyword type="struct" name="hb_glyph_extents_t" link="harfbuzz-hb-font.html#hb-glyph-extents-t"/>
+    <keyword type="function" name="hb_map_create ()" link="harfbuzz-hb-map.html#hb-map-create" since="1.7.7"/>
     <keyword type="function" name="hb_map_allocation_successful ()" link="harfbuzz-hb-map.html#hb-map-allocation-successful" since="1.7.7"/>
+    <keyword type="function" name="hb_map_copy ()" link="harfbuzz-hb-map.html#hb-map-copy" since="4.4.0"/>
     <keyword type="function" name="hb_map_clear ()" link="harfbuzz-hb-map.html#hb-map-clear" since="1.7.7"/>
-    <keyword type="function" name="hb_map_create ()" link="harfbuzz-hb-map.html#hb-map-create" since="1.7.7"/>
-    <keyword type="function" name="hb_map_del ()" link="harfbuzz-hb-map.html#hb-map-del" since="1.7.7"/>
-    <keyword type="function" name="hb_map_destroy ()" link="harfbuzz-hb-map.html#hb-map-destroy" since="1.7.7"/>
-    <keyword type="function" name="hb_map_get ()" link="harfbuzz-hb-map.html#hb-map-get" since="1.7.7"/>
     <keyword type="function" name="hb_map_get_empty ()" link="harfbuzz-hb-map.html#hb-map-get-empty" since="1.7.7"/>
-    <keyword type="function" name="hb_map_get_population ()" link="harfbuzz-hb-map.html#hb-map-get-population" since="1.7.7"/>
+    <keyword type="function" name="hb_map_reference ()" link="harfbuzz-hb-map.html#hb-map-reference" since="1.7.7"/>
+    <keyword type="function" name="hb_map_destroy ()" link="harfbuzz-hb-map.html#hb-map-destroy" since="1.7.7"/>
+    <keyword type="function" name="hb_map_set_user_data ()" link="harfbuzz-hb-map.html#hb-map-set-user-data" since="1.7.7"/>
     <keyword type="function" name="hb_map_get_user_data ()" link="harfbuzz-hb-map.html#hb-map-get-user-data" since="1.7.7"/>
+    <keyword type="function" name="hb_map_set ()" link="harfbuzz-hb-map.html#hb-map-set" since="1.7.7"/>
+    <keyword type="function" name="hb_map_get ()" link="harfbuzz-hb-map.html#hb-map-get" since="1.7.7"/>
+    <keyword type="function" name="hb_map_del ()" link="harfbuzz-hb-map.html#hb-map-del" since="1.7.7"/>
     <keyword type="function" name="hb_map_has ()" link="harfbuzz-hb-map.html#hb-map-has" since="1.7.7"/>
+    <keyword type="function" name="hb_map_get_population ()" link="harfbuzz-hb-map.html#hb-map-get-population" since="1.7.7"/>
     <keyword type="function" name="hb_map_is_empty ()" link="harfbuzz-hb-map.html#hb-map-is-empty" since="1.7.7"/>
-    <keyword type="function" name="hb_map_reference ()" link="harfbuzz-hb-map.html#hb-map-reference" since="1.7.7"/>
-    <keyword type="function" name="hb_map_set ()" link="harfbuzz-hb-map.html#hb-map-set" since="1.7.7"/>
-    <keyword type="function" name="hb_map_set_user_data ()" link="harfbuzz-hb-map.html#hb-map-set-user-data" since="1.7.7"/>
+    <keyword type="function" name="hb_map_is_equal ()" link="harfbuzz-hb-map.html#hb-map-is-equal" since="4.3.0"/>
+    <keyword type="function" name="hb_map_hash ()" link="harfbuzz-hb-map.html#hb-map-hash" since="4.4.0"/>
+    <keyword type="function" name="hb_map_update ()" link="harfbuzz-hb-map.html#hb-map-update" since="7.0.0"/>
+    <keyword type="function" name="hb_map_next ()" link="harfbuzz-hb-map.html#hb-map-next" since="7.0.0"/>
+    <keyword type="function" name="hb_map_keys ()" link="harfbuzz-hb-map.html#hb-map-keys" since="7.0.0"/>
+    <keyword type="function" name="hb_map_values ()" link="harfbuzz-hb-map.html#hb-map-values" since="7.0.0"/>
     <keyword type="macro" name="HB_MAP_VALUE_INVALID" link="harfbuzz-hb-map.html#HB-MAP-VALUE-INVALID:CAPS" since="1.7.7"/>
     <keyword type="typedef" name="hb_map_t" link="harfbuzz-hb-map.html#hb-map-t"/>
-    <keyword type="function" name="hb_set_add ()" link="harfbuzz-hb-set.html#hb-set-add" since="0.9.2"/>
-    <keyword type="function" name="hb_set_add_range ()" link="harfbuzz-hb-set.html#hb-set-add-range" since="0.9.7"/>
+    <keyword type="function" name="hb_set_create ()" link="harfbuzz-hb-set.html#hb-set-create" since="0.9.2"/>
     <keyword type="function" name="hb_set_allocation_successful ()" link="harfbuzz-hb-set.html#hb-set-allocation-successful" since="0.9.2"/>
     <keyword type="function" name="hb_set_copy ()" link="harfbuzz-hb-set.html#hb-set-copy" since="2.8.2"/>
+    <keyword type="function" name="hb_set_get_empty ()" link="harfbuzz-hb-set.html#hb-set-get-empty" since="0.9.2"/>
+    <keyword type="function" name="hb_set_reference ()" link="harfbuzz-hb-set.html#hb-set-reference" since="0.9.2"/>
+    <keyword type="function" name="hb_set_destroy ()" link="harfbuzz-hb-set.html#hb-set-destroy" since="0.9.2"/>
+    <keyword type="function" name="hb_set_set_user_data ()" link="harfbuzz-hb-set.html#hb-set-set-user-data" since="0.9.2"/>
+    <keyword type="function" name="hb_set_get_user_data ()" link="harfbuzz-hb-set.html#hb-set-get-user-data" since="0.9.2"/>
     <keyword type="function" name="hb_set_clear ()" link="harfbuzz-hb-set.html#hb-set-clear" since="0.9.2"/>
-    <keyword type="function" name="hb_set_create ()" link="harfbuzz-hb-set.html#hb-set-create" since="0.9.2"/>
+    <keyword type="function" name="hb_set_set ()" link="harfbuzz-hb-set.html#hb-set-set" since="0.9.2"/>
+    <keyword type="function" name="hb_set_has ()" link="harfbuzz-hb-set.html#hb-set-has" since="0.9.2"/>
+    <keyword type="function" name="hb_set_add ()" link="harfbuzz-hb-set.html#hb-set-add" since="0.9.2"/>
+    <keyword type="function" name="hb_set_add_range ()" link="harfbuzz-hb-set.html#hb-set-add-range" since="0.9.7"/>
+    <keyword type="function" name="hb_set_add_sorted_array ()" link="harfbuzz-hb-set.html#hb-set-add-sorted-array" since="4.1.0"/>
     <keyword type="function" name="hb_set_del ()" link="harfbuzz-hb-set.html#hb-set-del" since="0.9.2"/>
     <keyword type="function" name="hb_set_del_range ()" link="harfbuzz-hb-set.html#hb-set-del-range" since="0.9.7"/>
-    <keyword type="function" name="hb_set_destroy ()" link="harfbuzz-hb-set.html#hb-set-destroy" since="0.9.2"/>
-    <keyword type="function" name="hb_set_get_empty ()" link="harfbuzz-hb-set.html#hb-set-get-empty" since="0.9.2"/>
     <keyword type="function" name="hb_set_get_max ()" link="harfbuzz-hb-set.html#hb-set-get-max" since="0.9.7"/>
     <keyword type="function" name="hb_set_get_min ()" link="harfbuzz-hb-set.html#hb-set-get-min" since="0.9.7"/>
     <keyword type="function" name="hb_set_get_population ()" link="harfbuzz-hb-set.html#hb-set-get-population" since="0.9.7"/>
-    <keyword type="function" name="hb_set_get_user_data ()" link="harfbuzz-hb-set.html#hb-set-get-user-data" since="0.9.2"/>
-    <keyword type="function" name="hb_set_has ()" link="harfbuzz-hb-set.html#hb-set-has" since="0.9.2"/>
+    <keyword type="function" name="hb_set_is_empty ()" link="harfbuzz-hb-set.html#hb-set-is-empty" since="0.9.7"/>
+    <keyword type="function" name="hb_set_hash ()" link="harfbuzz-hb-set.html#hb-set-hash" since="4.4.0"/>
+    <keyword type="function" name="hb_set_subtract ()" link="harfbuzz-hb-set.html#hb-set-subtract" since="0.9.2"/>
     <keyword type="function" name="hb_set_intersect ()" link="harfbuzz-hb-set.html#hb-set-intersect" since="0.9.2"/>
+    <keyword type="function" name="hb_set_union ()" link="harfbuzz-hb-set.html#hb-set-union" since="0.9.2"/>
+    <keyword type="function" name="hb_set_symmetric_difference ()" link="harfbuzz-hb-set.html#hb-set-symmetric-difference" since="0.9.2"/>
     <keyword type="function" name="hb_set_invert ()" link="harfbuzz-hb-set.html#hb-set-invert" since="3.0.0"/>
-    <keyword type="function" name="hb_set_is_empty ()" link="harfbuzz-hb-set.html#hb-set-is-empty" since="0.9.7"/>
+    <keyword type="function" name="hb_set_is_inverted ()" link="harfbuzz-hb-set.html#hb-set-is-inverted" since="7.0.0"/>
     <keyword type="function" name="hb_set_is_equal ()" link="harfbuzz-hb-set.html#hb-set-is-equal" since="0.9.7"/>
     <keyword type="function" name="hb_set_is_subset ()" link="harfbuzz-hb-set.html#hb-set-is-subset" since="1.8.1"/>
     <keyword type="function" name="hb_set_next ()" link="harfbuzz-hb-set.html#hb-set-next" since="0.9.2"/>
     <keyword type="function" name="hb_set_next_range ()" link="harfbuzz-hb-set.html#hb-set-next-range" since="0.9.7"/>
+    <keyword type="function" name="hb_set_next_many ()" link="harfbuzz-hb-set.html#hb-set-next-many" since="4.2.0"/>
     <keyword type="function" name="hb_set_previous ()" link="harfbuzz-hb-set.html#hb-set-previous" since="1.8.0"/>
     <keyword type="function" name="hb_set_previous_range ()" link="harfbuzz-hb-set.html#hb-set-previous-range" since="1.8.0"/>
-    <keyword type="function" name="hb_set_reference ()" link="harfbuzz-hb-set.html#hb-set-reference" since="0.9.2"/>
-    <keyword type="function" name="hb_set_set ()" link="harfbuzz-hb-set.html#hb-set-set" since="0.9.2"/>
-    <keyword type="function" name="hb_set_set_user_data ()" link="harfbuzz-hb-set.html#hb-set-set-user-data" since="0.9.2"/>
-    <keyword type="function" name="hb_set_subtract ()" link="harfbuzz-hb-set.html#hb-set-subtract" since="0.9.2"/>
-    <keyword type="function" name="hb_set_symmetric_difference ()" link="harfbuzz-hb-set.html#hb-set-symmetric-difference" since="0.9.2"/>
-    <keyword type="function" name="hb_set_union ()" link="harfbuzz-hb-set.html#hb-set-union" since="0.9.2"/>
     <keyword type="macro" name="HB_SET_VALUE_INVALID" link="harfbuzz-hb-set.html#HB-SET-VALUE-INVALID:CAPS" since="0.9.21"/>
     <keyword type="typedef" name="hb_set_t" link="harfbuzz-hb-set.html#hb-set-t"/>
     <keyword type="function" name="hb_shape_plan_create ()" link="harfbuzz-hb-shape-plan.html#hb-shape-plan-create" since="0.9.7"/>
     <keyword type="function" name="hb_shape_plan_create_cached ()" link="harfbuzz-hb-shape-plan.html#hb-shape-plan-create-cached" since="0.9.7"/>
     <keyword type="function" name="hb_shape_plan_create2 ()" link="harfbuzz-hb-shape-plan.html#hb-shape-plan-create2" since="1.4.0"/>
     <keyword type="function" name="hb_shape_plan_create_cached2 ()" link="harfbuzz-hb-shape-plan.html#hb-shape-plan-create-cached2" since="1.4.0"/>
-    <keyword type="function" name="hb_shape_plan_destroy ()" link="harfbuzz-hb-shape-plan.html#hb-shape-plan-destroy" since="0.9.7"/>
-    <keyword type="function" name="hb_shape_plan_execute ()" link="harfbuzz-hb-shape-plan.html#hb-shape-plan-execute" since="0.9.7"/>
     <keyword type="function" name="hb_shape_plan_get_empty ()" link="harfbuzz-hb-shape-plan.html#hb-shape-plan-get-empty" since="0.9.7"/>
-    <keyword type="function" name="hb_shape_plan_get_shaper ()" link="harfbuzz-hb-shape-plan.html#hb-shape-plan-get-shaper" since="0.9.7"/>
-    <keyword type="function" name="hb_shape_plan_get_user_data ()" link="harfbuzz-hb-shape-plan.html#hb-shape-plan-get-user-data" since="0.9.7"/>
     <keyword type="function" name="hb_shape_plan_reference ()" link="harfbuzz-hb-shape-plan.html#hb-shape-plan-reference" since="0.9.7"/>
+    <keyword type="function" name="hb_shape_plan_destroy ()" link="harfbuzz-hb-shape-plan.html#hb-shape-plan-destroy" since="0.9.7"/>
     <keyword type="function" name="hb_shape_plan_set_user_data ()" link="harfbuzz-hb-shape-plan.html#hb-shape-plan-set-user-data" since="0.9.7"/>
+    <keyword type="function" name="hb_shape_plan_get_user_data ()" link="harfbuzz-hb-shape-plan.html#hb-shape-plan-get-user-data" since="0.9.7"/>
+    <keyword type="function" name="hb_shape_plan_execute ()" link="harfbuzz-hb-shape-plan.html#hb-shape-plan-execute" since="0.9.7"/>
+    <keyword type="function" name="hb_shape_plan_get_shaper ()" link="harfbuzz-hb-shape-plan.html#hb-shape-plan-get-shaper" since="0.9.7"/>
     <keyword type="typedef" name="hb_shape_plan_t" link="harfbuzz-hb-shape-plan.html#hb-shape-plan-t"/>
     <keyword type="function" name="hb_shape ()" link="harfbuzz-hb-shape.html#hb-shape" since="0.9.2"/>
     <keyword type="function" name="hb_shape_full ()" link="harfbuzz-hb-shape.html#hb-shape-full" since="0.9.2"/>
+    <keyword type="function" name="hb_shape_justify ()" link="harfbuzz-hb-shape.html#hb-shape-justify"/>
     <keyword type="function" name="hb_shape_list_shapers ()" link="harfbuzz-hb-shape.html#hb-shape-list-shapers" since="0.9.2"/>
+    <keyword type="function" name="hb_unicode_general_category ()" link="harfbuzz-hb-unicode.html#hb-unicode-general-category" since="0.9.2"/>
     <keyword type="function" name="hb_unicode_combining_class ()" link="harfbuzz-hb-unicode.html#hb-unicode-combining-class" since="0.9.2"/>
-    <keyword type="function" name="hb_unicode_combining_class_func_t ()" link="harfbuzz-hb-unicode.html#hb-unicode-combining-class-func-t"/>
+    <keyword type="function" name="hb_unicode_mirroring ()" link="harfbuzz-hb-unicode.html#hb-unicode-mirroring" since="0.9.2"/>
+    <keyword type="function" name="hb_unicode_script ()" link="harfbuzz-hb-unicode.html#hb-unicode-script" since="0.9.2"/>
     <keyword type="function" name="hb_unicode_compose ()" link="harfbuzz-hb-unicode.html#hb-unicode-compose" since="0.9.2"/>
-    <keyword type="function" name="hb_unicode_compose_func_t ()" link="harfbuzz-hb-unicode.html#hb-unicode-compose-func-t"/>
     <keyword type="function" name="hb_unicode_decompose ()" link="harfbuzz-hb-unicode.html#hb-unicode-decompose" since="0.9.2"/>
-    <keyword type="function" name="hb_unicode_decompose_func_t ()" link="harfbuzz-hb-unicode.html#hb-unicode-decompose-func-t"/>
     <keyword type="function" name="hb_unicode_funcs_create ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-create" since="0.9.2"/>
-    <keyword type="function" name="hb_unicode_funcs_destroy ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-destroy" since="0.9.2"/>
-    <keyword type="function" name="hb_unicode_funcs_get_default ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-get-default" since="0.9.2"/>
     <keyword type="function" name="hb_unicode_funcs_get_empty ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-get-empty" since="0.9.2"/>
-    <keyword type="function" name="hb_unicode_funcs_get_parent ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-get-parent" since="0.9.2"/>
-    <keyword type="function" name="hb_unicode_funcs_get_user_data ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-get-user-data" since="0.9.2"/>
-    <keyword type="function" name="hb_unicode_funcs_is_immutable ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-is-immutable" since="0.9.2"/>
-    <keyword type="function" name="hb_unicode_funcs_make_immutable ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-make-immutable" since="0.9.2"/>
     <keyword type="function" name="hb_unicode_funcs_reference ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-reference" since="0.9.2"/>
-    <keyword type="function" name="hb_unicode_funcs_set_combining_class_func ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-combining-class-func" since="0.9.2"/>
-    <keyword type="function" name="hb_unicode_funcs_set_compose_func ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-compose-func" since="0.9.2"/>
-    <keyword type="function" name="hb_unicode_funcs_set_decompose_func ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-decompose-func" since="0.9.2"/>
-    <keyword type="function" name="hb_unicode_funcs_set_general_category_func ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-general-category-func" since="0.9.2"/>
-    <keyword type="function" name="hb_unicode_funcs_set_mirroring_func ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-mirroring-func" since="0.9.2"/>
-    <keyword type="function" name="hb_unicode_funcs_set_script_func ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-script-func" since="0.9.2"/>
+    <keyword type="function" name="hb_unicode_funcs_destroy ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-destroy" since="0.9.2"/>
     <keyword type="function" name="hb_unicode_funcs_set_user_data ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-user-data" since="0.9.2"/>
-    <keyword type="function" name="hb_unicode_general_category ()" link="harfbuzz-hb-unicode.html#hb-unicode-general-category" since="0.9.2"/>
+    <keyword type="function" name="hb_unicode_funcs_get_user_data ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-get-user-data" since="0.9.2"/>
+    <keyword type="function" name="hb_unicode_funcs_make_immutable ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-make-immutable" since="0.9.2"/>
+    <keyword type="function" name="hb_unicode_funcs_is_immutable ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-is-immutable" since="0.9.2"/>
+    <keyword type="function" name="hb_unicode_funcs_get_default ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-get-default" since="0.9.2"/>
+    <keyword type="function" name="hb_unicode_funcs_get_parent ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-get-parent" since="0.9.2"/>
     <keyword type="function" name="hb_unicode_general_category_func_t ()" link="harfbuzz-hb-unicode.html#hb-unicode-general-category-func-t"/>
-    <keyword type="function" name="hb_unicode_mirroring ()" link="harfbuzz-hb-unicode.html#hb-unicode-mirroring" since="0.9.2"/>
+    <keyword type="function" name="hb_unicode_funcs_set_general_category_func ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-general-category-func" since="0.9.2"/>
+    <keyword type="function" name="hb_unicode_combining_class_func_t ()" link="harfbuzz-hb-unicode.html#hb-unicode-combining-class-func-t"/>
+    <keyword type="function" name="hb_unicode_funcs_set_combining_class_func ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-combining-class-func" since="0.9.2"/>
     <keyword type="function" name="hb_unicode_mirroring_func_t ()" link="harfbuzz-hb-unicode.html#hb-unicode-mirroring-func-t"/>
-    <keyword type="function" name="hb_unicode_script ()" link="harfbuzz-hb-unicode.html#hb-unicode-script" since="0.9.2"/>
+    <keyword type="function" name="hb_unicode_funcs_set_mirroring_func ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-mirroring-func" since="0.9.2"/>
     <keyword type="function" name="hb_unicode_script_func_t ()" link="harfbuzz-hb-unicode.html#hb-unicode-script-func-t"/>
+    <keyword type="function" name="hb_unicode_funcs_set_script_func ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-script-func" since="0.9.2"/>
+    <keyword type="function" name="hb_unicode_compose_func_t ()" link="harfbuzz-hb-unicode.html#hb-unicode-compose-func-t"/>
+    <keyword type="function" name="hb_unicode_funcs_set_compose_func ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-compose-func" since="0.9.2"/>
+    <keyword type="function" name="hb_unicode_decompose_func_t ()" link="harfbuzz-hb-unicode.html#hb-unicode-decompose-func-t"/>
+    <keyword type="function" name="hb_unicode_funcs_set_decompose_func ()" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-set-decompose-func" since="0.9.2"/>
     <keyword type="macro" name="HB_UNICODE_MAX" link="harfbuzz-hb-unicode.html#HB-UNICODE-MAX:CAPS" since="1.9.0"/>
     <keyword type="enum" name="enum hb_unicode_combining_class_t" link="harfbuzz-hb-unicode.html#hb-unicode-combining-class-t"/>
-    <keyword type="typedef" name="hb_unicode_funcs_t" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-t"/>
     <keyword type="enum" name="enum hb_unicode_general_category_t" link="harfbuzz-hb-unicode.html#hb-unicode-general-category-t"/>
+    <keyword type="typedef" name="hb_unicode_funcs_t" link="harfbuzz-hb-unicode.html#hb-unicode-funcs-t"/>
     <keyword type="macro" name="HB_VERSION_ATLEAST()" link="harfbuzz-hb-version.html#HB-VERSION-ATLEAST:CAPS"/>
     <keyword type="function" name="hb_version ()" link="harfbuzz-hb-version.html#hb-version" since="0.9.2"/>
     <keyword type="function" name="hb_version_atleast ()" link="harfbuzz-hb-version.html#hb-version-atleast" since="0.9.30"/>
     <keyword type="function" name="hb_ot_color_glyph_reference_png ()" link="harfbuzz-hb-ot-color.html#hb-ot-color-glyph-reference-png" since="2.1.0"/>
     <keyword type="function" name="hb_ot_color_glyph_reference_svg ()" link="harfbuzz-hb-ot-color.html#hb-ot-color-glyph-reference-svg" since="2.1.0"/>
     <keyword type="function" name="hb_ot_color_has_layers ()" link="harfbuzz-hb-ot-color.html#hb-ot-color-has-layers" since="2.1.0"/>
+    <keyword type="function" name="hb_ot_color_has_paint ()" link="harfbuzz-hb-ot-color.html#hb-ot-color-has-paint" since="7.0.0"/>
+    <keyword type="function" name="hb_ot_color_glyph_has_paint ()" link="harfbuzz-hb-ot-color.html#hb-ot-color-glyph-has-paint" since="7.0.0"/>
     <keyword type="function" name="hb_ot_color_has_palettes ()" link="harfbuzz-hb-ot-color.html#hb-ot-color-has-palettes" since="2.1.0"/>
     <keyword type="function" name="hb_ot_color_has_png ()" link="harfbuzz-hb-ot-color.html#hb-ot-color-has-png" since="2.1.0"/>
     <keyword type="function" name="hb_ot_color_has_svg ()" link="harfbuzz-hb-ot-color.html#hb-ot-color-has-svg" since="2.1.0"/>
     <keyword type="function" name="hb_ot_tags_to_script_and_language ()" link="harfbuzz-hb-ot-layout.html#hb-ot-tags-to-script-and-language" since="2.0.0"/>
     <keyword type="function" name="hb_ot_layout_collect_lookups ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-collect-lookups" since="0.9.8"/>
     <keyword type="function" name="hb_ot_layout_collect_features ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-collect-features" since="1.8.5"/>
+    <keyword type="function" name="hb_ot_layout_collect_features_map ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-collect-features-map" since="8.1.0"/>
     <keyword type="function" name="hb_ot_layout_feature_get_characters ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-feature-get-characters" since="2.0.0"/>
     <keyword type="function" name="hb_ot_layout_feature_get_lookups ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-feature-get-lookups" since="0.9.7"/>
     <keyword type="function" name="hb_ot_layout_feature_get_name_ids ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-feature-get-name-ids" since="2.0.0"/>
-    <keyword type="function" name="hb_ot_layout_feature_with_variations_get_lookups ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-feature-with-variations-get-lookups"/>
+    <keyword type="function" name="hb_ot_layout_feature_with_variations_get_lookups ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-feature-with-variations-get-lookups" since="1.4.0"/>
     <keyword type="function" name="hb_ot_layout_get_attach_points ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-attach-points"/>
+    <keyword type="function" name="hb_ot_layout_get_font_extents ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-font-extents" since="8.0.0"/>
+    <keyword type="function" name="hb_ot_layout_get_font_extents2 ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-font-extents2" since="8.0.0"/>
+    <keyword type="function" name="hb_ot_layout_get_horizontal_baseline_tag_for_script ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-horizontal-baseline-tag-for-script" since="4.0.0"/>
     <keyword type="function" name="hb_ot_layout_get_baseline ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-baseline" since="2.6.0"/>
+    <keyword type="function" name="hb_ot_layout_get_baseline2 ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-baseline2" since="8.0.0"/>
+    <keyword type="function" name="hb_ot_layout_get_baseline_with_fallback ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-baseline-with-fallback" since="4.0.0"/>
+    <keyword type="function" name="hb_ot_layout_get_baseline_with_fallback2 ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-baseline-with-fallback2" since="8.0.0"/>
     <keyword type="function" name="hb_ot_layout_get_glyph_class ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-glyph-class" since="0.9.7"/>
     <keyword type="function" name="hb_ot_layout_get_glyphs_in_class ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-glyphs-in-class" since="0.9.7"/>
     <keyword type="function" name="hb_ot_layout_get_ligature_carets ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-ligature-carets"/>
     <keyword type="function" name="hb_ot_layout_get_size_params ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-get-size-params" since="0.9.10"/>
     <keyword type="function" name="hb_ot_layout_has_glyph_classes ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-has-glyph-classes"/>
     <keyword type="function" name="hb_ot_layout_has_positioning ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-has-positioning"/>
-    <keyword type="function" name="hb_ot_layout_has_substitution ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-has-substitution"/>
-    <keyword type="function" name="hb_ot_layout_language_find_feature ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-language-find-feature"/>
-    <keyword type="function" name="hb_ot_layout_language_get_feature_indexes ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-language-get-feature-indexes"/>
-    <keyword type="function" name="hb_ot_layout_language_get_feature_tags ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-language-get-feature-tags"/>
+    <keyword type="function" name="hb_ot_layout_has_substitution ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-has-substitution" since="0.6.0"/>
+    <keyword type="function" name="hb_ot_layout_language_find_feature ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-language-find-feature" since="0.6.0"/>
+    <keyword type="function" name="hb_ot_layout_language_get_feature_indexes ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-language-get-feature-indexes" since="0.6.0"/>
+    <keyword type="function" name="hb_ot_layout_language_get_feature_tags ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-language-get-feature-tags" since="0.6.0"/>
     <keyword type="function" name="hb_ot_layout_language_get_required_feature ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-language-get-required-feature" since="0.9.30"/>
     <keyword type="function" name="hb_ot_layout_lookup_collect_glyphs ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-lookup-collect-glyphs" since="0.9.7"/>
     <keyword type="function" name="hb_ot_layout_lookup_get_glyph_alternates ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-lookup-get-glyph-alternates" since="2.6.8"/>
+    <keyword type="function" name="hb_ot_layout_lookup_get_optical_bound ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-lookup-get-optical-bound" since="5.3.0"/>
     <keyword type="function" name="hb_ot_layout_lookup_substitute_closure ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-lookup-substitute-closure" since="0.9.7"/>
     <keyword type="function" name="hb_ot_layout_lookups_substitute_closure ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-lookups-substitute-closure" since="1.8.1"/>
     <keyword type="function" name="hb_ot_layout_lookup_would_substitute ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-lookup-would-substitute" since="0.9.7"/>
-    <keyword type="function" name="hb_ot_layout_script_get_language_tags ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-script-get-language-tags"/>
+    <keyword type="function" name="hb_ot_layout_script_find_language ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-script-find-language" deprecated="2.0.0" since="0.6.0"/>
+    <keyword type="function" name="hb_ot_layout_script_get_language_tags ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-script-get-language-tags" since="0.6.0"/>
     <keyword type="function" name="hb_ot_layout_script_select_language ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-script-select-language" since="2.0.0"/>
-    <keyword type="function" name="hb_ot_layout_table_find_feature_variations ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-table-find-feature-variations"/>
-    <keyword type="function" name="hb_ot_layout_table_get_feature_tags ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-table-get-feature-tags"/>
+    <keyword type="function" name="hb_ot_layout_script_select_language2 ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-script-select-language2" since="7.0.0"/>
+    <keyword type="function" name="hb_ot_layout_table_find_feature_variations ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-table-find-feature-variations" since="1.4.0"/>
+    <keyword type="function" name="hb_ot_layout_table_get_feature_tags ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-table-get-feature-tags" since="0.6.0"/>
     <keyword type="function" name="hb_ot_layout_table_get_script_tags ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-table-get-script-tags"/>
     <keyword type="function" name="hb_ot_layout_table_get_lookup_count ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-table-get-lookup-count" since="0.9.22"/>
     <keyword type="function" name="hb_ot_layout_table_select_script ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-table-select-script" since="2.0.0"/>
     <keyword type="function" name="hb_ot_shape_plan_collect_lookups ()" link="harfbuzz-hb-ot-layout.html#hb-ot-shape-plan-collect-lookups" since="0.9.7"/>
-    <keyword type="function" name="hb_ot_layout_language_get_required_feature_index ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-language-get-required-feature-index"/>
+    <keyword type="function" name="hb_ot_layout_language_get_required_feature_index ()" link="harfbuzz-hb-ot-layout.html#hb-ot-layout-language-get-required-feature-index" since="0.6.0"/>
     <keyword type="macro" name="HB_OT_MAX_TAGS_PER_LANGUAGE" link="harfbuzz-hb-ot-layout.html#HB-OT-MAX-TAGS-PER-LANGUAGE:CAPS" since="2.0.0"/>
     <keyword type="macro" name="HB_OT_MAX_TAGS_PER_SCRIPT" link="harfbuzz-hb-ot-layout.html#HB-OT-MAX-TAGS-PER-SCRIPT:CAPS" since="2.0.0"/>
     <keyword type="macro" name="HB_OT_TAG_DEFAULT_LANGUAGE" link="harfbuzz-hb-ot-layout.html#HB-OT-TAG-DEFAULT-LANGUAGE:CAPS"/>
     <keyword type="function" name="hb_ot_meta_reference_entry ()" link="harfbuzz-hb-ot-meta.html#hb-ot-meta-reference-entry" since="2.6.0"/>
     <keyword type="enum" name="enum hb_ot_meta_tag_t" link="harfbuzz-hb-ot-meta.html#hb-ot-meta-tag-t" since="2.6.0"/>
     <keyword type="function" name="hb_ot_metrics_get_position ()" link="harfbuzz-hb-ot-metrics.html#hb-ot-metrics-get-position" since="2.6.0"/>
+    <keyword type="function" name="hb_ot_metrics_get_position_with_fallback ()" link="harfbuzz-hb-ot-metrics.html#hb-ot-metrics-get-position-with-fallback" since="4.0.0"/>
     <keyword type="function" name="hb_ot_metrics_get_variation ()" link="harfbuzz-hb-ot-metrics.html#hb-ot-metrics-get-variation" since="2.6.0"/>
     <keyword type="function" name="hb_ot_metrics_get_x_variation ()" link="harfbuzz-hb-ot-metrics.html#hb-ot-metrics-get-x-variation" since="2.6.0"/>
     <keyword type="function" name="hb_ot_metrics_get_y_variation ()" link="harfbuzz-hb-ot-metrics.html#hb-ot-metrics-get-y-variation" since="2.6.0"/>
     <keyword type="function" name="hb_ot_name_get_utf32 ()" link="harfbuzz-hb-ot-name.html#hb-ot-name-get-utf32" since="2.1.0"/>
     <keyword type="function" name="hb_ot_name_get_utf8 ()" link="harfbuzz-hb-ot-name.html#hb-ot-name-get-utf8" since="2.1.0"/>
     <keyword type="typedef" name="hb_ot_name_id_t" link="harfbuzz-hb-ot-name.html#hb-ot-name-id-t" since="2.0.0"/>
+    <keyword type="enum" name="enum hb_ot_name_id_predefined_t" link="harfbuzz-hb-ot-name.html#hb-ot-name-id-predefined-t" since="7.0.0"/>
     <keyword type="struct" name="hb_ot_name_entry_t" link="harfbuzz-hb-ot-name.html#hb-ot-name-entry-t" since="2.1.0"/>
     <keyword type="function" name="hb_ot_shape_glyphs_closure ()" link="harfbuzz-hb-ot-shape.html#hb-ot-shape-glyphs-closure" since="0.9.2"/>
     <keyword type="function" name="hb_ot_var_has_data ()" link="harfbuzz-hb-ot-var.html#hb-ot-var-has-data" since="1.4.2"/>
     <keyword type="function" name="hb_ft_font_set_load_flags ()" link="harfbuzz-hb-ft.html#hb-ft-font-set-load-flags" since="1.0.5"/>
     <keyword type="function" name="hb_ft_font_get_load_flags ()" link="harfbuzz-hb-ft.html#hb-ft-font-get-load-flags" since="1.0.5"/>
     <keyword type="function" name="hb_ft_font_set_funcs ()" link="harfbuzz-hb-ft.html#hb-ft-font-set-funcs" since="1.0.5"/>
+    <keyword type="function" name="hb_ft_hb_font_changed ()" link="harfbuzz-hb-ft.html#hb-ft-hb-font-changed" since="4.4.0"/>
     <keyword type="function" name="hb_glib_get_unicode_funcs ()" link="harfbuzz-hb-glib.html#hb-glib-get-unicode-funcs" since="0.9.38"/>
     <keyword type="function" name="hb_glib_script_from_script ()" link="harfbuzz-hb-glib.html#hb-glib-script-from-script" since="0.9.38"/>
     <keyword type="function" name="hb_glib_script_to_script ()" link="harfbuzz-hb-glib.html#hb-glib-script-to-script" since="0.9.38"/>
     <keyword type="function" name="hb_glib_blob_create ()" link="harfbuzz-hb-glib.html#hb-glib-blob-create" since="0.9.38"/>
     <keyword type="function" name="hb_graphite2_face_get_gr_face ()" link="harfbuzz-hb-graphite2.html#hb-graphite2-face-get-gr-face" since="0.9.10"/>
+    <keyword type="function" name="hb_graphite2_font_get_gr_font ()" link="harfbuzz-hb-graphite2.html#hb-graphite2-font-get-gr-font" deprecated="1.4.2" since="0.9.10"/>
     <keyword type="macro" name="HB_GRAPHITE2_TAG_SILF" link="harfbuzz-hb-graphite2.html#HB-GRAPHITE2-TAG-SILF:CAPS"/>
     <keyword type="function" name="hb_icu_get_unicode_funcs ()" link="harfbuzz-hb-icu.html#hb-icu-get-unicode-funcs" since="0.9.38"/>
     <keyword type="function" name="hb_icu_script_from_script ()" link="harfbuzz-hb-icu.html#hb-icu-script-from-script"/>
     <keyword type="function" name="hb_gdi_face_create ()" link="harfbuzz-hb-gdi.html#hb-gdi-face-create" since="2.6.0"/>
     <keyword type="function" name="hb_directwrite_face_create ()" link="harfbuzz-hb-directwrite.html#hb-directwrite-face-create" since="2.4.0"/>
     <keyword type="function" name="hb_directwrite_face_get_font_face ()" link="harfbuzz-hb-directwrite.html#hb-directwrite-face-get-font-face" since="2.5.0"/>
+    <keyword type="function" name="hb_cairo_font_face_create_for_font ()" link="harfbuzz-hb-cairo.html#hb-cairo-font-face-create-for-font" since="7.0.0"/>
+    <keyword type="function" name="hb_cairo_font_face_get_font ()" link="harfbuzz-hb-cairo.html#hb-cairo-font-face-get-font" since="7.0.0"/>
+    <keyword type="function" name="hb_cairo_font_face_create_for_face ()" link="harfbuzz-hb-cairo.html#hb-cairo-font-face-create-for-face" since="7.0.0"/>
+    <keyword type="function" name="hb_cairo_font_face_get_face ()" link="harfbuzz-hb-cairo.html#hb-cairo-font-face-get-face" since="7.0.0"/>
+    <keyword type="function" name="hb_cairo_font_init_func_t ()" link="harfbuzz-hb-cairo.html#hb-cairo-font-init-func-t" since="7.0.0"/>
+    <keyword type="function" name="hb_cairo_font_face_set_font_init_func ()" link="harfbuzz-hb-cairo.html#hb-cairo-font-face-set-font-init-func" since="7.0.0"/>
+    <keyword type="function" name="hb_cairo_scaled_font_get_font ()" link="harfbuzz-hb-cairo.html#hb-cairo-scaled-font-get-font" since="7.0.0"/>
+    <keyword type="function" name="hb_cairo_font_face_set_scale_factor ()" link="harfbuzz-hb-cairo.html#hb-cairo-font-face-set-scale-factor" since="7.0.0"/>
+    <keyword type="function" name="hb_cairo_font_face_get_scale_factor ()" link="harfbuzz-hb-cairo.html#hb-cairo-font-face-get-scale-factor" since="7.0.0"/>
+    <keyword type="function" name="hb_cairo_glyphs_from_buffer ()" link="harfbuzz-hb-cairo.html#hb-cairo-glyphs-from-buffer" since="7.0.0"/>
     <keyword type="function" name="hb_style_get_value ()" link="harfbuzz-hb-style.html#hb-style-get-value" since="3.0.0"/>
     <keyword type="enum" name="enum hb_style_tag_t" link="harfbuzz-hb-style.html#hb-style-tag-t" since="3.0.0"/>
     <keyword type="function" name="hb_subset_input_create_or_fail ()" link="harfbuzz-hb-subset.html#hb-subset-input-create-or-fail" since="1.8.0"/>
     <keyword type="function" name="hb_subset_input_destroy ()" link="harfbuzz-hb-subset.html#hb-subset-input-destroy" since="1.8.0"/>
     <keyword type="function" name="hb_subset_input_set_user_data ()" link="harfbuzz-hb-subset.html#hb-subset-input-set-user-data" since="2.9.0"/>
     <keyword type="function" name="hb_subset_input_get_user_data ()" link="harfbuzz-hb-subset.html#hb-subset-input-get-user-data" since="2.9.0"/>
-    <keyword type="function" name="hb_subset_input_get_flags ()" link="harfbuzz-hb-subset.html#hb-subset-input-get-flags" since="2.9.0"/>
+    <keyword type="function" name="hb_subset_input_keep_everything ()" link="harfbuzz-hb-subset.html#hb-subset-input-keep-everything" since="7.0.0"/>
     <keyword type="function" name="hb_subset_input_set_flags ()" link="harfbuzz-hb-subset.html#hb-subset-input-set-flags" since="2.9.0"/>
+    <keyword type="function" name="hb_subset_input_get_flags ()" link="harfbuzz-hb-subset.html#hb-subset-input-get-flags" since="2.9.0"/>
     <keyword type="function" name="hb_subset_input_unicode_set ()" link="harfbuzz-hb-subset.html#hb-subset-input-unicode-set" since="1.8.0"/>
     <keyword type="function" name="hb_subset_input_glyph_set ()" link="harfbuzz-hb-subset.html#hb-subset-input-glyph-set" since="1.8.0"/>
     <keyword type="function" name="hb_subset_input_set ()" link="harfbuzz-hb-subset.html#hb-subset-input-set" since="2.9.1"/>
+    <keyword type="function" name="hb_subset_input_old_to_new_glyph_mapping ()" link="harfbuzz-hb-subset.html#hb-subset-input-old-to-new-glyph-mapping" since="7.3.0"/>
+    <keyword type="function" name="hb_subset_input_pin_axis_location ()" link="harfbuzz-hb-subset.html#hb-subset-input-pin-axis-location" since="6.0.0"/>
+    <keyword type="function" name="hb_subset_input_pin_axis_to_default ()" link="harfbuzz-hb-subset.html#hb-subset-input-pin-axis-to-default" since="6.0.0"/>
     <keyword type="function" name="hb_subset_or_fail ()" link="harfbuzz-hb-subset.html#hb-subset-or-fail" since="2.9.0"/>
+    <keyword type="function" name="hb_subset_plan_create_or_fail ()" link="harfbuzz-hb-subset.html#hb-subset-plan-create-or-fail" since="4.0.0"/>
+    <keyword type="function" name="hb_subset_plan_reference ()" link="harfbuzz-hb-subset.html#hb-subset-plan-reference" since="4.0.0"/>
+    <keyword type="function" name="hb_subset_plan_destroy ()" link="harfbuzz-hb-subset.html#hb-subset-plan-destroy" since="4.0.0"/>
+    <keyword type="function" name="hb_subset_plan_set_user_data ()" link="harfbuzz-hb-subset.html#hb-subset-plan-set-user-data" since="4.0.0"/>
+    <keyword type="function" name="hb_subset_plan_get_user_data ()" link="harfbuzz-hb-subset.html#hb-subset-plan-get-user-data" since="4.0.0"/>
+    <keyword type="function" name="hb_subset_plan_execute_or_fail ()" link="harfbuzz-hb-subset.html#hb-subset-plan-execute-or-fail" since="4.0.0"/>
+    <keyword type="function" name="hb_subset_plan_unicode_to_old_glyph_mapping ()" link="harfbuzz-hb-subset.html#hb-subset-plan-unicode-to-old-glyph-mapping" since="4.0.0"/>
+    <keyword type="function" name="hb_subset_plan_new_to_old_glyph_mapping ()" link="harfbuzz-hb-subset.html#hb-subset-plan-new-to-old-glyph-mapping" since="4.0.0"/>
+    <keyword type="function" name="hb_subset_plan_old_to_new_glyph_mapping ()" link="harfbuzz-hb-subset.html#hb-subset-plan-old-to-new-glyph-mapping" since="4.0.0"/>
+    <keyword type="function" name="hb_subset_preprocess ()" link="harfbuzz-hb-subset.html#hb-subset-preprocess" since="6.0.0"/>
     <keyword type="enum" name="enum hb_subset_flags_t" link="harfbuzz-hb-subset.html#hb-subset-flags-t" since="2.9.0"/>
     <keyword type="typedef" name="hb_subset_input_t" link="harfbuzz-hb-subset.html#hb-subset-input-t"/>
     <keyword type="enum" name="enum hb_subset_sets_t" link="harfbuzz-hb-subset.html#hb-subset-sets-t" since="2.9.1"/>
+    <keyword type="typedef" name="hb_subset_plan_t" link="harfbuzz-hb-subset.html#hb-subset-plan-t"/>
     <keyword type="constant" name="HB_MEMORY_MODE_DUPLICATE" link="harfbuzz-hb-blob.html#HB-MEMORY-MODE-DUPLICATE:CAPS"/>
     <keyword type="constant" name="HB_MEMORY_MODE_READONLY" link="harfbuzz-hb-blob.html#HB-MEMORY-MODE-READONLY:CAPS"/>
     <keyword type="constant" name="HB_MEMORY_MODE_WRITABLE" link="harfbuzz-hb-blob.html#HB-MEMORY-MODE-WRITABLE:CAPS"/>
     <keyword type="constant" name="HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE" link="harfbuzz-hb-blob.html#HB-MEMORY-MODE-READONLY-MAY-MAKE-WRITABLE:CAPS"/>
     <keyword type="constant" name="HB_GLYPH_FLAG_UNSAFE_TO_BREAK" link="harfbuzz-hb-buffer.html#HB-GLYPH-FLAG-UNSAFE-TO-BREAK:CAPS"/>
     <keyword type="constant" name="HB_GLYPH_FLAG_UNSAFE_TO_CONCAT" link="harfbuzz-hb-buffer.html#HB-GLYPH-FLAG-UNSAFE-TO-CONCAT:CAPS"/>
+    <keyword type="constant" name="HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL" link="harfbuzz-hb-buffer.html#HB-GLYPH-FLAG-SAFE-TO-INSERT-TATWEEL:CAPS"/>
     <keyword type="constant" name="HB_GLYPH_FLAG_DEFINED" link="harfbuzz-hb-buffer.html#HB-GLYPH-FLAG-DEFINED:CAPS"/>
     <keyword type="constant" name="HB_BUFFER_CONTENT_TYPE_INVALID" link="harfbuzz-hb-buffer.html#HB-BUFFER-CONTENT-TYPE-INVALID:CAPS"/>
     <keyword type="constant" name="HB_BUFFER_CONTENT_TYPE_UNICODE" link="harfbuzz-hb-buffer.html#HB-BUFFER-CONTENT-TYPE-UNICODE:CAPS"/>
     <keyword type="constant" name="HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES" link="harfbuzz-hb-buffer.html#HB-BUFFER-FLAG-REMOVE-DEFAULT-IGNORABLES:CAPS"/>
     <keyword type="constant" name="HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE" link="harfbuzz-hb-buffer.html#HB-BUFFER-FLAG-DO-NOT-INSERT-DOTTED-CIRCLE:CAPS"/>
     <keyword type="constant" name="HB_BUFFER_FLAG_VERIFY" link="harfbuzz-hb-buffer.html#HB-BUFFER-FLAG-VERIFY:CAPS"/>
+    <keyword type="constant" name="HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT" link="harfbuzz-hb-buffer.html#HB-BUFFER-FLAG-PRODUCE-UNSAFE-TO-CONCAT:CAPS"/>
+    <keyword type="constant" name="HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL" link="harfbuzz-hb-buffer.html#HB-BUFFER-FLAG-PRODUCE-SAFE-TO-INSERT-TATWEEL:CAPS"/>
+    <keyword type="constant" name="HB_BUFFER_FLAG_DEFINED" link="harfbuzz-hb-buffer.html#HB-BUFFER-FLAG-DEFINED:CAPS"/>
     <keyword type="constant" name="HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES" link="harfbuzz-hb-buffer.html#HB-BUFFER-CLUSTER-LEVEL-MONOTONE-GRAPHEMES:CAPS"/>
     <keyword type="constant" name="HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS" link="harfbuzz-hb-buffer.html#HB-BUFFER-CLUSTER-LEVEL-MONOTONE-CHARACTERS:CAPS"/>
     <keyword type="constant" name="HB_BUFFER_CLUSTER_LEVEL_CHARACTERS" link="harfbuzz-hb-buffer.html#HB-BUFFER-CLUSTER-LEVEL-CHARACTERS:CAPS"/>
     <keyword type="constant" name="HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS" link="harfbuzz-hb-buffer.html#HB-BUFFER-SERIALIZE-FLAG-GLYPH-EXTENTS:CAPS"/>
     <keyword type="constant" name="HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS" link="harfbuzz-hb-buffer.html#HB-BUFFER-SERIALIZE-FLAG-GLYPH-FLAGS:CAPS"/>
     <keyword type="constant" name="HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES" link="harfbuzz-hb-buffer.html#HB-BUFFER-SERIALIZE-FLAG-NO-ADVANCES:CAPS"/>
+    <keyword type="constant" name="HB_BUFFER_SERIALIZE_FLAG_DEFINED" link="harfbuzz-hb-buffer.html#HB-BUFFER-SERIALIZE-FLAG-DEFINED:CAPS"/>
     <keyword type="constant" name="HB_BUFFER_DIFF_FLAG_EQUAL" link="harfbuzz-hb-buffer.html#HB-BUFFER-DIFF-FLAG-EQUAL:CAPS"/>
     <keyword type="constant" name="HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH" link="harfbuzz-hb-buffer.html#HB-BUFFER-DIFF-FLAG-CONTENT-TYPE-MISMATCH:CAPS"/>
     <keyword type="constant" name="HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH" link="harfbuzz-hb-buffer.html#HB-BUFFER-DIFF-FLAG-LENGTH-MISMATCH:CAPS"/>
     <keyword type="constant" name="HB_SCRIPT_TOTO" link="harfbuzz-hb-common.html#HB-SCRIPT-TOTO:CAPS"/>
     <keyword type="constant" name="HB_SCRIPT_VITHKUQI" link="harfbuzz-hb-common.html#HB-SCRIPT-VITHKUQI:CAPS"/>
     <keyword type="constant" name="HB_SCRIPT_MATH" link="harfbuzz-hb-common.html#HB-SCRIPT-MATH:CAPS"/>
+    <keyword type="constant" name="HB_SCRIPT_KAWI" link="harfbuzz-hb-common.html#HB-SCRIPT-KAWI:CAPS"/>
+    <keyword type="constant" name="HB_SCRIPT_NAG_MUNDARI" link="harfbuzz-hb-common.html#HB-SCRIPT-NAG-MUNDARI:CAPS"/>
     <keyword type="constant" name="HB_SCRIPT_INVALID" link="harfbuzz-hb-common.html#HB-SCRIPT-INVALID:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_EXTEND_PAD" link="harfbuzz-hb-paint.html#HB-PAINT-EXTEND-PAD:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_EXTEND_REPEAT" link="harfbuzz-hb-paint.html#HB-PAINT-EXTEND-REPEAT:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_EXTEND_REFLECT" link="harfbuzz-hb-paint.html#HB-PAINT-EXTEND-REFLECT:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_CLEAR" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-CLEAR:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_SRC" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-SRC:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_DEST" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-DEST:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_SRC_OVER" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-SRC-OVER:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_DEST_OVER" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-DEST-OVER:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_SRC_IN" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-SRC-IN:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_DEST_IN" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-DEST-IN:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_SRC_OUT" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-SRC-OUT:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_DEST_OUT" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-DEST-OUT:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_SRC_ATOP" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-SRC-ATOP:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_DEST_ATOP" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-DEST-ATOP:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_XOR" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-XOR:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_PLUS" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-PLUS:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_SCREEN" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-SCREEN:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_OVERLAY" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-OVERLAY:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_DARKEN" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-DARKEN:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_LIGHTEN" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-LIGHTEN:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_COLOR_DODGE" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-COLOR-DODGE:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_COLOR_BURN" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-COLOR-BURN:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_HARD_LIGHT" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-HARD-LIGHT:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-SOFT-LIGHT:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_DIFFERENCE" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-DIFFERENCE:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_EXCLUSION" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-EXCLUSION:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_MULTIPLY" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-MULTIPLY:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_HSL_HUE" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-HSL-HUE:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_HSL_SATURATION" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-HSL-SATURATION:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_HSL_COLOR" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-HSL-COLOR:CAPS"/>
+    <keyword type="constant" name="HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY" link="harfbuzz-hb-paint.html#HB-PAINT-COMPOSITE-MODE-HSL-LUMINOSITY:CAPS"/>
     <keyword type="constant" name="HB_UNICODE_COMBINING_CLASS_NOT_REORDERED" link="harfbuzz-hb-unicode.html#HB-UNICODE-COMBINING-CLASS-NOT-REORDERED:CAPS"/>
     <keyword type="constant" name="HB_UNICODE_COMBINING_CLASS_OVERLAY" link="harfbuzz-hb-unicode.html#HB-UNICODE-COMBINING-CLASS-OVERLAY:CAPS"/>
     <keyword type="constant" name="HB_UNICODE_COMBINING_CLASS_NUKTA" link="harfbuzz-hb-unicode.html#HB-UNICODE-COMBINING-CLASS-NUKTA:CAPS"/>
     <keyword type="constant" name="HB_UNICODE_COMBINING_CLASS_CCC122" link="harfbuzz-hb-unicode.html#HB-UNICODE-COMBINING-CLASS-CCC122:CAPS"/>
     <keyword type="constant" name="HB_UNICODE_COMBINING_CLASS_CCC129" link="harfbuzz-hb-unicode.html#HB-UNICODE-COMBINING-CLASS-CCC129:CAPS"/>
     <keyword type="constant" name="HB_UNICODE_COMBINING_CLASS_CCC130" link="harfbuzz-hb-unicode.html#HB-UNICODE-COMBINING-CLASS-CCC130:CAPS"/>
-    <keyword type="constant" name="HB_UNICODE_COMBINING_CLASS_CCC133" link="harfbuzz-hb-unicode.html#HB-UNICODE-COMBINING-CLASS-CCC133:CAPS"/>
+    <keyword type="constant" name="HB_UNICODE_COMBINING_CLASS_CCC132" link="harfbuzz-hb-unicode.html#HB-UNICODE-COMBINING-CLASS-CCC132:CAPS"/>
     <keyword type="constant" name="HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT" link="harfbuzz-hb-unicode.html#HB-UNICODE-COMBINING-CLASS-ATTACHED-BELOW-LEFT:CAPS"/>
     <keyword type="constant" name="HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW" link="harfbuzz-hb-unicode.html#HB-UNICODE-COMBINING-CLASS-ATTACHED-BELOW:CAPS"/>
     <keyword type="constant" name="HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE" link="harfbuzz-hb-unicode.html#HB-UNICODE-COMBINING-CLASS-ATTACHED-ABOVE:CAPS"/>
     <keyword type="constant" name="HB_OT_LAYOUT_BASELINE_TAG_HANGING" link="harfbuzz-hb-ot-layout.html#HB-OT-LAYOUT-BASELINE-TAG-HANGING:CAPS"/>
     <keyword type="constant" name="HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT" link="harfbuzz-hb-ot-layout.html#HB-OT-LAYOUT-BASELINE-TAG-IDEO-FACE-BOTTOM-OR-LEFT:CAPS"/>
     <keyword type="constant" name="HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT" link="harfbuzz-hb-ot-layout.html#HB-OT-LAYOUT-BASELINE-TAG-IDEO-FACE-TOP-OR-RIGHT:CAPS"/>
+    <keyword type="constant" name="HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL" link="harfbuzz-hb-ot-layout.html#HB-OT-LAYOUT-BASELINE-TAG-IDEO-FACE-CENTRAL:CAPS"/>
     <keyword type="constant" name="HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT" link="harfbuzz-hb-ot-layout.html#HB-OT-LAYOUT-BASELINE-TAG-IDEO-EMBOX-BOTTOM-OR-LEFT:CAPS"/>
     <keyword type="constant" name="HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT" link="harfbuzz-hb-ot-layout.html#HB-OT-LAYOUT-BASELINE-TAG-IDEO-EMBOX-TOP-OR-RIGHT:CAPS"/>
+    <keyword type="constant" name="HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL" link="harfbuzz-hb-ot-layout.html#HB-OT-LAYOUT-BASELINE-TAG-IDEO-EMBOX-CENTRAL:CAPS"/>
     <keyword type="constant" name="HB_OT_LAYOUT_BASELINE_TAG_MATH" link="harfbuzz-hb-ot-layout.html#HB-OT-LAYOUT-BASELINE-TAG-MATH:CAPS"/>
     <keyword type="constant" name="HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED" link="harfbuzz-hb-ot-layout.html#HB-OT-LAYOUT-GLYPH-CLASS-UNCLASSIFIED:CAPS"/>
     <keyword type="constant" name="HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH" link="harfbuzz-hb-ot-layout.html#HB-OT-LAYOUT-GLYPH-CLASS-BASE-GLYPH:CAPS"/>
     <keyword type="constant" name="HB_OT_METRICS_TAG_STRIKEOUT_OFFSET" link="harfbuzz-hb-ot-metrics.html#HB-OT-METRICS-TAG-STRIKEOUT-OFFSET:CAPS"/>
     <keyword type="constant" name="HB_OT_METRICS_TAG_UNDERLINE_SIZE" link="harfbuzz-hb-ot-metrics.html#HB-OT-METRICS-TAG-UNDERLINE-SIZE:CAPS"/>
     <keyword type="constant" name="HB_OT_METRICS_TAG_UNDERLINE_OFFSET" link="harfbuzz-hb-ot-metrics.html#HB-OT-METRICS-TAG-UNDERLINE-OFFSET:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_COPYRIGHT" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-COPYRIGHT:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_FONT_FAMILY" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-FONT-FAMILY:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_FONT_SUBFAMILY" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-FONT-SUBFAMILY:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_UNIQUE_ID" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-UNIQUE-ID:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_FULL_NAME" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-FULL-NAME:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_VERSION_STRING" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-VERSION-STRING:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_POSTSCRIPT_NAME" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-POSTSCRIPT-NAME:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_TRADEMARK" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-TRADEMARK:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_MANUFACTURER" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-MANUFACTURER:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_DESIGNER" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-DESIGNER:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_DESCRIPTION" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-DESCRIPTION:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_VENDOR_URL" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-VENDOR-URL:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_DESIGNER_URL" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-DESIGNER-URL:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_LICENSE" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-LICENSE:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_LICENSE_URL" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-LICENSE-URL:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-TYPOGRAPHIC-FAMILY:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-TYPOGRAPHIC-SUBFAMILY:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_MAC_FULL_NAME" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-MAC-FULL-NAME:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_SAMPLE_TEXT" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-SAMPLE-TEXT:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_CID_FINDFONT_NAME" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-CID-FINDFONT-NAME:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_WWS_FAMILY" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-WWS-FAMILY:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_WWS_SUBFAMILY" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-WWS-SUBFAMILY:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_LIGHT_BACKGROUND" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-LIGHT-BACKGROUND:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_DARK_BACKGROUND" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-DARK-BACKGROUND:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_VARIATIONS_PS_PREFIX" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-VARIATIONS-PS-PREFIX:CAPS"/>
+    <keyword type="constant" name="HB_OT_NAME_ID_INVALID" link="harfbuzz-hb-ot-name.html#HB-OT-NAME-ID-INVALID:CAPS"/>
     <keyword type="constant" name="HB_OT_VAR_AXIS_FLAG_HIDDEN" link="harfbuzz-hb-ot-var.html#HB-OT-VAR-AXIS-FLAG-HIDDEN:CAPS"/>
     <keyword type="constant" name="HB_AAT_LAYOUT_FEATURE_TYPE_INVALID" link="harfbuzz-hb-aat-layout.html#HB-AAT-LAYOUT-FEATURE-TYPE-INVALID:CAPS"/>
     <keyword type="constant" name="HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC" link="harfbuzz-hb-aat-layout.html#HB-AAT-LAYOUT-FEATURE-TYPE-ALL-TYPOGRAPHIC:CAPS"/>
     <keyword type="constant" name="HB_SUBSET_FLAGS_NOTDEF_OUTLINE" link="harfbuzz-hb-subset.html#HB-SUBSET-FLAGS-NOTDEF-OUTLINE:CAPS"/>
     <keyword type="constant" name="HB_SUBSET_FLAGS_GLYPH_NAMES" link="harfbuzz-hb-subset.html#HB-SUBSET-FLAGS-GLYPH-NAMES:CAPS"/>
     <keyword type="constant" name="HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES" link="harfbuzz-hb-subset.html#HB-SUBSET-FLAGS-NO-PRUNE-UNICODE-RANGES:CAPS"/>
+    <keyword type="constant" name="HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE" link="harfbuzz-hb-subset.html#HB-SUBSET-FLAGS-NO-LAYOUT-CLOSURE:CAPS"/>
     <keyword type="constant" name="HB_SUBSET_SETS_GLYPH_INDEX" link="harfbuzz-hb-subset.html#HB-SUBSET-SETS-GLYPH-INDEX:CAPS"/>
     <keyword type="constant" name="HB_SUBSET_SETS_UNICODE" link="harfbuzz-hb-subset.html#HB-SUBSET-SETS-UNICODE:CAPS"/>
     <keyword type="constant" name="HB_SUBSET_SETS_NO_SUBSET_TABLE_TAG" link="harfbuzz-hb-subset.html#HB-SUBSET-SETS-NO-SUBSET-TABLE-TAG:CAPS"/>
     <keyword type="constant" name="HB_SUBSET_SETS_NAME_ID" link="harfbuzz-hb-subset.html#HB-SUBSET-SETS-NAME-ID:CAPS"/>
     <keyword type="constant" name="HB_SUBSET_SETS_NAME_LANG_ID" link="harfbuzz-hb-subset.html#HB-SUBSET-SETS-NAME-LANG-ID:CAPS"/>
     <keyword type="constant" name="HB_SUBSET_SETS_LAYOUT_FEATURE_TAG" link="harfbuzz-hb-subset.html#HB-SUBSET-SETS-LAYOUT-FEATURE-TAG:CAPS"/>
+    <keyword type="constant" name="HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG" link="harfbuzz-hb-subset.html#HB-SUBSET-SETS-LAYOUT-SCRIPT-TAG:CAPS"/>
     <keyword type="member" name="hb-glyph-info-t.codepoint" link="harfbuzz-hb-buffer.html#hb-glyph-info-t.codepoint"/>
     <keyword type="member" name="hb-glyph-info-t.cluster" link="harfbuzz-hb-buffer.html#hb-glyph-info-t.cluster"/>
     <keyword type="member" name="hb-glyph-position-t.x-advance" link="harfbuzz-hb-buffer.html#hb-glyph-position-t.x-advance"/>
     <keyword type="member" name="hb-feature-t.end" link="harfbuzz-hb-common.html#hb-feature-t.end"/>
     <keyword type="member" name="hb-variation-t.tag" link="harfbuzz-hb-common.html#hb-variation-t.tag"/>
     <keyword type="member" name="hb-variation-t.value" link="harfbuzz-hb-common.html#hb-variation-t.value"/>
+    <keyword type="member" name="hb-draw-state-t.path-open" link="harfbuzz-hb-draw.html#hb-draw-state-t.path-open"/>
+    <keyword type="member" name="hb-draw-state-t.path-start-x" link="harfbuzz-hb-draw.html#hb-draw-state-t.path-start-x"/>
+    <keyword type="member" name="hb-draw-state-t.path-start-y" link="harfbuzz-hb-draw.html#hb-draw-state-t.path-start-y"/>
+    <keyword type="member" name="hb-draw-state-t.current-x" link="harfbuzz-hb-draw.html#hb-draw-state-t.current-x"/>
+    <keyword type="member" name="hb-draw-state-t.current-y" link="harfbuzz-hb-draw.html#hb-draw-state-t.current-y"/>
+    <keyword type="member" name="hb-color-stop-t.offset" link="harfbuzz-hb-paint.html#hb-color-stop-t.offset"/>
+    <keyword type="member" name="hb-color-stop-t.is-foreground" link="harfbuzz-hb-paint.html#hb-color-stop-t.is-foreground"/>
+    <keyword type="member" name="hb-color-stop-t.color" link="harfbuzz-hb-paint.html#hb-color-stop-t.color"/>
     <keyword type="member" name="hb-ot-var-axis-t.tag" link="harfbuzz-hb-deprecated.html#hb-ot-var-axis-t.tag"/>
     <keyword type="member" name="hb-ot-var-axis-t.name-id" link="harfbuzz-hb-deprecated.html#hb-ot-var-axis-t.name-id"/>
     <keyword type="member" name="hb-ot-var-axis-t.min-value" link="harfbuzz-hb-deprecated.html#hb-ot-var-axis-t.min-value"/>
index c5a145e..576a846 100644 (file)
@@ -65,7 +65,7 @@
 <dt><span class="chapter"><a href="shaping-concepts.html">Shaping concepts</a></span></dt>
 <dd><dl>
 <dt><span class="section"><a href="shaping-concepts.html#text-shaping-concepts">Text shaping</a></span></dt>
-<dt><span class="section"><a href="complex-scripts.html">Complex scripts</a></span></dt>
+<dt><span class="section"><a href="script-specific-shaping.html">Script-specific shaping</a></span></dt>
 <dt><span class="section"><a href="shaping-operations.html">Shaping operations</a></span></dt>
 <dt><span class="section"><a href="unicode-character-categories.html">Unicode character categories</a></span></dt>
 <dt><span class="section"><a href="text-runs.html">Text runs</a></span></dt>
@@ -94,6 +94,7 @@
 <dt><span class="section"><a href="fonts-and-faces-custom-functions.html">Customizing font functions</a></span></dt>
 <dt><span class="section"><a href="fonts-and-faces-native-opentype.html">Font objects and HarfBuzz's native OpenType implementation</a></span></dt>
 <dt><span class="section"><a href="fonts-and-faces-variable.html">Working with OpenType Variable Fonts</a></span></dt>
+<dt><span class="section"><a href="glyphs-and-rendering.html">Glyphs and rendering</a></span></dt>
 </dl></dd>
 <dt><span class="chapter"><a href="shaping-and-shape-plans.html">Shaping and shape plans</a></span></dt>
 <dd><dl>
 <dd><dl>
 <dt><span class="section"><a href="integration.html#integration-glib">GNOME integration, GLib, and GObject</a></span></dt>
 <dt><span class="section"><a href="integration-freetype.html">FreeType integration</a></span></dt>
+<dt><span class="section"><a href="integration-cairo.html">Cairo integration</a></span></dt>
 <dt><span class="section"><a href="integration-uniscribe.html">Uniscribe integration</a></span></dt>
 <dt><span class="section"><a href="integration-coretext.html">Core Text integration</a></span></dt>
 <dt><span class="section"><a href="integration-icu.html">ICU integration</a></span></dt>
 <span class="refentrytitle"><a href="harfbuzz-hb-common.html">hb-common</a></span><span class="refpurpose"> — Common data types</span>
 </dt>
 <dt>
+<span class="refentrytitle"><a href="harfbuzz-hb-features.html">hb-features</a></span><span class="refpurpose"> — Feature detection</span>
+</dt>
+<dt>
+<span class="refentrytitle"><a href="harfbuzz-hb-draw.html">hb-draw</a></span><span class="refpurpose"> — Glyph drawing</span>
+</dt>
+<dt>
+<span class="refentrytitle"><a href="harfbuzz-hb-paint.html">hb-paint</a></span><span class="refpurpose"> — Glyph painting</span>
+</dt>
+<dt>
 <span class="refentrytitle"><a href="harfbuzz-hb-deprecated.html">hb-deprecated</a></span><span class="refpurpose"> — Deprecated API</span>
 </dt>
 <dt>
 <dt>
 <span class="refentrytitle"><a href="harfbuzz-hb-directwrite.html">hb-directwrite</a></span><span class="refpurpose"> — DirectWrite integration</span>
 </dt>
+<dt>
+<span class="refentrytitle"><a href="harfbuzz-hb-cairo.html">hb-cairo</a></span><span class="refpurpose"> — Cairo integration</span>
+</dt>
 </dl></dd>
 <dt><span class="chapter"><a href="style-api.html">Style API</a></span></dt>
 <dd><dl><dt>
 </dt></dl></dd>
 <dt><span class="index"><a href="api-index-full.html">API Index</a></span></dt>
 <dt><span class="index"><a href="deprecated-api-index.html">Index of deprecated API</a></span></dt>
+<dt><span class="index"><a href="api-index-8-2-0.html">Index of new symbols in 8.2.0</a></span></dt>
+<dt><span class="index"><a href="api-index-8-1-0.html">Index of new symbols in 8.1.0</a></span></dt>
+<dt><span class="index"><a href="api-index-8-0-0.html">Index of new symbols in 8.0.0</a></span></dt>
+<dt><span class="index"><a href="api-index-7-3-0.html">Index of new symbols in 7.3.0</a></span></dt>
+<dt><span class="index"><a href="api-index-7-1-0.html">Index of new symbols in 7.1.0</a></span></dt>
+<dt><span class="index"><a href="api-index-7-0-0.html">Index of new symbols in 7.0.0</a></span></dt>
+<dt><span class="index"><a href="api-index-6-0-0.html">Index of new symbols in 6.0.0</a></span></dt>
+<dt><span class="index"><a href="api-index-5-3-0.html">Index of new symbols in 5.3.0</a></span></dt>
+<dt><span class="index"><a href="api-index-5-0-0.html">Index of new symbols in 5.0.0</a></span></dt>
+<dt><span class="index"><a href="api-index-4-4-0.html">Index of new symbols in 4.4.0</a></span></dt>
+<dt><span class="index"><a href="api-index-4-3-0.html">Index of new symbols in 4.3.0</a></span></dt>
+<dt><span class="index"><a href="api-index-4-2-0.html">Index of new symbols in 4.2.0</a></span></dt>
+<dt><span class="index"><a href="api-index-4-1-0.html">Index of new symbols in 4.1.0</a></span></dt>
+<dt><span class="index"><a href="api-index-4-0-0.html">Index of new symbols in 4.0.0</a></span></dt>
 <dt><span class="index"><a href="api-index-3-4-0.html">Index of new symbols in 3.4.0</a></span></dt>
 <dt><span class="index"><a href="api-index-3-3-0.html">Index of new symbols in 3.3.0</a></span></dt>
 <dt><span class="index"><a href="api-index-3-1-0.html">Index of new symbols in 3.1.0</a></span></dt>
 <dt><span class="index"><a href="api-index-1-8-1.html">Index of new symbols in 1.8.1</a></span></dt>
 <dt><span class="index"><a href="api-index-1-8-0.html">Index of new symbols in 1.8.0</a></span></dt>
 <dt><span class="index"><a href="api-index-1-7-7.html">Index of new symbols in 1.7.7</a></span></dt>
-<dt><span class="index"><a href="api-index-1-7-5.html">Index of new symbols in 1.7.5</a></span></dt>
 <dt><span class="index"><a href="api-index-1-7-2.html">Index of new symbols in 1.7.2</a></span></dt>
 <dt><span class="index"><a href="api-index-1-6-0.html">Index of new symbols in 1.6.0</a></span></dt>
 <dt><span class="index"><a href="api-index-1-5-0.html">Index of new symbols in 1.5.0</a></span></dt>
 </dl></div>
 <div class="note">
 <p>
-      The current HarfBuzz codebase is versioned 2.x.x and is stable
+      The current HarfBuzz codebase is stable
       and under active maintenance. This is what is used in latest
       versions of Firefox, GNOME, ChromeOS, Chrome, LibreOffice,
       XeTeX, Android, and KDE, among other places.
index fdb7b45..1bbeb38 100644 (file)
@@ -47,6 +47,9 @@
 <dt>
 <span class="refentrytitle"><a href="harfbuzz-hb-directwrite.html">hb-directwrite</a></span><span class="refpurpose"> — DirectWrite integration</span>
 </dt>
+<dt>
+<span class="refentrytitle"><a href="harfbuzz-hb-cairo.html">hb-cairo</a></span><span class="refpurpose"> — Cairo integration</span>
+</dt>
 </dl></div>
 </div>
 <div class="footer">
diff --git a/docs/html/integration-cairo.html b/docs/html/integration-cairo.html
new file mode 100644 (file)
index 0000000..a3628f4
--- /dev/null
@@ -0,0 +1,66 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Cairo integration: HarfBuzz Manual</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
+<link rel="home" href="index.html" title="HarfBuzz Manual">
+<link rel="up" href="integration.html" title="Platform Integration Guide">
+<link rel="prev" href="integration-freetype.html" title="FreeType integration">
+<link rel="next" href="integration-uniscribe.html" title="Uniscribe integration">
+<meta name="generator" content="GTK-Doc V1.32 (XML mode)">
+<link rel="stylesheet" href="style.css" type="text/css">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
+<td width="100%" align="left" class="shortcuts"></td>
+<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
+<td><a accesskey="u" href="integration.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
+<td><a accesskey="p" href="integration-freetype.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="n" href="integration-uniscribe.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+</tr></table>
+<div class="section">
+<div class="titlepage"><div><div><h2 class="title" style="clear: both">
+<a name="integration-cairo"></a>Cairo integration</h2></div></div></div>
+<p>
+      Cairo is a 2D graphics library that is frequently used together
+      with GTK and Pango. Cairo supports rendering text using FreeType, or
+      by using callback-based 'user fonts'.
+    </p>
+<p>
+      HarfBuzz provides integration points with cairo for fonts as well as
+      for buffers. To use the Cairo-integration API, link against libharfbuzz-cairo,
+      and include the <code class="filename">hb-cairo.h</code> header. For easy buildsystem
+      integration, HarfBuzz comes with a <code class="filename">harfbuzz-cairo.pc</code>
+      pkg-config file.
+    </p>
+<p>
+      To create a <span class="type">cairo_scaled_font_t</span> font from a HarfBuzz
+      <span class="type">hb_font_t</span>, you can use <code class="function">hb_cairo_font_face_create_for_font()</code>
+      or <code class="function">hb_cairo_font_face_create_for_face()</code>. The former API
+      applies variations and synthetic slant from the <span class="type">hb_font_t</span> when
+      rendering, the latter takes them from the <span class="type">cairo_font_options_t</span>
+      that were passed when creating the <span class="type">cairo_scaled_font_t</span>.
+    </p>
+<p>
+      The Cairo fonts created in this way make use of Cairo's user-font facilities.
+      They can be used to render on any Cairo context, and provide full support for
+      font rendering features, including color. One current limitation of the
+      implementation is that it does not support hinting for glyph outlines.
+    </p>
+<p>
+      When using color fonts with this API, the color palette index is taken from
+      the <span class="type">cairo_font_options_t</span> (with new enough Cairo), and the foreground
+      color is extracted from the source of the Cairo context.
+    </p>
+<p>
+      To render the results of shaping a piece of text, use
+      <code class="function">hb_cairo_glyphs_from_buffer()</code> to obtain the glyphs in
+      a form that can be passed to <code class="function">cairo_show_text_glyphs()</code> or
+      <code class="function">cairo_show_glyphs()</code>.
+    </p>
+</div>
+<div class="footer">
+<hr>Generated by GTK-Doc V1.32</div>
+</body>
+</html>
\ No newline at end of file
index c1070e9..3a5ae35 100644 (file)
@@ -7,7 +7,7 @@
 <link rel="home" href="index.html" title="HarfBuzz Manual">
 <link rel="up" href="integration.html" title="Platform Integration Guide">
 <link rel="prev" href="integration.html" title="Platform Integration Guide">
-<link rel="next" href="integration-uniscribe.html" title="Uniscribe integration">
+<link rel="next" href="integration-cairo.html" title="Cairo integration">
 <meta name="generator" content="GTK-Doc V1.32 (XML mode)">
 <link rel="stylesheet" href="style.css" type="text/css">
 </head>
@@ -17,7 +17,7 @@
 <td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
 <td><a accesskey="u" href="integration.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
 <td><a accesskey="p" href="integration.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
-<td><a accesskey="n" href="integration-uniscribe.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+<td><a accesskey="n" href="integration-cairo.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
 </tr></table>
 <div class="section">
 <div class="titlepage"><div><div><h2 class="title" style="clear: both">
@@ -34,7 +34,9 @@
 <p>
       HarfBuzz provides integration points with FreeType at the
       face-object and font-object level and for the font-functions
-      virtual-method structure of a font object. To use the
+      virtual-method structure of a font object. These functions
+      make it easy for clients that use FreeType for rasterization
+      or font-loading, to use HarfBuzz for shaping. To use the
       FreeType-integration API, include the
       <code class="filename">hb-ft.h</code> header.
     </p>
index e95014f..e6c521a 100644 (file)
@@ -6,7 +6,7 @@
 <meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
 <link rel="home" href="index.html" title="HarfBuzz Manual">
 <link rel="up" href="integration.html" title="Platform Integration Guide">
-<link rel="prev" href="integration-freetype.html" title="FreeType integration">
+<link rel="prev" href="integration-cairo.html" title="Cairo integration">
 <link rel="next" href="integration-coretext.html" title="Core Text integration">
 <meta name="generator" content="GTK-Doc V1.32 (XML mode)">
 <link rel="stylesheet" href="style.css" type="text/css">
@@ -16,7 +16,7 @@
 <td width="100%" align="left" class="shortcuts"></td>
 <td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
 <td><a accesskey="u" href="integration.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
-<td><a accesskey="p" href="integration-freetype.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="p" href="integration-cairo.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
 <td><a accesskey="n" href="integration-coretext.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
 </tr></table>
 <div class="section">
index 8493b91..7fd264b 100644 (file)
@@ -25,6 +25,7 @@
 <div class="toc"><dl class="toc">
 <dt><span class="section"><a href="integration.html#integration-glib">GNOME integration, GLib, and GObject</a></span></dt>
 <dt><span class="section"><a href="integration-freetype.html">FreeType integration</a></span></dt>
+<dt><span class="section"><a href="integration-cairo.html">Cairo integration</a></span></dt>
 <dt><span class="section"><a href="integration-uniscribe.html">Uniscribe integration</a></span></dt>
 <dt><span class="section"><a href="integration-coretext.html">Core Text integration</a></span></dt>
 <dt><span class="section"><a href="integration-icu.html">ICU integration</a></span></dt>
index 8fd85a7..bbb4724 100644 (file)
 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
 <li class="listitem"><p>
          The <span class="emphasis"><em>default</em></span> shaping model handles all
-         non-complex scripts, and may also be used as a fallback for
+         scripts with no script-specific shaping model, and may also be used as a fallback for
          handling unrecognized scripts.
        </p></li>
 <li class="listitem">
 <p>
          The <span class="emphasis"><em>Indic</em></span> shaping model handles the Indic
          scripts Bengali, Devanagari, Gujarati, Gurmukhi, Kannada,
-         Malayalam, Oriya, Tamil, Telugu, and Sinhala.
+         Malayalam, Oriya, Tamil, and Telugu.
        </p>
 <p>
          The Indic shaping model was revised significantly in
@@ -78,7 +78,7 @@
        </p></li>
 <li class="listitem"><p>
          The <span class="emphasis"><em>Universal Shaping Engine</em></span> (USE)
-         shaping model supports complex scripts not covered by one of
+         shaping model supports scripts not covered by one of
          the above, script-specific shaping models, including
          Javanese, Balinese, Buginese, Batak, Chakma, Lepcha, Modi,
          Phags-pa, Tagalog, Siddham, Sundanese, Tai Le, Tai Tham, Tai
index e9f73da..51426e3 100644 (file)
@@ -24,7 +24,7 @@
 <div><h1 class="title">
 <a name="reference-manual"></a>Part II. Reference manual</h1></div>
 <div><p class="releaseinfo">
-        This document is for HarfBuzz 3.4.0
+        This document is for HarfBuzz 8.2.2
 .
         
       </p></div>
 <span class="refentrytitle"><a href="harfbuzz-hb-common.html">hb-common</a></span><span class="refpurpose"> — Common data types</span>
 </dt>
 <dt>
+<span class="refentrytitle"><a href="harfbuzz-hb-features.html">hb-features</a></span><span class="refpurpose"> — Feature detection</span>
+</dt>
+<dt>
+<span class="refentrytitle"><a href="harfbuzz-hb-draw.html">hb-draw</a></span><span class="refpurpose"> — Glyph drawing</span>
+</dt>
+<dt>
+<span class="refentrytitle"><a href="harfbuzz-hb-paint.html">hb-paint</a></span><span class="refpurpose"> — Glyph painting</span>
+</dt>
+<dt>
 <span class="refentrytitle"><a href="harfbuzz-hb-deprecated.html">hb-deprecated</a></span><span class="refpurpose"> — Deprecated API</span>
 </dt>
 <dt>
 <dt>
 <span class="refentrytitle"><a href="harfbuzz-hb-directwrite.html">hb-directwrite</a></span><span class="refpurpose"> — DirectWrite integration</span>
 </dt>
+<dt>
+<span class="refentrytitle"><a href="harfbuzz-hb-cairo.html">hb-cairo</a></span><span class="refpurpose"> — Cairo integration</span>
+</dt>
 </dl></dd>
 <dt><span class="chapter"><a href="style-api.html">Style API</a></span></dt>
 <dd><dl><dt>
 </dt></dl></dd>
 <dt><span class="index"><a href="api-index-full.html">API Index</a></span></dt>
 <dt><span class="index"><a href="deprecated-api-index.html">Index of deprecated API</a></span></dt>
+<dt><span class="index"><a href="api-index-8-2-0.html">Index of new symbols in 8.2.0</a></span></dt>
+<dt><span class="index"><a href="api-index-8-1-0.html">Index of new symbols in 8.1.0</a></span></dt>
+<dt><span class="index"><a href="api-index-8-0-0.html">Index of new symbols in 8.0.0</a></span></dt>
+<dt><span class="index"><a href="api-index-7-3-0.html">Index of new symbols in 7.3.0</a></span></dt>
+<dt><span class="index"><a href="api-index-7-1-0.html">Index of new symbols in 7.1.0</a></span></dt>
+<dt><span class="index"><a href="api-index-7-0-0.html">Index of new symbols in 7.0.0</a></span></dt>
+<dt><span class="index"><a href="api-index-6-0-0.html">Index of new symbols in 6.0.0</a></span></dt>
+<dt><span class="index"><a href="api-index-5-3-0.html">Index of new symbols in 5.3.0</a></span></dt>
+<dt><span class="index"><a href="api-index-5-0-0.html">Index of new symbols in 5.0.0</a></span></dt>
+<dt><span class="index"><a href="api-index-4-4-0.html">Index of new symbols in 4.4.0</a></span></dt>
+<dt><span class="index"><a href="api-index-4-3-0.html">Index of new symbols in 4.3.0</a></span></dt>
+<dt><span class="index"><a href="api-index-4-2-0.html">Index of new symbols in 4.2.0</a></span></dt>
+<dt><span class="index"><a href="api-index-4-1-0.html">Index of new symbols in 4.1.0</a></span></dt>
+<dt><span class="index"><a href="api-index-4-0-0.html">Index of new symbols in 4.0.0</a></span></dt>
 <dt><span class="index"><a href="api-index-3-4-0.html">Index of new symbols in 3.4.0</a></span></dt>
 <dt><span class="index"><a href="api-index-3-3-0.html">Index of new symbols in 3.3.0</a></span></dt>
 <dt><span class="index"><a href="api-index-3-1-0.html">Index of new symbols in 3.1.0</a></span></dt>
 <dt><span class="index"><a href="api-index-1-8-1.html">Index of new symbols in 1.8.1</a></span></dt>
 <dt><span class="index"><a href="api-index-1-8-0.html">Index of new symbols in 1.8.0</a></span></dt>
 <dt><span class="index"><a href="api-index-1-7-7.html">Index of new symbols in 1.7.7</a></span></dt>
-<dt><span class="index"><a href="api-index-1-7-5.html">Index of new symbols in 1.7.5</a></span></dt>
 <dt><span class="index"><a href="api-index-1-7-2.html">Index of new symbols in 1.7.2</a></span></dt>
 <dt><span class="index"><a href="api-index-1-6-0.html">Index of new symbols in 1.6.0</a></span></dt>
 <dt><span class="index"><a href="api-index-1-5-0.html">Index of new symbols in 1.5.0</a></span></dt>
index a051767..2dc32dd 100644 (file)
@@ -23,7 +23,7 @@
 <div class="titlepage"><div><div><h2 class="title" style="clear: both">
 <a name="reordering-in-levels-0-and-1"></a>Reordering in levels 0 and 1</h2></div></div></div>
 <p>
-      Another common operation in the more complex shapers is glyph
+      Another common operation in some shapers is glyph
       reordering. In order to maintain a monotonic cluster sequence
       when glyph reordering takes place, HarfBuzz merges the clusters
       of everything in the reordering sequence.
similarity index 65%
rename from docs/html/complex-scripts.html
rename to docs/html/script-specific-shaping.html
index fcce71f..c9f9899 100644 (file)
@@ -2,7 +2,7 @@
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-<title>Complex scripts: HarfBuzz Manual</title>
+<title>Script-specific shaping: HarfBuzz Manual</title>
 <meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
 <link rel="home" href="index.html" title="HarfBuzz Manual">
 <link rel="up" href="shaping-concepts.html" title="Shaping concepts">
 </tr></table>
 <div class="section">
 <div class="titlepage"><div><div><h2 class="title" style="clear: both">
-<a name="complex-scripts"></a>Complex scripts</h2></div></div></div>
+<a name="script-specific-shaping"></a>Script-specific shaping</h2></div></div></div>
 <p>
-      In text-shaping terminology, scripts are generally classified as
-      either <span class="emphasis"><em>complex</em></span> or <span class="emphasis"><em>non-complex</em></span>.
-    </p>
-<p>
-      Complex scripts are those for which transforming the input
-      sequence into the final layout requires some combination of
+      In many scripts, transforming the input
+      sequence into the final layout often requires some combination of
       operations—such as context-dependent substitutions,
       context-dependent mark positioning, glyph-to-glyph joining,
       glyph reordering, or glyph stacking.
     </p>
 <p>
-      In some complex scripts, the shaping rules require that a text
+      In some scripts, the shaping rules require that a text
       run be divided into syllables before the operations can be
-      applied. Other complex scripts may apply shaping operations over
+      applied. Other scripts may apply shaping operations over
       entire words or over the entire text run, with no subdivision
       required.
     </p>
 <p>
-      Non-complex scripts, by definition, do not require these
-      operations. However, correctly shaping a text run in a
-      non-complex script may still involve Unicode normalization,
+      Other scripts, do not require these
+      operations. However, correctly shaping a text run in
+      any script may still involve Unicode normalization,
       ligature substitutions, mark positioning, kerning, and applying
-      other font features. The key difference is that a text run in a
-      non-complex script can be processed sequentially and in the same
-      order as the input sequence of Unicode codepoints, without
-      requiring an analysis stage.
+      other font features.
     </p>
 </div>
 <div class="footer">
index 3e19db5..cb26245 100644 (file)
@@ -6,7 +6,7 @@
 <meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
 <link rel="home" href="index.html" title="HarfBuzz Manual">
 <link rel="up" href="user-manual.html" title="Part I. User's manual">
-<link rel="prev" href="fonts-and-faces-variable.html" title="Working with OpenType Variable Fonts">
+<link rel="prev" href="glyphs-and-rendering.html" title="Glyphs and rendering">
 <link rel="next" href="shaping-opentype-features.html" title="OpenType features">
 <meta name="generator" content="GTK-Doc V1.32 (XML mode)">
 <link rel="stylesheet" href="style.css" type="text/css">
@@ -16,7 +16,7 @@
 <td width="100%" align="left" class="shortcuts"></td>
 <td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
 <td><a accesskey="u" href="user-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
-<td><a accesskey="p" href="fonts-and-faces-variable.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="p" href="glyphs-and-rendering.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
 <td><a accesskey="n" href="shaping-opentype-features.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
 </tr></table>
 <div class="chapter">
     </p>
 <p>
       The algorithms
-      used for complex scripts can be quite involved; HarfBuzz tries
+      used for shaping can be quite involved; HarfBuzz tries
       to be compatible with the OpenType Layout specification
       and, wherever there is any ambiguity, HarfBuzz attempts to replicate the
-      output of Microsoft's Uniscribe engine. See the <a class="ulink" href="https://docs.microsoft.com/en-us/typography/script-development/standard" target="_top">Microsoft
+      output of Microsoft's Uniscribe engine, to the extent that is feasible and desirable. See the <a class="ulink" href="https://docs.microsoft.com/en-us/typography/script-development/standard" target="_top">Microsoft
       Typography pages</a> for more detail.
     </p>
 <p>
index 6ce7bcc..31d4731 100644 (file)
@@ -7,7 +7,7 @@
 <link rel="home" href="index.html" title="HarfBuzz Manual">
 <link rel="up" href="user-manual.html" title="Part I. User's manual">
 <link rel="prev" href="a-simple-shaping-example.html" title="A simple shaping example">
-<link rel="next" href="complex-scripts.html" title="Complex scripts">
+<link rel="next" href="script-specific-shaping.html" title="Script-specific shaping">
 <meta name="generator" content="GTK-Doc V1.32 (XML mode)">
 <link rel="stylesheet" href="style.css" type="text/css">
 </head>
 <td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
 <td><a accesskey="u" href="user-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
 <td><a accesskey="p" href="a-simple-shaping-example.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
-<td><a accesskey="n" href="complex-scripts.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
+<td><a accesskey="n" href="script-specific-shaping.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
 </tr></table>
 <div class="chapter">
 <div class="titlepage"><div><div><h2 class="title">
 <a name="shaping-concepts"></a>Shaping concepts</h2></div></div></div>
 <div class="toc"><dl class="toc">
 <dt><span class="section"><a href="shaping-concepts.html#text-shaping-concepts">Text shaping</a></span></dt>
-<dt><span class="section"><a href="complex-scripts.html">Complex scripts</a></span></dt>
+<dt><span class="section"><a href="script-specific-shaping.html">Script-specific shaping</a></span></dt>
 <dt><span class="section"><a href="shaping-operations.html">Shaping operations</a></span></dt>
 <dt><span class="section"><a href="unicode-character-categories.html">Unicode character categories</a></span></dt>
 <dt><span class="section"><a href="text-runs.html">Text runs</a></span></dt>
@@ -49,7 +49,7 @@
       correct amount for each successive glyph.
     </p>
 <p>
-      But, for <span class="emphasis"><em>complex scripts</em></span>, any combination of
+      But, for other scripts (often unceremoniously called <span class="emphasis"><em>complex scripts</em></span>), any combination of
       several shaping operations may be required, and the rules for how
       and when they are applied vary from script to script. HarfBuzz and
       other shaping engines implement these rules.
index e36d84a..ef0e896 100644 (file)
@@ -32,7 +32,7 @@
     </p>
 <p>
       Some OpenType features are defined for the purpose of supporting
-      complex-script shaping, and are automatically activated, but
+      script-specific shaping, and are automatically activated, but
       only when a buffer's script property is set to a script that the
       feature supports.
     </p>
index b96df28..72bab04 100644 (file)
@@ -6,7 +6,7 @@
 <meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
 <link rel="home" href="index.html" title="HarfBuzz Manual">
 <link rel="up" href="shaping-concepts.html" title="Shaping concepts">
-<link rel="prev" href="complex-scripts.html" title="Complex scripts">
+<link rel="prev" href="script-specific-shaping.html" title="Script-specific shaping">
 <link rel="next" href="unicode-character-categories.html" title="Unicode character categories">
 <meta name="generator" content="GTK-Doc V1.32 (XML mode)">
 <link rel="stylesheet" href="style.css" type="text/css">
 <td width="100%" align="left" class="shortcuts"></td>
 <td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
 <td><a accesskey="u" href="shaping-concepts.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
-<td><a accesskey="p" href="complex-scripts.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="p" href="script-specific-shaping.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
 <td><a accesskey="n" href="unicode-character-categories.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
 </tr></table>
 <div class="section">
 <div class="titlepage"><div><div><h2 class="title" style="clear: both">
 <a name="shaping-operations"></a>Shaping operations</h2></div></div></div>
 <p>
-      Shaping a complex-script text run involves transforming the
+      Shaping a text run involves transforming the
       input sequence of Unicode codepoints with some combination of
       operations that is specified in the shaping model for the
       script.
@@ -33,7 +33,7 @@
       text run varies from script to script, as do the order that the
       operations are performed in and which codepoints are
       affected. However, the same general set of shaping operations is
-      common to all of the complex-script shaping models. 
+      common to all of the script shaping models. 
     </p>
 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
 <li class="listitem">
@@ -43,7 +43,7 @@
          some other ("visual") position.
        </p>
 <p>
-         The shaping model for a given complex script might involve
+         The shaping model for a given script might involve
          more than one reordering step.
        </p>
 </li>
@@ -66,7 +66,7 @@
          particular string pattern.
        </p>
 <p>
-         The shaping model for a given complex script might involve
+         The shaping model for a given script might involve
          multiple contextual-substitution operations, each applying
          to different target glyphs and patterns, and which are
          performed in separate steps.
@@ -84,7 +84,7 @@
          Many contextual positioning operations are used to place
          <span class="emphasis"><em>mark</em></span> glyphs (such as diacritics, vowel
          signs, and tone markers) with respect to
-         <span class="emphasis"><em>base</em></span> glyphs. However, some complex
+         <span class="emphasis"><em>base</em></span> glyphs. However, some
          scripts may use contextual positioning operations to
          correctly place base glyphs as well, such as
          when the script uses <span class="emphasis"><em>stacking</em></span> characters.
index 952cf46..fabeddc 100644 (file)
@@ -6,7 +6,7 @@
 <meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
 <link rel="home" href="index.html" title="HarfBuzz Manual">
 <link rel="up" href="reference-manual.html" title="Part II. Reference manual">
-<link rel="prev" href="harfbuzz-hb-directwrite.html" title="hb-directwrite">
+<link rel="prev" href="harfbuzz-hb-cairo.html" title="hb-cairo">
 <link rel="next" href="harfbuzz-hb-style.html" title="hb-style">
 <meta name="generator" content="GTK-Doc V1.32 (XML mode)">
 <link rel="stylesheet" href="style.css" type="text/css">
@@ -16,7 +16,7 @@
 <td width="100%" align="left" class="shortcuts"></td>
 <td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
 <td><a accesskey="u" href="reference-manual.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
-<td><a accesskey="p" href="harfbuzz-hb-directwrite.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
+<td><a accesskey="p" href="harfbuzz-hb-cairo.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
 <td><a accesskey="n" href="harfbuzz-hb-style.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
 </tr></table>
 <div class="chapter">
index f1c3dbe..fc63fdc 100644 (file)
@@ -66,7 +66,7 @@
              implements separate shapers for Indic, Arabic, Thai and
              Lao, Khmer, Myanmar, Tibetan, Hangul, Hebrew, the
              Universal Shaping Engine (USE), and a default shaper for
-             non-complex scripts. 
+             scripts with no script-specific shaping model.
            </p></td>
 </tr>
 <tr>
index 8ecaf32..2a6e537 100644 (file)
@@ -66,7 +66,7 @@
       multiple positions).
     </p>
 <p>
-      Some complex scripts require that the text run be split into
+      Some scripts require that the text run be split into
       syllables. What constitutes a valid syllable in these
       scripts is specified in regular expressions, formed from the
       Letter and Mark codepoints, that take the UISC and UIPC
index 5420493..3331b05 100644 (file)
@@ -53,7 +53,7 @@
 <dt><span class="chapter"><a href="shaping-concepts.html">Shaping concepts</a></span></dt>
 <dd><dl>
 <dt><span class="section"><a href="shaping-concepts.html#text-shaping-concepts">Text shaping</a></span></dt>
-<dt><span class="section"><a href="complex-scripts.html">Complex scripts</a></span></dt>
+<dt><span class="section"><a href="script-specific-shaping.html">Script-specific shaping</a></span></dt>
 <dt><span class="section"><a href="shaping-operations.html">Shaping operations</a></span></dt>
 <dt><span class="section"><a href="unicode-character-categories.html">Unicode character categories</a></span></dt>
 <dt><span class="section"><a href="text-runs.html">Text runs</a></span></dt>
@@ -82,6 +82,7 @@
 <dt><span class="section"><a href="fonts-and-faces-custom-functions.html">Customizing font functions</a></span></dt>
 <dt><span class="section"><a href="fonts-and-faces-native-opentype.html">Font objects and HarfBuzz's native OpenType implementation</a></span></dt>
 <dt><span class="section"><a href="fonts-and-faces-variable.html">Working with OpenType Variable Fonts</a></span></dt>
+<dt><span class="section"><a href="glyphs-and-rendering.html">Glyphs and rendering</a></span></dt>
 </dl></dd>
 <dt><span class="chapter"><a href="shaping-and-shape-plans.html">Shaping and shape plans</a></span></dt>
 <dd><dl>
 <dd><dl>
 <dt><span class="section"><a href="integration.html#integration-glib">GNOME integration, GLib, and GObject</a></span></dt>
 <dt><span class="section"><a href="integration-freetype.html">FreeType integration</a></span></dt>
+<dt><span class="section"><a href="integration-cairo.html">Cairo integration</a></span></dt>
 <dt><span class="section"><a href="integration-uniscribe.html">Uniscribe integration</a></span></dt>
 <dt><span class="section"><a href="integration-coretext.html">Core Text integration</a></span></dt>
 <dt><span class="section"><a href="integration-icu.html">ICU integration</a></span></dt>
index 937bd35..643f503 100644 (file)
@@ -30,8 +30,7 @@
 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
 <li class="listitem"><p>
          Indic (covering Devanagari, Bengali, Gujarati,
-         Gurmukhi, Kannada, Malayalam, Oriya, Tamil, Telugu, and
-         Sinhala)
+         Gurmukhi, Kannada, Malayalam, Oriya, Tamil, and Telugu)
        </p></li>
 <li class="listitem"><p>
          Arabic (covering Arabic, N'Ko, Syriac, and Mongolian)
index 7641d06..9e39c46 100644 (file)
     </p>
 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
 <li class="listitem">
-<p><span class="emphasis"><em>Level 0</em></span> is the default and
-       reproduces the behavior of the old HarfBuzz library.
+<p><span class="emphasis"><em>Level 0</em></span> is the default.
        </p>
 <p>
          The distinguishing feature of level 0 behavior is that, at
          as well as the <span class="emphasis"><em>Zero Width Joiner</em></span> and
          <span class="emphasis"><em>Zero Width Non-Joiner</em></span> code points, are
          assigned the cluster value of the closest preceding code
-         point from <span class="emphasis"><em>different</em></span> category. 
+         point from <span class="emphasis"><em>different</em></span> category.
        </p>
 <p>
          In essence, whenever a base character is followed by a mark
          Technical Report 29</a>.
        </p>
 <p>
+         This cluster level is suitable for code that likes to use
+         HarfBuzz cluster values as an approximation of the Unicode
+         Grapheme Cluster Boundaries as well.
+       </p>
+<p>
          Client programs can specify level 0 behavior for a buffer by
          setting its <code class="literal">cluster_level</code> to
          <code class="literal">HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES</code>. 
          implement backward compatibility with the old HarfBuzz.
        </p>
 <p>
-         Level 1 differs from level 0 by not merging the 
+         <span class="emphasis"><em>Level 1</em></span> differs from level 0 by not merging the
          clusters of marks and other modifier code points with the
          preceding "base" code point's cluster. By preserving the
          separate cluster values of these marks and modifier code
          points, script shapers can perform additional operations
-         that might lead to improved results (for example, reordering
-         a sequence of marks).
+         that might lead to improved results (for example, coloring
+         mark glyphs differently than their base).
        </p>
 <p>
          Client programs can specify level 1 behavior for a buffer by
        </p>
 <p>
          This difference can be seen most clearly when HarfBuzz processes
-         ligature substitutions and glyph decompositions. In level 0 
+         ligature substitutions and glyph decompositions. In level 0
          and level 1, ligatures and glyph decomposition both involve
          merging clusters; in level 2, neither of these operations
          triggers a merge.
       assign initial cluster values in a buffer by reusing the indices
       of the code points in the input text. This gives a sequence of
       cluster values that is monotonically increasing (for example,
-      0,1,2,3,4). 
+      0,1,2,3,4).
     </p>
 <p>
       It is not <span class="emphasis"><em>required</em></span> that the cluster values
index 9da1fd5..45ca93a 100644 (file)
@@ -1,8 +1,3 @@
-if build_machine.system() == 'windows'
-  message('Skipping gtk-doc while building on Windows')
-  subdir_done()
-endif
-
 if not find_program('gtkdoc-scan', required: get_option('docs')).found()
   message('Not building documentation as gtk-doc was not found')
   subdir_done()
@@ -41,10 +36,12 @@ html_images = [
 ]
 
 ignore_headers = [
+  'hb-features.h',
   'hb-gobject.h',
   'hb-gobject-enums.h',
   'hb-gobject-enums-tmp.h',
   'hb-gobject-structs.h',
+  'hb-wasm-api.h',
 ]
 
 gnome.gtkdoc('harfbuzz',
@@ -53,7 +50,7 @@ gnome.gtkdoc('harfbuzz',
             meson.current_build_dir() / '..' / 'src',
            ],
   scan_args: ['--deprecated-guards=HB_DISABLE_DEPRECATED',
-              '--ignore-decorators=HB_EXTERN|HB_DEPRECATED',
+              '--ignore-decorators=HB_EXTERN|HB_DEPRECATED|HB_DEPRECATED_FOR()',
              ],
   mkdb_args: ['--source-suffixes=h,cc',
               '--xml-mode',
@@ -63,4 +60,6 @@ gnome.gtkdoc('harfbuzz',
   html_assets: html_images,
   ignore_headers: ignore_headers,
   dependencies: [libharfbuzz_dep],
-  install: true)
+  install: true,
+  check: get_option('doc_tests'),
+)
index 9147ff0..545afde 100644 (file)
     </para>
     <itemizedlist>
       <listitem>
-       <para><emphasis>Level 0</emphasis> is the default and
-       reproduces the behavior of the old HarfBuzz library.
+       <para><emphasis>Level 0</emphasis> is the default.
        </para>
        <para>
          The distinguishing feature of level 0 behavior is that, at
          as well as the <emphasis>Zero Width Joiner</emphasis> and
          <emphasis>Zero Width Non-Joiner</emphasis> code points, are
          assigned the cluster value of the closest preceding code
-         point from <emphasis>different</emphasis> category. 
+         point from <emphasis>different</emphasis> category.
        </para>
        <para>
          In essence, whenever a base character is followed by a mark
          Technical Report 29</ulink>.
        </para>
        <para>
+         This cluster level is suitable for code that likes to use
+         HarfBuzz cluster values as an approximation of the Unicode
+         Grapheme Cluster Boundaries as well.
+       </para>
+       <para>
          Client programs can specify level 0 behavior for a buffer by
          setting its <literal>cluster_level</literal> to
          <literal>HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES</literal>. 
          implement backward compatibility with the old HarfBuzz.
        </para>
        <para>
-         Level 1 differs from level 0 by not merging the 
+         <emphasis>Level 1</emphasis> differs from level 0 by not merging the
          clusters of marks and other modifier code points with the
          preceding "base" code point's cluster. By preserving the
          separate cluster values of these marks and modifier code
          points, script shapers can perform additional operations
-         that might lead to improved results (for example, reordering
-         a sequence of marks).
+         that might lead to improved results (for example, coloring
+         mark glyphs differently than their base).
        </para>
        <para>
          Client programs can specify level 1 behavior for a buffer by
        </para>
        <para>
          This difference can be seen most clearly when HarfBuzz processes
-         ligature substitutions and glyph decompositions. In level 0 
+         ligature substitutions and glyph decompositions. In level 0
          and level 1, ligatures and glyph decomposition both involve
          merging clusters; in level 2, neither of these operations
          triggers a merge.
       assign initial cluster values in a buffer by reusing the indices
       of the code points in the input text. This gives a sequence of
       cluster values that is monotonically increasing (for example,
-      0,1,2,3,4). 
+      0,1,2,3,4).
     </para>
     <para>
       It is not <emphasis>required</emphasis> that the cluster values
       </listitem>
     </itemizedlist>
   </section>
-  
+
   <section id="a-clustering-example-for-levels-0-and-1">
     <title>A clustering example for levels 0 and 1</title>
     <para>
   <section id="reordering-in-levels-0-and-1">
     <title>Reordering in levels 0 and 1</title>
     <para>
-      Another common operation in the more complex shapers is glyph
+      Another common operation in some shapers is glyph
       reordering. In order to maintain a monotonic cluster sequence
       when glyph reordering takes place, HarfBuzz merges the clusters
       of everything in the reordering sequence.
index abf5dc2..3923394 100644 (file)
@@ -55,7 +55,7 @@
       shaping. The typeface must be set to a specific point size in
       order for some details (such as hinting) to work. In addition,
       if the font file in question is an OpenType Variable Font, then
-      you may need to specify one or variation-axis settings (or a
+      you may need to specify one or more variation-axis settings (or a
       named instance) in order to get the output you need.
     </para>
     <para>
       the glyph index that corresponds to a given glyph name.
     </para>
       </listitem>
+      <listitem>
+    <para>
+      <function>hb_font_draw_glyph_func_t</function>: gets the outlines
+      of a glyph (by calling #hb_draw_funcs_t callbacks).
+    </para>
+      </listitem>
+      <listitem>
+    <para>
+      <function>hb_font_paint_glyph_func_t</function>: paints a glyph
+      (by calling #hb_paint_funcs_t callbacks).
+    </para>
+      </listitem>
     </itemizedlist>
     <para>
       You can create new font-functions by calling
     </para>
   </section>
 
-
-  <!-- Commenting out FreeType integration section-holder for now. May move
-       to the full-blown Integration Chapter. -->
-  
-  <!--   <section id="fonts-and-faces-freetype">
-    <title>Using FreeType</title>
-    <para>
-
-    </para>
-    <para>
-      
-    </para>
-  </section> -->
-
   <section id="fonts-and-faces-variable">
     <title>Working with OpenType Variable Fonts</title>
     <para>
       range actually implemented in the font's variation axis. After
       all, a font might only provide lighter-than-regular weights, and
       setting a heavier value on the <literal>wght</literal> axis will
-      not change that. 
+      not change that.
     </para>
     <para>
       Once your variation settings are specified on your font object,
       however, shaping with a variable font is just like shaping a
       static font.
     </para>
+    <para>
+      In addition to providing the variation axes themselves, fonts may also
+      pre-define certain variation coordinates as named instances. HarfBuzz
+      makes these coordinates (and their associated names) available via
+      <function>hb_ot_var_named_instance_get_design_coords()</function> and
+      <function>hb_ot_var_named_instance_get_subfamily_name_id()</function>.
+    </para>
+    <para>
+      Applications should treat named instances like multiple independent,
+      static fonts.
+    </para>
+  </section>
+
+  <section id="glyphs-and-rendering">
+    <title>Glyphs and rendering</title>
+
+    <para>
+      The main purpose of HarfBuzz is shaping, which creates a list of positioned
+      glyphs as output. The remaining task for text layout is to convert this list
+      into rendered output. While HarfBuzz does not handle rasterization of glyphs
+      per se, it does have APIs that provide access to the font data that is needed
+      to perform this task.
+    </para>
+    <para>
+      Traditionally, the shapes of glyphs in scalable fonts are provided as quadratic
+      or cubic Beziér curves defining outlines to be filled. To obtain the outlines
+      for a glyph, call <function>hb_font_draw_glyph()</function> and pass a
+      <type>hb_draw_funcs_t</type> struct. The callbacks in that struct will be called
+      for each segment of the outline. Note that this API provides access to outlines
+      as they are defined in the font, without applying hinting to fit the curves
+      to the pixel grid.
+    </para>
+    <para>
+      Fonts may provide pre-rendered images for glyphs instead of or in addition to
+      outlines. This is most common for fonts that contain colored glyphs, such as
+      Emoji. To access these images, use <function>hb_ot_color_reference_png()</function>
+      or <function>hb_ot_color_reference_svg()</function>.
+    </para>
+    <para>
+      Another way in which fonts provide colored glyphs is via paint graphs that
+      combine glyph outlines with gradients and allow for transformations and
+      compositing. In its simplest form, this can be presented as a series of
+      layers that are rendered on top of each other, each with its own color.
+      HarfBuzz has the <function>hb_ot_color_glyph_get_layers()</function> to
+      access glyph data in this form.
+    </para>
+    <para>
+      In the general case, you have to use <function>hb_font_paint_glyph()</function>
+      and pass a <type>hb_paint_funcs_t</type> struct with callbacks to obtain paint
+      graphs for glyphs that have them. The <function>hb_font_paint_glyph()</function>
+      API can handle outline and image glyphs as well, so it provides a unified API for
+      access to glyph rendering information.
+    </para>
   </section>
 
  </chapter>
index e7241a6..7048b4e 100644 (file)
              implements separate shapers for Indic, Arabic, Thai and
              Lao, Khmer, Myanmar, Tibetan, Hangul, Hebrew, the
              Universal Shaping Engine (USE), and a default shaper for
-             non-complex scripts. 
+             scripts with no script-specific shaping model.
            </para>
          </listitem>
        </varlistentry>
       </listitem>
     </orderedlist>
     <programlisting language="C">
+      // If you know the direction, script, and language
       hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
       hb_buffer_set_script(buf, HB_SCRIPT_LATIN);
       hb_buffer_set_language(buf, hb_language_from_string("en", -1));
+
+      // If you don't know the direction, script, and language
+      hb_buffer_guess_segment_properties(buffer);
     </programlisting>
     <orderedlist numeration="arabic">
       <listitem override="3">
index 5d31ec2..e208370 100644 (file)
     <para>
       HarfBuzz provides integration points with FreeType at the
       face-object and font-object level and for the font-functions
-      virtual-method structure of a font object. To use the
+      virtual-method structure of a font object. These functions
+      make it easy for clients that use FreeType for rasterization
+      or font-loading, to use HarfBuzz for shaping. To use the
       FreeType-integration API, include the
       <filename>hb-ft.h</filename> header.
     </para>
       it when it is unneeded.
     </para>
   </section>
-  
+
+  <section id="integration-cairo">
+    <title>Cairo integration</title>
+
+    <para>
+      Cairo is a 2D graphics library that is frequently used together
+      with GTK and Pango. Cairo supports rendering text using FreeType, or
+      by using callback-based 'user fonts'.
+    </para>
+    <para>
+      HarfBuzz provides integration points with cairo for fonts as well as
+      for buffers. To use the Cairo-integration API, link against libharfbuzz-cairo,
+      and include the <filename>hb-cairo.h</filename> header. For easy buildsystem
+      integration, HarfBuzz comes with a <filename>harfbuzz-cairo.pc</filename>
+      pkg-config file.
+    </para>
+    <para>
+      To create a <type>cairo_scaled_font_t</type> font from a HarfBuzz
+      <type>hb_font_t</type>, you can use <function>hb_cairo_font_face_create_for_font()</function>
+      or <function>hb_cairo_font_face_create_for_face()</function>. The former API
+      applies variations and synthetic slant from the <type>hb_font_t</type> when
+      rendering, the latter takes them from the <type>cairo_font_options_t</type>
+      that were passed when creating the <type>cairo_scaled_font_t</type>.
+    </para>
+    <para>
+      The Cairo fonts created in this way make use of Cairo's user-font facilities.
+      They can be used to render on any Cairo context, and provide full support for
+      font rendering features, including color. One current limitation of the
+      implementation is that it does not support hinting for glyph outlines.
+    </para>
+    <para>
+      When using color fonts with this API, the color palette index is taken from
+      the <type>cairo_font_options_t</type> (with new enough Cairo), and the foreground
+      color is extracted from the source of the Cairo context.
+    </para>
+    <para>
+      To render the results of shaping a piece of text, use
+      <function>hb_cairo_glyphs_from_buffer()</function> to obtain the glyphs in
+      a form that can be passed to <function>cairo_show_text_glyphs()</function> or
+      <function>cairo_show_glyphs()</function>.
+    </para>
+  </section>
+
   <section id="integration-uniscribe">
     <title>Uniscribe integration</title>
     <para>
index e9ea145..56eba61 100644 (file)
     </para>
     <para>
       The algorithms
-      used for complex scripts can be quite involved; HarfBuzz tries
+      used for shaping can be quite involved; HarfBuzz tries
       to be compatible with the OpenType Layout specification
       and, wherever there is any ambiguity, HarfBuzz attempts to replicate the
-      output of Microsoft's Uniscribe engine. See the <ulink
+      output of Microsoft's Uniscribe engine, to the extent that is feasible and desirable. See the <ulink
       url="https://docs.microsoft.com/en-us/typography/script-development/standard">Microsoft
       Typography pages</ulink> for more detail.
     </para>
     </para>
     <para>
       Some OpenType features are defined for the purpose of supporting
-      complex-script shaping, and are automatically activated, but
+      script-specific shaping, and are automatically activated, but
       only when a buffer's script property is set to a script that the
       feature supports.
     </para>
index db4e309..a95b0cb 100644 (file)
@@ -22,7 +22,7 @@
       correct amount for each successive glyph.
     </para>
     <para>
-      But, for <emphasis>complex scripts</emphasis>, any combination of
+      But, for other scripts (often unceremoniously called <emphasis>complex scripts</emphasis>), any combination of
       several shaping operations may be required, and the rules for how
       and when they are applied vary from script to script. HarfBuzz and
       other shaping engines implement these rules.
     </para>
   </section>
   
-  <section id="complex-scripts">
-    <title>Complex scripts</title>
+  <section id="script-specific-shaping">
+    <title>Script-specific shaping</title>
     <para>
-      In text-shaping terminology, scripts are generally classified as
-      either <emphasis>complex</emphasis> or <emphasis>non-complex</emphasis>.
-    </para>
-    <para>
-      Complex scripts are those for which transforming the input
-      sequence into the final layout requires some combination of
+      In many scripts, transforming the input
+      sequence into the final layout often requires some combination of
       operations&mdash;such as context-dependent substitutions,
       context-dependent mark positioning, glyph-to-glyph joining,
       glyph reordering, or glyph stacking.
     </para>
     <para>
-      In some complex scripts, the shaping rules require that a text
+      In some scripts, the shaping rules require that a text
       run be divided into syllables before the operations can be
-      applied. Other complex scripts may apply shaping operations over
+      applied. Other scripts may apply shaping operations over
       entire words or over the entire text run, with no subdivision
       required.
     </para>
     <para>
-      Non-complex scripts, by definition, do not require these
-      operations. However, correctly shaping a text run in a
-      non-complex script may still involve Unicode normalization,
+      Other scripts, do not require these
+      operations. However, correctly shaping a text run in
+      any script may still involve Unicode normalization,
       ligature substitutions, mark positioning, kerning, and applying
-      other font features. The key difference is that a text run in a
-      non-complex script can be processed sequentially and in the same
-      order as the input sequence of Unicode codepoints, without
-      requiring an analysis stage.
+      other font features.
     </para>
   </section>
   
   <section id="shaping-operations">
     <title>Shaping operations</title>
     <para>
-      Shaping a complex-script text run involves transforming the
+      Shaping a text run involves transforming the
       input sequence of Unicode codepoints with some combination of
       operations that is specified in the shaping model for the
       script.
@@ -81,7 +74,7 @@
       text run varies from script to script, as do the order that the
       operations are performed in and which codepoints are
       affected. However, the same general set of shaping operations is
-      common to all of the complex-script shaping models. 
+      common to all of the script shaping models. 
     </para>
     
     <itemizedlist>
@@ -92,7 +85,7 @@
          some other ("visual") position.
        </para>
        <para>
-         The shaping model for a given complex script might involve
+         The shaping model for a given script might involve
          more than one reordering step.
        </para>
       </listitem>
          particular string pattern.
        </para>
        <para>
-         The shaping model for a given complex script might involve
+         The shaping model for a given script might involve
          multiple contextual-substitution operations, each applying
          to different target glyphs and patterns, and which are
          performed in separate steps.
          Many contextual positioning operations are used to place
          <emphasis>mark</emphasis> glyphs (such as diacritics, vowel
          signs, and tone markers) with respect to
-         <emphasis>base</emphasis> glyphs. However, some complex
+         <emphasis>base</emphasis> glyphs. However, some
          scripts may use contextual positioning operations to
          correctly place base glyphs as well, such as
          when the script uses <emphasis>stacking</emphasis> characters.
       multiple positions).
     </para>
     <para>
-      Some complex scripts require that the text run be split into
+      Some scripts require that the text run be split into
       syllables. What constitutes a valid syllable in these
       scripts is specified in regular expressions, formed from the
       Letter and Mark codepoints, that take the UISC and UIPC
       <listitem>
        <para>
          The <emphasis>default</emphasis> shaping model handles all
-         non-complex scripts, and may also be used as a fallback for
+         scripts with no script-specific shaping model, and may also be used as a fallback for
          handling unrecognized scripts.
        </para>
       </listitem>
        <para>
          The <emphasis>Indic</emphasis> shaping model handles the Indic
          scripts Bengali, Devanagari, Gujarati, Gurmukhi, Kannada,
-         Malayalam, Oriya, Tamil, Telugu, and Sinhala.
+         Malayalam, Oriya, Tamil, and Telugu.
        </para>
        <para>
          The Indic shaping model was revised significantly in
       <listitem>
        <para>
          The <emphasis>Universal Shaping Engine</emphasis> (USE)
-         shaping model supports complex scripts not covered by one of
+         shaping model supports scripts not covered by one of
          the above, script-specific shaping models, including
          Javanese, Balinese, Buginese, Batak, Chakma, Lepcha, Modi,
          Phags-pa, Tagalog, Siddham, Sundanese, Tai Le, Tai Tham, Tai
index 4534783..fdf04b2 100644 (file)
       <listitem>
        <para>
          Indic (covering Devanagari, Bengali, Gujarati,
-         Gurmukhi, Kannada, Malayalam, Oriya, Tamil, Telugu, and
-         Sinhala)
+         Gurmukhi, Kannada, Malayalam, Oriya, Tamil, and Telugu)
        </para>
       </listitem>
       <listitem>
index 1809198..308c0cb 100644 (file)
@@ -1 +1 @@
-3.4.0
+8.2.2
index 0769969..2a5c0e6 100644 (file)
@@ -7,11 +7,11 @@
   <shortdesc xml:lang="en">Text shaping library</shortdesc>
 
   <homepage
-  rdf:resource="http://harfbuzz.org/" />
+  rdf:resource="https://github.com/harfbuzz/harfbuzz" />
   <mailing-list
-  rdf:resource="http://lists.freedesktop.org/mailman/listinfo/harfbuzz" />
-  <!--download-page
-  rdf:resource=""/-->
+  rdf:resource="https://github.com/harfbuzz/harfbuzz/discussions" />
+  <download-page
+  rdf:resource="https://github.com/harfbuzz/harfbuzz/releases" />
   <bug-database
   rdf:resource="https://github.com/harfbuzz/harfbuzz/issues" />
 
index 3e64cba..05ab1ab 100644 (file)
@@ -1,8 +1,9 @@
 project('harfbuzz', 'c', 'cpp',
   meson_version: '>= 0.55.0',
-  version: '3.4.0',
+  version: '8.2.2',
   default_options: [
-    'cpp_rtti=false',       # Just to support msvc, we are passing -fno-exceptions also anyway
+    'cpp_eh=none',          # Just to support msvc, we are passing -fno-exceptions also anyway
+    # 'cpp_rtti=false',     # Do NOT enable, wraps inherit it and ICU needs RTTI
     'cpp_std=c++11',
     'wrap_mode=nofallback', # Use --wrap-mode=default to revert, https://github.com/harfbuzz/harfbuzz/pull/2548
   ],
@@ -14,30 +15,30 @@ hb_version_minor = hb_version_arr[1].to_int()
 hb_version_micro = hb_version_arr[2].to_int()
 
 # libtool versioning
-hb_version_int = hb_version_major*10000 + hb_version_minor*100 + hb_version_micro
+hb_version_int = 60000 + hb_version_major*100 + hb_version_minor*10 + hb_version_micro
 hb_libtool_version_info = '@0@:0:@0@'.format(hb_version_int)
 
 pkgmod = import('pkgconfig')
 cpp = meson.get_compiler('cpp')
 null_dep = dependency('', required: false)
 
-if cpp.get_id() == 'msvc'
+# Enforce C++14 requirement for MSVC STL
+if ['clang', 'clang-cl'].contains(cpp.get_id()) and cpp.get_define('_MSC_FULL_VER') != ''
+  add_project_arguments('-std=c++14', language: 'cpp')
+endif
+
+if cpp.get_argument_syntax() == 'msvc'
   # Ignore several spurious warnings for things HarfBuzz does very commonly.
   # If a warning is completely useless and spammy, use '/wdXXXX' to suppress it
   # If a warning is harmless but hard to fix, use '/woXXXX' so it's shown once
   # NOTE: Only add warnings here if you are sure they're spurious
   msvc_args = [
-    '/wd4018', # implicit signed/unsigned conversion
-    '/wd4146', # unary minus on unsigned (beware INT_MIN)
     '/wd4244', # lossy type conversion (e.g. double -> int)
-    '/wd4305', # truncating type conversion (e.g. double -> float)
     cpp.get_supported_arguments(['/utf-8']), # set the input encoding to utf-8
   ]
   add_project_arguments(msvc_args, language: ['c', 'cpp'])
   # Disable SAFESEH with MSVC for libs that use external deps that are built with MinGW
   # noseh_link_args = ['/SAFESEH:NO']
-  # disable exception handling
-  add_project_arguments(['/EHs-', '/EHc-'], language: 'cpp')
 endif
 
 add_project_link_arguments(cpp.get_supported_link_arguments([
@@ -79,24 +80,39 @@ check_funcs = [
   ['isatty'],
   ['uselocale'],
   ['newlocale'],
+  ['sincosf'],
 ]
 
 m_dep = cpp.find_library('m', required: false)
 
-freetype_dep = null_dep
-if not get_option('freetype').disabled()
-  freetype_dep = dependency('freetype2', required: false)
-
-  if (not freetype_dep.found() and
-      cpp.get_id() == 'msvc' and
-      cpp.has_header('ft2build.h'))
-    freetype_dep = cpp.find_library('freetype', required: false)
+if meson.version().version_compare('>=0.60.0')
+  # pkg-config: freetype2, cmake: Freetype
+  freetype_dep = dependency('freetype2', 'Freetype',
+                            required: get_option('freetype'),
+                            default_options: ['harfbuzz=disabled'],
+                            allow_fallback: true)
+else
+  # painful hack to handle multiple dependencies but also respect options
+  freetype_opt = get_option('freetype')
+  # we want to handle enabled manually after fallbacks, but also handle disabled normally
+  if freetype_opt.enabled()
+    freetype_opt = false
   endif
-
-  if not freetype_dep.found()
-    # https://github.com/harfbuzz/harfbuzz/pull/2498
-    freetype_dep = dependency('freetype2', required: get_option('freetype'),
-                              default_options: ['harfbuzz=disabled'])
+  # try pkg-config name
+  freetype_dep = dependency('freetype2', method: 'pkg-config', required: freetype_opt)
+  # when disabled, leave it not-found
+  if not freetype_dep.found() and not get_option('freetype').disabled()
+    # Try cmake name
+    freetype_dep = dependency('Freetype', method: 'cmake', required: false)
+    # Subproject fallback, `allow_fallback: true` means the fallback will be
+    # tried even if the freetype option is set to `auto`.
+    if not freetype_dep.found()
+      freetype_dep = dependency('freetype2',
+                                method: 'pkg-config',
+                                required: get_option('freetype'),
+                                default_options: ['harfbuzz=disabled'],
+                                allow_fallback: true)
+    endif
   endif
 endif
 
@@ -104,34 +120,44 @@ glib_dep = dependency('glib-2.0', required: get_option('glib'))
 gobject_dep = dependency('gobject-2.0', required: get_option('gobject'))
 graphite2_dep = dependency('graphite2', required: get_option('graphite2'))
 graphite_dep = dependency('graphite2', required: get_option('graphite'))
-
-icu_dep = null_dep
-if not get_option('icu').disabled()
-  icu_dep = dependency('icu-uc', required: false)
-
-  if (not icu_dep.found() and
-      cpp.get_id() == 'msvc' and
-      cpp.has_header('unicode/uchar.h') and
-      cpp.has_header('unicode/unorm2.h') and
-      cpp.has_header('unicode/ustring.h') and
-      cpp.has_header('unicode/utf16.h') and
-      cpp.has_header('unicode/uversion.h') and
-      cpp.has_header('unicode/uscript.h'))
-    if get_option('buildtype') == 'debug'
-      icu_dep = cpp.find_library('icuucd', required: false)
-    else
-      icu_dep = cpp.find_library('icuuc', required: false)
-    endif
+wasm_dep = cpp.find_library('iwasm', required: get_option('wasm'))
+# How to check whether iwasm was built, and hence requires, LLVM?
+#llvm_dep = cpp.find_library('LLVM-15', required: get_option('wasm'))
+
+if meson.version().version_compare('>=0.60.0')
+  # pkg-config: icu-uc, cmake: ICU but with components
+  icu_dep = dependency('icu-uc', 'ICU',
+                            components: 'uc',
+                            required: get_option('icu'),
+                            allow_fallback: true)
+else
+  # painful hack to handle multiple dependencies but also respect options
+  icu_opt = get_option('icu')
+  # we want to handle enabled manually after fallbacks, but also handle disabled normally
+  if icu_opt.enabled()
+    icu_opt = false
   endif
-
-  if not icu_dep.found()
-    icu_dep = dependency('icu-uc', required: get_option('icu'))
+  # try pkg-config name
+  icu_dep = dependency('icu-uc', method: 'pkg-config', required: icu_opt)
+  # when disabled, leave it not-found
+  if not icu_dep.found() and not get_option('icu').disabled()
+    # Try cmake name
+    icu_dep = dependency('ICU', method: 'cmake', components: 'uc', required: false)
+    # Try again with subproject fallback. `allow_fallback: true` means the
+    # fallback will be tried even if the icu option is set to `auto`, but
+    # we cannot pass this option until Meson 0.59.0, because no wrap file
+    # is checked into git.
+    if not icu_dep.found()
+      icu_dep = dependency('icu-uc',
+                           method: 'pkg-config',
+                           required: get_option('icu'))
+    endif
   endif
 endif
 
 if icu_dep.found() and icu_dep.type_name() == 'pkgconfig'
-  icu_defs = icu_dep.get_variable(pkgconfig: 'DEFS', default_value: '')
-  if icu_defs != ''
+  icu_defs = icu_dep.get_variable(pkgconfig: 'DEFS', default_value: '').split()
+  if icu_defs.length() > 0
     add_project_arguments(icu_defs, language: ['c', 'cpp'])
   endif
 endif
@@ -143,7 +169,7 @@ if not get_option('cairo').disabled()
   cairo_ft_dep = dependency('cairo-ft', required: false)
 
   if (not cairo_dep.found() and
-      cpp.get_id() == 'msvc' and
+      cpp.get_argument_syntax() == 'msvc' and
       cpp.has_header('cairo.h'))
     cairo_dep = cpp.find_library('cairo', required: false)
     if cairo_dep.found() and cpp.has_function('cairo_ft_font_face_create_for_ft_face',
@@ -159,7 +185,8 @@ if not get_option('cairo').disabled()
     # harfbuzz support disabled, so when cairo will lookup freetype2 dependency
     # it will be forced to use that one.
     cairo_dep = dependency('cairo', required: get_option('cairo'))
-    cairo_ft_dep = dependency('cairo-ft', required: get_option('cairo'))
+    cairo_ft_required = get_option('cairo').enabled() and get_option('freetype').enabled()
+    cairo_ft_dep = dependency('cairo-ft', required: cairo_ft_required)
   endif
 endif
 
@@ -186,6 +213,20 @@ endif
 
 if cairo_dep.found()
   conf.set('HAVE_CAIRO', 1)
+  check_cairo_funcs = [
+    ['cairo_user_font_face_set_render_color_glyph_func', {'deps': cairo_dep}],
+    ['cairo_font_options_get_custom_palette_color', {'deps': cairo_dep}],
+    ['cairo_user_scaled_font_get_foreground_source', {'deps': cairo_dep}],
+  ]
+
+  if cairo_dep.type_name() == 'internal'
+    foreach func: check_cairo_funcs
+      name = func[0]
+      conf.set('HAVE_@0@'.format(name.to_upper()), 1)
+    endforeach
+  else
+    check_funcs += check_cairo_funcs
+  endif
 endif
 
 if cairo_ft_dep.found()
@@ -196,6 +237,11 @@ if chafa_dep.found()
   conf.set('HAVE_CHAFA', 1)
 endif
 
+if wasm_dep.found()
+  conf.set('HAVE_WASM', 1)
+  conf.set('HB_WASM_MODULE_DIR', '"'+get_option('prefix')+'/'+get_option('libdir')+'/harfbuzz/wasm"')
+endif
+
 if graphite2_dep.found() or graphite_dep.found()
   conf.set('HAVE_GRAPHITE2', 1)
 endif
@@ -218,6 +264,7 @@ if freetype_dep.found()
     ['FT_Get_Var_Blend_Coordinates', {'deps': freetype_dep}],
     ['FT_Set_Var_Blend_Coordinates', {'deps': freetype_dep}],
     ['FT_Done_MM_Var', {'deps': freetype_dep}],
+    ['FT_Get_Transform', {'deps': freetype_dep}],
   ]
 
   if freetype_dep.type_name() == 'internal'
@@ -252,17 +299,12 @@ if host_machine.system() == 'windows' and not get_option('gdi').disabled()
 endif
 
 # DirectWrite (Windows)
-directwrite_dep = null_dep
 if host_machine.system() == 'windows' and not get_option('directwrite').disabled()
   if get_option('directwrite').enabled() and not cpp.has_header('dwrite_1.h')
     error('DirectWrite was enabled explicitly, but required header is missing.')
   endif
 
-  directwrite_dep = cpp.find_library('dwrite', required: get_option('directwrite'))
-
-  if directwrite_dep.found()
-    conf.set('HAVE_DIRECTWRITE', 1)
-  endif
+  conf.set('HAVE_DIRECTWRITE', 1)
 endif
 
 # CoreText (macOS)
@@ -343,8 +385,31 @@ foreach check : check_funcs
   endif
 endforeach
 
+# CMake support (package install dir)
+
+# Equivalent to configure_package_config_file(INSTALL_DESTINATION ...), see
+# https://cmake.org/cmake/help/latest/module/CMakePackageConfigHelpers.html#command:configure_package_config_file.
+# In certain unusual packaging layouts such as Nixpkgs, the Harfbuzz package
+# is installed into two Nix store paths, "out" and "dev", where "out" contains
+# libraries only (i.e. lib/libharfbuzz.so) and "dev" contains development
+# files, i.e. include and lib/cmake. If CMake package files are installed to
+# "out", Nixpkgs will move them to "dev", which breaks assumptions about
+# our file paths. Since we need to figure out relative install paths here
+# to make a relocatable package, we do need to know the final path of our
+# CMake files to calculate the correct relative paths.
+# Of course, this still defaults to $libdir/cmake if unset, which works for
+# most packaging layouts.
+cmake_package_install_dir = get_option('cmakepackagedir')
+
+if cmake_package_install_dir == ''
+  cmake_package_install_dir = get_option('libdir') / 'cmake'
+endif
+
 subdir('src')
-subdir('util')
+
+if not get_option('utilities').disabled()
+  subdir('util')
+endif
 
 if not get_option('tests').disabled()
   subdir('test')
@@ -360,6 +425,9 @@ endif
 
 configure_file(output: 'config.h', configuration: conf)
 
+alias_target('lib', libharfbuzz)
+alias_target('libs', libharfbuzz, libharfbuzz_subset)
+
 build_summary = {
   'Directories':
     {'prefix': get_option('prefix'),
@@ -367,6 +435,7 @@ build_summary = {
      'libdir': get_option('libdir'),
      'includedir': get_option('includedir'),
      'datadir': get_option('datadir'),
+     'cmakepackagedir': cmake_package_install_dir
     },
   'Unicode callbacks (you want at least one)':
     {'Builtin': true,
@@ -374,7 +443,8 @@ build_summary = {
      'ICU': conf.get('HAVE_ICU', 0) == 1,
     },
   'Font callbacks (the more the merrier)':
-    {'FreeType': conf.get('HAVE_FREETYPE', 0) == 1,
+    {'Builtin' : true,
+     'FreeType': conf.get('HAVE_FREETYPE', 0) == 1,
     },
   'Dependencies used for command-line utilities':
     {'Cairo': conf.get('HAVE_CAIRO', 0) == 1,
@@ -382,15 +452,17 @@ build_summary = {
     },
   'Additional shapers':
     {'Graphite2': conf.get('HAVE_GRAPHITE2', 0) == 1,
+     'WebAssembly (experimental)': conf.get('HAVE_WASM', 0) == 1,
     },
   'Platform shapers (not normally needed)':
     {'CoreText': conf.get('HAVE_CORETEXT', 0) == 1,
-     'DirectWrite': conf.get('HAVE_DIRECTWRITE', 0) == 1,
+     'DirectWrite (experimental)': conf.get('HAVE_DIRECTWRITE', 0) == 1,
      'GDI/Uniscribe': (conf.get('HAVE_GDI', 0) == 1) and (conf.get('HAVE_UNISCRIBE', 0) == 1),
     },
   'Other features':
     {'Documentation': conf.get('HAVE_GTK_DOC', 0) == 1,
      'GObject bindings': conf.get('HAVE_GOBJECT', 0) == 1,
+     'Cairo integration': conf.get('HAVE_CAIRO', 0) == 1,
      'Introspection': conf.get('HAVE_INTROSPECTION', 0) == 1,
      'Experimental APIs': conf.get('HB_EXPERIMENTAL_API', 0) == 1,
     },
index 9ebba72..97d6dae 100644 (file)
@@ -21,6 +21,8 @@ option('directwrite', type: 'feature', value: 'disabled',
   description: 'Enable DirectWrite shaper backend on Windows (experimental)')
 option('coretext', type: 'feature', value: 'disabled',
   description: 'Enable CoreText shaper backend on macOS')
+option('wasm', type: 'feature', value: 'disabled',
+  description: 'Enable WebAssembly shaper backend (experimental)')
 
 # Common feature options
 option('tests', type: 'feature', value: 'enabled', yield: true,
@@ -29,6 +31,10 @@ option('introspection', type: 'feature', value: 'auto', yield: true,
   description: 'Generate gobject-introspection bindings (.gir/.typelib files)')
 option('docs', type: 'feature', value: 'auto', yield: true,
   description: 'Generate documentation with gtk-doc')
+option('doc_tests', type: 'boolean', value: false,
+  description: 'Run gtkdoc-check tests')
+option('utilities', type: 'feature', value: 'enabled', yield: true,
+  description: 'Build harfbuzz utils')
 
 option('benchmark', type: 'feature', value: 'disabled',
   description: 'Enable benchmark tests')
@@ -40,3 +46,7 @@ option('ragel_subproject', type: 'boolean', value: false,
   description: 'Build Ragel subproject if no suitable version is found')
 option('fuzzer_ldflags', type: 'string',
   description: 'Extra LDFLAGS used during linking of fuzzing binaries')
+
+# Install directory options
+option('cmakepackagedir', type: 'string',
+  description: 'CMake package configuration install directory')
index 3281ce3..496cae2 100755 (executable)
@@ -17,12 +17,14 @@ exec "$(dirname "$0")"/configure \
        CPP= \
        LD= \
        CFLAGS="-static-libgcc" \
-       CXXFLAGS="-static-libgcc -static-libstdc++" \
+       CXXFLAGS="-O2 -static-libgcc -static-libstdc++" \
        CPPFLAGS="-I$HOME/.local/$target/include" \
        LDFLAGS=-L$HOME/.local/$target/lib \
        PKG_CONFIG_LIBDIR=$HOME/.local/$target/lib/pkgconfig:/usr/$target/sys-root/mingw/lib/pkgconfig/ \
        PKG_CONFIG_PATH=$HOME/.local/$target/share/pkgconfig:/usr/$target/sys-root/mingw/share/pkgconfig/ \
        PATH=$HOME/.local/$target/bin:/usr/$target/sys-root/mingw/bin:/usr/$target/bin:$PATH \
        --without-icu \
+       --with-gdi \
        --with-uniscribe \
+       --with-directwrite=auto \
        "$@"
diff --git a/perf/Makefile.am b/perf/Makefile.am
new file mode 100644 (file)
index 0000000..1e67b92
--- /dev/null
@@ -0,0 +1,23 @@
+# Process this file with automake to produce Makefile.in
+
+NULL =
+EXTRA_DIST =
+SUBDIRS =
+
+EXTRA_DIST += \
+       meson.build \
+       benchmark-font.cc \
+       benchmark-map.cc \
+       benchmark-ot.cc \
+       benchmark-set.cc \
+       benchmark-shape.cc \
+       benchmark-subset.cc \
+       fonts \
+       texts \
+       $(NULL)
+
+# Convenience targets:
+lib:
+       @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
+
+-include $(top_srcdir)/git.mk
diff --git a/perf/Makefile.in b/perf/Makefile.in
new file mode 100644 (file)
index 0000000..98b3621
--- /dev/null
@@ -0,0 +1,709 @@
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Process this file with automake to produce Makefile.in
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \  ]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs  ]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = perf
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_link_flag.m4 \
+       $(top_srcdir)/m4/ax_code_coverage.m4 \
+       $(top_srcdir)/m4/ax_cxx_compile_stdcxx.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)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+       ctags-recursive dvi-recursive html-recursive info-recursive \
+       install-data-recursive install-dvi-recursive \
+       install-exec-recursive install-html-recursive \
+       install-info-recursive install-pdf-recursive \
+       install-ps-recursive install-recursive installcheck-recursive \
+       installdirs-recursive pdf-recursive ps-recursive \
+       tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive        \
+  distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+  $(RECURSIVE_TARGETS) \
+  $(RECURSIVE_CLEAN_TARGETS) \
+  $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+       distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_FT_CFLAGS = @CAIRO_FT_CFLAGS@
+CAIRO_FT_LIBS = @CAIRO_FT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CHAFA_CFLAGS = @CHAFA_CFLAGS@
+CHAFA_LIBS = @CHAFA_LIBS@
+CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@
+CODE_COVERAGE_CPPFLAGS = @CODE_COVERAGE_CPPFLAGS@
+CODE_COVERAGE_CXXFLAGS = @CODE_COVERAGE_CXXFLAGS@
+CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
+CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@
+CODE_COVERAGE_LIBS = @CODE_COVERAGE_LIBS@
+CORETEXT_CFLAGS = @CORETEXT_CFLAGS@
+CORETEXT_LIBS = @CORETEXT_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
+FREETYPE_DEPS = @FREETYPE_DEPS@
+FREETYPE_LIBS = @FREETYPE_LIBS@
+GCOV = @GCOV@
+GDI_CFLAGS = @GDI_CFLAGS@
+GDI_LIBS = @GDI_LIBS@
+GENHTML = @GENHTML@
+GIT = @GIT@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_DEPS = @GLIB_DEPS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GRAPHITE2_CFLAGS = @GRAPHITE2_CFLAGS@
+GRAPHITE2_DEPS = @GRAPHITE2_DEPS@
+GRAPHITE2_LIBS = @GRAPHITE2_LIBS@
+GREP = @GREP@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+HAVE_CXX11 = @HAVE_CXX11@
+HB_LIBTOOL_VERSION_INFO = @HB_LIBTOOL_VERSION_INFO@
+HB_VERSION = @HB_VERSION@
+HB_VERSION_MAJOR = @HB_VERSION_MAJOR@
+HB_VERSION_MICRO = @HB_VERSION_MICRO@
+HB_VERSION_MINOR = @HB_VERSION_MINOR@
+HTML_DIR = @HTML_DIR@
+ICU_CFLAGS = @ICU_CFLAGS@
+ICU_LIBS = @ICU_LIBS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
+INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
+INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@
+INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@
+INTROSPECTION_LIBS = @INTROSPECTION_LIBS@
+INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@
+INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
+INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+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@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
+UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
+VERSION = @VERSION@
+WASM_CFLAGS = @WASM_CFLAGS@
+WASM_LIBS = @WASM_LIBS@
+_GI_EXP_DATADIR = @_GI_EXP_DATADIR@
+_GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+have_gobject = @have_gobject@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+NULL = 
+EXTRA_DIST = meson.build benchmark-font.cc benchmark-map.cc \
+       benchmark-ot.cc benchmark-set.cc benchmark-shape.cc \
+       benchmark-subset.cc fonts texts $(NULL)
+SUBDIRS = 
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits perf/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnits perf/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+#     (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+       @fail=; \
+       if $(am__make_keepgoing); then \
+         failcom='fail=yes'; \
+       else \
+         failcom='exit 1'; \
+       fi; \
+       dot_seen=no; \
+       target=`echo $@ | sed s/-recursive//`; \
+       case "$@" in \
+         distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+         *) list='$(SUBDIRS)' ;; \
+       esac; \
+       for subdir in $$list; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           dot_seen=yes; \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done; \
+       if test "$$dot_seen" = "no"; then \
+         $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+       fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+       $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+       set x; \
+       here=`pwd`; \
+       if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+         include_option=--etags-include; \
+         empty_fix=.; \
+       else \
+         include_option=--include; \
+         empty_fix=; \
+       fi; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           test ! -f $$subdir/TAGS || \
+             set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+         fi; \
+       done; \
+       $(am__define_uniq_tagged_files); \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+       $(am__define_uniq_tagged_files); \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+       list='$(am__tagged_files)'; \
+       case "$(srcdir)" in \
+         [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+         *) sdir=$(subdir)/$(srcdir) ;; \
+       esac; \
+       for i in $$list; do \
+         if test -f "$$i"; then \
+           echo "$(subdir)/$$i"; \
+         else \
+           echo "$$sdir/$$i"; \
+         fi; \
+       done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+       @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           $(am__make_dryrun) \
+             || test -d "$(distdir)/$$subdir" \
+             || $(MKDIR_P) "$(distdir)/$$subdir" \
+             || exit 1; \
+           dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+           $(am__relativize); \
+           new_distdir=$$reldir; \
+           dir1=$$subdir; dir2="$(top_distdir)"; \
+           $(am__relativize); \
+           new_top_distdir=$$reldir; \
+           echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+           echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+           ($(am__cd) $$subdir && \
+             $(MAKE) $(AM_MAKEFLAGS) \
+               top_distdir="$$new_top_distdir" \
+               distdir="$$new_distdir" \
+               am__remove_distdir=: \
+               am__skip_length_check=: \
+               am__skip_mode_fix=: \
+               distdir) \
+             || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+       check-am clean clean-generic clean-libtool cscopelist-am ctags \
+       ctags-am distclean distclean-generic distclean-libtool \
+       distclean-tags distdir dvi dvi-am html html-am info info-am \
+       install install-am install-data install-data-am install-dvi \
+       install-dvi-am install-exec install-exec-am install-html \
+       install-html-am install-info install-info-am install-man \
+       install-pdf install-pdf-am install-ps install-ps-am \
+       install-strip installcheck installcheck-am installdirs \
+       installdirs-am maintainer-clean maintainer-clean-generic \
+       mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+       ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Convenience targets:
+lib:
+       @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
+
+-include $(top_srcdir)/git.mk
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/perf/benchmark-font.cc b/perf/benchmark-font.cc
new file mode 100644 (file)
index 0000000..67e0517
--- /dev/null
@@ -0,0 +1,319 @@
+#include "benchmark/benchmark.h"
+#include <cassert>
+#include <cstring>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hb.h"
+#include "hb-ot.h"
+#ifdef HAVE_FREETYPE
+#include "hb-ft.h"
+#endif
+
+
+#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
+
+struct test_input_t
+{
+  bool is_variable;
+  const char *font_path;
+} default_tests[] =
+{
+  {false, SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf"},
+  {true , SUBSET_FONT_BASE_PATH "RobotoFlex-Variable.ttf"},
+  {false, SUBSET_FONT_BASE_PATH "SourceSansPro-Regular.otf"},
+  {true , SUBSET_FONT_BASE_PATH "AdobeVFPrototype.otf"},
+  {true , SUBSET_FONT_BASE_PATH "SourceSerifVariable-Roman.ttf"},
+  {false, SUBSET_FONT_BASE_PATH "Comfortaa-Regular-new.ttf"},
+  {false, SUBSET_FONT_BASE_PATH "NotoNastaliqUrdu-Regular.ttf"},
+  {false, SUBSET_FONT_BASE_PATH "NotoSerifMyanmar-Regular.otf"},
+};
+
+static test_input_t *tests = default_tests;
+static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
+
+enum backend_t { HARFBUZZ, FREETYPE };
+
+enum operation_t
+{
+  nominal_glyphs,
+  glyph_h_advances,
+  glyph_extents,
+  draw_glyph,
+  paint_glyph,
+  load_face_and_shape,
+};
+
+static void
+_hb_move_to (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, float x, float y, void *)
+{
+  float &i = * (float *) draw_data;
+  i += x + y;
+}
+
+static void
+_hb_line_to (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, float x, float y, void *)
+{
+  float &i = * (float *) draw_data;
+  i += x + y;
+}
+
+static void
+_hb_quadratic_to (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, float cx, float cy, float x, float y, void *)
+{
+  float &i = * (float *) draw_data;
+  i += cx + cy + x + y;
+}
+
+static void
+_hb_cubic_to (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, float cx1, float cy1, float cx2, float cy2, float x, float y, void *)
+{
+  float &i = * (float *) draw_data;
+  i += cx1 + cy1 + cx2 + cy2 + x + y;
+}
+
+static void
+_hb_close_path (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, void *)
+{
+  float &i = * (float *) draw_data;
+  i += 1.0;
+}
+
+static hb_draw_funcs_t *
+_draw_funcs_create (void)
+{
+  hb_draw_funcs_t *draw_funcs = hb_draw_funcs_create ();
+  hb_draw_funcs_set_move_to_func (draw_funcs, _hb_move_to, nullptr, nullptr);
+  hb_draw_funcs_set_line_to_func (draw_funcs, _hb_line_to, nullptr, nullptr);
+  hb_draw_funcs_set_quadratic_to_func (draw_funcs, _hb_quadratic_to, nullptr, nullptr);
+  hb_draw_funcs_set_cubic_to_func (draw_funcs, _hb_cubic_to, nullptr, nullptr);
+  hb_draw_funcs_set_close_path_func (draw_funcs, _hb_close_path, nullptr, nullptr);
+  return draw_funcs;
+}
+
+static void BM_Font (benchmark::State &state,
+                    bool is_var, backend_t backend, operation_t operation,
+                    const test_input_t &test_input)
+{
+  hb_font_t *font;
+  unsigned num_glyphs;
+  {
+    hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
+    assert (blob);
+    hb_face_t *face = hb_face_create (blob, 0);
+    hb_blob_destroy (blob);
+    num_glyphs = hb_face_get_glyph_count (face);
+    font = hb_font_create (face);
+    hb_face_destroy (face);
+  }
+
+  if (is_var)
+  {
+    hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500};
+    hb_font_set_variations (font, &wght, 1);
+  }
+
+  switch (backend)
+  {
+    case HARFBUZZ:
+      hb_ot_font_set_funcs (font);
+      break;
+
+    case FREETYPE:
+#ifdef HAVE_FREETYPE
+      hb_ft_font_set_funcs (font);
+#endif
+      break;
+  }
+
+  switch (operation)
+  {
+    case nominal_glyphs:
+    {
+      hb_set_t *set = hb_set_create ();
+      hb_face_collect_unicodes (hb_font_get_face (font), set);
+      unsigned pop = hb_set_get_population (set);
+      hb_codepoint_t *unicodes = (hb_codepoint_t *) calloc (pop, sizeof (hb_codepoint_t));
+      hb_codepoint_t *glyphs = (hb_codepoint_t *) calloc (pop, sizeof (hb_codepoint_t));
+
+      hb_codepoint_t *p = unicodes;
+      for (hb_codepoint_t u = HB_SET_VALUE_INVALID;
+          hb_set_next (set, &u);)
+        *p++ = u;
+      assert (p == unicodes + pop);
+
+      for (auto _ : state)
+       hb_font_get_nominal_glyphs (font,
+                                   pop,
+                                   unicodes, sizeof (*unicodes),
+                                   glyphs, sizeof (*glyphs));
+
+      free (glyphs);
+      free (unicodes);
+      hb_set_destroy (set);
+      break;
+    }
+    case glyph_h_advances:
+    {
+      hb_codepoint_t *glyphs = (hb_codepoint_t *) calloc (num_glyphs, sizeof (hb_codepoint_t));
+      hb_position_t *advances = (hb_position_t *) calloc (num_glyphs, sizeof (hb_codepoint_t));
+
+      for (unsigned g = 0; g < num_glyphs; g++)
+        glyphs[g] = g;
+
+      for (auto _ : state)
+       hb_font_get_glyph_h_advances (font,
+                                     num_glyphs,
+                                     glyphs, sizeof (*glyphs),
+                                     advances, sizeof (*advances));
+
+      free (advances);
+      free (glyphs);
+      break;
+    }
+    case glyph_extents:
+    {
+      hb_glyph_extents_t extents;
+      for (auto _ : state)
+       for (unsigned gid = 0; gid < num_glyphs; ++gid)
+         hb_font_get_glyph_extents (font, gid, &extents);
+      break;
+    }
+    case draw_glyph:
+    {
+      hb_draw_funcs_t *draw_funcs = _draw_funcs_create ();
+      for (auto _ : state)
+      {
+       float i = 0;
+       for (unsigned gid = 0; gid < num_glyphs; ++gid)
+         hb_font_draw_glyph (font, gid, draw_funcs, &i);
+      }
+      hb_draw_funcs_destroy (draw_funcs);
+      break;
+    }
+    case paint_glyph:
+    {
+      hb_paint_funcs_t *paint_funcs = hb_paint_funcs_create ();
+      for (auto _ : state)
+      {
+       for (unsigned gid = 0; gid < num_glyphs; ++gid)
+         hb_font_paint_glyph (font, gid, paint_funcs, nullptr, 0, 0);
+      }
+      hb_paint_funcs_destroy (paint_funcs);
+      break;
+    }
+    case load_face_and_shape:
+    {
+      for (auto _ : state)
+      {
+       hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
+       assert (blob);
+       hb_face_t *face = hb_face_create (blob, 0);
+       hb_blob_destroy (blob);
+       hb_font_t *font = hb_font_create (face);
+       hb_face_destroy (face);
+
+       switch (backend)
+       {
+         case HARFBUZZ:
+           hb_ot_font_set_funcs (font);
+           break;
+
+         case FREETYPE:
+#ifdef HAVE_FREETYPE
+           hb_ft_font_set_funcs (font);
+#endif
+           break;
+       }
+
+       hb_buffer_t *buffer = hb_buffer_create ();
+       hb_buffer_add_utf8 (buffer, " ", -1, 0, -1);
+       hb_buffer_guess_segment_properties (buffer);
+
+       hb_shape (font, buffer, nullptr, 0);
+
+       hb_buffer_destroy (buffer);
+       hb_font_destroy (font);
+      }
+      break;
+    }
+  }
+
+
+  hb_font_destroy (font);
+}
+
+static void test_backend (backend_t backend,
+                         const char *backend_name,
+                         bool variable,
+                         operation_t op,
+                         const char *op_name,
+                         benchmark::TimeUnit time_unit,
+                         const test_input_t &test_input)
+{
+  char name[1024] = "BM_Font/";
+  strcat (name, op_name);
+  strcat (name, "/");
+  const char *p = strrchr (test_input.font_path, '/');
+  strcat (name, p ? p + 1 : test_input.font_path);
+  strcat (name, variable ? "/var" : "");
+  strcat (name, "/");
+  strcat (name, backend_name);
+
+  benchmark::RegisterBenchmark (name, BM_Font, variable, backend, op, test_input)
+   ->Unit(time_unit);
+}
+
+static void test_operation (operation_t op,
+                           const char *op_name,
+                           benchmark::TimeUnit time_unit)
+{
+  for (unsigned i = 0; i < num_tests; i++)
+  {
+    auto& test_input = tests[i];
+    for (int variable = 0; variable < int (test_input.is_variable) + 1; variable++)
+    {
+      bool is_var = (bool) variable;
+
+      test_backend (HARFBUZZ, "hb", is_var, op, op_name, time_unit, test_input);
+#ifdef HAVE_FREETYPE
+      test_backend (FREETYPE, "ft", is_var, op, op_name, time_unit, test_input);
+#endif
+    }
+  }
+}
+
+int main(int argc, char** argv)
+{
+  benchmark::Initialize(&argc, argv);
+
+  if (argc > 1)
+  {
+    num_tests = argc - 1;
+    tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
+    for (unsigned i = 0; i < num_tests; i++)
+    {
+      tests[i].is_variable = true;
+      tests[i].font_path = argv[i + 1];
+    }
+  }
+
+#define TEST_OPERATION(op, time_unit) test_operation (op, #op, time_unit)
+
+  TEST_OPERATION (nominal_glyphs, benchmark::kMicrosecond);
+  TEST_OPERATION (glyph_h_advances, benchmark::kMicrosecond);
+  TEST_OPERATION (glyph_extents, benchmark::kMicrosecond);
+  TEST_OPERATION (draw_glyph, benchmark::kMicrosecond);
+  TEST_OPERATION (paint_glyph, benchmark::kMillisecond);
+  TEST_OPERATION (load_face_and_shape, benchmark::kMicrosecond);
+
+#undef TEST_OPERATION
+
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+
+  if (tests != default_tests)
+    free (tests);
+}
diff --git a/perf/benchmark-map.cc b/perf/benchmark-map.cc
new file mode 100644 (file)
index 0000000..b2f6dae
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Benchmarks for hb_map_t operations.
+ */
+#include "benchmark/benchmark.h"
+
+#include <cassert>
+#include <cstdlib>
+#include "hb.h"
+
+void RandomMap(unsigned size, hb_map_t* out, hb_set_t* key_sample) {
+  hb_map_clear(out);
+
+  unsigned sample_denom = 1;
+  if (size > 10000)
+    sample_denom = size / 10000;
+
+  srand(size);
+  for (unsigned i = 0; i < size; i++) {
+    while (true) {
+      hb_codepoint_t next = rand();
+      if (hb_map_has (out, next)) continue;
+
+      hb_codepoint_t val = rand();
+      if (key_sample && val % sample_denom == 0)
+        hb_set_add (key_sample, next);
+      hb_map_set (out, next, val);
+      break;
+    }
+  }
+}
+
+/* Insert a single value into map of varying sizes. */
+static void BM_MapInsert(benchmark::State& state) {
+  unsigned map_size = state.range(0);
+
+  hb_map_t* original = hb_map_create ();
+  RandomMap(map_size, original, nullptr);
+  assert(hb_map_get_population(original) == map_size);
+
+  unsigned mask = 1;
+  while (mask < map_size)
+    mask <<= 1;
+  mask--;
+
+  auto needle = 0u;
+  for (auto _ : state) {
+    // TODO(garretrieger): create a copy of the original map.
+    //                     Needs a hb_map_copy(..) in public api.
+
+    hb_map_set (original, needle++ & mask, 1);
+  }
+
+  hb_map_destroy(original);
+}
+BENCHMARK(BM_MapInsert)
+    ->Range(1 << 4, 1 << 20);
+
+/* Single value lookup on map of various sizes where the key is not present. */
+static void BM_MapLookupMiss(benchmark::State& state) {
+  unsigned map_size = state.range(0);
+
+  hb_map_t* original = hb_map_create ();
+  RandomMap(map_size, original, nullptr);
+  assert(hb_map_get_population(original) == map_size);
+
+  auto needle = map_size / 2;
+
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        hb_map_get (original, needle++));
+  }
+
+  hb_map_destroy(original);
+}
+BENCHMARK(BM_MapLookupMiss)
+    ->Range(1 << 4, 1 << 20); // Map size
+
+/* Single value lookup on map of various sizes. */
+static void BM_MapLookupHit(benchmark::State& state) {
+  unsigned map_size = state.range(0);
+
+  hb_map_t* original = hb_map_create ();
+  hb_set_t* key_set = hb_set_create ();
+  RandomMap(map_size, original, key_set);
+  assert(hb_map_get_population(original) == map_size);
+
+  unsigned num_keys = hb_set_get_population (key_set);
+  hb_codepoint_t* key_array =
+    (hb_codepoint_t*) calloc (num_keys, sizeof(hb_codepoint_t));
+  
+  hb_codepoint_t cp = HB_SET_VALUE_INVALID;
+  unsigned i = 0;
+  while (hb_set_next (key_set, &cp))
+    key_array[i++] = cp;
+
+  i = 0;
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        hb_map_get (original, key_array[i++ % num_keys]));
+  }
+
+  hb_set_destroy (key_set);
+  free (key_array);
+  hb_map_destroy(original);
+}
+BENCHMARK(BM_MapLookupHit)
+    ->Range(1 << 4, 1 << 20); // Map size
+
+
+BENCHMARK_MAIN();
diff --git a/perf/benchmark-ot.cc b/perf/benchmark-ot.cc
new file mode 100644 (file)
index 0000000..c79c384
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Benchmarks for hb_set_t operations.
+ */
+#include "benchmark/benchmark.h"
+
+#include "hb-ot.h"
+
+static void BM_hb_ot_tags_from_script_and_language (benchmark::State& state,
+                                                   hb_script_t script,
+                                                   const char *language_str) {
+
+  hb_language_t language = hb_language_from_string (language_str, -1);
+
+  for (auto _ : state)
+  {
+    hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
+    unsigned script_count = HB_OT_MAX_TAGS_PER_SCRIPT;
+
+    hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
+    unsigned language_count = HB_OT_MAX_TAGS_PER_LANGUAGE;
+
+    hb_ot_tags_from_script_and_language (script,
+                                        language,
+                                        &script_count /* IN/OUT */,
+                                        script_tags /* OUT */,
+                                        &language_count /* IN/OUT */,
+                                        language_tags /* OUT */);
+  }
+}
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON zh_abcd, HB_SCRIPT_COMMON, "zh_abcd");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON zh_hans, HB_SCRIPT_COMMON, "zh_hans");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON ab_abcd, HB_SCRIPT_COMMON, "ab_abcd");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON ab_abc, HB_SCRIPT_COMMON, "ab_abc");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON abcdef_XY, HB_SCRIPT_COMMON, "abcdef_XY");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON abcd_XY, HB_SCRIPT_COMMON, "abcd_XY");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON cxy_CN, HB_SCRIPT_COMMON, "cxy_CN");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON exy_CN, HB_SCRIPT_COMMON, "exy_CN");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON zh_CN, HB_SCRIPT_COMMON, "zh_CN");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON en_US, HB_SCRIPT_COMMON, "en_US");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, LATIN en_US, HB_SCRIPT_LATIN, "en_US");
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON none, HB_SCRIPT_LATIN, nullptr);
+BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, LATIN none, HB_SCRIPT_LATIN, nullptr);
+
+BENCHMARK_MAIN();
diff --git a/perf/benchmark-set.cc b/perf/benchmark-set.cc
new file mode 100644 (file)
index 0000000..c170acf
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Benchmarks for hb_set_t operations.
+ */
+#include "benchmark/benchmark.h"
+
+#include <cassert>
+#include <cstdlib>
+#include "hb.h"
+
+void RandomSet(unsigned size, unsigned max_value, hb_set_t* out) {
+  hb_set_clear(out);
+
+  srand(size * max_value);
+  for (unsigned i = 0; i < size; i++) {
+    while (true) {
+      unsigned next = rand() % max_value;
+      if (hb_set_has (out, next)) continue;
+
+      hb_set_add(out, next);
+      break;
+    }
+  }
+}
+
+// TODO(garretrieger): benchmark union/subtract/intersection etc.
+
+/* Insert a 1000 values into set of varying sizes. */
+static void BM_SetInsert_1000(benchmark::State& state) {
+  unsigned set_size = state.range(0);
+  unsigned max_value = state.range(0) * state.range(1);
+
+  hb_set_t* original = hb_set_create ();
+  RandomSet(set_size, max_value, original);
+  assert(hb_set_get_population(original) == set_size);
+
+  for (auto _ : state) {
+    state.PauseTiming ();
+    hb_set_t* data = hb_set_copy(original);
+    state.ResumeTiming ();
+    for (int i = 0; i < 1000; i++) {
+      hb_set_add(data, i * 2654435761u % max_value);
+    }
+    hb_set_destroy(data);
+  }
+
+  hb_set_destroy(original);
+}
+BENCHMARK(BM_SetInsert_1000)
+    ->Unit(benchmark::kMicrosecond)
+    ->Ranges(
+        {{1 << 10, 1 << 16}, // Set Size
+         {2, 512}});          // Density
+
+/* Insert a 1000 values into set of varying sizes. */
+static void BM_SetOrderedInsert_1000(benchmark::State& state) {
+  unsigned set_size = state.range(0);
+  unsigned max_value = state.range(0) * state.range(1);
+
+  hb_set_t* original = hb_set_create ();
+  RandomSet(set_size, max_value, original);
+  assert(hb_set_get_population(original) == set_size);
+
+  for (auto _ : state) {
+    state.PauseTiming ();
+    hb_set_t* data = hb_set_copy(original);
+    state.ResumeTiming ();
+    for (int i = 0; i < 1000; i++) {
+      hb_set_add(data, i);
+    }
+    hb_set_destroy(data);
+  }
+
+  hb_set_destroy(original);
+}
+BENCHMARK(BM_SetOrderedInsert_1000)
+    ->Unit(benchmark::kMicrosecond)
+    ->Ranges(
+        {{1 << 10, 1 << 16}, // Set Size
+         {2, 512}});          // Density
+
+/* Single value lookup on sets of various sizes. */
+static void BM_SetLookup(benchmark::State& state, unsigned interval) {
+  unsigned set_size = state.range(0);
+  unsigned max_value = state.range(0) * state.range(1);
+
+  hb_set_t* original = hb_set_create ();
+  RandomSet(set_size, max_value, original);
+  assert(hb_set_get_population(original) == set_size);
+
+  auto needle = max_value / 2;
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        hb_set_has (original, (needle += interval) % max_value));
+  }
+
+  hb_set_destroy(original);
+}
+BENCHMARK_CAPTURE(BM_SetLookup, ordered, 3)
+    ->Ranges(
+        {{1 << 10, 1 << 16}, // Set Size
+         {2, 512}});          // Density
+BENCHMARK_CAPTURE(BM_SetLookup, random, 12345)
+    ->Ranges(
+        {{1 << 10, 1 << 16}, // Set Size
+         {2, 512}});          // Density
+
+/* Full iteration of sets of varying sizes. */
+static void BM_SetIteration(benchmark::State& state) {
+  unsigned set_size = state.range(0);
+  unsigned max_value = state.range(0) * state.range(1);
+
+  hb_set_t* original = hb_set_create ();
+  RandomSet(set_size, max_value, original);
+  assert(hb_set_get_population(original) == set_size);
+
+  hb_codepoint_t cp = HB_SET_VALUE_INVALID;
+  for (auto _ : state) {
+    hb_set_next (original, &cp);
+  }
+
+  hb_set_destroy(original);
+}
+BENCHMARK(BM_SetIteration)
+    ->Ranges(
+        {{1 << 10, 1 << 16}, // Set Size
+         {2, 512}});          // Density
+
+/* Set copy. */
+static void BM_SetCopy(benchmark::State& state) {
+  unsigned set_size = state.range(0);
+  unsigned max_value = state.range(0) * state.range(1);
+
+  hb_set_t* original = hb_set_create ();
+  RandomSet(set_size, max_value, original);
+  assert(hb_set_get_population(original) == set_size);
+
+  for (auto _ : state) {
+    hb_set_t *s = hb_set_create ();
+    hb_set_set (s, original);
+    hb_set_destroy (s);
+  }
+
+  hb_set_destroy(original);
+}
+BENCHMARK(BM_SetCopy)
+    ->Unit(benchmark::kMicrosecond)
+    ->Ranges(
+        {{1 << 10, 1 << 16}, // Set Size
+         {2, 512}});          // Density
+
+BENCHMARK_MAIN();
diff --git a/perf/benchmark-shape.cc b/perf/benchmark-shape.cc
new file mode 100644 (file)
index 0000000..f44b3e5
--- /dev/null
@@ -0,0 +1,180 @@
+#include "benchmark/benchmark.h"
+#include <cstring>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <cassert>
+
+#include "hb.h"
+#include "hb-ot.h"
+#ifdef HAVE_FREETYPE
+#include "hb-ft.h"
+#endif
+
+#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
+
+struct test_input_t
+{
+  const char *font_path;
+  const char *text_path;
+  bool is_variable;
+} default_tests[] =
+{
+
+  {"perf/fonts/NotoNastaliqUrdu-Regular.ttf",
+   "perf/texts/fa-thelittleprince.txt",
+   false},
+
+  {"perf/fonts/NotoNastaliqUrdu-Regular.ttf",
+   "perf/texts/fa-words.txt",
+   false},
+
+  {"perf/fonts/Amiri-Regular.ttf",
+   "perf/texts/fa-thelittleprince.txt",
+   false},
+
+  {SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf",
+   "perf/texts/hi-words.txt",
+   false},
+
+  {"perf/fonts/Roboto-Regular.ttf",
+   "perf/texts/en-thelittleprince.txt",
+   false},
+
+  {"perf/fonts/Roboto-Regular.ttf",
+   "perf/texts/en-words.txt",
+   false},
+
+  {SUBSET_FONT_BASE_PATH "SourceSerifVariable-Roman.ttf",
+   "perf/texts/en-thelittleprince.txt",
+   true},
+};
+
+static test_input_t *tests = default_tests;
+static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
+
+enum backend_t { HARFBUZZ, FREETYPE };
+
+static void BM_Shape (benchmark::State &state,
+                     bool is_var,
+                     backend_t backend,
+                     const test_input_t &input)
+{
+  hb_font_t *font;
+  {
+    hb_blob_t *blob = hb_blob_create_from_file_or_fail (input.font_path);
+    assert (blob);
+    hb_face_t *face = hb_face_create (blob, 0);
+    hb_blob_destroy (blob);
+    font = hb_font_create (face);
+    hb_face_destroy (face);
+  }
+
+  if (is_var)
+  {
+    hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500};
+    hb_font_set_variations (font, &wght, 1);
+  }
+
+  switch (backend)
+  {
+    case HARFBUZZ:
+      hb_ot_font_set_funcs (font);
+      break;
+
+    case FREETYPE:
+#ifdef HAVE_FREETYPE
+      hb_ft_font_set_funcs (font);
+#endif
+      break;
+  }
+
+  hb_blob_t *text_blob = hb_blob_create_from_file_or_fail (input.text_path);
+  assert (text_blob);
+  unsigned orig_text_length;
+  const char *orig_text = hb_blob_get_data (text_blob, &orig_text_length);
+
+  hb_buffer_t *buf = hb_buffer_create ();
+  for (auto _ : state)
+  {
+    unsigned text_length = orig_text_length;
+    const char *text = orig_text;
+
+    const char *end;
+    while ((end = (const char *) memchr (text, '\n', text_length)))
+    {
+      hb_buffer_clear_contents (buf);
+      hb_buffer_add_utf8 (buf, text, text_length, 0, end - text);
+      hb_buffer_guess_segment_properties (buf);
+      hb_shape (font, buf, nullptr, 0);
+
+      unsigned skip = end - text + 1;
+      text_length -= skip;
+      text += skip;
+    }
+  }
+  hb_buffer_destroy (buf);
+
+  hb_blob_destroy (text_blob);
+  hb_font_destroy (font);
+}
+
+static void test_backend (backend_t backend,
+                         const char *backend_name,
+                         bool variable,
+                         const test_input_t &test_input)
+{
+  char name[1024] = "BM_Shape";
+  const char *p;
+  strcat (name, "/");
+  p = strrchr (test_input.font_path, '/');
+  strcat (name, p ? p + 1 : test_input.font_path);
+  strcat (name, "/");
+  p = strrchr (test_input.text_path, '/');
+  strcat (name, p ? p + 1 : test_input.text_path);
+  strcat (name, variable ? "/var" : "");
+  strcat (name, "/");
+  strcat (name, backend_name);
+
+  benchmark::RegisterBenchmark (name, BM_Shape, variable, backend, test_input)
+   ->Unit(benchmark::kMillisecond);
+}
+
+int main(int argc, char** argv)
+{
+  benchmark::Initialize(&argc, argv);
+
+  if (argc > 2)
+  {
+    num_tests = (argc - 1) / 2;
+    tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
+    for (unsigned i = 0; i < num_tests; i++)
+    {
+      tests[i].is_variable = true;
+      tests[i].font_path = argv[1 + i * 2];
+      tests[i].text_path = argv[2 + i * 2];
+    }
+  }
+
+  for (unsigned i = 0; i < num_tests; i++)
+  {
+    auto& test_input = tests[i];
+    for (int variable = 0; variable < int (test_input.is_variable) + 1; variable++)
+    {
+      bool is_var = (bool) variable;
+
+      test_backend (HARFBUZZ, "hb", is_var, test_input);
+#ifdef HAVE_FREETYPE
+      test_backend (FREETYPE, "ft", is_var, test_input);
+#endif
+    }
+  }
+
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+
+  if (tests != default_tests)
+    free (tests);
+}
diff --git a/perf/benchmark-subset.cc b/perf/benchmark-subset.cc
new file mode 100644 (file)
index 0000000..714f540
--- /dev/null
@@ -0,0 +1,277 @@
+#include "benchmark/benchmark.h"
+#include <cassert>
+#include <cstring>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hb-subset.h"
+
+
+enum operation_t
+{
+  subset_glyphs,
+  subset_unicodes,
+  instance,
+};
+
+struct axis_location_t
+{
+  hb_tag_t axis_tag;
+  float axis_value;
+};
+
+static const axis_location_t
+_roboto_flex_instance_opts[] =
+{
+  {HB_TAG ('w', 'g', 'h', 't'), 600.f},
+  {HB_TAG ('w', 'd', 't', 'h'), 75.f},
+  {HB_TAG ('o', 'p', 's', 'z'), 90.f},
+  {HB_TAG ('G', 'R', 'A', 'D'), -100.f},
+  {HB_TAG ('s', 'l', 'n', 't'), -3.f},
+  {HB_TAG ('X', 'T', 'R', 'A'), 500.f},
+  {HB_TAG ('X', 'O', 'P', 'Q'), 150.f},
+  {HB_TAG ('Y', 'O', 'P', 'Q'), 100.f},
+  {HB_TAG ('Y', 'T', 'L', 'C'), 480.f},
+  {HB_TAG ('Y', 'T', 'U', 'C'), 600.f},
+  {HB_TAG ('Y', 'T', 'A', 'S'), 800.f},
+  {HB_TAG ('Y', 'T', 'D', 'E'), -50.f},
+  {HB_TAG ('Y', 'T', 'F', 'I'), 600.f},
+};
+
+static const axis_location_t
+_mplus_instance_opts[] =
+{
+  {HB_TAG ('w', 'g', 'h', 't'), 800.f},
+};
+
+template <typename Type, unsigned int n>
+static inline unsigned int ARRAY_LEN (const Type (&)[n]) { return n; }
+
+#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
+
+struct test_input_t
+{
+  const char *font_path;
+  unsigned max_subset_size;
+  const axis_location_t *instance_opts;
+  unsigned num_instance_opts;
+} default_tests[] =
+{
+  {SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf", 1000, nullptr, 0},
+  {SUBSET_FONT_BASE_PATH "Amiri-Regular.ttf", 4096, nullptr, 0},
+  {SUBSET_FONT_BASE_PATH "NotoNastaliqUrdu-Regular.ttf", 1400, nullptr, 0},
+  {SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf", 1000, nullptr, 0},
+  {SUBSET_FONT_BASE_PATH "Mplus1p-Regular.ttf", 10000, nullptr, 0},
+  {SUBSET_FONT_BASE_PATH "SourceHanSans-Regular_subset.otf", 10000, nullptr, 0},
+  {SUBSET_FONT_BASE_PATH "SourceSansPro-Regular.otf", 2000, nullptr, 0},
+  {SUBSET_FONT_BASE_PATH "AdobeVFPrototype.otf", 300, nullptr, 0},
+  {SUBSET_FONT_BASE_PATH "MPLUS1-Variable.ttf", 6000, _mplus_instance_opts, ARRAY_LEN (_mplus_instance_opts)},
+  {SUBSET_FONT_BASE_PATH "RobotoFlex-Variable.ttf", 900, _roboto_flex_instance_opts, ARRAY_LEN (_roboto_flex_instance_opts)},
+#if 0
+  {"perf/fonts/NotoSansCJKsc-VF.ttf", 100000},
+#endif
+};
+
+static test_input_t *tests = default_tests;
+static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
+
+
+void AddCodepoints(const hb_set_t* codepoints_in_font,
+                   unsigned subset_size,
+                   hb_subset_input_t* input)
+{
+  auto *unicodes = hb_subset_input_unicode_set (input);
+  hb_codepoint_t cp = HB_SET_VALUE_INVALID;
+  for (unsigned i = 0; i < subset_size; i++) {
+    // TODO(garretrieger): pick randomly.
+    if (!hb_set_next (codepoints_in_font, &cp)) return;
+    hb_set_add (unicodes, cp);
+  }
+}
+
+void AddGlyphs(unsigned num_glyphs_in_font,
+               unsigned subset_size,
+               hb_subset_input_t* input)
+{
+  auto *glyphs = hb_subset_input_glyph_set (input);
+  for (unsigned i = 0; i < subset_size && i < num_glyphs_in_font; i++) {
+    if (i + 1 == subset_size &&
+        hb_subset_input_get_flags (input) & HB_SUBSET_FLAGS_RETAIN_GIDS)
+    {
+      hb_set_add (glyphs, num_glyphs_in_font - 1);
+      continue;
+    }
+    hb_set_add (glyphs, i);
+  }
+}
+
+// Preprocess face and populate the subset accelerator on it to speed up
+// the subsetting operations.
+static hb_face_t* preprocess_face(hb_face_t* face)
+{
+  hb_face_t* new_face = hb_subset_preprocess(face);
+  hb_face_destroy(face);
+  return new_face;
+}
+
+static hb_face_t *cached_face;
+
+static void
+free_cached_face (void)
+{
+  hb_face_destroy (cached_face);
+  cached_face = nullptr;
+}
+
+
+/* benchmark for subsetting a font */
+static void BM_subset (benchmark::State &state,
+                       operation_t operation,
+                       const test_input_t &test_input,
+                       bool retain_gids)
+{
+  unsigned subset_size = state.range(0);
+
+  hb_face_t *face = nullptr;
+
+  static const char *cached_font_path;
+
+  if (!cached_font_path || strcmp (cached_font_path, test_input.font_path))
+  {
+    hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
+    assert (blob);
+    face = hb_face_create (blob, 0);
+    hb_blob_destroy (blob);
+
+    face = preprocess_face (face);
+
+    if (cached_face)
+      hb_face_destroy (cached_face);
+
+    cached_face = hb_face_reference (face);
+    cached_font_path = test_input.font_path;
+  }
+  else
+    face = hb_face_reference (cached_face);
+
+  hb_subset_input_t* input = hb_subset_input_create_or_fail ();
+  assert (input);
+
+  if (retain_gids)
+    hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_RETAIN_GIDS);
+
+  switch (operation)
+  {
+    case subset_unicodes:
+    {
+      hb_set_t* all_codepoints = hb_set_create ();
+      hb_face_collect_unicodes (face, all_codepoints);
+      AddCodepoints(all_codepoints, subset_size, input);
+      hb_set_destroy (all_codepoints);
+    }
+    break;
+
+    case subset_glyphs:
+    {
+      unsigned num_glyphs = hb_face_get_glyph_count (face);
+      AddGlyphs(num_glyphs, subset_size, input);
+    }
+    break;
+
+    case instance:
+    {
+      hb_set_t* all_codepoints = hb_set_create ();
+      hb_face_collect_unicodes (face, all_codepoints);
+      AddCodepoints(all_codepoints, subset_size, input);
+      hb_set_destroy (all_codepoints);
+
+      for (unsigned i = 0; i < test_input.num_instance_opts; i++)
+        hb_subset_input_pin_axis_location (input, face,
+                                           test_input.instance_opts[i].axis_tag,
+                                           test_input.instance_opts[i].axis_value);
+    }
+    break;
+  }
+
+  for (auto _ : state)
+  {
+    hb_face_t* subset = hb_subset_or_fail (face, input);
+    assert (subset);
+    hb_face_destroy (subset);
+  }
+
+  hb_subset_input_destroy (input);
+  hb_face_destroy (face);
+}
+
+static void test_subset (operation_t op,
+                         const char *op_name,
+                         bool retain_gids,
+                         benchmark::TimeUnit time_unit,
+                         const test_input_t &test_input)
+{
+  if (op == instance && test_input.instance_opts == nullptr)
+    return;
+
+  char name[1024] = "BM_subset/";
+  strcat (name, op_name);
+  strcat (name, "/");
+  const char *p = strrchr (test_input.font_path, '/');
+  strcat (name, p ? p + 1 : test_input.font_path);
+  if (retain_gids)
+    strcat (name, "/retaingids");
+
+  benchmark::RegisterBenchmark (name, BM_subset, op, test_input, retain_gids)
+      ->Range(10, test_input.max_subset_size)
+      ->Unit(time_unit);
+}
+
+static void test_operation (operation_t op,
+                            const char *op_name,
+                            const test_input_t *tests,
+                            unsigned num_tests,
+                            benchmark::TimeUnit time_unit)
+{
+  for (unsigned i = 0; i < num_tests; i++)
+  {
+    auto& test_input = tests[i];
+    test_subset (op, op_name, true, time_unit, test_input);
+    test_subset (op, op_name, false, time_unit, test_input);
+  }
+}
+
+int main(int argc, char** argv)
+{
+  benchmark::Initialize(&argc, argv);
+
+#ifndef HB_NO_ATEXIT
+  atexit (free_cached_face);
+#endif
+
+  if (argc > 1)
+  {
+    num_tests = (argc - 1) / 2;
+    tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
+    for (unsigned i = 0; i < num_tests; i++)
+    {
+      tests[i].font_path = argv[1 + i * 2];
+      tests[i].max_subset_size = atoi (argv[2 + i * 2]);
+    }
+  }
+
+#define TEST_OPERATION(op, time_unit) test_operation (op, #op, tests, num_tests, time_unit)
+
+  TEST_OPERATION (subset_glyphs, benchmark::kMicrosecond);
+  TEST_OPERATION (subset_unicodes, benchmark::kMicrosecond);
+  TEST_OPERATION (instance, benchmark::kMicrosecond);
+
+#undef TEST_OPERATION
+
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
+
+  if (tests != default_tests)
+    free (tests);
+}
index e12744c..ae122f4 100644 (file)
@@ -1,21 +1,62 @@
 google_benchmark = subproject('google-benchmark')
 google_benchmark_dep = google_benchmark.get_variable('google_benchmark_dep')
 
-ttf_parser_dep = null_dep
-if get_option('experimental_api') and add_languages('rust', required: false, native: true)
-  ttf_parser_dep = subproject('ttf-parser').get_variable('ttf_parser_dep')
-endif
-
-benchmark('perf', executable('perf', 'perf.cc',
+benchmark('benchmark-font', executable('benchmark-font', 'benchmark-font.cc',
   dependencies: [
     google_benchmark_dep, freetype_dep,
+  ],
+  cpp_args: [],
+  include_directories: [incconfig, incsrc],
+  link_with: [libharfbuzz],
+  install: false,
+), workdir: meson.current_source_dir() / '..', timeout: 100)
+
+benchmark('benchmark-map', executable('benchmark-map', 'benchmark-map.cc',
+  dependencies: [
+    google_benchmark_dep,
+  ],
+  cpp_args: [],
+  include_directories: [incconfig, incsrc],
+  link_with: [libharfbuzz],
+  install: false,
+), workdir: meson.current_source_dir() / '..', timeout: 100)
 
-    # the last two, thread and dl, aren't nice as ttf-parser isn't no_std yet
-    # https://github.com/RazrFalcon/ttf-parser/issues/29
-    ttf_parser_dep, thread_dep, cpp.find_library('dl'),
+benchmark('benchmark-ot', executable('benchmark-ot', 'benchmark-ot.cc',
+  dependencies: [
+    google_benchmark_dep,
   ],
-  cpp_args: ttf_parser_dep.found() ? ['-DHAVE_TTFPARSER'] : [],
+  cpp_args: [],
   include_directories: [incconfig, incsrc],
   link_with: [libharfbuzz],
   install: false,
 ), workdir: meson.current_source_dir() / '..', timeout: 100)
+
+benchmark('benchmark-set', executable('benchmark-set', 'benchmark-set.cc',
+  dependencies: [
+    google_benchmark_dep,
+  ],
+  cpp_args: [],
+  include_directories: [incconfig, incsrc],
+  link_with: [libharfbuzz],
+  install: false,
+), workdir: meson.current_source_dir() / '..', timeout: 100)
+
+benchmark('benchmark-shape', executable('benchmark-shape', 'benchmark-shape.cc',
+  dependencies: [
+    google_benchmark_dep, freetype_dep,
+  ],
+  cpp_args: [],
+  include_directories: [incconfig, incsrc],
+  link_with: [libharfbuzz],
+  install: false,
+), workdir: meson.current_source_dir() / '..', timeout: 100)
+
+benchmark('benchmark-subset', executable('benchmark-subset', 'benchmark-subset.cc',
+  dependencies: [
+    google_benchmark_dep,
+  ],
+  cpp_args: [],
+  include_directories: [incconfig, incsrc],
+  link_with: [libharfbuzz, libharfbuzz_subset],
+  install: false,
+), workdir: meson.current_source_dir() / '..', timeout: 100)
diff --git a/perf/perf-draw.hh b/perf/perf-draw.hh
deleted file mode 100644 (file)
index 12581bc..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-#include "benchmark/benchmark.h"
-
-#include "hb.h"
-#include "hb-ot.h"
-#include "hb-ft.h"
-#include FT_OUTLINE_H
-
-#ifdef HAVE_TTFPARSER
-#include "ttfparser.h"
-#endif
-
-#define HB_UNUSED __attribute__((unused))
-
-static void
-_hb_move_to (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
-
-static void
-_hb_line_to (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
-
-static void
-_hb_quadratic_to (hb_position_t control_x HB_UNUSED, hb_position_t control_y HB_UNUSED,
-                 hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
-                 void *user_data HB_UNUSED) {}
-
-static void
-_hb_cubic_to (hb_position_t control1_x HB_UNUSED, hb_position_t control1_y HB_UNUSED,
-             hb_position_t control2_x HB_UNUSED, hb_position_t control2_y HB_UNUSED,
-             hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
-             void *user_data HB_UNUSED) {}
-
-static void
-_hb_close_path (void *user_data HB_UNUSED) {}
-
-static void
-_ft_move_to (const FT_Vector* to HB_UNUSED, void* user HB_UNUSED) {}
-
-static void
-_ft_line_to (const FT_Vector* to HB_UNUSED, void* user HB_UNUSED) {}
-
-static void
-_ft_conic_to (const FT_Vector* control HB_UNUSED, const FT_Vector* to HB_UNUSED,
-             void* user HB_UNUSED) {}
-
-static void
-_ft_cubic_to (const FT_Vector* control1 HB_UNUSED, const FT_Vector* control2 HB_UNUSED,
-             const FT_Vector* to HB_UNUSED, void* user HB_UNUSED) {}
-
-#ifdef HAVE_TTFPARSER
-static void _tp_move_to (float x HB_UNUSED, float y HB_UNUSED, void *data HB_UNUSED) {}
-static void _tp_line_to (float x, float y, void *data) {}
-static void _tp_quad_to (float x1, float y1, float x, float y, void *data) {}
-static void _tp_curve_to (float x1, float y1, float x2, float y2, float x, float y, void *data) {}
-static void _tp_close_path (void *data) {}
-#endif
-
-static void draw (benchmark::State &state, const char *font_path, bool is_var, backend_t backend)
-{
-  hb_font_t *font;
-  unsigned num_glyphs;
-  {
-    hb_blob_t *blob = hb_blob_create_from_file_or_fail (font_path);
-    assert (blob);
-    hb_face_t *face = hb_face_create (blob, 0);
-    hb_blob_destroy (blob);
-    num_glyphs = hb_face_get_glyph_count (face);
-    font = hb_font_create (face);
-    hb_face_destroy (face);
-  }
-
-  if (backend == HARFBUZZ)
-  {
-    if (is_var)
-    {
-      hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500};
-      hb_font_set_variations (font, &wght, 1);
-    }
-    hb_draw_funcs_t *draw_funcs = hb_draw_funcs_create ();
-    hb_draw_funcs_set_move_to_func (draw_funcs, _hb_move_to);
-    hb_draw_funcs_set_line_to_func (draw_funcs, _hb_line_to);
-    hb_draw_funcs_set_quadratic_to_func (draw_funcs, _hb_quadratic_to);
-    hb_draw_funcs_set_cubic_to_func (draw_funcs, _hb_cubic_to);
-    hb_draw_funcs_set_close_path_func (draw_funcs, _hb_close_path);
-
-    for (auto _ : state)
-      for (unsigned gid = 0; gid < num_glyphs; ++gid)
-       hb_font_draw_glyph (font, gid, draw_funcs, nullptr);
-
-    hb_draw_funcs_destroy (draw_funcs);
-  }
-  else if (backend == FREETYPE)
-  {
-    if (is_var)
-    {
-      hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500};
-      hb_font_set_variations (font, &wght, 1);
-    }
-    hb_ft_font_set_funcs (font);
-    FT_Face ft_face = hb_ft_font_get_face (font);
-    hb_ft_font_set_load_flags (font, FT_LOAD_NO_HINTING | FT_LOAD_NO_SCALE);
-
-    FT_Outline_Funcs draw_funcs;
-    draw_funcs.move_to = (FT_Outline_MoveToFunc) _ft_move_to;
-    draw_funcs.line_to = (FT_Outline_LineToFunc) _ft_line_to;
-    draw_funcs.conic_to = (FT_Outline_ConicToFunc) _ft_conic_to;
-    draw_funcs.cubic_to = (FT_Outline_CubicToFunc) _ft_cubic_to;
-    draw_funcs.shift = 0;
-    draw_funcs.delta = 0;
-
-    for (auto _ : state)
-      for (unsigned gid = 0; gid < num_glyphs; ++gid)
-      {
-       FT_Load_Glyph (ft_face, gid, FT_LOAD_NO_HINTING | FT_LOAD_NO_SCALE);
-       FT_Outline_Decompose (&ft_face->glyph->outline, &draw_funcs, nullptr);
-      }
-  }
-  else if (backend == TTF_PARSER)
-  {
-#ifdef HAVE_TTFPARSER
-    ttfp_face *tp_font = (ttfp_face *) malloc (ttfp_face_size_of ());
-    hb_blob_t *blob = hb_face_reference_blob (hb_font_get_face (font));
-    assert (ttfp_face_init (hb_blob_get_data (blob, nullptr), hb_blob_get_length (blob), 0, tp_font));
-    if (is_var) ttfp_set_variation (tp_font, TTFP_TAG('w','g','h','t'), 500);
-
-    ttfp_outline_builder builder;
-    builder.move_to = _tp_move_to;
-    builder.line_to = _tp_line_to;
-    builder.quad_to = _tp_quad_to;
-    builder.curve_to = _tp_curve_to;
-    builder.close_path = _tp_close_path;
-
-    ttfp_rect bbox;
-    for (auto _ : state)
-      for (unsigned gid = 0; gid < num_glyphs; ++gid)
-       ttfp_outline_glyph (tp_font, builder, &builder, gid, &bbox);
-
-    hb_blob_destroy (blob);
-    free (tp_font);
-#endif
-  }
-  else abort ();
-
-  hb_font_destroy (font);
-}
-
-#define FONT_BASE_PATH "test/subset/data/fonts/"
-
-BENCHMARK_CAPTURE (draw, cff - ot - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (draw, cff - ft - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, FREETYPE);
-BENCHMARK_CAPTURE (draw, cff - tp - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, TTF_PARSER);
-
-BENCHMARK_CAPTURE (draw, cff2 - ot - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (draw, cff2 - ft - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, FREETYPE);
-BENCHMARK_CAPTURE (draw, cff2 - tp - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, TTF_PARSER);
-
-BENCHMARK_CAPTURE (draw, cff2/vf - ot - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, HARFBUZZ);
-BENCHMARK_CAPTURE (draw, cff2/vf - ft - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, FREETYPE);
-BENCHMARK_CAPTURE (draw, cff2/vf - tp - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, TTF_PARSER);
-
-BENCHMARK_CAPTURE (draw, glyf - ot - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (draw, glyf - ft - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, FREETYPE);
-BENCHMARK_CAPTURE (draw, glyf - tp - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, TTF_PARSER);
-
-BENCHMARK_CAPTURE (draw, glyf/vf - ot - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, HARFBUZZ);
-BENCHMARK_CAPTURE (draw, glyf/vf - ft - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, FREETYPE);
-BENCHMARK_CAPTURE (draw, glyf/vf - tp - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, TTF_PARSER);
-
-BENCHMARK_CAPTURE (draw, glyf - ot - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (draw, glyf - ft - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, FREETYPE);
-BENCHMARK_CAPTURE (draw, glyf - tp - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, TTF_PARSER);
-
-BENCHMARK_CAPTURE (draw, glyf/vf - ot - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, HARFBUZZ);
-BENCHMARK_CAPTURE (draw, glyf/vf - ft - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, FREETYPE);
-BENCHMARK_CAPTURE (draw, glyf/vf - tp - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, TTF_PARSER);
-
-BENCHMARK_CAPTURE (draw, glyf - ot - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (draw, glyf - ft - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, FREETYPE);
-BENCHMARK_CAPTURE (draw, glyf - tp - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, TTF_PARSER);
diff --git a/perf/perf-extents.hh b/perf/perf-extents.hh
deleted file mode 100644 (file)
index c7bc84c..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-#include "benchmark/benchmark.h"
-
-#include "hb.h"
-#include "hb-ft.h"
-#include "hb-ot.h"
-
-#ifdef HAVE_TTFPARSER
-#include "ttfparser.h"
-#endif
-
-static void extents (benchmark::State &state, const char *font_path, bool is_var, backend_t backend)
-{
-  hb_font_t *font;
-  unsigned num_glyphs;
-  {
-    hb_blob_t *blob = hb_blob_create_from_file_or_fail (font_path);
-    assert (blob);
-    hb_face_t *face = hb_face_create (blob, 0);
-    hb_blob_destroy (blob);
-    num_glyphs = hb_face_get_glyph_count (face);
-    font = hb_font_create (face);
-    hb_face_destroy (face);
-  }
-
-  if (is_var)
-  {
-    hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500};
-    hb_font_set_variations (font, &wght, 1);
-  }
-
-  if (backend == HARFBUZZ || backend == FREETYPE)
-  {
-    if (backend == FREETYPE)
-    {
-      hb_ft_font_set_funcs (font);
-      hb_ft_font_set_load_flags (font, FT_LOAD_NO_HINTING | FT_LOAD_NO_SCALE);
-    }
-
-    hb_glyph_extents_t extents;
-    for (auto _ : state)
-      for (unsigned gid = 0; gid < num_glyphs; ++gid)
-       hb_font_get_glyph_extents (font, gid, &extents);
-  }
-  else if (backend == TTF_PARSER)
-  {
-#ifdef HAVE_TTFPARSER
-    ttfp_face *tp_font = (ttfp_face *) malloc (ttfp_face_size_of ());
-    hb_blob_t *blob = hb_face_reference_blob (hb_font_get_face (font));
-    assert (ttfp_face_init (hb_blob_get_data (blob, nullptr), hb_blob_get_length (blob), 0, tp_font));
-    if (is_var) ttfp_set_variation (tp_font, TTFP_TAG('w','g','h','t'), 500);
-
-    ttfp_rect bbox;
-    for (auto _ : state)
-      for (unsigned gid = 0; gid < num_glyphs; ++gid)
-       ttfp_get_glyph_bbox(tp_font, gid, &bbox);
-
-    hb_blob_destroy (blob);
-    free (tp_font);
-#endif
-  }
-
-  hb_font_destroy (font);
-}
-
-#define FONT_BASE_PATH "test/subset/data/fonts/"
-
-BENCHMARK_CAPTURE (extents, cff - ot - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (extents, cff - ft - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, FREETYPE);
-BENCHMARK_CAPTURE (extents, cff - tp - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, TTF_PARSER);
-
-BENCHMARK_CAPTURE (extents, cff2 - ot - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (extents, cff2 - ft - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, FREETYPE);
-BENCHMARK_CAPTURE (extents, cff2 - tp - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, TTF_PARSER);
-
-BENCHMARK_CAPTURE (extents, cff2/vf - ot - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, HARFBUZZ);
-BENCHMARK_CAPTURE (extents, cff2/vf - ft - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, FREETYPE);
-BENCHMARK_CAPTURE (extents, cff2/vf - tp - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, TTF_PARSER);
-
-BENCHMARK_CAPTURE (extents, glyf - ot - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (extents, glyf - ft - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, FREETYPE);
-BENCHMARK_CAPTURE (extents, glyf - tp - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, TTF_PARSER);
-
-BENCHMARK_CAPTURE (extents, glyf/vf - ot - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, HARFBUZZ);
-BENCHMARK_CAPTURE (extents, glyf/vf - ft - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, FREETYPE);
-BENCHMARK_CAPTURE (extents, glyf/vf - tp - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, TTF_PARSER);
-
-BENCHMARK_CAPTURE (extents, glyf - ot - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (extents, glyf - ft - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, FREETYPE);
-BENCHMARK_CAPTURE (extents, glyf - tp - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, TTF_PARSER);
-
-BENCHMARK_CAPTURE (extents, glyf/vf - ot - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, HARFBUZZ);
-BENCHMARK_CAPTURE (extents, glyf/vf - ft - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, FREETYPE);
-BENCHMARK_CAPTURE (extents, glyf/vf - tp - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, TTF_PARSER);
-
-BENCHMARK_CAPTURE (extents, glyf - ot - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, HARFBUZZ);
-BENCHMARK_CAPTURE (extents, glyf - ft - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, FREETYPE);
-BENCHMARK_CAPTURE (extents, glyf - tp - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, TTF_PARSER);
-
diff --git a/perf/perf-shaping.hh b/perf/perf-shaping.hh
deleted file mode 100644 (file)
index 85ee19b..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-#include "benchmark/benchmark.h"
-
-#include "hb.h"
-
-static void shape (benchmark::State &state, const char *text_path,
-                  hb_direction_t direction, hb_script_t script,
-                  const char *font_path)
-{
-  hb_font_t *font;
-  {
-    hb_blob_t *blob = hb_blob_create_from_file_or_fail (font_path);
-    assert (blob);
-    hb_face_t *face = hb_face_create (blob, 0);
-    hb_blob_destroy (blob);
-    font = hb_font_create (face);
-    hb_face_destroy (face);
-  }
-
-  hb_blob_t *text_blob = hb_blob_create_from_file_or_fail (text_path);
-  assert (text_blob);
-  unsigned text_length;
-  const char *text = hb_blob_get_data (text_blob, &text_length);
-
-  hb_buffer_t *buf = hb_buffer_create ();
-  for (auto _ : state)
-  {
-    hb_buffer_add_utf8 (buf, text, text_length, 0, -1);
-    hb_buffer_set_direction (buf, direction);
-    hb_buffer_set_script (buf, script);
-    hb_shape (font, buf, nullptr, 0);
-    hb_buffer_clear_contents (buf);
-  }
-  hb_buffer_destroy (buf);
-
-  hb_blob_destroy (text_blob);
-  hb_font_destroy (font);
-}
-
-BENCHMARK_CAPTURE (shape, fa-thelittleprince.txt - Amiri,
-                  "perf/texts/fa-thelittleprince.txt",
-                  HB_DIRECTION_RTL, HB_SCRIPT_ARABIC,
-                  "perf/fonts/Amiri-Regular.ttf");
-BENCHMARK_CAPTURE (shape, fa-thelittleprince.txt - NotoNastaliqUrdu,
-                  "perf/texts/fa-thelittleprince.txt",
-                  HB_DIRECTION_RTL, HB_SCRIPT_ARABIC,
-                  "perf/fonts/NotoNastaliqUrdu-Regular.ttf");
-
-BENCHMARK_CAPTURE (shape, fa-monologue.txt - Amiri,
-                  "perf/texts/fa-monologue.txt",
-                  HB_DIRECTION_RTL, HB_SCRIPT_ARABIC,
-                  "perf/fonts/Amiri-Regular.ttf");
-BENCHMARK_CAPTURE (shape, fa-monologue.txt - NotoNastaliqUrdu,
-                  "perf/texts/fa-monologue.txt",
-                  HB_DIRECTION_RTL, HB_SCRIPT_ARABIC,
-                  "perf/fonts/NotoNastaliqUrdu-Regular.ttf");
-
-BENCHMARK_CAPTURE (shape, en-thelittleprince.txt - Roboto,
-                  "perf/texts/en-thelittleprince.txt",
-                  HB_DIRECTION_LTR, HB_SCRIPT_LATIN,
-                  "perf/fonts/Roboto-Regular.ttf");
-
-BENCHMARK_CAPTURE (shape, en-words.txt - Roboto,
-                  "perf/texts/en-words.txt",
-                  HB_DIRECTION_LTR, HB_SCRIPT_LATIN,
-                  "perf/fonts/Roboto-Regular.ttf");
diff --git a/perf/perf.cc b/perf/perf.cc
deleted file mode 100644 (file)
index a364b91..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#include "benchmark/benchmark.h"
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "perf-shaping.hh"
-#ifdef HAVE_FREETYPE
-enum backend_t { HARFBUZZ, FREETYPE, TTF_PARSER };
-#include "perf-extents.hh"
-#ifdef HB_EXPERIMENTAL_API
-#include "perf-draw.hh"
-#endif
-#endif
-
-BENCHMARK_MAIN ();
diff --git a/perf/texts/duployan.txt b/perf/texts/duployan.txt
new file mode 100644 (file)
index 0000000..f330fc9
--- /dev/null
@@ -0,0 +1,27 @@
+𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚
+
+𛱇𛰣 𛰂𛱆 𛰆𛱄𛰉𛰅𛰋𛱁𛰄𛰃
+
+𛱁𛰆𛱇𛰅𛰜 𛰅𛱄𛰈 𛱊𛱁‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛱛‌𛰅𛱛𛰅 𛰜𛱇𛱇‌𛰜𛱇𛰙 𛰅𛱄‌𛰂𛱁 𛰣𛱇‌𛰚𛱛𛰅
+
+𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚 𛱆‌𛰚𛱁‌𛰃𛱁𛱆 𛰅𛱄‌𛰂𛱁 𛰜𛰅𛱂𛱆 𛰜𛰃𛱂‌𛰆𛱄͏͏͏, 𛱞𛰅 𛰃𛰆𛱛𛰜 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰅‌𛰜𛰃𛱂 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜; 𛰂𛱆 𛰚𛱁𛱋‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰚𛱁‌𛱞‌𛰃𛰅𛱁, 𛰂𛱛͏͏͏𛰜 𛰚𛱁𛱋‌𛰅𛱁 𛰚𛱁‌𛰚𛱇𛰣 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛱇𛰆𛱇𛰂 𛰅𛱄‌𛰂𛱁 𛰂𛱁‌𛱊𛱁 𛰂𛱆 𛱜‌𛱜 𛰅𛱁‌𛰅𛱜 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛰅𛱁‌𛰅𛱜 𛰂𛱛͏͏͏𛰜 𛱆𛰂‌𛰜𛱛𛰃 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛰅𛱁‌𛰚𛱁‌𛱞 𛱆𛰅‌𛰃𛱂 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜: 𛱛‌𛰅𛱛𛰅 𛰚𛰜𛱁𛱆‌𛰅𛱁 𛱇𛰆𛱄͏͏͏ 𛰚𛱁‌𛰚𛱇𛰣. 𛱁‌𛱊𛱁𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰚𛱇𛰙 𛰅𛱄‌𛰂𛱁 𛱇𛰛𛱇𛰂𛰃 𛱇𛰆𛱇‌𛰀𛱇. 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅 𛱁𛰚‌𛰅𛱁‌𛰃𛱇 𛰃𛱚𛰚 𛰙𛱇𛰋𛱄𛱆 𛰂𛱆 𛱄͏͏͏𛰄𛱆𛰋. 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛱇𛱇 𛰅𛱄‌𛰂𛱁 𛰜𛰃𛱇𛰅, 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙, 𛰂𛱆 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰅𛱁‌𛰚𛱁‌𛱞 𛱆𛰅‌𛰃𛱂 𛱆𛰂‌𛰜𛱛𛰃 𛰅𛱄‌𛰂𛱁 𛱂𛰄𛰋𛱇𛰅𛱁. 𛱞𛰀𛰃 𛰜𛰄𛱆𛰚𛰅𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙, 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛱊𛱁‌𛰅𛱁 𛱜‌𛱜; 𛰂𛱆 𛱇𛰆𛱇𛰂 𛰅𛱄‌𛰂𛱁 𛰜𛰄𛱆𛰚𛰅𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛱇𛰆𛱇‌𛰀𛱇, 𛰂𛱆 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁𛰛 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛱆𛰅‌𛰃𛱂 𛱁𛰚‌𛰅𛱁‌𛰃𛱇 𛰜𛰄𛱆𛰚𛰅𛰜 𛰙𛱁𛰛 𛰃𛱄𛰙‌𛰃𛱄𛰙.
+
+𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚 𛱇𛰆𛱇𛰂 𛰂𛱛͏͏͏𛰜 𛰃𛱂‌𛱇𛱇 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰙𛱁‌𛰙𛱛𛰅 𛰆𛱄͏͏͏ 𛰂𛱛͏͏͏𛰜 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰜𛰅‌𛰜𛰃𛱂 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜, 𛱆𛰀𛰃 𛱄𛰆‌𛰙𛱁𛰚 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚 𛱁‌𛱊𛱁𛰜 𛰃𛱇‌𛰅𛱆 𛱇𛰜‌𛰅𛱄𛰙 𛰂𛱆 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛱇𛰆𛱄͏͏͏ 𛰚𛱁𛱋‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛱆𛰅‌𛰃𛱂 𛰙𛱁‌𛰙𛱛𛰅 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰅𛱁‌𛰅𛱜; 𛰅𛱄‌𛰂𛱆𛰃 𛰚𛱁𛱋‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰂𛱛͏͏͏𛰜 𛱁‌𛱑 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛱇𛰆𛱄͏͏͏ 𛰃𛱇‌𛰅𛱆 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛰂𛱆 𛱆𛰂‌𛰜𛱛𛰃 𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰊𛱁𛰋𛰈𛱇𛰚 𛰂𛱆 𛱇𛰆𛱇‌𛰀𛱇. 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛰂𛱛͏͏͏𛰜 𛰅𛱁‌𛰅𛱜, 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛰂𛱆 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚 𛱁‌𛱊𛱁𛰜 𛰃𛱇‌𛰅𛱆 𛱇𛰜‌𛰅𛱄𛰙 𛰂𛱆 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛰅𛱁‌𛰚𛱁‌𛱞 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛱞𛰅 𛰜𛱁‌𛱊𛱁 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱂‌𛰚𛱁𛰜 𛰀𛱚𛰜. 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛰈𛰋𛱇𛰃 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛱜‌𛱜 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰔𛱄‌𛰆𛱁𛰚 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰀𛱚𛰜: 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰅‌𛰜𛰃𛱂 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰅𛱁‌𛰃𛱂 𛰂𛱛͏͏͏𛰜 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛰂𛱆 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛰂𛱆 𛱇𛰆𛱄͏͏͏ 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛱜‌𛱜 𛱆𛰅‌𛰃𛱂 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛰂𛱆 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚. 𛱞𛰅 𛰃𛰆𛱛𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰜𛱇𛱂‌𛰀𛱛𛰜 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛰂𛱆 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚 𛰂𛱆 𛰅𛱁‌𛰅𛱜 𛰂𛱛͏͏͏𛰜 𛱆𛰂‌𛰜𛱛𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱂‌𛰚𛱁𛰜 𛰀𛱚𛰜 𛰅𛱆‌𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛱁‌𛱊𛱁𛰜 𛰜𛰃𛱇𛰅 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛱇𛰆𛱇‌𛰀𛱇. 𛱇𛰆𛱄͏͏͏ 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰃𛱇‌𛰅𛱆 𛱛‌𛰅𛱛𛰅 𛰙𛱄𛰅𛰜𛰃 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙. 𛰂𛱆 𛱇𛰆𛱇𛰂 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱜͏͏͏𛰛 𛰅𛰆𛱁𛰜‌𛰅𛱁. 𛱇𛰆𛱄͏͏͏ 𛱆𛰅‌𛰃𛱂 𛰜𛱁‌𛰆𛱇𛰅𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁. 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛰆𛱛𛰜 𛰚𛱁‌𛰚𛱇𛰣 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰜𛱁‌𛱊𛱁 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱂‌𛰚𛱁𛰜 𛰀𛱚𛰜 𛰅𛱆‌𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰜𛰃𛱇𛰅. 𛰂𛱛͏͏͏𛰜 𛱆𛰀𛰃 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛱜 𛰂𛱆 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰔𛱄‌𛰆𛱁𛰚 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛰀𛱚𛰜, 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱁‌𛱑 𛱜‌𛱜. 𛰂𛱆 𛰅𛱄‌𛰂𛱁 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛱛‌𛰅𛱛𛰅. 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱜‌𛱜 𛰙𛱇𛰋𛰜𛱇 𛰂𛱛͏͏͏𛰜 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱂‌𛰚𛱁𛰜 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛱜 𛰂𛱆 𛰣𛱁‌𛰅𛱄 𛱇𛰆𛱄͏͏͏. 𛱇𛰆𛱄͏͏͏ 𛱁‌𛱑 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜. 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰅𛱄‌𛰂𛱁 𛰅𛱁𛰀 𛰣𛱁‌𛰅𛱄 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜.
+
+𛱆𛰀𛰃 𛰜𛱄𛰚 𛱁‌𛱑 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰔𛱄 𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚 𛱊𛱁‌𛰅𛱁 𛰜𛰃𛱄𛰚 𛱄𛱇‌𛰀𛱁𛰃. 𛱇𛰆𛱄͏͏͏ 𛰅𛱁‌𛰅𛱜 𛱛‌𛰅𛱛𛰅 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱜‌𛰚𛱇‌𛰜𛱇𛰙 𛰚𛱁‌𛰚𛱇𛰣 𛰅𛱄‌𛰂𛱁 𛱄𛱇‌𛰀𛱁𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁. 𛰅𛱄‌𛰂𛱁 𛰙𛱁‌𛰅𛱛𛰅 𛰀𛱚𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱂‌𛰙𛱁‌𛰚𛱜͏͏𛰜: 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱜‌𛱜 𛱆𛰅‌𛰃𛱂 𛱁𛰆‌𛰅𛱆 𛰣𛱁‌𛰅𛱄 𛰂𛱆 𛰙𛱁‌𛰅𛱛𛰅 𛰃𛰆𛱛𛰜 𛰅𛱁‌𛰙𛱄‌𛰜𛱁𛰅. 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰅‌𛰜𛰃𛱂 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛱆𛰅‌𛰃𛱂 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱇𛰆𛱇‌𛰀𛱇. 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰜𛰅𛱛‌𛰅𛱛𛰙 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛰅𛱄‌𛰂𛱁 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰜𛰃𛱒‌𛱇𛰆 𛱛‌𛰅𛱛𛰅 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙, 𛰂𛱆 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰂𛱆𛰚𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰥𛱇𛰅‌𛰥𛱇𛰅 𛰅𛱄‌𛰂𛱁 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰂𛱆 𛰙𛱛𛰜‌𛰙𛱛𛰜 𛰆𛱂‌𛰃𛱇𛰃, 𛰅𛱁𛰆𛱂‌𛰅𛱁𛰆𛱂, 𛰙𛱁𛰚 𛰆𛱂‌𛰙𛱛‌𛰃𛱄͏͏͏, 𛰂𛱆 𛰆𛱁𛱆𛰚𛰜. 𛰃𛱂‌𛱇𛱇 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰆𛱄͏͏͏‌𛰆𛱄͏͏͏ 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰜𛱇𛱂‌𛰂𛱛𛰃𛰆 𛰅𛱄‌𛰂𛱁 𛰙𛱄𛰅𛰜𛰃 𛰀𛱄𛰋𛰚 𛰂𛱆 𛱆𛰀𛰃 𛰅𛱄‌𛱑‌𛰅𛱄‌𛱑 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰀𛱄𛰋𛰚.
+
+𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛱆𛰀𛰃 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱁𛰚; 𛱇𛰆𛱄͏͏͏ 𛱊𛱁‌𛰅𛱁 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰙𛱁‌𛰙𛱁 𛰂𛱆 𛰂𛱁‌𛰂𛱁, 𛰅𛱄‌𛰂𛱆𛰃 𛱆𛰀𛰃 𛰃𛱂‌𛰚𛱁𛰜 𛰃𛰆𛱇𛰆 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛱊𛱁‌𛰅𛱁 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃. 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛱁‌𛱊𛱁𛰜 𛰃𛱇‌𛰅𛱆 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛱁‌𛱊𛱁𛰜 𛰜𛱇𛰅 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛱊𛱁‌𛰅𛱁 𛰙𛱁‌𛰙𛱁 𛰂𛱆 𛰂𛱁‌𛰂𛱁, 𛰂𛱆 𛰅𛱄‌𛰂𛱆𛰃 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰙𛱁‌𛰙𛱛𛰅 𛰃𛰆𛱛𛰜 𛱊𛱁‌𛰅𛱁 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛱁𛰆‌𛰃𛱂. 𛰅𛱁‌𛰚𛱁‌𛱞 𛰃𛱂‌𛰚𛱁𛰜 𛱁‌𛱊𛱁𛰜 𛰃𛱇‌𛰅𛱆 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰂𛱆 𛰃𛱇‌𛰅𛱆 𛰚𛱁‌𛰚𛱇𛰣 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰂𛰆𛱇. 𛰅𛱁‌𛰅𛱜, 𛱇𛰆𛱄͏͏͏ 𛱁‌𛱑 𛱊𛱁‌𛰅𛱁 𛰅𛰋𛱁𛱆. 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱁𛰚 𛱊𛱁‌𛰅𛱁 𛰚𛱇𛰙 𛰙𛱇𛰚𛱇𛰜 𛰃𛰆𛱛𛰜 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛰂𛱛͏͏͏𛰜 𛱊𛱁‌𛰅𛱁 𛰂𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛰅𛱁 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛱞𛰅 𛰜𛱁‌𛱊𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰥𛱇𛰅‌𛰥𛱇𛰅.
+
+𛰣𛱁‌𛰅𛱄 𛰃𛰆𛱛𛰚 𛰃𛱂‌𛰚𛱁𛰜 𛰜𛱄𛰚 𛰅𛱁𛰀 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚, 𛰂𛱆 𛱞𛰅 𛰅𛱁‌𛰃𛱂 𛰙𛱇𛰚𛱇𛰜 𛰃𛰆𛱁𛰂 𛱊𛱁‌𛰅𛱁 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛰂𛱛͏͏͏𛰜 𛱊𛱁‌𛰅𛱁 𛰅𛰋𛱁𛱆 𛰅𛱄‌𛰂𛱁 𛰙𛱁‌𛰅𛱛𛰅 𛰀𛱚𛰜, 𛰅𛱁𛰚‌𛰜𛱇𛰀 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱁‌𛰙𛱛𛰅 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛰅𛱁 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅 𛱄𛰆‌𛰙𛱁𛰚 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚, 𛰂𛱆 𛱞𛰀𛰃 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰀𛱚𛰜 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰔𛱄‌𛰆𛱁𛰚 𛱛‌𛰅𛱛𛰅 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇. 𛰂𛱛͏͏͏𛰜 𛰙𛱇𛰚𛱇𛰜 𛰔𛱄‌𛰆𛱁𛰚 𛱛‌𛰅𛱛𛰅 𛰜𛱇𛱇‌𛰜𛱇𛰙, 𛱊𛱁‌𛰅𛱁 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰋𛱁𛱆. 𛰣𛱇 𛱊𛱁‌𛰅𛱁 𛰜𛰃𛱒‌𛱇𛰆. 𛱊𛱁‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰜𛱁‌𛰀𛱁‌𛰆𛱇 𛱊𛱁‌𛰅𛱁 𛰆𛱇‌𛰙𛱁 𛰅𛱄‌𛰂𛱁 𛰜𛰅𛱂𛱆 𛰂𛱆 𛱜‌𛱜 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰆𛱂‌𛰆𛱁𛰚𛰊 𛰜𛰃𛱒‌𛱇𛰆: 𛱇𛰆𛱄͏͏͏ 𛱛‌𛰅𛱛𛰅 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛱆𛰅‌𛰃𛱂 𛱊𛱁‌𛰅𛱁 𛱜‌𛱜. 𛰂𛱆 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱇‌𛰅𛱆 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜. 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰚𛱁‌𛰚𛱇𛰣 𛰜𛱁‌𛰀𛱁‌𛰆𛱇: 𛱛‌𛰅𛱛𛰅 𛰜𛰅𛱂𛱆 𛰂𛱆 𛰅𛰆𛱚𛰈𛰜 𛰣𛱁‌𛰅𛱄 𛰀𛰆𛱄𛱆‌𛰙𛱁. 𛱁‌𛱊𛱁𛰜 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛱛‌𛰅𛱛𛰅. 𛰂𛱛͏͏͏𛰜 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱁𛰚 𛰜𛰃𛱒‌𛱇𛰆, 𛱛‌𛰅𛱛𛰅 𛰅𛰆𛱚𛰈𛰜 𛰣𛱁‌𛰅𛱄 𛰅𛱁‌𛰅𛱜 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰙𛱁‌𛱞𛰣: 𛰅𛱁‌𛰅𛱜 𛱁‌𛱑 𛰙𛱁‌𛱞𛰣 𛰣𛱁‌𛰅𛱄 𛰙𛱇𛰅𛰜𛰃 𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃. 𛰂𛱆 𛰅𛱜‌𛰚𛱇‌𛰜𛱇𛰙 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰚𛱁‌𛰚𛱇𛰣 𛱆𛰅‌𛰃𛱂 𛰅𛱁‌𛰅𛱜 𛰂𛱛͏͏͏𛰜 𛰃𛱛͏͏͏‌𛰙𛱁𛰣 𛰚𛱁‌𛱞‌𛰃𛰅𛱁 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛰅𛰆𛱁𛰜‌𛰅𛱁…
+
+𛱛‌𛰅𛱛𛰅 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱁𛰛 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚 𛰂𛱆 𛱞𛰅 𛰅𛱁𛰚‌𛰜𛱇𛰀 𛱞𛰀𛰃 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰚𛱁‌𛰚𛱇𛰣 𛰅𛰆𛱁𛰜‌𛰅𛱁. 𛰂𛱆 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰣𛱁‌𛰅𛱄 𛰅𛱜͏͏͏𛰛: 𛱇𛰆𛱄͏͏͏ 𛱆𛰀𛰃 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰚𛱁‌𛰚𛱇𛰣 𛰅𛱄‌𛰂𛱁 𛰃𛱚𛰚. 𛰅𛱄‌𛰂𛱁 𛰅𛱁‌𛰚𛱁‌𛱞 𛰀𛱚𛰜 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰣𛱁‌𛰅𛱄 𛱇𛰆𛱄͏͏͏: 𛱁‌𛱊𛱁𛰜 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰂𛱆 𛰃𛱂‌𛰚𛱁𛰜, 𛰃𛰆𛱇𛰆, 𛰆𛱇‌𛰊𛰆𛱇, 𛰆𛱇‌𛰅𛰋𛱇𛰙, 𛰃𛰆𛱇𛰆. 𛱄𛰆‌𛰙𛱁𛰚 𛰅𛰋𛱁𛰚𛱄𛰚, 𛰃𛱂‌𛱇𛱇 𛰅𛱄‌𛰂𛱁 𛰃𛱚𛰚, 𛱊𛱁‌𛰅𛱁 𛱜‌𛱜 𛰂𛱛͏͏͏𛰜 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱁𛰂‌𛰛𛱜‌𛰆𛱂 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛰅𛰆𛱛͏͏͏‌𛰚𛱁𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱇‌𛰅𛱆 𛰂𛱁‌𛰃𛰆𛱁𛰣 𛰆𛱂‌𛰂𛱆‌𛰆𛱇‌𛰃𛱁𛰜 𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙. 𛱊𛱁‌𛰅𛱁 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛱜‌𛱜 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰂𛱆 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰥𛱇𛰅‌𛰥𛱇𛰅. 𛰂𛱆 𛱆𛰀𛰃 𛰙𛱁𛰚, 𛱊𛱁‌𛰅𛱁 𛰚𛱇𛰙 𛰚𛱇𛰑 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛰃𛰆𛱛𛰜 𛰚𛱁‌𛰚𛱇𛰣 𛰂𛱆‌𛰂𛱁, 𛱊𛱁‌𛰅𛱁 𛱜‌𛱜 “𛰃𛰆𛱛𛰜 𛱛‌𛰅𛱛𛰅 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛰙𛱁𛰚 𛰂𛱆 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚 𛰃𛰆𛱁𛰂 𛱛‌𛰅𛱛𛰅 𛰆𛱂‌𛰂𛱆‌𛰆𛱇‌𛰃𛱁𛰜”. 𛰂𛱆 𛰚𛱁‌𛱞‌𛰃𛰅𛱁 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛰂𛱆 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚 𛰅𛱜‌𛰚𛱇‌𛰜𛱇𛰙 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛱇𛰆𛱇𛰂 𛱁‌𛱑 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛰂𛱆 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰅‌𛰜𛰃𛱂 𛰃𛱇‌𛰅𛱆 𛰙𛱁‌𛰙𛱛𛰅 𛰅𛱄𛰋𛰃 𛰀𛱚𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁. 𛱞𛰀𛰃 𛰇𛱁𛰋𛰅𛱆𛰂 𛱊𛱁‌𛰅𛱁 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱁𛰚 𛱁𛰃𛱁𛰆 𛱜‌𛱜 𛰂𛱛͏͏͏𛰜 𛰆𛱁𛰜𛰃 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛱊𛱁‌𛰅𛱁 𛰚𛱁‌𛰚𛱇𛰣 𛰅𛱁‌𛰚𛱁‌𛱞 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰅𛰆𛱂‌𛰀𛱁‌𛰚𛱇 𛰅𛱄‌𛰂𛱁 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛰙𛱁𛰚 𛱊𛱁‌𛰅𛱁 𛰀𛱚𛰜, 𛰅𛱆‌𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰜𛰃𛱇𛰅. 𛰃𛰆𛱂‌𛱜 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛰋𛱚𛰚 𛱛‌𛰅𛱛𛰅 𛰀𛱚𛰜. 𛰙𛱄𛰅𛰜𛰃 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛱆𛰙‌𛰃𛱂 𛰅𛱄‌𛰂𛱁 𛰙𛱄𛰅𛰜𛰃 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜, 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛰋𛱚𛰚. 𛰅𛱁‌𛰅𛱜 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰙𛱁‌𛱞𛰣 𛰃𛱂‌𛰙𛱁‌𛰚𛱜͏͏𛰜. 𛱇𛰆𛱄͏͏͏ 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰚𛱁‌𛱞‌𛰃𛰅𛱁 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱁𛰚. 𛰈𛰋𛱇𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱜͏͏͏𛰛 𛱛‌𛰅𛱛𛰅 𛱄𛰆‌𛰙𛱁𛰚 𛰂𛱆 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱇‌𛰅𛱆 𛰙𛱁‌𛰙𛱛𛰅 𛰅𛱄𛰋𛰃 𛰀𛱚𛰜 𛱊𛱁‌𛰅𛱁 𛰂𛱛͏͏͏𛰜 𛱊𛱁‌𛰅𛱁 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰅𛰆𛱂‌𛰀𛱁‌𛰚𛱇 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛰅𛱁 𛰀𛱚𛰜 𛰂𛱆 𛰜𛱁‌𛱊𛱁 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛰅𛱁 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛱇𛰆𛱇‌𛰀𛱇.
+
+𛰅𛱁‌𛰅𛱜, 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛱛‌𛰅𛱛𛰅 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰣𛱁‌𛰅𛱄 𛰜𛱁‌𛰆𛱇𛰅𛰜, 𛰂𛱆 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛰜𛰆𛱇𛰂. 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰊𛱆𛰃‌𛱄͏͏͏𛰂 𛰃𛱂‌𛰚𛱁𛰜 𛰜𛱄𛰚: 𛰀𛱜! 𛱞𛰀𛰃 𛰅𛱁‌𛰚𛱁‌𛱞 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰀𛱚𛰜! 𛱁‌𛱊𛱁𛰜 𛰂𛱆 𛰃𛱂‌𛰚𛱁𛰜, 𛰃𛰆𛱇𛰆, 𛰆𛱇‌𛰊𛰆𛱇, 𛰆𛱇‌𛰅𛰋𛱇𛰙, 𛰂𛱆 𛰃𛰅𛱄𛰂. 𛱇𛰆𛱄͏͏͏ 𛱆𛰀𛰃 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰣𛱁‌𛰅𛱄 𛱇𛰆𛱄͏͏͏. 𛰂𛱆 𛱁‌𛱊𛱁𛰜 𛰊𛰋𛱇𛰜 𛱛‌𛰅𛱛𛰅 𛰂𛱛‌𛰂𛱛͏͏͏𛰜, 𛰂𛱆 𛱁‌𛱊𛱁𛰜 𛰃𛰆𛱛𛰜 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛰅𛰆𛱁𛰜‌𛰅𛱁. 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛱁‌𛱑 𛱜‌𛱜 𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅, 𛰂𛱆 𛰃𛰆𛱁𛰂 𛰜𛰅𛱛‌𛰅𛱛𛰙 𛰃𛱄𛰙‌𛰃𛱄𛰙. 𛱄𛰆‌𛰙𛱁𛰚 𛰅𛰋𛱁𛰚𛱄𛰚 𛱞𛰀𛰃 𛱊𛱁‌𛰅𛱁 𛱜‌𛱜 𛰂𛱛͏͏͏𛰜 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱁𛰂‌𛰛𛱜‌𛰆𛱂 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛱞𛰅 𛰅𛱁𛰚‌𛰜𛱇𛰀 𛱁𛰚‌𛰅𛱁‌𛰃𛱇 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛱆‌𛰆𛱂‌𛰂𛱂𛱆 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛰙𛱁𛰚 𛱊𛱁‌𛰅𛱁 𛰀𛱚𛰜. 𛰂𛱆 𛰅𛱁‌𛰚𛱁‌𛱞 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛱆𛰀𛰃 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅: 𛱇𛰆𛱄͏͏͏ 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰃𛱇‌𛰅𛱆 𛰙𛱁𛰅‌𛰙𛱁𛰅 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰜𛱄𛰚, 𛰂𛱆 𛱁‌𛱊𛱁𛰜 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛱛‌𛰅𛱛𛰅. 𛰙𛱄𛰅𛰜𛰃 𛰜𛱄𛰚 𛱛‌𛰅𛱛𛰅 𛰊𛰋𛱇𛰜 𛰂𛱆 𛰆𛱇‌𛰜𛱇 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛱇𛰆𛱄͏͏͏ 𛰃𛱇‌𛰅𛱆 𛰙𛱁𛰅‌𛰙𛱁𛰅: 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛱞𛰅 𛰜𛱁‌𛱊𛱁 𛰅𛱄‌𛰂𛱁 𛰂𛱁‌𛱊𛱁 𛰂𛱆 𛰅𛱄‌𛰂𛱁 𛰜𛱄𛰚.
+
+𛰅𛱄‌𛰂𛱆𛰃 𛰅𛱁‌𛰚𛱁‌𛱞 𛱆𛰀𛰃 𛰜𛱄𛰚‌𛰈𛱇 𛰂𛱆 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰚𛱁‌𛰚𛱇𛰣 𛱇𛰆𛱄͏͏͏ 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰆𛱂𛱆𛰃 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛰙𛱁𛰚 𛱊𛱁‌𛰅𛱁 𛰀𛱚𛰜 𛰅𛱆‌𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛰜𛰃𛱇𛰅. 𛰃𛱂‌𛰚𛱁𛰜 𛰚𛱇𛰑 𛱜‌𛱜 𛰂𛱛͏͏͏𛰜, 𛰅𛱄‌𛰂𛱆𛰃 𛱛‌𛰅𛱛𛰅 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛰅𛱁𛰀 𛰣𛱁‌𛰅𛱄 𛱇𛰆𛱄͏͏͏ 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜, 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰅‌𛰜𛰃𛱂 𛰚𛱁‌𛰚𛱇𛰣 𛱛‌𛰅𛱛𛰅 𛱄𛰆‌𛰙𛱁𛰚 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚. 𛰅𛱄‌𛰂𛱆𛰃 𛱆𛰀𛰃 𛱞𛰀𛰃 𛰜𛱄𛰚‌𛰈𛱇 𛰂𛱆 𛰃𛱂‌𛱇𛱇 𛰅𛱄‌𛰂𛱁 𛰃𛱚𛰚 𛰙𛱁‌𛰙𛱛𛰅 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰙𛱄𛰅𛰜𛰃 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙. 𛱊𛱁‌𛰅𛱁 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃 𛰛𛱁𛰚𛰊 𛰂𛱆 𛰑𛱛𛰆 𛰂𛱛͏͏͏𛰜 𛱞𛰀𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰚𛱁‌𛰚𛱇𛰣. 𛰛𛱁𛰚𛰊 𛰙𛱁‌𛰙𛱛𛰅 𛰣𛱇𛰅‌𛰙𛱇𛰚 𛱆𛰅‌𛰃𛱁𛰜 𛰂𛱆 𛰑𛱛𛰆 𛱊𛱁‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰅𛱑𛰃 𛰜𛰃𛱄𛰚. 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰀𛱁‌𛰆𛱁𛰅 𛱛‌𛰅𛱛𛰅 𛰀𛱚𛰜 𛱊𛱁‌𛰅𛱁 𛰆𛱂‌𛰂𛱄𛰋𛰃, 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰚𛱁‌𛰚𛱇𛰣 𛱛‌𛰅𛱛𛰅: 𛰙𛱄𛰅𛰜𛰃 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰇𛱄𛰚 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰅𛱄‌𛰂𛱁 𛱇𛰆𛱇‌𛰀𛱇, 𛰂𛱆 𛰅𛱄‌𛰂𛱁 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛰃𛱂‌𛰚𛱁𛰜 𛱁‌𛱑 𛰇𛱆‌𛰃𛱇𛰆 𛰅𛱛‌𛰆𛱇 𛰋𛱚𛰚.
+
+𛱊𛱁‌𛱜 𛰃𛱂‌𛱇𛱇 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚 𛱁‌𛱑 𛱜‌𛱜 𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃. 𛰜𛱁𛰑, 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛱊𛱁‌𛰅𛱁 𛰃𛰆𛱛𛰜 𛰚𛱁‌𛰚𛱇𛰣 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛰃𛱇‌𛰆𛱇‌𛰅𛱛𛰙, 𛱁‌𛱑 𛱜‌𛱜 𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃 𛰚𛱇𛰑, 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛱊𛱁‌𛰅𛱁 𛰃𛰆𛱛𛰜 𛰚𛱁‌𛰚𛱇𛰣 𛰂𛱆‌𛰂𛱁; 𛰅𛱁‌𛰚𛱁‌𛱞 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱁‌𛱑 𛱁𛰜𛰅 𛱄𛰆‌𛰙𛱁𛰚 𛰅𛰋𛱁𛰚𛱄𛰚 𛰂𛱆 𛰛𛱁𛰚𛰊 𛰂𛱆 𛰑𛱛𛰆. 𛱞𛰀𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱁‌𛱑 𛱁𛰜𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛱁𛰃𛱁𛰆, 𛰇𛱁𛰋𛰅𛱆𛰂 𛱊𛱁‌𛰅𛱁 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱁𛰚, 𛰂𛱆 𛰂𛱁‌𛰃𛰆𛱁𛰣 𛰅𛱁𛰚‌𛰈𛱇 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛰅𛱁. 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱁‌𛱑 𛱜‌𛱜 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛱄𛰆‌𛰙𛱁𛰚 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚, 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙, 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱇𛰚𛱇𛰜 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛰃𛰆𛱇𛰆 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜, 𛰅𛱁‌𛰃𛱂 𛰙𛱇𛰚𛱇𛰜 𛱊𛱁‌𛰅𛱁 𛰜𛰃𛱒‌𛱇𛰆, 𛰅𛱁‌𛰃𛱂 𛰜𛰅𛱂𛱆 𛰂𛱛͏͏͏𛰜 𛱊𛱁‌𛰅𛱁 𛰜𛰃𛱒‌𛱇𛰆, 𛱆𛰅‌𛰃𛱂 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰙𛱁‌𛰙𛱛𛰅 𛱛‌𛰅𛱛𛰅 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛰅𛱁𛰀 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱁𛰛 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚, 𛰂𛱆 𛱆𛰅‌𛰃𛱂 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛰆𛱁𛰂 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰀𛱚𛰜 𛰅𛱆‌𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛰜𛰃𛱇𛰅 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛱇𛰆𛱇‌𛰀𛱇.
+
+𛰅𛱄‌𛰂𛱆𛰃 𛱛‌𛰅𛱛𛰅, 𛰃𛱂‌𛱇𛱇 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱁‌𛰙𛱛𛰅 𛱁‌𛱊𛱁𛰜 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰆𛱄͏͏͏: 𛰅𛱁‌𛰚𛱁‌𛱞 𛰅𛱄‌𛰂𛱁 𛰀𛱁𛰑𛱇𛰊 𛰙𛱁‌𛰅𛱛𛰅 𛰀𛱚𛰜 𛰂𛱆 𛱛‌𛰅𛱛𛰅 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛰚𛱇𛰋 𛱇𛰆𛱇‌𛰀𛱇 𛰅𛱜‌𛰚𛱇‌𛰜𛱇𛰙 𛱁‌𛱑 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰆𛱄͏͏͏. 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛱛‌𛰅𛱛𛰅 𛰆𛱄͏͏͏: 𛱞𛰅 𛰃𛰆𛱛𛰜 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰅‌𛰜𛰃𛱂 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜.
+
+𛰅𛱄‌𛰂𛱆𛰃 𛰅𛱁‌𛰅𛱜 𛱛‌𛰅𛱛𛰅 𛰜𛱇𛱇‌𛰜𛱇𛰙
diff --git a/perf/texts/fa-monologue.txt b/perf/texts/fa-monologue.txt
deleted file mode 100644 (file)
index c41257c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-من اسمم کاظمه. ما توی یه کوچه بن بست خونه داریم. کوچه‌مون خاکیه. اونوقت خیلی پایئن تر از خونه ما - زیاد پایین نه - اینور می‌پیچی یه نونواس. از اونجا صاف می‌ریم اینجا. یه خیابونه اینجا. اونوقت خیلی پایین‌ترش یه حمومه. بعداً یه بقالی هم دم خونمونه. یه خرده انور خرابه، یه قصابیه. قصابه با بابام رفیقه. پشت خونمون یه دباغیه. اینقده بچه گوسفند توشه! خونه‌مون ساس داره. ساس کوچیک و سیاس. هر جا بزنه جاش باد می‌کنه. وقتی داره از دیوار اتاق می‌ره بالا، نمی‌تونه خودشو نگه داره، می‌افته رو تن ما، می‌گیره خونمونو می‌مکه. یه دفعه همه اثاث مثاثامونو ریختیم بیرون، یه عالمه دوا خریدیم زدیم همه جا: به رختخوابا،‌ زیر زیلو، سوراخ سنبه‌ها. ولی ساسها بیشتر شدن، کمتر نشدن. بابام توی حموم کار می‌کنه. دوتا برادر داریم، یه خواهر: من و مصطفی و زهرا کوچولو. بابا وقتی داره شب می‌شه برمی‌گرده خونه. همیشه استخوناش درد می‌کنه. سر هیچی به هیچی می‌گیره می‌زنه‌مون، بازهم طلبکاره. مثلاً وسط سال، صبح ساعت شیش می‌آد می‌گه، «پاشو برو سیگار بفروش، پول دربیار لباس بخر!» من هم می‌گم: «لباس می‌خوام چی‌ کار؟» اون هم می‌گیره با کمربند حالمونو جا می‌آره. باز خوبه سه ماه تعطیلی خودمون می‌ریم کار می‌کنیم. یه کارخونه هست. می‌ریم اونجا قابلمه درست می‌کنیم، کاسه درست می‌کنیم، عصر که شونصد تا کاسه درست کردیم، دستگارو تمیز می‌کنیم برمی‌گردیم خونه. پارسال هفته‌ای پنجاه تومن مزد می‌دادن. امسال دیگه خدا می‌دونه. با همه این حرفا، بمیریم بهتره آقا! هر روز هر روز کتک.  بابام دیشب بیخودی مصطفی رو گرفت زد. گرفت زدش گفت: «چرا وقتی می‌ری دست به آب، سر پا می‌شاشی؟ بشی بشاش!» مصطفی‌مون هیچی حالیش نمی‌شه. قد زهرامون بوده که از بالا پشت بوم افتاده، رگ کله‌اش تکون خرده. حالا سیزده سالشه. نه چارده،‌ چارده سالشه. داداش بزرگ‌ مونه. الان مدرسه عقب افتاده‌ها درس می‌خونه. آب، بابا، بار میخونه یاد بگیره، بیاد جلو. دو سه کلمه بلده حرف بزنه ولی چیزه... نمیتونه قشنگ حرف بزنه. بابام می‌خواد از مدرسه ورش داره، بذاره یه جا که کار یاد بگیره. بابا زهرا را از همه بیشتر می‌خواد. اون هم هر کاری دلش بخواد می‌کنه. هرچی می‌گیم گوش نمی‌کنه، می‌ره تو جوب محل کثافت‌کاری می‌کنه. اون روزی حواسم نبود، رفت یه مشت دیگ مونده سر کوچه بود ورداشت خورد. شب دلش درد گرفت نزدیک بود بمیره. اونوقت بابام اومد گرفت منو با شیلنگ کشت. آقا مگه شهر هرته؟ خر کتک می‌خوره. دیگه چرا ما رو می‌زنن؟ برن به خر بزنن! آخه من که نمی‌تونم همه‌ش مواظب زهرا باشم. راستی یه صاحب حیاط داریم، خیلی بد اخلاقه آقا! اسمش عباس آقاس. صبح می‌ره ظهر می‌آد. سپور شهرداریه. بیست و چار ساعت می‌آد بند میکنه به ما، میگه: «آب زیاد مصرف نکنین، چاه پر میشه.» زهرامون که گاهی گریه می‌کنه، دادش بلند می‌شه می‌گه: «صدای این تخم‌سگو خفه کنین!» اونوقت که مادرمون زنده بود، یه دفعه می‌خواست از دست عباس آقا نفت بریزه سرش، خودشو آتیش بزنه. عباس آقا اصلاً رحم حالیش نمی‌شه؛ پسر سیزده ساله‌شو گرفته از خونه انداخته بیرون. اون هم رفته توی کوچه‌ پس ‌کوچه‌‌ها ول شده. حالا خدا می‌دونه کجاس، چه کار می‌کنه،‌ از کجا می‌آره می‌خوره. بچه‌ها می‌گن: «شب‌ها می‌ره توی پارک‌ها پیش سگها می‌خوابه.» که رفته دهات خونهٔ باباش، می‌گه دیگه نمی‌آم تهران. آقا، ما هم دلمون می‌خواد میرفتیم دهمون با گوسفندها بازی می‌کردیم؛ با بابا بزرگ‌مون می‌رفتیم دشت بز می‌چروندیم،‌ بادوم پاک می‌کردیم، انگور می‌چیدیم. دهمون ولی خیلی دوره آخه! زن عباس آقا حق داره، آقا! محله‌مون خیلی بده. هر روز اونجا دعواس، دعوا، چاقو کشی. توی خرابه هم پر معتاده، بگی دوهزار تا هم بیشتر. می‌رن اونجا قمار می‌کنن، شیره می‌کشن، آمپول می‌زنن تو رگشون. ماهم از ترس معتادها جرأت نمی‌کنیم از خونه بریم کوچه، یه ذره بازی کنیم. از کمیته‌م نمی‌ترسن، میگیرن بچه‌های مردمو می‌دزدن، میبرن توی کوره‌ها،‌ توی دلاشون چیز قایم می‌کنن؛ هروئین قایم میکنن. یه امیر ریزه هست تریاکیه، اون روزی اومد خرم کنه، گفت: «بیا سوار ماشین بشیم، بریم یه جائی.» من هم از ترسم خر نشدم. یه چیز خنده دار بگم بخندی، آقا: اینورمون یه همسایه داریم، اسمش ربابه. انوقت توپ،‌ لنگه کفش، تنکه، هرچی بیفته خونشون،‌ شوهرش ور می‌داره می‌اندازه توی آب انبارشون. هروقت هم کوچه شلوغ بشه، شوهر رباب می‌آد بیرون می‌گه: «واق، عو!» اون هم مث مصطفی‌ ما لقوه‌ایه‌؛ دستش می‌لزره، همه جاش می‌لرزه. اون روز اومد دم دکون، رفت اونور جوب نشت. این یکی همسایه‌مون رفت یه کتاب دربارهٔ خدا و فرشته‌ها آورد براش خوند. رباب خانم خودش خونه یه اعیونه کار می‌کنه؛ چیزاشونو می‌شوره، باغ‌شونو آب می‌ده؛ کلفتی می‌کنه. بعد همه‌ش می‌آد پز اربابشو می‌ده. الان دیگه همه اهل محل می‌دونن باغ خونهٔ ارباب رباب خانوم اندازه پارک شهره. استخرش از مال پارک شهر هم گنده‌تره. هروقت هم که ارباب می‌خواد‌ آبتنی کنه،‌ اول یه قطره دوای مخصوص هست، می‌ریزه توی استخر که آب‌شو می‌کنه مث اشک چشم. بعد می‌ره زیر دوش، با عطر و گلاب خودشو می‌شوره. بعد می‌پره توی استخر، می‌گیره شوخی شوخی آب می‌پاشه به رباب خانوم. زن اربابش هم خارجیه. مال همون کشوریه که شیش ماه شبه، شیش ماه روز. رباب یه چاخان‌هایی می‌کنه که کلهٔ آدم سوت می‌کشه! می‌گه ارباب یه سگ پشمالو داره،‌ اسمش مونیکاس. قسم می‌خوره می‌گه مونیکا غذاشو با کارد و چنگال می‌خوره. اللَه اکبر به این دروغ. یه پیرزنه هم هست سر کوچمونه. با خودش تنهایی زندگی می‌کنه. اسمش ننه غلامه. هشتاد نود سالشه ولی خجالت نمی‌کشه،‌ از امریکا خوشش می‌آد. همه ازش می‌ترسن؛ هر وفت بیاد بیرون، فحش می‌ده، جیغ و ویغ می‌زنه. مثلا من اذیتش کردم، می‌آد سر فحش‌رو می‌کشه به تو. وقتی بچه‌ها بخوان لج‌شو در‌بیارن، می‌گن: «مرگ بر امریکا!» اونوقت اون هم حرصش می‌گیره، هزار تا فحش بی‌ناموسی و خوار و مادر می‌کشه به جون همه. ننه غلام دیونه‌س. بعضی وقتا هم با‌ آدم خوبه. یه روز من و زهرا رو گرفت به زور برد خونه‌ش، کله پاچه داد، گفت «بخورین!» ما هم خوردیم. ته کاسه یه لقمه موند که روش یه عالمه مو بود. گفت: «اگه نخورین با همین چاقو سرتونو می‌برم.» ما هم از ترس جونمون خوردیم. ننه غلام وقتی سر حاله، چیز می‌آره می‌ده آدم. مثلا یکی زخمه،‌ دوا می‌آره بهش می‌ده. مثلا کسی چیزی نداره، چیز می‌آره بهش می‌ده، وسط کوچه‌مون یه خونه‌س که دخترهاش خرابن، آقا. اونوقت شیره‌ای‌ها و چاقوکش‌ها می‌رن خونه‌شون، کار بد می‌کنن. بعضی وقتا هم دختر‌هاش لباس سرخ و زرد تن می‌کنن و کفش پاشنه بلند تق‌تقی می‌پوشن، می‌رن واسه بالاشهری‌ها قر می‌دن. یه دفعه هم داشتم می‌رفتم پیش بچه‌ها «لیس پس لیس» بازی کنم که دختر کوچیکه‌ش امیر ریزه رو صدا کرد و بهش گفت: «تو چقدر پاهات لاغره!» بعد امیر ریزه هم نامردی نکرد. گفت:«خودت چرا لمبه‌هات چاقه؟» بعد دوتایی کرکر خندیدن. خودم با همین دو تا چشمام دیدم، آقا! اونوقت ما هم که می‌بینیم محله‌مون پر از بی‌تربیتی‌یه، زدیم با هفت‌تا از بچه محلامون قهر کردیم. با اون هفت‌تا هم بمیرم آشتی نمی‌کنم، آقا. با یکی‌شون یه ساله قهریم، اسمش محمده. یه روز سر کوچه‌مون عروسی بود، ما هم داشتیم بازی می‌کردیم. من دراومدم به محمد گفتم: «محمد امشب چه خبره؟ آبجی‌ت می‌ره حجله؟» ناراحت شد، گفت: «باهات قهرم.» من هم گفتم: «چه بهتر! می‌رم درسامو می‌خونم.» به خدا ما چه می‌دونستیم، به خیالمون عروسی آبجیشه، آقا! فقط با دو نفر دوستیم: مهدی ملخ و حسن گامبو. مهدی از بس مردنیه، همه ملخ صداش می‌کنن. باباش قوری بست می‌زنه. وسط بازی یهو پیداش می‌شه، می‌آد می‌گه: «اگه منو بازی ندین، بازی‌تونو بهم می‌زنم.» اونوقت تا که دس بهش می‌خوره، جیغش می‌ره هوا، میگه: «گه خوردم، گه خوردم.» اونوقت می‌ره از حرصش با میخ یه شکل‌هایی می‌کشه روی دیوار، می‌گه: «این عکس کاظمه.» فسقلی فوتش کنی، قل می‌خوره، ها. آقا، ما دوچرخه خیلی دوست داریم، بعضی وقتا می‌ریم یه تومن می‌دیم چرخ کرایه می‌کنیم. حسن گامبو زورش می‌آد، با سنگ می‌زنه، می‌گه: «منو باید سوار کنی.» من هم می‌بینم داره دلش می‌شکنه، می‌گم: «بیا تو هم سوار شو!» داداش حسن گامبو پنج ماهه رفته لب مرز با خارجیا بجنگه. حسن می‌گه: «رفته امریکا رو نابود کنه، برگرده.» بابای حسن آهنکاره؛ یعنی قالب می‌سازه، پشقاب می‌سازه، همه‌چی می‌سازه. نه که حسن خیکیه، بچه‌ها صداش می‌کنن: «حسن گامبو، سرت تو شامپو!» می‌خواییم با این دو نفر هم قهر کنیم بره. هی می‌آن در خونمون داد می‌زنن: «کاظم، بیا بازی، بیا بازی!» بازی چیه، آقا؟ بده بچه بازی کنه. رفوزه بشیم چه کار؟ دلم می‌خواد دکتر، مهندس، بازنشست، نیرو هوایی، هرچی شد بشیم، بریم پی کارمون بره. ولی تو خونه ما نمی‌شه درس خوند. تا می‌آم بشینم، باید پاشم برم نون بخرم، جارو کنم، خشتک زهرامونو بشورم. پارسال که رفوزه شدم، همه‌ش نیم نمره می‌خواستم قبول بشم. مدرسه‌مونم خیلی هردمبیه، آقا! بچه‌هاش دزدن، می‌آن دفترامونو می‌دزدن. سر کلاس یکی گچ پرت می‌کنه، یکی رو نیمکت ضرب می‌گیره، یکی پا می‌شه می‌رقصه. ما هم که می‌بینیم خر تو خره، حوصله‌مون سر می‌ره، از مدرسه جیم می‌شیم، می‌ریم فروشگاه بزرگ. اونجا پله‌برقی داره. می‌ریم می‌ایستیم خودمونو می‌زینم به اون راه. الکی نگاه می‌کنیم به جنس منس‌ها؛ یعنی مثلا ما هم اومدیم چیز بخریم. بعد می‌ریم سوار پله‌برقی می‌شیم، می‌ریم سواری می‌خوریم، عشق می‌کنیم. آقا، اجازه؟ سه تا دایی هم دارم، آقا! یکی‌شون دایی ضامن، یکی‌شونم دایی مرتضی. اونی که وضعش خوبه اسمش دایی رضوانه. یه وانت داره با یه اتوشویی. تا پامونو می‌ذاریم در دکونش، نامرد یه لگد می‌زنه در اونجامون، می‌گه: «بزن به چاک! باز اومدی از دخل کف ببری» به خدا تهمت می‌زنه، آقا! آقا، به خدا هیچکی به اندازه ما از دزدی بدش نمی‌آد. آقا، دایی مرتضی‌مون اولها کارگر بلورسازی بود، ولی وقتی من هنوز تو دل مادرم بودم، افتاد زندان. یه شب هفت نفر ریختن سرش، اون هم چاقو کشید، زد یکی‌شونو کشت. بعد دادگاه هم اومد بیخودی تقصیر رو گذاشت گردن دایی ما. قبل انقلاب از زندان اومد بیرون، رفت معتاد شد. حالا هم همیشه با زنش دعوا مرافعه داره. گاهی می‌ذاره از خونه‌ش می‌ره، می‌ره می‌ره پیداش نمی‌شه. بعد که برمی‌گرده، الکی به زنش می‌گه، رفته بودم بیمارستان ترک کنم. دایی مرتضی یه بچه کوچولو داره، هروقت می‌آد خونمون، می‌خواد از پله‌هامون بره بالا، بیاد پایین. ما هم می‌ریم دنبالش که نیفته سرش بشکنه. می‌ریم بغلش می‌کنیم. اونوقت می‌ترسه، سفت آدمو می‌گیره. دایی ضامن‌مون توی دولت آباد نفتیه، بعضی روزها که می‌ره نفت پخش کنه منو هم با خودش می‌بره. اون تا می‌ره نفت بده به خونه‌ها، بچه‌ها می‌گیرن مسخره‌م می‌کنن، می‌گن: «ای عرب پا نفتی، کی اومدی، کی رفتی؟» سنگ می‌زنن تو کله‌ام. من هم که زورم نمی‌رسه، گریه‌م می‌گیره. یه روز رفتیم در یه خونه نفت بدیم، اونوقت یه پسره بود - لال بود - دنبالمون کرد تا سر کوچه‌شون. فحش مادر داد، گفت: «دیگه در خونه ما نیا!» لال بود، آقا! نمی‌دونیم چی می‌گفت... آقا، هر وقت از مادرمون حرف می‌زنیم، بغض می‌آد گلومونو می‌گیره، ول‌مون نمی‌کنه... مادرمون سر بچه مرد، آقا! شب درد بچه گرفتش. رفتیم نبات خانومو آوردیم. نبات خانوم مامای محله‌س، شله، یه چشمش هم چپه. صبح که بچه اومد دنیا، مادرمون گذاشت از دنیا رفت. بچه‌ هم پشت سرش مرد، آقا!... مادرمون اون وقت که زنده بود، توی کارخونهٔ استارلایت کار می‌کرد. جوراب شلواری می‌بافت. وقتی شکمش اومد بالا، از اونجا بیرونش کردن. مادرمون اینقده سختی کشیده که خدا بگه، بس! همیشه مریض بود، بعضی وقتا هم غش می‌کرد. پاهاش قد یه متکا باد کرده بود، آقا!... آقا، باور کن، آقا... وقتی مادرمون مرد ما صد برابر الان بغض کردیم. من و زهرا و مصطفی شب تا صبح خوابمون نبرد. بابام اون شب هزار تا سیگار کشید،‌ ولی صبحش مادرمون مرد. وقتی رفتیم خاکش کنیم، ننه غلام نمی‌خواست بذاره ما بریم تماشا، می‌گفت، ما بچه‌ایم، گناه داریم. ولی من دزدکی توی مرده‌شور خونه هم رفتم. بوی بدی می‌ده مرده‌شور خونه، بوی گربهٔ مرده. آدم می‌خواد دل و روده‌شو بالا بیاره. وقتی مادرمونو اوردن گذاشتن توی سالن مرده‌شور خونه، هفت تا مرده زودتر مرده بودن. مادرمون نفر هشتم بود. مرده‌ها منتظر بودن دوش خالی بشه، سر نوبت برن تو، غسل کنن. جنازه یه دختر مدرسه هم بود. نمی‌دونی فک و فامیل دختره چی‌کار می‌کردن؛ یکی سرشو می‌زد به دیوار، یکی کفش‌شو دراورده بود می‌زد تو سر خودش. مادرمونو که اوردن بذارن توی قبر، سروکله‌ٔ مصطفی هم پیداش شد. مادرمون با مصطفی خوب بود. خدا بیامرز که رفت توی قبر، نمی‌دونم از کجا یه مگس اومد نشست روی کفنش. تا مصطفی کیش‌اش کرد، مگسه گذاشت در رفت. بعد شروع کردن با بیل خاک ریختن روی سر مادرمون. رباب خانم با ناخن صورتشو می‌کند. بابام داشت توی دل خودش گریه می‌کرد. اگه مصطفی نمی‌زد زیر گریه و توی خاک و خل غلت نمی‌خورد، من هم گریه نمی‌کردم... مادرمونو که خاک کردیم، دم قبرستان حلوای نذری پخش می‌کردن. واسه اینکه بوی گربهٔ مرده از دماغم بره، یه قاشق حلوا گذاشتم دهنم. ولی صاحب عذا که روشو برگردوند، تفش کردم. آقا، هیچی نمی‌تونستیم بخوریم. آقا، ما دلمون خیلی تنگه، هیشکی نیست ما را زفت کنه. دل‌مون می‌خواد از این دنیا می‌رفتیم. آقا، باورتون نمی‌شه، توی محله ما ملت تند تند می‌میرن، آقا! زهرامون یه همبازی داره، همقد خودشه. اسمش الهامه، پنج سالشه. ده بیست روز پیش باباش از داربست افتاد زمین عکس برگردون شد، مرد. دیروز الهام اومده بود خونه‌مون، یه عکس از باباش هم اورده بود، می‌گفت، هر شب خواب باباشو می‌بینه که اون دنیا آتیش درست کرده، می‌خواد بیاد  بگیره اونو کباب کنه بخوره. یه حرفهایی می‌زد که مو به تن آدم سیخ می‌شد. اونوقت شب که خوابم برد، خوابیدم، خواب دیدم عزرائیل و شمر با آتیش اومدن بالای سرم، هی می‌چرخن و چه‌چه می‌خندن. عزرائیل نصفه‌س، آقا! یعنی پا نداره. من هم اومدم از دست‌شون در برم که دیدم یه خرگوشه داره با مامانش قایم موشک بازی می‌کنه. رفتم بگم، من هم بازی که گذاشتن در رفتن. من هم دنبالشون کردم. خسته که شدم دیدم سوار یه قایقم، یه سگ هم داشتم. داشتم با سگ بازی می‌کردم که یهو امیر ریزه پشت پا انداخت، افتادم توی آب. من هم رفتم سوار دوچرخه شدم، زدم به چاک. سگ هم از توی قایق پرید، اومد دنبالم. بعدش دیدم یه هلی‌کوپتر بالای سرمه، می‌خواد باید بستنی لیوانی‌مو قاپ بزنه. من هم با سنگ زدم شیشه‌شو شکوندم. اون هم ترسید در رفت، توی کوچه دباغ‌ها غیب شد. بعدش دیدم عباس آقا گرگ شده، می‌خواد بیاد زهرامونو بگیره لقمه‌ٔ چپش کنه. از ترسم دویدم توی پارک و رفتم سوار تاب شدم. اینقده تاب بازی کردم تا حسابی سرم گیج رفت. اومدم از تاب بپرم پایین، دیدیم زیر پام یه چاهه، یه چاه به این گندگی. داشتم ول می‌شدم ته چاه که از خواب پریدم. نشستم گریه کردم. اونوقت بابام بیدار شد، پرسید: «باز چی شده؟ شاشیدی؟» گفتم: «می‌ترسم.» گفت: «بگیر بخواب بابا تو هم دلت خوشه!» من هم لحافو که کشیدم روی سرم، همه‌ش خدا خدا می‌کردم ایم دفعه که خوابم برد، شانسم بگه، بزنه خواب خوشبختی ببینم، دلم خوش بشه. ولی اگه ما شانس داشتیم، آقا، اسم‌مونو می‌ذاشتن شانسعلی.
diff --git a/perf/texts/fa-words.txt b/perf/texts/fa-words.txt
new file mode 100644 (file)
index 0000000..4937544
--- /dev/null
@@ -0,0 +1,10000 @@
+در
+به
+از
+ویکی‌پدیا
+که
+را
+این
+با
+است
+رده
+برای
+کاربر
+بحث
+تصویر
+میلادی
+ایران
+تاریخ
+نام
+پرونده
+آن
+یک
+ساعت
+صفحهٔ
+کنید
+پیوند
+مقاله
+صفحه
+شما
+اصلی
+عنوان
+یا
+تا
+سال
+هم
+من
+استفاده
+بر
+خود
+شده
+شد
+تغییرمسیر
+شهرستان
+کار
+راهنمای
+اگر
+تکثیر
+چه
+ویرایش
+حق
+مقاله‌های
+می
+فارسی
+نیست
+دیگر
+نوشتن
+پنج
+بود
+زبان
+سیارک
+امضا
+کمک
+شیوه‌نامه
+منابع
+ملی
+ثبت
+آثار
+پانویس
+۱۱
+میز
+خودآموز
+بخش
+دارد
+خرد
+انگلیسی
+او
+لطفاً
+نیز
+۱۵
+شماره
+پهنا
+بنیاد
+استان
+هر
+اثر
+می‌شود
+مورد
+کرد
+یادکرد
+امیدوارم
+راهنما
+کنیم
+خوش
+ویکی
+چیزی
+پس
+شهر
+پیش
+فهرست
+مرجع
+خط
+آمدید
+اطلاعات
+اینجا
+تاریخی
+زیر
+منبع
+جعبه
+جدید
+دوره
+بیشتر
+اینکه
+بهتر
+یکی
+شود
+دو
+سپتامبر
+راهنمایی
+پیوندهای
+حذف
+۲۰۰۰
+خوب
+نظر
+آزاد
+قرار
+خواهد
+تمرین
+باشد
+بله
+پیرامون
+سلام
+آموزش
+اصل
+۱۰
+نه
+صفحات
+۱۹
+۱۲
+۲۰۱۱،
+های
+پاس
+ولی
+توسط
+چگونه
+برگزیده
+بداریم
+فقط
+ویکی‌پروژه
+۲۰۰۱
+روی
+سریع
+اکتبر
+صورت
+دست
+قهوه‌خانه
+۱۴
+دانشگاه
+بنیادی
+اما
+بیاید
+ناشر
+داشتید،
+باید
+بروید
+الگو
+چهار
+اول
+مارس
+کتاب
+ایجاد
+بازدید
+توجه
+آنها
+پایه
+۲۰
+کشور
+ساختار
+سخ
+خوش‌آمدید
+مقالهٔ
+شده‌است
+سازمان
+فارسی‌نویسی
+بودن
+مرکزی
+باز
+آمریکا
+وب
+۱۶
+نویسنده
+کادر
+دسامبر
+صورتی
+۲۰۰۷
+۱۸
+۲۰۱۰،
+کند
+فنی
+تصمیم
+۱۳
+تهران
+وجود
+۱۷
+نشانی
+چطور
+چند
+کشف
+اوت
+دانشنامه‌ای
+فوتبال
+علمی
+۲۰۰۸،
+درج
+۲۰۰۲
+هستند
+بگیرید
+۲۱
+۲۰۱۱
+نوامبر
+مطالب
+آزمایش
+وی
+کاربران
+فیلم
+ها
+ماندن
+مقالات
+بپرسید
+حروف
+لذت
+جمعیت
+بحثم
+ببرید
+خوشتان
+مدک
+وابسته
+ویکی‌پدیانویس
+ویکی‌پدیانویسان
+۲۰۰۹،
+اسلام
+۲۲
+مسایل
+آوریل
+بنویسیم
+۱۹۹۹
+کاربری
+علامت
+واقع
+شوید
+اهمیت
+۲۳
+کلاس
+کردن
+ای
+آشنا
+باشید
+نگاهی
+کوچک
+نکنید
+وب‌گاه
+پروژه‌های
+کرده
+۲۸
+می‌توانید
+انتخاب
+مکنید
+بعد
+روز
+است،
+جستارهای
+شدن
+نوع
+نمونه‌های
+۲۴
+نفر
+دارید،
+بیندازید
+خودکار
+۲۰۰۶
+نوشته
+مطالعهٔ
+انبار
+عجله
+غفلت
+فهرست‌شده
+مشارکت
+اهل
+۲۵
+سوال
+محمد
+بوده
+۳۰
+بسیار
+بزرگ
+میراث
+میان
+زمان
+منابعی
+اثبات‌پذیری
+جلالی
+سیارک‌های
+دهستان
+مرکز
+انجام
+فوریه
+می‌کند
+۲۶
+نام‌های
+ما
+یعنی
+ایرانی
+ژوئن
+غیر
+پایان
+یونسکو
+حال
+پرحجم
+چپ
+می‌گویم
+داشته
+جمله
+پیام
+عمومی
+گردشگری
+قبل
+همین
+همچنین
+همان
+مالک
+سپاسگزارم
+سال‌های
+همه
+اندازه
+مربوط
+ویکی‌انبار
+قدر
+چون
+بیرون
+ویکی‌نویسی
+داده
+کسب
+دوم
+ویژه
+هیچ
+فرهنگ
+کسی
+بروید،
+تنها
+۲۰۰۳
+دارای
+ساخت
+افراد
+رتب
+تازه‌واردان،
+مه
+محلی
+بصب
+بین
+پتوپ
+مقاله‌ها
+نیازمند
+اسلامی
+۲۷
+بی
+مرگ
+علی
+۲۰۰۵
+متون
+مطلق
+سه
+می‌باشد
+نیاز
+شرکت
+۲۹
+۲۰۰۹
+باشگاه
+دلیل
+زندگی
+چاپ
+موجود
+۲۰۰۸
+نقل
+گروه
+۲۰۰۴
+انتهای
+دارند
+محتویات
+شاد
+موضوعات
+جستجوی
+۱۹۹۸
+مردم
+نشان
+موسیقی
+ویکی‌مدیا
+همراه
+ویکی‌گفتاورد
+تپه
+شورای
+دانشنامه
+ویکی‌واژه
+بدون
+مانند
+راه
+شهرهای
+فرهنگی
+سیاره
+ویکی‌نبشته
+ترجمه
+فراویکی
+حجم
+کنونی
+طبق
+ژانویهٔ
+بار
+اجرام
+روستای
+ویکی‌نَسک
+تغییر
+خوشامد
+سرعت
+۲۰۱۲،
+جنگ
+برابر
+محل
+سر
+سپس
+سیارک‌ها
+عربی
+بازیابی
+داشت
+بازی
+ماه
+می‌تواند
+رو
+کنید،
+ژانویه
+معرفی
+بنا
+مشترک
+چندین
+دوران
+ندارد
+جهان
+حقوق
+کنم
+بالا
+ضمن
+داد
+وبگاه
+البته
+آب
+قدیمی
+امکان
+جمهوری
+قسمت
+۰۹
+مفیدند
+پیدا
+وپ
+پروژه
+بن
+همکاری
+۰۸
+تغییرات
+كه
+منطقه
+معماری
+چم‌وخم
+معرفی‌شده
+کنند
+هزار
+عرض‌جغرافیایی
+طول‌جغرافیایی
+۰۷
+روی‌نقشه
+برخی
+آی‌پی
+آمار
+ویکی‌پدیای
+۲۰۱۰
+جای
+موضوع
+تمام
+گرفته
+شرقی
+فوریهٔ
+اخیر
+قمری
+متوسط
+دیگری
+غربی
+درگاه
+ربات
+راستی
+اولین
+۳۱
+باستانی
+امنیت
+چنین
+آلمان
+کم
+رسمی
+جهانی
+مطالعه
+بررسی
+ژوئیه
+فعالیت
+آغاز
+آذربایجان
+فکر
+اين
+الگوی
+تیم
+لطفا
+ژوئیهٔ
+صنایع
+درود
+نامه
+تلفن
+اقدام
+روستا
+ایشان
+می‌کنند
+فارس
+حتی
+تعداد
+دربارهٔ
+فعلی
+درست
+مدیران
+گفتگو
+حجت
+دستی
+ستاره
+بسیاری
+اند
+نقش
+کلیک
+بودند
+۰۶
+تولد
+کردم
+زادگان
+شاه
+متحده
+توضیح
+طول
+دوست
+ذکر
+رسیده
+مقاله‌ای
+قابل
+اضافه
+مسائل
+ایالات
+همهٔ
+اینترنتی
+نام‌گذاری
+سیاسی
+طور
+خیلی
+رضا
+روستاهای
+چپ‌چین
+تولید
+صفحه‌های
+برچسب
+خانه
+شکل
+دولت
+می‌توان
+شامل
+می‌نویسید
+یادتان
+موسسه
+جنوب
+نرود
+نشریه
+باشند
+۰۰
+آمد
+وارد
+فرانسه
+جوایز
+مجموعه
+قانون
+به‌عنوان
+متن
+۰۵
+جایزه
+خبری
+سید
+ویکی‌خبر
+گفته
+اساس
+سیاست‌های
+جنوبی
+سایت
+آری
+ممکن
+نمی
+بنویسید
+روسیه
+فیلم‌های
+مهٔ
+سوم
+تشکر
+جام
+۱۳۸۵
+حدود
+کامل
+عرض
+شمارهٔ
+قاجار
+ماني
+عکس
+اجازه
+تصحیح
+آرش
+علوم
+نظری
+جای‌های
+اشاره
+دانشنامهٔ
+گرفت
+کردند
+جان
+فرهنگی،
+مختلف
+بانی
+توضیحات
+ارتفاع
+موارد
+میلاد
+مثل
+مرمت
+ژورنال
+شعر
+محتوای
+بیش
+چرا
+شمال
+خواهر
+می‌کنم
+خم
+فصل
+شروع
+تشکیل
+چم
+سرشماری
+دهه
+مشکل
+ساخته
+زبان‌ها
+گونه‌های
+مدت
+مجموعه‌ای
+زیادی
+بهترین
+درباره
+موافق
+دیرینگی
+نتیجه
+هست
+آلبوم
+ادامه
+جهت
+خراسان
+شرح
+ایران‌شهر
+زیستی
+پیشرفته
+می‌دهد
+راهنماهای
+صفحه‌ی
+افغانستان
+هماهنگی
+قلعه
+اصفهان
+بالای
+جغرافیایی
+شخصی
+نسبت
+می‌شوند
+تصنيف
+مطرح
+عناوین
+بوده‌است
+۰۱
+۱۳۸۶
+زمین
+سازی
+حزب
+سی
+آن‌ها
+سرشناسی
+انقلاب
+مي
+واژه‌ها
+مهم
+سایر
+می‌آید،
+دکتر
+مساحت
+قطعنامه
+۰۴
+شدند
+مرد
+درگذشتگان
+پرونده‌های
+باعث
+نکاتی
+اعلام
+نامگذاری
+پروژه‌ای
+زبانه
+سیستم
+انتفاعی
+یادداشتی
+کتابچه
+پرسیدن
+۰۳
+چندرسانه‌ای
+قول‌ها
+هرکسی،
+ویکی‌گونه
+خوانندگانش
+کیلومتر
+سطح
+زمینه
+اهالی
+سؤال،
+حسین
+اصطلاح‌نامه
+موقت
+سندباد
+بود،
+تبدیل
+سبک
+بنویسیم؟
+روش
+میثم
+زمانی
+۱۳۸۷
+دسترسی
+کد
+انگلستان
+برنامه
+رنگ
+تحت
+هاروارد
+مدیر
+امیروبات
+جرم
+جلد
+وقتی
+گودال
+نگاره
+شمالی
+۰۲
+پاسخ
+آیا
+تر
+منتشر
+شوند
+انتشارات
+مخالف
+مسجد
+بایگانی
+هماهنگ‌کننده
+کپی
+متر
+مجلس
+۴۰
+دهید
+شاید
+آنجا
+گل
+کاربرهای
+ناسا
+دوستان
+جناب
+پیشنهاد
+ان
+دی
+یافت
+آسمانی
+۱۳۸۸
+هنوز
+نخستین
+مذهب
+نویسندگان
+زنده
+ایالت
+ماسه‌بازی
+احمد
+آنهاست
+کنار
+شبکه
+بازی‌های
+مشخص
+ژاپن
+نمود
+وقت
+کشورهای
+خواندن
+معروف
+اروپا
+اشتباه
+کرمان
+سن
+معرف
+پهلوی
+درجه
+سوی
+ام
+محیط
+بحثتان
+روزنامه
+گونه
+۱۹۹۷
+طرف
+کل
+داستان
+علت
+الگوهای
+آمریکایی
+تو
+آمده
+بین‌المللی
+داتک
+امیر
+انتشار
+قوانین
+شماره‌دار
+دادگان
+موفق
+رشته
+خاطر
+دارم
+خورشیدی
+حسن
+معنی
+زنان
+انتقال
+پی
+حکومت
+لازم
+به‌آفرید
+تپه‌های
+نام‌صفحه
+شابک
+زن
+قرن
+دهد
+عمل
+بازیگر
+تصاویر
+رئیس
+ممنون
+عزیز
+یاد
+گفت
+هفته
+دین
+رای
+وضعیت
+فرار
+درخواست
+سیاست
+سمت
+حالت
+پسر
+کوه
+پرچم
+طی
+ادبیات
+الله
+کلی
+کشف‌شده
+بازیابی‌شده
+غرب
+فرودگاه
+۱۳۹۰
+سپاس
+واژه
+توابع
+ابعاد
+کمربند
+دور
+مدرک
+مبدا
+مازندران
+کننده
+مدیریت
+دوستدار
+وجه
+مهدی
+نمایش
+هجری
+هنر
+ابتدا
+ده
+رسید
+اعضای
+انسان
+امام
+مثال
+دادن
+آخرین
+اسرائیل
+قول
+نمایید
+حضور
+رود
+خودتان
+زیاد
+جا
+توصیه
+مناطق
+عراق
+مطلب
+پرسش
+خان
+عضو
+حسام
+حداقل
+باستان
+ارائه
+۵۰
+مواد
+کمی
+خارج
+دما
+چین
+وزارت
+اوج
+خروج
+طبیعی
+پزشکی
+ستاره‌شناسی
+فراموش
+پایین
+کاری
+اکنون
+بعضی
+میانگین
+نشده
+هزاره
+نشر
+مهندسی
+شد،
+آباد
+خودم
+اسپانیا
+خاص
+دوران‌های
+۱۳۸۹
+جریان
+منظور
+طریق
+ترتیب
+بناهای
+بیان
+دارید
+روستایی
+سطحی
+شیخ
+نسخه
+حرکت
+بنده
+سده
+اجتماعی
+طراحی
+حرف
+خودروهای
+ویکی‌گزارش
+نو
+هند
+استاد
+به‌شما
+دوباره
+توان
+نظامی
+بلکه
+سری
+همسر
+هنری
+شیراز
+مفیدی
+جمع
+علم
+خانواده
+انتخابات
+آلمانی
+فاصله
+نیروی
+مرتبط
+نمونه
+پدیا
+فرمایید؛
+شناخته
+چگالی
+دیده
+معتبر
+مناسب
+قرآن
+میلیون
+واحد
+۴۵
+مهر
+تبریز
+هنگام
+گسترش
+طبقه‌بندی
+۱۹۹۶
+فلسفه
+کرمانشاه
+گردید
+گذشته
+دنیا
+زیرا
+قدرت
+مثلا
+ببینید
+لیگ
+دریافت
+انحراف
+نام‌رسمی
+می‌آید
+حمله
+گرانش
+توسعه
+افزایش
+چشم
+مکان
+عدد
+ابهام‌زدایی
+دانش
+موضوعی
+نزدیک
+شخص
+آنان
+دیگران
+بازیکنان
+آقای
+کاشف
+تلویزیونی
+زاده
+بسته
+جایی
+خدا
+حاضر
+شرق
+می‌شد
+حساب
+پدر
+داشتید
+نقض
+پیش‌شماره
+ایتالیا
+کاربرد
+سعی
+رفت
+برد
+‌بودن
+کاربردها
+تناوب
+۳۵
+معمولاً
+زبان‌های
+بهمن
+۳۲
+عباس
+حضیض
+پدیدآور
+انجمن
+فیزیک
+نگاه
+فعال
+نور
+نسخه‌ها
+ریاست
+هستم
+فلکی
+فرد
+مسیر
+اجازه‌نامه
+جامعه
+آلبدو
+مصر
+آنومالی
+کلمه
+نیم‌محور
+بریتانیا
+۱۹۹۵
+پر
+پاک
+۱۹۹۳
+بازیگران
+بخشی
+فرانسوی
+داخلی
+خبر
+سئوال
+محمود
+باشد،
+امروز
+کرده‌است
+ارتباط
+درصد
+تاریخچه
+ملل
+اصلاح
+معیارهای
+همچون
+طرح
+شده‌اند
+هدف
+عالی
+وقایع
+میدان
+محسوب
+حل
+باغ
+استان‌های
+خودش
+قطع
+ایران،
+۳۳
+۳۴
+اش
+دنبال
+شهری
+تعریف
+دانشکده
+انواع
+دار
+ورزشگاه
+نقشه
+کوتاه
+شمار
+مدرسه
+کمتر
+آرامگاه
+عصر
+عبارت
+بیست
+تن
+خرابکاری
+المپیک
+تیر
+می‌رود
+خیابان
+بازار
+نامزد
+میرزا
+داخل
+اندازه‌تصویر
+پایگاه
+رضوی
+سؤال
+۱۹۹۰
+الان
+گرامی
+نبود
+خوبی
+۳۷
+خارجی
+گیری
+آورد
+برچسب‌تصویر
+۴۸
+سیستان
+۱۹۹۴
+آزادی
+رشد
+نباید
+پرسشی
+۱۳۸۴
+حد
+۳۶
+ملیت
+رشدجمعیت
+تازه
+میانگین‌دما
+عدم
+نیروهای
+تراکم‌جمعیت
+سؤالی
+نام‌های‌قدیمی
+بنابراین
+ارتش
+شب
+داشتن
+علاوه
+ابن
+شمارروزهای‌یخبندان
+میانگین‌بارش‌سالانه
+پل
+تصویب
+میانه
+خرداد
+گیلان
+سنگ
+کنترل
+بهزاد
+کیفیت
+می‌‌نویسید
+۴۱
+درگذشت
+علیه
+گزارش
+شیعه
+خور
+۳۸
+جزیره
+ره‌آورد
+دسترس
+دستگاه
+نام‌محلی
+تگزاس
+جز
+همیشه
+۴۲
+اجرا
+کوشش
+پخش
+رد
+۴۶
+متحد
+اسفند
+وزیر
+خواننده
+بهبود
+اثبات
+سفید
+نظرخواهی
+شرایط
+جمله‌خوشامد
+ترکیه
+۴۴
+همدان
+قم
+۳۹
+می‌گیرد
+۴۳
+بلوچستان
+چیز
+دسته
+خوزستان
+گنو
+ترانه
+کدام
+خودرو
+۵۵
+۴۷
+باقی
+بندی
+۵۱
+بخوانید
+۱۹۹۲
+خواهند
+صد
+ناحیه
+۵۳
+کاهش
+۱۹۹۱
+میشود
+مذهبی
+۴۹
+ساختمان
+اولیه
+مقابل
+۵۲
+سبز
+وحید
+۵۷
+مشهور
+متوجه
+تهیه
+کافی
+آنچه
+ترک
+افزودن
+می‌شود،
+جدا
+۱۳۸۲
+چهارم
+تقسیم
+نژاد
+معنای
+کشاورزی
+صفوی
+براساس
+سیاه
+هایی
+آسیا
+تمامی
+تحقیق
+۱۹۶۰
+ساسانیان
+نوشتار
+رادیو
+۵۶
+۵۴
+اسم
+ارزش
+دهانه
+اقتصادی
+ابراهیم
+نخست
+فرزندان
+۵۹
+هاي
+شهرها
+دقیقه
+حالا
+دستور
+امور
+رابطه
+پارک
+جنبش
+دختر
+قالب
+بیماری
+نام‌های‌دیگر
+محوطه
+بازیکن
+کشته
+دارد،
+مشهد
+منتقل
+شهریور
+مرداد
+کیلومتری
+پرداخت
+۵۸
+تخصصی
+۲۰۱۲
+مرده
+دهیار
+صنعتی
+خدمت
+پشت
+فشار
+می‌کرد
+تلاش
+مدیاویکی
+تلویزیون
+میزان
+سال‌بنیاد
+قبلی
+انرژی
+بدست
+نظام
+حوزه
+پا
+بودم
+یزد
+هفت
+ازدواج
+است؟
+فضای
+نظریه
+اختلاف
+حمایت
+خواهم
+مجله
+رفته
+اجرای
+می‌گردد
+برتر
+متولد
+کره
+خاک
+برگزار
+سرزمین
+بدن
+کرده‌اید
+مسابقات
+اقتصاد
+ندارم
+بعدی
+قبول
+خلیج
+آخر
+کمیته
+فروردین
+مادر
+کارگردان
+می‌کنید
+سال‌ها
+کسانی
+مصرف
+جدول
+جشنواره
+آنرا
+دید
+فرزند
+عرب
+کاملا
+آمل
+پادشاه
+دیدگاه
+آذر
+اشکانیان
+سفر
+متفاوت
+وزن
+نیویورک
+داشتند
+بیشتری
+موزه
+یه
+می‌رسد
+خاصی
+دل
+دهستان‌های
+آنکه
+استقلال
+پنهان
+مجوز
+نوعی
+کردید
+لرستان
+جغرافیا
+ترکی
+محسن
+هوایی
+۱۹۸۱
+فروش
+مقام
+مقدار
+۱۶۱۵
+قزوین
+حالی
+عمر
+لزوم
+میل
+آبی
+دقت
+اصلا
+اطلاع
+رخ
+شکست
+اعمال
+اینترنت
+موتور
+دومین
+شهید
+تحقیقات
+تاسیس
+برخورد
+روم
+ماده
+محله
+لینک
+راست
+امروزه
+کرده‌اند
+بازگشت
+جواب
+پارس
+یونان
+رتبه
+شده،
+۱۳۸۱
+اساسی
+نقطه
+گردد
+موجب
+سخن
+تقویم
+نکته
+می‌دهند
+مستقل
+جامع
+اردیبهشت
+هستید
+سینما
+مدل
+کانادا
+گاه
+آورده
+حفظ
+ثابت
+احترام
+بوشهر
+مربع
+۱۹۸۸
+روابط
+سیمرغ
+درون
+زیرنویس
+کن
+نظرم
+ترکیب
+بهار
+بد
+پادشاهی
+دلار
+شیمی
+تعیین
+بابل
+نفت
+دولتی
+مدتی
+نظرات
+درستش
+کاتالوگ
+گاهشماری
+لحاظ
+ساده
+بخش‌های
+شوروی
+باب
+بی‌بی‌سی
+گرفتن
+دادم
+مثلاً
+گروه‌های
+ندارند
+کردستان
+حاصل
+شود،
+انسانی
+گرم
+روشن
+مسکن
+خون
+۱۳۸۰
+رسیدگی
+مفهوم
+خمینی
+گیاهان
+ساز
+آهنگ
+ترین
+هرمزگان
+۱۹۸۹
+صاحب
+کارهای
+اغلب
+عبدالله
+مشغول
+۱۰۰
+شناسی
+محمديان
+گفتم
+مختصات
+دهند
+یونانی
+رایانه‌ای
+یکم
+ستارگان
+کتاب‌های
+ایرانیان
+آوردن
+صنعت
+کند،
+صحبت
+فناوری
+نمی‌شود
+آینده
+واگردانی
+کتابخانه
+برجسته
+امر
+نقد
+مخصوص
+بزرگی
+آبان
+نتایج
+براي
+یافته
+لقب
+متاسفانه
+مالکیت
+مشاهده
+عرضه
+کارت
+گاهی
+شش
+دفاع
+مایکل
+اداره
+خبرگزاری
+دره
+مسئله
+صحیح
+ولایت
+گروهی
+رودخانه
+مقدس
+مراسم
+کشورها
+باد
+تاکنون
+خلاف
+علاقه
+ارومیه
+مرحله
+ورود
+۲۰۰۷،
+تکمیل
+موقعیت
+رویدادها
+تفاوت
+ایستگاه
+شیمیایی
+مگر
+ضد
+ژاپنی
+استاندارد
+دریای
+۱۹۸۰
+معاصر
+زندان
+غیرقابل
+عملیات
+دریایی
+خصوص
+برخوردار
+لندن
+شیوه
+آقا
+مشابه
+سخت
+خلاصه
+دفتر
+برنده
+سنت
+پاپ
+جلوگیری
+قدیم
+ورودی
+اسکار
+بطور
+چر
+بندر
+مرا
+راک
+نیشابور
+نیستند
+۱۵۱
+مشکلی
+آتش
+کشوری
+تابستانی
+امپراتوری
+بررسی‌های
+آن،
+اس
+میکنم
+پارسی
+تشخیص
+شاعر
+خدمات
+عهده
+نیمه
+مشکلات
+نیست،
+آشنایی
+بصورت
+تأسیس
+درمان
+ابزار
+آموزشی
+نوروز
+بروجرد
+تواند
+قتل
+تحصیل
+دیدم
+مدرس
+دانشگاه‌های
+جمهور
+محدود
+برج
+آبشار
+دانشجویان
+احتمال
+رفتار
+اعتماد
+اطراف
+هشدار
+همواره
+قطعنامه‌های
+محمدرضا
+پاریس
+ساله
+کالیفرنیا
+وسیله
+اصول
+درخت
+سالگی
+۱۹۷۷
+پیشه
+داریم
+شخصیت
+قصد
+نداشته
+می‌گوید
+جشن
+ویرایش‌های
+ادبی
+بهره
+سنتی
+فوق
+کنید؛
+تام
+بانک
+دهم
+استرالیا
+دقیق
+نامیده
+نفوس
+فراهم
+می‌توانند
+بدین
+اختیار
+چشمه
+دادند
+يا
+اردبیل
+پست
+خانوار
+قهرمانی
+منصور
+سرخ
+روسی
+۱۳۸۳
+شبیه
+بشر
+قرمز
+قطر
+سبب
+کشتی
+برده
+صدا
+یکسان
+شمسی
+مجدد
+اکثر
+جالب
+تک
+گلستان
+پنجم
+فراوان
+يك
+نرم‌افزار
+توهین
+اتحادیه
+عشق
+ظهیری
+گورستان
+بلژیک
+بکار
+رستم
+سرشناس
+‌ها
+هیئت
+علیا
+مقالاتی
+رباتیکی
+هنگامی
+لطف
+بختیاری
+روح
+ارجاع
+تقریبا
+۱۹۷۳
+سپاه
+‌های
+یکدیگر
+نموده
+رمان
+کرد،
+جنسی
+بزرگترین
+پیشرفت
+دعوت
+بقیه
+کلمات
+شهرت
+مرکزی،
+رایانه
+یمن
+تخت
+معادل
+صادق
+وسط
+خوانندگان
+تلفظ
+اتفاق
+امامزاده
+تحصیلات
+خانوادگی
+حقیقت
+خورشید
+نوری
+نقاط
+پایتخت
+بند
+گوگل
+مانده
+نزدیکی
+سعید
+امید
+نشود
+نر
+مسعود
+سلطان
+ادغام
+سفلی
+دریا
+لاتین
+اجماع
+خوانده
+سابق
+ریاضی
+درستی
+فضایی
+دلایل
+برندگان
+بعدها
+متعلق
+پیشین
+شدم
+هنرمند
+درس
+ذخیره
+کارگردانی
+نباشد
+دانقولا
+اون
+تابع
+مالی
+صدای
+بلند
+بارگذاری
+بخش‌ها
+اینگونه
+اواخر
+ریشه
+نشد
+کاخ
+ریز
+فرض
+قانونی
+برق
+جلوی
+کودکان
+نزد
+قاسم
+آهن
+زنجان
+نگارش
+شدت
+می‌گویند
+جایگزین
+جاده
+می‌کردند
+مفید
+زرشک
+لیست
+محور
+ویکیپدیا
+رایج
+مناسبت‌ها
+خلق
+مراکز
+ساری
+عامل
+نقاشی
+رسیدن
+کارشناسی
+۱۹۸۴
+زده
+رعایت
+انگلیس
+اطلاعاتی
+ورزشی
+مقایسه
+منبعی
+بازبینی
+حافظه
+حتما
+عربستان
+مستقیم
+گیرد
+الدین
+۱۹۸۲
+علیرضا
+تعدادی
+ورزش
+برادر
+گذاشته
+تهران،
+محصولات
+زندگینامه
+هوا
+۱۹۸۶
+۶۰
+کس
+پوشش
+حکم
+قهرمان
+خانه‌های
+حاج
+خواهش
+گردآفرید
+نوبل
+نرم
+رهبری
+خیر
+تجاری
+نوشت
+۱۹۸۵
+جوان
+واقعی
+نظیر
+سند
+سرانجام
+منجر
+اعداد
+فی
+واقعا
+نبرد
+مردان
+جغرافیای
+شدید
+روند
+ویرایشی
+دشت
+رده‌بندی
+پرحجم،
+گذاری
+افشار
+۱۹۷۸
+زدن
+سوئد
+خویش
+ماهی
+خالی
+درآمد
+آمریکای
+مسلمانان
+کجا
+می‌باشند
+طوری
+اید
+دکمهٔ
+احمدی
+درد
+۱۹۸۷
+شاعران
+گویا
+نداشت
+هـ
+سالهای
+ششم
+شیر
+دچار
+تاثیر
+زیست
+دینی
+سریال
+نماد
+راجع
+مطالعات
+مراجعه
+لحن
+خطر
+پرسپولیس
+حضرت
+مکتب
+دامنه
+بروید؛
+زیبا
+بافت
+مسلمان
+کامیار
+محافظت
+ناوبری
+نهایت
+کلیسای
+هشت
+تکرار
+پرورش
+توزیع
+معمولا
+وبلاگ
+طولانی
+تجربه
+ظاهر
+گسترده
+ممنوع
+پیروزی
+چهل
+گاز
+عکاسی
+کاملاً
+احساس
+همچنان
+تفسیر
+چک
+مترجم
+مشخصات
+اینها
+تایید
+۱۹۷۹
+توکیو
+ال
+سمنان
+۲۰۰
+رهبر
+بیت
+سومین
+خورده‌است
+پاکستان
+۹۰
+همانند
+فردی
+ملحق
+کامپیوتر
+سوریه
+پدرش
+اوایل
+پول
+سوره
+تقویم‌های
+آفریقا
+کتاب‌ها
+دنیای
+همانطور
+دودمان
+هدایت
+باره
+سلسله
+موسوی
+قضیه
+غیره
+صرف
+آید
+ايران
+پک
+طبقه
+حاکم
+داریوش
+گوناگون
+زهرا
+اسماعیل
+زمین‌لرزه
+اعتبار
+بعنوان
+مُروا
+توانست
+۱۳۷۹
+تدوین
+اهواز
+سبزوار
+جکسون
+نمایندگان
+مقاومت
+آی
+برداشت
+گشت
+قلم
+تنظیم
+نگاری
+هلند
+باور
+نهاد
+سینمای
+تمدن
+فرهنگستان
+کردی
+ویندوز
+سوئیس
+کانی
+نویسی
+ممتنع
+مانی
+پشتیبانی
+جو
+رده‌ها
+ساکن
+شهرک
+روزی
+صحنه
+اصطلاح
+تئاتر
+جستجو
+جلو
+فردا
+جیمز
+کی
+هرگز
+چیست؟
+حمل
+توصیف
+گیتار
+ری
+والدین
+۱۹۷۶
+حفاظت
+رشت
+سابقه
+کودک
+کنون
+فعالیت‌های
+عوض
+اعتراض
+نسل
+دریاچه
+مرز
+باشگاه‌های
+کهگیلویه
+میکند
+دادگاه
+تصویری
+خانم
+مخالفت
+نصب
+آل
+افرادی
+چاه
+نماینده
+نگه
+عملکرد
+جدیدی
+۱۹۷۰
+مهمترین
+آمده‌است
+محمدعلی
+بدهید
+اتحاد
+شرکت‌های
+موج
+رم
+کشیده
+تحلیل
+نظارت
+تابلوی
+شهرداری
+محصول
+متعدد
+نماید
+قوم
+مصطفی
+جزایر
+گرمی
+عقب
+صلح
+شعار
+ارسال
+جی
+نوشته‌های
+غلط
+۱۹۷۱
+سازنده
+نکرده
+مواردی
+جوانان
+حمام
+دورهٔ
+تبریک
+بگذارید
+دانشگاهی
+مس
+ماند
+خداوند
+مهاجرت
+ضبط
+ست
+احتمالا
+لبنان
+دوربین
+خودشان
+عبور
+ارشد
+بنام
+فرمان
+عبارتند
+مطابق
+خرم‌آباد
+بالاتر
+سد
+تقریباً
+اکبر
+دیدن
+موفقیت
+مدرن
+نگهداری
+۷۰
+عوامل
+پای
+جایگاه
+۸۰
+زادروز
+پرواز
+خلیفه
+هفتم
+ماشین
+هرچند
+هسته‌ای
+عناصر
+اسناد
+گنبد
+لا
+نهایی
+تدریس
+طلایی
+زابل
+چندان
+اروپایی
+ظاهری
+صفر
+اول،
+اشعار
+دبیرستان
+معلوم
+برنامه‌های
+نخواهد
+زد
+بیفزایید
+خصوصی
+وظیفه
+ادعا
+عزیزی
+عمده
+انتظار
+آن‌لاین
+قبلا
+مبارزه
+هستند،
+خسته
+فرصت
+رفتن
+مشارکت‌ها
+گرامی،
+سراسر
+۱۹۸۳
+پیروز
+گویش
+رفع
+جزو
+گفتاورد
+متال
+مکزیک
+۱۳۵۷
+امپراتور
+اطلس
+اسپانیایی
+پنجاه
+شاپا
+بیمارستان
+پیامبر
+بستک
+می‌کنیم
+اشکال
+تقسیمات
+الکتریکی
+درک
+سلطنت
+لباس
+دهنده
+نشست
+اعدام
+اقوام
+شاخه
+سلام،
+الگوریتم
+چپچین
+شان
+خواست
+مدال
+امارات
+جبهه
+باشم
+مطبوعات
+مستعار
+نیازی
+عادی
+چینی
+افتخار
+کهن
+نا
+مثبت
+شخصیت‌های
+خطوط
+ویلیام
+سلطنتی
+منطقی
+اطمینان
+جعفر
+سقوط
+روزهای
+گرفته‌است
+طبیعت
+باشیم
+رده‌های
+ترتیب‌پیش‌فرض
+شبه
+موافقم
+یهودیان
+تربیت
+دیوید
+معاون
+پرندگان
+ملت
+دیوان
+تی
+پلیس
+ملک
+نيز
+هنرمندان
+عین
+تماس
+حرفه‌ای
+آستانه
+بماند
+واکنش
+زحمت
+عمان
+حافظ
+نیم
+منفی
+آسیای
+تابستان
+جدی
+قابلیت
+ساختن
+آسیایی
+رجوع
+شهرستان‌های
+معین
+نیستم
+ناشی
+تهیه‌کننده
+داشته‌است
+دانشمندان
+صبح
+اعتقاد
+مبارک
+سورنا
+اساطیر
+اصلاً
+تذکر
+خطی
+کاربردی
+داشتم
+آدم
+کتابی
+مختلفی
+کاربرانی
+سرباز
+جذب
+متغیر
+وضع
+روزبه
+مجازی
+گذاشت
+بابت
+اعلانات
+مهمی
+فلان
+آماده
+مصاحبه
+باتجربه‌تر
+رقص
+کلاسیک
+گیاه
+سامانه
+مجبور
+نحوه
+نبوده
+نفوذ
+متری
+کانال
+حیات
+گفتمان
+جلسه
+ارادتمند
+درفش
+حومه
+تصور
+خاندان
+بهرام
+لحظه
+برزیل
+یهودی
+دهخدا
+ایتالیایی
+رسانه
+۱۹۷۵
+مسابقه
+خواستم
+کابل
+نی
+اوکراین
+موسی
+شما،
+بگیرد
+زرد
+هوای
+فلسطین
+اهداف
+است؛
+ولسوالی
+غار
+بنای
+نوشتارهای
+مربوطه
+اخبار
+بودند،
+مهم‌ترین
+سینمایی
+پیمان
+۸۸
+همزمان
+ها،
+احتمالاً
+آسمان
+شهرک‌های
+ابتدای
+ندهید
+بوجود
+آیدا
+جانوران
+سده‌های
+بازداشت
+هسته
+یادداشت
+ایلام
+نامی
+مجموع
+هنرهای
+می‌دانند
+ادعای
+سرویس
+بگویم
+ظهور
+هزینه
+کاویانی
+الگوها
+ضروری
+آرام
+حذفی
+اقیانوس
+یی
+امتیاز
+زمینی
+آدرس
+باشه
+امکانات
+بیشترین
+طراح
+نواحی
+مطالبی
+مقالات،
+بخاطر
+لی
+آفتاب
+بفرمایید
+دقیقا
+هشتم
+توانایی
+آیت‌الله
+مسیحیت
+تبلیغات
+محوطه‌های
+بارها
+ته
+سنچولی
+يک
+الف
+متصل
+ساسانی
+بویراحمد
+سروش
+نظرتان
+ربطی
+روایت
+بروز
+دیگه
+پژوهشی
+زبانی
+۱۳۷۸
+ثانیه
+برگزاری
+تبلیغ
+شاهنامه
+نزاکت
+قوی
+خواجه
+پوست
+پژوهش
+شروین
+سنی
+میباشد
+سرد
+بگویید
+شکایت
+بنی
+صدر
+مطلبی
+اسید
+کلید
+خسرو
+گذشت
+طلا
+شیرازی
+اي
+شناسایی
+تأثیر
+شیرین
+می‌کند،
+رأی
+فردوسی
+اگرچه
+چهارمین
+نمی‌کند
+زاپاس
+خشک
+جنگی
+برداری
+قادر
+بومی
+بنابر
+ديگر
+تقدیم
+حاشیه
+نگاره‌های
+۱۹۷۲
+اختصاص
+یونایتد
+بردن
+اندیشه
+حتماً
+بودجه
+داشت،
+افزوده
+۱۹۷۴
+بیرجند
+عضویت
+مستند
+بحثی
+الکترونیک
+امروزی
+بیرونی
+فتح
+معمول
+واژگان
+ادب
+نمی‌توان
+مرتضی
+اتصال
+مخالفان
+گویند
+ناقص
+سفارت
+۱۳۷۷
+المللی
+قسمتی
+چنان
+مدفن
+فضا
+گرچه
+ويکيپديا
+آمدن
+زیبایی
+نوشتم
+عهد
+رای‌گیری
+سرمایه
+نامعلوم
+ردیف
+تجارت
+نیک
+ایل
+یافتن
+اظهار
+گرد
+مایل
+اعراب
+قیمت
+چی
+مقدمه
+خرید
+عمق
+گمان
+هری
+معتقد
+داده‌است
+یوسف
+مردتنها
+بزرگ‌ترین
+فراوانی
+مرور
+جزء
+ناصر
+موشک
+رومانی
+دانست
+نادرست
+خود،
+فایل
+تلقی
+مشاهیر
+بوده‌اند
+آواز
+ضمنا
+بشود
+عثمانی
+مبنای
+قلب
+گوش
+جمعه
+آیت
+ویرایشات
+هاشمی
+دارند،
+استادان
+فرق
+همگی
+پرتغال
+ذهن
+پیر
+زیست‌شناسی
+پرنده
+بتواند
+ارمنستان
+اتریش
+اندکی
+آیین
+اتاق
+قطعه
+شناخت
+تغییری
+۱۹۶۸
+عبری
+معیار
+هفتاد
+روش‌های
+نکردن
+فاقد
+آیه
+دم
+عید
+مکانیک
+تک‌آهنگ
+نوبت
+دیوار
+گشتن
+درمانی
+مطمئن
+نصف‌النهار
+جنس
+تیره
+منظومه
+بایستی
+ریاضیات
+مهندس
+رییس
+بارگذار
+هواپیما
+میشه
+آرژانتین
+کلا
+کریم
+شاهد
+گر
+سنگی
+مسئول
+نشانه
+فیلمبرداری
+نوکیا
+جمشید
+تغییراتی
+کتب
+کرج
+استناد
+شریف
+ایرلند
+اف
+نسخهٔ
+چهره
+نوید
+کنگره
+منچستر
+رابرت
+نباشید
+پرویز
+مى
+نماز
+کمال
+گونه‌ای
+ژان
+دلیلی
+داری
+عالم
+اسب
+حمید
+قرارداد
+پیشینه
+قره
+خروجی
+کمونیست
+قاسمیان
+می‌گیرند
+شصت
+زمستان
+کلمبیا
+راهی
+محدوده
+نام‌ها
+میر
+لینوکس
+میلادی،
+بهداشت
+اگه
+سدهٔ
+۵۰۰
+بجای
+مغز
+پوستر
+حاوی
+لغت
+رسانی
+لوگو
+مسیح
+فرزاد
+فرمول
+مؤسسه
+مفصل
+پدید
+درام
+اردشیر
+آفریقای
+خرابکار
+تامین
+داره
+اتمی
+بزرگان
+محکوم
+نجات
+یادبودهای
+ریچارد
+رومی
+مدار
+تخریب
+بدانید
+درگیری
+بیستم
+افتاد
+محترم
+خودروها
+نوین
+مطابقت
+تاجیکستان
+نقش‌های
+افزار
+مراجع
+اتومبیل‌های
+عزیز،
+ضعیف
+امضاء
+بیگانه
+فرا
+اکثریت
+هرات
+می‌یابد
+پنجمین
+میکنند
+کنندگان
+فعلا
+۸۵
+نکات
+ارتباطات
+خواهید
+مجمع
+کنی
+یابد
+منطق
+دیدار
+دویست
+دوستانه
+آوری
+آلبوم‌های
+اتهام
+بینی
+مسیحی
+گری
+آنلاین
+ویژگی
+ادوارد
+امنیتی
+برایتان
+كرد
+دیگر،
+عام
+اصرار
+بودید
+تبلیغاتی
+حاجی
+هرچه
+۱۹۶۴
+انتقاد
+برسد
+شک
+توانید
+ویژگی‌های
+خوی
+۶۴
+زادگاه
+مساله
+فیزیکی
+هخامنشی
+غذایی
+نمی‌دانم
+سامسونگ
+گرفتند
+تاج
+موقع
+۱۹۶۹
+فاطمه
+سخنرانی
+سختی
+استدلال
+۱۳۷۶
+شهردار
+ار
+سلیمان
+متهم
+مذکور
+عملی
+چندی
+پدیای
+صادر
+منتظر
+ضرب
+تیم‌های
+تل
+حسینی
+گیر
+سراب
+تیرداد
+ویکی‌سازی
+تان
+مشروطه
+کوچکی
+مردمان
+ویکی‌پدیا،
+مجاز
+محاسبه
+بزنید
+جنگل
+مجموعه‌های
+واقعیت
+سان
+قومی
+صفحه‌ها
+قطب
+تالار
+خواب
+تاکید
+گاه‌شماری
+امین
+لذا
+آسیب
+هیات
+قد
+میلیارد
+کوچولو
+برقرار
+بالایی
+شیعیان
+قاضی
+برگرفته
+عنصر
+معانی
+ارتباطی
+شبکه‌های
+درود،
+۳۰۰
+مراحل
+لهستان
+معمولی
+نوار
+محس
+۸۹
+قبیل
+سیر
+دهیم
+شاخص
+عیسی
+ترور
+دمای
+تکامل
+کبیر
+درگیر
+سونی
+یاری
+۱۹۵۰
+آگاهی
+نیوز
+پیوست
+رچ
+خدای
+کودکی
+مرتب
+رژیم
+روبات
+ابتدایی
+میتوان
+هشتاد
+زادهٔ
+کشت
+بازسازی
+وسایل
+بتوان
+مجارستان
+پیاده
+میان‌ویکی
+فرمانده
+۸۷
+تهدید
+ویک
+محرم
+نهم
+احمدی‌نژاد
+۶۵
+خورد
+رسول
+تمیزکاری
+بندانگشتی
+گیاهی
+سیاست‌ها
+این‌که
+کلیه
+بهشت
+هندی
+مشکوک
+فکری
+عقیده
+اشغال
+نویس
+ستون
+خارجه
+۱۳۸۶،
+۸۶
+نمی‌گیرد
+کارخانه
+دانشجو
+پیوسته
+خاطرات
+پادشاهان
+۱۹۶۷
+غذا
+زرتشت
+سود
+خوشحال
+رساند
+آر
+فیلمی
+می‌پردازد
+تری
+لایه
+سپهرنوش
+ظاهرا
+مصدق
+کویت
+مال
+احداث
+کانون
+مد
+فرماندهی
+مرحوم
+مواجه
+۱۳۹۰،
+بايد
+افتاده
+دوم،
+گردیده
+کارل
+وگرنه
+ندارد،
+ترجمهٔ
+ساحل
+جم
+طرفی
+نگهدار
+شرط
+روان
+آبتین
+جوانبخت
+سازهای
+الکترونیکی
+پور
+نود
+جمعی
+راحتی
+حیوانات
+داروهای
+دستگیر
+بابک
+حداکثر
+دانش‌آموختگان
+حلقه
+راستای
+اراک
+نادر
+اثری
+زبانهای
+برندارید
+رشته‌های
+بستن
+برگردان
+آبشارها
+ریزی
+مراغه
+دروازه
+پذیرش
+نمایی
+مدیریتی
+منصفانه
+واژهٔ
+جانب
+متعددی
+رسد
+گوید
+شغل
+زاهدان
+نمای
+رواج
+واضح
+عده‌ای
+می‌مانند
+ایوان
+چوب
+نکند
+فلسفی
+معنا
+نمی‌تواند
+خورده
+سو
+باند
+ماهواره
+مرغ
+دشمن
+کوه‌های
+سرطان
+دبی
+پرداخته
+ایکس
+آشکار
+کاشان
+بغداد
+ببخشید
+ششمین
+منظورم
+جلب
+دیر
+مـهـران
+زند
+مناسبی
+خانگی
+تجزیه
+بالغ
+می‌داند
+علامه
+جولای
+برگ
+سیستم‌های
+سیستم‌عامل
+کاوه
+۷۵
+دراپر
+مدارس
+ظاهراً
+رنگی
+دهه‌ها
+چیست
+تظاهرات
+مربی
+سازمان‌های
+برپایه
+متشکرم
+دوازده
+ایراد
+گیتاشناسی
+می‌برد
+اسامی
+او،
+دارد؟
+بورکینافاسو
+تجهیزات
+شاهزاده
+دربار
+دانم
+زاویه
+قاره
+رهبران
+سرود
+ابهام
+۱۳۷۵
+ایمیل
+پیغام
+فرآیند
+دالبا
+پستی
+ظرفیت
+بشه
+سیتی
+هستیم
+پرتاب
+کمدی
+توی
+فجر
+این‌جا
+گرگان
+می‌دانم
+جواد
+شاتل
+خطاب
+الهی
+گرایش
+ملا
+دانشمند
+فیلتر
+نسبی
+شوم
+داستان‌های
+نمایشگاه
+تربت
+ممنونم
+آگوست
+پایدار
+مشارکت‌هایتان
+منطقه‌ای
+تنگ
+مقیاس
+شریک
+جزئی
+هویت
+بدهد
+نوشتهٔ
+بابا
+ادیان
+۱۹۶۵
+جورج
+هفتمین
+تصرف
+آهنگساز
+پاورقی
+دلیلتان
+حس
+کوچه
+رقابت
+نمایند
+رها
+مقامات
+منطقهٔ
+قلعه‌های
+فن
+مادرش
+متخصص
+تکنولوژی
+سالی
+کیفیتی
+زمین‌شناسی
+می‌دهم
+مک
+کشتار
+سنگین
+می‌نویسد
+نکردم
+ید
+پرو
+بدان
+باران
+دخالت
+درختان
+جوانی
+آنگاه
+حسب
+حرفه
+سندی
+چگونگی
+تبار
+توافق
+کتابهای
+اطلاق
+نامناسب
+مایکروسافت
+۱۹۶۶
+ارشاد
+فردوس
+صوتی
+روزگار
+نمودند
+سگ
+دارو
+خاورمیانه
+معلم
+گره
+ون
+سوخت
+مترو
+آموخت
+نشده‌است
+شماست
+هتل
+حدیث
+نداریم
+پیدایش
+۱۳۷۰
+میانی
+کنند،
+عقاید
+پیچیده
+قهوه
+فرشته
+نحوهٔ
+عجیب
+جداگانه
+هشتمین
+جزئیات
+همشهری
+مبنی
+کاتولیک
+اصفهانی
+حملات
+جاری
+پویان
+انگلیسی،
+برخلاف
+نيست
+اشخاص
+مجید
+سیمای
+کانی‌های
+تغذیه
+مربیگری
+برنامه‌نویسی
+‌پدیا
+فدراسیون
+اجرایی
+سیصد
+احمدآباد
+می‌خواهید
+جنگ‌های
+پیگیری
+حوادث
+اخیراً
+دیجیتال
+تکیه
+مریم
+الی
+۱۹۴۸
+كند
+عده
+اقدامات
+شعاع
+تخیلی
+ماه‌های
+۶۶
+آزمایشی
+شده‌است،
+واژه‌های
+دشتی
+موافقت
+قهرمانان
+جلال
+اچ‌دی
+الفبای
+نفس
+پایانی
+پانصد
+برایش
+ترجیح
+خواند
+سلول
+عصبی
+کوخرد
+آب‌انبار
+۶۲
+مفاهیم
+شنبه
+بالاخره
+دانسته
+هواپیمای
+نهمین
+ایالتی
+مو
+فارغ
+پلی
+دروغ
+اداری
+استقبال
+مسئولیت
+داده‌اند
+فدرال
+ترانه‌های
+نوازندگان
+چای
+دههٔ
+تراکم
+فهرست‌های
+مردی
+زمرہ
+گورستان‌های
+سوالات
+عباسی
+سردار
+محک
+ترکیبی
+رقم
+سعودی
+نرم‌افزارهای
+بازرگانی
+برلین
+نروژ
+مارتین
+فوت
+دیدنی
+کنفرانس
+فارسی،
+اهر
+نجف
+پذیرفته
+اینست
+ملکه
+سرخط
+كرده
+زنی
+قلمرو
+بخصوص
+امی
+بهائی
+نقاش
+کازرون
+تار
+گرفته،
+نظم
+۷۲
+خودداری
+شمس
+صفحه‌ای
+بیمار
+واقعه
+هادی
+۸۴
+خاتمی
+بارسلونا
+سرچشمه
+زنز
+برچسب‌های
+منتخب
+بحرین
+واشنگتن
+پاتر
+کرده‌ام
+شاهین
+زرین
+مارک
+توپ
+وقوع
+حدی
+آذری
+شاگردان
+معبد
+آرمان
+۱۹۶۲
+بیماری‌های
+بچه
+فعالان
+کوروش
+دارویی
+اوقات
+اوست
+می‌کنند،
+قضاوت
+ین
+دست‌اول
+فریدون
+تئوری
+نمی‌توانید
+دوستی
+حقیقی
+زندانی
+مقطع
+راستش
+۱۹۶۳
+شاپور
+۱۹۵۶
+آکادمی
+بازنویسی
+ارمنی
+۱۹۶۱
+مهران
+مردمی
+ندارید
+گذاشتن
+کوتاهی
+فقه
+تنکابن
+درجه‌بندی
+ژنرال
+مایع
+طرفداران
+مدارک
+بدلیل
+پیشنهادی
+باشند،
+ذرات
+دانشجویی
+نگارخانه
+نیت
+کیلوگرم
+سردشت
+ایده
+تسلیم
+برادران
+هزاران
+حادثه
+مرتضا
+خواستار
+نهضت
+نرسی
+آمیز
+استودیو
+قدمت
+مجموعهٔ
+مغناطیسی
+قطعات
+عمران
+توجهی
+فیلم‌ها
+كار
+۶۳
+رسم
+درب
+مبتنی
+امواج
+تمایل
+احزاب
+روحانی
+اردن
+۶۱
+عمارت
+می‌دانید
+گفتار
+دزفول
+داوری
+کا
+حقوقی
+زمستانی
+فولاد
+امریکا
+مزرعه
+بوده،
+رساله
+رامین
+جراحی
+محقق
+ابزارهای
+ویکی‌
+پزشک
+قبلاً
+ضلع
+سرور
+مجاهدین
+اخلاق
+گراف
+مانع
+مشارکت‌کنندگان
+قشلاق
+نوازنده
+پرده
+۱۹۵۳
+شیروان
+کاظم
+اریکسون
+طیف
+مسکو
+۱۹۳۰
+۶۸
+مقابله
+لوله
+علی‌آباد
+واقعاً
+معدنی
+طباطبایی
+شاهان
+تاريخ
+ودر
+ماهان
+یوشیمیتسو
+۱۹۴۵
+نمونه‌هایی
+البرز
+چهارمحال
+مالزی
+۱۹۵۸
+خودرویی
+بیاورید
+آبادی
+مخابرات
+می‌دهید
+رودبار
+جور
+یحیی
+كتاب
+وین
+می‌داد
+غلامرضا
+طایفه
+سطر
+خواهیم
+جانشین
+اقامت
+توده
+مشارکت‌های
+برود
+جویا
+می‌روند
+نتیجهٔ
+اختیاری
+اساتید
+آگاه
+ساوه
+قدس
+ناخالص
+چرخ
+پردازش
+خرم
+به‌
+کاربردهای
+فیلسوفان
+طب
+زمانه
+وحدت
+افغان
+منوچهر
+طرز
+بوسیله
+مدیری
+اخذ
+اصلاحات
+فرهاد
+۱۳۷۳
+بایرن
+تور
+۸۲
+بست
+راحت
+تقلید
+لهجه
+قرون
+افسانه
+۶۷
+منزل
+۰۰۰
+رکوردز
+تأثیرات
+افتتاح
+بزرگتر
+هندوستان
+نقره
+بهشتی
+پذیر
+عظیم
+سیم
+خواص
+اعتراضات
+سخنان
+رزیدنت
+مسجدهای
+هرگونه
+می‌آورد
+این‌ها
+دقیقاً
+بسکتبال
+صوت
+بوئین
+۱۲۰
+۱۵۰
+شور
+زودی
+توانند
+سربازان
+رویداد
+خب
+بنیان
+چلسی
+زیبای
+شورش
+خامنه‌ای
+برایم
+درخواستی
+روان‌شناسی
+جسم
+ممنوعیت
+اهورا
+چقدر
+ابوالحسن
+سالن
+صحت
+می‌خواهد
+۹۶۴
+نرخ
+اختلال
+رویدادهای
+خراب
+تونی
+دایره
+دبیر
+۸۱
+۱۳۶۸
+دانشگاه‌ها
+تقویت
+زلزله
+دهانه‌های
+کوهستانی
+محض
+۱۹۵۴
+نبودن
+بين
+کارکنان
+جملات
+خاکستری
+دادید
+فرایند
+دارا
+وفيات
+چهارصد
+خصوصیات
+چارلز
+گفتند
+ستاد
+۱۰۰۰
+پیتر
+انگلیسی‌زبان
+مجتمع
+وسعت
+می‌شدند
+۱۳۷۴
+نیروگاه
+گذار
+قوچان
+تحصیلی
+دهی
+میلان
+نمی‌کنم
+فرم
+پستانداران
+گردن
+۱۳۷۲
+۱۹۴۰
+جناح
+شوشتر
+پذیری
+لیبی
+اسلامی،
+بحث‌های
+سوء
+همسرش
+قفل
+اسکندر
+تحلیلی
+تحمل
+فعلاً
+۱۳۵۴
+میوه
+مصنوعی
+ارزیابی
+روزانه
+مدعی
+دانمارک
+فرستاده
+شناسه
+صبر
+شطرنج
+گفتید
+وسیع
+گام
+گوشت
+کرده،
+رصد
+کوهدشت
+اینطور
+نوجوانی
+ملت‌های
+محمدی
+۶۹
+لشکر
+بزرگراه
+۱۹۵۲
+پاینده
+۴۰۰
+جانبی
+ایول
+تجدید
+نیست؟
+حامد
+نشریات
+توماس
+مجازات
+قیام
+گپ
+سینا
+۷۸
+بس
+وظایف
+کوهستان
+اینجاست
+میدهد
+کارها
+سالها
+یادبود
+آبادان
+طبس
+خوردن
+روزه
+مسکونی
+اعظم
+دموکرات
+خشونت
+۸۳
+هوشنگ
+تخصص
+سیما
+منظر
+علمیه
+سالم
+پیکسل
+کمکی
+خواسته
+ایرج
+مدنی
+گفتن
+آذربایجانی
+ره
+اتمام
+آلاباما
+۱۹۲۰
+ابی
+بام
+فقیه
+کیلومترمربع
+عوارض
+۱۳۵۰
+ترس
+بازگردانی
+سعدی
+موثر
+کلیبر
+انقلابی
+وبسایت
+روانی
+موردی
+دختران
+روس
+بم
+پاک‌کن
+داشته‌اند
+یوتی‌سی
+صدها
+پانویس‌ها
+نفتی
+ورزقان
+کمبود
+نابود
+فرانک
+دان
+۷۶
+جرج
+جدایی
+کیهان
+نامش
+تبریزی
+کتیبه
+حکومتی
+قسمت‌های
+صرفا
+۷۱
+اندازی
+قدم
+منحصر
+عموم
+پهنای
+پدیده
+روغن
+رسانه‌های
+اطلاعات،
+سایت‌ها
+اکران
+سلامت
+بالاترین
+پیروی
+۱۹۵۱
+مصداق
+۷۳
+شکار
+مباحث
+پوویا
+فاصلهٔ
+فاز
+۷۷
+حالیکه
+شهریار
+۱۹۵۷
+درخشان
+آن‌جا
+تنهایی
+نکرد
+عدالت
+می‌نماید
+مقبره
+سانسور
+داده‌ها
+شاهرود
+تخمین
+نشست‌های
+۱۹۳۶
+جین
+روبرو
+پس‌زمینه
+نیرو
+اخلاقی
+داستانی
+سینه
+شاهنشاهی
+مولانا
+گاو
+استخوان
+گرگ
+دکتری
+اند،
+کشف‌های
+سنندج
+۷۴
+ساحلی
+برهان
+پیش‌نمایش
+کردم،
+دوره‌های
+۱۳۵۶
+آغازین
+سالانه
+بستگی
+تخم
+۹۹
+سیگنال
+ویکی‌پروژهٔ
+ناقض
+خودمان
+کرد؟
+ویرایشگران
+داوران
+برداشته
+۱۳۷۱
+یکمین
+ریزشگاه
+سوار
+سلاح
+شایسته
+سفیدپر
+غزه
+ترکیبات
+لاله
+اولی
+گذر
+جک
+ذیل
+دراز
+۹۵
+پان
+درصورت
+ایرانشهر
+عرصه
+پیروان
+پردازنده
+زایش
+مدینه
+انفجار
+کمپانی
+فرشتهٔ
+واحدهای
+حرارت
+بعداً
+۱۹۴۹
+همینطور
+استخراج
+ملاقات
+فرو
+پارامتر
+منتقدان
+آزمایشگاه
+نوشته‌شده
+اصطلاحات
+بتوانند
+مشتری
+متوقف
+اجباری
+مسلح
+سلجوقیان
+کندی
+اسکاتلند
+فیلسوف
+می‌سازد
+زود
+۷۹
+رجبی
+هفتصد
+تقی
+معدن
+مار
+فراز
+ایالت‌های
+ایمان
+ابراز
+ممسنی
+رادیویی
+سرکوب
+پیوندها
+۱۹۵۹
+توزیع‌کننده
+کشید
+بال
+۱۳۵۸
+۱۹۵۵
+شفاف
+کلام
+یکبار
+رصدخانه
+موسوم
+صلاح
+اخیرتان
+کالج
+واز
+شیکاگو
+جنبه
+۱۳۶۹
+عاشق
+کک
+خنثی
+امیرکبیر
+آنقدر
+زبان‌شناسی
+مشاور
+نمایشگر
+دا
+مِنْ
+آرزوی
+آئین
+می‌آیند
+شکلی
+۱۳۶۰
+سقف
+فرامرز
+بحث‌ها
+همت
+خیام
+تصادفی
+میتواند
+تجاوز
+روح‌الله
+روستاها
+هواپیمایی
+گلدن
+منظورتان
+کرمانی
+قله
+ضربه
+ساکنان
+اورشلیم
+مجدد،
+ویکی‌پ
+معتقدند
+۱۹۳۸
+محیطی
+جعفری
+خطا
+ویروس
+نگار
+سال‌ف
+ابراهیمی
+هشتصد
+نکنم
+ذوب
+رایت
+هاست
+متنی
+نان
+اضافی
+باله
+اصغر
+تایلند
+را،
+پیانو
+سکونت
+تالیف
+اختصاصی
+بهتری
+ترابری
+چو
+دیو
+زندگی‌نامه
+شیشه
+قلبی
+تحریک
+کیش
+ستاره‌ای
+اختراع
+برآورد
+سزار
+دهستانی
+مجسمه
+برطرف
+سپرده
+پارلمان
+رمز
+درسی
+سپاهان
+منصوب
+۱۹۴۱
+پروانه
+جمع‌بندی
+فعل
+کربن
+دژ
+تفکیک
+قفقاز
+همراهی
+عبدالحسین
+بسيار
+مواليد
+۲۵۰
+پیرو
+معاونت
+پیرانشهر
+۹۱
+معنوی
+کاروانسرای
+دفن
+سیزدهم
+ند
+اینقدر
+هخامنشیان
+دستگیری
+گل‌های
+می‌خواهم
+گیرند
+متفاوتی
+شیلی
+مراکش
+کنسرت
+بدهم
+تومان
+کهکشان
+اوضاع
+اندونزی
+چنانچه
+جایزهٔ
+بدهند
+کروبی
+سکه
+گرفته‌اند
+می‌شوم
+تضاد
+ملایر
+شیطان
+سهم
+اخطار
+حرم
+موافق،
+هیتلر
+واسطه
+ناظر
+نمودار
+بگوید
+تیمور
+قصر
+مکانی
+فرودگاه‌های
+۱۹۴۶
+جهاد
+مقداری
+داد،
+اندک
+دکترای
+فیلیپ
+۱۹۳۳
+کارگران
+آماری
+۹۸
+تست
+هستی
+میزبان
+تقاضای
+اوبلاست
+شیوه‌نامهٔ
+من،
+محتوا
+مربیان
+دیسک
+معتبری
+زدایی
+صعود
+حکمت
+مخفی
+زمینهٔ
+دهان
+گو
+رمضان
+ششصد
+هم‌اکنون
+شکسته
+‌است
+حرفی
+۹۶
+هواداران
+تبعید
+نشین
+توجیه
+مکه
+جاذبه‌های
+منافع
+بیفزایید،
+عرفان
+کشی
+آمریکایی‌های
+عقل
+وفات
+سیب
+پربارتر
+کنه
+تألیف
+بنیانگذار
+دموکراسی
+نهصد
+یادم
+سراسری
+تفکر
+لارستان
+برگزیدگی
+رباط
+لس
+حساس
+حبیب
+ویکی‌پدی
+فرود
+همکاران
+تشویق
+تحویل
+باقری
+داده‌های
+معرض
+گلوب
+کلیسا
+ویکی‌پد
+کف
+۱۳۶۷
+امضای
+بخواهیم
+خالد
+فلزی
+نظرخواهی‌ها
+آیات
+درگذشته
+شباهت
+هم‌چنین
+تعلق
+بگیرند
+گوناگونی
+نایب
+حساسیت
+کارگردانان
+مغول
+سازمانی
+دیا
+داغ
+خواهی
+فشرده
+ماجرای
+زندانیان
+تصاویری
+بیماران
+کهنه
+مکمل
+بخواهید
+رایگان
+رویه
+ماری
+فرمایید
+بلورین
+فورد
+درخواست‌های
+سازد
+پروتکل
+راس
+فرقه
+وفق
+نازی
+احتمالی
+طلب
+اقماری
+محدودیت
+همایون
+۱۱۰
+هیأت
+احسان
+ابرخس
+بخواهد
+له
+مهرداد
+می‌شوند،
+سکوت
+مهاجر
+صدور
+بازیگری
+آسان
+سراغ
+اولا
+محلول
+وان
+کوی
+الکساندر
+لیسانس
+خزر
+۹۲
+شکنجه
+امیررضا
+گرجستان
+بازرسی
+عکاس
+۱۳۶۲
+آسیاب
+گویی
+شود؟
+حیاط
+موجهی
+ارکستر
+ارباب
+نویسندهٔ
+یخ
+السلام
+نسب
+بوی
+۱۹۴۷
+نمي
+اعضا
+خانوادهٔ
+ویکیپدیای
+سحابی
+شاهی
+شیوهٔ
+زیارت
+تحقیقاتی
+فعالیتهای
+کاغذ
+تهرانی
+پروفسور
+بریتانیایی
+اخیرا
+ایرنا
+مادرید
+۱۳۵۵
+زمینه‌های
+ببینم
+۱۹۳۴
+می‌بینید،
+فیفا
+صالح
+متداول
+ربط
+سطوح
+ی‌پدیا
+خواهدشد
+بحران
+۱۹۳۹
+افکار
+پیراهن
+۱۹۳۲
+انتظامی
+بلافاصله
+ارایه
+کمیسیون
+راز
+محمدحسین
+آبیلا
+محبوب
+سایه
+جوامع
+داور
+۱۹۰۰
+زودتر
+ولز
+سوخته
+تأیید
+ابوالقاسم
+برادرش
+بمب
+امتحان
+آرتور
+فرستاد
+صص
+دانشجوی
+کارگر
+هوش
+اتفاقا
+غلامحسین
+قربانی
+می‌خورد
+احکام
+سرزمین‌های
+ضمناً
+فینال
+قبرستان
+ضعف
+نامهای
+گندم
+قواعد
+تند
+تایپ
+ماموریت
+موسیقی‌دانان
+گوشه
+دری
+مناسبت
+ارقام
+چاراویماق
+مبانی
+گذاشته‌اید
+ابر
+مدخل
+یو
+شناس
+اندازهٔ
+غالب
+قنات
+مبتلا
+ویکی‌فا
+نوزدهم
+مونیخ
+کابینه
+میرحسین
+باقر
+۱۹۳۵
+سامان
+هلندی
+موجودات
+فنلاند
+برعهده
+مدافع
+قطار
+تغییرات،
+فرمانروایی
+واگذار
+حکیم
+آهنگسازان
+شوند،
+تحول
+مرکب
+مقادیر
+اختیارات
+نوشتاری
+چندانی
+جان،
+هکتار
+رازی
+محله‌های
+آوردند
+صف
+مقاله،
+تدریج
+نیستید
+تسلط
+اسلام‌آباد
+آزمون
+ویرایشاتشان
+اصولا
+صفت
+۱۹۳۷
+می‌شد،
+سفیر
+تمرکز
+شهروند
+نمودن
+ویتنام
+نمایندگی
+گردش
+سران
+فر
+ایمنی
+خو
+مشارکت،
+پسرش
+می‌ماند
+متروی
+ختم
+علمای
+۱۳۶۴
+ران
+کودتای
+قهوه‌ای
+دایرة‌المعارف
+لنگه
+درونی
+سرا
+خاموش
+منصب
+ماد
+دومی
+کشور،
+سوادکوه
+خدایان
+بی‌طرف
+ماجرا
+دماوند
+بردسکن
+ویکی‌نویس
+ماهنامه
+یادگیری
+قابل‌
+هاشم
+همگان
+روانشناسی
+محمدآباد
+نگهبان
+آفرید
+گیرنده
+۱۳۵۲
+۱۳۸۹،
+ترکان
+هوی
+دندان
+خوش‌آمد
+گرفتم
+پایهٔ
+دانلود
+جفت
+فهم
+گوشزد
+متشکل
+رسمیت
+مقدماتی
+جویباری
+پيش
+کنیم،
+استانداردهای
+سرجعبه
+آنجایی
+خیریه
+بیش‌تر
+في
+دکمه
+ماندگار
+فیروزآباد
+بخار
+فیلیپین
+جلگه
+آرامش
+۹۳
+رونق
+پاسداران
+میتوانید
+کاووس
+۱۳۵۳
+۶۰۰
+مرو
+نیافتید،
+نداره
+نجفی
+الهام
+میکنید
+ناصرالدین
+قصه
+آمدند
+پراکنده
+خواهان
+روي
+مرودشت
+مسیحیان
+عبدالهی
+حسابی
+پاییز
+جانبدارانه
+کی‌پدیا
+حین
+پلی‌استیشن
+اعصاب
+می‌توانیم
+فرح
+نمک
+به‌طور
+۹۷
+۱۳۵۹
+گرافیک
+زمین‌لرزه‌های
+منتهی
+مستقر
+تقدیر
+۱۹۳۱
+می‌رفت
+افسانه‌ای
+برخط‌اند
+آبشارهای
+برخوردی
+عکسی
+خاور
+مورخ
+جمال
+باتجربه‌ترند
+به‌کار
+مطالبتان
+راه‌آهن
+نفع
+پاجعبه
+نسخه‌های
+بدی
+آکادمیک
+امتداد
+یوشیچی
+رضاشاه
+تأمین
+خواهشمندیم
+لو
+رئال
+خراسانی
+سردر
+آشپزی
+ایرانیکا
+شاگرد
+سرای
+یزدی
+نامزدهای
+وکیل
+نقشهٔ
+اکسیژن
+شفافیت
+یکی‌پدیا
+مقیم
+ویل
+یادآوری
+بلوری
+شعاعی
+قائم
+آلن
+استانبول
+بکنید
+عمیق
+تایمز
+سلماس
+بی‌طرفی
+بیل
+بویژه
+تک‌آهنگ‌های
+می‌باشد،
+جماهیر
+وحشی
+نمایشنامه
+روایات
+غنی
+کسروی
+بازتاب
+شاملو
+اروپای
+برنج
+بيشتر
+اخراج
+جمعیتی
+اخترسنجی
+شوش
+خوشنویسی
+تقاضا
+مکان‌های
+کریمی
+۱۹۲۹
+دفاعی
+برگشت
+کنید؟
+معمار
+خوش‌حال
+قوه
+۱۳۶۵
+اکسید
+لاهیجان
+آئیله
+عقاب
+پائین
+سوالی
+کنم،
+مان
+خواف
+انجیل
+محاکمه
+ور
+كنيد
+میخی
+مرزهای
+روشی
+بل
+آداب
+زرتشتی
+باشی
+جهرم
+آور
+شهادت
+رسیده‌است
+سادات
+زحمات
+بنویسم
+شریعتی
+بان
+مرتبه
+آثاری
+شه
+کابلی
+تویوهارا
+بیجار
+می‌زند
+نگران
+کر
+سیرجان
+اماکن
+ایلخانی
+ماست
+گزینه
+دوشنبه
+شواهد
+قاعده
+موازی
+شتاب
+۱۳۶۶
+حال،
+ویا
+می‌برند
+۱۹۲۴
+نت
+نجومی
+تعارض
+سادگی
+۱۳۰
+خلافت
+تأثیرپذیرفته
+طبری
+تعقیب
+کاشانی
+منع
+توضیحی
+دورود
+حبس
+بهایی
+محاسبات
+بگوییم
+تنوع
+معادله
+۱۳۵۱
+کوچکتر
+جوی
+دورنما
+شرایطی
+فرماندار
+هریوا
+پی‌گیری
+۱۹۲۸
+می‌نامند
+فومن
+الجزایر
+سیاست‌مداران
+۹۴
+مقدم
+طرفین
+چمن
+صفویه
+یر
+نابودی
+رفسنجانی
+معادن
+۱۳۴۷
+نیل
+سانتی
+دام
+نامه‌ای
+ات
+یافته‌است
+می‌دارد
+بقعه
+۸۰۰
+پرتو
+قید
+ظرف
+لری
+قدیمی‌ترین
+انسان‌ها
+برنامه‌ریزی
+وسطی
+مسلم
+چالوس
+پیشتر
+پوشیده
+فرزان
+میشوند
+منظم
+تلفن‌های
+خوشحالم
+تجمع
+رنج
+آباد،
+مختصر
+هماهنگ
+روشهای
+لفظ
+چوبی
+همين
+شادی
+وسیعی
+گور
+کردیم
+تندیس
+مواقع
+الیگودرز
+نسبتاً
+هٔ
+مخصوصا
+شی
+مشهورترین
+می‌خواستم
+انها
+نهنگ
+حرکات
+دنباله
+قانع
+۱۹۴۲
+داوود
+می‌کردم
+جاوا
+تعادل
+پزشکان
+نحوی
+مادی
+ردهٔ
+گذاشتم
+۱۳۶۳
+کمان
+بعدا
+شرمنده
+ویراستار
+ایام
+اسلواکی
+ناراحت
+متحرک
+تجربی
+خاصیت
+گیلانغرب
+کشتن
+مرزی
+پرچم‌ها
+ذهنی
+لر
+مساوی
+رستمی
+کرم
+ازبکستان
+رضایی
+احیا
+هنگ
+توانم
+شکر
+مند
+کمتری
+بردارید
+قبر
+فرعی
+ایم
+معارف
+پیوندی
+اطلاع‌رسانی
+بسازید
+کردند،
+کلیدی
+سيستم
+لغو
+بسیج
+سرنوشت
+شاخه‌های
+طرفدار
+سیاوش
+کشیدن
+پناه
+هشترود
+ورزشگاه‌های
+صفحه،
+عارف
+ابرکوه
+،خرد
+دراین
+بایر
+قلی
+دشوار
+بیزانس
+بهانه
+جالبی
+قبیله
+بیژن
+چنانکه
+می‌
+بیانیه
+آلفا
+کارگاه
+استوار
+کش
+پویا
+چیزهایی
+نمی‌کنند
+رهنمود
+وصل
+کریس
+پسوند
+مهاجم
+جامعه‌شناسی
+مجددا
+ایر
+احتیاج
+متأسفانه
+خودکشی
+۱۳۴۸
+مراتب
+یازدهم
+خام
+نوجوانان
+بدانم
+طنز
+چهره‌های
+شبانه
+دامغان
+مقصد
+وزیران
+لوح
+شهرام
+بده
+جلا
+دشتستان
+روزنامهٔ
+چهارشنبه
+دالاهو
+ضریب
+تکنیک
+سرخس
+ولي
+دکترا
+آنجلس
+خرس
+مجتبی
+نهاوند
+مسیه
+حسینیه
+كنند
+ملاک
+۳۶۰
+هندسه
+ابو
+کامپیوتری
+۱۳۴۵
+۱۰۱
+صندوق
+بلی
+آقایی
+قالی
+۱۹۲۵
+اشتغال
+اوستا
+خاش
+باتری
+قربان
+رمان‌های
+زير
+خالص
+زدم
+باشد؟
+توقف
+دوستانی
+اجتماع
+کوهی
+کلاه
+قائل
+فلز
+مطلوب
+گربه
+نگرانی
+زوج
+یار
+سرپل
+نوروزی
+۱۹۲۶
+الآن
+اختلالات
+بریتانیکا
+ايجاد
+آزار
+سا
+پروتئین
+بادی
+مجزا
+سانتیمتر
+اله
+پسران
+۱۳۴۶
+دروس
+کور
+مطلع
+نستعلیق
+خطرناک
+لوگوی
+دنده
+ویژه‌ای
+بهینه
+الکترون
+سقز
+عددی
+کاش
+جیرفت
+راسته
+بتوانم
+نسبتا
+یازده
+کمیل
+مانفی
+انتخابی
+نداشتن
+حرکتی
+کمترین
+مرورگر
+مقاله‌ی
+برنز
+انشای
+فراتر
+وسیلهٔ
+انزلی
+سوم،
+آشور
+اجزای
+روزنامه‌های
+نداشتند
+برتری
+توقیف
+گنجایش
+نویسندگی
+واشینگتن
+وَ
+عبد
+ماهیت
+ترکمن
+تابش
+برف
+اثرات
+نمایشی
+است‌
+حدس
+بین‌الملل
+۱۹۲۳
+راوی
+بامداد
+تنگه
+گذراند
+اتفاقی
+هالیوود
+گشته
+اسمیت
+باش
+آلی
+ترکمنستان
+سوسیالیستی
+مجلات
+۱۹۱۸
+بدنه
+قاهره
+خانهٔ
+بید
+ایرانی،
+۱۳۴۰
+پری
+اشتباهی
+نهاده
+وب‌سایت
+شهروندان
+همایش
+خوان
+نژادی
+عملیاتی
+افزود
+مخلوط
+رودسر
+الیزابت
+نمونه‌ای
+مغزی
+قضایی
+یان
+گالری
+بگو
+ملقب
+ایفا
+انیمیشن
+بخش‌هایی
+شکستگی
+سوپر
+کانی‌شناسی
+ویتامین
+می‌دادند
+پرجمعیت
+درسال
+۱۰۵
+ستاره‌های
+مدیا
+بندپی
+تردید
+كشور
+ماهیان
+پوزش
+انگار
+اسلام،
+ايشان
+سرپرستی
+تاکستان
+۱۹۲۷
+۱،
+پذیرفت
+نما
+مشتق
+باستان‌شناسی
+امامی
+اتم
+ندیدم
+نوشهر
+گزیدن
+۱۹۱۹
+حیوان
+بنظر
+کورش
+اواسط
+رفتند
+تبادل
+میلی
+استون
+دانستن
+آمریکا،
+حصار
+آینه
+گرایی
+قبایل
+کبیسه
+۱۹۴۳
+۱۹۱۲
+۱۹۱۷
+برقراری
+فيلم
+نداشتم
+سرده
+فعالیت‌ها
+بوستان
+خیال
+کارش
+کربلا
+کنم؟
+سیاست‌مدار
+معنایی
+آلودگی
+شماری
+کودتا
+پانزده
+المعارف
+کالبدشناسی
+عظیمی
+علائم
+کنسول
+نحو
+سوئدی
+گرفت،
+مازندرانی
+مثال،
+منسوب
+نشدم
+ویران
+درخشندگی
+بندرعباس
+ارگ
+سامانه‌های
+بیمه
+انجامید
+اردکان
+متمرکز
+سلولی
+مرسوم
+صادقی
+هيچ
+امثال
+ولتاژ
+مقررات
+رکورد
+بلخ
+نامزدی
+پردیس
+راه‌های
+‌ای
+مانده‌است
+هدیه
+خاکی
+کلاً
+كنم
+جویبار
+گرجی
+سنجش
+بو
+مثلث
+جمهوری‌های
+خاتمه
+رشتهٔ
+بوش
+حسین‌آباد
+۱۳۴۹
+جنگلی
+عزل
+مزار
+اختلافات
+زاکسن
+عشایر
+دشمنان
+کنگ
+یهودیت
+الگویی
+فرکانس
+تحریف
+پژوهش‌های
+شام
+لار
+می‌بینید
+مریخ
+علی‌اکبر
+عامه
+روزها
+زخمی
+عبارت‌اند
+ویکی‌های
+بری
+کارائیب
+رده‌فرد
+رحیم
+نگاشته
+القاب
+قاتل
+مکرر
+محمد،
+ابداع
+ویدئو
+اسطوره
+جامد
+ژنتیک
+مجاور
+سیاسی،
+رفسنجان
+بعید
+مرند
+روحانیون
+اریک
+قریب
+نثر
+تحریم
+موزیک
+برداشتن
+ارتفاعات
+اشکالی
+غذاهای
+شهاب
+بورس
+سال،
+نقشه‌های
+عروس
+نخل
+محلات
+آلبرت
+فا
+دشمنی
+۱۹۴۴
+يكي
+جایگزینی
+تفاصیل
+خدابنده
+اقلیت
+مشخصی
+محاصره
+زین
+افتخارات
+این،
+بي
+سواحل
+اندام
+فرماندهان
+دانند
+دوازدهم
+بجز
+آرا
+بهائیت
+۱۹۲۱
+کالا
+استقرار
+تلخ
+تکه
+جلوه
+امان
+نگونبانگونی
+فیلمنامه
+مترجمان
+کتاب،
+بستر
+تولیدی
+باغ‌های
+نباشند
+انصاری
+محمدتقی
+ان‌جی‌سی
+سلمان
+پهن
+گستره
+سودان
+پرهیز
+همون
+موسسات
+جاهای
+اشرف
+سواد
+مصوب
+دانه
+اينكه
+شعبه
+تشیع
+اپرا
+مجری
+موضع
+۱۴۰
+گلوله
+دارایی
+آوردم
+۱۸۰
+بلد
+سیروس
+گرمسار
+مهارت
+پیشاپیش
+ساختمانی
+باختر
+نامید
+ایفای
+باریک
+تعجب
+عقد
+فرمودید
+وطن
+گوی
+قبرس
+محبوبیت
+کوچ
+جدید،
+اخترشناسی
+کلمهٔ
+ایذه
+احوال
+پراکندگی
+ویرایش‌ها
+سانتا
+نپال
+چرخش
+فخرالدین
+دستگاه‌های
+پاراگراف
+می‌توانم
+پیکر
+بعد،
+جای‌ها
+یاران
+بیگ
+پنجره
+رامسر
+خواه
+انکار
+می‌کشد
+۱۹۲۲
+برعکس
+پاره
+اکشن
+لغات
+گردآوری
+سهراب
+نیز،
+عراقی
+پاسارگاد
+نوجوان
+مخفف
+هیچگاه
+کاندید
+بهروز
+بناب
+تهمت
+آفریقایی
+جسد
+پژوهشگران
+موسس
+بلاگ
+آبخواره
+مایه
+مجدداً
+لقب‌ها
+تلسکوپ
+استانی
+منتقد
+داراب
+دلخواه
+فرش
+بارگذاری‌شده
+صحرای
+نوک
+فارسي
+رسانه‌ها
+ماکو
+۱۳۶۱
+استفادهٔ
+دستیابی
+سرو
+بردار
+آلبوم‌ها
+مکعب
+تب
+می‌گرفت
+وی،
+قطعی
+اقبال
+پلاک
+برابری
+جوش
+التحصیل
+بردند
+شارل
+خشم
+سارا
+گناه
+حوصله
+بیافزایید
+اصیل
+خودمختار
+نمی‌دهد
+داند
+سراوان
+صور
+یعقوب
+شنیدن
+اشتراک
+دفع
+اد
+ه‍
+وستفالن
+بهائیان
+پناهگاه
+مسیرهای
+هست،
+مذاهب
+گران
+تابعیت
+یابی
+ولسوالی‌های
+اسرائیلی
+تاریکی
+تعطیل
+همکار
+زور
+خلیل
+شوخی
+سلول‌های
+تنش
+کرسی
+نصف
+می‌افتد
+بیات
+فضل
+نامشخص
+تعبیر
+۷۰۰
+شو
+سوسیالیسم
+اب
+پرچمک
+دموکراتیک
+تحولات
+بگیریم
+گسترده‌ای
+آریایی
+کیلو
+والی
+براون
+ناچار
+گنج
+بلندترین
+انگشت
+محتواهای
+۱۳۸۵،
+نه؟
+یهود
+وضوح
+بلوک
+بلور
+باکیفیت
+غير
+بدل
+نادیده
+لاریجان
+دلفین
+جاز
+حاکمان
+دوری
+آرای
+خاوری
+شناختی
+ماریا
+شیب
+نیوزیلند
+مشکین
+منتظری
+خریداری
+۱۱۵
+جانی
+به‌شمار
+تعلیم
+تأکید
+اندازه‌گیری
+یافتند
+مادری
+فون
+بادن
+کدهای
+بدنی
+لوئیس
+ادامهٔ
+مبلغ
+صلیب
+می‌بایست
+آریا
+۱۲۵
+بفرمائید
+قراردادی
+شر
+گفت‌وگو
+گرینویچ
+مولکولی
+نیو
+سايت
+۱۹۱۴
+جزیره‌های
+رسیدند
+فرمت
+قائم‌شهر
+تفرش
+نظریهٔ
+خواستید
+هافبک
+دائمی
+تنیس
+می‌دهد،
+ماتریس
+باخت
+سیا
+مغرب
+سل
+اسلحه
+ذهاب
+دهد،
+فرقی
+صرفاً
+وبلاگ‌ها
+نمیشود
+راضی
+آتن
+چراغ
+حالتی
+شلیک
+الیور
+اینکار
+برپا
+آهنگرکلا
+لویی
+نیما
+بجنورد
+نهادهای
+محروم
+نکا
+لب
+وحش
+اعتراضی
+ژن
+ويكي
+عثمان
+نیشابوری
+بلک
+کنندهٔ
+موتورهای
+رئیس‌جمهور
+حکایت
+حاکمیت
+نفره
+هرسین
+مالیات
+انجام‌دادنی‌ها
+خودت
+مناقشه
+کارهایی
+غذای
+نوردراین
+علل
+دیپلم
+دادگستری
+پیچ
+لیورپول
+سرپرست
+گلی
+تفت
+جنسیت
+امری
+صبا
+اسفراین
+ریخته
+برا
+ناپلئون
+دبستان
+ویدئویی
+خمیر
+انتخاباتی
+گفته‌است
+ورزشکاران
+عادت
+آرایه
+اعتراف
+استخدام
+آرامگاه‌های
+دوتایی
+ارنست
+عمدتا
+مجهز
+زدند
+۱۳۳۰
+۱۳۸
+۱۳۳۲
+آلبانی
+نشانه‌های
+باغین
+شعبان
+فارسی‌زبان
+نیمی
+سازگار
+زبانان
+پیست
+کارایی
+گرافیکی
+کوره
+اتیوپی
+ساوجبلاغ
+مشرق
+فِي
+سیزده
+۱۰۳
+مردم‌شناسی
+بلندی
+محمودآباد
+بتا
+۱۰۲
+مراد
+افتخاری
+سهام
+امیدان
+دلایلی
+غول
+۲،
+مازیار
+عمدتاً
+مملکت
+۱۳۴۲
+انگیزه
+فرنگی
+مینودشت
+بقایای
+ابوالفضل
+فاکس
+میگوید
+همچنين
+شعری
+لس‌آنجلس
+تائید
+تاریک
+تونس
+بستان‌آباد
+کارمندان
+اسحاق
+۱۶۰
+کارگری
+پتانسیل
+سحر
+۱۰۹
+نیازهای
+آرسنال
+افزون
+نظریات
+کوبا
+فهرستی
+آزادگان
+کارشناسان
+تزریق
+کاپیتان
+حدودی
+فیل
+والیبال
+ازای
+این‌گونه
+همانگونه
+نداده
+سردبیر
+تالش
+سام
+می‌گذرد
+آنتی
+مجلهٔ
+بازی‌ها
+رجال
+هم‌درازا
+دختری
+رفته‌است
+ابریشم
+فلوریدا
+بلغارستان
+مصری
+بلوار
+دليل
+راه‌اندازی
+۱۰۴
+شمشیر
+ندا
+صادرات
+دانیل
+هریس
+کله
+حوزهٔ
+نشسته
+بیاندازید
+۱۲۸
+وبه
+تازگی
+شورا
+سروده
+درمورد
+شدند،
+قطعا
+اراضی
+می‌گویید
+حامی
+خوراکی
+جایزه‌ها
+کویر
+مفهومی
+رودهای
+زمان،
+کمیاب
+مخاطب
+سوابق
+سلامتی
+علوی
+خواندم
+نهایتا
+هوشمند
+همیشگی
+همدیگر
+سازه
+ترویج
+مقر
+قشم
+تغيير
+دیروز
+مخالفم
+نجوم
+آرزو
+عموماً
+افقی
+گوشی‌های
+رباتیک
+کلاته
+لورنس
+وزیری
+پرداختند
+رجب
+جوزف
+سپری
+تایوان
+مقاله‌هایی
+بود؟
+بزند
+مرسی
+باختری
+صلاحیت
+نمی‌آید
+بهشهر
+جماعت
+خونی
+نوشته‌است
+ازنا
+مکانیکی
+فضاهای
+فرمانروایان
+رزمی
+همسایه
+همدانی
+۱۹۰۸
+۱۹۰۵
+هردو
+۱۱۴
+هرم
+شهرکرد
+۱۰۷
+آب‌های
+متقاعد
+شویم
+نبود،
+نویسان
+هم‌زمان
+شهر،
+صخره‌ای
+ارزشمند
+۱۳۲۰
+حذفش
+سامی
+ثانویه
+دن
+احساسات
+بوئینگ
+نام،
+شبکهٔ
+شمرده
+طوایف
+باری
+جبر
+اجازهٔ
+بزرگ،
+بهم
+۱۱۱
+جهان،
+مولوی
+تفریحی
+ماساچوست
+آنها،
+اجتماعی،
+طاق
+خوشامدید
+نیامده
+اچ
+ملاحظه
+کمبریج
+زی
+برش
+می‌گذارد
+شدگان
+بدو
+درحال
+چارچوب
+شده‌اند،
+قطبی
+لئون
+هیدروژن
+کاردانی
+درمیان
+نقاشان
+شنیده
+چنين
+آتشکده
+کوههای
+قروه
+هجوم
+سرهنگ
+عکس‌های
+تاجگذاری
+خرج
+۱۳۴۴
+جعلی
+آمیزش
+راهپیمایی
+سرشار
+فیروز
+دوک
+بهداشتی
+شکی
+ماهواره‌ای
+طاهره
+زیرصفحه
+تسخیر
+مخزن
+حیدر
+اتفاقات
+غزل
+زهج
+بولیوی
+کردها
+۱۹۰۱
+قند
+نخست‌وزیر
+بازهم
+عصب
+مهاباد
+پرس
+گازی
+ابزاری
+مبدل
+۱۳۵
+میشل
+مستقیما
+صدام
+محکم
+فلزات
+طنابداران
+پروژهٔ
+امّا
+صحرا
+۱۰۸
+جملهٔ
+شوهر
+هواپیماهای
+سعادت
+جعل
+صفحه‌کلید
+اوباما
+۱۹۰۶
+انب
+اپل
+مرخصی
+معیارها
+دانید
+دعا
+تلفات
+تضمین
+آرامی
+دائم
+شد؛
+چرخه
+شجره‌نامه
+آفرینش
+معادلات
+رسما
+مزبور
+بارش
+برکه
+نبی
+مصالح
+والتر
+سدیم
+بحثش
+پیشگیری
+پروین
+نشود،
+می‌گردند
+مسافر
+راین
+بتن
+خوشه
+طوسی
+جونز
+وابستگی
+اسیر
+خیابانی
+بت
+اینجانب
+ببینیم
+لیکن
+بگذاریم
+شراب
+انگیز
+برروی
+حاجی‌آباد
+پارسک
+اعزام
+اعطا
+فقر
+علي
+کارنامه
+حجاب
+اینک
+جمع‌آوری
+درهم
+خواهشمندم
+اینه
+گانه
+پارچه
+گردیده‌است
+مداوم
+آلوده
+حقایق
+جعبه‌دندهٔ
+بشری
+چهارده
+۱۳۰۰
+لیلا
+بدیهی
+مابین
+مثنوی
+ویدیویی
+محققان
+رابط
+تلمبه
+پرفروش‌ترین
+استیو
+ساختمان‌های
+وانتشار
+معترضان
+وحی
+برنامهٔ
+بگم
+عسل
+پرتغالی
+فصلنامه
+عجب
+رفتارهای
+وورتمبرگ
+امپراطوری
+برون
+شانزدهم
+مدل‌های
+آکسفورد
+فساد
+چیزها
+خبرنگار
+ذره
+کان
+کنیم؟
+دامداری
+هی
+عبدالکریم
+کوهرنگ
+آنتونیو
+ایرادی
+۱۱۶
+دریافتی
+هرمز
+آب،
+گـپ
+ویکی‌پدیایی‌ها
+۱۰۶
+غریب
+دلفان
+راسل
+۱۹۰۷
+گویم
+قزاقستان
+وحشت
+منشور
+انتقام
+مشروطیت
+کیفی
+بپردازد
+براى
+شركت
+تعصب
+ویلهلم
+خطای
+متقابل
+۲۰۱
+اشکانی
+می‌کرد،
+بروجردی
+طبقات
+طالبان
+سفارش
+فیلمهای
+آهنگ‌های
+کنستانتین
+پیوستن
+دیدگاه‌های
+چالش
+ستایش
+نقشی
+کهریز
+منطقه‌های
+خلبان
+تنگستان
+فروند
+حج
+خاتم
+۱۳۴۱
+گردند
+پایتون
+گفته‌اند
+دانسته‌اند
+دانشکدهٔ
+تکلیف
+بازرگان
+نتوانست
+بیوگرافی
+۱۵۰۰
+بنت
+مری
+نقص
+فانتزی
+پژوهشگر
+دویچه
+کنت
+قاجاریه
+دوام
+حیدریه
+جیمی
+پویانمایی
+قوای
+می‌آورند
+کامران
+متنوع
+استراتژی
+شمارش
+۱۹۰۴
+اعم
+داراي
+بهبهان
+الدوله
+تخلف
+فراری
+ایزد
+رأس
+انداخت
+چرداول
+پیش‌فرض
+رهنمودهای
+بافتا
+شناسان
+اردو
+آبیاری
+ترانه‌سرا
+روحی
+ادیب
+فلات
+ایست
+سلیقه
+ماجراهای
+باکو
+همارس
+تراکتورسازی
+گم
+رابطهٔ
+داشتند،
+رپ
+گز
+بگذارد
+۱۱۲
+مستندات
+زمین‌های
+سایت‌های
+مبحث
+مشکلاتی
+بوکان
+ابزارها
+جبران
+تقریبی
+زیان
+گلپایگان
+خوشنویسان
+۱۲۲
+بارز
+مَا
+بوک
+اشتباهات
+تانک
+می‌شده
+دهه‌های
+واژه‌نامه
+خشکی
+ایی
+اللَّهِ
+عفونت
+۱۲۳
+باده
+نام‌تصویر
+بیس
+كردن
+گچ
+زدهٔ
+طلای
+معکوس
+نبودند
+رضایت
+ثروت
+انار
+کشاورز
+کوانتومی
+اژدها
+سوراخ
+بیلبورد
+شاهین‌دژ
+بره
+اهدا
+زیرزمینی
+تکراری
+صربستان
+مراقبت
+تروریستی
+۱۹۱۱
+متمایز
+آملی
+برساند
+عن
+ابهر
+معتدل
+گفتگوی
+املش
+می‌بینم
+می‌آمد
+۱۹۱۳
+ناشناس
+وله
+جایش
+جنبش‌های
+توليد
+موزه‌های
+نمائید
+دهمین
+برند
+تاریخچهٔ
+می‌شده‌است
+پاسخی
+پشتی
+تشریح
+نمی‌شوند
+خویشاوندان
+انگشتدان
+دكتر
+ژانر
+فریاد
+اخلال
+تمشک
+سعد
+پارسا
+۹۰۰
+نامدار
+نظامیان
+قدری
+حمام‌های
+مستوفی
+گرما
+گرا
+یادگار
+عاشورا
+دفعه
+بیانی
+شنا
+استعفا
+رسانه‌ای
+انحلال
+بزرگداشت
+فایرفاکس
+بتوانید
+مؤلف
+حامیان
+ناحیهٔ
+مور
+۱۹۱۰
+حیاتی
+هرگاه
+آنا
+جاسوسی
+منتج
+جابجایی
+تولیدات
+هاى
+قدردانی
+۱۷۰
+راست۱
+لیلی
+عملاً
+میشد
+کشورهایی
+درجهٔ
+حامل
+ابوبکر
+خصوصا
+اختصار
+مجاورت
+پدیدآورنده
+آراء
+چپ۱
+گله
+یکپارچه
+عبارات
+جمینای
+جزیرهٔ
+اسرار
+خانواده‌های
+بلوز
+مونته‌نگرو
+بیابان
+به‌صورت
+دارید؟
+نقطهٔ
+ضرورت
+وي
+کارکرد
+هوانوردی
+محبت
+پارک‌های
+واژه‌ای
+امامزاده‌های
+هریک
+کوچکترین
+طاهر
+حوالی
+مطهری
+کنگاور
+شدهٔ
+شبکه‌ها
+شیوه‌های
+تیراندازی
+۱۱۸
+جست
+آژانس
+سایز
+بدن۱
+تکذیب
+نقدی
+متناسب
+دال
+بابی
+شانزده
+هرکدام
+ادعاهای
+العاده
+عنایت
+مزدیسنا
+انقراض
+مقدونیه
+۱۲۷
+ندیده
+رأی‌گیری
+دلو
+هندسی
+موبایل
+تورم
+رفتاری
+پیامدهای
+زید
+زادروزها
+حیدری
+بتوانیم
+فوری
+علایم
+نویسه
+غم
+خلال
+اریل
+کاشمر
+بز
+بردسیر
+۱۹۱۵
+حتا
+برخط
+خرمشهر
+همچین
+نفری
+سالگرد
+متخصصان
+شاهرخ
+صحن
+جنین
+جشن‌های
+یکشنبه
+تمیز
+ارامنه
+چپ۲
+جلسات
+مهمان
+کجای
+روال
+۱۳۴۳
+پینک
+سبک‌های
+هان
+بدن۲
+عمودی
+افسران
+شجریان
+نوسنگی
+الاسلام
+مساجد
+صاف
+مروارید
+جانور
+آنهایی
+راست۲
+اسکی
+ناشناخته
+اعتقادات
+یم
+انگور
+ويرايش
+گروههای
+ترانهٔ
+شد؟
+دقیقی
+استادیوم
+مختلف،
+عتیق
+توطئه
+بالا،
+مین
+همگانی
+تلفنی
+می‌دانست
+ود
+ميان
+تشکیلات
+روده
+مدیره
+ونزوئلا
+مخصوصاً
+مشتمل
+انتقادی
+تفنگ
+برایشان
+طالقان
+فرانسیس
+بازارهای
+پایین‌تر
+کاروان
+به‌جای
+الیاف
+خامنه
+خصوصاً
+ظهر
+سکس
+چهاردهم
+ایزو
+مسجدسلیمان
+الکل
+فلاندری
+محمدیان
+شکوه
+کرده‌اید،
+اسلامي
+سم
+کناره
+لوازم
+نمیدانم
+پیامی
+فارغ‌التحصیل
+باس
+کام
+بنویسد
+بازنشسته
+نصر
+کاشی
+شکارچی
+پست‌های
+ویلیامز
+دهکده
+اندر
+۱۵۴
+جهانگیر
+ملکان
+می‌توانست
+عبارتی
+مسئولان
+هلال
+مهندسان
+غارهای
+بیلی
+۱۹۱۶
+بنگلادش
+حملهٔ
+توانستند
+پارینه‌سنگی
+پولی
+خوشبختانه
+نموده‌است
+امینی
+نه،
+هما
+مشورت
+نامحدود
+آندره
+پلنگ
+مخدر
+مضمون
+برمی
+هم،
+لاس
+دهید،
+ویکتوریا
+موثق
+داود
+عذرخواهی
+یاهو
+رنگ‌های
+۱۱۷
+تناوبی
+نوشتید
+لااقل
+شتر
+مرکزیت
+امن
+ترسیم
+سیستم‌ها
+اتومبیل
+آفی
+جون
+خالق
+حرارتی
+رسوم
+موریس
+مارشال
+یورو
+بانو
+اولين
+منشورات
+غیبت
+نوشته‌اند
+قدرتمند
+شکم
+هایش
+انداز
+رویکرد
+علاقه‌مند
+خانواده‌ای
+دمشق
+دربند
+برو
+آرشیو
+۱۹۰۹
+رویش
+استخر
+آنالیز
+گچساران
+بکنم
+مولا
+متفرقه
+رحمت
+شاخ
+۱۳۱۰
+اتفاقاً
+اسمش
+سهامی
+دبلیو
+بخشهای
+سرتاسر
+ویکی‌ها
+خیالی
+نکنند
+تناسلی
+م‍انفی
+جديد
+۱۳۲۴
+کار،
+برندهٔ
+پیچیدگی
+گواهی
+زرتشتیان
+ناصری
+همانجا
+رغم
+گفتهٔ
+۱۱۳
+گرمسیری
+طلوع
+برترین
+درآورد
+به‌دست
+برقی
+سپاهیان
+ویژگی‌ها
+مر
+۱۲۴
+چهاردانگه
+جامعهٔ
+تحقق
+مجاری
+می‌گفتند
+فروپاشی
+چشمه‌های
+ساختاری
+مسافرت
+پیکان
+نرم‌افزاری
+جد
+روشنی
+معرفت
+تله
+می‌کنم،
+محرک
+مشتریان
+بیانگر
+سازمانهای
+چیزهای
+رقیب
+فرعون
+بیروت
+منعکس
+تابناک
+مشرف
+آورده‌است
+نمی‌توانم
+۱۱۹
+مولکول
+نعمت
+می‌رساند
+فرمانداری
+دستکاری
+۱۳۳۹
+مت
+اردبیلی
+مسدود
+بله،
+رانندگی
+۱۲۱
+سایپا
+استعداد
+پیامبران
+داماد
+واجب
+نسخ
+فاضل
+عرفانی
+بزرگ‌تر
+حق‌تکثیر
+شخصاً
+دگرگونی
+عكس
+انبوه
+آپولو
+فنون
+افلاطون
+حمزه
+میانجی‌گری
+نظرسنجی
+آنتونی
+اکوادور
+آن‌چه
+قذافی
+اسکن
+خاتون
+ناگهان
+گونه‌ها
+تونل
+به‌ویژه
+ناگهانی
+بدهیم
+دوشیزه
+آباده
+نمی‌توانند
+شلوغ
+ی،
+۱۳۳۵
+خلع
+فلوید
+ابومسلم
+بایت
+اعطای
+جاسک
+پوند
+پایداری
+تیتر
+واپسین
+استالین
+تعطیلات
+آستین
+مختلط
+تابلو
+خنده
+نویسه‌های
+ثمر
+۲۰۰۰،
+بازاریابی
+حسابداری
+تکلم
+رنگرزی
+نهبندان
+۱۳۳۶
+نیلوفر
+شرقی،
+بداند
+فسا
+آلیکانته
+دیلمی
+اجتناب
+نیر
+سطح‌بالای
+اينجا
+می‌زنند
+کیم
+لغتنامه
+عاشقانه
+فتحعلی
+اشیاء
+تعمیر
+فلانی
+استیون
+سازماندهی
+ویرجینیا
+راجر
+بگویند
+روزنامه‌نگاران
+هندو
+دیوانسالار
+ایستاده
+۱۳۳۷
+کرانه
+کلسیم
+هایدلبرگ
+کرواسی
+سرانه
+الملک
+سنگ‌های
+ژنتیکی
+نیکی
+هجرت
+مامور
+خنک
+نمایان
+بهرامی
+شبستر
+واسط
+آرایش
+مبهم
+بسی
+بریتانیای
+محدودهٔ
+بحث‍
+گاما
+ده‌ها
+نواختن
+فروشگاه
+خمین
+صنعاء،
+کنفدراسیون
+اموال
+هنرپیشه
+پارسیان
+متوسطه
+دامن
+۱۲۶
+لک
+شیشه‌ای
+ابراهیم،
+آمادگی
+هو
+زنجیره‌ای
+۱۳۲۸
+بازیهای
+سنقر
+بدر
+آورند
+مرجعیت
+آلت
+اسدآباد
+کارلوس
+سودمند
+نشانگر
+رسید،
+حوزه‌های
+دیار
+کنگو
+میهن
+کلانی
+۱۲۹
+افسر
+باکتری
+معماران
+۱۳۲
+سیدنی
+کفش
+ارادت
+می‌خواهند
+خر
+۳۵۰
+بدترین
+تاریخ،
+فلسطینی
+زاگرس
+بیاورد
+یانگ
+شخصا
+تشدید
+آدمی
+ماهی‌ها
+هیچکدام
+میناب
+بوسنی
+ایندیانا
+دنباله‌دار
+ملوان
+روزنامه‌نگار
+مؤثر
+دستورات
+رطوبت
+تعامل
+کلان
+عباس‌آباد
+کاملی
+احادیث
+مدرکی
+پاکسازی
+۱۳۷
+تفاوتی
+ورزشکار
+جنبه‌های
+غالباً
+بود؛
+چنگ
+مهاجران
+پله
+تراز
+آمد،
+وا
+کوثر
+وادی
+اتوبوس
+کاظمی
+خبرگان
+موس
+تکمیلی
+لهستانی
+درویش
+منم
+جعفرآباد
+نیا
+جاذبه
+گیلانی
+طلاق
+تروریسم
+به‌خاطر
+آيا
+گرفتار
+اشعه
+می‌پردازند
+شخصیتی
+آقایان
+رفتم
+جریمه
+مهره
+خاستگاه
+میان‌ویکی‌ها
+بالینی
+یزدگرد
+ببرد
+دوش
+چغازنبیل
+۳۰۰۰
+فوقانی
+۱۳۳۱
+گیلکی
+خط‌به‌خط
+کاترین
+بختیار
+کردید،
+گردان
+ادی
+طاها
+مدیترانه
+ارس
+حسن‌آباد
+پوشاک
+بابلسر
+رساندن
+کند؟
+بهش
+وست
+خوشامدگویی
+مهار
+میبد
+فلسفهٔ
+وند
+آش
+سیمین
+خوراک
+خوزه
+ساختند
+نياز
+عروسی
+میگردد
+جلفا
+بودیم
+بکند
+۱۳۸۸،
+روحانیان
+حماسه
+پایتخت‌های
+مبارزات
+احمد،
+ارث
+محمّد
+۱۳۳۳
+کوشک
+سنگ‌ها
+زشت
+دنا
+دستیار
+گرمایی
+ایشون
+نامهٔ
+تحمیل
+گوشی
+دوره‌ای
+ققنوس
+بدانند
+شن
+انداختن
+هفدهم
+غالبا
+اسدالله
+۱۳۴
+شدیدی
+ناپذیر
+۱۴۴
+گینه
+سرمربی
+نطنز
+کیبورد
+محفوظ
+آیند
+انفرادی
+آن‌که
+گمانم
+توانسته
+سال‌شهرشدن
+علم‌جو
+خرده
+درگز
+ایستگاه‌های
+بکشید
+پیش‌بینی
+حالات
+هرکس
+بزودی
+کایروس
+اوستایی
+صفات
+مارکسیست
+خشت
+جنب
+عذر
+ونیز
+آسانی
+کریستین
+صفویان
+اسدی
+۱۹۰۳
+تاخیر
+خیانت
+قوس
+قطره
+آثارش
+سیل
+اسکات
+مشاغل
+شم
+بخارا
+چاپی
+مکتوب
+دیدید
+انتها
+موزیکال
+كاربر
+منشأ
+سمی
+لَا
+پهلوان
+پوسته
+درختی
+مشابهی
+کنیا
+عاملی
+۱۳۹
+گویید
+۱۳۳
+تلاش‌های
+اهمیتی
+عازم
+اسمی
+پکن
+تصوف
+تکاب
+حاکی
+برت
+کنيد
+نوروزتان
+ببیند
+کبوتر
+سفرنامه
+۱۳۳۴
+تخلیه
+آق
+زنجیره
+انتقادات
+کوک
+همان‌طور
+غربی،
+جنجال
+فیزیولوژی
+سانتی‌متر
+بسط
+زخم
+۱۴۱
+ویکتور
+آران
+یك
+التهاب
+دسته‌بندی
+جنگنده
+ایفتا
+ژاک
+طاهری
+فیض
+بهتره
+ادعایی
+اسد
+بودنش
+پیک
+مسأله
+بانوان
+بنفش
+گشود
+باغی
+هیدوچ
+جسمی
+انگشتی
+یوهان
+لنز
+چراکه
+رهایی
+نگرفته
+مقصود
+جوراب۱
+آنهم
+قمی
+سکته
+کو
+سره
+زبانها
+برج‌های
+مکان‌ها
+نشدن
+چابهار
+پاراگوئه
+کتابها
+طولانی‌ترین
+اولویت
+مبارز
+استراحت
+مشت
+حرام
+فرمود
+نقلیه
+کمر
+پستان
+سرچ
+فعاليت
+ارتقاء
+شانس
+خودی
+فاتح
+مطالب،
+گوسفند
+میگویند
+غلام
+وصف
+دلم
+اظهارات
+انتگرال
+سوسیالیست
+گذارد
+ماموران
+بادام
+چال
+ساگه
+ایسنا
+معده
+ریشتر
+اعلان
+تک‌نفره
+بلو
+مناطقی
+شافعی
+می‌گفت
+می‌خواند
+ثانی
+هست؟
+منو
+لوث‌شدن
+جنایت
+برخاست
+بوده‌است،
+نمی‌باشد
+اشراف
+نداد
+مهربان
+الهیات
+همه‌ی
+زمين
+کینگ
+رول
+والتوزیع،
+مدرسهٔ
+ترافیک
+اتهامات
+وای
+بهنام
+شجاع
+سیار
+ترسناک
+ذات
+مختار
+عموما
+اینتر
+فرزندش
+داروشناسی
+ریسک
+۱۹۹
+نیجریه
+مظفر
+حشرات
+میدانید
+جبل
+آریزونا
+نارنجی
+کتابخانه‌های
+میدانم
+آرم
+بشمار
+اعتباری
+کره‌ای
+عکس‌ها
+پیکچرز
+تخته
+متمایل
+رفاه
+شهبازی
+میخائیل
+تطبیق
+نظریه‌های
+بلوغ
+عزیزم
+۱۳۹۱
+محاسباتی
+سنجی
+مکانیسم
+سریعتر
+آبشاری
+کالاهای
+اشک
+خانی
+سازگاری
+مارچ
+گرین
+قرص
+خوانندهٔ
+صفی
+نازک
+داروها
+۳،
+۱۳۶
+هماهنگ‌کنندهٔ
+لینکلن
+بانوی
+خودروی
+پل‌های
+۱۳۳۸
+دیوارهای
+ورامین
+۱۴۵
+اتخاذ
+کمیت
+دارم،
+مذاکرات
+حول
+برگزید
+کارشناس
+نامعتبر
+سفرهای
+رومیان
+ربات‌ها
+غیراینصورت
+انیمه
+به‌وسیله
+استعمال
+صریح
+سازه‌ها
+رامهرمز
+اندیس
+رازقنــدی
+تثبیت
+۱۰،
+تصوير
+گویش‌های
+کتک
+طالب
+حماس
+۱۳۲۹
+علیرغم
+۱۴۸
+حزبی
+استونی
+اوین
+غروب
+حریف
+استراتژیک
+شگفت
+مرگش
+جانسون
+پانزدهم
+موشک‌های
+گن‌آباد
+ارتقا
+باطل
+خورشیدی،
+آلفرد
+ساموئل
+بحرانی
+قندهار
+كردم
+ماکس
+گی
+میخواستم
+بچه‌های
+۱۳۲۵
+شرطی
+گشایش
+زندگي
+دایی
+یون
+فرانس
+تورات
+گزارشی
+۲۲۰
+فیلم،
+دهلی
+مسافران
+سنگر
+نخواهم
+موش
+ریشهٔ
+سخنگوی
+زنگ
+نینتندو
+دیوانه
+بمباران
+مسئولین
+استودیویی
+شدیدا
+تیلور
+۱۲۰۰
+قزوینی
+لاست
+مسلما
+ورق
+شهرزاد
+لطفی
+کلات
+بارداری
+دیواره
+باشگاهی
+شکستن
+تریلر
+ممتاز
+پرانتز
+یوتیوب
+بیهوده
+ابدی
+نباشد،
+کیوان
+طرح‌های
+بدم
+کاریکاتور
+بدتر
+داش
+می‌رسید
+میانجی
+بيش
+اختریان
+سربیشه
+روشنایی
+تبیان
+بکشد
+اراده
+چربی
+خرما
+سلطانی
+شيخ
+مقا
+مستخدم
+وب‌گاه‌ها،
+نشینی
+نرگس
+۱۷۵
+تویسرکان
+خاطره
+برکنار
+غیرقانونی
+ساواک
+نگاره‌ای
+سین
+شناسنامه
+بناها
+‌ها،
+غرق
+شعرهای
+مسلط
+سرش
+اه
+برکت
+جنگل‌های
+سلطه
+اقیانوسیه
+علما
+بنفشه
+یال
+هولوکاست
+دادستان
+حلی
+اجسام
+غواصی
+احاطه
+والا
+بیماریهای
+صدوق
+ریو
+دیویس
+ناهید
+دهها
+نتوانستم
+ایکس‌باکس
+ول
+منبع‌ها
+تاریخی،
+کثیر
+لیتوانی
+شده‌
+بپرسم
+قربانیان
+جانشینی
+سیریلیک
+بوستون
+یونانیان
+دوبار
+فرضیه
+امروز،
+دیده‌ام
+عزيز
+۱۴۲
+میگیرد
+شلوارک۱
+مِنَ
+ارسطو
+ومبلی
+بخواند
+۱۹۰
+صوفی
+صدق
+کارب
+گذاشتند
+هزینه‌های
+فردریک
+نوشته‌اید
+آو
+عمده‌ای
+م‍
+هیچگونه
+حسی
+اللَّهُ
+معدود
+مارکس
+سنگاپور
+رایانش
+عادل
+ریگان
+میرسد
+الگوریتم‌های
+ائتلاف
+فریدون‌کنار
+بازگا
+نگرش
+هرحال
+بدانیم
+کفایت
+فین
+۱۳۲۷
+باورهای
+بازگیر
+لردگان
+چرا؟
+تعویض
+سلجوقی
+جستار
+نخواهند
+می‌نمایند
+دهستان‌ها
+فرمانروای
+خودتون
+منتقدین
+کلاردشت
+اره
+لزومی
+مرتفع
+ویر
+سندرم
+نیاید
+آجر
+دانشکده‌های
+نمین
+مق
+تن‍
+اینچ
+فوتسال
+ساکنین
+‍ه‍
+فرانسه،
+صفحاتی
+۱۹۰۲
+طالقانی
+جعبهٔ
+غارت
+بزرگسالان
+لین
+۱۶۵
+قیاس
+افغانی
+نگذاشته‌اید
+ساید
+نادری
+امامان
+سنا
+سرگذشت
+رایش
+توجیهتان
+بروند
+سمفونی
+آهنگ‌ها
+توس
+تم
+پنسیلوانیا
+خرچنگ
+مغان
+سجاد
+پایینی
+تحریر
+لوث
+شانه
+طوفان
+اصولاً
+کبودرآهنگ
+تسمیه
+عامیانه
+بیشینه
+فضاپیمای
+بودایی
+۱۸۹۰
+اقلیم
+مثالی
+جشنواره‌های
+برایان
+میرود
+پین
+آم
+سرگرمی
+مزایای
+ریال
+رسماً
+ناحیه‌های
+تازه‌ای
+می‌دهیم
+هارد
+مقال
+فراهان
+دلیلش
+میلیمتر
+۱۸۰۰
+ماهنشان
+سالار
+جت
+مردگان
+فقیر
+۱۵۵
+راستا
+میکنیم
+جوری
+شلوارک۲
+پژوهشگاه
+نیستند،
+۱۴۶
+اینشتین
+یخچال
+روزمره
+ارم
+سنین
+تحسین
+سکه‌های
+۱۳۱
+فحاشی
+پاپ‌های
+عینی
+رسانده
+رز
+بودم،
+ارزشی
+ستان
+باراک
+اصلي
+الکتریک
+نامه‌های
+عطار
+علمي
+بخشید
+السلطنه
+يعني
+غلبه
+مستقیماً
+منش
+رستاق
+افراطی
+بگیرم
+سيد
+۱۴۷
+ندارند،
+الَّذِينَ
+نمونهٔ
+کریستال
+قایق
+نوادگان
+سالیانه
+می‌پذیرد
+احترامات
+شیری
+سیاهکل
+سرب
+نصرالله
+مانه
+گیم
+ببر
+آستان
+زیستگاه
+ای،
+داده‌ام
+لوئی
+شریعت
+آموز
+رتبهٔ
+کمک‌های
+نقدها
+حلقه‌ها
+ارتقای
+هال
+انسانها
+پشتو
+امیرحسین
+سین‌آباد
+رشید
+۱۴۳
+شیرینی
+مذاکره
+تعدیل
+کارمند
+اعضاء
+روانه
+بنر
+معروفترین
+خیابان‌های
+مشاوره
+اکثرا
+افت
+کنگان
+بگذارند
+دامنه‌های
+رحم
+بیدار
+تیپ
+تنفس
+افغانستان،
+میشیگان
+استعمار
+فرخ
+گذرگاه
+توالی
+تایم
+جمله‌ای
+ولادیمیر
+دستوری
+تساوی
+ساختارهای
+جانوری
+قسم
+۱۳۱۶
+هفده
+یقین
+صوفیان
+می‌نویسند
+رومرکز
+بک
+انگشته
+مولف
+نگفتم
+یورش
+ثبات
+بیایند
+بپرهیزید
+وبا
+اس‌جی‌اچ
+جن
+ورزش‌های
+لامرد
+سپیدان
+کبک
+عزت
+افشین
+کامرون
+فیلم‌شناسی
+پاول
+نکنیم
+درگیری‌های
+رخداد
+کیا
+عرف
+شازند
+یکصد
+استهبان
+می‌گیرد،
+نرسیده
+ویژهٔ
+ابتلا
+اینطوری
+گارد
+بزن
+مدتها
+وعده
+شرف
+پيدا
+نیدرزاکسن
+زواری‌جان
+اسدخانی
+هندواروپایی
+تصویرگر
+مختص
+استادی
+هیپ
+امشب
+احیای
+بنو
+امامت
+خونریزی
+سیگار
+کاسه
+غرض
+معتقدم
+ساختم
+صفح
+روایتی
+نمادهای
+متوالی
+خدایی
+نمود،
+عجم
+آبهای
+آمده‌اند
+نموده‌اید
+لاریجانی
+شیوع
+زمينه
+الا
+بیا
+آزمایشگاهی
+آنتن
+قرآنی
+بیستون
+فاجعه
+۱۵۸
+ریه
+انعکاس
+تقلب
+هجدهم
+طبرستان
+تناقض
+مدت‌ها
+علمی،
+تصنیف
+فروغ
+دایرةالمعارف
+آلمریا
+تاسیسات
+گونهٔ
+هیچکس
+ایدز
+آوا
+۱۴۹
+مديريت
+بیاد
+پایگاه‌های
+زیرصفحه‌های
+مقاوم
+گمشده
+نشدید
+نوزاد
+سیف
+دیفرانسیل
+موافقان
+بانه
+فونت
+صفا
+واتیکان
+اصالت
+کتابخانهٔ
+یگانه
+کیت
+ترجیحات
+کنوانسیون
+نانو
+۱۵۳
+آنزیم
+كردند
+تیمی
+۱۸۵
+هستید،
+حوض
+نویسنده،
+ورد
+حسنی
+پديا
+بویین
+مادها
+ناوگان
+بنگاه
+اردلان
+صومعه
+تورنتو
+کارولینای
+۵۰۰۰
+اشکالات
+مسائلی
+انداخته
+نماند
+دستمزد
+بخواهم
+سرقت
+میدانی
+ریتم
+خوبیدگی
+پوستی
+اندی
+الماس
+بزنم
+مقدونی
+هسن
+گروه‌ها
+بروجن
+تگ
+منشی
+ملکی
+تبعیض
+ببین
+افق
+خشن
+کورین
+دوی
+قوام
+ایلینوی
+بچه‌ها
+تکاملی
+دخترش
+برانگیز
+اصطلاحی
+مل
+یکان
+داراست
+عرب‌ها
+ناموفق
+کبد
+کوفی
+رودها
+پشته
+رسالت
+مرتکب
+معروف‌ترین
+نشوند
+نبودم
+بنیانگذاری
+لیبرال
+فرید
+حوضه
+ربع
+نوح
+سیاهه
+تای
+خستگی
+پدری
+برنامه‌ها
+فرستادن
+بیطرفی
+نواب
+نزول
+استیشن
+رادار
+پخش‌کننده
+سازند
+عضلات
+سعیدی
+کوین
+بنویسند
+برم
+بیایید
+حجازی
+شده؟
+تالیفات
+حسینعلی
+نیست؛
+مزاحم
+فروشی
+آموزان
+میکرد
+۲۴۰
+بحث،
+وارنر
+کوری
+واکنش‌های
+فستیوال
+قارچ
+لغت‌نامه
+تاجیک
+شرکتهای
+هروی
+ویژگیهای
+عکسهای
+چارلی
+باشيد
+داشتیم
+بومیان
+باقیمانده
+یافت،
+اشاره‌ای
+فصلی
+عبدی
+بزرگوار
+بیتی
+مُعجَم
+نازل
+امپراتوران
+مهمتر
+کانی‌ها
+۱۸۹۶
+محمدباقر
+شایع
+ادریس
+که‌
+دهندگان
+اعلامیه
+به‌نظر
+داروی
+لیک
+اتوماتیک
+مي‌شود
+فروغی
+برآورده
+بلا
+آدولف
+قشقایی
+تنفسی
+اردوگاه
+زنجانی
+تنه
+گزیده
+مریوان
+پورنو
+کامبوج
+تل‌های
+رمزنگاری
+دامپزشکی
+شاهنشاه
+قرقیزستان
+ارابه‌ران
+نمودم
+ضرر
+بازنگری
+دگرگون
+بررسي
+شده‌بود
+ناپدید
+متاسفم
+نسخه‌ای
+اشنویه
+پیاپی
+عبدالعزیز
+۱۶۸
+اسباب
+نسبیت
+کعبه
+مردم،
+ذوب‌آهن
+آنچنان
+ادرار
+رنسانس
+سوسیال
+دهخدا،
+تختی
+فاطمی
+ماشین‌های
+پاسکال
+مینا
+تابعی
+سایتی
+توانیم
+ترين
+توران
+ادارهٔ
+فهرست‌ها
+خوشی
+معینی
+یادآور
+مخالفین
+دود
+مدام
+انی
+تقاطع
+پتاسیم
+نساجی
+ارد
+اندیمشک
+داده،
+مخالفتی
+دونفره
+اندیشه‌های
+علیزاده
+آجری
+برسیم
+اقدامی
+فقهی
+اشکان
+همبستگی
+فرادیرینه‌سنگی
+گناوه
+کوفه
+۱۸۹۹
+اینصورت
+عبدالرحمن
+لبه
+بی‌پایان
+میدهند
+منشا
+مرحلهٔ
+بیطرف
+کردید؟
+مسخره
+مشخصه
+عضلانی
+اسارت
+عنوانی
+۱۵۲
+ندارم،
+برچسب‌ها
+اچ‌آی‌پی
+منصوری
+۲۱۰
+بینم
+مجنون
+تعاریف
+تعهد
+اقتباس
+جلیل
+می‌کنید؟
+رزن
+مسئلهٔ
+فرستنده
+گان
+قاب
+کمونیسم
+تناسب
+ندای
+توحید
+هواشناسی
+کرده‌اند،
+منتها
+روز،
+شوال
+لیزر
+پس‌از
+دزدان
+دارد؛
+جنگ‌افزار
+جایزه‌های
+واحدی
+تیموریان
+ذكر
+کنده
+ترش
+می‌خوانند
+ریش
+تمایز
+پیشبرد
+زندگانی
+دلتا
+پیش‌از
+نقده
+ایرلندی
+هنرستان
+قبال
+فرصتی
+دودویی
+عليه
+زیباترین
+شاعری
+سرما
+ایلی‌نوی
+شهبانو
+پنالتی
+بهاری
+افتد
+فیروزکوه
+فایده
+۱۶۳
+بروس
+نیسان
+نکردند
+نمیتوان
+۱۶۲
+روباه
+سقراط
+کشته‌شدگان
+اورانیوم
+عملا
+طراحان
+ماهیچه
+سرم
+اوهایو
+علاقمند
+نویسد
+الجزیره
+گذشته،
+مزارع
+گزینش
+جنگهای
+اطلاعی
+نوشته‌ها
+پارلمانی
+۱۱،
+جنابعالی
+اسفندیار
+امیدوار
+ک‌گ
+گازهای
+کبود
+زمین،
+تلگراف
+لئونیداس
+گرمای
+کتابخانه‌ها
+آشوری
+طعم
+راد
+زنانه
+عربی،
+جادو
+حمیدرضا
+جنگ،
+جابجا
+ماکیان
+بیابید
+شکاف
+گلزار
+متفقین
+متاخر
+سایتهای
+بایگانی‌ها
+بهره‌برداری
+جنایی
+کارون
+شهدای
+میامی
+پدیده‌های
+هستم،
+برکلی
+نایین
+ببینند
+استانداری
+۱۶۱
+پسری
+شوالیه
+کت
+شاخه‌ای
+مقاطع
+آنوقت
+اسکو
+۱۸۹۲
+نده
+رسانید
+۲۳۰
+تاسف
+هايي
+پلدختر
+تاجیکی
+جاجرم
+وضع‌کننده
+استر
+همنشین
+زحمتی
+کانادایی
+تبلیغات،
+زهک
+دولت‌های
+ترمودینامیک
+سوری
+خلفای
+درآن
+فراگیری
+ختنه
+امیرآباد
+تروث
+بوم
+زاد
+خنج
+بروم
+سومالی
+جیم
+دیجیتالی
+عفو
+سوشی
+اصفهان،
+بلاندی
+کوچک‌تر
+گمنام
+سکوی
+نزاع
+احتیاط
+گردید،
+بزنند
+علنی
+ویلا
+۱۳۲۶
+الهه
+هدر
+ظلم
+ناو
+می‌کردند،
+الحکمة،
+یاقوت
+حتي
+شرکت‌ها
+تعلیق
+خواستند
+کاروان‌سرا
+نکتهٔ
+رشته‌ای
+باهم
+بپردازند
+درجات
+وجودی
+بودا
+نیوتن
+منطبق
+نصرت
+ال‌جی
+سومی
+فلش
+۱۳۸۵جمعیت
+فریم
+دوما
+ساقه
+اسماعیلی
+دینامیک
+المقحفی،
+المُدُن
+فیلم‌هایی
+فیزیکدان
+محضر
+آخوند
+فراهانی
+صید
+بسا
+الیَمَنِیَة
+بنایی
+۱۷۳
+می‌گوییم
+درآمده
+مورخان
+یونیکس
+جاها
+وام
+کوتوله
+۱۷۶
+ژرفای
+موجودی
+مرادی
+بدنیا
+پمپ
+پرستاری
+می‌شوید
+مناره
+انقلاب،
+برجستهٔ
+جذاب
+نوشتارها
+نمیشه
+مایک
+امیری
+چناران
+ــ
+گردو
+تفویض
+دخیل
+۱۵۹
+بنیادین
+بدیع
+سالیان
+مواضع
+وَالقَبائِل
+۱۶۹
+می‌بیند
+درگذشتهٔ
+داشته،
+قنطورس
+۱۸۹۸
+تصمیم‌گیری
+مشمول
+رودان
+فراگیر
+آمده،
+نفهمیدم
+۱۸۸۹
+شده‌اید
+نفی
+افسردگی
+می‌دانستند
+آلات
+قوت
+دانه‌های
+محمدحسن
+عزيزی
+جامی
+نجم
+طرحی
+گاندی
+جنوبی،
+بصره
+اروگوئه
+شرکت‌ها،
+پورت
+خجسته
+زمانیکه
+ریشه‌های
+فمینیسم
+گاردین
+بایست
+وار
+دیوان‌سالار
+فوتبالیست
+۱۶۷
+آلمان،
+شعله
+آناتولی
+على
+شمالی،
+سیمون
+ظروف
+رستوران
+دایر
+می‌گذارند
+تفاهم
+آناتومی
+گذراندن
+شكل
+مرگ‌ها
+آهنگسازی
+لیتر
+دزدی
+فرموده
+معصوم
+اطاعت
+تارنمای
+فارس،
+پلان
+هانس
+فریدریش
+ملی،
+روحانیت
+اوّل
+نتيجه
+وادار
+صورت،
+۱۳۰۴
+ترتیبی
+مبارکه
+بنیان‌گذار
+۱۷۹
+ژوزف
+اردستان
+افزودم
+مطبوعاتی
+ارز
+جنجالی
+نوازندگی
+سوزان
+دارن
+افتادن
+هایشان
+تحقیقی
+سهند
+سپاسگذارم
+فیزیوتراپی
+محافظ
+ماشینی
+ربر
+یدالله
+میمون
+سیاستهای
+نگارهٔ
+چه؟
+صراحت
+رسته
+تجویز
+توفیق
+مغولستان
+کین
+وال
+ساکورا
+پیشروی
+متوفی
+تازی
+دیلم
+پل‌دختر
+می‌خواست
+صدیق
+نمی‌بینم
+ایلات
+درحالی
+غلات
+نوه
+هاله
+سیستمهای
+کتیبه‌های
+سیال
+منبر
+بیک
+۱۳۱۴
+۱۳۱۸
+حسين
+۱۷۱
+درشت
+سوق
+برنامه‌ای
+گهواره
+دست‌آوردهای
+تعبیه
+رادیوی
+ساسان
+درامز
+۱۲۹۹
+تجسمی
+سیمان
+گنجی
+کشش
+اسلوونی
+ویلسون
+داماش
+إِنَّ
+کارتوگرافی
+کاشت
+دستان
+لید
+نوازندهٔ
+نمی‌شد
+قران
+ایدئولوژی
+کامپکت
+ناغان
+قرائت
+کاراکتر
+خانه‌ها
+شفاهی
+فله‌ای
+شهرسازی
+اعتصاب
+۱۸۱
+ویدیو
+شايد
+ویرایشگر
+پردازد
+داده‌اید
+حاد
+اجتهاد
+مرطوب
+کلماتی
+مهریز
+حلال
+بیافزایید،
+۱۵۷
+همجنس‌گرایان
+لینکی
+تطابق
+باورند
+دالاس
+إِلَّا
+اصولی
+کپی‌رایت
+الفبا
+کیهانی
+تاب
+شرعی
+محتوی
+هانری
+می‌دهند،
+یوگسلاوی
+بگذارم
+تداوم
+گریز
+نشده‌اند
+شناخته‌شده
+انعطاف
+اندک،
+دعوا
+کری
+تبیین
+احساسی
+ساعات
+معاصر،
+پیشوند
+طبع
+میاندوآب
+اخترفیزیک
+مطمئنا
+پرسید
+انگل
+برکناری
+رولینگ
+حفاری
+زیارتگاه
+منتسب
+پیام‌های
+گسسته
+طريق
+باخ
+۱۳۲۳
+کلیساهای
+معصومه
+شهروز
+متناوب
+۱۸۹۵
+پن
+ابراهيم
+۱۳۱۳
+بطوریکه
+رابین
+آموخته
+میدان‌های
+تاریخ‌نگاران
+بکر
+میش
+پخته
+قلمداد
+رویا
+باشید،
+سیستانی
+قومیت
+جرمی
+لوس
+آفرین
+تلف
+خوارزمی
+محتوایی
+سول
+دبط
+جُستارهای
+می‌نمود
+روزنامه‌ها
+یت
+دگر
+بانکی
+سدان
+متغیرهای
+یابند
+بکارگیری
+انتاریو
+کوسه
+۱۶۴
+بلخی
+بیم
+خلخال
+حائری
+۱۸۹۳
+آورده‌اند
+نقطه‌ای
+علمجو
+استیل
+سلولهای
+گوگرد
+میتوانند
+گوارش
+سبزی
+۱۶۰۰
+جوراب۲
+زیرین
+ميشود
+پنبه
+آورد،
+حرفهای
+لنگرود
+فریمان
+سلاح‌های
+میانگین‌جریان
+غبار
+مردانه
+مؤسسهٔ
+اسراییل
+تک‌نواز
+۱۶۶
+لکی
+خبرنگاران
+پالایشگاه
+مصلحت
+۱۷۷
+مجروح
+پرستش
+دوگانه
+مدفون
+ولیعهد
+سرزمینی
+آق‌قلا
+اساسا
+بهر
+ملي
+كنار
+روستاي
+کلاس‌های
+سفره
+نرمال
+وری
+کیف
+۱۸۸۰
+۱۹۸
+زدید
+زراعت
+رهنمودها
+توضيح
+۱۷۲
+۱۹۲
+پدیدار
+وایت
+بمانند
+لرد
+دستم
+ایسلند
+لیقوان
+نیافتم
+باتشکر
+تئودور
+عبادت
+تبديل
+نکردید
+مسلحانه
+دیزنی
+رانش
+فرهنگ‌های
+مخاطبان
+دول
+کتابت
+سلیم
+ایرانی‌تبار
+غلظت
+شونده
+۱۲،
+اوراق
+سامانی
+اقتصادی،
+۲۵۰۰
+شخصیت‌ها
+فحش
+سربازی
+هشداردهنده
+ندرت
+۳۲۰
+می‌شه
+۱۸۹۷
+فروهر
+صلی
+سیوند
+انجمن‌های
+بعلاوه
+ترشح
+فرج
+جاي
+بخیر
+محراب
+کارتان
+هجده
+قریه
+ربیع‌الاول
+ضخامت
+بارندگی
+بح
+نسیم
+زهره
+جادویی
+تالاب
+جنون
+بروی
+۱۳،
+فیلد
+کریسمس
+میزبانی
+می‌کنید،
+آپلود
+برگزیدگان
+یش
+خانواده‌اش
+کریستوفر
+بیننده
+توکلی
+می‌سازند
+لنگ
+تداخل
+مقدمات
+۱۸۹۴
+الوند
+مع
+گناباد
+مزدا
+رکن
+عیلام
+ترقی
+منکر
+معامله
+اینچنین
+کول
+سازمان‌ها
+مأموریت
+موعود
+دولت‌آباد
+بلبل
+طولی
+می‌رسند
+اجاق‌کندی
+ديگري
+ندارد؟
+براین
+مصور
+اعتقادی
+فرخزاد
+درباره‌ی
+خداآفرین
+گفتاری
+خوانی
+پارامترهای
+تهاجم
+آیوی
+توضیحاتی
+بشرویه
+۹۷۸
+کیست
+نداشت،
+شهروندی
+برخي
+۱۵۶
+سمرقند
+نوا
+كمك
+لامپ
+عماد
+رام
+اينکه
+ضمیمه
+بنابراین،
+تصویربرداری
+سیبری
+یوفا
+کلر
+گوجه
+حیف
+سواری
+۱۳۱۲
+طارم
+۲۶۰
+اباد
+عنوان‌های
+مركز
+مقوله
+گوستاو
+مرعشی
+بحر
+تون
+انصار
+جداسازی
+تصفیه
+سازندگان
+ببنید
+محافل
+نقره‌ای
+تیرماه
+پیاز
+سرسبز
+انه
+چشمان
+تایباد
+اشیا
+طرد
+گوهر
+نکن
+هرزگوین
+اقلید
+خاص،
+ثالث
+علی‌رضا
+آنگونه
+مستمر
+عضوی
+هامبورگ
+پورتال
+تویوتا
+رامیان
+هخامنش
+اردل
+قاطع
+گنجینه
+روشنفکران
+تصادف
+۱۹۷
+جزیی
+مؤسس
+روبروی
+آلاسکا
+خوشه‌مهر
+آرد
+صالحی
+سونامی
+کشیش
+پروس
+انحصاری
+کاسته
+دوستانش
+گاوران
+دلالت
+۱۸۴
+اصحاب
+جزیره‌ها
+مهدوی
+آبیک
+افزايش
+مزیت
+جوابی
+صغیر
+منحنی
+رمین
+سانتیگراد
+دبیرکل
+غریب‌دوست
+بنزین
+اپیزود
+استانهای
+بهاءالله
+سپید
+کمونیستی
+سوگند
+شهباز
+اکتشاف
+استحکام
+مفاد
+بسازد
+اسکناس
+۱۴۰۰
+مبدأ
+بخورد
+مناظر
+زا
+پرستی
+تمبکا
+محرمانه
+سکنه
+زیتون
+رومانیایی
+جسارت
+عمومی،
+دات
+آهنی
+بینید
+مخابراتی
+نظرش
+مولداوی
+العظمی
+ولف
+ممکنه
+راننده
+اولاً
+وَمَا
+وسیله‌ای
+موی
+بادلو
+چرب
+مسافت
+مکس
+۱۷۸
+پودر
+عوام
+که،
+پنجم،
+گرگوری
+میسر
+مفصلی
+استبداد
+حیدرآباد
+آلیس
+فیروزه
+ریخت
+اینان
+کروی
+وقف
+شعارهای
+۱۹۶
+سملقان
+فروخته
+۱۷۴
+نبوده‌است
+دیکتاتوری
+میدهم
+ظریف
+معتبرترین
+سیاسر
+ایرادات
+اجماعی
+۱۹۳
+منحل
+زاید
+میخواهم
+صاحبان
+مهلت
+می‌پرداخت
+ماهه
+جری
+بازرس
+وَلَا
+گلشن
+برهنه
+نوشته‌ام
+می‌شود؟
+صخره
+عمو
+ابد
+بیداری
+۱۸۸۸
+۲۷۰
+بعلت
+پنیر
+حاتمی
+خانقاه
+رس
+شکسپیر
+معذرت
+پايان
+ساختگی
+آموختن
+فقدان
+پاسخگویی
+زانو
+كوه
+لزوما
+قمر
+شهریاری
+بيان
+واین
+صورتیکه
+بدنبال
+پاره‌ای
+ارمغان
+می‌شود؛
+شغلی
+دیگ
+عنبرآباد
+امریکایی
+پیشرو
+تجربیات
+علوم،
+پیری‌کندی
+ازجمله
+به‌نام
+صومای
+۳۳۰
+۲۶،
+اسطوره‌های
+منفجره
+دستتان
+رشته‌کوه
+۱۹۵
+برن
+بلده
+شیعی
+رحیمی
+رجایی
+کجور
+۱۵،
+تاون
+آموزگار
+آستارا
+هیل
+ترانه‌ها
+یوری
+کلاله
+محو
+خوانندگی
+زار
+عیب
+افسانه‌های
+پخت
+نامبرده
+پنجشنبه
+سور
+نروژی
+تکنیک‌های
+دریاچه‌های
+مالدیو
+سوسن
+کیسه
+کاوش
+دابودشت
+کردن،
+زندگان
+مقدمه‌ای
+موزهٔ
+۱۸۸
+برپایی
+داگلاس
+فضل‌الله
+زینب
+اللَّهَ
+صحرایی
+کرت
+اذیت
+نمی‌رسد
+آتشفشان
+۱۳۲۱
+بلاروس
+انگ
+ارگان
+بسامد
+نشوید
+بزرگای
+کلارک
+۲۱،
+بشدت
+نقوش
+خوشنویس
+الفبایی
+نخ
+رفیق
+ناراحتی
+رسی
+بخواهند
+طرفداری
+دردسر
+۴۵۰
+۱۸۳
+ایرباس
+پرت
+فرآیندهای
+گردشگران
+مخرب
+میگم
+کارتون
+نوژن
+سفری
+صندلی
+می‌کرده
+نزنید
+ج۱
+میخواهید
+گنگ
+می‌ریزد
+پشتکوه
+ویکی‌پدیاست
+دلاری
+ویکیفا
+خيلي
+بازگشایی
+چشمگیری
+نیتروژن
+بافی
+لانه
+بدید
+آشتیانی
+باشد؛
+محققین
+۲۴،
+یوتا
+طرفه
+توسعهٔ
+کشتی‌های
+۲۰۶
+جاستین
+شوشتری
+اسمیت‌سونیان
+طوطی
+عباسیان
+رده‌ای
+زرند
+می‌رود،
+ابتکار
+دهلران
+بستان
+برجای
+۳۸۰
+رمانتیک
+ترجمه‌های
+کاربرها
+بندری
+پرداختن
+منهتن
+پاتریک
+طناب
+چهارم،
+نتواند
+بور
+دانسته‌های
+روحیه
+میلاد،
+برزنجیر
+مرجان
+دهند،
+شهرستان‌ها
+سپرد
+داران
+استوارت
+دوچرخه
+طراحي
+۱۱۰۰
+خانه‌ای
+نوآوری
+نامنظم
+کامپیوترهای
+دیوانسالاری
+وفادار
+هرودوت
+امسال
+استثنا
+فرانکفورت
+مجالس
+خدمتتان
+کتابداری
+لاین
+پوران
+آنالوگ
+برادوست
+۲۰۸
+شادباش
+می‌شناسند
+بولکیمده
+می‌نویسم
+چالدران
+کهنوج
+تطبیقی
+۱۶،
+دیدگاهی
+منحرف
+شنوایی
+تیز
+تیغ
+موشکی
+پرشیانا
+امیل
+ایزدان
+سه‌گانه
+پنجه
+۱۸۹۱
+۱۳۲۲
+دين
+قبله
+جهنم
+خدماتی
+ببرند
+مأمور
+نیستیم
+کلمه‌ای
+اعتیاد
+فرانکلین
+معجزه
+ذهنم
+بازماندگان
+مصوبه
+کلینتون
+برسند
+معاهده
+نمیکنم
+چندگانه
+شهرستانی
+لاک
+موضوعاتی
+خوسف
+اسک
+خروس
+لتونی
+وات
+کرد؛
+رودکی
+خدمتم
+تاری
+مجلسی
+فهمید
+هفتگی
+کروز
+برگرداننده
+قیصر
+معروفی
+فكر
+نو،
+فضانورد
+فتح‌آباد
+هورمون
+الفاظ
+آمازون
+بیاوریم
+دستهٔ
+می‌کردید
+بینایی
+پافشاری
+بردم
+دیپلماتیک
+سنگینی
+نمره
+غیرآزاد
+فریب
+پذیرد
+حیطه
+اصلی،
+تربیتی
+محال
+ارجمند
+می‌یابند
+فلج
+اربر
+اینجا،
+آوای
+دودانگه
+چاه‌بهار
+همزه
+۲۳۸
+تمبر
+انوشیروان
+متن‌های
+پشتوانه
+عجب‌شیر
+قسمت‌ها
+آشوب
+بدرود
+نظرشان
+ه‌های
+روزتان
+استفان
+گیتاریست
+نشده،
+دینار
+چاره
+تیموری
+زهی
+مغولی
+۲۵۶
+هیوستون
+الموت
+۱۸۷۹
+راگبی
+لوکزامبورگ
+حیث
+عاج
+سخت‌افزار
+رمانی
+نگهبانی
+پتروشیمی
+چادر
+صلیبی
+کنکور
+کانسار
+بلوچ
+زاهدی
+هستید؟
+دوبله
+طیفی
+نشریه‌های
+زنبور
+حزب‌الله
+اخوان
+اجزاء
+ژنو
+دعای
+مزمن
+سخنی
+نهایتاً
+اندرو
+میشوم
+۱۸،
+دارمشترانگ
+می‌دارند
+سه‌شنبه
+حفره
+زرندیه
+ذخایر
+۱۳۱۹
+زنجیر
+سبکی
+قیمتی
+جنیفر
+۲۰،
+تعمید
+آبگرم
+حکمرانی
+پلاستیک
+بی‌نزاکتی
+تماشاگر
+لایحه
+بازه
+تحکیم
+موضعی
+جویی
+محافظة
+شاه،
+ما،
+۳۰،
+آمبرلا
+کلرادو
+هیجانی
+مجتهد
+گیاه‌شناسی
+اضطراب
+جنگ‌افزارهای
+۱۹،
+ادوار
+مسیری
+چمران
+پایه‌های
+گیتاشناسی،
+نمی‌کنید
+گیل
+متین
+آدلر
+۱۷،
+بعدش
+باکس
+یاس
+حکمیت
+کیلوبایت
+بریده
+هموار
+معقول
+کروم
+۱۸۸۶
+غزنوی
+نوش
+بازنشستگی
+گوینده
+یک‌نمونه
+هنر،
+میاد
+عظمت
+جهش
+جانبداری
+شبكه
+آسا
+استاندار
+۲۰۹
+فرانسیسکو
+بریتنی
+محدودیت‌های
+بشکه
+بنگرید
+تاثیرات
+آسفالت
+گیج
+کاروان‌سراهای
+فراموشی
+گلدار
+ترتیب،
+يافت
+همینجا
+بدخشان
+۲۵،
+تمدید
+زيادي
+هستش
+رضا۱۶۱۵
+بودی
+مهرماه
+اسکندریه
+لزوماً
+سیستمی
+هارون
+نگفته
+می‌دانیم
+سایوز
+آن‌را
+نوزده
+بمبئی
+فان
+میدانند
+۱۸۷
+دانستند
+اجاره
+فورت
+مراقب
+نفرت
+نوی
+۲۰۴
+تدریجی
+تهی
+نورآباد
+گزاره
+کلامی
+نتیجه‌ای
+پانک
+هاكل
+عفونی
+بسر
+پیشگامان
+بلاغ
+زئوس
+بريفين
+گزارش‌های
+نمایندهٔ
+سیالات
+۱۸۲
+فارسان
+جلدی
+فلک
+تحقیر
+فهمیدم
+ناتو
+سایرین
+شناور
+انستیتو
+نیکو
+مارکسیسم
+تبعیت
+تفریح
+زبان،
+گلوگاه
+بقیهٔ
+کمپین
+احراز
+بودن،
+محکومیت
+کماکان
+بستری
+تروریست
+سرواژهٔ
+دانمارکی
+آمستردام
+همی
+داوید
+کافیست
+دنی
+رون
+۶۰۰۰
+لابد
+کانتری
+سس
+کسری
+می‌فرمایید
+سیاستمدار
+حریم
+معنویت
+عسکری
+بخشیدن
+محصور
+مدافعان
+گرایش‌های
+واگن
+حجر
+سرداران
+مشهود
+یافتم
+تنسی
+نهر
+دارالفنون
+نمايش
+بسياري
+سابقهٔ
+یتیم
+توپولوژی
+۱۴،
+نگارشی
+جمعيت
+تنبیه
+کیو
+سقط
+شریفی
+کما
+میکروبیولوژی
+دیابت
+تاتنهام
+منقرض
+تاتی
+محمددین
+انگليسي
+فارسی‌سازی
+زمینهای
+شهدا
+۰۸،
+متکی
+کوه‌ها
+دزد
+کنایه
+مشایخ
+ارزان
+ماسه
+هرمان
+تنظیمات
+اونجا
+خار
+هیلاری
+چنار
+خزانه
+شکاری
+عجایب
+رنو
+قراردادن
+جابر
+سروستان
+مستطیل
+مجموعه‌ها
+بهمیی
+یکسال
+سرخرگ
+نادرشاه
+لیاقت
+دوستار
+وارده
+کاستیا
+لرزه
+اى
+بجا
+نم
+مغولان
+امارت
+کشاورزان
+طبی
+کجاست؟
+نبح
+نمایم
+للطباعة
+بکنند
+داستان‌ها
+آمیخته
+تاريخي
+اندازه‌ای
+پیکار
+مستعمره
+کوهپایه
+تصدیق
+۱۳۱۵
+فیلترینگ
+۰۹،
+آدینه
+توبه
+بصری
+بکنیم
+هوتک
+فیلم‌نامه
+پشتون
+زمره
+حبیبی
+اسکندری
+نیایش
+هائی
+رقابت‌های
+داوطلب
+ازش
+بنظرم
+دلیجان
+رضی
+مصاحب
+پرون
+بازگو
+آگهی
+قولی
+سیسیل
+انگلیسی‌ها
+مکاتب
+حبیب‌الله
+سانسکریت
+توکل‌آباد
+نموده‌اند
+حیوانی
+پروژه‌ها
+گیتی
+فالتز
+سنگسار
+بخت
+میلانی
+مارکوس
+نید
+شدیم
+۲۲۴
+مش
+فصول
+کتابش
+می‌خواهیم
+مشی
+آنی
+مادهٔ
+میکردند
+یکا
+طلبان
+عهدنامه
+الملل
+ارکان
+کاربریتان
+جلال‌الدین
+ایرونی
+یونس
+آبراهام
+فرشتگان
+فارسی‌زبانان
+۲۰۳
+۳۵،
+ناتمام
+موظف
+ایت
+می‌زنم
+ییلاق
+منی
+كم
+گریه
+بسازیم
+سیبک
+انجا
+موفق‌ترین
+۱۳۰۷
+ثروتمند
+گریخت
+زمان‌دار
+تروا
+ژرمنی
+برنارد
+تشكر
+ژنریک
+راهبردی
+گره‌های
+پارسی‌گوی
+بندهای
+مبادله
+اسفندیاری
+سرتیپ
+خوارزم
+کلاغ
+ياد
+ايراني
+نجف‌آباد
+سولفات
+كامل
+ناظری
+شهرستانهای
+أَنْ
+میگ
+پادگان
+مرتضوی
+زياد
+کلود
+مقاصد
+بهارستان
+دیکتاتور
+باستان،
+۳۱،
+اسکای
+الکلی
+میباشند
+پارتی
+بیاورند
+لایه‌های
+پرتقال
+آمیزی
+۴۰،
+۱۸۶
+رستاخیز
+خرگوش
+فیبر
+لیبرالیسم
+مخترع
+تعمیم
+برمی‌گردد
+تل‌آویو
+خورش
+مولد
+ستم
+باغات
+نژادهای
+ضربات
+آنست
+ارواح
+جوار
+اپرای
+تحتانی
+آنتوان
+زحمتش
+۱۸۸۲
+بازگشتی
+رفت،
+۱۸۹
+هوگو
+گیلاس
+۲۰۵
+دستاوردهای
+قضائیه
+۴۰۰۰
+مستقلی
+رعنا
+بخوان
+۵۶،
+سوزی
+تلاشی
+هرکسی
+میلی‌متر
+هفته‌نامه
+برومند
+کباب
+سرمایه‌گذاری
+پلاتین
+دنیس
+وگاس
+قرآن،
+نصرت‌آباد
+۲۲۵
+۱۹۱
+بافق
+ژاله
+آبریز
+صدد
+املاک
+مقاله‌
+بوانات
+پژو
+زمان‌ها
+کامیاران
+پگاه
+۲۰۲
+حرف‌های
+ترغیب
+حک
+مسطح
+دی‌وی‌دی
+جانبه
+سفیران
+غدد
+هستند؟
+مدرسه‌های
+۵۲،
+منبع‌دار
+چاله
+نائین
+مدير
+عکاسان
+آب‌خورده
+فیات
+خبرنامه
+مشهدی
+استرالیایی
+سیامک
+بگیر
+شایان
+درسته
+نامند
+ویرایشهای
+گل‌ها
+مایا
+گروه،
+آتشفشانی
+کرده‌است،
+نیمهٔ
+آزادشهر
+رانده
+علاقه‌ای
+ثریا
+متشکر
+ولت
+فرزانه
+صورت‌های
+دانشگاههای
+وز
+ویدئوی
+جنازه
+برتون
+جلوه‌های
+تغییرمسیرهای
+بیانیه‌ای
+دون
+نبوی
+یک‌بار
+رک
+حزب‌های
+مدارهای
+میگویم
+كنيم
+معلق
+تماشاگران
+نش
+نصیر
+۱۹۴
+رضاخان
+گردد،
+کنسول‌های
+قسمتهای
+شورشیان
+دقیق‌تر
+مداخله
+علاءالدین
+استنباط
+مصرفی
+باردار
+اهورامزدا
+ادبيات
+باهنر
+مقرر
+عزاداری
+كلمه
+خونین
+محدودی
+نمی‌دارد
+ذوق
+پرسش‌های
+بریم
+قشر
+۳۸،
+صالح‌آباد
+محسنی
+تخلص
+شکل‌های
+شوی
+رنگ‌ها
+توربین
+مگابایت
+فسفات
+واجد
+اهانت
+محفل
+برحسب
+گیگا
+گيرد
+۱۸۷۰
+صنفی
+تن‌تن
+برگردانده
+دایناسور
+لای
+می‌بینیم
+۰۴،
+فرمائید
+سیارات
+۵۱،
+تص
+سرودهای
+معترض
+ممكن
+متا
+می‌شویم
+ثلاث
+گفته‌های
+بی‌طرفانه
+هاپ
+نهان
+ادارات
+عجیبی
+جنایات
+دستورالعمل
+پارا
+نهادند
+ام،
+فتنه
+فواصل
+۱۸۵۰
+توریستی
+مرمر
+دیتابیس
+۴۲،
+کلیات
+۱۸۸۳
+لنین
+بلكه
+کاتوزیان
+میسیسیپی
+معاویه
+یوونتوس
+کشاورزی،
+هوافضا
+كوخرد
+فاریاب
+محيط
+نکنید،
+میترا
+رنگین
+آلپ
+آلومینیوم
+ملودی
+سیاستمداران
+گمر
+اسکان
+مختصری
+قشون
+جوادی
+رباتی
+۲۱۱
+جایز
+۲۷،
+محمودی
+كاربران
+یافته‌اند
+بگذریم
+محوری
+زمان‌های
+۲۲،
+انصراف
+میلا
+ساير
+۲۱۴
+تصریح
+۳۶،
+۲۸،
+آلباسته
+وظیفهٔ
+آذرشهر
+خدمه
+بارانی
+فیزیک‌دانان
+۱۸۸۴
+تماشای
+۱۳۱۱
+نويسنده
+علامرودشت
+افزاری
+گلشیری
+عملیات‌های
+داس
+ناخواسته
+هوتن
+واسه
+ثانیا
+لینه
+سنج
+اروپا،
+ایلیا
+بازمانده
+بشریت
+شناسی،
+۱۷۰۰
+کالیفرنیا،
+نکرده‌ام
+سیلیکات
+آزاده
+کامنت
+یونیکد
+آمدم
+احضار
+توده‌ای
+فرایندهای
+بیماری‌ها
+آخه
+تبلور
+۰۷،
+۲۰۷
+مونوبوک
+تصمیمات
+اختراعات
+جشنوارهٔ
+مشاهدات
+ریزشگاه‌ها
+۲۹،
+فیلادلفیا
+یزید
+سکولار
+خشایارشا
+سنتور
+محافظه
+کاپ
+نادرستی
+علی،
+محیط‌های
+منفرد
+اهتمام
+القاعده
+علاقهٔ
+لرزش
+عصبانی
+پسند
+لیل
+۲۲۶
+جدای
+جواهر
+ژولیوسی
+کوچک،
+شمیرانات
+بخوانند
+ربیع‌الثانی
+۵۰،
+۲۳۵
+توپخانه
+نیکلاس
+ویستا
+فردیناند
+۲۸۰
+تشییع
+نمیکند
+موسیقی،
+نیرومند
+۱۸۷۸
+غفاری
+بفتا
+هویدا
+صدیقی
+سلیمانی
+سياسي
+شهرضا
+جوانرود
+انتشاراتی
+شخصه
+۵۵،
+آسیاب‌های
+خوب،
+راههای
+والنشر
+حماسی
+عکسها
+۲۱۲
+۱۸۸۵
+تعریفی
+قاسمی
+مصادف
+مفرغ
+گشتاور
+۱۸۷۵
+شکل‌گیری
+طهماسب
+موجودیت
+ستاره‌ها
+آوردید
+سازه‌های
+۲۱۷
+ببریم
+ارسنجان
+بیدگل
+مگه
+عبادی
+فایل‌های
+۱۸۷۶
+تبریز،
+رهنما
+سپر
+قاره‌ای
+وو
+جعبه‌ای
+دانش‌نامه
+اجتماعي
+هیجان
+کارتر
+نرسید
+۳۳،
+کارم
+نمی‌شود،
+نسل‌کشی
+نمونه،
+صمد
+دریک
+میله
+پلاسما
+زاغ‌ده
+داروین
+۴۴،
+ویس
+قاچاق
+املای
+نامیدن
+گنجانده
+شادگان
+نی‌بید
+۲۲۲
+تسهیل
+هلن
+ناپدیدشدن
+خط‌ها
+ابلاغ
+شمع
+بازی،
+فندقاع
+جوهر
+پترزبورگ
+هخ
+سکو
+۴۱،
+یاسر
+۵۷،
+مستلزم
+آلبومی
+کلک
+ضخیم
+پاشا
+۲۳،
+۱۸۸۱
+دی‌ان‌ای
+حساب‌های
+غلامعلی
+خواندند
+معلمان
+همیلتون
+مداری
+مست
+تصویرها
+اندیشهٔ
+شدیداً
+دیواندره
+کنن
+بشوند
+نیامد
+مانگا
+۱۳۱۷
+چسب
+شجاعت
+مشتاق
+ایرا
+دانا
+بریتیش
+ویکی‌پدیاها
+مهم‌تر
+روبرت
+کافه
+ئی
+ارضی
+دست‌کم
+دندان‌پزشکی
+مهرآباد
+كننده
+رضوانشهر
+پراگ
+پال
+فرسایش
+درگاه‌ها
+راور
+میکروسکوپ
+فشارهای
+آرزومندم
+مصاحبه‌ای
+ویولن
+دریافت‌کنندگان
+نجیب
+سئول
diff --git a/perf/texts/hi-words.txt b/perf/texts/hi-words.txt
new file mode 100644 (file)
index 0000000..1dc18dc
--- /dev/null
@@ -0,0 +1,10000 @@
+के
+में
+की
+है
+का
+और
+से
+को
+है।
+एक
+पर
+श्रेणी
+वार्ता
+भारत
+हैं
+भी
+यह
+शीर्षक
+पूर्व
+लिए
+गाँव
+ईसा
+उत्तराखण्ड
+किया
+ने
+इस
+संवत
+कि
+हिन्दी
+जो
+।
+जाता
+गया
+या
+जिले
+वर्ष
+जिला
+नहीं
+कर
+साँचा
+ही
+हैं।
+करने
+हो
+रूप
+था
+साथ
+द्वारा
+जन्म
+तहसील
+फ़िल्म
+होता
+तथा
+बाद
+विकिपीडिया
+आधार
+अन्य
+प्राचीन
+कुछ
+सदस्य
+अपने
+इसके
+प्रदेश
+तो
+एवं
+तक
+चित्र
+बाहरी
+राज्य
+जा
+प्रकार
+सरकार
+नाम
+दिया
+होती
+स्वागत
+कई
+वह
+बिहार
+करते
+सप्तर्षि
+जैसे
+थे
+समय
+अनुसार
+आदि
+वे
+सकते
+अधिक
+वाले
+किसी
+आधिकारिक
+सकता
+कड़ियाँ
+भारतीय
+उत्तर
+मण्डल
+हुए
+न
+जाती
+प्रखण्ड
+हुआ
+क्षेत्र
+लेख
+द
+बनी
+होने
+उसके
+करता
+इन
+अंग्रेज़ी
+संदर्भ
+थी
+था।
+शक
+कारण
+भाषा
+बहुत
+स्थित
+पहले
+उनके
+प्रसिद्ध
+सहायता
+जब
+दो
+अपनी
+कोई
+सबसे
+अलावा
+स्थान
+होते
+कम
+विश्व
+लिये
+ये
+जाने
+बारे
+लेकिन
+प्रयोग
+उन्होंने
+राष्ट्रीय
+वर्षों
+कहा
+पृष्ठ
+गए
+रहा
+आप
+देखें
+व
+एक्स्प्रेस
+तरह
+मे
+करना
+शामिल
+सभी
+प्रमुख
+आंध्र
+इसी
+अमेरिका
+प्राप्त
+करें
+अन्तर्गत
+इसे
+माना
+सितंबर
+उस
+५७
+इसका
+जानकारी
+नगर
+मुख्य
+हुई
+शिक्षा
+उन्हें
+संस्कृत
+कलियुग
+बीच
+गई
+विक्रमी
+रहे
+उपयोग
+मार्च
+पोर्टल
+काम
+वेबसाइट
+जनवरी
+कुमाऊँ
+उसे
+शहर
+जाते
+उनकी
+लोग
+जिसमें
+देश
+दी
+संघ
+थे।
+भाग
+लोगों
+जीवन
+१
+कार्य
+जी
+फिल्म
+विशेष
+बार
+ओर
+२
+इतिहास
+कभी
+दोनों
+अब
+निर्माण
+२००९
+पुरस्कार
+वाली
+शब्द
+पताका
+अधिकांश
+चिह्न
+विकास
+धर्म
+केवल
+लिया
+ए
+दक्षिण
+पुराने
+जुलाई
+यहाँ
+नया
+स्टेशन
+फिर
+लगभग
+संयुक्त
+अलग
+आन्ध्रप्रदेश
+गढ़वाल
+स्थल
+दिल्ली
+ई
+आरम्भ
+अपना
+जून
+विस्तृत
+यदि
+प्रान्त
+इसकी
+सूत्र
+शुरु
+मंदिर
+जालपृष्ठ
+जिसे
+घटनाएँ
+कृषि
+दौरान
+करती
+निधन
+दिन
+संगीत
+यहां
+तीन
+क्योंकि
+इसमें
+साहित्य
+ऑफ़
+मूल
+भूगोल
+॥
+पास
+पटना
+नए
+हालांकि
+सिंह
+प्रदर्शित
+प्रतिरूप
+अप्रैल
+बात
+विषय
+टेनिस
+२०१०
+प्रतियोगिता
+प्रचलित
+कहते
+विज्ञान
+विभिन्न
+अगस्त
+ऑफ
+पद्धति
+छत्तीसगढ़
+सन्
+जाना
+शुरू
+बना
+समूह
+अनेक
+थी।
+ता
+प्रामाणिक
+मध्य
+रही
+सूची
+संख्या
+व्यक्ति
+ऐसा
+गणना
+प्रति
+आज
+तब
+उनका
+क
+इलाहाबाद
+ऐसे
+मैं
+काल
+हम
+युद्ध
+गया।
+वाला
+श्री
+आदर्श
+स्थिति
+सी
+सकती
+दिसंबर
+प्रदान
+विक्रम
+विश्वविद्यालय
+रेलवे
+बड़े
+सामूहिक
+किया।
+किए
+राज्यक्षेत्र
+यातायात
+उन
+चार
+उपरोक्त
+दर्शाता
+बन
+अर्थ
+अलीगढ़
+दूसरे
+तौर
+गयी
+५८
+अन्तर
+उत्तरा
+राजा
+प्रभा
+क्या
+घटित
+मानकर
+विभाग
+कैलेंडर
+देने
+बनाने
+खेल
+प्रथम
+हिंदी
+इन्हें
+एकल
+उसकी
+एंड
+मसीह
+अथवा
+अमेरिकी
+जहां
+उदाहरण
+कलाकार
+निकाले
+आवश्यक
+७८
+महत्वपूर्ण
+पुरुष
+मई
+नदी
+जिसके
+प्रभाव
+आम
+जूलियन
+योगदान
+किये
+अधारित
+ले
+अधार
+इस्तेमाल
+सेवा
+३०७६
+जिसका
+३१०२
+पंचाग
+६६७६
+चर्चा
+भोजपुरी
+कैसे
+उर्दु
+कलेण्डर
+करके
+चाहिए
+स
+कला
+उपलब्ध
+जनसांख्यिकी
+साल
+काफी
+फर्रुखाबाद
+आगरा
+कंपनी
+३
+उच्च
+अक्तूबर
+आ
+मेरा
+स्तर
+नवंबर
+नीचे
+देता
+अध्ययन
+जारी
+कोड
+पहली
+प्रणाली
+अगर
+ओपन
+ध्यान
+उसका
+नामक
+बड़ी
+जल
+नैनीताल
+अक्सर
+अंग्रेजी
+सरकारी
+वर्तमान
+रंग
+जिससे
+मेल
+पुलिस
+रखा
+प्रत्येक
+हर
+बनाया
+ट्रेन
+सामान्य
+दुनिया
+भूमिका
+लिंक
+दे
+जबकि
+सन्देश
+शरीर
+पता
+भागलपुर
+विचार
+जहाँ
+लगा
+लेकर
+बड़ा
+वर्ग
+आगे
+छोटे
+तथ्य
+समाज
+पानी
+इससे
+उसने
+देशों
+महिला
+इसलिए
+देना
+पर्यटन
+एस
+परिणाम
+अल्मोड़ा
+सब
+स्थापना
+बाह्य
+स्थापित
+पौड़ी
+दल
+माध्यम
+आधारित
+पश्चिम
+प्रदर्शन
+सर्वश्रेष्ठ
+चीन
+शक्ति
+बाहर
+बी
+ऊपर
+बेगूसराय
+उत्पन्न
+हेतु
+डी
+आशीष
+अतिरिक्त
+समान
+वीं
+हिन्दू
+गये
+परिवर्तन
+आधुनिक
+लिखा
+कुमार
+देखा
+अंत
+मार्ग
+मानव
+रेल
+अक्टूबर
+आपको
+घर
+प्रश्न
+दूर
+कन्नौज
+भटनागर
+सामाजिक
+प्रकाशित
+अभिनेता
+देते
+कुल
+अभी
+जिस
+होना
+आई
+४
+पूरी
+संबंधित
+रहता
+ज्ञान
+ब्रिटिश
+कृपया
+हस्ताक्षर
+व्यक्तिगत
+बिना
+नई
+रोग
+१०
+दशक
+अधिकार
+परिवार
+शैली
+लेखक
+संस्करण
+जिनमें
+सेना
+संबंधी
+औरंगाबाद
+प्रक्रिया
+यात्रा
+२००८
+नये
+आवश्यकता
+ऐसी
+स्वयं
+होगा
+संबंध
+चिकित्सा
+मात्रा
+परियोजना
+प्रबंधक
+१५
+विकसित
+संदेशों
+होकर
+प्रकाश
+पहाड़ी
+पहला
+आकार
+सुधार
+जगह
+पन्ना
+सही
+मैथिली
+तैयार
+नवम्बर
+पिता
+मुक्त
+क्षेत्रों
+रचना
+१२
+२००७
+पूरा
+पी
+संस्थान
+५
+लोक
+१३
+चरित्र
+तुलना
+हुआ।
+लाल
+उत्पादन
+जनसंख्या
+रहते
+उसी
+इनके
+ा
+१४
+संदेश
+ज्यादा
+शताब्दी
+मृत्यु
+साधारण
+पाकिस्तान
+मास्टर्स
+दूसरी
+पुस्तक
+भगवान
+इनमें
+पूर्ण
+लाभ
+टीम
+बैंक
+अवधि
+भिन्न
+खिलाड़ी
+ली
+सदस्यों
+आने
+प्रयोक्ता
+कार्यक्रम
+सीमा
+समर्थन
+संस्कृति
+े
+अंतिम
+स्कूल
+बने
+विकि
+टी
+अ
+पाया
+नही
+र
+सदी
+फरवरी
+मुझे
+सन
+परिचय
+लेने
+मेरे
+पार्टी
+उत्तरी
+लिखने
+१८
+दिसम्बर
+राम
+भर
+विशिष्ट
+मी
+क्षमता
+प्रयास
+सहित
+पश्चिमी
+सिद्धांत
+दर्शन
+सभा
+किंतु
+वर्णन
+विधि
+श्रृंखला
+बजे
+संगठन
+गीत
+एम
+बेबल
+राजधानी
+प्रभावित
+पौडी
+ठीक
+सुझाव
+गति
+प्रबंधन
+व्यापार
+सामग्री
+ना
+एन
+दृष्टि
+दिया।
+पद
+ब्रजभाषा
+म
+सूचना
+शोध
+नामांकन
+अवधी
+लोकप्रिय
+आन्ध्र
+हाथ
+रहने
+विस्तार
+ऑस्ट्रेलिया
+वृद्धि
+फ़रवरी
+११
+जैसा
+आर
+कहानी
+व्यवस्था
+क्रिकेट
+बागेश्वर
+पृथ्वी
+चमोली
+गांव
+युग
+यौगिक
+कहीं
+पूर्वी
+२०
+सुरक्षा
+मुखपृष्ठ
+स्पष्ट
+१६
+मिलता
+देवी
+यही
+बुंदेली
+सामने
+प्रवेश
+यूरोप
+रखने
+दिए
+जॉन
+जिन्हें
+दूसरा
+पूरे
+स्थानीय
+आते
+नियंत्रण
+चीनी
+दिखाई
+प्रकाशन
+ऊर्जा
+प्राकृतिक
+की।
+जैन
+लगता
+बनाए
+अमरीकी
+कवि
+व्यापक
+दर
+वजह
+वहाँ
+परीक्षण
+लंदन
+प
+ी
+बदल
+जाए
+अदिलाबादु
+शासक
+खोज
+द्वितीय
+बस्तर
+मदद
+योजना
+ब्रिटेन
+प्रस्तुत
+जे
+धार्मिक
+आर्थिक
+सहायक
+लेखन
+शुरुआत
+मिल
+डॉ
+प्रौद्योगिकी
+शासन
+स्रोत
+रायगढ़
+वैज्ञानिक
+कमी
+आपके
+मिनट
+पत्र
+निर्वाचन
+रक्त
+ऑफिस
+गूगल
+संग्रह
+उद्योग
+राष्ट्र
+एशिया
+सांस्कृतिक
+पदार्थ
+इनका
+आपका
+मुंबई
+हिस्सा
+दृष्टिकोण
+उद्देश्य
+वी
+ह
+दूरी
+आता
+अनुवाद
+वो
+पीछे
+भूषण
+क्रिया
+स्वास्थ्य
+पैदा
+केंद्र
+२०११
+अच्छे
+पद्म
+शब्दों
+ऐतिहासिक
+गैर
+पिथोरागढ
+छोटी
+६
+सार्वजनिक
+कपूर
+प्रेम
+मुंगेर
+रहती
+चैनल
+समस्या
+कनाडा
+अंतर्गत
+देवनागरी
+राष्ट्रपति
+जिसने
+बैंड
+साम्राज्य
+कॉलेज
+मगही
+प्रयुक्त
+पुत्र
+अनुसंधान
+पहचान
+निर्मित
+किमी
+बंद
+प्रतिशत
+लगे
+अंतर्राष्ट्रीय
+ताकि
+भूमि
+मानक
+इंग्लैंड
+सके
+प्रारंभिक
+सन्दर्भ
+थीं
+अंगिका
+दिशा
+जर्मनी
+१९
+संकेत
+बच्चों
+द्वीप
+समाचार
+अफ्रीका
+घोषणा
+रह
+बंगाल
+भाषाओं
+घंटे
+हाल
+राजस्थान
+वहां
+आया
+उपन्यास
+कानून
+दिनों
+अभिनेत्री
+खिलाफ
+सदर
+अनुमति
+हवाई
+टीवी
+समाप्त
+मीडिया
+उपचार
+हमारे
+जनता
+नियम
+संक्षेप
+मन
+मिलियन
+चौपाल
+उपकरण
+राज
+भीतर
+चेन्नई
+२८
+कृष्ण
+क्लिक
+३०
+कविता
+कथा
+सूर्य
+प्रेस
+वीडियो
+स्वतंत्रता
+वन
+राजनीतिक
+आमतौर
+देती
+दृश्य
+न्यू
+योग्य
+लागू
+मिला
+बताया
+मैच
+जिसकी
+सा
+मीटर
+नेटवर्क
+रोचक
+भोजन
+हूँ
+मौजूद
+धीरे
+१७
+संभव
+माता
+नृत्य
+७
+महत्व
+परन्तु
+आशा
+डॉलर
+शायद
+आयोजित
+सम्मान
+युगल
+कांग्रेस
+सफल
+उर्दू
+उनमें
+वापस
+चाहिए।
+दें
+मनुष्य
+लाख
+महान
+निजी
+उल्लेख
+जैसी
+इनकी
+व्यवहार
+पन्ने
+नीति
+जाति
+एल
+पोस्टर
+विशाल
+बल्कि
+संचालित
+देखने
+विवाह
+अच्छा
+ख़ान
+२६
+इ
+कृष्णा
+वंश
+जापान
+केन्द्र
+मेरी
+तमिल
+देख
+विजेता
+वेब
+शिव
+सिर्फ
+न्यूयॉर्क
+भाई
+यूरोपीय
+राजीव
+प्रयोगस्थल
+उत्पाद
+मंच
+पांच
+०५
+पंजाब
+०४
+राजमार्ग
+मॉडल
+कंप्यूटर
+स्वीकार
+अंतर
+कार्बनिक
+सक्रिय
+परंतु
+लखीसराय
+किलोमीटर
+यमकेश्वर
+चला
+आलेख
+पड़ता
+उसमें
+ज्ञानसन्दूक
+आपने
+हमें
+मान
+इंजन
+तहत
+पत्रिका
+अवस्था
+९
+चम्पावत
+ं
+सहयोग
+मौलिक
+मामले
+अच्छी
+तिथि
+आरंभ
+स्वतंत्र
+बल
+बाजार
+८
+प्रारंभ
+मूल्य
+सरल
+वास्तव
+यू
+उससे
+तुम
+मैंने
+पुनः
+सागर
+पक्ष
+०६
+छोड़
+खाना
+अनुभव
+टू
+तरफ
+बस
+विजय
+महाराष्ट्र
+समुद्र
+उचित
+रेडियो
+चल
+हटाने
+खुद
+समीक्षाएँ
+जीव
+तेल
+दिल
+उम्र
+जर्मन
+ग्रंथ
+रूस
+संपर्क
+बौक्स
+रखें
+गंगा
+एल्बम
+राय
+पाठ
+हासिल
+निश्चित
+सीमित
+सात
+प्रांत
+गई।
+नेपाल
+दक्षिणी
+काव्य
+निर्णय
+छोटा
+२५
+डिजाइन
+रात
+हों
+लगाया
+वास्तविक
+पूछे
+ज्ञात
+प्रकृति
+कार
+गए।
+निर्वाचित
+तरीके
+त
+ज
+चुनाव
+किन्तु
+बढ़
+२१
+हो।
+जीत
+विपरीत
+दस
+वर्मन
+औसत
+इंडिया
+सम्मानित
+२२
+नाटक
+अधिनियम
+वस्तु
+संरचना
+मत
+सर्वाधिक
+लेखों
+विश्वास
+मास
+संकिपा
+वायु
+शीघ्र
+घटना
+निम्न
+विरोध
+सप्ताह
+स्वरूप
+प्रवेशद्वार
+सितम्बर
+गुरु
+सॉफ्टवेयर
+निर्धारित
+विद्युत
+रक्षा
+पूर्णिमा
+पड़ा
+बावजूद
+बेहतर
+वर्ल्ड
+चुका
+भारी
+मगध
+समुदाय
+क्यों
+ऑस्ट्रेलियाई
+जनगणना
+लीग
+अंक
+मिलती
+भागों
+बाल
+भेज
+कप
+कोरिया
+कर्नाटक
+मात्र
+हुई।
+अत्यंत
+तत्व
+महाभारत
+ओ
+अरब
+पूजा
+निर्माता
+रोमन
+विदेशी
+अल
+पर्वत
+पिछले
+इनसे
+पार्क
+स्थानों
+जिन
+धारा
+चुके
+मिली
+जाकर
+बदलने
+स्वामी
+सम्मेलन
+२३
+बनाये
+अल्मोडा
+शो
+जंक्शन
+मन्दिर
+गलत
+सफलता
+लिपि
+पाए
+योग
+निर्भर
+सिस्टम
+प्रसाद
+गांधी
+प्रचार
+फ्रांस
+वर्मा
+जिन्होंने
+रहें
+बौद्ध
+बच्चे
+आंदोलन
+एच
+तंत्र
+मोबाइल
+कोशिश
+अध्यक्ष
+गैस
+प्यार
+सारे
+ल
+लक्ष्य
+अवश्य
+लेते
+आसपास
+चरण
+पर्याप्त
+आयु
+शर्मा
+कार्बन
+सुरक्षित
+कोलकाता
+शीर्ष
+२७
+मै
+समिति
+धन
+विवरण
+सुविधा
+खान
+आती
+जिनके
+यद्यपि
+मामलों
+प्रशिक्षण
+सिटी
+कैंसर
+पात्र
+इतना
+रिपोर्ट
+नेतृत्व
+महिलाओं
+फल
+महीने
+सड़क
+देव
+मान्यता
+क्लब
+अनंतपुर
+क्रम
+य
+बजाय
+साँचे
+उप
+२४
+विश्लेषण
+आनन्द
+यूनानी
+चाहते
+राज्यों
+फाइनल
+अवार्ड
+जुड़े
+अत्यधिक
+तकनीक
+अज्ञात
+निकट
+सेंट
+चलता
+रेखा
+निर्देशक
+इंडियन
+मानते
+देवता
+जांच
+हे
+पत्नी
+इंटरनेट
+केरल
+जोखिम
+रिकॉर्ड
+बदलाव
+डिग्री
+प्रतीक
+जाएगा
+अतः
+पालन
+खंड
+विष्णु
+भौतिक
+जिनका
+अकादमी
+होगा।
+गुण
+वित्तीय
+क्षेत्रफल
+कर्नूलु
+करें।
+भाव
+तापमान
+०७
+अनुमान
+डे
+अमरीका
+रासायनिक
+च
+ग
+अभिनय
+पत्थर
+खाता
+किस
+गणराज्य
+टेस्ट
+चोर
+इत्यादि
+शुद्ध
+होगी
+भिकियासैण
+संघर्ष
+अंतरराष्ट्रीय
+लगातार
+माँ
+उल्लेखनीय
+रखते
+लक्षण
+जेम्स
+ग्रह
+प्राय
+वही
+औद्योगिक
+संक्षिप्त
+२००६
+विमान
+टिप्पणी
+नागरिक
+ध्वनि
+याद
+संचार
+बराबर
+प्रधान
+अमेरिकन
+पारंपरिक
+युक्त
+अत
+पुरी
+प्रतिक्रिया
+शाह
+चक्र
+अवसर
+हमेशा
+शारीरिक
+हंडिया
+आबादी
+तट
+लाइन
+विकल्प
+अंग
+लोकसभा
+खाद्य
+पर्यावरण
+संसार
+विवाद
+बनने
+करीब
+व्यक्तियों
+०
+वैदिक
+बिक्री
+ब
+निम्नलिखित
+कोशिका
+पार
+परमाणु
+भवन
+समझ
+नष्ट
+स्वर
+दुर्ग
+जितना
+प्रकट
+फॉर
+विमानक्षेत्र
+रख
+रुप
+शहरों
+तकनीकी
+लखनऊ
+मुद्रा
+हिस्से
+झील
+आयोजन
+इकाई
+मील
+समस्त
+संरक्षण
+अंदर
+संस्था
+परंपरा
+सतह
+कार्यों
+विद्यालय
+संसद
+अभियान
+सिद्ध
+मुख्यालय
+प्रस्ताव
+सीधे
+सर्वोच्च
+डालकर
+वाहन
+गुजरात
+उपयुक्त
+राशि
+बोली
+सक्षम
+अधिकतर
+नेशनल
+प्राथमिक
+मौत
+इसने
+गणित
+अली
+व्यवसाय
+हवा
+मिट्टी
+अगले
+फिल्मों
+चले
+डेविड
+मिलते
+बनाई
+महल
+आक्रमण
+रे
+राजनीति
+मंत्री
+गंभीर
+शाखा
+अम्ल
+हटा
+तटस्थ
+भविष्य
+ईश्वर
+आए
+वि
+दावा
+प्रसारण
+जीवित
+कड़ी
+रखें।
+लिमिटेड
+अन्दर
+क्रांति
+लिखे
+मैदान
+धातु
+एफ
+सम्बन्ध
+विलियम
+हृदय
+संभावना
+वातावरण
+न्यायालय
+लगाने
+सैन्य
+परिवहन
+परिषद
+चारों
+पवित्र
+योगदानकर्ताओ
+गुणवत्ता
+खगड़िया
+शेष
+करे
+ला
+युवा
+नियमित
+ऑन
+सर
+पसंद
+दबाव
+ईरान
+लागत
+०९
+०८
+२९
+अधिकारी
+उनसे
+कहना
+बोर्ड
+ग्रहण
+अशोक
+स्टार
+जान
+दिखाया
+ग्राम
+स्पेन
+नीतियाँ
+सभ्य
+०००
+समारोह
+संविधान
+इटली
+आठ
+संग्रहालय
+तर्क
+दूतावास
+पाने
+लिया।
+पाँच
+थलीसैंण
+लगी
+जन
+ताप
+परिणामस्वरूप
+लॉग
+लिखी
+रॉक
+कार्ड
+प्रेरित
+आगंतुकों
+फूल
+तेलगू
+लेता
+मिले
+रोगी
+आक्षेप
+जरूरत
+गठन
+व्यक्त
+भुगतान
+मौसम
+मीडियाविकि
+अन्तर्राष्ट्रीय
+पदार्थों
+पूर्वाग्रह
+रहे।
+शादी
+पुरा
+विषयों
+बिलियन
+ढंग
+आदेश
+लंबे
+काउंटी
+धन्यवाद
+मुस्लिम
+विरोधी
+वेल्स
+लिखें।
+पुरानी
+कांडा
+रानी
+विभाजित
+मिलकर
+तारा
+वैसे
+ईसाई
+पू
+शिकार
+ज्ञानसंदूक
+नेता
+शास्त्र
+कौन
+राजवंश
+ब्लैक
+अस्तित्व
+धारी
+प्र
+०३
+तेजी
+रायपुर
+संवाद
+किनारे
+टाइम्स
+भार
+सिर
+उत्तरप्रदेश
+छह
+आलोचना
+दिये
+गुप्त
+गेम
+नियंत्रित
+पुराण
+उद्यान
+डालें।
+हिंदू
+डीवीडी
+परीक्षा
+वालों
+घरेलू
+वस्तुओं
+व्याख्या
+पौराणिक
+अर्थात
+फूलपुर
+करोड़
+दिवस
+लघु
+जिसमे
+पिथौरागढ
+विज्ञापन
+पेश
+चर्च
+घोषित
+कंपनियों
+पशु
+पाएँ
+दर्द
+चलते
+समाधान
+माइकल
+सामना
+पूछें
+लड़ाई
+जोड़ें।
+संपादित
+जनरल
+विविध
+मिश्र
+आग
+भावना
+टिल्ड
+कैलंडर
+हत्या
+ग्रेगोरी
+प्रशासन
+रिलीज़
+खास
+मध्यम
+ज्यादातर
+अरबी
+रानीखेत
+देखते
+पाई
+आसानी
+अंश
+कश्मीर
+नवागंतुकों
+प्रभावी
+लिख
+किताब
+जीन
+इंडियाना
+चूंकि
+सत्य
+गंगोलीहाट
+नामांकित
+कोशिकाओं
+कार्यालय
+छात्र
+मस्तिष्क
+डेटा
+अनुनाद
+मंडल
+चुकी
+नारायण
+कर्म
+संपूर्ण
+प्रतिनिधित्व
+पहुंचती
+तेज
+अपेक्षा
+जाएगा।
+व्यंजन
+आत्मा
+वैश्विक
+मांग
+सेट
+इन्होंने
+सम्पूर्ण
+बदलें
+लग
+एशियाई
+रोड
+ऑनलाइन
+इस्लाम
+दास
+संत
+पक्षी
+बीबीसी
+व्यावसायिक
+सीज़न
+फुट
+जानते
+संक्रमण
+विचारों
+चाहता
+मतलब
+विरुद्ध
+रसायन
+निवेश
+वर्षा
+प्रमंडल
+संस्कार
+केन्द्रीय
+अंतरिक्ष
+ध्वज
+विशेषता
+बाकी
+थीं।
+यूनिवर्सिटी
+शंकर
+दैनिक
+आचार्य
+सं
+अनुरोध
+गायक
+मानसिक
+जमा
+हाउस
+मंत्रालय
+पहुंच
+जॉर्ज
+उपस्थित
+मार
+प्रधानमंत्री
+अंततः
+घनत्व
+थराली
+दूध
+सेवाओं
+वर्णित
+नियमों
+यूनाइटेड
+साथी
+विभाजन
+आपकी
+चौबटाखाल
+सम्मिलित
+प्रवाह
+गोल
+हुए।
+बिलासपुर
+कह
+जलवायु
+ब्राह्मण
+समर्पित
+निवास
+फोन
+प्रमाण
+पैमाने
+बिजली
+रोहित
+शांति
+अति
+उत्पत्ति
+तीसरे
+आनंद
+हमारी
+एकमात्र
+नुकसान
+मिलने
+पे
+सौ
+घटनाओं
+मां
+प्रायः
+भौतिकी
+कठिन
+माने
+घाटी
+अधीन
+स्थिर
+लेना
+उपयोगी
+रखना
+छूटती
+द्वार
+वेद
+चैम्पियनशिप
+बिंदु
+जुड़ा
+कल्पना
+आये
+संपादन
+तारे
+दें।
+परिभाषित
+उ
+सिद्धार्थ
+जापानी
+ऊंचाई
+भौगोलिक
+समुद्री
+आदमी
+उपकरणों
+स्त्री
+वाक्य
+निर्देश
+मशीन
+०२
+सत्र
+फुटबॉल
+घाट
+उपग्रह
+पंथ
+बहुधा
+हाइड्रोजन
+लंबी
+श
+सुंदर
+दौर
+रखता
+फ़ाइल
+मोहन
+देकर
+काला
+नंबर
+उपस्थिति
+दवा
+जीवनी
+आंतरिक
+परिवर्तित
+ज्ञानकोष
+वहीं
+आय
+समझा
+निगम
+वृक्ष
+पॉल
+बुद्ध
+बाज़ार
+मराठी
+रूसी
+जय
+ग्रैंड
+संचालन
+तत्वों
+व्यक्तित्व
+कीया
+३१
+कारणों
+बनाना
+अपराध
+फिल्में
+चक
+व्यास
+चाहे
+छोड़कर
+नमस्कार
+टेलीविजन
+डा
+वितरण
+एक्स
+पुराना
+रामायण
+बेरीनाग
+ग्रामीण
+सेंटर
+लाइसेंस
+मित्र
+छात्रों
+अध्याय
+शेयर
+अभाव
+मानना
+विद्वानों
+जनजातियां
+वैकल्पिक
+तुर्की
+जैव
+पश्चात
+नहीं।
+डिजिटल
+तारीख़
+समीक्षा
+हजार
+प्रिय
+इतनी
+अर्जुन
+शराब
+स्मृति
+जीता
+उच्चारण
+श्रीलंका
+बीजापुर
+निकल
+स्वीडन
+सत्ता
+संपत्ति
+गर्म
+बीमारी
+अर्थात्
+५०
+सम्राट
+व्रत
+मिश्रण
+वार्षिक
+प्रत्यक्ष
+अंकित
+रॉबर्ट
+समूहों
+आपूर्ति
+इंजीनियरिंग
+कैलिफोर्निया
+उनको
+गेंद
+इच्छा
+रन
+ऋषि
+समस्याओं
+आन्दोलन
+अपेक्षाकृत
+रोम
+चाहिये
+चलने
+गतिविधियों
+गाने
+विम्बलडन
+हैरी
+एण्ड
+इंच
+सेवाएं
+वेस्ट
+वें
+जाये
+पहुँच
+हूं
+श्रेष्ठ
+रहा।
+हार
+अस्पताल
+निरंतर
+नियुक्त
+तारों
+ख
+केंद्रीय
+वर्तनी
+धारण
+दान
+वाराणसी
+स्टूडियो
+रोगियों
+कुकर्म
+साधन
+जटिल
+अक्षर
+देंगे
+स्कोर
+उत्पादों
+प्रोटीन
+अनिवार्य
+२००१
+कायमगंज
+सौर
+सरगुजा
+साबित
+ऊँचाई
+लीला
+सैनिक
+स्टेडियम
+रायगढ
+पर्व
+जयपुर
+व्याकरण
+रावत
+इसलिये
+करेगा
+तीव्र
+प्रकाशक
+कृतियाँ
+प्रसार
+नोबेल
+सभ्यता
+परिसर
+अफ़्रीका
+राजनैतिक
+इलाज
+साहित्यिक
+सतपुली
+लिखित
+फ्रेंच
+देखे
+ऋण
+अकबर
+सोवियत
+हमला
+प्रोग्राम
+मिस्र
+डाला
+छत्तीसगढ
+आयोग
+पुरुषों
+रस
+सुनिश्चित
+पेरिस
+साहित्यकार
+परिभाषा
+डाटा
+अर्थव्यवस्था
+महाराज
+ओम
+सह
+पेज
+जिनकी
+वर्ण
+दर्ज
+भारती
+तभी
+तय
+एसोसिएशन
+अनुपात
+झारखंड
+जोड़ा
+पुन
+छत्तीसगढ़ी
+यानि
+लकड़ी
+त्वचा
+अधिकतम
+कोरबा
+देखकर
+डाल
+पुरालेख
+कोइल
+बढ़ती
+सफेद
+प्रतीत
+कानूनी
+चयन
+बनता
+हाथों
+जल्दी
+चार्ल्स
+ग्रन्थ
+रोक
+कारक
+खाने
+अभ्यास
+कैरियर
+वर्गीकरण
+सर्वेक्षण
+नारायणपुर
+मिश्रित
+ें
+तमिलनाडु
+प्राप्ति
+आकर्षित
+भेजा
+बनाकर
+संग्राम
+किले
+अड्डा
+कहलाता
+महसूस
+मार्क
+माल
+वजन
+फ़्रेंच
+ठोस
+उपयोगकर्ता
+चम्पा
+सलाह
+भेद
+काफ़ी
+लोगो
+खाते
+निर्देशन
+स्वर्ण
+बनाते
+नोकिया
+मूर्ति
+हद
+रोकने
+समाप्ति
+अकाउंट
+कार्यक्रमों
+ग्रीक
+संधि
+लंबाई
+निवासी
+दौरे
+चाहें
+क्षेत्रीय
+स्थायी
+किंग
+न्याय
+मोटर
+संभवतः
+बनाता
+पेड़
+तल
+पति
+वां
+कराया
+शुरूआत
+प्रारूप
+काले
+कांकेर
+रखे
+पौधों
+खेलों
+००
+काशी
+मस्जिद
+हरा
+आकर्षण
+नयी
+रखी
+मजबूत
+कडप
+आजकल
+टंकण
+साक्षात्कार
+तीसरी
+खेती
+महासागर
+लाया
+जोड़
+सामान्यतः
+सम्बंधित
+सुन्दर
+रचित
+जांजगीर
+पृष्ठों
+दीवार
+उन्होने
+विद्या
+लाने
+पड़ती
+संयोजन
+तीसरा
+पड़
+रोगों
+संसाधन
+भाषाएँ
+मानचित्र
+जमीन
+देहरादून
+मुगल
+कोर्ट
+कवर्धा
+धमतरी
+जशपुर
+पौधे
+कदम
+आकर
+बढ़ा
+अधिकारियों
+आरोप
+मिलाकर
+बढ़ाने
+प्रशासनिक
+हमले
+टाइम
+प्रेरणा
+उड़ान
+शक्तिशाली
+पीपी
+महासमुन्द
+विधानसभा
+फीट
+प्रगति
+स्नातक
+सूक्ष्म
+जवाब
+कम्प्यूटर
+अप
+छवि
+फ़िल्मों
+भ
+शुल्क
+विभूतियाँ
+कलाकारों
+संकट
+संभावित
+दिशानिर्देश
+जोर
+विधान
+आहार
+गोठ
+उपाधि
+राजनांदगांव
+जम्मू
+सतनाम
+कर्णप्रयाग
+थोड़ा
+बाबा
+साइट
+तथापि
+दन्तेवाड़ा
+यानी
+अमर
+मार्टिन
+तुरंत
+जिले।
+लाइव
+पुनःप्राप्त
+निर्धारण
+तत्कालीन
+कक्षा
+सारी
+प्रजातियों
+गये।
+करो
+मूल्यांकन
+द्वाराहाट
+राजशाही
+घई
+होगी।
+गैरसैण
+हॉल
+बिल
+ऐ
+रूपों
+मंगल
+जानी
+चित्रण
+नीतियां
+शिक्षण
+अवधारणा
+चेक
+किला
+तीनों
+मारे
+इमारत
+आवासीय
+किंगडम
+राजीवमास
+चुना
+आँकड़े
+फलस्वरूप
+करेंगे
+ज्योतिष
+यंत्र
+ग्राहक
+चित्रों
+नौ
+सल्ट
+उम्मीदवार
+कोश्याँकुटोली
+बीज
+उत्कृष्ट
+०१
+कम्पनी
+महात्मा
+खर्च
+केंद्रित
+सिन्हा
+हाई
+प्रबंधकों
+मुश्किल
+नर
+गाँधी
+बनाएं
+करनी
+हूँ।
+स्टेट
+प्
+दार्शनिक
+निकाल
+मनोरंजन
+पुस्तकालय
+सोचते
+जेल
+हिमालय
+पा
+जहाज
+तरल
+यूनिकोड
+सैन
+हास्य
+पैर
+दि
+दी।
+खराब
+ख़ुदा
+कृति
+पुष्टि
+हल्द्वानी
+असम
+अर्थशास्त्र
+सेवन
+ग्रंथों
+कड़ियां
+बदले
+पुस्तकों
+हेनरी
+रिचर्ड
+परम
+सके।
+पृ
+रहना
+हल
+सर्वप्रथम
+सामान
+काली
+चेतावनी
+मनोविज्ञान
+बॉक्स
+छोड़ने
+संगठनों
+तारामंडल
+हैदराबाद
+छिबरामऊ
+मुख्यतः
+टैग
+४०
+यहूदी
+विद्रोह
+दर्शकों
+ग्रुप
+जोशी
+डीडीहाट
+सेन
+गरुङ
+कीमत
+पीटर
+कृत्रिम
+विपणन
+प्राण
+आस
+बुनियादी
+वीर
+जल्द
+ऊपरी
+टिप्पणियाँ
+नज़र
+पहुंचा
+लेखकों
+ईंधन
+गुणों
+२००४
+स्ट्रीट
+बचपन
+लैटिन
+मलयालम
+हिमाचल
+सरस्वती
+स्वामित्व
+जंगल
+भनोली
+भक्ति
+श्रीकृष्ण
+नवीन
+मैन
+पीढ़ी
+शहरी
+लव
+अररिया
+अनुबंध
+विश्वभर
+स्मारक
+पुर्णीमा
+देवताओं
+पढ़ें
+प्रसारित
+परिस्थितियों
+रास्ते
+टाटा
+वा
+तरीका
+विषाणु
+अनुप्रयोग
+ईरानी
+यात्री
+संशोधन
+क्रमांक
+पंडित
+ते
+माह
+मुक्ति
+गहराई
+सुबह
+यहीं
+नाथ
+संबद्ध
+उत्तम
+प्रजाति
+मापन
+गद्य
+टीका
+वित्त
+विख्यात
+अवतार
+उपनिषद
+दीया
+मुहम्मद
+राजाओं
+फैसला
+परंपरागत
+जर्नल
+व्यापारिक
+होंगे
+एयर
+चौखुटिया
+मथुरा
+लगते
+उसको
+तनाव
+सिंगापुर
+उत्सव
+पुणे
+अभिव्यक्ति
+बढ़ावा
+इसको
+बच्चन
+द्रव
+अनुरूप
+एट
+मेट्रो
+उत्सर्जन
+एलबम
+हरियाणा
+चलती
+वाणिज्यिक
+डॉक्टर
+चली
+मानी
+लगा।
+लॉस
+सैनिकों
+सवाल
+२००५
+आरंभिक
+निदान
+अतरौली
+कराने
+मालिक
+देर
+तीर्थ
+विदेश
+यथा
+प्रबंध
+संपादक
+जैविक
+दोस्त
+मि
+अनुकूल
+संस्थापक
+इंटरनेशनल
+स्लैम
+सकारात्मक
+टाइप
+पुस्तकें
+रा
+मियामी
+लगे।
+ड
+घटक
+निदेशक
+इतने
+प्रतिनिधि
+मितुल
+अंग्रेजों
+दोनो
+बांग्लादेश
+वनस्पति
+बढ़ने
+बंदरगाह
+आसान
+सटीक
+मनाया
+भू
+समकालीन
+पाठक
+दोष
+औपचारिक
+डिस्क
+बेटी
+संदर्भित
+निभाई
+राव
+सूरज
+मगर
+चलचित्र
+मछली
+देखी
+जगत
+ज़्यादा
+सर्वर
+लम्बाई
+ग्रेट
+कर्मचारियों
+पंजाबी
+अगला
+शाही
+दर्जा
+चिकित्सक
+विकार
+फैला
+शुक्ल
+प्रजनन
+हां
+सदा
+अग्रणी
+नायक
+गृह
+धन्यवाद।
+जालस्थल
+आवाज
+बनाम
+कपकोट
+संघीय
+बिग
+गलती
+विविधता
+नो
+लगती
+पेट
+रिलीज
+विद्वान
+अन्तिम
+कॉपीराइट
+नमक
+अधिकारों
+प्रणालियों
+युकेश
+आर्ट
+रॉयल
+बालक
+पश्चात्
+हटाया
+पर्यटक
+आर्य
+प्रीमियर
+शब्दावली
+परत
+सिद्धांतों
+हमारा
+अकार्बनिक
+चोट
+कौशल
+प्रारम्भ
+विकेट
+गुना
+ब्रह्म
+आयरलैंड
+पेशेवर
+इस्पात
+ठाकुर
+अग्नि
+कोश
+रुचि
+उपनाम
+दत्त
+उम्मीद
+पशुओं
+श्रेय
+मुम्बई
+निकाला
+सिख
+पदक
+कवियों
+इसीलिए
+मार्शल
+बॉलीवुड
+खन्ना
+प्रवृत्ति
+यौन
+रचनाओं
+उड़ीसा
+तेलुगू
+आश्रम
+अस्पष्ट
+माइक्रोसॉफ्ट
+महत्त्वपूर्ण
+चयनित
+शास्त्रीय
+कर्मचारी
+जैक
+खो
+विशेषकर
+शब्दकोष
+स्क्रीन
+प्रतिमा
+बर्फ
+फारसी
+महाराजा
+ब्लू
+शून्य
+जरूरी
+आनेवालों
+दौरा
+प्रतिभा
+सच
+मौजूदा
+क्षति
+स्थलों
+खून
+फ़िल्में
+प्रशंसा
+होटल
+सेल
+सालों
+थ
+दुर्गा
+हाँ
+स्मिथ
+बुक
+नोट
+रचयिता
+शिखर
+नेहरू
+ब्रांड
+सुख
+समझने
+मुंह
+महाविद्यालय
+ईस्ट
+शृंखला
+बचाने
+आध्यात्मिक
+पुल
+त्याग
+आविष्कार
+हजारों
+कहता
+जाय
+प्रक्रियाओं
+विलय
+दूसरों
+जाए।
+२०००
+वापसी
+आकाश
+थॉमस
+इलेक्ट्रॉनिक
+कडियाँ
+संगीतकार
+परस्पर
+मुख्यमंत्री
+उपभोक्ता
+प्राणी
+होनी
+आउट
+स्व
+उपनिषदों
+वक्त
+कक्ष
+यांत्रिक
+आंशिक
+बांग्ला
+संकोच
+शनि
+ट
+हिन्द
+पट्टी
+लंबा
+कन्या
+जीवों
+नैतिक
+किशोर
+फ्रांसीसी
+वस्त्र
+शिकागो
+नदियों
+संस्थाओं
+ो
+गतिविधि
+कठोर
+सोने
+कंपनियां
+बेटे
+प्रतिरोध
+दवाओं
+न्यूनतम
+खैर
+गरीब
+मेला
+निकटतम
+स्थानांतरित
+लौट
+विटामिन
+जोड़ने
+ब्रायन
+यादव
+सहारा
+अफ्रीकी
+सिनेमा
+रचनात्मक
+नामों
+यज्ञ
+स्थितियों
+तृतीय
+हुये
+रिंग
+पोषण
+कहने
+उपाय
+विशेषज्ञ
+चार्ट
+क्लासिक
+मानवीय
+कार्रवाई
+एक्सप्रेस
+निर्देशित
+सम्बन्धित
+ग्राहकों
+चलाने
+अड्डे
+चेतना
+देखभाल
+रंगों
+विकी
+कल
+संबंधों
+सम्पर्क
+निष्कर्ष
+तंत्रिका
+वैज्ञानिकों
+टॉम
+प्रयत्न
+२००३
+पाठ्यक्रम
+चिंता
+३५
+श्रम
+बहन
+काल्पनिक
+डब्ल्यू
+कपड़े
+डबल्यू
+जातियों
+खाड़ी
+गीता
+हाथी
+डिज़ाइन
+एकीकृत
+कन्नड़
+खतरा
+प्रस्तावित
+खरीद
+अन्त
+कार्यरत
+ग्रीन
+विकिरण
+असफल
+हानि
+लोहाघाट
+कानपुर
+खिलाड़ियों
+छ
+सूचित
+अयोध्या
+स्टॉक
+चन्द्र
+गवर्नर
+लिंक्स
+फ़ारसी
+खनिज
+मंदिरों
+गिरावट
+पोखरी
+सारा
+आवाज़
+वायरस
+विलियम्स
+राधा
+सेंट्रल
+सहमत
+बातें
+रामनगर
+लिंग
+श्वेत
+लक्षणों
+दर्शनीय
+बाराकोट
+ऐंड
+सन्‌
+रास्ता
+वसा
+शती
+बदला
+उन्नत
+हिन्दुस्तान
+३६
+पृष्ठभूमि
+हार्ट
+सहज
+गिटार
+इतालवी
+पर्यटकों
+हरे
+खुले
+वर
+व्युत्पन्न
+जाँच
+धारणा
+मुख
+होली
+खड़े
+प्रतिष्ठित
+पड़ा।
+बचने
+निवासियों
+बरो
+लेती
+पीठ
+पाकिस्तानी
+रामचरितमानस
+आपस
+समझौते
+महीनों
+कर्ण
+हिस्ट्री
+सो
+पोस्ट
+पंक्ति
+बहु
+संशोधित
+कोलंबिया
+बचाव
+रिकॉर्डिंग
+थोड़ी
+चुने
+चौधरी
+अंकों
+शाम
+बातचीत
+ओलम्पिक
+गर्मी
+फ्लोरिडा
+गोली
+लाइफ
+लम्बी
+बम
+चावल
+बातों
+वर्गों
+आवास
+मिशन
+सफ़ेद
+४५
+दशा
+अपलोड
+मेडिकल
+जानने
+कार्यकारी
+सकतें
+समीप
+संयंत्र
+नि
+आवेदन
+मांस
+गहरा
+तरीकों
+छः
+कल्याण
+लगने
+हुसैन
+औ
+संजय
+जंगली
+केन
+सुपर
+सबूत
+साफ
+क्रमश
+लॉर्ड
+समझौता
+नाडु
+अदालत
+आगमन
+प्रथा
+डालने
+औषधि
+करवाया
+जिम्मेदार
+यान
+पन्नों
+महावीर
+सकें
+परम्परा
+मेक्सिको
+गोल्डन
+गईं
+टन
+एकदिवसीय
+आदि।
+ऑल
+१००
+प्रदूषण
+अणु
+चोपड़ा
+भा
+संरक्षित
+प्रभावशाली
+पुचः
+जुड़ी
+प्रोत्साहित
+तल्ला
+साधना
+न्यूटन
+लोकप्रियता
+भरा
+प्रार्थना
+बंगाली
+द्रव्यमान
+व्यावहारिक
+ट्रैक
+सावधान
+बैठक
+तुम्हारे
+पॉटर
+रथ
+प्रोग्रामिंग
+कही
+कमल
+मशहूर
+नजर
+धरती
+स्वाभाविक
+चेहरे
+सकता।
+शिशु
+कोण
+पॉप
+मन्त्र
+५१
+निवेदन
+अकेले
+आवृत्ति
+३२
+उठा
+कवर
+गरम
+शैक्षिक
+वास्तुकला
+पाते
+खूबसूरत
+एसिड
+होता।
+जायेगा
+पड़े
+सीजन
+नीला
+योग्यता
+वैध
+ग्लोबल
+पथ
+बीमा
+हिस्सों
+माप
+मैने
+बारह
+उल्लंघन
+जानवरों
+प्रवासी
+साहब
+एजेंसी
+हिट
+सुविधाओं
+सोच
+रवि
+गीतों
+पेन
+गुजराती
+अगली
+दर्शाया
+पतन
+चित्रित
+आकृति
+मैसूर
+बुद्धि
+मंत्र
+मनुष्यों
+पत्रकार
+पेय
+विद्यमान
+मादा
+बोलने
+मना
+बेस
+सहयोगी
+हराया
+समीकरण
+लिखते
+फसल
+संहिता
+लें
+तिलक
+प्रोफेसर
+सीधा
+आकर्षक
+संज्ञा
+मोटे
+वार
+खगोलीय
+क्रमशः
+समर्थक
+स्नान
+नकारात्मक
+नक्षत्र
+पहुंचने
+चित्रकार
+दुर्लभ
+सिद्धान्त
+भाँति
+छाया
+पूंजी
+आलोचक
+अपनाया
+बेहद
+खड़ा
+सका
+उदय
+भूल
+यमुना
+क्रेडिट
+साउथ
+नैदानिक
+हिल
+में।
+फ
+नील
+प्रयोगशाला
+५२
+शासकों
+मा
+हिसाब
+इन्हीं
+रॉय
+गाय
+घायल
+ऋतु
+तार
+लम्बे
+३८
+संपन्न
+क्रिस
+कृत
+उतना
+नामकरण
+स्वाद
+मनोवैज्ञानिक
+भय
+नौसेना
+हावड़ा
+४८
+श्याम
+कार्यवाही
+हस्तक्षेप
+दंड
+दुबई
+किस्म
+अभियांत्रिकी
+फ़िल्मफ़ेयर
+मोहम्मद
+उर्जा
+पारित
+गोरखपुर
+अस्थायी
+स्तंभ
+मुसलमानों
+असामान्य
+कैथोलिक
+वर्गीकृत
+पाप
+मनीष
+श्रेणियों
+भरे
+४६
+पढ़ने
+बिल्कुल
+खुला
+उद्यम
+मूलतः
+जोड़ी
+युनाइटेड
+दरबार
+मद्रास
+निकालने
+विरासत
+संगम
+निहित
+गिर
+कथन
+दाब
+आवश्यकताओं
+कहानियों
+ऑक्सफोर्ड
+आफ
+उन्हीं
+आधा
+मर
+सोसाइटी
+ब्लॉग
+मल्ला
+कालाढूगी
+आकलन
+अत्यन्त
+पकड़
+चाहिये।
+भरी
+भाषण
+आधे
+रत्न
+टूर
+नाना
+संस्थानों
+कालेज
+शल्य
+।।
+नौकरी
+जुड़ने
+गा
+मास्टर
+किरदार
+कुशल
+पक्षियों
+अधिग्रहण
+मजबूर
+खड़ी
+बताते
+अनिल
+महाद्वीप
+हथियार
+कलकत्ता
+प्लास्टिक
+पायलट
+स्वस्थ
+जिनसे
+रचनाएँ
+शिवाजी
+परिक्रमा
+२००२
+भोपाल
+पटकथा
+खत्म
+ड्राइव
+रूपांतरण
+भक्त
+४२
+अन्यथा
+उच्चतम
+बढ़ता
+असर
+रेड
+घरों
+व्हाइट
+आना
+खाली
+जॉनी
+राहुल
+कमजोर
+ब्राज़ील
+श्रीमती
+चाय
+रखकर
+ॐ
+एपिसोड
+मुसलमान
+जाया
+एडवर्ड
+पारी
+बांध
+विस्फोट
+उर्फ
+गुरू
+डच
+प्रमाणित
+समग्र
+मतदान
+कण
+पाटी
+प्रोटोकॉल
+विकिपीडीया
+हिंसा
+आजादी
+तस्वीर
+४७
+चुनौती
+क्रांतिकारी
+शेर
+न्यूजीलैंड
+ऑक्सीजन
+बनते
+निगरानी
+व्यवस्थित
+सर्विस
+आखिरी
+चिन्ह
+समृद्ध
+प्रयासों
+रेस
+पाता
+खतरे
+उन्हे
+पटेल
+बादशाह
+गर्भ
+हमने
+चरम
+मुखर्जी
+चलकर
+पाउंड
+जातक
+टिप्पणीसूची
+न्यायाधीश
+५५
+अनुच्छेद
+शास्त्री
+हि
+५३
+पेशकश
+बिट
+गणेश
+जीवाणु
+संकलन
+पीड़ित
+ख़ास
+बेस्ट
+निकलने
+लोहे
+ऑव
+स्वर्ग
+सोसायटी
+बेल
+भट्ट
+बढ़ते
+दुर्घटना
+त्यौहार
+संगणक
+विनोद
+हालाँकि
+न्यूज़
+गहरी
+पब्लिक
+४३
+तीव्रता
+पेटेंट
+तिब्बत
+पीने
+इस्लामी
+भीड़
+बहादुर
+ड्रामा
+सुल्तान
+हटाए
+अन्तरविकि
+साक्षरता
+विक्टोरिया
+सिनसिनाटी
+मठ
+प्रतिदिन
+सम्बन्धी
+निबंध
+बनाती
+नव
+विषय।
+तेलुगु
+वीकीपीडीया
+ऊतक
+असली
+संसाधनों
+जानवर
+डाक
+बाग
+डर
+स्रोतों
+प्रतिबंध
+सोमेश्वर
+कब्जा
+रहित
+अवशेष
+वरिष्ठ
+बेल्जियम
+देशी
+जीतने
+रणनीति
+हें
+ताल
+द्रव्य
+खेला
+राजस्व
+रीति
+गयी।
+सजा
+उपयोगकर्ताओं
+बोस
+आलोक
+आत्म
+फ़्रांस
+किसान
+गणितीय
+ज्वालामुखी
+अंगों
+ों
+बनती
+४९
+कायम
+खिताब
+तुलसी
+लक्ष्मी
+समानता
+वयस्क
+शिष्य
+संतुलन
+अचानक
+नदियाँ
+नीतियों
+नागरिकों
+जाल
+नामित
+नेताओं
+पात्रों
+सिविल
+कप्तान
+दुश्मन
+चमक
+अर्जित
+मौखिक
+स्वभाव
+आनुवंशिक
+कितने
+भागीदारी
+चोरी
+रोशन
+आलोचकों
+बोल
+गहरे
+गेट
+स्तरीय
+बता
+बहस
+जावा
+खासकर
+पड़ने
+दौड़
+३७
+निर्माताओं
+विशेषताओं
+माई
+काट
+५६
+सृष्टि
+फाउंडेशन
+संप्रदाय
+उपर
+प्रखंड
+एटा
+प्रकरण
+अक्षय
+स्कॉटलैंड
+राजकुमार
+इंग्लिश
+आइपी
+ध्रुव
+मैक
+अनुमानित
+मधुमेह
+गौतम
+चरणों
+कहे
+ि
+महादेवी
+निम्नांकित
+कथित
+परिणामों
+लिखना
+गाड़ी
+कॉम
+लड़की
+उद्धृत
+ब्लॉक
+३९
+टेलीविज़न
+एकता
+खेलने
+कारों
+सांसद
+चौथे
+सहमति
+बचा
+गाइड
+भले
+हा
+कां
+रिसर्च
+ज़मीन
+आयुर्वेद
+बॉब
+मुद्दों
+सोडियम
+तरंग
+चालक
+बाघ
+साइंस
+ग्लोब
+सकल
+मिलान
+बताता
+जिलों
+जिम
+पत्रिकाओं
+लगाना
+वाशिंगटन
+बैंकिंग
+प्राणियों
+ै
+ईमेल
+३३
+निर्दिष्ट
+पोर्ट
+पुर्तगाली
+चीज़
+बाबू
+अखिल
+उदयपुर
+चोटी
+शक्तियों
+मापदंड
+ण
+घातक
+माध्यमिक
+मारा
+जरिए
+इकाइयों
+५४
+लेजर
+विधियों
+खण्ड
+देखना
+कान
+प्रस्तुति
+३४
+अक्षांश
+कइ
+मानकों
+गुफा
+रखती
+सुरक्षीत
+होम
+करियर
+कारकों
+पत्रकारिता
+पृष्ठ।
+प्रचलन
+अनुक्रम
+इगलास
+जूनियर
+विनिमय
+अनुवादक
+विद्यार्थी
+निर्यात
+शब्दार्थ
+केन्द्रित
+सम्पादन
+बोध
+ब्रह्मा
+फ़ोन
+चाल
+ध
+अंडे
+हनुमान
+ज़
+बास्केटबॉल
+समापन
+राग
+छोर
+साहिब
+शांत
+यॉर्क
+अद्भुत
+राष्ट्रों
+सदन
+प्रसंग
+मोशन
+तकनीकों
+परामर्श
+पैसे
+एवम
+पं
+पृथक
+सरदार
+माया
+मारने
+लेबल
+टु
+निचले
+अतिथि
+महादेव
+परियोजनाओं
+दर्शक
+विकिपीडियन
+जगदीश
+विकिपरियोजना
+मुख्यत
+सीमाओं
+मुकाबले
+प्रताप
+यौगिकों
+बजट
+५९
+अहमद
+चलाया
+अहमदाबाद
+अनुपम
+पूर्ति
+पिक्चर
+स्कूलों
+अंग्रेज
+स्वीकृति
+बसा
+धरोहर
+आंकड़े
+बैटरी
+फूलों
+बेटा
+गर्मियों
+प्रबन्धक
+जोड़े
+महाकाव्य
+जन्मे
+गानों
+वनों
+लेन
+बाह
+एकत्रित
+नेपाली
+अमीर
+नीदरलैंड
+कहानियाँ
+मेयर
+ऑपरेशन
+एक्शन
+श्रेणियाँ
+४१
+चुंबकीय
+मृत
+मुद्दे
+हित
+तोड़
+करे।
+बर्मा
+कहलगाँव
+कहाँ
+बैंकों
+मेले
+ग्रहों
+परे
+ब्रज
+ऑस्टिन
+सूचीबद्ध
+जरिये
+दूरभाष
+कितना
+प्रभावों
+वध
+वर्णमाला
+कितनी
+सचिव
+पवन
+मैक्स
+पिछला
+सौंदर्य
+लो
+खबर
+वाह्य
+प्रचालन
+री
+प्रभाकर
+पहल
+प्रभाग
+अनुसरण
+पहलू
+धूम्रपान
+रिकार्ड
+प्रशांत
+अक्षरों
+कथानक
+पारिवारिक
+लाहौर
+भाषाओँ
+यात्रियों
+घास
+जनपद
+विचारधारा
+बिलकुल
+सीता
+प्रतिष्ठा
+निशान
+टॉप
+अवैध
+दूरसंचार
+लौह
+अतीत
+छत
+इंक
+पूर्णिया
+कोर
+एलन
+उद्योगों
+निष्क्रिय
+क्यूबा
+वेग
+स्टील
+टाउन
+यूनान
+साफ़
+अलंकार
+विफल
+कुत्ते
+सम
+करना।
+मलेशिया
+तैयारी
+भव्य
+ार
+पुत्री
+इमामगंज
+वकील
+४४
+संकेतों
+मूल्यों
+बाई
+भ्रम
+पाल
+ब्याज
+गहन
+अंतराल
+चौथी
+प्रतिस्पर्धा
+निश्चय
+कारोबार
+बच
+कोटि
+साझा
+खुल
+लन्दन
+सार
+राज्यपाल
+पराजित
+स्नातकोत्तर
+रात्रि
+शानदार
+हॉलीवुड
+नाटकों
+पीला
+ब्राजील
+ऊंची
+पाये
+जोशीमठ
+सदस्यता
+पैरों
+हॉट
+आँख
+शिक्षक
+घिरा
+फ़ाइलों
+कथाओं
+बिगाड़
+रुपये
+तू
+संदेह
+लेखा
+क्रिसमस
+भूकंप
+बुरी
+हवेली
+बीकानेर
+जोधपुर
+कहलाते
+करनेवाले
+दशकों
+प्रदेशों
+कमरे
+वुल्फ़
+जितनी
+खतरनाक
+गुगल
+मामला
+रक्तचाप
+डा०
+रविवार
+लीये
+स्थापत्य
+वाहनों
+छूट
+हों।
+प्रो
+जातीय
+फंड
+चौक
+सिक्किम
+मिस्टर
+टूर्नामेंट
+रहमान
+जड़
+बनवाया
+इलाके
+गठबंधन
+किरण
+गोपाल
+कागज
+शुभ
+मिस
+एयरलाइंस
+लाखों
+तत्काल
+अवार्ड्स
+मौका
+गोल्ड
+व्यापारी
+हरी
+सलाहकार
+मनु
+फ़र्रूख़ाबाद
+अपवाद
+मूवी
+जोन्स
+फ्रॉम
+शिकारी
+ऑडियो
+महेश
+गौरव
+ऊँचा
+कब
+सतत
+पहाड़
+अनिरुद्ध
+अध्ययनों
+इंदिरा
+उपर्युक्त
+एकत्र
+महर्षि
+भर्ती
+सोचा
+गुरुआ
+शुरुआती
+अभियान्त्रिकी
+जनवादी
+पड़ी
+आंख
+फ़्राँस
+गोवा
+जैंती
+ट्रस्ट
+सर्जरी
+संयोग
+गिरफ्तार
+रामपुर
+समाजवादी
+सृजन
+बपतिस्मा
+कोष
+आराम
+मैचों
+बसे
+पैदल
+तलाश
+थियेटर
+शुष्क
+विश्वयुद्ध
+प्रतिद्वंदी
+परिवर्तनों
+एकदम
+भ्रूण
+मासिक
+द्वीपसमूह
+माला
+फैल
+नरेन्द्र
+स्टोन
+उठाया
+सारणी
+प्रारम्भिक
+बेतालघाट
+बीस
+त्रुटि
+संगठित
+क्लास
+एड
+आयरिश
+हू
+ललिता
+आग्रह
+संतान
+प्रबल
+नहर
+डॉन
+प्रवाहित
+स्पेनिश
+बनावट
+भाषाएं
+करा
+प्रोत्साहन
+भ्रष्टाचार
+उष्णकटिबंधीय
+गाना
+उपरांत
+पोलैंड
+बनायी
+आएगा।
+पादरी
+फैशन
+बजाए
+टूट
+सोनी
+गले
+मलेरिया
+बंगलौर
+पढ़ाई
+क्रिस्टल
+चौड़ाई
+जोकि
+व्यय
+मिला।
+विवेक
+अब्दुल
+परिवारों
+बाधा
+भूत
+रंगीन
+राजेश
+नींव
+हाइड्रोकार्बन
+पीले
+राकेश
+बुलाया
+इंस्पेक्टर
+परिचित
+वेतन
+इलेक्ट्रिक
+तरी
+खोला
+पदों
+मेन
+स्तरों
+रोजगार
+डोमेन
+मानता
+सेकंड
+६०
+ईसवी
+सिरे
+नाइट
+गभाना
+यथार्थ
+लि
+कीट
+भावनाओं
+नरेश
+करार
+जानता
+कार्यकाल
+सिडनी
+रमेश
+परिमाण
+भरत
+कार्ल
+खोल
+म्यूज़िक
+पठार
+शाखाओं
+गुप्ता
+कार्लो
+तिरवा
+वर्षीय
+चक्रवर्ती
+दिव्य
+चंद्र
+पावर
+विथ
+पूरक
+मुफ्त
+ग्रस्त
+रोज़
+समुदायों
+शैक्षणिक
+नीले
+भिन्नता
+फ़
+देन
+जाएँ
+अनेकों
+काउंसिल
+प्रतिद्वंद्वी
+माइक
+चालू
+सम्भव
+क्रियाओं
+शहीद
+विश्वविद्यालयों
+चौथा
+सदैव
+सुधीर
+नागपुर
+दु
+नवाब
+स्पर्श
+कोट
+दलों
+लगाए
+इतिहासकार
+ओवर
+फ़तेहाबाद
+ऑस्ट्रिया
+हार्ड
+मुकदमा
+स्टीव
+चीज
+पायी
+बादल
+आकाशगंगा
+आवरण
+भेजने
+सुनील
+कुश्ती
+ईसापूर्व
+२००
+मुनि
+स्
+बृहस्पति
+प्रयोगों
+बयान
+खाँ
+शब्दकोश
+स्वचालित
+सिम्बल
+पसंदीदा
+उत्तराधिकारी
+संसदीय
+गायन
+क्षमा
+आतंकवाद
+पत्रों
+हरिद्वार
+लगाकर
+अतएव
+गार्डन
+बैठे
+मदन
+चौहान
+चन्द्रमा
+उठाने
+जायें
+अर्ध
+तारीख
+डाउनलोड
+अनु
+ओलंपिक
+श्रंखला
+दिखाने
+अमिताभ
+मौर्य
+मुताबिक
+प्रपात
+फोटो
+लक्ष्मण
+मालूम
+देगा
+अपील
+लेंस
+स्पेस
+बिन्दु
+द्वीपों
+स्विट्ज़रलैंड
+अर्जेंटीना
+पूछा
+वोट
+अकाल
+शत्रु
+कबीर
+आचरण
+सफलतापूर्वक
+एक्सचेंज
+उत्तराखंड
+शिकायत
+शंकराचार्य
+धारावाहिक
+दृश्यों
+१९९०
+तूफान
+सड़कों
+अपेक्षित
+बाढ़
+प्रोजेक्ट
+पहुँचने
+हूं।
+ग्रांड
+उन्नति
+कच्चे
+स्वीकृत
+बहती
+व्यायाम
+प्रयोजन
+एरिक
+ऑटो
+इंटरसिटी
+सरलता
+उपनगरीय
+अनाज
+धातुओं
+संकल्प
+तेरे
+धूप
+वंशज
+परिपथ
+घोड़े
+मोक्ष
+तालाब
+असमर्थ
+श्रद्धा
+विनाश
+सापेक्ष
+अद्वितीय
+सराय
+सुरेश
+जनजाति
+ट्यूब
+रहकर
+कैम्ब्रिज
+श्वसन
+सुविधाएं
+सूत्रों
+बंध
+जंगलों
+नेत्र
+डीएनए
+बिलबोर्ड
+आदिवासी
+दिखने
+गाया
+आर्थर
+नैशनल
+सिक्के
+वायुयान
+समक्ष
+समतल
+पिछली
+छोड़े।
+विधा
+सीखने
+कालीन
+बौद्धिक
+विधेयक
+सक्सेना
+खा
+यूनियन
+परमात्मा
+संस्करणों
+योद्धा
+पैटर्न
+स्त्रियों
+कर्तव्य
+जातियाँ
+वंशावली
+कमाई
+पैसा
+वसंत
+कहलाती
+एंजिल्स
+अपोलो
+सिंहासन
+इनपुट
+बस्ती
+दीवारों
+प्राधिकरण
+संभवत
+भालू
+केबल
+पुष्प
+सिंचाई
+मानने
+कॉल
+क्रॉस
+अभिगम
+उपलब्धि
+राजनीतिज्ञ
+नोट्स
+बे
+मेजर
+ग्वालियर
+प्रजातियां
+लॉ
+प्रसन्न
+यूएस
+रहेगा
+बुरा
+रोल
+नली
+उक्त
+राजकीय
+हल्के
+हंगरी
+पैलेस
+बनकर
+फेर
+पुरे
+घड़ी
+कविताओं
+स्वरुप
+सेनानी
+अवयव
+अनुप्रयोगों
+कृतियों
+ध्रुवीय
+विल
+इंडोनेशिया
+बहुमत
+टिकट
+कठिनाई
+शासनकाल
+कार्यान्वयन
+दायित्व
+जर्सी
+वितरित
+मूर
+टर्मिनस
+सुन
+जाएगी
+फोर्ड
+दीपक
+चित्रकला
+गरीबी
+सेमी
+तात्पर्य
+संलग्न
+आश्चर्य
+मेहरा
+१९९८
+भंडार
+परिषद्
+लाइब्रेरी
+बंधन
+इण्डिया
+कोयला
+महमूद
+सुना
+नंदीग्राम
+संतोष
+यूके
+जागरण
+बदलकर
+नींद
+बचे
+किसानों
+खुशी
+स्पोर्ट्स
+बलों
+भंग
+कहानियां
+सफाई
+रहस्य
+कणों
+किशन
+वृत्त
+अरुण
+मानस
+प्रेमी
+हमलों
+जीते
+नमूने
+त्वरित
+नम्बर
+शरण
+आतंकवादी
+रंगमंच
+टुकड़े
+निकलता
+ठंडा
+खेत
+गेम्स
+राजेन्द्र
+तालिका
+तटीय
+दिनेश
+भंडारण
+निकला
+मध्यकालीन
+५००
+पान
+चक्कर
+ब्राउन
+वाणी
+असाधारण
+यकृत
+बोलते
+रोटी
+झूठ
+पौधा
+वेदों
+संक्रमित
+जितने
+खूब
+नाभिकीय
+ज्यामिति
+रेटिंग
+जिम्मेदारी
+प्रेमचंद
+एजेंट
+निरीक्षण
+लुईस
+नित्य
+मेमोरी
+उतनी
+उसपर
+पड़ोसी
+तुम्हें
+वचन
+लोकतंत्र
+पार्श्व
+संवेदनशील
+उत्पादित
+सीरीज
+कॉर्पोरेट
+सूचकांक
+चैनलों
+अनंत
+नीतिया
+रिकॉर्ड्स
+ज़रूरत
+भावी
+होल
+विवादास्पद
+पिनकोड
+सरकारों
+पहलुओं
+जादू
+तपस्या
+विहार
+मोटी
+रुपए
+अपितु
+व्यंग्य
+सीधी
+सिर्फ़
+गुवाहाटी
+बेच
+नाटकीय
+शोर
+पुराणों
+मरीज
+वाजपेयी
+तिवारी
+रही।
+ब्रेक
+फैले
+विन्यास
+भाप
+थोड़े
+सर्वोत्तम
+शशि
+पार्वती
+रचनाकाल
+अदा
+गयीं
+पुर्णिया
+बॉन्ड
+बिन
+मोंटे
+नाक
+दीक्षित
+जिनमे
+अवलोकन
+नस्ल
+डेनमार्क
+वरुण
+विभक्त
+सैकड़ों
+अनुभूति
+पंजीकृत
+मतभेद
+कॉमेडी
+कलात्मक
+निकाय
+तरफ़
+आणि
+साथियों
+गुलाब
+झिल्ली
+सोना
+संश्लेषण
+इलाकों
+पण्डित
+आया।
+रेसिंग
+खपत
+टेलीफोन
+पड़ते
+दिलीप
+ई०
+एकादशी
+प्रतिबंधित
+फलों
+साइड
+उपासना
+खोटे
+प्रिक्स
+एचआईवी
+आमंत्रित
+फार्म
+इसपर
+रेंज
+१९९९
+प्रयाग
+मंगोल
+शासित
+रद्द
+अजय
+भाजपा
+आईएसबीएन
+सुमित
+एवम्
+रजिस्टर
+विकीस्रोत
+इंदौर
+बोइंग
+अमृतसर
+मकान
+पारिस्थितिकी
+मैड्रिड
+समन्वय
+अन्ना
+लोहा
+कम्युनिस्ट
+गण
+अवसरों
+ब्यूरो
+चूँकि
+खुली
+तन्त्र
+राजपूत
+समझते
+बिहारी
+वैष्णव
+चैंपियनशिप
+प्रतिकूल
+सिंड्रोम
+बंबई
+अमृतपुर
+ख्याति
+पुर्तगाल
+क्यूँ
+घ
+नारी
+अनुभाग
+मैरी
+गर्भाशय
+सर्व
+पूर्ववर्ती
+चतुर्थ
+इमारतों
+रेजिस्ट्रेशन
+प्रभु
+अस्वीकार
+साक्ष्य
+वॉ
+बढ़कर
+इनकार
+सांस
+प्रतिवर्ष
+भाषी
+बढा
+मूत्र
+अरारिया
+निकलती
+क्रिटिक्स
+धारक
+उपयोगिता
+त्योहार
+समेत
+प्रतिरक्षा
+बटन
+समर्थ
+दा
+नगरी
+तेज़
+भूतपूर्व
+देखता
+दमन
+अनुचित
+श्रीवास्तव
+हट
+प्रशंसकों
+भंडा
+तथ्यों
+दस्तावेज
+ऑपरेटिंग
+कोशिकाएं
+वाणिज्य
+पोषक
+धीमी
+वियतनाम
+स्कॉट
+रहीं
+घाव
+प्रावधान
+१९९२
+बैक
+श्रीराम
+मुकाबला
+स्टेट्स
+पादप
+गणतंत्र
+योजनाओं
+रोजर
+हार्मोन
+उत्पादक
+टेक्सास
+बेहतरीन
+फ़्रांसिसी
+राजस्थानी
+लगाते
+बीटा
+मान्य
+उद्धरण
+एज
+उद्घाटन
+पूर्वोत्तर
+हार्डी
+यहा
+शैलियों
+ऋग्वेद
+तमाम
+बेन
+सुभाष
+प्रशिक्षित
+दुबारा
+भीतरी
+प्रिंस
+हड्डी
+मल्ली
+बेचने
+महत्त्व
+आक्रामक
+कार्यकर्ता
+कटौती
+सोमवार
+गिर्द
+शुरूआती
+तिहाई
+खरीदने
+इट
+बिजनेस
+असंभव
+डिज़्नी
+जानकी
+ली।
+तें
+बने।
+खेले
+दादा
+पृथ्वीराज
+सांख्यिकी
+हुईं
+केविन
+बनारस
+रोशनी
+आरती
+पीछा
+स्थानांतरण
+रिश्ते
+बर्तन
+परिस्थिति
+बोले
+राष्ट्रीयता
+बलि
+इंजीनियर
+प्रमेय
+बुक्स
+उनपर
+छंद
+गुंजन
+टॉवर
+शाब्दिक
+स्वप्न
+सुधारने
+यूरो
+अवध
+तत्त्व
+निधि
+ललित
+भांति
+विमानों
+जलप्रपात
+चाहती
+आंकड़ों
+तेज़ी
+मैनेजमेंट
+मैट्रिक्स
+राजभाषा
+आयाम
+गुड
+पाली
+सनहौला
+पारस्परिक
+जंग
+पिक्चर्स
+इनको
+आस्था
+गुलाबी
+आजाद
+टेक
+ऊंचा
+एतमादपुर
+ब्लोक
+प्रतिनिधियों
+स्टेशनों
+हालत
+१९९१
+अटलांटिक
+ऊँचे
+वेबसाईट
+पत्ते
+आलू
+इन्द्र
+परिकल्पना
+सुनने
+गुलशन
+हज़ार
+कम्प्यूटिंग
+नियुक्ति
+पहुँचा
+विशेषताएं
+आयात
+खुदरा
+लैंड
+मग
+महा
+फ़िर
+अनुयायी
+काफलीगैर
+डाउन
+ओबामा
+कैद
+सूजन
+उपदेश
+विवेचन
+मोटा
+नारंगी
+धर्मों
+कुमारी
+बंदी
+ख़त्म
+अल्प
+कोटा
+चीजों
+पहाड़ियों
+८०
+सर्किट
+स्रोतहीन
+दुकान
+हंस
+सैद्धांतिक
+किरन
+देखें।
+तलवार
+सबके
+ब्रदर्स
+दोषी
+टेलर
+बॉल
+कटाई
+वाद
+पक्षों
+फ्रैंक
+नगरों
+वाहक
+विश्वसनीय
+समस्याएं
+पत्थरों
+कार्टून
+जि
+बीसवीं
+तिब्बती
+गो
+भेंट
+जगहों
+निष्पादन
+विक्रेता
+खगोल
+रोज
+कसम
+स्मरण
+क्रोध
+कॉमिक्स
+सूर्यवंशी
+पोप
+भेजे
+्य
+किरौली
+सख्त
+ग्रीष्मकालीन
+विल्सन
+सुदूर
+ढांचे
+जगन्नाथ
+ड्राइवर
+गांवों
+कश्मीरी
+स्वीडिश
+वशिष्ठ
+पीड़ा
+कहकर
+नैतिकता
+वस्तुत
+औषधीय
+मैट
+ज्योति
+नगला
+महापौर
+गठित
+प्रदाता
+श्
+आर्ट्स
+हटाना
+ऊष्मा
+सकने
+मरने
+ग्रीस
+मिश्रा
+हमसे
+आपसे
+क्वीन
+गिनती
+शिल्प
+मनोनीत
+एकड़
+रोकथाम
+हितों
+आशू
+अधिकृत
+इर्द
+सांता
+खुदाई
+स्टीफन
+विश्वकोश
+लायक
+विश्वनाथ
+गीतकार
+मुमताज़
+रूचि
+इराक
+लम्बा
+ग़ैर
+वॉशिंगटन
+आपसी
+भूमिगत
+भरपूर
+रावण
+वन्य
+सौरभ
+जुड़
+विद्युत्
+अद्यतन
+जीएसएम
+मैकमोहन
+सेतु
+दूरदर्शन
+संवैधानिक
+जीवाश्म
+डबल
+हानिकारक
+दर्पण
+पूजन
+विलयन
+िया
+लता
+उपहार
+क़ानून
+थिएटर
+परिचालन
+एकीकरण
+प्लेट
+हार्डवेयर
+समावेश
+संचिका
+अपशिष्ट
+मनमोहन
+फाइबर
+भारतीयों
+दुसरे
+आंखों
+संस्कृतियों
+यंग
+सदियों
+मत्स्य
+युक्ति
+फ्रांसिस्को
+बर्लिन
+लौटने
+मेहता
+क्षण
+पाश्चात्य
+गामा
+कैमरा
+ताजमहल
+सर्च
+बना।
+तल्ली
+साधनों
+पहचाना
+राजा।
+मेरठ
+जिसको
+मधु
+रिश्ता
+धूल
+गायब
+मोर
+सीरीज़
+इति
+सें
+सामुदायिक
+अनुदान
+ड्रम
+बडा
+कालिदास
+ब्रूस
+क्षय
+मातृवंश
+ट्रिपल
+प्रगतिशील
+गोस्वामी
+शनिवार
+हल्का
+हिन्दुओं
+फैली
+विष
+गर्भावस्था
+विस्तारित
+मिमी
+बा
+डेल्टा
+आँखों
+दीर्घ
+गंतव्य
+गणितज्ञ
+बिली
+बल्लेबाज
+क्लोराइड
+बालों
+मैनचेस्टर
+यु
+निर्णायक
+इंगित
+मयुर
+साप्ताहिक
+वैशाली
+पूर्णतया
+बच्चा
+अक्ष
+भविष्यवाणी
+भ्रमण
+हांगकांग
+ब्लेक
+रेस्तरां
+कृपा
+परेशान
+विकासशील
+मांसपेशियों
+गोविन्द
+प्राकृत
+कथाएँ
+गुलाम
+व्यस्त
+मार्गदर्शन
+कोंच
+कट
+प्रतिस्थापित
+वैभव
+पहने
+पाठकों
+बातकरें
+डॉग
+विकिमीडिया
+बेदी
+पोशाक
+चंद्रमा
+छिद्र
+इमारतें
+माउंट
+सिफारिश
+होगन
+उज्जैन
+समर्थित
+ब्रह्माण्ड
+रसूल
+श्लोक
+राहत
+आखिर
+एम्
+दाल
+पकड़ने
+मुँह
+उत्साह
+गर्दन
+तुलनात्मक
+काटने
+पाक
+महारानी
+ग्रंथि
+जरुर
+यूरोपियन
+आत्महत्या
+शर्त
+चुम्बकीय
+सम्प्रदाय
+नवीनतम
+हीरो
+मशीनों
+जयंती
+मिथुन
+उद्देश्यों
+सामयिक
+अकेला
+परिवेश
+मोड
+लवण
+चिली
+रखरखाव
+बोलचाल
+अभिलेख
+चाँद
+लें।
+सेनाओं
+अखबार
+दिखा
+रूपरेखा
+भास्कर
+समाधि
+विंडोज
+बनाया।
+भयंकर
+अमृत
+अरुणा
+ऊंचे
+खेर
+दोबारा
+बाध्य
+लगी।
+नागर
+उपन्यासों
+हीन्दी
+नाट्य
+जनक
+नमूना
+टीमों
+आउटपुट
+जोस
+कोरियाई
+मरम्मत
+डाक्टर
+सूरा
+कष्ट
+परीक्षणों
+बाएं
+भरने
+वेन
+केस
+महिलाएं
+लुप्त
+फ्रेम
+द्विवेदी
+असरानी
+शोषण
+नियमितता
+इंसान
+पद्य
+वायुमंडल
+पोल
+विलुप्त
+अपूर्ण
+बेचा
+लिनक्स
+कडी
+सतीश
+बहरहाल
+आयी
+हिन्दु
+मल
+बताने
+श्रीनगर
+लड़ने
+टोक्यो
+ऊँची
+पर्ल
+पितृवंश
+नी
+दीर्घा
+धार
+मंदी
+फ्री
+घंटा
+दोपहर
+इंस्टिट्यूट
+गुर्दे
+एचटीएमएल
+रजत
+अवकाश
+सीबीएस
+पाना
+होती।
+फेसबुक
+भगवानपुर
+पतली
+सीट
+मोड़
+मक्का
+स्पेक्ट्रम
+संरचनाओं
+इसमे
+बुध
+ब्लूज़
+अवसाद
+अफगानिस्तान
+पंजीकरण
+जरुरत
+अवरोध
+ब्राउज़र
+टाइगर
+विनिर्माण
+जालघर
+विज्ञापनों
+बॉट
+ग्यारह
+मुजफ्फरपुर
+गिनी
+परी
+मिलेगा
+कस्बे
+भाषाई
+बारी
+माँग
+गैलरी
+मिलन
+शुक्र
+आर्मेनिया
+इंस्टीट्यूट
+आत्मकथा
+सदस्योंको
+प्रतिपादन
+टर्मिनल
+रहेगा।
+पेड़ों
+मिली।
+कमीशन
+योनि
+फसलों
+गतिशील
+भी।
+संचरण
+प्रभुत्व
+उपक्रम
+समुचित
+दक्षता
+द्रविड़
+बन्द
+दिखता
+मध्यप्रदेश
+सारांश
+भीम
+अस्तित्वहीन
+हथियारों
+खुराक
+प्रकारों
+तेरा
+ताकत
+भगवान्
+लेक
+समकक्ष
+देशांतर
+ै।
+जोसेफ
+आज़ाद
+सामान्यत
+उपभोग
+भीष्म
+ऊतकों
+खिलाफ़
+लोकमान्य
+अन
+राजू
+अस्थि
+दरवाजे
+राजनेता
+आघात
+उपमहाद्वीप
+प्रख्यात
+टोनी
+टुल्सका
+विफलता
+स्टोरी
+बैठ
+बनना
+स्वतः
+भाषाविज्ञान
+दृढ़
+अर्थात्‌
+शी
+पचास
+प्रसिद्धि
+अपराधी
+डाली
+हरि
+डकोटा
+कोहली
+प्लेयर
+आश्रय
+नाग
+बिस्मिल
+छात्रवृति
+मिनेसोटा
+लाए
+सकें।
+चुनावों
+ब्रिज
+चिंतन
+बिगाड
+विमर्श
+पहुंचे
+होंगे।
+वैसा
+भूख
+दिखें
+नॉर्थ
+अवस्थित
+घेरे
+स्ट्रोक
+सर्बिया
+असल
+हिन्दुस्तानी
+घन
+वीज़ा
+महोत्सव
+घटकों
+बढ़ी
+करवा
+सुनकर
+रावल
+घट
+प्रायद्वीप
+स्वाधीनता
+विशेषज्ञों
+प्रबंधकोने
+कैलिन्डर
+धनरूआ
+डेली
+किलो
+जाट
+अधिकारिक
+माहौल
+सीटें
+पुरातत्व
+पीपल
+लीटर
+अनुकूलन
+गेंदबाज़ी
+शीह
+वायुसेना
+सूर्यगढा
+उन्होनें
+सिंध
+इधर
+टैंक
+पंच
+भूमध्य
+अफ़्रीकी
+डांस
+बलिया
+एड्स
+जनन
+जंतु
+समझना
+ग्रन्थों
+सैम
+गुरुत्वाकर्षण
+कोमल
+जायेंगे
+थाईलैंड
+टेलिविज़न
+दायर
+ज़िले
+त्रिपाठी
+प्राचीनतम
+विदेशों
+करी
+पढ़ा
+पर्वतीय
+नाइट्रोजन
+परशुराम
+स्वतन्त्रता
+चार्ज
+मेहनत
+फिलिप
+पेट्रोलियम
+नदियां
+पिंड
+उत्तरार्ध
+लेनदेन
+दीर्घकालिक
+आयतन
+मूलभूत
+टनकपुर
+डाटाबेस
+औरत
+नकल
+डि
+चैंपियन
+मोती
+होनेवाले
+दिमाग
+टेक्स्ट
+जीवनचरित
+मणिपुर
+फील्ड
+प्रक्षेपण
+निकले
+खड़गपुर
+करन
+९१
+प्रदर्शनी
+अनुष्ठान
+वक्र
+संबोधित
+शिविर
+वास्तविकता
+गोआ
+मेटल
+भगत
+सवार
+मजदूर
+शतक
+मानवता
+वॉन
+बढ़ाया
+दानव
+सदृश
+१९८९
+विभागों
+कमाल
+बचत
+मिर्च
+कॉफी
+बडे
+कीं
+फर्स्ट
+स्तन
+कोने
+संसारके
+१९७२
+डुमरिया
+क्
+आवागमन
+१९८०
+होम्स
+संकलित
+पत्तियों
+सूखे
+मुलाकात
+लास
+सनातन
+सामग्रियों
+कुत्तों
+रोबोट
+खैरागढ़
+कर्नल
+राखी
+आधारभूत
+पालीगंज
+स्पेशल
+संजीव
+अग्रवाल
+आस्ट्रेलिया
+आधी
+सूरत
+संक्रामक
+मुझसे
+मुग़ल
+वोल्टेज
+अणुओं
+ज़रा
+सील
+खनन
+समानांतर
+बोला
+ग्रे
+ष
+भागवत
+रंजीत
+मीनार
+पूर्णागिरी
+बीरबल
+गायत्री
+जबलपुर
+उजागर
+सशस्त्र
+कोच
+प्रश्नों
+बुंदेलखंड
+बडी
+बदलते
+पुर
+जीवविज्ञान
+राह
+प्रशंसक
+पर्यावरणीय
+लड़कियों
+स्टोर
+संगत
+प्रोफ़ेसर
+एलिस
+हिंद
+पूल
+भि
+९०
+भावनात्मक
+प्राथमिकता
+वाष्प
+ओल्ड
+आज्ञा
+औजार
+गैसों
+व्हिस्की
+रोका
+कहती
+जहाजों
+सशक्त
+दिवसीय
+उतार
+शान्ति
+वृक्षों
+प्रचुर
+प्रसव
+७०
+संरचनात्मक
+फीचर
+फॉक्स
+देरी
+पुरूष
+कीबोर्ड
+लाइट
+शिलालेख
+सपना
+व्युत्पत्ति
+कद
+सजीव
+लोकतांत्रिक
+स्राव
+विन्डोज़
+शॉट
+चिह्नित
+उधार
+जेट
+चे
+युधिष्ठिर
+माधव
+आसन
+संख्याओं
+शेख
+घूमने
+आक्सीजन
+राइट
+नियत
+इतिहासकारों
+एनरॉन
+रु
+पारम्परिक
+व्
+सर्वथा
+वाद्य
+आपदा
+दरभंगा
+जात
+१९७१
+लाभदायक
+म्यूजिक
+दावे
+वोल्डेमॉर्ट
+भारतवर्ष
+जोकर
+राणा
+कादर
+गढ़
+कनालीछीना
+मुकेश
+जाएं
+क्लार्क
+बॉबी
+सम्पन्न
+भूरे
+शोधकर्ताओं
+पूर्ववत
+अहिंसा
+बीमार
+जूते
+फाइल
+नारियल
+अमरीश
+अवतरण
+छेद
+शर्करा
+सेनापति
+एक्सेस
+वस्तुएं
+वादक
+दांत
+योगी
+चोल
+परिष्कृत
+श्रमिक
+नामांकरण
+सबको
+जिसपर
+इलेक्ट्रॉन
+महिमा
+क्षैतिज
+उत्तरदायी
+शूटिंग
+कारखाने
+आरक्षण
+आरेख
+किए।
+रो
+यों
+घटनाएं
+बाइबिल
+दम
+वार्ड
+ज़रूरी
+औचित्य
+एव
+१९७०
+तीस
+यूनिट
+खेलते
+डेटाबेस
+मामूली
+सफर
+अध्यक्षता
+आदर
+कॉर्पोरेशन
+चैतन्य
+िक
+निरपेक्ष
+निकोलस
+आसमान
+विश्राम
+वर्जीनिया
+अभिनीत
+आन
+संरक्षक
+दाता
+तेरी
+जॉनसन
+अल्कोहल
+दिस
+दर्शाते
+अन्वेषण
+लगाई
+जीने
+टीबी
+३००
+उदाहरणार्थ
+करण
+चंडीगढ़
+शरद
+कास्त्रो
+सहकारी
+छुट्टी
+स्थिरता
+जोड़ता
+कैल्शियम
+वुड्स
+ित
+सपने
+इत्यादि।
+प्रजा
+सेक्स
+शुक्रवार
+सर्दियों
+चीजें
+नाव
+फर्म
+हॉकी
+कहां
+विमानक्षेत्रों
+१९४७
+चढ़ाई
+परवर्ती
+क्षत्रिय
+ब्राह्मणों
+कराता
+नौबतपुर
+आयन
+आइ
+प्रवर्तन
+लिटिल
+स्वत
+नासा
+तंग
+रक्षक
+ग्रोवर
+शिवपुरी
+सीडी
+गौर
+बतौर
+कल्प
+साधु
+इकाइयाँ
+पढ़
+दीक्षा
+घंटों
+करेगी
+उदहारण
+लीवर
+सती
+बियर
+हार्वर्ड
+सहारे
+दक्ष
+१९९६
+अभिषेक
+तुम्हारी
+रेगिस्तान
+अभयारण्य
+चाचा
+प्रशासकीय
+टावर
+अनुकरण
+जें
+ऊन
+फायर
+जैसलमेर
+कविताएँ
+विक्रमादित्य
+लड़के
+न्यायिक
+आपराधिक
+निंदा
+सेठ
+गत
+दुर्योधन
+गगनचुम्बी
+हीरा
+१९९५
+वैन
+मिशेल
+मालुम
+जिमी
+रिपब्लिकन
+चटर्जी
+पेपर
+बोस्टन
+व्यापारियों
+शान
+सुप्रसिद्ध
+सचिन
+हु
+राजकुमारी
+निवारण
+विकृत
+त्रिपुरा
+लेबनान
+परेशानी
+१९९७
+देवलथल
+प्रत्यय
+मरीजों
+स्‍थान
+फतेहपुर
+ह्रदय
+अध्यापन
+लीड्स
+औरंगजेब
+वस्तुएँ
+निवेशकों
+सरोवर
+एंडी
+दिनांक
+कंट्री
+लीप
+गंध
+श्रेणियां
+आरक्षित
+मारुति
+प्रशासक
+ज़िन्दगी
+जन्मस्थान
+वॉल
+भाइयों
+सहकुंड
+शेयरों
+कवरेज
+धाम
+कर्ता
+वाल्मीकि
+संग
+सेल्सियस
+सलीम
+सूक्ष्मदर्शी
+यांत्रिकी
+इलाका
+रियल
+पंकज
+विशेषताएँ
+मकबरा
+प्रहार
+अजमेर
+अभिगमन
+केशव
+मयूर
+धनी
+ऑक्साइड
+अरुणाचल
+उपलब्धता
+नजदीकी
+इंजीनियरी
+डीन
+उपनिषद्
+जरूर
+प्रखण्ड।
+ब्रह्मांड
+शीत
+पहाड़ों
+एक्ट
+विण्डोज़
+छठी
+कश्यप
+वार्नर
+उ०व०
+बुश
+१९६०
+सन्त
+पारसी
+खोजने
+कुंजी
+रोमानिया
+इकट्ठा
+लय
+शस्त्र
+फलन
+तुलसीदास
+आदित्य
+जगदीशपुर
+नीम
+इयर
+सामान्यतया
+चार्ली
+जानेवाले
+एजेंसियों
+पाटिल
+सिगरेट
+बरकरार
+पाठ्य
+साहनी
+जोड़कर
+शैल
+पाचन
+लेट
+से।
+अनावश्यक
+गतिविधियाँ
+विषयक
+शर्तों
+असंख्य
+याहू
+विक्रय
+राष्ट्रमंडल
+ऑस्ट्रेलियन
+बलिदान
+उपेक्षा
+पाती
+गौरी
+संचित
+मार्केट
+सिकंदर
+सीरिया
+अभिक्रिया
+टक्कर
+दहन
+हैमिल्टन
+घोष
+समाजशास्त्र
+भाग्य
+चट्टानों
+साझेदारी
+पठन
+उत्तेजित
+अवशोषण
+चिकित्सकीय
+अपमान
+ओजोन
+स्तूप
+वयस्कों
+ट्यूमर
+रॉ
+इंटरफेस
+टेबल
+संज्ञानात्मक
+सच्चे
+कपड़ा
+वक़्त
+ऐल्बम
+मित्रों
+बीहता
+उदाहरणों
+ऑस्कर
+पृथक्
+घी
+अं
+सुई
+झलक
+विराम
+फोर्ट
+पुरस्कारों
+इज़
+एनबीसी
+रखा।
+सत्येन्द्र
+वर्णक्रम
+चांदी
+वेगास
+नें
+वषीश्ठ
+श्र
+बगैर
+पुनर्निर्माण
+आदान
+हिटलर
+क्षतिग्रस्त
+ज्यों
+प्रसंस्करण
+सुरंग
+शाकाहारी
+धनुष
+वैचारिक
+मधुर
+गायिका
+प्रोफाइल
+प्रतिरोधी
+उपज
+संवर्धन
+चेहरा
+बाँध
+कोर्स
+स्पेनी
+परिप्रेक्ष्य
+प्रतापगढ़
+महानगर
+सुनाई
+गद्दी
+वास्तु
+निर्देशांक
+आँखें
+व्यतीत
+उन्नीसवीं
+गिरने
+भावों
+सांख्यिकीय
+आशय
+भगवती
+साधारणतया
+भोज
+मुराद
+रवी
+प्लेस
+परंपराओं
+हिप
+डार्क
+चुन
+साजन
+परिदृश्य
+रज़ा
+ताइवान
+सवारी
+देखिये
+त्रिकोण
+कपड़ों
+पद्धतियों
+अपनाने
+स्त्रोत
+खिज़िरसराय
+समर
+जड़ी
+वेदव्यास
+१९६५
+चलन
+जिव्
+सौंप
+औपनिवेशिक
+चिकित्सीय
+ट्रेड
+स्वच्छ
+बुरे
+डैनियल
+मंगलवार
+पूर्वज
+उष्मा
+चिकित्सकों
+रूपांतरित
+जंतुओं
+नारद
+पैकेज
+नागरी
+पल
+बहुविकल्पी
+तथाकथित
+कार्यक्षेत्र
+पंख
+अवॉर्ड
+मसौढी
+तम्बाकू
+लहर
+बीमारियों
+निरूपण
+साइकिल
+थीम
+क्रान्तिकारी
+इंग्लैण्ड
+सर्वत्र
+जॉर्जिया
+शेट्टी
+छाप
+मलिक
+हैमबर्ग
+स्वदेशी
+सूचक
+१९६२
+धारचुला
+चर्चिल
+रिलायंस
+ईस
+ती
+संकर
+विजुअल
+उदार
+उद्गम
+पंचमी
+मंजूरी
+अनन्त
+प्रायोजित
+नेट
+मालवा
+लाई
+बगल
+धर्मेन्द्र
+नाश
+फीफा
+नगरपालिका
+टेप
+खुर्द
+मार्गों
+धमकी
+शिवलिंग
+प्रासंगिक
+धरहरा
+मारिया
+विवादित
+मेक्सिकन
+१९८६
+उपायों
+दरअसल
+सम्पादक
+वृत्तचित्र
+सिंगल
+लुई
+विद्यार्थियों
+मुद्दा
+फैसले
+आए।
+अलगाव
+मिशिगन
+धान
+भयानक
+पिट
+दिखाए
+ान
+चाप
+पहनने
+विशेषज्ञता
+पैट्रिक
+इनमे
+चर
+कुत्ता
+निर्वाण
+दण्ड
+नागरिकता
+दुकानों
+वर्चुअल
+लंका
+शॉन
+ब्लड
+जैक्सन
+जलीय
+अमास
+कड़ियों
+अनुसूचित
+रेत
+गारंटी
+दिशाओं
+स्टैनफोर्ड
+मूलत
+डेनियल
+परि
+सेवक
+अमृता
+शताब्दियों
+जायेगी
+दिलचस्पी
+नाईट
+मॉडलों
+हान
+स्वायत्त
+ज्वर
+जवाहरलाल
+आगामी
+कूद
+बुधवार
+राक्षस
+आयेगा।
+इंटर
+वांछित
+धमनी
+सुलभ
+बाण
+वाई
+पुरातात्विक
+गौड़
+सामवेद
+नाभिक
+अध्यापक
+समाजवाद
+उद्भव
+डैनी
+चक्रवात
+फैलाव
+एंटीबायोटिक
+चर्चित
+जितेन्द्र
+उपनिवेश
+लास्ट
+१९७५
+डाई
+गुणा
+सूट
+इलेक्ट्रॉनिक्स
+स्क्वायर
+डाले
+दुःख
+कुंड
+सांचे
+चंपारण
+प्रवास
+दुख
+अधिवेशन
+भरोसा
+तप
+महामारी
+सेब
+जेरी
+हसन
+ऑर्डर
+घोड़ा
+पासवर्ड
+खारिज
+ख़ुद
+इन्होने
+डेविस
+सरन
+प्लाज्मा
+खुलासा
+स्कॉटिश
+टोरंटो
+बेकर
+प्रतीक्षा
+कराते
+क्षमताओं
+पांडे
+हॉप
+कांच
+मणि
+ऐतरेय
+णी
+न्यूज
+संतुलित
+सीला
+विरूद्ध
+द्वितीयक
+ट्रक
+भेदभाव
+निराला
+नजदीक
+भाष्य
+आयेगा
+सहन
+उस्ताद
+नॉर्वे
+बैठा
+संस्कारों
+घने
+गोपनीयता
+स्तम्भ
+वैमानिक
+पंत
+भक्तों
+सम्भावना
+श्वास
+ओवेन
+जगत्
+फायदा
+तस्वीरें
+रुक
+निषेध
+नेटवर्किंग
+आयरन
+मॉडलिंग
+१९८४
+चंद
+शिमला
+कोल
+मनोज
+बैल
+झा
+केन्द्रों
+केप
+एकाधिक
+कुरुक्षेत्र
+डिएगो
+कराना
+फिल्मी
+ठहराया
+जिल्ला
+अमीरात
+ज़िला
+प्रतिस्थापन
+मूर्तियों
+कूट
+साहस
+बेबी
+हाइब्रिड
+पेशी
+तिरुपति
+सोलह
+इयान
+डिक्शनरी
+ताज
+बहुमूल्य
+सुगंधित
+पैनल
+वाटर
+नकली
+टैक्सी
+अस्त्र
+बुखार
+जानना
+उत्परिवर्तन
+निमित्त
+द्वारका
+फिलिप्स
+कांगो
+आइलैंड
+दाढ़ीकेश
+आक्साइड
+मिल्वौकी
+पर्वतों
+१९८५
+ढाल
+ईस्टर
+वर्षो
+उधर
+बिल्डिंग
+ज़ोर
+निर्भरता
+सिन्धु
+अनौपचारिक
+यम
+योर
+नवजात
+नियंत्रक
+अनुभवों
+विज्ञानी
+लगाये
+वर्णों
+स्वतन्त्र
+अलौकिक
+हीं
+बदलता
+डालते
+चौड़ी
+आशीर्वाद
+गोद
+उपाध्याय
+जिनको
+स्टर्लिंग
+क्यू
+सिपाही
+मासने
+अनुभवी
+अपभ्रंश
+सलमान
+दर्जे
+आईसीसी
+मेँ
+किलोग्राम
+इंजनों
+खुश
+किंग्स
+व्यर्थ
+प्राप्तकर्ता
+सल्तनत
+उत
+सीख
+१०००
+अवयवों
+जिक्र
+दीप
+ज्ञानपीठ
+कोयले
+्र
+संदिग्ध
+नम
+परमाणुओं
+मछलियों
+मार्टिना
+स्कैन
+मादक
+अधिवर्ष
+महान्
+लेखांकन
+आजीवन
+बेला
+बाली
+दाहिने
+उठ
+भूरा
+कोस्ट
+यंत्रों
+दलित
+पर्याय
+प्रस्थान
+रेखाओं
+ईस्वी
+पालतू
+गिरा
+बरौनी
+१९९४
+प्लग
+दोहरी
+एडम्स
+अजीत
+सावधानी
+थ्री
+आशंका
+सिल्वर
+न्यूयार्क
+रोमांस
+डॉट
+कॉपी
+बाप
+ईंट
+गर्भवती
+लाला
+घूर्णन
+जया
+यशवंतपुर
+पागल
+जागरूकता
+कंठ
+आईटी
+पत्तों
+समर्थकों
+टूल
+राउंड
+अन्‍य
+ग्रिड
+दंत
+हिंसक
+तार्किक
+विशुद्ध
+बैठने
+मुद्रण
+सकती।
+पहुंचाने
+कंधे
+परिश्रम
+खोलने
+वृत्तांत
+सिस्टम्स
+धरातल
+सांचा
+संवेदनशीलता
+जिंदगी
+पूर्णतः
+पुरस्कृत
+सराहना
+अन्न
+मीठा
+संतों
+डीसी
+एंड्रयू
+़
+बृहदारण्यक
+टुकड़ों
+रिजर्व
+खंडन
+उपभोक्ताओं
+टिम
+नागार्जुन
+श्रवण
+प्रविष्टियों
+कीटों
+रेसलिंग
+मैदानों
+अभिनव
+एनिमेटेड
+दीन
+बारिश
+मॉल
+डेथ
+क्रान्ति
+छोड़ा
+पुण्य
+प्रतियोगिताओं
+देह
+माइक्रोफोन
+मनाने
+किम
+हेल्थ
+अभिव्यक्त
+दस्तावेजों
+बेरी
+अपहरण
+टोपी
+बाजारों
+संग्रहित
+देखो
+बहने
+भली
+चतुर्वेदी
+विघटन
+रियासत
+भवनों
+जायेगा।
+छठे
+अपर्याप्त
+वस्तुतः
+कार्बोहाइड्रेट
+इंजेक्शन
+नायर
+विद्रोही
+बैटमैन
+गोल्फ
+प्रतिज्ञा
+जरा
+पीस
+बदलती
+खरीदा
+इंटरनैशनल
+झुकाव
+लाना
+उत्थान
+सुसज्जित
+अर्चना
+ओं
+लोड
+कमांडर
+१९८२
+विद्यालयों
+व्याप्त
+आतंक
+अनियमित
+विंग
+चंद्रशेखर
+जाहिर
+त्र
+काटकर
+गिल
+इवान
+एंटी
+जाता।
+प्रदीप
+वकालत
+परजीवी
+प्रणालियां
+अहम
+केले
+चन्द्रगुप्त
+इक्विटी
+दोस्तों
+विद्यापीठ
+समर्पण
+जिल
+तोड़ने
+फिलाडेल्फिया
+पंचायत
+चिड़ियाघर
+नर्मदा
+विनियमन
+परम्परागत
+लॉजिक
+बधाई
+टेक्नोलॉजी
+थाई
+मापने
+सोशल
+७५
+फॉण्ट
+चित्रकूट
+प्राइवेट
+मराठा
+तुम्हारा
+जमशेदपुर
+१९६१
+सावली
+भूमिकाओं
+चयापचय
+अभिन्न
+किन
+खंडों
+एलिजाबेथ
+ग्रहणाधिकार
+ताजा
+निक
+उदा
+प्रयोजनों
+पश्चात्‌
+लेखो
+गन
+नमस्ते
+जोनाथन
+गोविंद
+ऑटोमोबाइल
+गोलाकार
+गंभीरता
+फिनलैंड
+प्रबन्धन
+पूर्णविराम
+एलेक्स
+मनोहर
+सौदा
+स्टाइल
+२०१२
+पीट
+सामरिक
+रेड्डी
+दया
+प्रा
+वॉल्ट
+वादा
+दरों
+उपन्यासकार
+तरंगों
+स्पैनिश
+बरेली
+दोस्ती
+विकारों
+पंक्तियों
+दिखायी
+ड्रैगन
+चाँदी
+यश
+विकृति
+बेसिक
+कामयाब
+हल्की
+अंडा
+वास
+आर्मी
+कार्तिक
+श्रे
+ब्रह्मचारी
+अर्द्ध
+ग्रेड
+फिल्मांकन
+पूर्वानुमान
+साइटों
+मैत्री
+इज
+कलाओं
+मुद्रित
+मिलर
+सुंदरता
+युवाओं
+विंबलडन
+मीले
+पाणिनि
+सहारनपुर
+पिशाच
+केंडीबार
+मृ
+डिवीजन
+निकलकर
+निभाया
+मनी
+वक्ता
+सिग्नल
+कैलाश
+वाक्यांश
+तुर्क
+विशेषण
+निशाना
+अग्रसर
+रैंक
+१९५०
+खाद
+ङ
+सीटों
+कनेक्शन
+पेट्रोल
+तु
+ग्राफ
+रण
+कंट्रोल
+रत
+जुड़वां
+पूर्वक
+बर्बरता
+पेरू
+एहसास
+व्याख्यान
+गिल्ड
+न्यूज़ीलैंड
+कमान
+पुत्रों
+फ्रांसिस
+पुजारी
+भरतपुर
+कुवैत
+मापा
+खाई
+थकान
+रिक्त
+अनुमोदन
+लेडी
+बाएँ
+शोथ
+अभिप्राय
+युवक
+स्टेम
+नीलम
+पीरपैंती
+प्रतियां
+बहाव
+बहार
+उत्
+अरविन्द
+आराधना
+मंगोलिया
+ध्वन्यात्मक
+फ़ेडरर
+एयरपोर्ट
+बाबर
+टेरियर
+क्रमिक
+विषम
+१९९३
+चालित
+स्थाई
+शीतल
+सज़ा
+अनुपस्थिति
+बफ़ेलो
+होस्ट
+क्लान
+जाएंगे
+ऊर्ध्वाधर
+द्रौपदी
+सूप
+रुपया
+१९४८
+मीना
+शेक्सपियर
+बेकार
+टैगोर
+किताबें
+प्रविष्ट
+सौंपा
+चा
+हिंदुओं
+ऑब्जेक्ट
+अवशोषित
+सातवीं
+पिन
+अयस्क
+हाइकु
+संस्थाएं
+निकासी
+भीषण
+सल्फेट
+बीघा
+निपटने
+नाते
+बाला
+रिक
+समलैंगिक
+आपातकालीन
+उष्ण
+ईस्टवुड
+रचनाएं
+बरसात
+अमित
+यजुर्वेद
+प्रशा
+संपदा
+व्यंजनों
+रॉकेट
+चट्टान
+जार्ज
+यहूदियों
+विजयनगर
+अल्फा
+उत्तेजना
+प्रायोगिक
+अर्थों
+गेज
+दस्तावेज़
+मानकीकरण
+१९७७
+पैक
+टेरी
+उल्लिखित
+काच
+परास्त
+स्वीकार्य
+रचनाकार
+अलंकृत
+शपथ
+अंगूर
+अग्रिम
+वंचित
+कपास
+पाण्डवों
+दानापुर
+घोर
+कामना
+बह
+धोखा
+नं
+प्रतियोगी
+१९६७
+ज़्यादातर
+जला
+अनुशासन
+मसाला
+अंडरटेकर
+दूरस्थ
+सेठी
+उसमे
+दिलाने
+मुक्केबाजी
+संस्कृतनिष्ठ
+ग्रा
+कोकेन
+जेरिको
+ठंडे
+प्रोडक्शन
+गर्ल
+विराट
+गेंदबाजी
+पैन
+जज
+कराची
+महानगरीय
+स्टाफ
+मजदूरों
+एनीमेशन
+शाखाएँ
+वाइन
+१९५६
+एंव
+वीर्य
+सकते।
+तलाई
+परिपक्व
+डेल
+अवस्थाओं
+सर्प
+उन्मुख
+भूभाग
+युद्धों
+रूढ़िवादी
+नाथनगर
+नामके
+लॉस्ट
+कॉट
+नियामक
+वहन
+कलम
+सम्राट्
+परिपूर्ण
+इश्क
+ड्रीम
+कब्र
+मोम
+अल्बर्ट
+दूरबीन
+उदर
+कानूनों
+जवान
+इन्हे
+सौदे
+गान
+दामोदर
+बेलारूस
+श्रेण
+दिख
+दही
+विजयी
+घोल
+चालीस
+मध्ययुगीन
+पेंगुइन
+समायोजित
+मिनी
+पीसी
+फ़्रांसीसी
+सीईओ
+भजन
+आदत
+लिखकर
+१९६८
+परमेश्वर
+एरिया
+कमर
+रेशम
+मिसाइल
+जेन
+मोटर्स
+उग्र
+शैव
+डालता
+यूनिवर्सल
+पिनांग
+फ्लैश
+विजेताओं
+१९८८
+स्वरों
+बैंगनी
+स्विच
+फेफड़ों
+सच्चाई
+चरित
+निकटवर्ती
+इंद्र
+निवेशक
+सिकंदराबाद
+पूंछ
+समाहित
+चित्त
+फिट
+खुसरो
+सार्वभौमिक
+खाया
+स्थानिक
+चिट्ठा
+लग्गा
+समझे
+उपसर्ग
+भोग
+साइन
+क्रीम
+पाकर
+बोलियों
+सका।
+१९७३
+सिद्धि
+गुलज़ार
+आलोचनात्मक
+मिलाया
+शोभा
+ऐनी
+दायरे
+गईं।
+जाएगी।
+वाल्व
+वैली
+रामचंद्र
+संध्या
+क्रय
+सम्बद्ध
+जमाने
+सहस्रनामन
+ध्वस्त
+किरणों
+कै
+आएगा
+एस्टन
+सोचना
+अनुयायियों
+जवाहर
+मॅट
+निभाने
+का।
+क्रोएशिया
+कीर्ति
+कल्चर
+चालु
+ईथेन
+इरादा
+न्यास
+वृंदावन
+हिम
+गेट्स
+ज़ी
+वृद्धी
+परीचय
+डेबिट
+कार्निवल
+सकी
+नालंदा
+यो
+परेश
+कालांतर
+मुखिया
+डेड
+डब्लू
+सांख्य
+फ्रैंकफर्ट
+अजीब
+वृत्ति
+एफ़
+अबतक
+रूट
+हिस्सेदारी
+आवेश
+रू
+अंतरण
+वॉकर
+भवानी
+पत्ती
+धवन
+लाभकारी
+मैगज़ीन
+ओपेरा
+निकलते
+परिधि
+विलक्षण
+बताती
+शिक्षित
+१९५४
+विद
+लेफ्टिनेंट
+उल्लेखनीयता
+जोली
+रतन
+डालर
+उड़िया
+अनुपालन
+क्रिस्टोफर
+केदारनाथ
+डायोड
+तराई
+गुरारू
+प्रतिपादित
+धुरी
+प्रतिबिंबित
+अंग्रेज़
+स्टेज
+खलनायक
+सुप्रीम
+राष्ट्रवादी
+स्विस
+कैथरीन
+अपोल्लोन
+हिल्स
+प्रवर्तक
+रबर
+जोड़ों
+बॉम्बे
+विवादों
+वेस्टर्न
+मध्यवर्ती
+मालिश
+दीवाना
+गुरुवार
+दर्शाती
+गतिविधियां
+मुख्यधारा
+ऋषियों
+खिलाडी
+औसतन
+फ्रेडरिक
+पंचम
+सूखी
+चौड़ा
+विधियाँ
+१९८७
+बेंजामिन
+गली
+हफ्ते
+डीप
+नलिका
+पिंक
+आईपी
+साउंडट्रैक
+दिनकर
+एमटीवी
+अंकन
+क्रूज़
+कैफीन
+बल्लेबाजी
+देसाई
+ऑप्टिकल
+विद्वान्
+हेड
+लेंगे।
+शिवा
+बॉण्ड
+कुशलता
+क्वांटम
+अनिश्चित
+कन्नड
+विचित्र
+रग्बी
+रिव्यू
+प्रपत्र
+निष्पक्षता
+आर्कटिक
+समस्याएँ
+प्रयोगात्मक
+जुडना
+वाल
+ज़िम्बाब्वे
+तलाक
+व्योम
+बिक्रम
+अमीनो
+प्रतिस्पर्धी
+श्रीश
+विश्वव्यापी
+ग्राउंड
+पॉवर
+्ड
+बहुतायत
+मौसमी
+उतर
+तैनात
+चित्रकारी
+इंटरफ़ेस
+खगोलशास्त्र
+गुहा
+अपराधों
+पाउडर
+नॉन
+टिप्पणियां
+डू
+राजन
+मेघालय
+समृद्धि
+सीमेंट
+कथाकार
+गौराडीह
+कतिपय
+डगलस
+असमिया
+आदिम
+हज़ारों
+मीर
+हड़ताल
+ज्ञानसे
+पोर्टलैंड
+्रेणी
+संकाय
+दर्शाने
+अल्लाह
+बिल्ली
+श्रमिकों
+अल्पसंख्यक
+मेजबानी
+चाइना
+ह्रास
+फ़ाइलें
+गल्फ
+राख
+औषधियों
+१८५७
+आश्चर्यजनक
+हाउ
+खेतों
+विनंत्ती
+बढ़े
+ग्रीवा
+ऋषिकेश
+पुनपुन
+जटिलता
+राज्‍य
+लक्ष्यों
+डमी
+किताबों
+जोश
+लड़कों
+कॉमिक
+कैमरून
+पूर
+हमे
+१९८१
+स्पर्धा
+दिखाता
+कार्यकर्ताओं
+वरदान
+कराई
+अनुकूलित
+आचार
+गार्ड
+सुर
+मोर्चा
+१९७४
+प्रदत्त
+प्रेत
+डेवलपमेंट
+कार्यात्मक
+बालू
+पहचानने
+आश्रित
+रॉबिन
+आकस्मिक
+कस्बा
+मालिकों
+उपाध्यक्ष
+सिलिकॉन
+करेगा।
+दूत
+संग्रहण
+ड्रग
+गिरजाघर
+मोहब्बत
+घूम
+चैन
+आर्यों
+महासचिव
+फिलहाल
+मेजबान
+बसने
+१९८३
+पोत
+एप्पल
+रेणी
+मल्होत्रा
+चैप्लिन
+जीवाणुओं
+१९७६
+छाती
+ट्विटर
+सिकन्दर
+बोझ
+बैठकर
+ऐसें
+विस्फोटक
+अद्वैत
+जीवनकाल
+विचलन
+कैपिटल
+नाटककार
+उपवास
+बसें
+बांटा
+मदर
+डेस्कटॉप
+उन्मूलन
+देनी
+इच्छुक
+नेटस्केप
+बैरी
+ढाका
+ति
+तह
+एचटीएम
+खुफिया
+कामों
+आतंरिक
+सोनिया
+स्वम्
+ईमान
+सार्थक
+मेडिसिन
+काण्ड
+कॉमन्स
+अफ़ग़ानिस्तान
+शिशुओं
+शतरंज
+१२४
+गाजियाबाद
+सर्दी
+स्क्रिप्ट
+बैकअप
+छद्म
+केली
+मकर
+साधक
+मूर्तियां
+शिया
+सूरी
+छाल
+अब्राहम
+फूड
+ञ
+पालि
+मीमांसा
+मीरा
+मान्यताओं
+कैसा
+विनय
+जाय।
+लेम्बोर्गिनी
+इज़रायल
+जीनोम
+मैक्सिको
+एलिज़ाबेथ
+नॉट
+कंक्रीट
+बाधित
+यूनिक्स
+पाण्डव
+स्तनधारी
+सिवाय
+शारदा
+सत्याग्रह
+पूर्णत
+कठ
+बताई
+लीड
+उत्सर्जित
+सुधारों
+एंडरसन
+उत्कर्षराज
+कमला
+मैनेजर
+डीजल
+डेक
+शेखर
+साईट
+संयम
+बढ़ाकर
+तैत्तिरीय
+चमत्कार
+कवच
+तिल
+सप्रू
+४००
+सिंधु
+सब्जी
+पाइप
+मैथ्यू
+लेग
+वादी
+काय
+नेचर
+कागज़
+मंजिल
+बेल्ट
+प्रोफ़ाइल
+गाथा
+सीमांत
+कीमतों
+अंतर्निहित
+मुद्राओं
+जग
+ममता
+स्टीवन
+शास्त्रों
+फोरम
+लिए।
+विचारक
+प्रबंधकोंने
+हिंदुस्तान
+सिखों
+महत्ता
+गोदावरी
+खुदाबंदपुर
+दुबे
+सबका
+फिक्शन
+व्यवसायिक
+मरे
+चमड़े
+कालोनी
+सितारों
+दुरउपयोग
+आयुक्त
+नसीरुद्दीन
+दाँत
+सुलतानगंज
+राष्ट्रिय
+फतुहा
+संग्रामपुर
+सोर्स
+करेंगे।
+सहयोगियों
+क्लैप्टन
+बीजगणित
+प्रांतों
+आभासी
+दीवान
+मानो
+गौण
+लगाता
+डेनिस
+सुदृढ़
+एडम
+आभास
+सदस्योंके
+उठता
+ल्योन
+बंगला
+टुन
+लिट्टे
+नक्काशी
+बिंदुओं
+हेपेटाइटिस
+वामन
+जिलाधिकारी
+्व
+आठवीं
+फी
+जिन्ना
+क्वार्टर
+अनवर
+विंडोज़
+देखरेख
+ऑयल
+समजकर
+साहित्यकारों
+बालकाण्ड
+कौटिल्य
+जामनगर
+अंचल
+बिकने
+ज्ञानकोषकी
+अंगूठी
+खींच
+एफबीआई
+पेस्ट
+विडियो
+मिलना
+लाइनों
+भूटान
+ट्रेडमार्क
+तने
+बापकी
+अत्याचार
+मॉरिसन
+मलय
+उतने
+एंटीबॉडी
+मिठाई
+१९७९
+कोलेस्ट्रॉल
+ेणी
+संतुष्ट
+बेगम
+समझता
+पोलिश
+फ़ुटबॉल
+मीटाकर
+तारापुर
+धनबाद
+एयरलाइन
+लाकर
+अप्रत्यक्ष
+इंकार
+लौटे
+मानसून
+रॉबर्ट्स
+फोर्स
+चलाते
+प्रिंट
+ठ
+यूनेस्को
+धुन
+स्टॉप
+हर्ष
+ऊ
+सावित्री
+सलाम
+फेडरल
+जनित
+कु
+अन्तरिक्ष
+विक्टर
+इथियोपिया
+दुरुपयोग
+भारद्वाज
+नमः
+दांते
+शव
+सचमुच
+मुनिता
+चौथाई
+सालाना
+कब्जे
+ओड़िशा
+अंतत
+संगमरमर
+पारिस्थितिक
+आरम्भिक
+राघव
+मैसाचुसेट्स
+वीकीपीडीयांके
+पुनर्जागरण
+मिलक्त
+बमबारी
+अस्थिर
+प्रतीकों
+उच्चतर
+पतले
+अधिकांशतः
+चरित्रों
+सौन्दर्य
+पुरातन
+डिज्नी
+ड्यूक
+कार्यालयों
+कमज़ोर
+मेट
+शेफ़ील्ड
+आरएनए
+उत्प्रेरक
+सेक्शन
+संभोग
+बास
+वापिस
+राष्ट्रभाषा
+सस्ते
+मैदानी
+लग्न
+भोजपुर
+कुण्ड
+सघन
+फ़ॉर
+१९६४
+संस्मरण
+फॉर्म
+वैद्युत
+पाम
+परदे
+अचल
+ग़लती
+मंद
+बरियारपुर
+शुद्धता
+परवेज़
+बॉय
+जीभ
+रोलिंग
+बदलना
+स्टब
+भुवनेश्वर
+कोइ
+हस्तांतरण
+मुकदमे
+फैलने
+पैरिस
+प्रत्यारोपण
+अफ़्ग़ानिस्तान
+दयाल
+कवक
+मेमोरियल
+एयरबस
+इंटेल
+फिल्मफेयर
+बरोबर
+पहुँचे
+सावरकर
+कुरान
+माली
+दिखाते
+किनारों
+निचली
+कराती
+किस्मों
+रहेंगे
+रीढ़
+खजुराहो
+शियर्र
+घात
+स्वयंसेवक
+मेगावाट
+झरने
+बाढ
+ग्रीष्म
+हराकर
+ठंडी
+गेहूं
+ओबेरॉय
+फ्रेंकलिन
+केंद्रों
+शुक्राणु
+रूपये
+इकाइयां
+हटाकर
+प्रचारक
+रैंकिंग
+नीली
+क्लाउड
+निजामुद्दीन
+फर्क
+ग्लास
+उपजाऊ
+गैरी
+घुटने
+सत्यजित
+न्यून
+कमजोरी
+जोएल
+हरीश
+जन्मदिन
+क्योकि
+शिवराज
+ख़़ुदा
+सिक्कों
+पंचांग
+मिथिला
+१९३०
+पेशे
+राष्‍ट्रीय
+पहना
+कॅरियर
+प्रतिष्ठान
+मालदीव
+कलाम
+गेहूँ
+हुयी
+दुष्ट
+रांची
+टुकड़ा
+डाकू
+प्रक्रियाएं
+सहाय
+फ्रंट
+निकास
+लहसुन
+हेलन
+डाइऑक्साइड
+श्रद्धांजलि
+चिप
+रोमांटिक
+बॉडी
+शोक
+सितारा
+लेनी
+आयुर्विज्ञान
+फेम
+हरित
+हीमोग्लोबिन
+ब्रायंट
+गोला
+मानद
+कब्ज़ा
+व्यू
+प्रदर्शनों
+डेमोक्रेटिक
+फेंक
+आंत
+समुच्चय
+मातृभाषा
+महाराणा
+रिटर्न
+१९५७
+छपाई
+उपग्रहों
+गोले
+जीवंत
+रियो
+ैं
+दृढ़ता
+धीमा
+गज
+यादृच्छिक
+विपक्ष
+विमानन
+कथाएं
+चेष्टा
+गतिशीलता
+लालकुआँ
+१५०
+दिलचस्प
+बैक्टीरिया
+पवार
+ढांचा
+पंप
+नूतन
+आमन्त्रित
+पुस्तिका
+चौदह
+फोर
+सऊदी
+सरसों
+कैलिफ़ोर्निया
+नेल्सन
+रकम
+६५
+कहा।
+नायिका
+आभार
+अनजाने
+एस्टर
+एलेन
+प्रेरक
+जरुरी
+वाइल्ड
+विशेषाधिकार
+नरसिंह
+ब्रदर
+अधिकता
+बर्मी
+धाराओं
+सिंघल
+समीक्षकों
+राजदूत
+समारोहों
+ढेर
+सूखा
+अर्जेन्टीना
+प्लेटो
+१९६३
+१९६६
+स्थलाकृति
+इरादे
+कर्मों
+जानेवाली
+क्षीण
+मरुस्थल
+प्रांतीय
+स्काई
+ऍ
+विशिष्टता
+एमी
+अरबों
+इंसुलिन
+युवावस्था
+कैमरे
+नमूनों
+जावेद
+नक्शे
+सु
+१९६९
+संकुचन
+किय
+समीक्षाएं
+स्पिन
+हवाला
+कारावास
+शिक्षकों
+नाहीं
+सर्जन
+दाने
+उठाते
+वरन्
+६००
+उठाना
+भट्टाचार्य
+्ता
+डोनाल्ड
+संतृप्त
+हड्डियों
+मिलाने
+करनेवाला
+निकोबार
+दे।
+सॉसेज
+चेतन
+त्रिवेंद्रम
+ऐन
+करीबी
+मासको
+पहेली
+देशभर
+इमेज
+मोटाई
+सिगार
+ऑक्सीकरण
+मैनुअल
+सूअर
+चलना
+पड़े।
+पर।
+पराजय
+मंगेशकर
+नर्तकी
+यज्ञोपवीत
+देखिए
+द्योतक
+आतां
+मीठे
+भागने
+रूपी
+परिणत
+श्रृंगार
+शक्तिपीठ
+कुरु
+बीजिंग
+मुगलों
+घटा
+सच्चा
+वान
+पैकेट
+चौथान
+मॉर्गन
+सिवा
+इन्टरनेट
+वैधानिक
+मास्को
+भेड़
+रोहिणी
+मैरीलैंड
+भेजी
+मिर्ज़ा
+परिशिष्ट
+निर्माणाधीन
+असे
+रॉन
+डायरी
+द्
+संदूक
+नक्शा
+विराजमान
+विकल्पों
+प्रधानता
+लिपियों
+काउण्टी
+याचिका
+वरीयता
+विजू
+त्रुटियों
+निर्देशिका
+चूर्ण
+समूचे
+प्लस
+टाइपिंग
+लिखें
+दोहरे
+प्रथाओं
+निर्मल
+रस्सी
+बेखम
+ण्ड
+बजाया
+मुलायम
+हमीरपुर
+बंधक
+प्रतिरक्षी
+आपरेशन
+निसान
+नरम
+वॉल्यूम
+ख्याल
+क्रैमलिन
+इट्स
+थ्योरी
+शेयरधारकों
+सुमीत
+अंदरूनी
+लवी
+माधुरी
+खातों
+गाड़ियों
+सजावट
+निपटान
+खोलकर
+जन्मा
+पीएच
+अभिनेताओं
+चावला
+प्रेमिका
+स्विट्जरलैंड
+ब्राउजर
+मोदी
+शेरशाह
+नमी
+चालुक्य
+सूफी
+उचाई
+कोलम्बिया
+सू
+उठाकर
+ग़ज़ल
+क्षरण
+ग़लत
+खरीदारी
+दुल्हन
+शम्मी
+निष्ठा
+प्रविष्टि
+साम्यवादी
+रहेगी
+अनोखा
+स्तुति
+उपलब्धियों
+परियोजनाएं
+गद्यकार
+स्विफ्ट
+इंडीज
+लौकिक
+कोशों
+प्रिया
+शिष्यों
+निकली
+बाँटने
+टकराव
+मौजूदगी
+निरन्तर
+आकाशवाणी
+उल
+चीफ
+सुविधाजनक
+यादगार
+समाचारपत्र
+म्युज़िक
+सूचनाओं
+जमालपुर
+रोकता
+लक्षित
+दौलत
+स्पेंसर
+लालू
+पिच
+आसवन
+ज्वार
+पाषाण
+संयोजित
+अरे
+ईथरनेट
+मय
+आखिरकार
+एथेंस
+लड़का
+धूम
+निर्देशों
+आहे
+प्रयोगकर्ता
+झीलों
+ज्वाला
+नागालैंड
+आपत्ति
+कांस्य
+ख़राब
+करनेवाली
+विगत
+ार्ता
+फेडरेशन
+वैसी
+युनुस
+वस्त्रों
+श्रद्धालु
+अदृश्य
+सामर्थ्य
+६३
+हार्दिक
+मानदंड
+बौना
+सुनवाई
+शॉपिंग
+बराबरी
+सि
+पलायन
+लाइसेंसिंग
+अञ्चल
+जगदीप
+गोत्र
+देहांत
+कार्टर
+प्रतिबन्ध
+शैतान
+फांसी
+रीड
+बोतल
+गोविन्दा
+सामंजस्य
+फर्श
+फिल
+यूएसए
+गाते
+उपक्षेत्र
+एंग्लो
+तुमने
+बुगु
+निर्वाह
+बताए
+दूरदर्शी
+धोखाधड़ी
+संचालक
+तकरीबन
+आमिर
+स्टारबक्स
+जड़ें
+रूम
+टेल
+घोड़ों
+नरसंहार
+प्रीति
+अश्लील
+कलश
+कैलगरी
+८५
+घूमते
+प्रवक्ता
+वूल्वरिन
+अप्रत्याशित
+आंकड़ा
+ग्रीनहाउस
+फेस्टिवल
+अनूदित
+सर्वे
+चेन
+छवियों
+अधिकाधिक
+मिटा
+पिरामिड
+अग्र
+चाणक्य
+प्रक्षेपास्त्र
+१९७८
+विक
+टंडन
+मैनहटन
+कैच
+मौन
+टमाटर
+सांद्रता
+इस्तीफा
+करवाने
+समीक्षक
+फारस
+वज़न
+प्रवृत्तियों
+लुइस
+उत्तीर्ण
+राँची
+वनस्पतियों
+अल्फ़ा
+रीडर
+गेंदबाज
+नकद
+क्रिश्चियन
+राजेंद्र
+ऐल्कोहॉल
+कच्चा
+असोसिएशन
+लैंग्वेज
+मसाले
+ज़रूर
+मंडी
+सुमन
+सनी
+कर्मियों
+साइबेरिया
+कंपन
+आवर्त
+रुधिर
+गढ़ी
+चिकन
+स्नेह
+दत्ता
+धर्मग्रन्थ
+जौनपुर
+मुरादाबाद
+पर्वतमाला
+लौटा
+लाये
+गोपी
+दाएं
+पुनर्जीवित
+आगम
+प्रतिक्रियाओं
+हीरे
+तीर
+भ्रष्ट
+गर्भाधान
+परेड
+टेलीग्राफ
+ऐक्शन
+वीरता
+आर्क
+इफ़्तेख़ार
+टार्ज़न
+प्रतिलिपि
+डेढ़
+सम्पत्ति
+गर्व
+मदुगु
+माघ
+मूर्तियाँ
+छन्द
+कठिनाइयों
+अभियानों
+तया
+चांद
+कौषीतकि
+वास्तुकार
+पडता
+मज़बूत
+कार्यान्वित
+क्लाइंट
+पूरब
+साइमन
+क्षतिपूर्ति
+माध्यमों
+स्केल
+उत्तरदायित्व
+पतला
+पीटर्सबर्ग
+नौका
+पटल
+समझाने
+मिसौरी
+आण्विक
+एस्पिरिन
+म०ब०
+जोन
+कुक
+बाईं
+ध्येय
+ब्लेड
+कृत्य
+गार्सिया
+तीर्थंकर
+सम्मुख
+चाहीये
+मार्केटिंग
+रोमांचक
+सहानुभूति
+वायरलेस
+घृणा
+महाद्वीपीय
+उर्मिला
+बसंत
+दवाएं
+पकाने
+नन्दा
+अलवर
+निराशा
+छिपा
+तपेदिक
+आदिवासियों
+अनुवादित
+सातवें
+सिक्का
+संवत्
+सावन
+कार्पोरेशन
+उर्वरक
+राही
+ओलिवर
+पांचवें
+झीलें
+डेविल
+खां
+अन्तरराष्ट्रीय
+ब्राह्मी
+कांड
+जू
+गाँवों
+भैरव
+वीकली
+टुडे
+बेसिन
+बाघों
+निरूपित
+शाप
+मन्त्री
+कुंडली
+अथ
+राष्ट्रगान
+आणविक
+दांतों
+वैश्वीकरण
+कहें
+शैवाल
+सिलसिला
+कैरी
+१९५५
+काबुल
+मोटरसाइकिल
+विवश
+फ़ूड
+अरोड़ा
+गिरोह
+पते
+झरना
+अनुमोदित
+मांडूक्य
+कडियां
+मजाक
+जरी
+विकीपीडिया
+होत
+जमैका
+स्पष्टीकरण
+पाद
+जरूरतों
+एम्पायर
+हस्त
+संहिताओं
+लड्डू
+मध्यकाल
+वीकी
+देवगन
+चित्रआकार
+विदिशा
+कॉफ़ी
+सेंचुरी
+होते।
+मित्रता
+कठोरता
+वज़ीर
+रूपक
+अश्वेत
+राज्यसभा
+आभूषण
+चैम्पियन
+उपरान्त
+लार्ड
+नोबल
+प्रविष्टियां
+बस्तियों
+िए
+नानक
+बर्ड
+पड़ेगा
+लिंकन
+बहाल
+९६
+बंदूक
+रेट
+अयोध्याकाण्ड
+महाप्रभु
+ग्राहम
+नल
+डार्विन
+ग्रेटर
+कारखानों
+वाट
+सोचने
+हिम्मत
+बढाने
+लेबर
+गिना
+पूर्वजों
+बेचे
+हरिवंश
+श्वेताश्वतर
+माइक्रो
+सीनेट
+पु
+दिए।
+नकदी
+ब्रॉडबैंड
+फ्रेमवर्क
+दाग
+ँ
+ग्लूकोज
+आश्वासन
+दरगाह
+बीवी
+किस्में
+अभिकल्पना
+इन्दिरा
+रामकृष्ण
+शेन
+वार्
+पॉइंट
+झांसी
+चेल्सी
+वाइस
+महानतम
+विश्वसनीयता
+चूना
+डिस्प्ले
+प्रकोप
+सदाबहार
+लोहिया
+मीनाक्षी
+र्ता
+हावर्ड
+इस्लामिक
+कौशिक
+भुजा
+पहलवान
+जादुई
+अर्थशास्त्री
+मनमौजी
+शायर
+डिजाइनर
+समयावधि
+सपनों
+मर्यादा
+रेकी
+दरवाजा
+उत्त
+बारूद
+हे।
+कुर्सी
+जन्मजात
+लूट
+नियोजित
+नियोजन
+तेरह
+हिंगू
+मैडोना
+्म
+सोमनाथ
+पीपुल्स
+मुद्रास्फीति
+बजाने
+काँच
+तैराकी
+साबुन
+अभ्यारण्य
+बढ़ाते
+तन
+उ०प०
+महासभा
+अहंकार
+मांसपेशी
+निर्वात
+खतरों
+जाओ
+हैपलोग्रुप
+हैवीवेट
+आरोपों
+सितारे
+विनियमित
+सब्जियों
+शीतकालीन
+पार्टियों
+शिला
+रसवात्सल्य
+पश्च
+चॅक
+लड़ाकू
+तुझे
+रॉस
+क्लोरीन
+विषाक्तता
+मानों
+वाक्यों
+प्रतियों
+उल्टी
+हैरिस
+निकालना
+अक्षम
+सिंधी
+विशेषत
+आस्ट्रिया
+अवगत
+साधारणत
+मार्क्स
+चीता
+व्यवसायों
+डालना
+क्षितिज
+पालिका
+उल्टा
+कारखाना
+सैयद
+कमेटी
+भला
+फेयर
+फ्लू
+रामभद्राचार्य
+स्प्रिंगस्टीन
+पिस्टन
+संदर्भों
+जनसँख्या
+आनुवांशिक
+उषा
+ज़रिए
+सीमाएं
+घर्षण
+प्रौद्योगिकियों
+दिखती
+मतों
+लत
+बैले
+एक्यूपंक्चर
+फोटोग्राफर
+क्रिकेटर
+अनीता
+इण्डिक
+आधिपत्य
+सतही
+गुफाओं
+प्रतीकात्मक
+नशीली
+शुक्ला
+शेंगेन
+फास्ट
+बुल्गारिया
+महंगे
+सनम
+नज़रिया
+हेलो
+माथुर
+सेवाएँ
+रिपब्लिक
+सेंसर
+सर्कल
+बिज़नेस
+सेकेंड
+असत्यापित
+कैनेडी
+दुर्भाग्य
+विनायक
+कारगर
+प्रस्तावना
+अरस्तू
+बताये
+गृहयुद्ध
+तर
+शीट
+गिरफ्तारी
+वार्मिंग
+इसीलिये
+महासागरीय
+खनिजों
+पेरी
+जटिलताओं
+जीती
+लॉरेंस
+पूर्
+साठ
+सूडान
+एबीसी
+संस्थाएँ
+सिएटल
+आख्यान
+बोल्ट
+खानों
+यीशु
+परिलक्षित
+अभिमन्यु
+दैत्य
+पॉलिन
+निकाली
+राष्ट्रवाद
+खोजा
+साक्षी
+पारदर्शी
+७२
+जाएँगे।
+फुलवारीशरीफ़
+वैवाहिक
+जुलती
+सेंटीमीटर
+ईश
+नाभि
+रेशे
+संकीर्ण
+नेताजी
+टीके
+एड्रेस
+विश्‍व
+चार्टर
+बीना
+मधुबनी
+पियानो
+हेक्टेयर
+मंगलौर
+फलत
+सीने
+संभाल
+अलास्का
+स्पाइवेयर
+सुलोचना
+नीलगिरी
+तैसें
+उभरा
+राजकोट
+मिलीग्राम
+फाइलें
+हिब्रू
+बैग
+आटा
+होतीं
+शंख
+मजबूती
+सीना
+उनमे
+आज़मी
+अभिलेखों
+रोचेस्टर
+पुष्ट
+दाहिनी
+क़रीब
+कार्लोस
+जादूगर
+मैनें
+अवरुद्ध
+झ
+सस्ता
+लैंस
+टैक्स
+बैड
+इशारा
+पढ़ना
+विलायक
+ज्यामितीय
+एनी
+पत्तियाँ
+बहामास
+पढ़े
+कारें
+प्ले
+चश्मे
+प्रतिकृति
+झंडा
+उभरते
+स्टेनली
+डेव
+बेनोइट
+वीवरण
+निकालकर
+तदनुसार
+बुल
+अवशेषों
+कच्छ
+बताना
+एंटरटेनमेंट
+राज्यमंत्री
+मायने
+परख
+बराक
+मिले।
+ढाई
+प्रतिफल
+क्रियाएँ
+स्थूल
+बसु
+आकलनकर्ता
+गुट
+अथर्ववेद
+संस
+केट
+टीमें
+सैंडविच
+लेखिका
+कैबिनेट
+जुर्माना
+मारी
+मिटाने
+परवरदिगार
+अंदाज़
+मूल्यवान
+लिखता
+संचय
+साउंड
+युवराज
+विकिक्वेट
+स्कूली
+नशे
+प्रयोक्ताओं
+पापों
+पित्त
+बहल
+विकलांग
+डूब
+किंगफिशर
+कार्यक्षमता
+टेड
+वगैरह
+डाउनटाउन
+अपूर्व
+कलन
+थाली
+साढ़े
+पीली
+कृष्णन
+९९
+प्रोसेसर
+एमआईटी
+तंतु
+राजेन्द्रनाथ
+छीन
+स्टैंड
+मुरलीधरन
+कंप्यूटिंग
+सॉफ़्टवेयर
+चुप
+एसी
+प्रोटोटाइप
+चुनने
+राजी
+अंडर
+सुविधाएँ
+शरत
+हरेक
+मु
+विमानसेवा
+पड़ी।
+मूर्तिकला
+जुडी
+संविदा
+बाय
+बढ़ाता
+रुख
+लोकगीत
+समायोजन
+अमेरिकियों
+कैन
+जीप
+नक़ल
+तेथ
+श्रृंखलाओं
+ज़माने
+मशीनी
+एक्सरे
+आह्वान
+अलाउद्दीन
+प्रत्याशी
+बिन्दू
+रहस्यमय
+रेखाएँ
+पिया
+पत्रकारों
+प्रतिभूति
+उमर
+स्वच्छता
+घनश्याम
+विषाक्त
+दबाने
+अध
+जोड़ते
+वायुमंडलीय
+ठंड
+बर्फ़
+फीसदी
+लेआउट
+दरिया
+क्लबों
+छत्रपति
+असुरक्षित
+नागरकोविल
+कार्यो
+सौभाग्य
+परवाह
+महंगा
+युगांडा
+नवाचार
+रामचन्द्र
+जुलता
+निष्कासन
+गर्भगृह
+वेदांत
+निराश
+शोधकर्ता
+पड़ोस
+मौके
+असफलता
+गय
+जयसिंह
+हैदर
+संगीतकारों
+दीपावली
+मूसा
+समाजों
+मानवाधिकार
+जोड़ना
+ट्रम्प
+एंजाइम
+गांधीजी
+चुनी
+१९३१
+डिवाइस
+समझाया
+हजरत
+प्रमोद
+कुशीनगर
+बर्मन
+गोलार्ध
+मोह
+पढ़ते
+गवाह
+मर्सिडीज
+आमन्त्रण
+कतर
+एकाधिकार
+टायसन
+ऑपरेटर
+बलराम
+होंगी
+आये।
+नानी
+अलीगंज
+जहा
+विद्युतीय
+जड़ों
+अपराधियों
+द्वि
+जौ
+बंदर
+बढ़िया
+रेसलमेनिया
+इलेक्ट्रान
+फिलीपींस
+प्राप्‍त
+क्यूंकि
+विकलांगता
+जिल्हा
+सींग
+बछवारा
+हावी
+गाए
+एकेडमी
+वाइरस
+सवालों
+फोटोग्राफी
+हाइड्रोकार्बनों
+कोबेन
+स्वर्गीय
+यार
+कोशिकीय
+बखरी
+उतरने
+गैलापागोस
+विलास
+हंगल
+आज़ादी
+अंशों
+सिलेंडर
+केन्या
+अप्रयुक्त
+धर्मनिरपेक्ष
+प्रबंधको
+ताजिकिस्तान
+पुनर्गठन
+स्टडी
+समा
+ीर्षक
+दोषों
+आईएसओ
+कोला
+रेलमार्ग
+जहाज़
+बहाने
+थोक
+जानबूझकर
+बेकेट
+कमाने
+खाल
+छावनी
+डबल्स
+पहनते
+आल
+मनोरंजक
+फ्रैंकलिन
+भ्रमित
+सुज़ुकी
+वॉर्स
+वर्जित
+अनशन
+वुड
+अपवाह
+श्राफ
+एवेन्यू
+नाप
+पर्पल
+हुक्म
+भूगोलवेत्ता
+दबा
+उभर
+शंघाई
+पैकेजिंग
+नॉटिंघम
+वर्
+भूमिकाएं
+जनमत
+सीखा
+हलसी
+ग्रैमी
+सकेगा
+वार्त
+१९४०
+डैन
+कलंकीत
+कारन
+नहरें
+पडा
+२५०
+दर्रा
+ओड़िया
+कांफ्रेंस
+तिमाही
+फिल्टर
+ग्राफिक्स
+लाइक
+रोज़ेज़
+केक
+आंदोलनों
+ऑ
+७६
+गाँठ
+सेन्ट्रल
+करों
+पोजीशन
+ट्रांस
+अस्पतालों
+प्रचारित
+सपोर्ट
+समितियों
+एस्टेट
+संकुचित
+दिखते
+जलन
+उत्तराधिकार
+प्राध्यापक
+सूक्ष्मजैविकी
+मिर्जापुर
+रैखिक
+नैनोट्यूब
+वीजा
+गुजरती
+मालाबार
+निगमों
+पोरबंदर
+ट्वेंटी
+नवरातिलोवा
+्त
+७७
+जासूस
+अभूतपूर्व
+नवागन्तुकों
+वर्मनने
+मिसाल
+गरीबों
+फूट
+फ्रेंड्स
+फोकस
+शत
+तैसा
+गे
+एनिमेशन
+मेवाड़
+स्ट्रीम
+१९५८
+प्रमुखता
+पेशियों
+ऋ
+जलाशय
+चलाता
+क्ष
+हेमामालिनी
+बैंगलोर
+सुनते
+लैंगिक
+सुदर्शन
+रमन
+नाइट्राइट
+टिहरी
+कैदी
+कस्टम
+खरा
+चिप्स
+अनगिनत
+महाकवि
+आवश्यकताएं
+कमिश्नर
+रचा
+श्रेणीबद्ध
+रवाना
+बूटी
+वाँ
+खिलौना
+गर्ल्स
+कमांड
+चलाना
+संसद्
+तस्वीरों
+प्रतियोगिताएं
+शाखाएं
+निरूपा
+पावन
+रसायनों
+औषध
+वीणा
+साजिश
+बुजुर्ग
+एनालॉग
+मकबरे
+परीक्षित
+धोनी
+नबम्बर
+प्रबंधित
+सैल्मन
+आकारों
+सवाई
+माईस्पेस
+किण्वन
+आईबीएम
+प्लांट
+गुजर
+शर्ट
+ल०व०
+विकिसम्मेलन
+पंद्रहवीं
+मातृ
+ीय
+भिक्षु
+फ़ोटो
+अपडेट
+दोहरा
+क्रेन
+बाइबल
+पहुँचाने
+दाएँ
+निःशुल्क
+नाइट्रेट
+एरनाकुलम
+पहुंची
+सक्रियता
+लियोन
+मंडली
+लोकपाल
+निकायों
+आधुनिकता
+वसूली
+नारा
+राना
+गॉर्डन
+दांव
+चन्द्रशेखर
+हार्बर
+सलाद
+मंत्रिमंडल
+रसेल
+तब्दील
+आशिक
+विधायक
+बची
+१९४९
+जैकी
+पनीर
+वेशभूषा
+वेल्श
+पसन्द
+चुपके
+चि
+अतरी
+परतों
+मधुबाला
+सांप
+पहुंचता
+रोकना
+पकड़े
+१९२०
+पीतल
+नास्तिक
+नासिर
+किस्मत
+लाइनें
+प्रतिबिंब
+माफी
+मार्क्सवादी
+एथिलीन
+कोशीश
+जगद्गुरु
+जीना
+वाह
+प्रेसीडेंसी
+सीनियर
+पूर्णता
+फिजी
+अत्र
+होनेवाली
+बिड़ला
+रिवाज
+उपनगर
+ईथर
+बद्रीनाथ
+शीर
+ु
+रेखाचित्र
+महेन्द्र
+त्तराखण्ड
+सूत
+सीढ़ी
+भट्ठी
+भण्डार
+व्यवसायी
+सेवानिवृत्त
+गुणांक
+जामा
+शेखावत
+८००
+क्रूर
+घिरे
+फलक
+अम्बेडकर
+लगन
+बिन्दुओं
+मुकुट
+वेस्टमिंस्टर
+इमाम
+बर्नार्ड
+मृदा
+बायें
+शासकीय
+ख़िताब
+षड्यंत्र
+रेखीय
+स्पीयर्स
+जीमेल
+डिस्ट्रिक्ट
+अल्बानिया
+राशियों
+लीन
+गवाही
+जस्टिस
+स्पेलिंग
+बाँटा
+कुश
+मकसद
+अटल
+मेटा
+सर्पिल
+रास
+पंखों
+संवेदना
+हलचल
+संकल्पना
+३०००
+मक्खन
+जॉर्डन
+मिथ्या
+समीकरणों
+फेफड़े
+पैतृक
+प्लैटिनम
+एंथोनी
+वीनस
+बदली
+७००
+पीढ़ियों
+सूरीनाम
+स्ट्रॉस
+क्रियाशील
+विक्रेताओं
+मोल
+लड़ते
+रहो
+वक्तव्य
+उत्पादकता
+मॉनिटर
+पुरोहित
+मालवीय
+समझी
+रूपांतर
+पनामा
+प्रतिरोधक
+समस्तीपुर
+वेधशाला
+पीड़ितों
+देवदास
+अवधारणाओं
+फर्ग्यूसन
+ग्लेन
+चौड़े
+फाँसी
+आंत्र
+त्रि
+फेरारी
+पदार्थो
+शंकु
+दादी
+पुनरावर्तन
+विवरणों
+हलके
+दरार
+मीन
+गिरीश
+चुनें
+निभाता
+१९४५
+स्पीड
+यथार्थवादी
+तोप
+किट
+चिन
+पुकार
+मॉडर्न
+कड़े
+कावेरी
+आई।
+तूफ़ान
+द्योल
+पिकनिक
+बायर
+गिटारवादक
+एकांकी
+लगाव
+सस्ती
+खुदा
+बढ़ाना
+संयंत्रों
+निष्पक्ष
+अरविंद
+पकड़ा
+गिने
+शहद
+मिथक
+मून
+दीया।
+डेविडसन
+ग्राफिक
+प्रियस
+अनिष्पक्ष
+कराटे
+सुनहरा
+सचिवालय
+फ़ॉर्मैटिंग
+वाल्टर
+स्तंभों
+आटे
+स्मार्ट
+मेक
+घाटियों
+मेसन
+अनोखी
+सदाशिव
+प्रतिजन
+रुझान
+प्रवीण
+कपिल
+विधवा
+रुकावट
+टर्नर
+त्रिभुज
+मंत्रियों
+तत्पश्चात
+चूहे
+म्हणे
+कॉलेजों
+उत्कीर्ण
+र्षक
+घेर
+नेपोलियन
+सुलझाने
+विभिन्‍न
+आइस
+भित्ति
+गला
+वैधता
+लुकास
+उड़
+स्टैंडर्ड
+खिलौने
+युगों
+लिवरपूल
+लिप्यन्तरण
+खड़ीबोली
+पर्दे
+शत्रुघन
+अग्निहोत्री
+वर्चस्व
+बहिष्कार
+एडवेंचर
+यूटोपिया
+ऐसीटिलीन
+विचरण
+कल्पित
+मुख्‍य
+अपनाई
+गंधक
+ेश
+किशोरावस्था
+लेज़र
+कैम्प
+टाई
+तुरन्त
+अर्धचालक
+मॉरीशस
+साँस
+संगठनात्मक
+बहुवचन
+तले
+कभार
+पुकारा
+चाँदनी
+१९५९
+जिनपर
+नागराज
+मोनिका
+्तराखण्ड
+६४
+सुखद
+आवारा
+पानदारक
+एशियन
+चैत्र
+कैश
+हथेली
+नैनो
+झूठा
+विस्थापन
+प्रमाणीकरण
+इसराइल
+आठवें
+सागरीय
+प्रजापति
+किसने
+सभ्यताओं
+अर्ल
+स्वराज
+१९३६
+चन्द
+बसाया
+महानदी
+वर्ड
+रिसाव
+चम्मच
+प्रशिक्षक
+रघुनाथ
+एमिनेम
+सुधा
+पंद्रह
+काटा
+चादर
+जैम
+निकटता
+उमा
+भयभीत
+फ़ॉर्मूला
+शाहजहाँ
+इंजीनियरों
+वर्दी
+ूर्व
+आनुवंशिकी
+घेरा
+हाथियों
+रैली
+संलयन
+आवर्ती
+क्रियान्वित
+दशहरा
+वृद्ध
+विरोधियों
+बोवी
+भूविज्ञान
+पो
+होय
+ऋणात्मक
+लाते
+अण्डा
+सम्बंध
+बोट
+इटावा
+साहसिक
+आपातकाल
+टायर
+साइप्रस
+चूहों
+विधियां
+षक
+जोड़ती
+त्रिज्या
+मनाते
+बांड
+प्रतिबद्धता
+आइसलैंड
+उत्तेजक
+पैमाना
+बांद्रा
+गर्भपात
+पब्लिशिंग
+अन्यत्र
+बम्बई
+महीन
+पूंजीवाद
+क्रियान्वयन
+संगीतमय
+दैट
+दाखिला
+आवश्यकतानुसार
+मेनन
+स्प्रिंग
+ख़िलाफ़
+शक्तियां
+अंतरजाल
+यूक्रेन
+अस
+वर्जिन
+मानती
+सद्भावना
+आंद्रे
+वल्लभ
+इजरायल
+अध्यायों
+मजदूरी
+उत्तरोत्तर
+प्रभात
+श्रोताओं
+हलन्त
+हीरोज़
+कुँवर
+अलेक्जेंडर
+कराया।
+वोल्टता
+एवार्ड
+गोल्डेन
+पनडुब्बी
+स्टेरॉयड
+सचदेव
+ट्रू
+सिरों
+मारकर
+माउंटबेटन
+बार्नस्टार
+कोका
+मन्दिरों
+फ़िल्मी
+धाराएं
+सांप्रदायिक
+आत्मसमर्पण
+समांतर
+प्रीमियम
+विनोबा
+बहुराष्ट्रीय
+डैविल
+धागे
+दसवीं
+बार्कलेज
+बिरला
+प्रतिमान
+कक्षाओं
+हैना
+अमूर्त
+मंज़िल
+निरंतरता
+निपुण
+ढोल
+१९४२
+मनोरोग
+डेप
+यूनीवर्स
+डाला।
+क्षार
+शूट
+बेसबॉल
+बीएमडब्लू
+शौकिया
+प्रागैतिहासिक
+ारत
+मुझ
+गुफाएं
+वर्क
+अनन्य
+सुरुचि
+छा
+बग
+कर्क
+उठे
+हक
+प्रशस्ति
+कलाई
+जयप्रकाश
+महीना
+चिंतित
+दूषित
+नियोक्ता
+स्वदेश
+यत्र
+पूछताछ
+विस्थापित
+खोजों
+लाभान्वित
+कांट
+पहचाने
+बॉर्न
+प्रवृति
+रेजिमेंट
+थिंक
+ऐश
+स्थगित
+सीटी
+विशेषतः
+बुराई
+रुद्रप्रयाग
+सुषमा
+८४
+बनी।
+जनजातियों
+रेख
+अन्याय
+संवाददाता
+कच्ची
+बोलियाँ
+एडी
+पेंटिंग
+जिन्हे
+रति
+स्टार्च
+अबू
+पहुंचते
+अम्लीय
+सैर
+बीबी
+इंटरटेनमेंट
+वानस्पतिक
+बेशक
+श्लोकों
+आपात
+नन्द
+मेज
+तृतीयक
+टॉड
+प्रसिद्द
+रांगेय
+कैप्टन
+बीन
+चाह
+बनीं
+पोटेंशिअल
+असित
+सीरम
+कैदियों
+चुनरी
+ज्येष्ठ
+अगासी
+जस्ता
+थेरेपी
+मैथुन
+लोकल
+सूर
+यात्राओं
+गेंदों
+चढ़
+गाजीपुर
+भागीदार
+राहु
+सजाया
+उत्पीड़न
+ओमान
+बायीं
+तुर्कमेनिस्तान
+फेस
+धड़
+वन्यजीव
+चीज़ों
+अनमोल
+निभाते
+जैसें
+मुंशी
+सुपरमैन
+बहारी
+विकिस्रोत
+दुग्ध
+लगीं
+गुड्डी
+माउस
+आग़ा
+गोरखा
+कसौटी
+अल्फ्रेड
+पूज्य
+वोक्सवैगन
+ख़
+तना
+ट्रैफिक
+खंडित
+मो
+्षक
+नायडू
+शबाना
+आतंकवादियों
+जाली
+लिविंग
+पुनरावृत्ति
+एक्सप्लोरर
+फ़ोर्स
+श्रोता
+राजनयिक
+तुल्य
+डेज़
+फ्रेड
+परोसा
+ची
+फोर्ब्स
+कण्ठ
+बर
+कीन
+प्रतिभागियों
+सुरेन्द्र
+फाइलों
+निद्रा
+बंगलोर
+संभावनाओं
+बॉस्टन
+हार्ले
+प्रोसेसिंग
+नासिक
+वाइड
+एनर्जी
+पकवान
+दारा
+कम्पनियों
+थोडा
+नवादा
+सप्त
+शाहरुख़
+तांबे
+नग्न
+अंजाम
+तुग़लक़
+बचाया
+बैनर्जी
+बादलों
+संप्रेषण
+लैरी
+९८
+डायमंड
+शुभारंभ
+अपार
+देगा।
+खिड़की
+जश्न
+मैनपुरी
+विधाओं
+६६
+भ्रामक
+तंत्रों
+सीरिज़
+लहरों
+पुस्तकालयों
+विनाशकारी
+जैज़
+खतना
+बस्तियां
+उत्कर्ष
+कोशिकाएँ
+नेहरु
+मेड
+लिखा।
+धनात्मक
+चॉकलेट
+मनोरमा
+१९५२
+बार्सिलोना
+लावा
+फैजाबाद
+वाटर्स
+प्रात
+बढ
+विद्युत्‌
+मसलन
+मसूरी
+अचार
+सटीकता
+कीर्तिमान
+ब्रिगेड
+प्रकाशीय
+कं
+उत्साहित
+नौकर
+वारिस
+नामदेव
+हेमंत
+ईंटों
+इंटेलिजेंस
+सपाट
+गोबर
+पर्सनल
+कार्यप्रणाली
+असीम
+कॉलम
+झाँसी
+प्रबन्ध
+करिश्मा
+मिसिसिपी
+ब्रेकिंग
+निभा
+खाती
+दावों
+वोल्ट
+आप्रवासी
+धड़कन
+बिताया
+प्रशस्त
+बीटल
+महलों
+निलंबित
+एबरडीन
+लूथर
+बारबरा
+खण्डों
+यूज़र
+बर्बाद
+उन्नयन
+वेल्लोर
+राजबब्बर
+समन्वित
+लोप
+हल्दी
+बुद्धिमान
+किराए
+८८
+अनुसन्धान
+जेड
+बादाम
+पासपोर्ट
+खुलता
+माकपा
+प्रमाणन
+वृन्दावन
+सड़कें
+बम्बोर
+पोषित
+सिन्दूर
+अमोनिया
+श्रुति
+उठाए
+तकनीकें
+पदवी
+ऑर
+गड़बड़ी
+आमाशय
+नरक
+मुहैया
+गुजरने
+संग्रहीत
+जेसन
+सीक्रेट
+असिमोव
+कन्याकुमारी
+र्व
+झारखण्ड
+उत्तराख
+परिपक्वता
+८१
+कौरव
+ज्ञानकोश
+रंगोली
+गान्धी
+ध्वनियों
+कनाडाई
+छिपे
+म्हणोनि
+प्रणालियाँ
+विखंडन
+गुम्बद
+किक
+बख़्तियारपुर
+वश
+नैस्टर
+शा
+बर्गर
+फ़ल
+हुवा
+बिक
+अटलांटा
+रोधी
+बचना
+घा
+लुटेरे
+मेगाडेथ
+बीजों
+वियना
+चिन्तन
+अय्यर
+सोम
+चिन्हित
+रेफरी
+सहिष्णुता
+छोड़ना
+मसले
+उद्यमी
+जुलते
+स्लोवाकिया
+साख
+गोकुल
+दरबारी
+बढ़ाई
+देखा।
+खूबसूरती
+पैसेंजर
+फ्लाइट
+हवाओं
+पीढी
+नौगांव
+आगंतुक
+लिली
+उत्तरकाशी
+गुरुत्व
+सिखाया
+पियरे
+शीर्
+सिक्स
+डब्ल्यूडब्ल्यूएफ
+प्री
+दशमलव
+तेतिहा
+क़ानूनी
+धृतराष्ट्र
+हाजीपुर
+आर्यभट्ट
+प्रायोजक
+सन्दूक
+सांसारिक
+फलित
+नामका
+भट्टी
+पांव
+त्
+सम्पादित
+शोधन
+विश्‍वविद्यालय
+कंस
+पम्प
+चलाई
+करतीं
+ईपू
+मिज़ोरम
+हीन्दीवीकीपीडीयाके
+दायें
+अयोग्य
+मृग
+आनेवाले
+लीबिया
+लेसनर
+तुमको
+मेहमान
+मेलबोर्न
+स्‍थापना
+थर्ड
+इमेजिंग
+सम्मेलनों
+अमज़द
+लगेगा
+बेड़े
+इब्राहिम
+पक्का
+पलट
+मानदंडों
+त्रिनिदाद
+साम्राज्यवाद
+परीक्षक
+पड़ाव
+पहाडी
+जुड़ना
+विलोपन
+सिलसिले
+खींचने
+चलाए
+जानकर
+बेली
+विचारकों
+पितामह
+नॉर्मन
+डिपार्टमेंट
+स्वादिष्ट
+सुगंध
+पेस
+समता
+गोंडा
+लेस
+फैलाने
+सैनी
+पिज़्ज़ा
+रामधारी
+तांत्रिक
+साध्य
+जन्मभूमि
+संभालने
+आकृतियों
+अख्तर
+हेल
+तवी
+पांडवों
+मीलकर
+उत्खनन
+स्वैच्छिक
+दिल्‍ली
+श्रीलंकाई
+दोहराया
+मुखर
+टोयोटा
+रिपोर्टिंग
+निषिद्ध
+गंगोत्री
+डिक
+परमार
+बार्न
+फ़ैल
+इण्डोनेशिया
+अकादमिक
+ड्राफ्ट
+भूकम्प
+दिखलाई
+धर्मशास्त्र
+किये।
+क्राई
+बकरी
+पाया।
+न्यूर्क
+जौहर
+कामयाबी
+फौज
+सुव्यवस्थित
+डॉक्टरों
+बढ़त
+क्योटो
+दर्जन
+जुटाने
+कलर
+हिन
+ग्
+प्रेरण
+एथलेटिक्स
+कपाल
+जस्टिन
+पश्तो
+कुंभ
+थाइलैंड
+बांस
+ँव
+कनेक्टिकट
+जोरदार
+बेरोजगारी
+सुल्तानपुर
+बिस्तर
+खींचा
+प्रौढ़
+एल्बमों
+कड़ा
+मानकीकृत
+सामंत
+वृहत
+परबत्ता
+दुल्हिनबाजार
+सोल
+चना
+भोसले
+सप्ताहांत
+विशालकाय
+धोने
+भस्म
+रहनेवाले
+टेघरा
+अमीन
+फ़्रान्सीसी
+शल्यक्रिया
+ग्रांट
+१९२१
+सांकेतिक
+फार
+मदिरा
+पोर्शे
+परिधान
+यूरेनियम
+जिन्होने
+बलात्कार
+परीक्षाओं
+उत्तराखण
+ट्रेक
+जन्में
+पि
+पवित्रता
+इंतजार
+लाता
+वादन
+महत्‍वपूर्ण
+ब्
+अल्जीरिया
+सीखना
+नगण्य
+खत्री
+चतुर्भुज
+बाक़ी
+१९००
+टेन
+करोड़ों
+स्क्रीनिंग
+टूटने
+प्रजातियाँ
+आन्तरिक
+कहो
+अपघटन
+देशो
+ब्रेट
+पहुँचे।
+परिस्थितियां
+म्
+पुनर्निर्देशित
+नतीजा
+साइबर
+पैदावार
+स्याही
+नंदा
+सैटेलाइट
+न्यूट्रॉन
+रोनाल्ड
+देवेन
+चमकदार
+जिगर
+योजनाएं
+प्लेग
+अध्यात्म
+विदेशियों
+सच्ची
+चट्टोपाध्याय
+दार्शनिकों
+परिसंपत्ति
+ओक
+जाये।
+इलाक़े
+तुमसे
+बिखरे
+व्यवहारिक
+तराखण्ड
+मऊ
+प्लूटो
+दुखी
+ताम्र
+इल्म
+फैलता
+समतुल्य
+किरणें
+पेव्ड
+हुमायूँ
+सईद
+भाभी
+अंडमान
+चूक
+रणधीर
+इब्न
+बो
+बॉस
+उपराष्ट्रपति
+वू
+स्पीकर
+च्वाइस
+स्टुअर्ट
+प्रदाताओं
+कार्गो
+डेन्जोंगपा
+महज
+सीतापुर
+लगान
+पेंटल
+अनुसूची
+हस्तियों
+बहू
+कुलीन
+किनारा
+कुलकर्णी
+धनराशि
+छुटकारा
+बगीचे
+शिरा
+देखती
+हीन
+मद
+बीट
+वर्धित
+संभाला
+नीच
+बेंज
+जम
+जप
+गियर
+एफएम
+आरोपित
+सोन
+ठाकरे
+स्टीवर्ट
+पाण्डेय
+आयकर
+स्वार्थ
+जन्मतिथि
+विज्ञप्ति
+न्
+रीज़न
+म्हणौनि
+वत
+रणनीतिक
+शु
+अत्याधिक
+खालसा
+प्रान्तों
+कैलोरी
+१२०
+विनिर्देश
+अमावस्या
+गोलियों
+जिन्दगी
+अशुद्ध
+स्मिता
+वार्तालाप
+दाखिल
+काउबॉय
+एक्टर्स
+टेनेसी
+पराबैंगनी
+घूमती
+खुलने
+हिरण
+संचारित
+लैला
+लाभप्रद
+प्वाइंट
+नर्तक
+जासूसी
+मानवों
+शाहपुर
+गुड़िया
+अनुग्रह
+९५
+विश्लेषक
+जहांगीर
+ही।
+त्रिशूल
+मनीश
+स्पैरो
+कोंकणी
+सेक्टर
+रिवर
+यथासंभव
+साम्यवाद
+हडसन
+सेव
+चैंपियंस
+बसों
+किपलिंग
+लड़
+विकिपिडिया
+घनिष्ठ
+दीवारें
+टॉक
+क्रमपरिवर्तन
+म्यूजियम
+प्लान
+केसरी
+फैमिली
+लातिन
+आर्द्रता
+घाना
+अस्मिता
+बट
+छड़ी
+कात्यायन
+पुनर्जन्म
+ग्लूकोज़
+अज्ञेय
+फिटनेस
+प्रतिभाशाली
+कलाकृतियों
+हीलियम
+दोहा
+अंधेरे
+तापीय
+मल्टी
+टीकू
+आर्किटेक्चर
+किन्हीं
+सत्यापन
+बलूचिस्तान
+लारा
+फिशर
+रिहा
+देवा
+गॉड
+सुनाया
+वेश
+सबौर
+प्रशान्त
+चिंताओं
+तंजानिया
+जाएँ।
+संयोजी
+साँचों
+पूछ
+श्राद्ध
+मात
+टैंगो
+अमरनाथ
+जानकार
+कृषक
+पेले
+गुणसूत्र
+पहियों
+जिज्ञासा
+टिप्पणियों
+कहलाने
+मोनोक्रोम
+हीरालाल
+बारीक
+देंगे।
+चित
+छोड़ते
+क़ुरान
+यमन
+आदर्शों
+अपन
+संघटन
+विषयवस्तु
+आमदनी
+स्क्वैश
+दर्शनों
+सूरदास
+मातृभूमि
+फेंकने
+१९५३
+दोस्ताना
+लैण्ड
+योजन
+लॉर्ड्स
+अभि
+यूएफओ
+विध्वंस
+भूपति
+नदाल
+प्रतिभूतियों
+ट्री
+टॉमी
+संप्रदायों
+६२
+वैयक्तिक
+भेजता
+मल्टीमीडिया
+आयामी
+गुड़
+ट्रॉफी
+आविष्कारक
+हुईं।
+लॉयड
+चिह्नों
+बिशप
+साँप
+हेवी
+पर्यवेक्षण
+ाद
+चिन्ता
+आलम
+चौबीस
+तलसानिया
+ताड़
+दायित्वों
+गलतियाँ
+रिएक्टर
+चंद्रगुप्त
+सप्तम
+नाइजीरिया
+स्थ
+गुदा
+त्यों
+मिटटी
+कर्ज़
+बॉन
+६७
+तात्कालिक
+गार्डनर
+अनूठा
+ओड़िआ
+रीटा
+विश्लेषणात्मक
+देवरिया
+नेवर
+्दी
+चिकनी
+डेटिंग
+पोर्टेबल
+उगाया
+बालकों
+स्पोर्ट
+१९५१
+द्रोण
+आवंटित
+गांगुली
+नार्वे
+यन्त्र
+देशपांडे
+८२
+प्याज
+एसएमएस
+तूं
+संहार
+अलौली
+शकीरा
+छू
+देवकी
+गोल्डबर्ग
+मशीनें
+कर्ज
+चढ़ने
+हिमानी
+बतलाया
+बंगलुरु
+पढाई
+नेम
+फ़ैसला
+प्रीतम
+हिरासत
+मुबारक
+खा०प०
+डिप्लोमा
+कॉनकॉर्ड
+समझकर
+संदर्म
+एलर्जी
+नितांत
+उठने
+मेरिल
+गोपनीय
+सुगम
+क़ी
+ाखण्ड
+युग्म
+बढ़ना
+अबाउट
+वहा
+चला।
+वतन
+बाधाओं
+हुबली
+हीट
+फुल
+अनुपस्थित
+येल
+भावुक
+पित्ताशय
+टिन
+लड़ा
+रॉकी
+नोल्स
+वमन
+मारना
+ब्लाक
+बहोत
+कूपर
+करो।
+प्रमाणपत्र
+यूट्यूब
+सम्मलेन
+रनवे
+पूँजी
+मंडप
+पोटेशियम
+उत्तरांचल
+ठेठ
+ओडिशा
+पल्लव
+इन्दौर
+तर्ज़
+ः
+अनूप
+आओ
+कुख्यात
+बांसुरी
+अनुपयुक्त
+मगरमच्छ
+स्पा
+सेबी
+चाहा
+धमनियों
+बारें
+अश्व
+हस्तिनापुर
+ईसाइयों
+आइपॉड
+१०१
+इराकी
+रयान
+ाल
+हिमनद
+अमरावती
+गिरी
+पूछने
+प्रेषित
+घटाने
+डिस्कवरी
+पथरी
+रायबरेली
+नायनमार
+बढती
+मिलेगी
+किशोरों
+साड़ी
+शिवजी
+पुनर्वास
+सहरसा
+कैरोलिना
+आरण्यक
+असुर
+लौंग
+समाविष्ट
+ज़ोन
+फकीर
+बियोवुल्फ़
+राइस
+थेफ्ट
+लू
+ल०
+अज़ाब
+वेबदुनिया
+ल्यूकेमिया
+मार्गरेट
+संन्यास
+रनों
+सुनहरे
+सबने
+विरल
+पॉलिसी
+रश
+कैमरों
+एंजेल्स
+प्राणायाम
+सेलिब्रिटी
+कण्डारस्यूं
+शाश्वत
+जुलूस
+विश
+जेफ
+मतानुसार
+उत्पात
+मामा
+७३
+रहीं।
+क्लिंटन
+विकिया
+आइवी
+लिस्ट
+आबू
+गोमती
+पुरुषोत्तम
+उत्तराखण्
+हेराल्ड
+दांता
+पद्मश्री
+शर्तें
+कटिहार
+स्विंग
+उत्तरार्द्ध
+सिंगल्स
+केदार
+रघु
+वासना
+पहुँचकर
+न्यूकैसल
+मांगी
+अमल
+सल्फर
+छोड
+अंजना
+कंप्यूटरों
+ढ
+विलिस
+सीकर
+जुड़ता
+प्रसन्नता
+प्लेटफॉर्म
+गिरि
+उछाल
+करीना
+जहर
+मासके
+सम्पदा
+चौदहवीं
+ढाईज्यूली
+साओ
+कोचीन
+श्रावण
+अर्पित
+मासूम
+टीन
+स्पार्क
+कट्टर
+चढ़ा
+ट्रिब्यून
+होंडा
+कीये
+एंटोनियो
+लैस
+किससे
+एकजुट
+पतंग
+१९२७
+टीकाकरण
+मूक
+असरगंज
+सतहों
+नाल
+आयताकार
+चढ़ाव
+कार्यशील
+दक्षिणपूर्व
+माथे
+मर्फी
+गुजरता
+सफ़र
+स्लोवेनिया
+रिले
+कॉमन
+जमाव
+कुलभूषण
+्स
+क्रोम
+उजाला
+मूत्राशय
+इस्राइल
+नाड़ी
+ंवत
+परगना
+लैंडिंग
+रेलगाड़ी
+कलाँ
+उद्धार
+ज़रिये
+शॉर्ट
+टिक
+डिज़नी
+फिल्माया
+मरते
+निष्कर्षों
+उलट
+भीमसेन
+चक्रों
+मात्राओं
+प्रणाम
+सिम्बियन
+संस्थागत
+बिताने
+आंग्ल
+बिजनौर
+फायदे
+खेड़ा
+कार्यभार
index 99168c6..ff6a6d6 100644 (file)
@@ -12,9 +12,9 @@ DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
 TESTS =
 check_PROGRAMS =
 
-EXTRA_DIST += harfbuzz.cc
+EXTRA_DIST += harfbuzz.cc harfbuzz-subset.cc
 EXTRA_DIST += meson.build
-EXTRA_DIST += fix_get_types.py
+EXTRA_DIST += fix_get_types.py relative_to.py
 
 # Convenience targets:
 lib: $(BUILT_SOURCES) libharfbuzz.la
@@ -47,6 +47,9 @@ HBLIBS   += $(GLIB_LIBS)
 HBDEPS   += $(GLIB_DEPS)
 HBSOURCES += $(HB_GLIB_sources)
 HBHEADERS += $(HB_GLIB_headers)
+HB_HAS_GLIB_DEF = define HB_HAS_GLIB 1
+else
+HB_HAS_GLIB_DEF = undef HB_HAS_GLIB
 endif
 
 if HAVE_FREETYPE
@@ -55,6 +58,9 @@ HBLIBS   += $(FREETYPE_LIBS)
 HBDEPS   += $(FREETYPE_DEPS)
 HBSOURCES += $(HB_FT_sources)
 HBHEADERS += $(HB_FT_headers)
+HB_HAS_FREETYPE_DEF = define HB_HAS_FREETYPE 1
+else
+HB_HAS_FREETYPE_DEF = undef HB_HAS_FREETYPE
 endif
 
 if HAVE_GRAPHITE2
@@ -63,6 +69,9 @@ HBLIBS   += $(GRAPHITE2_LIBS)
 HBDEPS   += $(GRAPHITE2_DEPS)
 HBSOURCES += $(HB_GRAPHITE2_sources)
 HBHEADERS += $(HB_GRAPHITE2_headers)
+HB_HAS_GRAPHITE_DEF = define HB_HAS_GRAPHITE 1
+else
+HB_HAS_GRAPHITE_DEF = undef HB_HAS_GRAPHITE
 endif
 
 if HAVE_UNISCRIBE
@@ -70,6 +79,9 @@ HBCFLAGS += $(UNISCRIBE_CFLAGS)
 HBNONPCLIBS += $(UNISCRIBE_LIBS)
 HBSOURCES += $(HB_UNISCRIBE_sources)
 HBHEADERS += $(HB_UNISCRIBE_headers)
+HB_HAS_UNISCRIBE_DEF = define HB_HAS_UNISCRIBE 1
+else
+HB_HAS_UNISCRIBE_DEF = undef HB_HAS_UNISCRIBE
 endif
 
 if HAVE_DIRECTWRITE
@@ -77,6 +89,9 @@ HBCFLAGS += $(DIRECTWRITE_CXXFLAGS)
 HBNONPCLIBS += $(DIRECTWRITE_LIBS)
 HBSOURCES += $(HB_DIRECTWRITE_sources)
 HBHEADERS += $(HB_DIRECTWRITE_headers)
+HB_HAS_DIRECTWRITE_DEF = define HB_HAS_DIRECTWRITE 1
+else
+HB_HAS_DIRECTWRITE_DEF = undef HB_HAS_DIRECTWRITE
 endif
 
 if HAVE_GDI
@@ -84,6 +99,9 @@ HBCFLAGS += $(GDI_CXXFLAGS)
 HBNONPCLIBS += $(GDI_LIBS)
 HBSOURCES += $(HB_GDI_sources)
 HBHEADERS += $(HB_GDI_headers)
+HB_HAS_GDI_DEF = define HB_HAS_GDI 1
+else
+HB_HAS_GDI_DEF = undef HB_HAS_GDI
 endif
 
 if HAVE_CORETEXT
@@ -91,6 +109,19 @@ HBCFLAGS += $(CORETEXT_CFLAGS)
 HBNONPCLIBS += $(CORETEXT_LIBS)
 HBSOURCES += $(HB_CORETEXT_sources)
 HBHEADERS += $(HB_CORETEXT_headers)
+HB_HAS_CORETEXT_DEF = define HB_HAS_CORETEXT 1
+else
+HB_HAS_CORETEXT_DEF = undef HB_HAS_CORETEXT
+endif
+
+if HAVE_WASM
+HBCFLAGS += $(WASM_CFLAGS)
+HBNONPCLIBS += $(WASM_LIBS)
+HBSOURCES += $(HB_WASM_sources)
+HBHEADERS += $(HB_WASM_headers)
+HB_HAS_WASM_DEF = define HB_HAS_WASM 1
+else
+HB_HAS_WASM_DEF = undef HB_HAS_WASM
 endif
 
 
@@ -114,6 +145,8 @@ export_symbols = -export-symbols harfbuzz.def
 harfbuzz_def_dependency = harfbuzz.def
 export_symbols_subset = -export-symbols harfbuzz-subset.def
 harfbuzz_subset_def_dependency = harfbuzz-subset.def
+export_symbols_cairo = -export-symbols harfbuzz-cairo.def
+harfbuzz_cairo_def_dependency = harfbuzz-cairo.def
 export_symbols_icu = -export-symbols harfbuzz-icu.def
 harfbuzz_icu_def_dependency = harfbuzz-icu.def
 export_symbols_gobject = -export-symbols harfbuzz-gobject.def
@@ -147,7 +180,7 @@ pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = harfbuzz.pc
 cmakedir = $(libdir)/cmake/harfbuzz
 cmake_DATA = harfbuzz-config.cmake
-EXTRA_DIST += hb-version.h.in harfbuzz.pc.in harfbuzz-config.cmake.in
+EXTRA_DIST += hb-version.h.in hb-features.h.in harfbuzz.pc.in harfbuzz-config.cmake.in
 
 lib_LTLIBRARIES += libharfbuzz-subset.la
 libharfbuzz_subset_la_LINK = $(chosen_linker) $(libharfbuzz_subset_la_LDFLAGS)
@@ -160,12 +193,36 @@ pkginclude_HEADERS += $(HB_SUBSET_headers)
 pkgconfig_DATA += harfbuzz-subset.pc
 EXTRA_DIST += harfbuzz-subset.pc.in
 
+harfbuzz-subset.cc: Makefile.sources
+       $(AM_V_GEN) \
+       LANG=C; \
+       for f in \
+               $(HB_BASE_sources) \
+               $(HB_SUBSET_sources) \
+               ; do echo '#include "'$$f'"'; done | \
+       sort -u | \
+       grep '[.]cc"' > $(srcdir)/harfbuzz-subset.cc \
+       || ($(RM) $(srcdir)/harfbuzz-subset.cc; false)
+BUILT_SOURCES += harfbuzz-subset.cc
+
+lib_LTLIBRARIES += libharfbuzz-cairo.la
+libharfbuzz_cairo_la_LINK = $(chosen_linker) $(libharfbuzz_cairo_la_LDFLAGS)
+libharfbuzz_cairo_la_SOURCES = $(HB_CAIRO_sources)
+libharfbuzz_cairo_la_CPPFLAGS = $(HBCFLAGS) $(CAIRO_CFLAGS) $(CODE_COVERAGE_CFLAGS)
+libharfbuzz_cairo_la_LDFLAGS = $(base_link_flags) $(export_symbols_cairo) $(CODE_COVERAGE_LDFLAGS)
+libharfbuzz_cairo_la_LIBADD = $(CAIRO_LIBS) libharfbuzz.la
+EXTRA_libharfbuzz_cairo_la_DEPENDENCIES = $(harfbuzz_cairo_def_dependency)
+pkginclude_HEADERS += $(HB_CAIRO_headers)
+pkgconfig_DATA += harfbuzz-cairo.pc
+EXTRA_DIST += harfbuzz-cairo.pc.in
+
 if HAVE_ICU
 if HAVE_ICU_BUILTIN
 HBCFLAGS += $(ICU_CFLAGS)
 HBLIBS += $(ICU_LIBS)
 HBSOURCES += $(HB_ICU_sources)
 HBHEADERS += $(HB_ICU_headers)
+HB_HAS_ICU_DEF = define HB_HAS_ICU 1
 else
 lib_LTLIBRARIES += libharfbuzz-icu.la
 libharfbuzz_icu_la_SOURCES = $(HB_ICU_sources)
@@ -175,6 +232,7 @@ libharfbuzz_icu_la_LIBADD = $(ICU_LIBS) libharfbuzz.la
 EXTRA_libharfbuzz_icu_la_DEPENDENCIES = $(harfbuzz_icu_def_dependency)
 pkginclude_HEADERS += $(HB_ICU_headers)
 pkgconfig_DATA += harfbuzz-icu.pc
+HB_HAS_ICU_DEF = undef HB_HAS_ICU
 endif
 endif
 EXTRA_DIST += harfbuzz-icu.pc.in
@@ -206,6 +264,9 @@ hb-gobject-enums.%: hb-gobject-enums.%.tmpl $(HBHEADERS)
                --template $^ | \
        sed 's/_t_get_type/_get_type/g; s/_T (/ (/g' > "$@" \
        || ($(RM) "$@"; false)
+HB_HAS_GOBJECT_DEF = define HB_HAS_GOBJECT 1
+else
+HB_HAS_GOBJECT_DEF = undef HB_HAS_GOBJECT
 endif
 EXTRA_DIST += \
        harfbuzz-gobject.pc.in \
@@ -214,6 +275,28 @@ EXTRA_DIST += \
        $(NULL)
 
 
+BUILT_SOURCES += \
+       hb-features.h
+DISTCLEANFILES += \
+       hb-features.h
+
+hb-features.h: hb-features.h.in $(top_builddir)/config.status
+       $(AM_V_GEN) $(SED) \
+               -e 's/mesondefine HB_HAS_CAIRO/$(HB_HAS_CAIRO_DEF)/' \
+               -e 's/mesondefine HB_HAS_CORETEXT/$(HB_HAS_CORETEXT_DEF)/' \
+               -e 's/mesondefine HB_HAS_DIRECTWRITE/$(HB_HAS_DIRECTWRITE_DEF)/' \
+               -e 's/mesondefine HB_HAS_FREETYPE/$(HB_HAS_FREETYPE_DEF)/' \
+               -e 's/mesondefine HB_HAS_GDI/$(HB_HAS_GDI_DEF)/' \
+               -e 's/mesondefine HB_HAS_GDI/$(HB_HAS_GDI_DEF)/' \
+               -e 's/mesondefine HB_HAS_GLIB/$(HB_HAS_GLIB_DEF)/' \
+               -e 's/mesondefine HB_HAS_GOBJECT/$(HB_HAS_GOBJECT_DEF)/' \
+               -e 's/mesondefine HB_HAS_GRAPHITE/$(HB_HAS_GRAPHITE_DEF)/' \
+               -e 's/mesondefine HB_HAS_ICU/$(HB_HAS_ICU_DEF)/' \
+               -e 's/mesondefine HB_HAS_UNISCRIBE/$(HB_HAS_UNISCRIBE_DEF)/' \
+               -e 's/mesondefine HB_HAS_WASM/$(HB_HAS_WASM_DEF)/' \
+               "$<" > "$@" || ($(RM) "$@"; false)
+
+
 %.pc: %.pc.in $(top_builddir)/config.status
        $(AM_V_GEN) \
        $(SED)  -e 's@%prefix%@$(prefix)@g' \
@@ -240,6 +323,8 @@ harfbuzz.def: $(HBHEADERS)
        $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
 harfbuzz-subset.def: $(HB_SUBSET_headers)
        $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
+harfbuzz-cairo.def: $(HB_CAIRO_headers)
+       $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
 harfbuzz-icu.def: $(HB_ICU_headers)
        $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
 harfbuzz-gobject.def: $(HB_GOBJECT_headers)
@@ -284,6 +369,7 @@ $(srcdir)/%.hh: $(srcdir)/%.rl
 
 harfbuzz.cc: Makefile.sources
        $(AM_V_GEN) \
+       LANG=C; \
        for f in \
                $(HB_BASE_sources) \
                $(HB_GLIB_sources) \
@@ -294,6 +380,7 @@ harfbuzz.cc: Makefile.sources
                $(HB_DIRECTWRITE_sources) \
                $(HB_CORETEXT_sources) \
                ; do echo '#include "'$$f'"'; done | \
+       sort -u | \
        grep '[.]cc"' > $(srcdir)/harfbuzz.cc \
        || ($(RM) $(srcdir)/harfbuzz.cc; false)
 BUILT_SOURCES += harfbuzz.cc
@@ -306,7 +393,9 @@ noinst_PROGRAMS = \
        test-ot-name \
        test-ot-glyphname \
        test-gpos-size-params \
+       test-gsub-get-alternates \
        test-gsub-would-substitute \
+       test-use-table \
        $(NULL)
 bin_PROGRAMS =
 
@@ -334,10 +423,18 @@ test_ot_glyphname_SOURCES = test-ot-glyphname.cc
 test_ot_glyphname_CPPFLAGS = $(HBCFLAGS)
 test_ot_glyphname_LDADD = libharfbuzz.la $(HBLIBS)
 
+test_use_table_SOURCES = test-use-table.cc
+test_use_table_CPPFLAGS = $(HBCFLAGS)
+test_use_table_LDADD = libharfbuzz.la $(HBLIBS)
+
 test_gpos_size_params_SOURCES = test-gpos-size-params.cc
 test_gpos_size_params_CPPFLAGS = $(HBCFLAGS)
 test_gpos_size_params_LDADD = libharfbuzz.la $(HBLIBS)
 
+test_gsub_get_alternates_SOURCES = test-gsub-get-alternates.cc
+test_gsub_get_alternates_CPPFLAGS = $(HBCFLAGS)
+test_gsub_get_alternates_LDADD = libharfbuzz.la $(HBLIBS)
+
 test_gsub_would_substitute_SOURCES = test-gsub-would-substitute.cc
 test_gsub_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
 test_gsub_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
@@ -349,6 +446,7 @@ COMPILED_TESTS = \
        test-iter \
        test-machinery \
        test-map \
+       test-multimap \
        test-number \
        test-ot-tag \
        test-priority-queue \
@@ -357,6 +455,10 @@ COMPILED_TESTS = \
        test-unicode-ranges \
        test-vector \
        test-repacker \
+       test-classdef-graph \
+       test-instancer-solver \
+       test-tuple-varstore \
+       test-item-varstore \
        $(NULL)
 COMPILED_TESTS_CPPFLAGS = $(HBCFLAGS) -DMAIN -UNDEBUG
 COMPILED_TESTS_LDADD = libharfbuzz.la $(HBLIBS)
@@ -387,6 +489,10 @@ test_map_SOURCES = test-map.cc hb-static.cc
 test_map_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
 test_map_LDADD = $(COMPILED_TESTS_LDADD)
 
+test_multimap_SOURCES = test-multimap.cc hb-static.cc
+test_multimap_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_multimap_LDADD = $(COMPILED_TESTS_LDADD)
+
 test_number_SOURCES = test-number.cc hb-number.cc
 test_number_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
 test_number_LDADD = $(COMPILED_TESTS_LDADD)
@@ -399,10 +505,14 @@ test_priority_queue_SOURCES = test-priority-queue.cc hb-static.cc
 test_priority_queue_CPPFLAGS = $(HBCFLAGS)
 test_priority_queue_LDADD = libharfbuzz.la $(HBLIBS)
 
-test_repacker_SOURCES = test-repacker.cc hb-static.cc
+test_repacker_SOURCES = test-repacker.cc hb-static.cc graph/gsubgpos-context.cc
 test_repacker_CPPFLAGS = $(HBCFLAGS)
 test_repacker_LDADD = libharfbuzz.la libharfbuzz-subset.la $(HBLIBS)
 
+test_classdef_graph_SOURCES = graph/test-classdef-graph.cc hb-static.cc graph/gsubgpos-context.cc
+test_classdef_graph_CPPFLAGS = $(HBCFLAGS)
+test_classdef_graph_LDADD = libharfbuzz.la libharfbuzz-subset.la $(HBLIBS)
+
 test_set_SOURCES = test-set.cc hb-static.cc
 test_set_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
 test_set_LDADD = $(COMPILED_TESTS_LDADD)
@@ -419,6 +529,18 @@ test_vector_SOURCES = test-vector.cc hb-static.cc
 test_vector_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
 test_vector_LDADD = $(COMPILED_TESTS_LDADD)
 
+test_instancer_solver_SOURCES = test-subset-instancer-solver.cc hb-subset-instancer-solver.cc hb-static.cc
+test_instancer_solver_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_instancer_solver_LDADD = $(COMPILED_TESTS_LDADD)
+
+test_tuple_varstore_SOURCES = test-tuple-varstore.cc hb-subset-instancer-solver.cc hb-static.cc
+test_tuple_varstore_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_tuple_varstore_LDADD = $(COMPILED_TESTS_LDADD)
+
+test_item_varstore_SOURCES = test-item-varstore.cc hb-subset-instancer-solver.cc hb-static.cc
+test_item_varstore_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_item_varstore_LDADD = $(COMPILED_TESTS_LDADD)
+
 dist_check_SCRIPTS = \
        check-c-linkage-decls.py \
        check-externs.py \
@@ -437,6 +559,7 @@ endif
 
 TESTS_ENVIRONMENT = \
        srcdir="$(srcdir)" \
+       base_srcdir="$(srcdir)" \
        builddir="$(builddir)" \
        MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
        HBSOURCES="$(HBSOURCES)" \
@@ -465,7 +588,7 @@ INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
 INTROSPECTION_SCANNER_ENV = CC="$(CC)"
 
 HarfBuzz-0.0.gir: libharfbuzz.la libharfbuzz-gobject.la
-HarfBuzz_0_0_gir_INCLUDES = GObject-2.0
+HarfBuzz_0_0_gir_INCLUDES = GObject-2.0 freetype2-2.0
 HarfBuzz_0_0_gir_CFLAGS = \
        $(INCLUDES) \
        $(HBCFLAGS) \
index 86a0c79..f37acb2 100644 (file)
@@ -130,39 +130,45 @@ check_PROGRAMS = $(am__EXEEXT_2)
 @HAVE_CORETEXT_TRUE@am__append_31 = $(CORETEXT_LIBS)
 @HAVE_CORETEXT_TRUE@am__append_32 = $(HB_CORETEXT_sources)
 @HAVE_CORETEXT_TRUE@am__append_33 = $(HB_CORETEXT_headers)
-@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_WASM_TRUE@am__append_34 = $(WASM_CFLAGS)
+@HAVE_WASM_TRUE@am__append_35 = $(WASM_LIBS)
+@HAVE_WASM_TRUE@am__append_36 = $(HB_WASM_sources)
+@HAVE_WASM_TRUE@am__append_37 = $(HB_WASM_headers)
+@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__append_38 = $(ICU_CFLAGS)
+@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__append_39 = $(ICU_LIBS)
+@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__append_40 = $(HB_ICU_sources)
+@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__append_41 = $(HB_ICU_headers)
+@HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@am__append_42 = libharfbuzz-icu.la
+@HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@am__append_43 = $(HB_ICU_headers)
+@HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@am__append_44 = harfbuzz-icu.pc
+@HAVE_GOBJECT_TRUE@am__append_45 = libharfbuzz-gobject.la
+@HAVE_GOBJECT_TRUE@am__append_46 = $(HB_GOBJECT_DIST_headers)
+@HAVE_GOBJECT_TRUE@am__append_47 = $(HB_GOBJECT_NODIST_headers)
+@HAVE_GOBJECT_TRUE@am__append_48 = harfbuzz-gobject.pc
+@HAVE_GOBJECT_TRUE@am__append_49 = \
 @HAVE_GOBJECT_TRUE@    $(HB_GOBJECT_ENUM_sources) \
 @HAVE_GOBJECT_TRUE@    $(HB_GOBJECT_ENUM_headers) \
 @HAVE_GOBJECT_TRUE@    $(NULL)
 
-@HAVE_GOBJECT_TRUE@am__append_46 = \
+@HAVE_GOBJECT_TRUE@am__append_50 = \
 @HAVE_GOBJECT_TRUE@    $(HB_GOBJECT_ENUM_sources) \
 @HAVE_GOBJECT_TRUE@    $(HB_GOBJECT_ENUM_headers) \
 @HAVE_GOBJECT_TRUE@    $(NULL)
 
-@HAVE_GOBJECT_TRUE@am__append_47 = harfbuzz-gobject.def
+@HAVE_GOBJECT_TRUE@am__append_51 = harfbuzz-gobject.def
 noinst_PROGRAMS = main$(EXEEXT) test$(EXEEXT) \
        test-buffer-serialize$(EXEEXT) test-ot-meta$(EXEEXT) \
        test-ot-name$(EXEEXT) test-ot-glyphname$(EXEEXT) \
        test-gpos-size-params$(EXEEXT) \
-       test-gsub-would-substitute$(EXEEXT) $(am__EXEEXT_1)
+       test-gsub-get-alternates$(EXEEXT) \
+       test-gsub-would-substitute$(EXEEXT) test-use-table$(EXEEXT) \
+       $(am__EXEEXT_1)
 bin_PROGRAMS =
-@WITH_LIBSTDCXX_FALSE@am__append_48 = \
+@WITH_LIBSTDCXX_FALSE@am__append_52 = \
 @WITH_LIBSTDCXX_FALSE@ check-libstdc++.py \
 @WITH_LIBSTDCXX_FALSE@ $(NULL)
 
-@HAVE_INTROSPECTION_TRUE@am__append_49 = $(gir_DATA) $(typelib_DATA)
+@HAVE_INTROSPECTION_TRUE@am__append_53 = $(gir_DATA) $(typelib_DATA)
 subdir = src
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_link_flag.m4 \
@@ -187,10 +193,13 @@ am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libdir)" \
 am__EXEEXT_1 =
 am__EXEEXT_2 = test-algs$(EXEEXT) test-array$(EXEEXT) \
        test-bimap$(EXEEXT) test-iter$(EXEEXT) test-machinery$(EXEEXT) \
-       test-map$(EXEEXT) test-number$(EXEEXT) test-ot-tag$(EXEEXT) \
-       test-priority-queue$(EXEEXT) test-set$(EXEEXT) \
-       test-serialize$(EXEEXT) test-unicode-ranges$(EXEEXT) \
-       test-vector$(EXEEXT) test-repacker$(EXEEXT) $(am__EXEEXT_1)
+       test-map$(EXEEXT) test-multimap$(EXEEXT) test-number$(EXEEXT) \
+       test-ot-tag$(EXEEXT) test-priority-queue$(EXEEXT) \
+       test-set$(EXEEXT) test-serialize$(EXEEXT) \
+       test-unicode-ranges$(EXEEXT) test-vector$(EXEEXT) \
+       test-repacker$(EXEEXT) test-classdef-graph$(EXEEXT) \
+       test-instancer-solver$(EXEEXT) test-tuple-varstore$(EXEEXT) \
+       test-item-varstore$(EXEEXT) $(am__EXEEXT_1)
 PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
 am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
 am__vpath_adj = case $$p in \
@@ -221,16 +230,24 @@ am__uninstall_files_from_dir = { \
   }
 LTLIBRARIES = $(lib_LTLIBRARIES)
 am__DEPENDENCIES_1 =
+libharfbuzz_cairo_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+       libharfbuzz.la
+am__objects_1 =
+am__objects_2 = libharfbuzz_cairo_la-hb-cairo.lo \
+       libharfbuzz_cairo_la-hb-cairo-utils.lo \
+       libharfbuzz_cairo_la-hb-static.lo $(am__objects_1)
+am_libharfbuzz_cairo_la_OBJECTS = $(am__objects_2)
+libharfbuzz_cairo_la_OBJECTS = $(am_libharfbuzz_cairo_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_1 = libharfbuzz_gobject_la-hb-gobject-structs.lo
+am__objects_3 = libharfbuzz_gobject_la-hb-gobject-structs.lo
 @HAVE_GOBJECT_TRUE@am_libharfbuzz_gobject_la_OBJECTS =  \
-@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_3)
+am__objects_4 = libharfbuzz_gobject_la-hb-gobject-enums.lo
+am__objects_5 = $(am__objects_4)
+@HAVE_GOBJECT_TRUE@nodist_libharfbuzz_gobject_la_OBJECTS =  \
+@HAVE_GOBJECT_TRUE@    $(am__objects_5)
 libharfbuzz_gobject_la_OBJECTS = $(am_libharfbuzz_gobject_la_OBJECTS) \
        $(nodist_libharfbuzz_gobject_la_OBJECTS)
 @HAVE_GOBJECT_TRUE@am_libharfbuzz_gobject_la_rpath = -rpath $(libdir)
@@ -238,9 +255,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_4 = libharfbuzz_icu_la-hb-icu.lo
+am__objects_6 = 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_4)
+@HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@        $(am__objects_6)
 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@)
@@ -253,8 +270,7 @@ libharfbuzz_icu_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
 @HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@am_libharfbuzz_icu_la_rpath =  \
 @HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@        -rpath $(libdir)
 libharfbuzz_subset_la_DEPENDENCIES = libharfbuzz.la
-am__objects_5 =
-am__objects_6 = libharfbuzz_subset_la-hb-number.lo \
+am__objects_7 = libharfbuzz_subset_la-hb-number.lo \
        libharfbuzz_subset_la-hb-ot-cff1-table.lo \
        libharfbuzz_subset_la-hb-ot-cff2-table.lo \
        libharfbuzz_subset_la-hb-static.lo \
@@ -262,21 +278,24 @@ am__objects_6 = libharfbuzz_subset_la-hb-number.lo \
        libharfbuzz_subset_la-hb-subset-cff1.lo \
        libharfbuzz_subset_la-hb-subset-cff2.lo \
        libharfbuzz_subset_la-hb-subset-input.lo \
+       libharfbuzz_subset_la-hb-subset-instancer-solver.lo \
        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-hb-subset-repacker.lo \
+       libharfbuzz_subset_la-hb-subset.lo \
+       libharfbuzz_subset_la-gsubgpos-context.lo $(am__objects_1)
+am_libharfbuzz_subset_la_OBJECTS = $(am__objects_7)
 libharfbuzz_subset_la_OBJECTS = $(am_libharfbuzz_subset_la_OBJECTS)
 @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_GDI_TRUE@am__DEPENDENCIES_8 = $(am__DEPENDENCIES_1)
-@HAVE_CORETEXT_TRUE@am__DEPENDENCIES_9 = $(am__DEPENDENCIES_1)
+@HAVE_GDI_TRUE@am__DEPENDENCIES_7 = $(am__DEPENDENCIES_1)
+@HAVE_CORETEXT_TRUE@am__DEPENDENCIES_8 = $(am__DEPENDENCIES_1)
+@HAVE_WASM_TRUE@am__DEPENDENCIES_9 = $(am__DEPENDENCIES_1)
 am__DEPENDENCIES_10 = $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_6) \
-       $(am__DEPENDENCIES_7) $(am__DEPENDENCIES_8) \
-       $(am__DEPENDENCIES_9)
+       $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_7) \
+       $(am__DEPENDENCIES_8) $(am__DEPENDENCIES_9)
 @HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__DEPENDENCIES_11 =  \
 @HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@ $(am__DEPENDENCIES_1)
 am__DEPENDENCIES_12 = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) \
@@ -297,51 +316,101 @@ am__libharfbuzz_la_SOURCES_DIST = hb-aat-layout-ankr-table.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-config.hh hb-debug.hh hb-dispatch.hh hb-draw.cc hb-draw.hh \
-       hb-face.cc hb-face.hh hb-fallback-shape.cc hb-font.cc \
-       hb-font.hh hb-iter.hh hb-kern.hh hb-machinery.hh hb-map.cc \
-       hb-map.hh hb-meta.hh hb-ms-feature-ranges.hh hb-mutex.hh \
-       hb-null.hh hb-number.cc hb-number.hh hb-object.hh \
-       hb-open-file.hh hb-open-type.hh hb-ot-cff-common.hh \
-       hb-ot-cff1-std-str.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-face.cc hb-face.hh hb-face-builder.cc hb-fallback-shape.cc \
+       hb-font.cc hb-font.hh hb-iter.hh hb-kern.hh hb-limits.hh \
+       hb-machinery.hh hb-map.cc hb-map.hh hb-meta.hh \
+       hb-ms-feature-ranges.hh hb-multimap.hh hb-mutex.hh hb-null.hh \
+       hb-number.cc hb-number.hh hb-object.hh hb-open-file.hh \
+       hb-open-type.hh hb-ot-cff-common.hh hb-ot-cff1-std-str.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.cc \
        hb-ot-face-table-list.hh 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-meta-table.hh hb-ot-meta.cc \
-       hb-ot-metrics.cc hb-ot-metrics.hh \
-       hb-ot-name-language-static.hh 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-joining-list.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-syllabic.cc \
-       hb-ot-shape-complex-syllabic.hh hb-ot-shape-complex-thai.cc \
-       hb-ot-shape-complex-use-table.hh hb-ot-shape-complex-use.cc \
-       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-common.hh \
+       hb-outline.hh hb-outline.cc hb-paint.cc hb-paint.hh \
+       hb-paint-extents.cc hb-paint-extents.hh \
+       hb-ot-layout-gsub-table.hh OT/Color/CBDT/CBDT.hh \
+       OT/Color/COLR/COLR.hh OT/Color/CPAL/CPAL.hh \
+       OT/Color/sbix/sbix.hh OT/Color/svg/svg.hh OT/glyf/glyf.hh \
+       OT/glyf/glyf-helpers.hh OT/glyf/loca.hh \
+       OT/glyf/path-builder.hh OT/glyf/Glyph.hh \
+       OT/glyf/GlyphHeader.hh OT/glyf/SimpleGlyph.hh \
+       OT/glyf/coord-setter.hh OT/glyf/composite-iter.hh \
+       OT/glyf/CompositeGlyph.hh OT/glyf/VarCompositeGlyph.hh \
+       OT/glyf/SubsetGlyph.hh OT/Layout/types.hh \
+       OT/Layout/Common/Coverage.hh \
+       OT/Layout/Common/CoverageFormat1.hh \
+       OT/Layout/Common/CoverageFormat2.hh \
+       OT/Layout/Common/RangeRecord.hh OT/Layout/GDEF/GDEF.hh \
+       OT/Layout/GPOS/AnchorFormat1.hh \
+       OT/Layout/GPOS/AnchorFormat2.hh \
+       OT/Layout/GPOS/AnchorFormat3.hh OT/Layout/GPOS/Anchor.hh \
+       OT/Layout/GPOS/AnchorMatrix.hh \
+       OT/Layout/GPOS/ChainContextPos.hh OT/Layout/GPOS/Common.hh \
+       OT/Layout/GPOS/ContextPos.hh \
+       OT/Layout/GPOS/CursivePosFormat1.hh \
+       OT/Layout/GPOS/CursivePos.hh OT/Layout/GPOS/ExtensionPos.hh \
+       OT/Layout/GPOS/GPOS.hh OT/Layout/GPOS/LigatureArray.hh \
+       OT/Layout/GPOS/MarkArray.hh \
+       OT/Layout/GPOS/MarkBasePosFormat1.hh \
+       OT/Layout/GPOS/MarkBasePos.hh \
+       OT/Layout/GPOS/MarkLigPosFormat1.hh \
+       OT/Layout/GPOS/MarkLigPos.hh \
+       OT/Layout/GPOS/MarkMarkPosFormat1.hh \
+       OT/Layout/GPOS/MarkMarkPos.hh OT/Layout/GPOS/MarkRecord.hh \
+       OT/Layout/GPOS/PairPosFormat1.hh \
+       OT/Layout/GPOS/PairPosFormat2.hh OT/Layout/GPOS/PairPos.hh \
+       OT/Layout/GPOS/PairSet.hh OT/Layout/GPOS/PairValueRecord.hh \
+       OT/Layout/GPOS/PosLookup.hh \
+       OT/Layout/GPOS/PosLookupSubTable.hh \
+       OT/Layout/GPOS/SinglePosFormat1.hh \
+       OT/Layout/GPOS/SinglePosFormat2.hh OT/Layout/GPOS/SinglePos.hh \
+       OT/Layout/GPOS/ValueFormat.hh OT/Layout/GSUB/AlternateSet.hh \
+       OT/Layout/GSUB/AlternateSubstFormat1.hh \
+       OT/Layout/GSUB/AlternateSubst.hh \
+       OT/Layout/GSUB/ChainContextSubst.hh OT/Layout/GSUB/Common.hh \
+       OT/Layout/GSUB/ContextSubst.hh \
+       OT/Layout/GSUB/ExtensionSubst.hh OT/Layout/GSUB/GSUB.hh \
+       OT/Layout/GSUB/Ligature.hh OT/Layout/GSUB/LigatureSet.hh \
+       OT/Layout/GSUB/LigatureSubstFormat1.hh \
+       OT/Layout/GSUB/LigatureSubst.hh \
+       OT/Layout/GSUB/MultipleSubstFormat1.hh \
+       OT/Layout/GSUB/MultipleSubst.hh \
+       OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh \
+       OT/Layout/GSUB/ReverseChainSingleSubst.hh \
+       OT/Layout/GSUB/Sequence.hh \
+       OT/Layout/GSUB/SingleSubstFormat1.hh \
+       OT/Layout/GSUB/SingleSubstFormat2.hh \
+       OT/Layout/GSUB/SingleSubst.hh OT/Layout/GSUB/SubstLookup.hh \
+       OT/Layout/GSUB/SubstLookupSubTable.hh OT/name/name.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-meta-table.hh hb-ot-meta.cc hb-ot-metrics.cc \
+       hb-ot-metrics.hh hb-ot-name-language-static.hh \
+       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-shaper-arabic-fallback.hh \
+       hb-ot-shaper-arabic-joining-list.hh hb-ot-shaper-arabic-pua.hh \
+       hb-ot-shaper-arabic-table.hh hb-ot-shaper-arabic-win1256.hh \
+       hb-ot-shaper-arabic.cc hb-ot-shaper-arabic.hh \
+       hb-ot-shaper-default.cc hb-ot-shaper-hangul.cc \
+       hb-ot-shaper-hebrew.cc hb-ot-shaper-indic-table.cc \
+       hb-ot-shaper-indic.cc hb-ot-shaper-indic.hh \
+       hb-ot-shaper-khmer.cc hb-ot-shaper-myanmar.cc \
+       hb-ot-shaper-syllabic.cc hb-ot-shaper-syllabic.hh \
+       hb-ot-shaper-thai.cc hb-ot-shaper-use-table.hh \
+       hb-ot-shaper-use.cc hb-ot-shaper-vowel-constraints.cc \
+       hb-ot-shaper-vowel-constraints.hh hb-ot-shaper.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-common.hh hb-ot-var-cvar-table.hh \
        hb-ot-var-fvar-table.hh hb-ot-var-gvar-table.hh \
        hb-ot-var-hvar-table.hh hb-ot-var-mvar-table.hh hb-ot-var.cc \
        hb-ot-vorg-table.hh hb-pool.hh hb-sanitize.hh hb-serialize.hh \
@@ -351,47 +420,53 @@ am__libharfbuzz_la_SOURCES_DIST = hb-aat-layout-ankr-table.hh \
        hb-string-array.hh hb-style.cc hb-ucd-table.hh hb-ucd.cc \
        hb-unicode-emoji-table.hh hb-unicode.cc hb-unicode.hh \
        hb-utf.hh hb-vector.hh hb-priority-queue.hh hb.hh \
-       hb-buffer-deserialize-json.hh hb-buffer-deserialize-text.hh \
-       hb-number-parser.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-glib.cc hb-ft.cc \
-       hb-graphite2.cc hb-uniscribe.cc hb-directwrite.cc hb-gdi.cc \
-       hb-coretext.cc hb-icu.cc hb-aat-layout.h hb-aat.h hb-blob.h \
-       hb-buffer.h hb-common.h hb-deprecated.h hb-draw.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-meta.h \
-       hb-ot-metrics.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-style.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-gdi.h hb-coretext.h \
-       hb-icu.h
-am__objects_7 = libharfbuzz_la-hb-aat-layout.lo \
+       hb-buffer-deserialize-json.hh \
+       hb-buffer-deserialize-text-glyphs.hh \
+       hb-buffer-deserialize-text-unicode.hh hb-number-parser.hh \
+       hb-ot-shaper-indic-machine.hh hb-ot-shaper-khmer-machine.hh \
+       hb-ot-shaper-myanmar-machine.hh hb-ot-shaper-use-machine.hh \
+       hb-glib.cc hb-ft.cc hb-ft-colr.hh hb-graphite2.cc \
+       hb-uniscribe.cc hb-directwrite.cc hb-gdi.cc hb-coretext.cc \
+       hb-wasm-api.cc hb-wasm-api.hh hb-wasm-api-blob.hh \
+       hb-wasm-api-buffer.hh hb-wasm-api-common.hh \
+       hb-wasm-api-face.hh hb-wasm-api-font.hh hb-wasm-api-shape.hh \
+       hb-wasm-shape.cc hb-icu.cc hb-aat-layout.h hb-aat.h hb-blob.h \
+       hb-buffer.h hb-common.h hb-cplusplus.hh hb-deprecated.h \
+       hb-draw.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-meta.h hb-ot-metrics.h hb-ot-name.h hb-ot-shape.h \
+       hb-ot-var.h hb-ot.h hb-paint.h hb-set.h hb-shape-plan.h \
+       hb-shape.h hb-style.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-gdi.h hb-coretext.h hb-wasm-api.h hb-icu.h
+am__objects_8 = 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-verify.lo libharfbuzz_la-hb-buffer.lo \
        libharfbuzz_la-hb-common.lo libharfbuzz_la-hb-draw.lo \
-       libharfbuzz_la-hb-face.lo libharfbuzz_la-hb-fallback-shape.lo \
-       libharfbuzz_la-hb-font.lo libharfbuzz_la-hb-map.lo \
-       libharfbuzz_la-hb-number.lo libharfbuzz_la-hb-ot-cff1-table.lo \
+       libharfbuzz_la-hb-face.lo libharfbuzz_la-hb-face-builder.lo \
+       libharfbuzz_la-hb-fallback-shape.lo libharfbuzz_la-hb-font.lo \
+       libharfbuzz_la-hb-map.lo libharfbuzz_la-hb-number.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-map.lo libharfbuzz_la-hb-ot-math.lo \
-       libharfbuzz_la-hb-ot-meta.lo libharfbuzz_la-hb-ot-metrics.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-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-syllabic.lo \
-       libharfbuzz_la-hb-ot-shape-complex-thai.lo \
-       libharfbuzz_la-hb-ot-shape-complex-use.lo \
-       libharfbuzz_la-hb-ot-shape-complex-vowel-constraints.lo \
+       libharfbuzz_la-hb-ot-font.lo libharfbuzz_la-hb-outline.lo \
+       libharfbuzz_la-hb-paint.lo libharfbuzz_la-hb-paint-extents.lo \
+       libharfbuzz_la-hb-ot-layout.lo libharfbuzz_la-hb-ot-map.lo \
+       libharfbuzz_la-hb-ot-math.lo libharfbuzz_la-hb-ot-meta.lo \
+       libharfbuzz_la-hb-ot-metrics.lo libharfbuzz_la-hb-ot-name.lo \
+       libharfbuzz_la-hb-ot-shaper-arabic.lo \
+       libharfbuzz_la-hb-ot-shaper-default.lo \
+       libharfbuzz_la-hb-ot-shaper-hangul.lo \
+       libharfbuzz_la-hb-ot-shaper-hebrew.lo \
+       libharfbuzz_la-hb-ot-shaper-indic-table.lo \
+       libharfbuzz_la-hb-ot-shaper-indic.lo \
+       libharfbuzz_la-hb-ot-shaper-khmer.lo \
+       libharfbuzz_la-hb-ot-shaper-myanmar.lo \
+       libharfbuzz_la-hb-ot-shaper-syllabic.lo \
+       libharfbuzz_la-hb-ot-shaper-thai.lo \
+       libharfbuzz_la-hb-ot-shaper-use.lo \
+       libharfbuzz_la-hb-ot-shaper-vowel-constraints.lo \
        libharfbuzz_la-hb-ot-shape-fallback.lo \
        libharfbuzz_la-hb-ot-shape-normalize.lo \
        libharfbuzz_la-hb-ot-shape.lo libharfbuzz_la-hb-ot-tag.lo \
@@ -399,42 +474,47 @@ am__objects_7 = libharfbuzz_la-hb-aat-layout.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-style.lo libharfbuzz_la-hb-ucd.lo \
-       libharfbuzz_la-hb-unicode.lo $(am__objects_5)
-am__objects_8 = $(am__objects_5)
-am__objects_9 = libharfbuzz_la-hb-glib.lo
-@HAVE_GLIB_TRUE@am__objects_10 = $(am__objects_9)
-am__objects_11 = libharfbuzz_la-hb-ft.lo
-@HAVE_FREETYPE_TRUE@am__objects_12 = $(am__objects_11)
-am__objects_13 = libharfbuzz_la-hb-graphite2.lo
-@HAVE_GRAPHITE2_TRUE@am__objects_14 = $(am__objects_13)
-am__objects_15 = libharfbuzz_la-hb-uniscribe.lo
-@HAVE_UNISCRIBE_TRUE@am__objects_16 = $(am__objects_15)
-am__objects_17 = libharfbuzz_la-hb-directwrite.lo
-@HAVE_DIRECTWRITE_TRUE@am__objects_18 = $(am__objects_17)
-am__objects_19 = libharfbuzz_la-hb-gdi.lo
-@HAVE_GDI_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-icu.lo
-@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__objects_24 =  \
-@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@ $(am__objects_23)
-am__objects_25 = $(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)
-@HAVE_GLIB_TRUE@am__objects_26 = $(am__objects_5)
-@HAVE_FREETYPE_TRUE@am__objects_27 = $(am__objects_5)
-@HAVE_GRAPHITE2_TRUE@am__objects_28 = $(am__objects_5)
-@HAVE_UNISCRIBE_TRUE@am__objects_29 = $(am__objects_5)
-@HAVE_DIRECTWRITE_TRUE@am__objects_30 = $(am__objects_5)
-@HAVE_GDI_TRUE@am__objects_31 = $(am__objects_5)
-@HAVE_CORETEXT_TRUE@am__objects_32 = $(am__objects_5)
-@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__objects_33 =  \
-@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@ $(am__objects_5)
-am__objects_34 = $(am__objects_8) $(am__objects_26) $(am__objects_27) \
-       $(am__objects_28) $(am__objects_29) $(am__objects_30) \
-       $(am__objects_31) $(am__objects_32) $(am__objects_33)
-am_libharfbuzz_la_OBJECTS = $(am__objects_25) $(am__objects_34)
+       libharfbuzz_la-hb-unicode.lo $(am__objects_1)
+am__objects_9 = $(am__objects_1)
+am__objects_10 = libharfbuzz_la-hb-glib.lo
+@HAVE_GLIB_TRUE@am__objects_11 = $(am__objects_10)
+am__objects_12 = libharfbuzz_la-hb-ft.lo
+@HAVE_FREETYPE_TRUE@am__objects_13 = $(am__objects_12)
+am__objects_14 = libharfbuzz_la-hb-graphite2.lo
+@HAVE_GRAPHITE2_TRUE@am__objects_15 = $(am__objects_14)
+am__objects_16 = libharfbuzz_la-hb-uniscribe.lo
+@HAVE_UNISCRIBE_TRUE@am__objects_17 = $(am__objects_16)
+am__objects_18 = libharfbuzz_la-hb-directwrite.lo
+@HAVE_DIRECTWRITE_TRUE@am__objects_19 = $(am__objects_18)
+am__objects_20 = libharfbuzz_la-hb-gdi.lo
+@HAVE_GDI_TRUE@am__objects_21 = $(am__objects_20)
+am__objects_22 = libharfbuzz_la-hb-coretext.lo
+@HAVE_CORETEXT_TRUE@am__objects_23 = $(am__objects_22)
+am__objects_24 = libharfbuzz_la-hb-wasm-api.lo \
+       libharfbuzz_la-hb-wasm-shape.lo $(am__objects_1)
+@HAVE_WASM_TRUE@am__objects_25 = $(am__objects_24)
+am__objects_26 = libharfbuzz_la-hb-icu.lo
+@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__objects_27 =  \
+@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@ $(am__objects_26)
+am__objects_28 = $(am__objects_8) $(am__objects_9) $(am__objects_11) \
+       $(am__objects_13) $(am__objects_15) $(am__objects_17) \
+       $(am__objects_19) $(am__objects_21) $(am__objects_23) \
+       $(am__objects_25) $(am__objects_27)
+@HAVE_GLIB_TRUE@am__objects_29 = $(am__objects_1)
+@HAVE_FREETYPE_TRUE@am__objects_30 = $(am__objects_1)
+@HAVE_GRAPHITE2_TRUE@am__objects_31 = $(am__objects_1)
+@HAVE_UNISCRIBE_TRUE@am__objects_32 = $(am__objects_1)
+@HAVE_DIRECTWRITE_TRUE@am__objects_33 = $(am__objects_1)
+@HAVE_GDI_TRUE@am__objects_34 = $(am__objects_1)
+@HAVE_CORETEXT_TRUE@am__objects_35 = $(am__objects_1)
+@HAVE_WASM_TRUE@am__objects_36 = $(am__objects_1)
+@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@am__objects_37 =  \
+@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@ $(am__objects_1)
+am__objects_38 = $(am__objects_9) $(am__objects_29) $(am__objects_30) \
+       $(am__objects_31) $(am__objects_32) $(am__objects_33) \
+       $(am__objects_34) $(am__objects_35) $(am__objects_36) \
+       $(am__objects_37)
+am_libharfbuzz_la_OBJECTS = $(am__objects_28) $(am__objects_38)
 libharfbuzz_la_OBJECTS = $(am_libharfbuzz_la_OBJECTS)
 am_main_OBJECTS = main-main.$(OBJEXT)
 main_OBJECTS = $(am_main_OBJECTS)
@@ -460,16 +540,41 @@ am_test_buffer_serialize_OBJECTS =  \
 test_buffer_serialize_OBJECTS = $(am_test_buffer_serialize_OBJECTS)
 test_buffer_serialize_DEPENDENCIES = libharfbuzz.la \
        $(am__DEPENDENCIES_12)
+am_test_classdef_graph_OBJECTS =  \
+       test_classdef_graph-test-classdef-graph.$(OBJEXT) \
+       test_classdef_graph-hb-static.$(OBJEXT) \
+       test_classdef_graph-gsubgpos-context.$(OBJEXT)
+test_classdef_graph_OBJECTS = $(am_test_classdef_graph_OBJECTS)
+test_classdef_graph_DEPENDENCIES = libharfbuzz.la \
+       libharfbuzz-subset.la $(am__DEPENDENCIES_12)
 am_test_gpos_size_params_OBJECTS =  \
        test_gpos_size_params-test-gpos-size-params.$(OBJEXT)
 test_gpos_size_params_OBJECTS = $(am_test_gpos_size_params_OBJECTS)
 test_gpos_size_params_DEPENDENCIES = libharfbuzz.la \
        $(am__DEPENDENCIES_12)
+am_test_gsub_get_alternates_OBJECTS =  \
+       test_gsub_get_alternates-test-gsub-get-alternates.$(OBJEXT)
+test_gsub_get_alternates_OBJECTS =  \
+       $(am_test_gsub_get_alternates_OBJECTS)
+test_gsub_get_alternates_DEPENDENCIES = libharfbuzz.la \
+       $(am__DEPENDENCIES_12)
 am_test_gsub_would_substitute_OBJECTS = test_gsub_would_substitute-test-gsub-would-substitute.$(OBJEXT)
 test_gsub_would_substitute_OBJECTS =  \
        $(am_test_gsub_would_substitute_OBJECTS)
 test_gsub_would_substitute_DEPENDENCIES = libharfbuzz.la \
        $(am__DEPENDENCIES_12) $(am__DEPENDENCIES_1)
+am_test_instancer_solver_OBJECTS =  \
+       test_instancer_solver-test-subset-instancer-solver.$(OBJEXT) \
+       test_instancer_solver-hb-subset-instancer-solver.$(OBJEXT) \
+       test_instancer_solver-hb-static.$(OBJEXT)
+test_instancer_solver_OBJECTS = $(am_test_instancer_solver_OBJECTS)
+test_instancer_solver_DEPENDENCIES = $(am__DEPENDENCIES_13)
+am_test_item_varstore_OBJECTS =  \
+       test_item_varstore-test-item-varstore.$(OBJEXT) \
+       test_item_varstore-hb-subset-instancer-solver.$(OBJEXT) \
+       test_item_varstore-hb-static.$(OBJEXT)
+test_item_varstore_OBJECTS = $(am_test_item_varstore_OBJECTS)
+test_item_varstore_DEPENDENCIES = $(am__DEPENDENCIES_13)
 am_test_iter_OBJECTS = test_iter-test-iter.$(OBJEXT) \
        test_iter-hb-static.$(OBJEXT)
 test_iter_OBJECTS = $(am_test_iter_OBJECTS)
@@ -482,6 +587,10 @@ am_test_map_OBJECTS = test_map-test-map.$(OBJEXT) \
        test_map-hb-static.$(OBJEXT)
 test_map_OBJECTS = $(am_test_map_OBJECTS)
 test_map_DEPENDENCIES = $(am__DEPENDENCIES_13)
+am_test_multimap_OBJECTS = test_multimap-test-multimap.$(OBJEXT) \
+       test_multimap-hb-static.$(OBJEXT)
+test_multimap_OBJECTS = $(am_test_multimap_OBJECTS)
+test_multimap_DEPENDENCIES = $(am__DEPENDENCIES_13)
 am_test_number_OBJECTS = test_number-test-number.$(OBJEXT) \
        test_number-hb-number.$(OBJEXT)
 test_number_OBJECTS = $(am_test_number_OBJECTS)
@@ -506,7 +615,8 @@ test_priority_queue_OBJECTS = $(am_test_priority_queue_OBJECTS)
 test_priority_queue_DEPENDENCIES = libharfbuzz.la \
        $(am__DEPENDENCIES_12)
 am_test_repacker_OBJECTS = test_repacker-test-repacker.$(OBJEXT) \
-       test_repacker-hb-static.$(OBJEXT)
+       test_repacker-hb-static.$(OBJEXT) \
+       test_repacker-gsubgpos-context.$(OBJEXT)
 test_repacker_OBJECTS = $(am_test_repacker_OBJECTS)
 test_repacker_DEPENDENCIES = libharfbuzz.la libharfbuzz-subset.la \
        $(am__DEPENDENCIES_12)
@@ -518,10 +628,19 @@ am_test_set_OBJECTS = test_set-test-set.$(OBJEXT) \
        test_set-hb-static.$(OBJEXT)
 test_set_OBJECTS = $(am_test_set_OBJECTS)
 test_set_DEPENDENCIES = $(am__DEPENDENCIES_13)
+am_test_tuple_varstore_OBJECTS =  \
+       test_tuple_varstore-test-tuple-varstore.$(OBJEXT) \
+       test_tuple_varstore-hb-subset-instancer-solver.$(OBJEXT) \
+       test_tuple_varstore-hb-static.$(OBJEXT)
+test_tuple_varstore_OBJECTS = $(am_test_tuple_varstore_OBJECTS)
+test_tuple_varstore_DEPENDENCIES = $(am__DEPENDENCIES_13)
 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 = $(am__DEPENDENCIES_13)
+am_test_use_table_OBJECTS = test_use_table-test-use-table.$(OBJEXT)
+test_use_table_OBJECTS = $(am_test_use_table_OBJECTS)
+test_use_table_DEPENDENCIES = libharfbuzz.la $(am__DEPENDENCIES_12)
 am_test_vector_OBJECTS = test_vector-test-vector.$(OBJEXT) \
        test_vector-hb-static.$(OBJEXT)
 test_vector_OBJECTS = $(am_test_vector_OBJECTS)
@@ -545,6 +664,9 @@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
 depcomp = $(SHELL) $(top_srcdir)/depcomp
 am__maybe_remake_depfiles = depfiles
 am__depfiles_remade =  \
+       ./$(DEPDIR)/libharfbuzz_cairo_la-hb-cairo-utils.Plo \
+       ./$(DEPDIR)/libharfbuzz_cairo_la-hb-cairo.Plo \
+       ./$(DEPDIR)/libharfbuzz_cairo_la-hb-static.Plo \
        ./$(DEPDIR)/libharfbuzz_gobject_la-hb-gobject-enums.Plo \
        ./$(DEPDIR)/libharfbuzz_gobject_la-hb-gobject-structs.Plo \
        ./$(DEPDIR)/libharfbuzz_icu_la-hb-icu.Plo \
@@ -558,6 +680,7 @@ am__depfiles_remade =  \
        ./$(DEPDIR)/libharfbuzz_la-hb-coretext.Plo \
        ./$(DEPDIR)/libharfbuzz_la-hb-directwrite.Plo \
        ./$(DEPDIR)/libharfbuzz_la-hb-draw.Plo \
+       ./$(DEPDIR)/libharfbuzz_la-hb-face-builder.Plo \
        ./$(DEPDIR)/libharfbuzz_la-hb-face.Plo \
        ./$(DEPDIR)/libharfbuzz_la-hb-fallback-shape.Plo \
        ./$(DEPDIR)/libharfbuzz_la-hb-font.Plo \
@@ -579,23 +702,26 @@ am__depfiles_remade =  \
        ./$(DEPDIR)/libharfbuzz_la-hb-ot-meta.Plo \
        ./$(DEPDIR)/libharfbuzz_la-hb-ot-metrics.Plo \
        ./$(DEPDIR)/libharfbuzz_la-hb-ot-name.Plo \
-       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-arabic.Plo \
-       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-default.Plo \
-       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-hangul.Plo \
-       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-hebrew.Plo \
-       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-indic-table.Plo \
-       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-indic.Plo \
-       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-khmer.Plo \
-       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-myanmar.Plo \
-       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-syllabic.Plo \
-       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-thai.Plo \
-       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-use.Plo \
-       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-vowel-constraints.Plo \
        ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-fallback.Plo \
        ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-normalize.Plo \
        ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape.Plo \
+       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-arabic.Plo \
+       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-default.Plo \
+       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-hangul.Plo \
+       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-hebrew.Plo \
+       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-indic-table.Plo \
+       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-indic.Plo \
+       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-khmer.Plo \
+       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-myanmar.Plo \
+       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-syllabic.Plo \
+       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-thai.Plo \
+       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-use.Plo \
+       ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-vowel-constraints.Plo \
        ./$(DEPDIR)/libharfbuzz_la-hb-ot-tag.Plo \
        ./$(DEPDIR)/libharfbuzz_la-hb-ot-var.Plo \
+       ./$(DEPDIR)/libharfbuzz_la-hb-outline.Plo \
+       ./$(DEPDIR)/libharfbuzz_la-hb-paint-extents.Plo \
+       ./$(DEPDIR)/libharfbuzz_la-hb-paint.Plo \
        ./$(DEPDIR)/libharfbuzz_la-hb-set.Plo \
        ./$(DEPDIR)/libharfbuzz_la-hb-shape-plan.Plo \
        ./$(DEPDIR)/libharfbuzz_la-hb-shape.Plo \
@@ -605,6 +731,9 @@ am__depfiles_remade =  \
        ./$(DEPDIR)/libharfbuzz_la-hb-ucd.Plo \
        ./$(DEPDIR)/libharfbuzz_la-hb-unicode.Plo \
        ./$(DEPDIR)/libharfbuzz_la-hb-uniscribe.Plo \
+       ./$(DEPDIR)/libharfbuzz_la-hb-wasm-api.Plo \
+       ./$(DEPDIR)/libharfbuzz_la-hb-wasm-shape.Plo \
+       ./$(DEPDIR)/libharfbuzz_subset_la-gsubgpos-context.Plo \
        ./$(DEPDIR)/libharfbuzz_subset_la-hb-number.Plo \
        ./$(DEPDIR)/libharfbuzz_subset_la-hb-ot-cff1-table.Plo \
        ./$(DEPDIR)/libharfbuzz_subset_la-hb-ot-cff2-table.Plo \
@@ -613,7 +742,9 @@ am__depfiles_remade =  \
        ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff1.Plo \
        ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff2.Plo \
        ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-input.Plo \
+       ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-instancer-solver.Plo \
        ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-plan.Plo \
+       ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-repacker.Plo \
        ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset.Plo \
        ./$(DEPDIR)/main-main.Po ./$(DEPDIR)/test-test.Po \
        ./$(DEPDIR)/test_algs-hb-static.Po \
@@ -622,14 +753,26 @@ am__depfiles_remade =  \
        ./$(DEPDIR)/test_bimap-hb-static.Po \
        ./$(DEPDIR)/test_bimap-test-bimap.Po \
        ./$(DEPDIR)/test_buffer_serialize-test-buffer-serialize.Po \
+       ./$(DEPDIR)/test_classdef_graph-gsubgpos-context.Po \
+       ./$(DEPDIR)/test_classdef_graph-hb-static.Po \
+       ./$(DEPDIR)/test_classdef_graph-test-classdef-graph.Po \
        ./$(DEPDIR)/test_gpos_size_params-test-gpos-size-params.Po \
+       ./$(DEPDIR)/test_gsub_get_alternates-test-gsub-get-alternates.Po \
        ./$(DEPDIR)/test_gsub_would_substitute-test-gsub-would-substitute.Po \
+       ./$(DEPDIR)/test_instancer_solver-hb-static.Po \
+       ./$(DEPDIR)/test_instancer_solver-hb-subset-instancer-solver.Po \
+       ./$(DEPDIR)/test_instancer_solver-test-subset-instancer-solver.Po \
+       ./$(DEPDIR)/test_item_varstore-hb-static.Po \
+       ./$(DEPDIR)/test_item_varstore-hb-subset-instancer-solver.Po \
+       ./$(DEPDIR)/test_item_varstore-test-item-varstore.Po \
        ./$(DEPDIR)/test_iter-hb-static.Po \
        ./$(DEPDIR)/test_iter-test-iter.Po \
        ./$(DEPDIR)/test_machinery-hb-static.Po \
        ./$(DEPDIR)/test_machinery-test-machinery.Po \
        ./$(DEPDIR)/test_map-hb-static.Po \
        ./$(DEPDIR)/test_map-test-map.Po \
+       ./$(DEPDIR)/test_multimap-hb-static.Po \
+       ./$(DEPDIR)/test_multimap-test-multimap.Po \
        ./$(DEPDIR)/test_number-hb-number.Po \
        ./$(DEPDIR)/test_number-test-number.Po \
        ./$(DEPDIR)/test_ot_glyphname-test-ot-glyphname.Po \
@@ -638,13 +781,18 @@ am__depfiles_remade =  \
        ./$(DEPDIR)/test_ot_tag-hb-ot-tag.Po \
        ./$(DEPDIR)/test_priority_queue-hb-static.Po \
        ./$(DEPDIR)/test_priority_queue-test-priority-queue.Po \
+       ./$(DEPDIR)/test_repacker-gsubgpos-context.Po \
        ./$(DEPDIR)/test_repacker-hb-static.Po \
        ./$(DEPDIR)/test_repacker-test-repacker.Po \
        ./$(DEPDIR)/test_serialize-hb-static.Po \
        ./$(DEPDIR)/test_serialize-test-serialize.Po \
        ./$(DEPDIR)/test_set-hb-static.Po \
        ./$(DEPDIR)/test_set-test-set.Po \
+       ./$(DEPDIR)/test_tuple_varstore-hb-static.Po \
+       ./$(DEPDIR)/test_tuple_varstore-hb-subset-instancer-solver.Po \
+       ./$(DEPDIR)/test_tuple_varstore-test-tuple-varstore.Po \
        ./$(DEPDIR)/test_unicode_ranges-test-unicode-ranges.Po \
+       ./$(DEPDIR)/test_use_table-test-use-table.Po \
        ./$(DEPDIR)/test_vector-hb-static.Po \
        ./$(DEPDIR)/test_vector-test-vector.Po
 am__mv = mv -f
@@ -684,35 +832,47 @@ 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_gobject_la_SOURCES) \
+SOURCES = $(libharfbuzz_cairo_la_SOURCES) \
+       $(libharfbuzz_gobject_la_SOURCES) \
        $(nodist_libharfbuzz_gobject_la_SOURCES) \
        $(libharfbuzz_icu_la_SOURCES) $(libharfbuzz_subset_la_SOURCES) \
        $(libharfbuzz_la_SOURCES) $(main_SOURCES) $(test_SOURCES) \
        $(test_algs_SOURCES) $(test_array_SOURCES) \
        $(test_bimap_SOURCES) $(test_buffer_serialize_SOURCES) \
+       $(test_classdef_graph_SOURCES) \
        $(test_gpos_size_params_SOURCES) \
-       $(test_gsub_would_substitute_SOURCES) $(test_iter_SOURCES) \
-       $(test_machinery_SOURCES) $(test_map_SOURCES) \
+       $(test_gsub_get_alternates_SOURCES) \
+       $(test_gsub_would_substitute_SOURCES) \
+       $(test_instancer_solver_SOURCES) $(test_item_varstore_SOURCES) \
+       $(test_iter_SOURCES) $(test_machinery_SOURCES) \
+       $(test_map_SOURCES) $(test_multimap_SOURCES) \
        $(test_number_SOURCES) $(test_ot_glyphname_SOURCES) \
        $(test_ot_meta_SOURCES) $(test_ot_name_SOURCES) \
        $(test_ot_tag_SOURCES) $(test_priority_queue_SOURCES) \
        $(test_repacker_SOURCES) $(test_serialize_SOURCES) \
-       $(test_set_SOURCES) $(test_unicode_ranges_SOURCES) \
+       $(test_set_SOURCES) $(test_tuple_varstore_SOURCES) \
+       $(test_unicode_ranges_SOURCES) $(test_use_table_SOURCES) \
        $(test_vector_SOURCES)
-DIST_SOURCES = $(am__libharfbuzz_gobject_la_SOURCES_DIST) \
+DIST_SOURCES = $(libharfbuzz_cairo_la_SOURCES) \
+       $(am__libharfbuzz_gobject_la_SOURCES_DIST) \
        $(am__libharfbuzz_icu_la_SOURCES_DIST) \
        $(libharfbuzz_subset_la_SOURCES) \
        $(am__libharfbuzz_la_SOURCES_DIST) $(main_SOURCES) \
        $(test_SOURCES) $(test_algs_SOURCES) $(test_array_SOURCES) \
        $(test_bimap_SOURCES) $(test_buffer_serialize_SOURCES) \
+       $(test_classdef_graph_SOURCES) \
        $(test_gpos_size_params_SOURCES) \
-       $(test_gsub_would_substitute_SOURCES) $(test_iter_SOURCES) \
-       $(test_machinery_SOURCES) $(test_map_SOURCES) \
+       $(test_gsub_get_alternates_SOURCES) \
+       $(test_gsub_would_substitute_SOURCES) \
+       $(test_instancer_solver_SOURCES) $(test_item_varstore_SOURCES) \
+       $(test_iter_SOURCES) $(test_machinery_SOURCES) \
+       $(test_map_SOURCES) $(test_multimap_SOURCES) \
        $(test_number_SOURCES) $(test_ot_glyphname_SOURCES) \
        $(test_ot_meta_SOURCES) $(test_ot_name_SOURCES) \
        $(test_ot_tag_SOURCES) $(test_priority_queue_SOURCES) \
        $(test_repacker_SOURCES) $(test_serialize_SOURCES) \
-       $(test_set_SOURCES) $(test_unicode_ranges_SOURCES) \
+       $(test_set_SOURCES) $(test_tuple_varstore_SOURCES) \
+       $(test_unicode_ranges_SOURCES) $(test_use_table_SOURCES) \
        $(test_vector_SOURCES)
 RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
        ctags-recursive dvi-recursive html-recursive info-recursive \
@@ -729,14 +889,16 @@ am__can_run_installinfo = \
   esac
 DATA = $(cmake_DATA) $(gir_DATA) $(pkgconfig_DATA) $(typelib_DATA)
 am__pkginclude_HEADERS_DIST = hb-aat-layout.h hb-aat.h hb-blob.h \
-       hb-buffer.h hb-common.h hb-deprecated.h hb-draw.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-meta.h \
-       hb-ot-metrics.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-style.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-gdi.h hb-coretext.h \
-       hb-icu.h hb-subset.h hb-gobject.h hb-gobject-structs.h
+       hb-buffer.h hb-common.h hb-cplusplus.hh hb-deprecated.h \
+       hb-draw.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-meta.h hb-ot-metrics.h hb-ot-name.h hb-ot-shape.h \
+       hb-ot-var.h hb-ot.h hb-paint.h hb-set.h hb-shape-plan.h \
+       hb-shape.h hb-style.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-gdi.h hb-coretext.h hb-wasm-api.h hb-icu.h hb-subset.h \
+       hb-subset-repacker.h hb-cairo.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
@@ -1009,8 +1171,6 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
-DIRECTWRITE_CXXFLAGS = @DIRECTWRITE_CXXFLAGS@
-DIRECTWRITE_LIBS = @DIRECTWRITE_LIBS@
 DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -1108,6 +1268,8 @@ STRIP = @STRIP@
 UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
 UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
 VERSION = @VERSION@
+WASM_CFLAGS = @WASM_CFLAGS@
+WASM_LIBS = @WASM_LIBS@
 _GI_EXP_DATADIR = @_GI_EXP_DATADIR@
 _GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@
 abs_builddir = @abs_builddir@
@@ -1169,19 +1331,21 @@ top_srcdir = @top_srcdir@
 NULL = 
 SUBDIRS = 
 DIST_SUBDIRS = 
-BUILT_SOURCES = hb-version.h $(am__append_45) $(RAGEL_GENERATED) \
-       harfbuzz.cc
-EXTRA_DIST = harfbuzz.cc meson.build fix_get_types.py 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) $(NULL)
-CLEANFILES = $(pkgconfig_DATA) $(DEF_FILES) $(am__append_49)
-DISTCLEANFILES = $(am__append_46)
+BUILT_SOURCES = hb-version.h harfbuzz-subset.cc $(am__append_49) \
+       hb-features.h $(RAGEL_GENERATED) harfbuzz.cc
+EXTRA_DIST = harfbuzz.cc harfbuzz-subset.cc meson.build \
+       fix_get_types.py relative_to.py hb-version.h.in \
+       hb-features.h.in harfbuzz.pc.in harfbuzz-config.cmake.in \
+       harfbuzz-subset.pc.in harfbuzz-cairo.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) $(NULL)
+CLEANFILES = $(pkgconfig_DATA) $(DEF_FILES) $(am__append_53)
+DISTCLEANFILES = $(am__append_50) hb-features.h
 MAINTAINERCLEANFILES = 
 DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
 lib_LTLIBRARIES = libharfbuzz.la libharfbuzz-subset.la \
-       $(am__append_38) $(am__append_41)
+       libharfbuzz-cairo.la $(am__append_42) $(am__append_45)
 HB_BASE_sources = \
        hb-aat-layout-ankr-table.hh \
        hb-aat-layout-bsln-table.hh \
@@ -1224,16 +1388,19 @@ HB_BASE_sources = \
        hb-draw.hh \
        hb-face.cc \
        hb-face.hh \
+       hb-face-builder.cc \
        hb-fallback-shape.cc \
        hb-font.cc \
        hb-font.hh \
        hb-iter.hh \
        hb-kern.hh \
+       hb-limits.hh \
        hb-machinery.hh \
        hb-map.cc \
        hb-map.hh \
        hb-meta.hh \
        hb-ms-feature-ranges.hh \
+       hb-multimap.hh \
        hb-mutex.hh \
        hb-null.hh \
        hb-number.cc \
@@ -1248,11 +1415,6 @@ HB_BASE_sources = \
        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-table-list.hh \
        hb-ot-face.cc \
@@ -1269,7 +1431,91 @@ HB_BASE_sources = \
        hb-ot-layout-common.hh \
        hb-ot-layout-gdef-table.hh \
        hb-ot-layout-gpos-table.hh \
+       hb-outline.hh \
+       hb-outline.cc \
+       hb-paint.cc \
+       hb-paint.hh \
+       hb-paint-extents.cc \
+       hb-paint-extents.hh \
        hb-ot-layout-gsub-table.hh \
+       OT/Color/CBDT/CBDT.hh \
+       OT/Color/COLR/COLR.hh \
+       OT/Color/CPAL/CPAL.hh \
+       OT/Color/sbix/sbix.hh \
+       OT/Color/svg/svg.hh \
+       OT/glyf/glyf.hh \
+       OT/glyf/glyf-helpers.hh \
+       OT/glyf/loca.hh \
+       OT/glyf/path-builder.hh \
+       OT/glyf/Glyph.hh \
+       OT/glyf/GlyphHeader.hh \
+       OT/glyf/SimpleGlyph.hh \
+       OT/glyf/coord-setter.hh \
+       OT/glyf/composite-iter.hh \
+       OT/glyf/CompositeGlyph.hh \
+       OT/glyf/VarCompositeGlyph.hh \
+       OT/glyf/SubsetGlyph.hh \
+       OT/Layout/types.hh \
+       OT/Layout/Common/Coverage.hh \
+       OT/Layout/Common/CoverageFormat1.hh \
+       OT/Layout/Common/CoverageFormat2.hh \
+       OT/Layout/Common/RangeRecord.hh \
+       OT/Layout/GDEF/GDEF.hh \
+       OT/Layout/GPOS/AnchorFormat1.hh \
+       OT/Layout/GPOS/AnchorFormat2.hh \
+       OT/Layout/GPOS/AnchorFormat3.hh \
+       OT/Layout/GPOS/Anchor.hh \
+       OT/Layout/GPOS/AnchorMatrix.hh \
+       OT/Layout/GPOS/ChainContextPos.hh \
+       OT/Layout/GPOS/Common.hh \
+       OT/Layout/GPOS/ContextPos.hh \
+       OT/Layout/GPOS/CursivePosFormat1.hh \
+       OT/Layout/GPOS/CursivePos.hh \
+       OT/Layout/GPOS/ExtensionPos.hh \
+       OT/Layout/GPOS/GPOS.hh \
+       OT/Layout/GPOS/LigatureArray.hh \
+       OT/Layout/GPOS/MarkArray.hh \
+       OT/Layout/GPOS/MarkBasePosFormat1.hh \
+       OT/Layout/GPOS/MarkBasePos.hh \
+       OT/Layout/GPOS/MarkLigPosFormat1.hh \
+       OT/Layout/GPOS/MarkLigPos.hh \
+       OT/Layout/GPOS/MarkMarkPosFormat1.hh \
+       OT/Layout/GPOS/MarkMarkPos.hh \
+       OT/Layout/GPOS/MarkRecord.hh \
+       OT/Layout/GPOS/PairPosFormat1.hh \
+       OT/Layout/GPOS/PairPosFormat2.hh \
+       OT/Layout/GPOS/PairPos.hh \
+       OT/Layout/GPOS/PairSet.hh \
+       OT/Layout/GPOS/PairValueRecord.hh \
+       OT/Layout/GPOS/PosLookup.hh \
+       OT/Layout/GPOS/PosLookupSubTable.hh \
+       OT/Layout/GPOS/SinglePosFormat1.hh \
+       OT/Layout/GPOS/SinglePosFormat2.hh \
+       OT/Layout/GPOS/SinglePos.hh \
+       OT/Layout/GPOS/ValueFormat.hh \
+       OT/Layout/GSUB/AlternateSet.hh \
+       OT/Layout/GSUB/AlternateSubstFormat1.hh \
+       OT/Layout/GSUB/AlternateSubst.hh \
+       OT/Layout/GSUB/ChainContextSubst.hh \
+       OT/Layout/GSUB/Common.hh \
+       OT/Layout/GSUB/ContextSubst.hh \
+       OT/Layout/GSUB/ExtensionSubst.hh \
+       OT/Layout/GSUB/GSUB.hh \
+       OT/Layout/GSUB/Ligature.hh \
+       OT/Layout/GSUB/LigatureSet.hh \
+       OT/Layout/GSUB/LigatureSubstFormat1.hh \
+       OT/Layout/GSUB/LigatureSubst.hh \
+       OT/Layout/GSUB/MultipleSubstFormat1.hh \
+       OT/Layout/GSUB/MultipleSubst.hh \
+       OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh \
+       OT/Layout/GSUB/ReverseChainSingleSubst.hh \
+       OT/Layout/GSUB/Sequence.hh \
+       OT/Layout/GSUB/SingleSubstFormat1.hh \
+       OT/Layout/GSUB/SingleSubstFormat2.hh \
+       OT/Layout/GSUB/SingleSubst.hh \
+       OT/Layout/GSUB/SubstLookup.hh \
+       OT/Layout/GSUB/SubstLookupSubTable.hh \
+       OT/name/name.hh \
        hb-ot-layout-gsubgpos.hh \
        hb-ot-layout-jstf-table.hh \
        hb-ot-layout.cc \
@@ -1291,30 +1537,29 @@ HB_BASE_sources = \
        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-joining-list.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-syllabic.cc \
-       hb-ot-shape-complex-syllabic.hh \
-       hb-ot-shape-complex-thai.cc \
-       hb-ot-shape-complex-use-table.hh \
-       hb-ot-shape-complex-use.cc \
-       hb-ot-shape-complex-vowel-constraints.cc \
-       hb-ot-shape-complex-vowel-constraints.hh \
-       hb-ot-shape-complex.hh \
+       hb-ot-shaper-arabic-fallback.hh \
+       hb-ot-shaper-arabic-joining-list.hh \
+       hb-ot-shaper-arabic-pua.hh \
+       hb-ot-shaper-arabic-table.hh \
+       hb-ot-shaper-arabic-win1256.hh \
+       hb-ot-shaper-arabic.cc \
+       hb-ot-shaper-arabic.hh \
+       hb-ot-shaper-default.cc \
+       hb-ot-shaper-hangul.cc \
+       hb-ot-shaper-hebrew.cc \
+       hb-ot-shaper-indic-table.cc \
+       hb-ot-shaper-indic.cc \
+       hb-ot-shaper-indic.hh \
+       hb-ot-shaper-khmer.cc \
+       hb-ot-shaper-myanmar.cc \
+       hb-ot-shaper-syllabic.cc \
+       hb-ot-shaper-syllabic.hh \
+       hb-ot-shaper-thai.cc \
+       hb-ot-shaper-use-table.hh \
+       hb-ot-shaper-use.cc \
+       hb-ot-shaper-vowel-constraints.cc \
+       hb-ot-shaper-vowel-constraints.hh \
+       hb-ot-shaper.hh \
        hb-ot-shape-fallback.cc \
        hb-ot-shape-fallback.hh \
        hb-ot-shape-normalize.cc \
@@ -1326,6 +1571,7 @@ HB_BASE_sources = \
        hb-ot-tag.cc \
        hb-ot-var-avar-table.hh \
        hb-ot-var-common.hh \
+       hb-ot-var-cvar-table.hh \
        hb-ot-var-fvar-table.hh \
        hb-ot-var-gvar-table.hh \
        hb-ot-var-hvar-table.hh \
@@ -1361,22 +1607,24 @@ HB_BASE_sources = \
 
 HB_BASE_RAGEL_GENERATED_sources = \
        hb-buffer-deserialize-json.hh \
-       hb-buffer-deserialize-text.hh \
+       hb-buffer-deserialize-text-glyphs.hh \
+       hb-buffer-deserialize-text-unicode.hh \
        hb-number-parser.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-ot-shaper-indic-machine.hh \
+       hb-ot-shaper-khmer-machine.hh \
+       hb-ot-shaper-myanmar-machine.hh \
+       hb-ot-shaper-use-machine.hh \
        $(NULL)
 
 HB_BASE_RAGEL_sources = \
        hb-buffer-deserialize-json.rl \
-       hb-buffer-deserialize-text.rl \
+       hb-buffer-deserialize-text-glyphs.rl \
+       hb-buffer-deserialize-text-unicode.rl \
        hb-number-parser.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 \
+       hb-ot-shaper-indic-machine.rl \
+       hb-ot-shaper-khmer-machine.rl \
+       hb-ot-shaper-myanmar-machine.rl \
+       hb-ot-shaper-use-machine.rl \
        $(NULL)
 
 HB_BASE_headers = \
@@ -1385,6 +1633,7 @@ HB_BASE_headers = \
        hb-blob.h \
        hb-buffer.h \
        hb-common.h \
+       hb-cplusplus.hh \
        hb-deprecated.h \
        hb-draw.h \
        hb-face.h \
@@ -1401,6 +1650,7 @@ HB_BASE_headers = \
        hb-ot-shape.h \
        hb-ot-var.h \
        hb-ot.h \
+       hb-paint.h \
        hb-set.h \
        hb-shape-plan.h \
        hb-shape.h \
@@ -1412,7 +1662,7 @@ HB_BASE_headers = \
 
 
 # Optional Sources and Headers with external deps
-HB_FT_sources = hb-ft.cc
+HB_FT_sources = hb-ft.cc hb-ft-colr.hh
 HB_FT_headers = hb-ft.h
 HB_GLIB_sources = hb-glib.cc
 HB_GLIB_headers = hb-glib.h
@@ -1428,10 +1678,21 @@ HB_GDI_sources = hb-gdi.cc
 HB_GDI_headers = hb-gdi.h
 HB_UNISCRIBE_sources = hb-uniscribe.cc
 HB_UNISCRIBE_headers = hb-uniscribe.h
-
-# Sources for libharfbuzz-gobject and libharfbuzz-icu
 HB_ICU_sources = hb-icu.cc
 HB_ICU_headers = hb-icu.h
+HB_WASM_sources = \
+       hb-wasm-api.cc \
+       hb-wasm-api.hh \
+       hb-wasm-api-blob.hh \
+       hb-wasm-api-buffer.hh \
+       hb-wasm-api-common.hh \
+       hb-wasm-api-face.hh \
+       hb-wasm-api-font.hh \
+       hb-wasm-api-shape.hh \
+       hb-wasm-shape.cc \
+       $(NULL)
+
+HB_WASM_headers = hb-wasm-api.h
 
 # Sources for libharfbuzz-subset
 HB_SUBSET_sources = \
@@ -1439,26 +1700,51 @@ HB_SUBSET_sources = \
        hb-number.hh \
        hb-ot-cff1-table.cc \
        hb-ot-cff2-table.cc \
-       hb-ot-color-colrv1-closure.hh \
        hb-ot-post-table-v2subset.hh \
        hb-static.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-input.cc \
        hb-subset-input.hh \
+       hb-subset-instancer-solver.hh \
+       hb-subset-instancer-solver.cc \
+       hb-subset-accelerator.hh \
        hb-subset-plan.cc \
        hb-subset-plan.hh \
+       hb-subset-plan-member-list.hh \
+       hb-subset-repacker.cc \
        hb-subset.cc \
        hb-subset.hh \
        hb-repacker.hh \
+       graph/graph.hh \
+       graph/gsubgpos-graph.hh \
+       graph/gsubgpos-context.hh \
+       graph/gsubgpos-context.cc \
+       graph/coverage-graph.hh \
+       graph/classdef-graph.hh \
+       graph/pairpos-graph.hh \
+       graph/markbasepos-graph.hh \
+       graph/split-helpers.hh \
+       graph/serialize.hh \
+       OT/Color/COLR/colrv1-closure.hh \
        $(NULL)
 
 HB_SUBSET_headers = \
        hb-subset.h \
+       hb-subset-repacker.h \
+       $(NULL)
+
+HB_CAIRO_sources = \
+       hb-cairo.cc \
+       hb-cairo-utils.cc \
+       hb-cairo-utils.hh \
+       hb-static.cc \
+       $(NULL)
+
+HB_CAIRO_headers = \
+       hb-cairo.h \
        $(NULL)
 
 HB_GOBJECT_DIST_sources = hb-gobject-structs.cc
@@ -1471,25 +1757,45 @@ 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_1) $(am__append_3) $(am__append_8) \
        $(am__append_13) $(am__append_18) $(am__append_22) \
-       $(am__append_26) $(am__append_30) $(am__append_34)
+       $(am__append_26) $(am__append_30) $(am__append_34) \
+       $(am__append_38)
 
 # Put the library together
 HBLIBS = $(am__append_4) $(am__append_9) $(am__append_14) \
-       $(HBNONPCLIBS) $(am__append_35)
+       $(HBNONPCLIBS) $(am__append_39)
 HBNONPCLIBS = $(am__append_2) $(am__append_19) $(am__append_23) \
-       $(am__append_27) $(am__append_31)
+       $(am__append_27) $(am__append_31) $(am__append_35)
 HBDEPS = $(am__append_5) $(am__append_10) $(am__append_15)
 HBSOURCES = $(HB_BASE_sources) $(HB_BASE_RAGEL_GENERATED_sources) \
        $(am__append_6) $(am__append_11) $(am__append_16) \
        $(am__append_20) $(am__append_24) $(am__append_28) \
-       $(am__append_32) $(am__append_36)
+       $(am__append_32) $(am__append_36) $(am__append_40)
 HBHEADERS = $(HB_BASE_headers) $(am__append_7) $(am__append_12) \
        $(am__append_17) $(am__append_21) $(am__append_25) \
-       $(am__append_29) $(am__append_33) $(am__append_37)
+       $(am__append_29) $(am__append_33) $(am__append_37) \
+       $(am__append_41)
+@HAVE_GLIB_FALSE@HB_HAS_GLIB_DEF = undef HB_HAS_GLIB
+@HAVE_GLIB_TRUE@HB_HAS_GLIB_DEF = define HB_HAS_GLIB 1
+@HAVE_FREETYPE_FALSE@HB_HAS_FREETYPE_DEF = undef HB_HAS_FREETYPE
+@HAVE_FREETYPE_TRUE@HB_HAS_FREETYPE_DEF = define HB_HAS_FREETYPE 1
+@HAVE_GRAPHITE2_FALSE@HB_HAS_GRAPHITE_DEF = undef HB_HAS_GRAPHITE
+@HAVE_GRAPHITE2_TRUE@HB_HAS_GRAPHITE_DEF = define HB_HAS_GRAPHITE 1
+@HAVE_UNISCRIBE_FALSE@HB_HAS_UNISCRIBE_DEF = undef HB_HAS_UNISCRIBE
+@HAVE_UNISCRIBE_TRUE@HB_HAS_UNISCRIBE_DEF = define HB_HAS_UNISCRIBE 1
+@HAVE_DIRECTWRITE_FALSE@HB_HAS_DIRECTWRITE_DEF = undef HB_HAS_DIRECTWRITE
+@HAVE_DIRECTWRITE_TRUE@HB_HAS_DIRECTWRITE_DEF = define HB_HAS_DIRECTWRITE 1
+@HAVE_GDI_FALSE@HB_HAS_GDI_DEF = undef HB_HAS_GDI
+@HAVE_GDI_TRUE@HB_HAS_GDI_DEF = define HB_HAS_GDI 1
+@HAVE_CORETEXT_FALSE@HB_HAS_CORETEXT_DEF = undef HB_HAS_CORETEXT
+@HAVE_CORETEXT_TRUE@HB_HAS_CORETEXT_DEF = define HB_HAS_CORETEXT 1
+@HAVE_WASM_FALSE@HB_HAS_WASM_DEF = undef HB_HAS_WASM
+@HAVE_WASM_TRUE@HB_HAS_WASM_DEF = define HB_HAS_WASM 1
 @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
 @OS_WIN32_TRUE@harfbuzz_subset_def_dependency = harfbuzz-subset.def
+@OS_WIN32_TRUE@export_symbols_cairo = -export-symbols harfbuzz-cairo.def
+@OS_WIN32_TRUE@harfbuzz_cairo_def_dependency = harfbuzz-cairo.def
 @OS_WIN32_TRUE@export_symbols_icu = -export-symbols harfbuzz-icu.def
 @OS_WIN32_TRUE@harfbuzz_icu_def_dependency = harfbuzz-icu.def
 @OS_WIN32_TRUE@export_symbols_gobject = -export-symbols harfbuzz-gobject.def
@@ -1507,11 +1813,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_39) $(am__append_42)
-nodist_pkginclude_HEADERS = $(am__append_43)
+       $(HB_CAIRO_headers) $(am__append_43) $(am__append_46)
+nodist_pkginclude_HEADERS = $(am__append_47)
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = harfbuzz.pc harfbuzz-subset.pc $(am__append_40) \
-       $(am__append_44)
+pkgconfig_DATA = harfbuzz.pc harfbuzz-subset.pc harfbuzz-cairo.pc \
+       $(am__append_44) $(am__append_48)
 cmakedir = $(libdir)/cmake/harfbuzz
 cmake_DATA = harfbuzz-config.cmake
 libharfbuzz_subset_la_LINK = $(chosen_linker) $(libharfbuzz_subset_la_LDFLAGS)
@@ -1520,6 +1826,14 @@ 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)
+libharfbuzz_cairo_la_LINK = $(chosen_linker) $(libharfbuzz_cairo_la_LDFLAGS)
+libharfbuzz_cairo_la_SOURCES = $(HB_CAIRO_sources)
+libharfbuzz_cairo_la_CPPFLAGS = $(HBCFLAGS) $(CAIRO_CFLAGS) $(CODE_COVERAGE_CFLAGS)
+libharfbuzz_cairo_la_LDFLAGS = $(base_link_flags) $(export_symbols_cairo) $(CODE_COVERAGE_LDFLAGS)
+libharfbuzz_cairo_la_LIBADD = $(CAIRO_LIBS) libharfbuzz.la
+EXTRA_libharfbuzz_cairo_la_DEPENDENCIES = $(harfbuzz_cairo_def_dependency)
+@HAVE_ICU_BUILTIN_FALSE@@HAVE_ICU_TRUE@HB_HAS_ICU_DEF = undef HB_HAS_ICU
+@HAVE_ICU_BUILTIN_TRUE@@HAVE_ICU_TRUE@HB_HAS_ICU_DEF = define HB_HAS_ICU 1
 @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)
@@ -1532,8 +1846,10 @@ EXTRA_libharfbuzz_subset_la_DEPENDENCIES = $(harfbuzz_subset_def_dependency)
 @HAVE_GOBJECT_TRUE@libharfbuzz_gobject_la_LDFLAGS = $(base_link_flags) $(CODE_COVERAGE_LDFLAGS)
 @HAVE_GOBJECT_TRUE@libharfbuzz_gobject_la_LIBADD = $(GOBJECT_LIBS) libharfbuzz.la
 @HAVE_GOBJECT_TRUE@EXTRA_libharfbuzz_gobject_la_DEPENDENCIES = $(harfbuzz_gobject_def_dependency)
+@HAVE_GOBJECT_FALSE@HB_HAS_GOBJECT_DEF = undef HB_HAS_GOBJECT
+@HAVE_GOBJECT_TRUE@HB_HAS_GOBJECT_DEF = define HB_HAS_GOBJECT 1
 DEF_FILES = harfbuzz.def harfbuzz-subset.def harfbuzz-icu.def \
-       harfbuzz-deprecated-symbols.txt $(am__append_47)
+       harfbuzz-deprecated-symbols.txt $(am__append_51)
 GENERATORS = \
        gen-arabic-joining-list.py \
        gen-arabic-table.py \
@@ -1572,9 +1888,15 @@ test_ot_name_LDADD = libharfbuzz.la $(HBLIBS)
 test_ot_glyphname_SOURCES = test-ot-glyphname.cc
 test_ot_glyphname_CPPFLAGS = $(HBCFLAGS)
 test_ot_glyphname_LDADD = libharfbuzz.la $(HBLIBS)
+test_use_table_SOURCES = test-use-table.cc
+test_use_table_CPPFLAGS = $(HBCFLAGS)
+test_use_table_LDADD = libharfbuzz.la $(HBLIBS)
 test_gpos_size_params_SOURCES = test-gpos-size-params.cc
 test_gpos_size_params_CPPFLAGS = $(HBCFLAGS)
 test_gpos_size_params_LDADD = libharfbuzz.la $(HBLIBS)
+test_gsub_get_alternates_SOURCES = test-gsub-get-alternates.cc
+test_gsub_get_alternates_CPPFLAGS = $(HBCFLAGS)
+test_gsub_get_alternates_LDADD = libharfbuzz.la $(HBLIBS)
 test_gsub_would_substitute_SOURCES = test-gsub-would-substitute.cc
 test_gsub_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
 test_gsub_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
@@ -1585,6 +1907,7 @@ COMPILED_TESTS = \
        test-iter \
        test-machinery \
        test-map \
+       test-multimap \
        test-number \
        test-ot-tag \
        test-priority-queue \
@@ -1593,6 +1916,10 @@ COMPILED_TESTS = \
        test-unicode-ranges \
        test-vector \
        test-repacker \
+       test-classdef-graph \
+       test-instancer-solver \
+       test-tuple-varstore \
+       test-item-varstore \
        $(NULL)
 
 COMPILED_TESTS_CPPFLAGS = $(HBCFLAGS) -DMAIN -UNDEBUG
@@ -1615,6 +1942,9 @@ test_machinery_LDADD = $(COMPILED_TESTS_LDADD)
 test_map_SOURCES = test-map.cc hb-static.cc
 test_map_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
 test_map_LDADD = $(COMPILED_TESTS_LDADD)
+test_multimap_SOURCES = test-multimap.cc hb-static.cc
+test_multimap_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_multimap_LDADD = $(COMPILED_TESTS_LDADD)
 test_number_SOURCES = test-number.cc hb-number.cc
 test_number_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
 test_number_LDADD = $(COMPILED_TESTS_LDADD)
@@ -1624,9 +1954,12 @@ test_ot_tag_LDADD = $(COMPILED_TESTS_LDADD)
 test_priority_queue_SOURCES = test-priority-queue.cc hb-static.cc
 test_priority_queue_CPPFLAGS = $(HBCFLAGS)
 test_priority_queue_LDADD = libharfbuzz.la $(HBLIBS)
-test_repacker_SOURCES = test-repacker.cc hb-static.cc
+test_repacker_SOURCES = test-repacker.cc hb-static.cc graph/gsubgpos-context.cc
 test_repacker_CPPFLAGS = $(HBCFLAGS)
 test_repacker_LDADD = libharfbuzz.la libharfbuzz-subset.la $(HBLIBS)
+test_classdef_graph_SOURCES = graph/test-classdef-graph.cc hb-static.cc graph/gsubgpos-context.cc
+test_classdef_graph_CPPFLAGS = $(HBCFLAGS)
+test_classdef_graph_LDADD = libharfbuzz.la libharfbuzz-subset.la $(HBLIBS)
 test_set_SOURCES = test-set.cc hb-static.cc
 test_set_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
 test_set_LDADD = $(COMPILED_TESTS_LDADD)
@@ -1639,11 +1972,21 @@ test_unicode_ranges_LDADD = $(COMPILED_TESTS_LDADD)
 test_vector_SOURCES = test-vector.cc hb-static.cc
 test_vector_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
 test_vector_LDADD = $(COMPILED_TESTS_LDADD)
+test_instancer_solver_SOURCES = test-subset-instancer-solver.cc hb-subset-instancer-solver.cc hb-static.cc
+test_instancer_solver_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_instancer_solver_LDADD = $(COMPILED_TESTS_LDADD)
+test_tuple_varstore_SOURCES = test-tuple-varstore.cc hb-subset-instancer-solver.cc hb-static.cc
+test_tuple_varstore_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_tuple_varstore_LDADD = $(COMPILED_TESTS_LDADD)
+test_item_varstore_SOURCES = test-item-varstore.cc hb-subset-instancer-solver.cc hb-static.cc
+test_item_varstore_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_item_varstore_LDADD = $(COMPILED_TESTS_LDADD)
 dist_check_SCRIPTS = check-c-linkage-decls.py check-externs.py \
        check-header-guards.py check-includes.py check-static-inits.py \
-       check-symbols.py $(NULL) $(am__append_48)
+       check-symbols.py $(NULL) $(am__append_52)
 TESTS_ENVIRONMENT = \
        srcdir="$(srcdir)" \
+       base_srcdir="$(srcdir)" \
        builddir="$(builddir)" \
        MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
        HBSOURCES="$(HBSOURCES)" \
@@ -1668,7 +2011,7 @@ TESTS_ENVIRONMENT = \
 
 @HAVE_INTROSPECTION_TRUE@INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
 @HAVE_INTROSPECTION_TRUE@INTROSPECTION_SCANNER_ENV = CC="$(CC)"
-@HAVE_INTROSPECTION_TRUE@HarfBuzz_0_0_gir_INCLUDES = GObject-2.0
+@HAVE_INTROSPECTION_TRUE@HarfBuzz_0_0_gir_INCLUDES = GObject-2.0 freetype2-2.0
 @HAVE_INTROSPECTION_TRUE@HarfBuzz_0_0_gir_CFLAGS = \
 @HAVE_INTROSPECTION_TRUE@      $(INCLUDES) \
 @HAVE_INTROSPECTION_TRUE@      $(HBCFLAGS) \
@@ -1849,6 +2192,9 @@ clean-libLTLIBRARIES:
          rm -f $${locs}; \
        }
 
+libharfbuzz-cairo.la: $(libharfbuzz_cairo_la_OBJECTS) $(libharfbuzz_cairo_la_DEPENDENCIES) $(EXTRA_libharfbuzz_cairo_la_DEPENDENCIES) 
+       $(AM_V_GEN)$(libharfbuzz_cairo_la_LINK) -rpath $(libdir) $(libharfbuzz_cairo_la_OBJECTS) $(libharfbuzz_cairo_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)
 
@@ -1885,14 +2231,30 @@ 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-classdef-graph$(EXEEXT): $(test_classdef_graph_OBJECTS) $(test_classdef_graph_DEPENDENCIES) $(EXTRA_test_classdef_graph_DEPENDENCIES) 
+       @rm -f test-classdef-graph$(EXEEXT)
+       $(AM_V_CXXLD)$(CXXLINK) $(test_classdef_graph_OBJECTS) $(test_classdef_graph_LDADD) $(LIBS)
+
 test-gpos-size-params$(EXEEXT): $(test_gpos_size_params_OBJECTS) $(test_gpos_size_params_DEPENDENCIES) $(EXTRA_test_gpos_size_params_DEPENDENCIES) 
        @rm -f test-gpos-size-params$(EXEEXT)
        $(AM_V_CXXLD)$(CXXLINK) $(test_gpos_size_params_OBJECTS) $(test_gpos_size_params_LDADD) $(LIBS)
 
+test-gsub-get-alternates$(EXEEXT): $(test_gsub_get_alternates_OBJECTS) $(test_gsub_get_alternates_DEPENDENCIES) $(EXTRA_test_gsub_get_alternates_DEPENDENCIES) 
+       @rm -f test-gsub-get-alternates$(EXEEXT)
+       $(AM_V_CXXLD)$(CXXLINK) $(test_gsub_get_alternates_OBJECTS) $(test_gsub_get_alternates_LDADD) $(LIBS)
+
 test-gsub-would-substitute$(EXEEXT): $(test_gsub_would_substitute_OBJECTS) $(test_gsub_would_substitute_DEPENDENCIES) $(EXTRA_test_gsub_would_substitute_DEPENDENCIES) 
        @rm -f test-gsub-would-substitute$(EXEEXT)
        $(AM_V_CXXLD)$(CXXLINK) $(test_gsub_would_substitute_OBJECTS) $(test_gsub_would_substitute_LDADD) $(LIBS)
 
+test-instancer-solver$(EXEEXT): $(test_instancer_solver_OBJECTS) $(test_instancer_solver_DEPENDENCIES) $(EXTRA_test_instancer_solver_DEPENDENCIES) 
+       @rm -f test-instancer-solver$(EXEEXT)
+       $(AM_V_CXXLD)$(CXXLINK) $(test_instancer_solver_OBJECTS) $(test_instancer_solver_LDADD) $(LIBS)
+
+test-item-varstore$(EXEEXT): $(test_item_varstore_OBJECTS) $(test_item_varstore_DEPENDENCIES) $(EXTRA_test_item_varstore_DEPENDENCIES) 
+       @rm -f test-item-varstore$(EXEEXT)
+       $(AM_V_CXXLD)$(CXXLINK) $(test_item_varstore_OBJECTS) $(test_item_varstore_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)
@@ -1905,6 +2267,10 @@ test-map$(EXEEXT): $(test_map_OBJECTS) $(test_map_DEPENDENCIES) $(EXTRA_test_map
        @rm -f test-map$(EXEEXT)
        $(AM_V_CXXLD)$(CXXLINK) $(test_map_OBJECTS) $(test_map_LDADD) $(LIBS)
 
+test-multimap$(EXEEXT): $(test_multimap_OBJECTS) $(test_multimap_DEPENDENCIES) $(EXTRA_test_multimap_DEPENDENCIES) 
+       @rm -f test-multimap$(EXEEXT)
+       $(AM_V_CXXLD)$(CXXLINK) $(test_multimap_OBJECTS) $(test_multimap_LDADD) $(LIBS)
+
 test-number$(EXEEXT): $(test_number_OBJECTS) $(test_number_DEPENDENCIES) $(EXTRA_test_number_DEPENDENCIES) 
        @rm -f test-number$(EXEEXT)
        $(AM_V_CXXLD)$(CXXLINK) $(test_number_OBJECTS) $(test_number_LDADD) $(LIBS)
@@ -1941,10 +2307,18 @@ test-set$(EXEEXT): $(test_set_OBJECTS) $(test_set_DEPENDENCIES) $(EXTRA_test_set
        @rm -f test-set$(EXEEXT)
        $(AM_V_CXXLD)$(CXXLINK) $(test_set_OBJECTS) $(test_set_LDADD) $(LIBS)
 
+test-tuple-varstore$(EXEEXT): $(test_tuple_varstore_OBJECTS) $(test_tuple_varstore_DEPENDENCIES) $(EXTRA_test_tuple_varstore_DEPENDENCIES) 
+       @rm -f test-tuple-varstore$(EXEEXT)
+       $(AM_V_CXXLD)$(CXXLINK) $(test_tuple_varstore_OBJECTS) $(test_tuple_varstore_LDADD) $(LIBS)
+
 test-unicode-ranges$(EXEEXT): $(test_unicode_ranges_OBJECTS) $(test_unicode_ranges_DEPENDENCIES) $(EXTRA_test_unicode_ranges_DEPENDENCIES) 
        @rm -f test-unicode-ranges$(EXEEXT)
        $(AM_V_CXXLD)$(CXXLINK) $(test_unicode_ranges_OBJECTS) $(test_unicode_ranges_LDADD) $(LIBS)
 
+test-use-table$(EXEEXT): $(test_use_table_OBJECTS) $(test_use_table_DEPENDENCIES) $(EXTRA_test_use_table_DEPENDENCIES) 
+       @rm -f test-use-table$(EXEEXT)
+       $(AM_V_CXXLD)$(CXXLINK) $(test_use_table_OBJECTS) $(test_use_table_LDADD) $(LIBS)
+
 test-vector$(EXEEXT): $(test_vector_OBJECTS) $(test_vector_DEPENDENCIES) $(EXTRA_test_vector_DEPENDENCIES) 
        @rm -f test-vector$(EXEEXT)
        $(AM_V_CXXLD)$(CXXLINK) $(test_vector_OBJECTS) $(test_vector_LDADD) $(LIBS)
@@ -1955,6 +2329,9 @@ mostlyclean-compile:
 distclean-compile:
        -rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_cairo_la-hb-cairo-utils.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_cairo_la-hb-cairo.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_cairo_la-hb-static.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_gobject_la-hb-gobject-enums.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_gobject_la-hb-gobject-structs.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_icu_la-hb-icu.Plo@am__quote@ # am--include-marker
@@ -1968,6 +2345,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-coretext.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-directwrite.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-draw.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-face-builder.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-face.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-fallback-shape.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-font.Plo@am__quote@ # am--include-marker
@@ -1989,23 +2367,26 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-meta.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-metrics.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-name.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-arabic.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-default.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-hangul.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-hebrew.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-indic-table.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-indic.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-khmer.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-myanmar.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-syllabic.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-thai.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-use.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-vowel-constraints.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-fallback.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-normalize.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shape.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-arabic.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-default.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-hangul.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-hebrew.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-indic-table.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-indic.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-khmer.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-myanmar.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-syllabic.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-thai.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-use.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-vowel-constraints.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-tag.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ot-var.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-outline.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-paint-extents.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-paint.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-set.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-shape-plan.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-shape.Plo@am__quote@ # am--include-marker
@@ -2015,6 +2396,9 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-ucd.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-unicode.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-uniscribe.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-wasm-api.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_la-hb-wasm-shape.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-gsubgpos-context.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-number.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-ot-cff1-table.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-ot-cff2-table.Plo@am__quote@ # am--include-marker
@@ -2023,7 +2407,9 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff1.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff2.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-input.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-instancer-solver.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-plan.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-repacker.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libharfbuzz_subset_la-hb-subset.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main-main.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-test.Po@am__quote@ # am--include-marker
@@ -2033,14 +2419,26 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_bimap-hb-static.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_bimap-test-bimap.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_buffer_serialize-test-buffer-serialize.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_classdef_graph-gsubgpos-context.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_classdef_graph-hb-static.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_classdef_graph-test-classdef-graph.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gpos_size_params-test-gpos-size-params.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gsub_get_alternates-test-gsub-get-alternates.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gsub_would_substitute-test-gsub-would-substitute.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_instancer_solver-hb-static.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_instancer_solver-hb-subset-instancer-solver.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_instancer_solver-test-subset-instancer-solver.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_item_varstore-hb-static.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_item_varstore-hb-subset-instancer-solver.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_item_varstore-test-item-varstore.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_iter-hb-static.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_iter-test-iter.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_machinery-hb-static.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_machinery-test-machinery.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_map-hb-static.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_map-test-map.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_multimap-hb-static.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_multimap-test-multimap.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_number-hb-number.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_number-test-number.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_ot_glyphname-test-ot-glyphname.Po@am__quote@ # am--include-marker
@@ -2049,13 +2447,18 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_ot_tag-hb-ot-tag.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_priority_queue-hb-static.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_priority_queue-test-priority-queue.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_repacker-gsubgpos-context.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_repacker-hb-static.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_repacker-test-repacker.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_serialize-hb-static.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_serialize-test-serialize.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_set-hb-static.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_set-test-set.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_tuple_varstore-hb-static.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_tuple_varstore-hb-subset-instancer-solver.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_tuple_varstore-test-tuple-varstore.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_unicode_ranges-test-unicode-ranges.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_use_table-test-use-table.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_vector-hb-static.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_vector-test-vector.Po@am__quote@ # am--include-marker
 
@@ -2086,6 +2489,27 @@ am--depfiles: $(am__depfiles_remade)
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@     DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
 
+libharfbuzz_cairo_la-hb-cairo.lo: hb-cairo.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_cairo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_cairo_la-hb-cairo.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_cairo_la-hb-cairo.Tpo -c -o libharfbuzz_cairo_la-hb-cairo.lo `test -f 'hb-cairo.cc' || echo '$(srcdir)/'`hb-cairo.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_cairo_la-hb-cairo.Tpo $(DEPDIR)/libharfbuzz_cairo_la-hb-cairo.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-cairo.cc' object='libharfbuzz_cairo_la-hb-cairo.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_cairo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_cairo_la-hb-cairo.lo `test -f 'hb-cairo.cc' || echo '$(srcdir)/'`hb-cairo.cc
+
+libharfbuzz_cairo_la-hb-cairo-utils.lo: hb-cairo-utils.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libharfbuzz_cairo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_cairo_la-hb-cairo-utils.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_cairo_la-hb-cairo-utils.Tpo -c -o libharfbuzz_cairo_la-hb-cairo-utils.lo `test -f 'hb-cairo-utils.cc' || echo '$(srcdir)/'`hb-cairo-utils.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_cairo_la-hb-cairo-utils.Tpo $(DEPDIR)/libharfbuzz_cairo_la-hb-cairo-utils.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-cairo-utils.cc' object='libharfbuzz_cairo_la-hb-cairo-utils.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_cairo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_cairo_la-hb-cairo-utils.lo `test -f 'hb-cairo-utils.cc' || echo '$(srcdir)/'`hb-cairo-utils.cc
+
+libharfbuzz_cairo_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_cairo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_cairo_la-hb-static.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_cairo_la-hb-static.Tpo -c -o libharfbuzz_cairo_la-hb-static.lo `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_cairo_la-hb-static.Tpo $(DEPDIR)/libharfbuzz_cairo_la-hb-static.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-static.cc' object='libharfbuzz_cairo_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_cairo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_cairo_la-hb-static.lo `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.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
@@ -2163,6 +2587,13 @@ libharfbuzz_subset_la-hb-subset-input.lo: hb-subset-input.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-input.lo `test -f 'hb-subset-input.cc' || echo '$(srcdir)/'`hb-subset-input.cc
 
+libharfbuzz_subset_la-hb-subset-instancer-solver.lo: hb-subset-instancer-solver.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-instancer-solver.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_subset_la-hb-subset-instancer-solver.Tpo -c -o libharfbuzz_subset_la-hb-subset-instancer-solver.lo `test -f 'hb-subset-instancer-solver.cc' || echo '$(srcdir)/'`hb-subset-instancer-solver.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_subset_la-hb-subset-instancer-solver.Tpo $(DEPDIR)/libharfbuzz_subset_la-hb-subset-instancer-solver.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-subset-instancer-solver.cc' object='libharfbuzz_subset_la-hb-subset-instancer-solver.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-instancer-solver.lo `test -f 'hb-subset-instancer-solver.cc' || echo '$(srcdir)/'`hb-subset-instancer-solver.cc
+
 libharfbuzz_subset_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_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_subset_la-hb-subset-plan.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_subset_la-hb-subset-plan.Tpo -c -o libharfbuzz_subset_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_la-hb-subset-plan.Tpo $(DEPDIR)/libharfbuzz_subset_la-hb-subset-plan.Plo
@@ -2170,6 +2601,13 @@ 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-repacker.lo: hb-subset-repacker.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-repacker.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_subset_la-hb-subset-repacker.Tpo -c -o libharfbuzz_subset_la-hb-subset-repacker.lo `test -f 'hb-subset-repacker.cc' || echo '$(srcdir)/'`hb-subset-repacker.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_subset_la-hb-subset-repacker.Tpo $(DEPDIR)/libharfbuzz_subset_la-hb-subset-repacker.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-subset-repacker.cc' object='libharfbuzz_subset_la-hb-subset-repacker.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-repacker.lo `test -f 'hb-subset-repacker.cc' || echo '$(srcdir)/'`hb-subset-repacker.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
@@ -2177,6 +2615,13 @@ libharfbuzz_subset_la-hb-subset.lo: hb-subset.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.lo `test -f 'hb-subset.cc' || echo '$(srcdir)/'`hb-subset.cc
 
+libharfbuzz_subset_la-gsubgpos-context.lo: graph/gsubgpos-context.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-gsubgpos-context.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_subset_la-gsubgpos-context.Tpo -c -o libharfbuzz_subset_la-gsubgpos-context.lo `test -f 'graph/gsubgpos-context.cc' || echo '$(srcdir)/'`graph/gsubgpos-context.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_subset_la-gsubgpos-context.Tpo $(DEPDIR)/libharfbuzz_subset_la-gsubgpos-context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='graph/gsubgpos-context.cc' object='libharfbuzz_subset_la-gsubgpos-context.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-gsubgpos-context.lo `test -f 'graph/gsubgpos-context.cc' || echo '$(srcdir)/'`graph/gsubgpos-context.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
@@ -2240,6 +2685,13 @@ libharfbuzz_la-hb-face.lo: hb-face.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-face.lo `test -f 'hb-face.cc' || echo '$(srcdir)/'`hb-face.cc
 
+libharfbuzz_la-hb-face-builder.lo: hb-face-builder.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-face-builder.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-face-builder.Tpo -c -o libharfbuzz_la-hb-face-builder.lo `test -f 'hb-face-builder.cc' || echo '$(srcdir)/'`hb-face-builder.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-face-builder.Tpo $(DEPDIR)/libharfbuzz_la-hb-face-builder.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-face-builder.cc' object='libharfbuzz_la-hb-face-builder.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-face-builder.lo `test -f 'hb-face-builder.cc' || echo '$(srcdir)/'`hb-face-builder.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
@@ -2303,6 +2755,27 @@ libharfbuzz_la-hb-ot-font.lo: hb-ot-font.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-font.lo `test -f 'hb-ot-font.cc' || echo '$(srcdir)/'`hb-ot-font.cc
 
+libharfbuzz_la-hb-outline.lo: hb-outline.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-outline.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-outline.Tpo -c -o libharfbuzz_la-hb-outline.lo `test -f 'hb-outline.cc' || echo '$(srcdir)/'`hb-outline.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-outline.Tpo $(DEPDIR)/libharfbuzz_la-hb-outline.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-outline.cc' object='libharfbuzz_la-hb-outline.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-outline.lo `test -f 'hb-outline.cc' || echo '$(srcdir)/'`hb-outline.cc
+
+libharfbuzz_la-hb-paint.lo: hb-paint.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-paint.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-paint.Tpo -c -o libharfbuzz_la-hb-paint.lo `test -f 'hb-paint.cc' || echo '$(srcdir)/'`hb-paint.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-paint.Tpo $(DEPDIR)/libharfbuzz_la-hb-paint.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-paint.cc' object='libharfbuzz_la-hb-paint.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-paint.lo `test -f 'hb-paint.cc' || echo '$(srcdir)/'`hb-paint.cc
+
+libharfbuzz_la-hb-paint-extents.lo: hb-paint-extents.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-paint-extents.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-paint-extents.Tpo -c -o libharfbuzz_la-hb-paint-extents.lo `test -f 'hb-paint-extents.cc' || echo '$(srcdir)/'`hb-paint-extents.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-paint-extents.Tpo $(DEPDIR)/libharfbuzz_la-hb-paint-extents.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-paint-extents.cc' object='libharfbuzz_la-hb-paint-extents.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-paint-extents.lo `test -f 'hb-paint-extents.cc' || echo '$(srcdir)/'`hb-paint-extents.cc
+
 libharfbuzz_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_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-layout.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-layout.Tpo -c -o libharfbuzz_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_la-hb-ot-layout.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-layout.Plo
@@ -2345,89 +2818,89 @@ libharfbuzz_la-hb-ot-name.lo: hb-ot-name.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-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
-@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-arabic.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-arabic.Plo
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shape-complex-arabic.cc' object='libharfbuzz_la-hb-ot-shape-complex-arabic.lo' libtool=yes @AMDEPBACKSLASH@
+libharfbuzz_la-hb-ot-shaper-arabic.lo: hb-ot-shaper-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-shaper-arabic.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-arabic.Tpo -c -o libharfbuzz_la-hb-ot-shaper-arabic.lo `test -f 'hb-ot-shaper-arabic.cc' || echo '$(srcdir)/'`hb-ot-shaper-arabic.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-arabic.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-arabic.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shaper-arabic.cc' object='libharfbuzz_la-hb-ot-shaper-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_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -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
+@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-shaper-arabic.lo `test -f 'hb-ot-shaper-arabic.cc' || echo '$(srcdir)/'`hb-ot-shaper-arabic.cc
 
-libharfbuzz_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_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape-complex-default.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-default.Tpo -c -o libharfbuzz_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_la-hb-ot-shape-complex-default.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-default.Plo
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shape-complex-default.cc' object='libharfbuzz_la-hb-ot-shape-complex-default.lo' libtool=yes @AMDEPBACKSLASH@
+libharfbuzz_la-hb-ot-shaper-default.lo: hb-ot-shaper-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_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shaper-default.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-default.Tpo -c -o libharfbuzz_la-hb-ot-shaper-default.lo `test -f 'hb-ot-shaper-default.cc' || echo '$(srcdir)/'`hb-ot-shaper-default.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-default.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-default.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shaper-default.cc' object='libharfbuzz_la-hb-ot-shaper-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_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_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_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-shaper-default.lo `test -f 'hb-ot-shaper-default.cc' || echo '$(srcdir)/'`hb-ot-shaper-default.cc
 
-libharfbuzz_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_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape-complex-hangul.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-hangul.Tpo -c -o libharfbuzz_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_la-hb-ot-shape-complex-hangul.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-hangul.Plo
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shape-complex-hangul.cc' object='libharfbuzz_la-hb-ot-shape-complex-hangul.lo' libtool=yes @AMDEPBACKSLASH@
+libharfbuzz_la-hb-ot-shaper-hangul.lo: hb-ot-shaper-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_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shaper-hangul.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-hangul.Tpo -c -o libharfbuzz_la-hb-ot-shaper-hangul.lo `test -f 'hb-ot-shaper-hangul.cc' || echo '$(srcdir)/'`hb-ot-shaper-hangul.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-hangul.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-hangul.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shaper-hangul.cc' object='libharfbuzz_la-hb-ot-shaper-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_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_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_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-shaper-hangul.lo `test -f 'hb-ot-shaper-hangul.cc' || echo '$(srcdir)/'`hb-ot-shaper-hangul.cc
 
-libharfbuzz_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_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape-complex-hebrew.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-hebrew.Tpo -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
-@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-hebrew.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-hebrew.Plo
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shape-complex-hebrew.cc' object='libharfbuzz_la-hb-ot-shape-complex-hebrew.lo' libtool=yes @AMDEPBACKSLASH@
+libharfbuzz_la-hb-ot-shaper-hebrew.lo: hb-ot-shaper-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_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shaper-hebrew.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-hebrew.Tpo -c -o libharfbuzz_la-hb-ot-shaper-hebrew.lo `test -f 'hb-ot-shaper-hebrew.cc' || echo '$(srcdir)/'`hb-ot-shaper-hebrew.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-hebrew.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-hebrew.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shaper-hebrew.cc' object='libharfbuzz_la-hb-ot-shaper-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_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
+@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-shaper-hebrew.lo `test -f 'hb-ot-shaper-hebrew.cc' || echo '$(srcdir)/'`hb-ot-shaper-hebrew.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
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shape-complex-indic-table.cc' object='libharfbuzz_la-hb-ot-shape-complex-indic-table.lo' libtool=yes @AMDEPBACKSLASH@
+libharfbuzz_la-hb-ot-shaper-indic-table.lo: hb-ot-shaper-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-shaper-indic-table.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-indic-table.Tpo -c -o libharfbuzz_la-hb-ot-shaper-indic-table.lo `test -f 'hb-ot-shaper-indic-table.cc' || echo '$(srcdir)/'`hb-ot-shaper-indic-table.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-indic-table.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-indic-table.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shaper-indic-table.cc' object='libharfbuzz_la-hb-ot-shaper-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_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
+@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-shaper-indic-table.lo `test -f 'hb-ot-shaper-indic-table.cc' || echo '$(srcdir)/'`hb-ot-shaper-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@
+libharfbuzz_la-hb-ot-shaper-indic.lo: hb-ot-shaper-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-shaper-indic.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-indic.Tpo -c -o libharfbuzz_la-hb-ot-shaper-indic.lo `test -f 'hb-ot-shaper-indic.cc' || echo '$(srcdir)/'`hb-ot-shaper-indic.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-indic.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-indic.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shaper-indic.cc' object='libharfbuzz_la-hb-ot-shaper-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
+@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-shaper-indic.lo `test -f 'hb-ot-shaper-indic.cc' || echo '$(srcdir)/'`hb-ot-shaper-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
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shape-complex-khmer.cc' object='libharfbuzz_la-hb-ot-shape-complex-khmer.lo' libtool=yes @AMDEPBACKSLASH@
+libharfbuzz_la-hb-ot-shaper-khmer.lo: hb-ot-shaper-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-shaper-khmer.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-khmer.Tpo -c -o libharfbuzz_la-hb-ot-shaper-khmer.lo `test -f 'hb-ot-shaper-khmer.cc' || echo '$(srcdir)/'`hb-ot-shaper-khmer.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-khmer.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-khmer.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shaper-khmer.cc' object='libharfbuzz_la-hb-ot-shaper-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_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -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_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-shaper-khmer.lo `test -f 'hb-ot-shaper-khmer.cc' || echo '$(srcdir)/'`hb-ot-shaper-khmer.cc
 
-libharfbuzz_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_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape-complex-myanmar.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-myanmar.Tpo -c -o libharfbuzz_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_la-hb-ot-shape-complex-myanmar.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-myanmar.Plo
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shape-complex-myanmar.cc' object='libharfbuzz_la-hb-ot-shape-complex-myanmar.lo' libtool=yes @AMDEPBACKSLASH@
+libharfbuzz_la-hb-ot-shaper-myanmar.lo: hb-ot-shaper-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_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shaper-myanmar.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-myanmar.Tpo -c -o libharfbuzz_la-hb-ot-shaper-myanmar.lo `test -f 'hb-ot-shaper-myanmar.cc' || echo '$(srcdir)/'`hb-ot-shaper-myanmar.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-myanmar.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-myanmar.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shaper-myanmar.cc' object='libharfbuzz_la-hb-ot-shaper-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_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libharfbuzz_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_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-shaper-myanmar.lo `test -f 'hb-ot-shaper-myanmar.cc' || echo '$(srcdir)/'`hb-ot-shaper-myanmar.cc
 
-libharfbuzz_la-hb-ot-shape-complex-syllabic.lo: hb-ot-shape-complex-syllabic.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-syllabic.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-syllabic.Tpo -c -o libharfbuzz_la-hb-ot-shape-complex-syllabic.lo `test -f 'hb-ot-shape-complex-syllabic.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-syllabic.cc
-@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-syllabic.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-syllabic.Plo
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shape-complex-syllabic.cc' object='libharfbuzz_la-hb-ot-shape-complex-syllabic.lo' libtool=yes @AMDEPBACKSLASH@
+libharfbuzz_la-hb-ot-shaper-syllabic.lo: hb-ot-shaper-syllabic.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-shaper-syllabic.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-syllabic.Tpo -c -o libharfbuzz_la-hb-ot-shaper-syllabic.lo `test -f 'hb-ot-shaper-syllabic.cc' || echo '$(srcdir)/'`hb-ot-shaper-syllabic.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-syllabic.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-syllabic.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shaper-syllabic.cc' object='libharfbuzz_la-hb-ot-shaper-syllabic.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-syllabic.lo `test -f 'hb-ot-shape-complex-syllabic.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-syllabic.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-shaper-syllabic.lo `test -f 'hb-ot-shaper-syllabic.cc' || echo '$(srcdir)/'`hb-ot-shaper-syllabic.cc
 
-libharfbuzz_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_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shape-complex-thai.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-thai.Tpo -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
-@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-thai.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-thai.Plo
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shape-complex-thai.cc' object='libharfbuzz_la-hb-ot-shape-complex-thai.lo' libtool=yes @AMDEPBACKSLASH@
+libharfbuzz_la-hb-ot-shaper-thai.lo: hb-ot-shaper-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_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-ot-shaper-thai.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-thai.Tpo -c -o libharfbuzz_la-hb-ot-shaper-thai.lo `test -f 'hb-ot-shaper-thai.cc' || echo '$(srcdir)/'`hb-ot-shaper-thai.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-thai.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-thai.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shaper-thai.cc' object='libharfbuzz_la-hb-ot-shaper-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_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
+@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-shaper-thai.lo `test -f 'hb-ot-shaper-thai.cc' || echo '$(srcdir)/'`hb-ot-shaper-thai.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
-@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-use.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-use.Plo
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shape-complex-use.cc' object='libharfbuzz_la-hb-ot-shape-complex-use.lo' libtool=yes @AMDEPBACKSLASH@
+libharfbuzz_la-hb-ot-shaper-use.lo: hb-ot-shaper-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-shaper-use.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-use.Tpo -c -o libharfbuzz_la-hb-ot-shaper-use.lo `test -f 'hb-ot-shaper-use.cc' || echo '$(srcdir)/'`hb-ot-shaper-use.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-use.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-use.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shaper-use.cc' object='libharfbuzz_la-hb-ot-shaper-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_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
+@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-shaper-use.lo `test -f 'hb-ot-shaper-use.cc' || echo '$(srcdir)/'`hb-ot-shaper-use.cc
 
-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@
+libharfbuzz_la-hb-ot-shaper-vowel-constraints.lo: hb-ot-shaper-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-shaper-vowel-constraints.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-vowel-constraints.Tpo -c -o libharfbuzz_la-hb-ot-shaper-vowel-constraints.lo `test -f 'hb-ot-shaper-vowel-constraints.cc' || echo '$(srcdir)/'`hb-ot-shaper-vowel-constraints.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-vowel-constraints.Tpo $(DEPDIR)/libharfbuzz_la-hb-ot-shaper-vowel-constraints.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-ot-shaper-vowel-constraints.cc' object='libharfbuzz_la-hb-ot-shaper-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-vowel-constraints.lo `test -f 'hb-ot-shape-complex-vowel-constraints.cc' || echo '$(srcdir)/'`hb-ot-shape-complex-vowel-constraints.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-shaper-vowel-constraints.lo `test -f 'hb-ot-shaper-vowel-constraints.cc' || echo '$(srcdir)/'`hb-ot-shaper-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
@@ -2569,6 +3042,20 @@ libharfbuzz_la-hb-coretext.lo: hb-coretext.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-coretext.lo `test -f 'hb-coretext.cc' || echo '$(srcdir)/'`hb-coretext.cc
 
+libharfbuzz_la-hb-wasm-api.lo: hb-wasm-api.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-wasm-api.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-wasm-api.Tpo -c -o libharfbuzz_la-hb-wasm-api.lo `test -f 'hb-wasm-api.cc' || echo '$(srcdir)/'`hb-wasm-api.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-wasm-api.Tpo $(DEPDIR)/libharfbuzz_la-hb-wasm-api.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-wasm-api.cc' object='libharfbuzz_la-hb-wasm-api.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-wasm-api.lo `test -f 'hb-wasm-api.cc' || echo '$(srcdir)/'`hb-wasm-api.cc
+
+libharfbuzz_la-hb-wasm-shape.lo: hb-wasm-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-wasm-shape.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-wasm-shape.Tpo -c -o libharfbuzz_la-hb-wasm-shape.lo `test -f 'hb-wasm-shape.cc' || echo '$(srcdir)/'`hb-wasm-shape.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-wasm-shape.Tpo $(DEPDIR)/libharfbuzz_la-hb-wasm-shape.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-wasm-shape.cc' object='libharfbuzz_la-hb-wasm-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-wasm-shape.lo `test -f 'hb-wasm-shape.cc' || echo '$(srcdir)/'`hb-wasm-shape.cc
+
 libharfbuzz_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_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libharfbuzz_la-hb-icu.lo -MD -MP -MF $(DEPDIR)/libharfbuzz_la-hb-icu.Tpo -c -o libharfbuzz_la-hb-icu.lo `test -f 'hb-icu.cc' || echo '$(srcdir)/'`hb-icu.cc
 @am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/libharfbuzz_la-hb-icu.Tpo $(DEPDIR)/libharfbuzz_la-hb-icu.Plo
@@ -2688,6 +3175,48 @@ 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_classdef_graph-test-classdef-graph.o: graph/test-classdef-graph.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_classdef_graph_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_classdef_graph-test-classdef-graph.o -MD -MP -MF $(DEPDIR)/test_classdef_graph-test-classdef-graph.Tpo -c -o test_classdef_graph-test-classdef-graph.o `test -f 'graph/test-classdef-graph.cc' || echo '$(srcdir)/'`graph/test-classdef-graph.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_classdef_graph-test-classdef-graph.Tpo $(DEPDIR)/test_classdef_graph-test-classdef-graph.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='graph/test-classdef-graph.cc' object='test_classdef_graph-test-classdef-graph.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_classdef_graph_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_classdef_graph-test-classdef-graph.o `test -f 'graph/test-classdef-graph.cc' || echo '$(srcdir)/'`graph/test-classdef-graph.cc
+
+test_classdef_graph-test-classdef-graph.obj: graph/test-classdef-graph.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_classdef_graph_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_classdef_graph-test-classdef-graph.obj -MD -MP -MF $(DEPDIR)/test_classdef_graph-test-classdef-graph.Tpo -c -o test_classdef_graph-test-classdef-graph.obj `if test -f 'graph/test-classdef-graph.cc'; then $(CYGPATH_W) 'graph/test-classdef-graph.cc'; else $(CYGPATH_W) '$(srcdir)/graph/test-classdef-graph.cc'; fi`
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_classdef_graph-test-classdef-graph.Tpo $(DEPDIR)/test_classdef_graph-test-classdef-graph.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='graph/test-classdef-graph.cc' object='test_classdef_graph-test-classdef-graph.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_classdef_graph_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_classdef_graph-test-classdef-graph.obj `if test -f 'graph/test-classdef-graph.cc'; then $(CYGPATH_W) 'graph/test-classdef-graph.cc'; else $(CYGPATH_W) '$(srcdir)/graph/test-classdef-graph.cc'; fi`
+
+test_classdef_graph-hb-static.o: hb-static.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_classdef_graph_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_classdef_graph-hb-static.o -MD -MP -MF $(DEPDIR)/test_classdef_graph-hb-static.Tpo -c -o test_classdef_graph-hb-static.o `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_classdef_graph-hb-static.Tpo $(DEPDIR)/test_classdef_graph-hb-static.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-static.cc' object='test_classdef_graph-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_classdef_graph_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_classdef_graph-hb-static.o `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc
+
+test_classdef_graph-hb-static.obj: hb-static.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_classdef_graph_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_classdef_graph-hb-static.obj -MD -MP -MF $(DEPDIR)/test_classdef_graph-hb-static.Tpo -c -o test_classdef_graph-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_classdef_graph-hb-static.Tpo $(DEPDIR)/test_classdef_graph-hb-static.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-static.cc' object='test_classdef_graph-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_classdef_graph_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_classdef_graph-hb-static.obj `if test -f 'hb-static.cc'; then $(CYGPATH_W) 'hb-static.cc'; else $(CYGPATH_W) '$(srcdir)/hb-static.cc'; fi`
+
+test_classdef_graph-gsubgpos-context.o: graph/gsubgpos-context.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_classdef_graph_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_classdef_graph-gsubgpos-context.o -MD -MP -MF $(DEPDIR)/test_classdef_graph-gsubgpos-context.Tpo -c -o test_classdef_graph-gsubgpos-context.o `test -f 'graph/gsubgpos-context.cc' || echo '$(srcdir)/'`graph/gsubgpos-context.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_classdef_graph-gsubgpos-context.Tpo $(DEPDIR)/test_classdef_graph-gsubgpos-context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='graph/gsubgpos-context.cc' object='test_classdef_graph-gsubgpos-context.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_classdef_graph_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_classdef_graph-gsubgpos-context.o `test -f 'graph/gsubgpos-context.cc' || echo '$(srcdir)/'`graph/gsubgpos-context.cc
+
+test_classdef_graph-gsubgpos-context.obj: graph/gsubgpos-context.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_classdef_graph_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_classdef_graph-gsubgpos-context.obj -MD -MP -MF $(DEPDIR)/test_classdef_graph-gsubgpos-context.Tpo -c -o test_classdef_graph-gsubgpos-context.obj `if test -f 'graph/gsubgpos-context.cc'; then $(CYGPATH_W) 'graph/gsubgpos-context.cc'; else $(CYGPATH_W) '$(srcdir)/graph/gsubgpos-context.cc'; fi`
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_classdef_graph-gsubgpos-context.Tpo $(DEPDIR)/test_classdef_graph-gsubgpos-context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='graph/gsubgpos-context.cc' object='test_classdef_graph-gsubgpos-context.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_classdef_graph_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_classdef_graph-gsubgpos-context.obj `if test -f 'graph/gsubgpos-context.cc'; then $(CYGPATH_W) 'graph/gsubgpos-context.cc'; else $(CYGPATH_W) '$(srcdir)/graph/gsubgpos-context.cc'; fi`
+
 test_gpos_size_params-test-gpos-size-params.o: test-gpos-size-params.cc
 @am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_gpos_size_params_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_gpos_size_params-test-gpos-size-params.o -MD -MP -MF $(DEPDIR)/test_gpos_size_params-test-gpos-size-params.Tpo -c -o test_gpos_size_params-test-gpos-size-params.o `test -f 'test-gpos-size-params.cc' || echo '$(srcdir)/'`test-gpos-size-params.cc
 @am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_gpos_size_params-test-gpos-size-params.Tpo $(DEPDIR)/test_gpos_size_params-test-gpos-size-params.Po
@@ -2702,6 +3231,20 @@ test_gpos_size_params-test-gpos-size-params.obj: test-gpos-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_gpos_size_params_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_gpos_size_params-test-gpos-size-params.obj `if test -f 'test-gpos-size-params.cc'; then $(CYGPATH_W) 'test-gpos-size-params.cc'; else $(CYGPATH_W) '$(srcdir)/test-gpos-size-params.cc'; fi`
 
+test_gsub_get_alternates-test-gsub-get-alternates.o: test-gsub-get-alternates.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_gsub_get_alternates_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_gsub_get_alternates-test-gsub-get-alternates.o -MD -MP -MF $(DEPDIR)/test_gsub_get_alternates-test-gsub-get-alternates.Tpo -c -o test_gsub_get_alternates-test-gsub-get-alternates.o `test -f 'test-gsub-get-alternates.cc' || echo '$(srcdir)/'`test-gsub-get-alternates.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_gsub_get_alternates-test-gsub-get-alternates.Tpo $(DEPDIR)/test_gsub_get_alternates-test-gsub-get-alternates.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='test-gsub-get-alternates.cc' object='test_gsub_get_alternates-test-gsub-get-alternates.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_gsub_get_alternates_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_gsub_get_alternates-test-gsub-get-alternates.o `test -f 'test-gsub-get-alternates.cc' || echo '$(srcdir)/'`test-gsub-get-alternates.cc
+
+test_gsub_get_alternates-test-gsub-get-alternates.obj: test-gsub-get-alternates.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_gsub_get_alternates_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_gsub_get_alternates-test-gsub-get-alternates.obj -MD -MP -MF $(DEPDIR)/test_gsub_get_alternates-test-gsub-get-alternates.Tpo -c -o test_gsub_get_alternates-test-gsub-get-alternates.obj `if test -f 'test-gsub-get-alternates.cc'; then $(CYGPATH_W) 'test-gsub-get-alternates.cc'; else $(CYGPATH_W) '$(srcdir)/test-gsub-get-alternates.cc'; fi`
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_gsub_get_alternates-test-gsub-get-alternates.Tpo $(DEPDIR)/test_gsub_get_alternates-test-gsub-get-alternates.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='test-gsub-get-alternates.cc' object='test_gsub_get_alternates-test-gsub-get-alternates.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_gsub_get_alternates_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_gsub_get_alternates-test-gsub-get-alternates.obj `if test -f 'test-gsub-get-alternates.cc'; then $(CYGPATH_W) 'test-gsub-get-alternates.cc'; else $(CYGPATH_W) '$(srcdir)/test-gsub-get-alternates.cc'; fi`
+
 test_gsub_would_substitute-test-gsub-would-substitute.o: test-gsub-would-substitute.cc
 @am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_gsub_would_substitute_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_gsub_would_substitute-test-gsub-would-substitute.o -MD -MP -MF $(DEPDIR)/test_gsub_would_substitute-test-gsub-would-substitute.Tpo -c -o test_gsub_would_substitute-test-gsub-would-substitute.o `test -f 'test-gsub-would-substitute.cc' || echo '$(srcdir)/'`test-gsub-would-substitute.cc
 @am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_gsub_would_substitute-test-gsub-would-substitute.Tpo $(DEPDIR)/test_gsub_would_substitute-test-gsub-would-substitute.Po
@@ -2716,6 +3259,90 @@ test_gsub_would_substitute-test-gsub-would-substitute.obj: test-gsub-would-subst
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@     DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_gsub_would_substitute_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_gsub_would_substitute-test-gsub-would-substitute.obj `if test -f 'test-gsub-would-substitute.cc'; then $(CYGPATH_W) 'test-gsub-would-substitute.cc'; else $(CYGPATH_W) '$(srcdir)/test-gsub-would-substitute.cc'; fi`
 
+test_instancer_solver-test-subset-instancer-solver.o: test-subset-instancer-solver.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_instancer_solver_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_instancer_solver-test-subset-instancer-solver.o -MD -MP -MF $(DEPDIR)/test_instancer_solver-test-subset-instancer-solver.Tpo -c -o test_instancer_solver-test-subset-instancer-solver.o `test -f 'test-subset-instancer-solver.cc' || echo '$(srcdir)/'`test-subset-instancer-solver.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_instancer_solver-test-subset-instancer-solver.Tpo $(DEPDIR)/test_instancer_solver-test-subset-instancer-solver.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='test-subset-instancer-solver.cc' object='test_instancer_solver-test-subset-instancer-solver.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_instancer_solver_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_instancer_solver-test-subset-instancer-solver.o `test -f 'test-subset-instancer-solver.cc' || echo '$(srcdir)/'`test-subset-instancer-solver.cc
+
+test_instancer_solver-test-subset-instancer-solver.obj: test-subset-instancer-solver.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_instancer_solver_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_instancer_solver-test-subset-instancer-solver.obj -MD -MP -MF $(DEPDIR)/test_instancer_solver-test-subset-instancer-solver.Tpo -c -o test_instancer_solver-test-subset-instancer-solver.obj `if test -f 'test-subset-instancer-solver.cc'; then $(CYGPATH_W) 'test-subset-instancer-solver.cc'; else $(CYGPATH_W) '$(srcdir)/test-subset-instancer-solver.cc'; fi`
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_instancer_solver-test-subset-instancer-solver.Tpo $(DEPDIR)/test_instancer_solver-test-subset-instancer-solver.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='test-subset-instancer-solver.cc' object='test_instancer_solver-test-subset-instancer-solver.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_instancer_solver_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_instancer_solver-test-subset-instancer-solver.obj `if test -f 'test-subset-instancer-solver.cc'; then $(CYGPATH_W) 'test-subset-instancer-solver.cc'; else $(CYGPATH_W) '$(srcdir)/test-subset-instancer-solver.cc'; fi`
+
+test_instancer_solver-hb-subset-instancer-solver.o: hb-subset-instancer-solver.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_instancer_solver_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_instancer_solver-hb-subset-instancer-solver.o -MD -MP -MF $(DEPDIR)/test_instancer_solver-hb-subset-instancer-solver.Tpo -c -o test_instancer_solver-hb-subset-instancer-solver.o `test -f 'hb-subset-instancer-solver.cc' || echo '$(srcdir)/'`hb-subset-instancer-solver.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_instancer_solver-hb-subset-instancer-solver.Tpo $(DEPDIR)/test_instancer_solver-hb-subset-instancer-solver.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-subset-instancer-solver.cc' object='test_instancer_solver-hb-subset-instancer-solver.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_instancer_solver_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_instancer_solver-hb-subset-instancer-solver.o `test -f 'hb-subset-instancer-solver.cc' || echo '$(srcdir)/'`hb-subset-instancer-solver.cc
+
+test_instancer_solver-hb-subset-instancer-solver.obj: hb-subset-instancer-solver.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_instancer_solver_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_instancer_solver-hb-subset-instancer-solver.obj -MD -MP -MF $(DEPDIR)/test_instancer_solver-hb-subset-instancer-solver.Tpo -c -o test_instancer_solver-hb-subset-instancer-solver.obj `if test -f 'hb-subset-instancer-solver.cc'; then $(CYGPATH_W) 'hb-subset-instancer-solver.cc'; else $(CYGPATH_W) '$(srcdir)/hb-subset-instancer-solver.cc'; fi`
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_instancer_solver-hb-subset-instancer-solver.Tpo $(DEPDIR)/test_instancer_solver-hb-subset-instancer-solver.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-subset-instancer-solver.cc' object='test_instancer_solver-hb-subset-instancer-solver.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_instancer_solver_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_instancer_solver-hb-subset-instancer-solver.obj `if test -f 'hb-subset-instancer-solver.cc'; then $(CYGPATH_W) 'hb-subset-instancer-solver.cc'; else $(CYGPATH_W) '$(srcdir)/hb-subset-instancer-solver.cc'; fi`
+
+test_instancer_solver-hb-static.o: hb-static.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_instancer_solver_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_instancer_solver-hb-static.o -MD -MP -MF $(DEPDIR)/test_instancer_solver-hb-static.Tpo -c -o test_instancer_solver-hb-static.o `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_instancer_solver-hb-static.Tpo $(DEPDIR)/test_instancer_solver-hb-static.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-static.cc' object='test_instancer_solver-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_instancer_solver_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_instancer_solver-hb-static.o `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc
+
+test_instancer_solver-hb-static.obj: hb-static.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_instancer_solver_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_instancer_solver-hb-static.obj -MD -MP -MF $(DEPDIR)/test_instancer_solver-hb-static.Tpo -c -o test_instancer_solver-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_instancer_solver-hb-static.Tpo $(DEPDIR)/test_instancer_solver-hb-static.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-static.cc' object='test_instancer_solver-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_instancer_solver_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_instancer_solver-hb-static.obj `if test -f 'hb-static.cc'; then $(CYGPATH_W) 'hb-static.cc'; else $(CYGPATH_W) '$(srcdir)/hb-static.cc'; fi`
+
+test_item_varstore-test-item-varstore.o: test-item-varstore.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_item_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_item_varstore-test-item-varstore.o -MD -MP -MF $(DEPDIR)/test_item_varstore-test-item-varstore.Tpo -c -o test_item_varstore-test-item-varstore.o `test -f 'test-item-varstore.cc' || echo '$(srcdir)/'`test-item-varstore.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_item_varstore-test-item-varstore.Tpo $(DEPDIR)/test_item_varstore-test-item-varstore.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='test-item-varstore.cc' object='test_item_varstore-test-item-varstore.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_item_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_item_varstore-test-item-varstore.o `test -f 'test-item-varstore.cc' || echo '$(srcdir)/'`test-item-varstore.cc
+
+test_item_varstore-test-item-varstore.obj: test-item-varstore.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_item_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_item_varstore-test-item-varstore.obj -MD -MP -MF $(DEPDIR)/test_item_varstore-test-item-varstore.Tpo -c -o test_item_varstore-test-item-varstore.obj `if test -f 'test-item-varstore.cc'; then $(CYGPATH_W) 'test-item-varstore.cc'; else $(CYGPATH_W) '$(srcdir)/test-item-varstore.cc'; fi`
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_item_varstore-test-item-varstore.Tpo $(DEPDIR)/test_item_varstore-test-item-varstore.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='test-item-varstore.cc' object='test_item_varstore-test-item-varstore.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_item_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_item_varstore-test-item-varstore.obj `if test -f 'test-item-varstore.cc'; then $(CYGPATH_W) 'test-item-varstore.cc'; else $(CYGPATH_W) '$(srcdir)/test-item-varstore.cc'; fi`
+
+test_item_varstore-hb-subset-instancer-solver.o: hb-subset-instancer-solver.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_item_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_item_varstore-hb-subset-instancer-solver.o -MD -MP -MF $(DEPDIR)/test_item_varstore-hb-subset-instancer-solver.Tpo -c -o test_item_varstore-hb-subset-instancer-solver.o `test -f 'hb-subset-instancer-solver.cc' || echo '$(srcdir)/'`hb-subset-instancer-solver.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_item_varstore-hb-subset-instancer-solver.Tpo $(DEPDIR)/test_item_varstore-hb-subset-instancer-solver.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-subset-instancer-solver.cc' object='test_item_varstore-hb-subset-instancer-solver.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_item_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_item_varstore-hb-subset-instancer-solver.o `test -f 'hb-subset-instancer-solver.cc' || echo '$(srcdir)/'`hb-subset-instancer-solver.cc
+
+test_item_varstore-hb-subset-instancer-solver.obj: hb-subset-instancer-solver.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_item_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_item_varstore-hb-subset-instancer-solver.obj -MD -MP -MF $(DEPDIR)/test_item_varstore-hb-subset-instancer-solver.Tpo -c -o test_item_varstore-hb-subset-instancer-solver.obj `if test -f 'hb-subset-instancer-solver.cc'; then $(CYGPATH_W) 'hb-subset-instancer-solver.cc'; else $(CYGPATH_W) '$(srcdir)/hb-subset-instancer-solver.cc'; fi`
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_item_varstore-hb-subset-instancer-solver.Tpo $(DEPDIR)/test_item_varstore-hb-subset-instancer-solver.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-subset-instancer-solver.cc' object='test_item_varstore-hb-subset-instancer-solver.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_item_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_item_varstore-hb-subset-instancer-solver.obj `if test -f 'hb-subset-instancer-solver.cc'; then $(CYGPATH_W) 'hb-subset-instancer-solver.cc'; else $(CYGPATH_W) '$(srcdir)/hb-subset-instancer-solver.cc'; fi`
+
+test_item_varstore-hb-static.o: hb-static.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_item_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_item_varstore-hb-static.o -MD -MP -MF $(DEPDIR)/test_item_varstore-hb-static.Tpo -c -o test_item_varstore-hb-static.o `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_item_varstore-hb-static.Tpo $(DEPDIR)/test_item_varstore-hb-static.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-static.cc' object='test_item_varstore-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_item_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_item_varstore-hb-static.o `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc
+
+test_item_varstore-hb-static.obj: hb-static.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_item_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_item_varstore-hb-static.obj -MD -MP -MF $(DEPDIR)/test_item_varstore-hb-static.Tpo -c -o test_item_varstore-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_item_varstore-hb-static.Tpo $(DEPDIR)/test_item_varstore-hb-static.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-static.cc' object='test_item_varstore-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_item_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_item_varstore-hb-static.obj `if test -f 'hb-static.cc'; then $(CYGPATH_W) 'hb-static.cc'; else $(CYGPATH_W) '$(srcdir)/hb-static.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
@@ -2800,6 +3427,34 @@ test_map-hb-static.obj: hb-static.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_map_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_map-hb-static.obj `if test -f 'hb-static.cc'; then $(CYGPATH_W) 'hb-static.cc'; else $(CYGPATH_W) '$(srcdir)/hb-static.cc'; fi`
 
+test_multimap-test-multimap.o: test-multimap.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_multimap_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_multimap-test-multimap.o -MD -MP -MF $(DEPDIR)/test_multimap-test-multimap.Tpo -c -o test_multimap-test-multimap.o `test -f 'test-multimap.cc' || echo '$(srcdir)/'`test-multimap.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_multimap-test-multimap.Tpo $(DEPDIR)/test_multimap-test-multimap.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='test-multimap.cc' object='test_multimap-test-multimap.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_multimap_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_multimap-test-multimap.o `test -f 'test-multimap.cc' || echo '$(srcdir)/'`test-multimap.cc
+
+test_multimap-test-multimap.obj: test-multimap.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_multimap_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_multimap-test-multimap.obj -MD -MP -MF $(DEPDIR)/test_multimap-test-multimap.Tpo -c -o test_multimap-test-multimap.obj `if test -f 'test-multimap.cc'; then $(CYGPATH_W) 'test-multimap.cc'; else $(CYGPATH_W) '$(srcdir)/test-multimap.cc'; fi`
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_multimap-test-multimap.Tpo $(DEPDIR)/test_multimap-test-multimap.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='test-multimap.cc' object='test_multimap-test-multimap.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_multimap_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_multimap-test-multimap.obj `if test -f 'test-multimap.cc'; then $(CYGPATH_W) 'test-multimap.cc'; else $(CYGPATH_W) '$(srcdir)/test-multimap.cc'; fi`
+
+test_multimap-hb-static.o: hb-static.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_multimap_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_multimap-hb-static.o -MD -MP -MF $(DEPDIR)/test_multimap-hb-static.Tpo -c -o test_multimap-hb-static.o `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_multimap-hb-static.Tpo $(DEPDIR)/test_multimap-hb-static.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-static.cc' object='test_multimap-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_multimap_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_multimap-hb-static.o `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc
+
+test_multimap-hb-static.obj: hb-static.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_multimap_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_multimap-hb-static.obj -MD -MP -MF $(DEPDIR)/test_multimap-hb-static.Tpo -c -o test_multimap-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_multimap-hb-static.Tpo $(DEPDIR)/test_multimap-hb-static.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-static.cc' object='test_multimap-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_multimap_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_multimap-hb-static.obj `if test -f 'hb-static.cc'; then $(CYGPATH_W) 'hb-static.cc'; else $(CYGPATH_W) '$(srcdir)/hb-static.cc'; fi`
+
 test_number-test-number.o: test-number.cc
 @am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_number_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_number-test-number.o -MD -MP -MF $(DEPDIR)/test_number-test-number.Tpo -c -o test_number-test-number.o `test -f 'test-number.cc' || echo '$(srcdir)/'`test-number.cc
 @am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_number-test-number.Tpo $(DEPDIR)/test_number-test-number.Po
@@ -2940,6 +3595,20 @@ test_repacker-hb-static.obj: hb-static.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_repacker_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_repacker-hb-static.obj `if test -f 'hb-static.cc'; then $(CYGPATH_W) 'hb-static.cc'; else $(CYGPATH_W) '$(srcdir)/hb-static.cc'; fi`
 
+test_repacker-gsubgpos-context.o: graph/gsubgpos-context.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_repacker_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_repacker-gsubgpos-context.o -MD -MP -MF $(DEPDIR)/test_repacker-gsubgpos-context.Tpo -c -o test_repacker-gsubgpos-context.o `test -f 'graph/gsubgpos-context.cc' || echo '$(srcdir)/'`graph/gsubgpos-context.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_repacker-gsubgpos-context.Tpo $(DEPDIR)/test_repacker-gsubgpos-context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='graph/gsubgpos-context.cc' object='test_repacker-gsubgpos-context.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_repacker_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_repacker-gsubgpos-context.o `test -f 'graph/gsubgpos-context.cc' || echo '$(srcdir)/'`graph/gsubgpos-context.cc
+
+test_repacker-gsubgpos-context.obj: graph/gsubgpos-context.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_repacker_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_repacker-gsubgpos-context.obj -MD -MP -MF $(DEPDIR)/test_repacker-gsubgpos-context.Tpo -c -o test_repacker-gsubgpos-context.obj `if test -f 'graph/gsubgpos-context.cc'; then $(CYGPATH_W) 'graph/gsubgpos-context.cc'; else $(CYGPATH_W) '$(srcdir)/graph/gsubgpos-context.cc'; fi`
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_repacker-gsubgpos-context.Tpo $(DEPDIR)/test_repacker-gsubgpos-context.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='graph/gsubgpos-context.cc' object='test_repacker-gsubgpos-context.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_repacker_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_repacker-gsubgpos-context.obj `if test -f 'graph/gsubgpos-context.cc'; then $(CYGPATH_W) 'graph/gsubgpos-context.cc'; else $(CYGPATH_W) '$(srcdir)/graph/gsubgpos-context.cc'; fi`
+
 test_serialize-test-serialize.o: test-serialize.cc
 @am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_serialize_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_serialize-test-serialize.o -MD -MP -MF $(DEPDIR)/test_serialize-test-serialize.Tpo -c -o test_serialize-test-serialize.o `test -f 'test-serialize.cc' || echo '$(srcdir)/'`test-serialize.cc
 @am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_serialize-test-serialize.Tpo $(DEPDIR)/test_serialize-test-serialize.Po
@@ -2996,6 +3665,48 @@ test_set-hb-static.obj: hb-static.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_set_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_set-hb-static.obj `if test -f 'hb-static.cc'; then $(CYGPATH_W) 'hb-static.cc'; else $(CYGPATH_W) '$(srcdir)/hb-static.cc'; fi`
 
+test_tuple_varstore-test-tuple-varstore.o: test-tuple-varstore.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_tuple_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_tuple_varstore-test-tuple-varstore.o -MD -MP -MF $(DEPDIR)/test_tuple_varstore-test-tuple-varstore.Tpo -c -o test_tuple_varstore-test-tuple-varstore.o `test -f 'test-tuple-varstore.cc' || echo '$(srcdir)/'`test-tuple-varstore.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_tuple_varstore-test-tuple-varstore.Tpo $(DEPDIR)/test_tuple_varstore-test-tuple-varstore.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='test-tuple-varstore.cc' object='test_tuple_varstore-test-tuple-varstore.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_tuple_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_tuple_varstore-test-tuple-varstore.o `test -f 'test-tuple-varstore.cc' || echo '$(srcdir)/'`test-tuple-varstore.cc
+
+test_tuple_varstore-test-tuple-varstore.obj: test-tuple-varstore.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_tuple_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_tuple_varstore-test-tuple-varstore.obj -MD -MP -MF $(DEPDIR)/test_tuple_varstore-test-tuple-varstore.Tpo -c -o test_tuple_varstore-test-tuple-varstore.obj `if test -f 'test-tuple-varstore.cc'; then $(CYGPATH_W) 'test-tuple-varstore.cc'; else $(CYGPATH_W) '$(srcdir)/test-tuple-varstore.cc'; fi`
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_tuple_varstore-test-tuple-varstore.Tpo $(DEPDIR)/test_tuple_varstore-test-tuple-varstore.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='test-tuple-varstore.cc' object='test_tuple_varstore-test-tuple-varstore.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_tuple_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_tuple_varstore-test-tuple-varstore.obj `if test -f 'test-tuple-varstore.cc'; then $(CYGPATH_W) 'test-tuple-varstore.cc'; else $(CYGPATH_W) '$(srcdir)/test-tuple-varstore.cc'; fi`
+
+test_tuple_varstore-hb-subset-instancer-solver.o: hb-subset-instancer-solver.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_tuple_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_tuple_varstore-hb-subset-instancer-solver.o -MD -MP -MF $(DEPDIR)/test_tuple_varstore-hb-subset-instancer-solver.Tpo -c -o test_tuple_varstore-hb-subset-instancer-solver.o `test -f 'hb-subset-instancer-solver.cc' || echo '$(srcdir)/'`hb-subset-instancer-solver.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_tuple_varstore-hb-subset-instancer-solver.Tpo $(DEPDIR)/test_tuple_varstore-hb-subset-instancer-solver.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-subset-instancer-solver.cc' object='test_tuple_varstore-hb-subset-instancer-solver.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_tuple_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_tuple_varstore-hb-subset-instancer-solver.o `test -f 'hb-subset-instancer-solver.cc' || echo '$(srcdir)/'`hb-subset-instancer-solver.cc
+
+test_tuple_varstore-hb-subset-instancer-solver.obj: hb-subset-instancer-solver.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_tuple_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_tuple_varstore-hb-subset-instancer-solver.obj -MD -MP -MF $(DEPDIR)/test_tuple_varstore-hb-subset-instancer-solver.Tpo -c -o test_tuple_varstore-hb-subset-instancer-solver.obj `if test -f 'hb-subset-instancer-solver.cc'; then $(CYGPATH_W) 'hb-subset-instancer-solver.cc'; else $(CYGPATH_W) '$(srcdir)/hb-subset-instancer-solver.cc'; fi`
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_tuple_varstore-hb-subset-instancer-solver.Tpo $(DEPDIR)/test_tuple_varstore-hb-subset-instancer-solver.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-subset-instancer-solver.cc' object='test_tuple_varstore-hb-subset-instancer-solver.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_tuple_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_tuple_varstore-hb-subset-instancer-solver.obj `if test -f 'hb-subset-instancer-solver.cc'; then $(CYGPATH_W) 'hb-subset-instancer-solver.cc'; else $(CYGPATH_W) '$(srcdir)/hb-subset-instancer-solver.cc'; fi`
+
+test_tuple_varstore-hb-static.o: hb-static.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_tuple_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_tuple_varstore-hb-static.o -MD -MP -MF $(DEPDIR)/test_tuple_varstore-hb-static.Tpo -c -o test_tuple_varstore-hb-static.o `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_tuple_varstore-hb-static.Tpo $(DEPDIR)/test_tuple_varstore-hb-static.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-static.cc' object='test_tuple_varstore-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_tuple_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_tuple_varstore-hb-static.o `test -f 'hb-static.cc' || echo '$(srcdir)/'`hb-static.cc
+
+test_tuple_varstore-hb-static.obj: hb-static.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_tuple_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_tuple_varstore-hb-static.obj -MD -MP -MF $(DEPDIR)/test_tuple_varstore-hb-static.Tpo -c -o test_tuple_varstore-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_tuple_varstore-hb-static.Tpo $(DEPDIR)/test_tuple_varstore-hb-static.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='hb-static.cc' object='test_tuple_varstore-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_tuple_varstore_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_tuple_varstore-hb-static.obj `if test -f 'hb-static.cc'; then $(CYGPATH_W) 'hb-static.cc'; else $(CYGPATH_W) '$(srcdir)/hb-static.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
@@ -3010,6 +3721,20 @@ test_unicode_ranges-test-unicode-ranges.obj: test-unicode-ranges.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_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_use_table-test-use-table.o: test-use-table.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_use_table_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_use_table-test-use-table.o -MD -MP -MF $(DEPDIR)/test_use_table-test-use-table.Tpo -c -o test_use_table-test-use-table.o `test -f 'test-use-table.cc' || echo '$(srcdir)/'`test-use-table.cc
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_use_table-test-use-table.Tpo $(DEPDIR)/test_use_table-test-use-table.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='test-use-table.cc' object='test_use_table-test-use-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_use_table_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_use_table-test-use-table.o `test -f 'test-use-table.cc' || echo '$(srcdir)/'`test-use-table.cc
+
+test_use_table-test-use-table.obj: test-use-table.cc
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_use_table_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_use_table-test-use-table.obj -MD -MP -MF $(DEPDIR)/test_use_table-test-use-table.Tpo -c -o test_use_table-test-use-table.obj `if test -f 'test-use-table.cc'; then $(CYGPATH_W) 'test-use-table.cc'; else $(CYGPATH_W) '$(srcdir)/test-use-table.cc'; fi`
+@am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_use_table-test-use-table.Tpo $(DEPDIR)/test_use_table-test-use-table.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='test-use-table.cc' object='test_use_table-test-use-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_use_table_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_use_table-test-use-table.obj `if test -f 'test-use-table.cc'; then $(CYGPATH_W) 'test-use-table.cc'; else $(CYGPATH_W) '$(srcdir)/test-use-table.cc'; fi`
+
 test_vector-test-vector.o: test-vector.cc
 @am__fastdepCXX_TRUE@  $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_vector_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_vector-test-vector.o -MD -MP -MF $(DEPDIR)/test_vector-test-vector.Tpo -c -o test_vector-test-vector.o `test -f 'test-vector.cc' || echo '$(srcdir)/'`test-vector.cc
 @am__fastdepCXX_TRUE@  $(AM_V_at)$(am__mv) $(DEPDIR)/test_vector-test-vector.Tpo $(DEPDIR)/test_vector-test-vector.Po
@@ -3452,6 +4177,13 @@ test-map.log: test-map$(EXEEXT)
        --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-multimap.log: test-multimap$(EXEEXT)
+       @p='test-multimap$(EXEEXT)'; \
+       b='test-multimap'; \
+       $(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-number.log: test-number$(EXEEXT)
        @p='test-number$(EXEEXT)'; \
        b='test-number'; \
@@ -3508,6 +4240,34 @@ test-repacker.log: test-repacker$(EXEEXT)
        --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-classdef-graph.log: test-classdef-graph$(EXEEXT)
+       @p='test-classdef-graph$(EXEEXT)'; \
+       b='test-classdef-graph'; \
+       $(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-instancer-solver.log: test-instancer-solver$(EXEEXT)
+       @p='test-instancer-solver$(EXEEXT)'; \
+       b='test-instancer-solver'; \
+       $(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-tuple-varstore.log: test-tuple-varstore$(EXEEXT)
+       @p='test-tuple-varstore$(EXEEXT)'; \
+       b='test-tuple-varstore'; \
+       $(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-item-varstore.log: test-item-varstore$(EXEEXT)
+       @p='test-item-varstore$(EXEEXT)'; \
+       b='test-item-varstore'; \
+       $(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)
 check-c-linkage-decls.py.log: check-c-linkage-decls.py
        @p='check-c-linkage-decls.py'; \
        b='check-c-linkage-decls.py'; \
@@ -3689,7 +4449,10 @@ clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
        mostlyclean-am
 
 distclean: distclean-recursive
-               -rm -f ./$(DEPDIR)/libharfbuzz_gobject_la-hb-gobject-enums.Plo
+               -rm -f ./$(DEPDIR)/libharfbuzz_cairo_la-hb-cairo-utils.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_cairo_la-hb-cairo.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_cairo_la-hb-static.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_gobject_la-hb-gobject-enums.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_gobject_la-hb-gobject-structs.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_icu_la-hb-icu.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-aat-layout.Plo
@@ -3702,6 +4465,7 @@ distclean: distclean-recursive
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-coretext.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-directwrite.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-draw.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-face-builder.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-face.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-fallback-shape.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-font.Plo
@@ -3723,23 +4487,26 @@ distclean: distclean-recursive
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-meta.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-metrics.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-name.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-arabic.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-default.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-hangul.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-hebrew.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-indic-table.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-indic.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-khmer.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-myanmar.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-syllabic.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-thai.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-use.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-vowel-constraints.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-fallback.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-normalize.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-arabic.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-default.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-hangul.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-hebrew.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-indic-table.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-indic.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-khmer.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-myanmar.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-syllabic.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-thai.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-use.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-vowel-constraints.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-tag.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-var.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-outline.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-paint-extents.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-paint.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-set.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-shape-plan.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-shape.Plo
@@ -3749,6 +4516,9 @@ distclean: distclean-recursive
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ucd.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-unicode.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-uniscribe.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-wasm-api.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-wasm-shape.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-gsubgpos-context.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-number.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-ot-cff1-table.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-ot-cff2-table.Plo
@@ -3757,7 +4527,9 @@ distclean: distclean-recursive
        -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff1.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff2.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-input.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-instancer-solver.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-plan.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-repacker.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset.Plo
        -rm -f ./$(DEPDIR)/main-main.Po
        -rm -f ./$(DEPDIR)/test-test.Po
@@ -3767,14 +4539,26 @@ distclean: distclean-recursive
        -rm -f ./$(DEPDIR)/test_bimap-hb-static.Po
        -rm -f ./$(DEPDIR)/test_bimap-test-bimap.Po
        -rm -f ./$(DEPDIR)/test_buffer_serialize-test-buffer-serialize.Po
+       -rm -f ./$(DEPDIR)/test_classdef_graph-gsubgpos-context.Po
+       -rm -f ./$(DEPDIR)/test_classdef_graph-hb-static.Po
+       -rm -f ./$(DEPDIR)/test_classdef_graph-test-classdef-graph.Po
        -rm -f ./$(DEPDIR)/test_gpos_size_params-test-gpos-size-params.Po
+       -rm -f ./$(DEPDIR)/test_gsub_get_alternates-test-gsub-get-alternates.Po
        -rm -f ./$(DEPDIR)/test_gsub_would_substitute-test-gsub-would-substitute.Po
+       -rm -f ./$(DEPDIR)/test_instancer_solver-hb-static.Po
+       -rm -f ./$(DEPDIR)/test_instancer_solver-hb-subset-instancer-solver.Po
+       -rm -f ./$(DEPDIR)/test_instancer_solver-test-subset-instancer-solver.Po
+       -rm -f ./$(DEPDIR)/test_item_varstore-hb-static.Po
+       -rm -f ./$(DEPDIR)/test_item_varstore-hb-subset-instancer-solver.Po
+       -rm -f ./$(DEPDIR)/test_item_varstore-test-item-varstore.Po
        -rm -f ./$(DEPDIR)/test_iter-hb-static.Po
        -rm -f ./$(DEPDIR)/test_iter-test-iter.Po
        -rm -f ./$(DEPDIR)/test_machinery-hb-static.Po
        -rm -f ./$(DEPDIR)/test_machinery-test-machinery.Po
        -rm -f ./$(DEPDIR)/test_map-hb-static.Po
        -rm -f ./$(DEPDIR)/test_map-test-map.Po
+       -rm -f ./$(DEPDIR)/test_multimap-hb-static.Po
+       -rm -f ./$(DEPDIR)/test_multimap-test-multimap.Po
        -rm -f ./$(DEPDIR)/test_number-hb-number.Po
        -rm -f ./$(DEPDIR)/test_number-test-number.Po
        -rm -f ./$(DEPDIR)/test_ot_glyphname-test-ot-glyphname.Po
@@ -3783,13 +4567,18 @@ distclean: distclean-recursive
        -rm -f ./$(DEPDIR)/test_ot_tag-hb-ot-tag.Po
        -rm -f ./$(DEPDIR)/test_priority_queue-hb-static.Po
        -rm -f ./$(DEPDIR)/test_priority_queue-test-priority-queue.Po
+       -rm -f ./$(DEPDIR)/test_repacker-gsubgpos-context.Po
        -rm -f ./$(DEPDIR)/test_repacker-hb-static.Po
        -rm -f ./$(DEPDIR)/test_repacker-test-repacker.Po
        -rm -f ./$(DEPDIR)/test_serialize-hb-static.Po
        -rm -f ./$(DEPDIR)/test_serialize-test-serialize.Po
        -rm -f ./$(DEPDIR)/test_set-hb-static.Po
        -rm -f ./$(DEPDIR)/test_set-test-set.Po
+       -rm -f ./$(DEPDIR)/test_tuple_varstore-hb-static.Po
+       -rm -f ./$(DEPDIR)/test_tuple_varstore-hb-subset-instancer-solver.Po
+       -rm -f ./$(DEPDIR)/test_tuple_varstore-test-tuple-varstore.Po
        -rm -f ./$(DEPDIR)/test_unicode_ranges-test-unicode-ranges.Po
+       -rm -f ./$(DEPDIR)/test_use_table-test-use-table.Po
        -rm -f ./$(DEPDIR)/test_vector-hb-static.Po
        -rm -f ./$(DEPDIR)/test_vector-test-vector.Po
        -rm -f Makefile
@@ -3839,7 +4628,10 @@ install-ps-am:
 installcheck-am: installcheck-binPROGRAMS
 
 maintainer-clean: maintainer-clean-recursive
-               -rm -f ./$(DEPDIR)/libharfbuzz_gobject_la-hb-gobject-enums.Plo
+               -rm -f ./$(DEPDIR)/libharfbuzz_cairo_la-hb-cairo-utils.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_cairo_la-hb-cairo.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_cairo_la-hb-static.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_gobject_la-hb-gobject-enums.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_gobject_la-hb-gobject-structs.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_icu_la-hb-icu.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-aat-layout.Plo
@@ -3852,6 +4644,7 @@ maintainer-clean: maintainer-clean-recursive
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-coretext.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-directwrite.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-draw.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-face-builder.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-face.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-fallback-shape.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-font.Plo
@@ -3873,23 +4666,26 @@ maintainer-clean: maintainer-clean-recursive
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-meta.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-metrics.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-name.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-arabic.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-default.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-hangul.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-hebrew.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-indic-table.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-indic.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-khmer.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-myanmar.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-syllabic.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-thai.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-use.Plo
-       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-complex-vowel-constraints.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-fallback.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape-normalize.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shape.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-arabic.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-default.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-hangul.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-hebrew.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-indic-table.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-indic.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-khmer.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-myanmar.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-syllabic.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-thai.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-use.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-shaper-vowel-constraints.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-tag.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ot-var.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-outline.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-paint-extents.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-paint.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-set.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-shape-plan.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-shape.Plo
@@ -3899,6 +4695,9 @@ maintainer-clean: maintainer-clean-recursive
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-ucd.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-unicode.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-uniscribe.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-wasm-api.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_la-hb-wasm-shape.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-gsubgpos-context.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-number.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-ot-cff1-table.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-ot-cff2-table.Plo
@@ -3907,7 +4706,9 @@ maintainer-clean: maintainer-clean-recursive
        -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff1.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-cff2.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-input.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-instancer-solver.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-plan.Plo
+       -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset-repacker.Plo
        -rm -f ./$(DEPDIR)/libharfbuzz_subset_la-hb-subset.Plo
        -rm -f ./$(DEPDIR)/main-main.Po
        -rm -f ./$(DEPDIR)/test-test.Po
@@ -3917,14 +4718,26 @@ maintainer-clean: maintainer-clean-recursive
        -rm -f ./$(DEPDIR)/test_bimap-hb-static.Po
        -rm -f ./$(DEPDIR)/test_bimap-test-bimap.Po
        -rm -f ./$(DEPDIR)/test_buffer_serialize-test-buffer-serialize.Po
+       -rm -f ./$(DEPDIR)/test_classdef_graph-gsubgpos-context.Po
+       -rm -f ./$(DEPDIR)/test_classdef_graph-hb-static.Po
+       -rm -f ./$(DEPDIR)/test_classdef_graph-test-classdef-graph.Po
        -rm -f ./$(DEPDIR)/test_gpos_size_params-test-gpos-size-params.Po
+       -rm -f ./$(DEPDIR)/test_gsub_get_alternates-test-gsub-get-alternates.Po
        -rm -f ./$(DEPDIR)/test_gsub_would_substitute-test-gsub-would-substitute.Po
+       -rm -f ./$(DEPDIR)/test_instancer_solver-hb-static.Po
+       -rm -f ./$(DEPDIR)/test_instancer_solver-hb-subset-instancer-solver.Po
+       -rm -f ./$(DEPDIR)/test_instancer_solver-test-subset-instancer-solver.Po
+       -rm -f ./$(DEPDIR)/test_item_varstore-hb-static.Po
+       -rm -f ./$(DEPDIR)/test_item_varstore-hb-subset-instancer-solver.Po
+       -rm -f ./$(DEPDIR)/test_item_varstore-test-item-varstore.Po
        -rm -f ./$(DEPDIR)/test_iter-hb-static.Po
        -rm -f ./$(DEPDIR)/test_iter-test-iter.Po
        -rm -f ./$(DEPDIR)/test_machinery-hb-static.Po
        -rm -f ./$(DEPDIR)/test_machinery-test-machinery.Po
        -rm -f ./$(DEPDIR)/test_map-hb-static.Po
        -rm -f ./$(DEPDIR)/test_map-test-map.Po
+       -rm -f ./$(DEPDIR)/test_multimap-hb-static.Po
+       -rm -f ./$(DEPDIR)/test_multimap-test-multimap.Po
        -rm -f ./$(DEPDIR)/test_number-hb-number.Po
        -rm -f ./$(DEPDIR)/test_number-test-number.Po
        -rm -f ./$(DEPDIR)/test_ot_glyphname-test-ot-glyphname.Po
@@ -3933,13 +4746,18 @@ maintainer-clean: maintainer-clean-recursive
        -rm -f ./$(DEPDIR)/test_ot_tag-hb-ot-tag.Po
        -rm -f ./$(DEPDIR)/test_priority_queue-hb-static.Po
        -rm -f ./$(DEPDIR)/test_priority_queue-test-priority-queue.Po
+       -rm -f ./$(DEPDIR)/test_repacker-gsubgpos-context.Po
        -rm -f ./$(DEPDIR)/test_repacker-hb-static.Po
        -rm -f ./$(DEPDIR)/test_repacker-test-repacker.Po
        -rm -f ./$(DEPDIR)/test_serialize-hb-static.Po
        -rm -f ./$(DEPDIR)/test_serialize-test-serialize.Po
        -rm -f ./$(DEPDIR)/test_set-hb-static.Po
        -rm -f ./$(DEPDIR)/test_set-test-set.Po
+       -rm -f ./$(DEPDIR)/test_tuple_varstore-hb-static.Po
+       -rm -f ./$(DEPDIR)/test_tuple_varstore-hb-subset-instancer-solver.Po
+       -rm -f ./$(DEPDIR)/test_tuple_varstore-test-tuple-varstore.Po
        -rm -f ./$(DEPDIR)/test_unicode_ranges-test-unicode-ranges.Po
+       -rm -f ./$(DEPDIR)/test_use_table-test-use-table.Po
        -rm -f ./$(DEPDIR)/test_vector-hb-static.Po
        -rm -f ./$(DEPDIR)/test_vector-test-vector.Po
        -rm -f Makefile
@@ -4010,6 +4828,17 @@ $(srcdir)/hb-version.h: hb-version.h.in $(top_srcdir)/configure.ac
                "$<" > "$@" || ($(RM) "$@"; false)
 
 @CODE_COVERAGE_RULES@
+
+harfbuzz-subset.cc: Makefile.sources
+       $(AM_V_GEN) \
+       LANG=C; \
+       for f in \
+               $(HB_BASE_sources) \
+               $(HB_SUBSET_sources) \
+               ; do echo '#include "'$$f'"'; done | \
+       sort -u | \
+       grep '[.]cc"' > $(srcdir)/harfbuzz-subset.cc \
+       || ($(RM) $(srcdir)/harfbuzz-subset.cc; false)
 @HAVE_GOBJECT_TRUE@hb-gobject-enums.%: hb-gobject-enums.%.tmpl $(HBHEADERS)
 @HAVE_GOBJECT_TRUE@    $(AM_V_GEN) PYTHONIOENCODING=UTF-8 $(GLIB_MKENUMS) \
 @HAVE_GOBJECT_TRUE@            --identifier-prefix hb_ --symbol-prefix hb_gobject \
@@ -4017,6 +4846,22 @@ $(srcdir)/hb-version.h: hb-version.h.in $(top_srcdir)/configure.ac
 @HAVE_GOBJECT_TRUE@    sed 's/_t_get_type/_get_type/g; s/_T (/ (/g' > "$@" \
 @HAVE_GOBJECT_TRUE@    || ($(RM) "$@"; false)
 
+hb-features.h: hb-features.h.in $(top_builddir)/config.status
+       $(AM_V_GEN) $(SED) \
+               -e 's/mesondefine HB_HAS_CAIRO/$(HB_HAS_CAIRO_DEF)/' \
+               -e 's/mesondefine HB_HAS_CORETEXT/$(HB_HAS_CORETEXT_DEF)/' \
+               -e 's/mesondefine HB_HAS_DIRECTWRITE/$(HB_HAS_DIRECTWRITE_DEF)/' \
+               -e 's/mesondefine HB_HAS_FREETYPE/$(HB_HAS_FREETYPE_DEF)/' \
+               -e 's/mesondefine HB_HAS_GDI/$(HB_HAS_GDI_DEF)/' \
+               -e 's/mesondefine HB_HAS_GDI/$(HB_HAS_GDI_DEF)/' \
+               -e 's/mesondefine HB_HAS_GLIB/$(HB_HAS_GLIB_DEF)/' \
+               -e 's/mesondefine HB_HAS_GOBJECT/$(HB_HAS_GOBJECT_DEF)/' \
+               -e 's/mesondefine HB_HAS_GRAPHITE/$(HB_HAS_GRAPHITE_DEF)/' \
+               -e 's/mesondefine HB_HAS_ICU/$(HB_HAS_ICU_DEF)/' \
+               -e 's/mesondefine HB_HAS_UNISCRIBE/$(HB_HAS_UNISCRIBE_DEF)/' \
+               -e 's/mesondefine HB_HAS_WASM/$(HB_HAS_WASM_DEF)/' \
+               "$<" > "$@" || ($(RM) "$@"; false)
+
 %.pc: %.pc.in $(top_builddir)/config.status
        $(AM_V_GEN) \
        $(SED)  -e 's@%prefix%@$(prefix)@g' \
@@ -4034,6 +4879,8 @@ harfbuzz.def: $(HBHEADERS)
        $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
 harfbuzz-subset.def: $(HB_SUBSET_headers)
        $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
+harfbuzz-cairo.def: $(HB_CAIRO_headers)
+       $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
 harfbuzz-icu.def: $(HB_ICU_headers)
        $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
 harfbuzz-gobject.def: $(HB_GOBJECT_headers)
@@ -4052,6 +4899,7 @@ $(srcdir)/%.hh: $(srcdir)/%.rl
 
 harfbuzz.cc: Makefile.sources
        $(AM_V_GEN) \
+       LANG=C; \
        for f in \
                $(HB_BASE_sources) \
                $(HB_GLIB_sources) \
@@ -4062,6 +4910,7 @@ harfbuzz.cc: Makefile.sources
                $(HB_DIRECTWRITE_sources) \
                $(HB_CORETEXT_sources) \
                ; do echo '#include "'$$f'"'; done | \
+       sort -u | \
        grep '[.]cc"' > $(srcdir)/harfbuzz.cc \
        || ($(RM) $(srcdir)/harfbuzz.cc; false)
 
index ce65014..fbbff53 100644 (file)
@@ -42,16 +42,19 @@ HB_BASE_sources = \
        hb-draw.hh \
        hb-face.cc \
        hb-face.hh \
+       hb-face-builder.cc \
        hb-fallback-shape.cc \
        hb-font.cc \
        hb-font.hh \
        hb-iter.hh \
        hb-kern.hh \
+       hb-limits.hh \
        hb-machinery.hh \
        hb-map.cc \
        hb-map.hh \
        hb-meta.hh \
        hb-ms-feature-ranges.hh \
+       hb-multimap.hh \
        hb-mutex.hh \
        hb-null.hh \
        hb-number.cc \
@@ -66,11 +69,6 @@ HB_BASE_sources = \
        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-table-list.hh \
        hb-ot-face.cc \
@@ -87,7 +85,91 @@ HB_BASE_sources = \
        hb-ot-layout-common.hh \
        hb-ot-layout-gdef-table.hh \
        hb-ot-layout-gpos-table.hh \
+       hb-outline.hh \
+       hb-outline.cc \
+       hb-paint.cc \
+       hb-paint.hh \
+       hb-paint-extents.cc \
+       hb-paint-extents.hh \
        hb-ot-layout-gsub-table.hh \
+       OT/Color/CBDT/CBDT.hh \
+       OT/Color/COLR/COLR.hh \
+       OT/Color/CPAL/CPAL.hh \
+       OT/Color/sbix/sbix.hh \
+       OT/Color/svg/svg.hh \
+       OT/glyf/glyf.hh \
+       OT/glyf/glyf-helpers.hh \
+       OT/glyf/loca.hh \
+       OT/glyf/path-builder.hh \
+       OT/glyf/Glyph.hh \
+       OT/glyf/GlyphHeader.hh \
+       OT/glyf/SimpleGlyph.hh \
+       OT/glyf/coord-setter.hh \
+       OT/glyf/composite-iter.hh \
+       OT/glyf/CompositeGlyph.hh \
+       OT/glyf/VarCompositeGlyph.hh \
+       OT/glyf/SubsetGlyph.hh \
+       OT/Layout/types.hh \
+       OT/Layout/Common/Coverage.hh \
+       OT/Layout/Common/CoverageFormat1.hh \
+       OT/Layout/Common/CoverageFormat2.hh \
+       OT/Layout/Common/RangeRecord.hh \
+       OT/Layout/GDEF/GDEF.hh \
+       OT/Layout/GPOS/AnchorFormat1.hh \
+       OT/Layout/GPOS/AnchorFormat2.hh \
+       OT/Layout/GPOS/AnchorFormat3.hh \
+       OT/Layout/GPOS/Anchor.hh \
+       OT/Layout/GPOS/AnchorMatrix.hh \
+       OT/Layout/GPOS/ChainContextPos.hh \
+       OT/Layout/GPOS/Common.hh \
+       OT/Layout/GPOS/ContextPos.hh \
+       OT/Layout/GPOS/CursivePosFormat1.hh \
+       OT/Layout/GPOS/CursivePos.hh \
+       OT/Layout/GPOS/ExtensionPos.hh \
+       OT/Layout/GPOS/GPOS.hh \
+       OT/Layout/GPOS/LigatureArray.hh \
+       OT/Layout/GPOS/MarkArray.hh \
+       OT/Layout/GPOS/MarkBasePosFormat1.hh \
+       OT/Layout/GPOS/MarkBasePos.hh \
+       OT/Layout/GPOS/MarkLigPosFormat1.hh \
+       OT/Layout/GPOS/MarkLigPos.hh \
+       OT/Layout/GPOS/MarkMarkPosFormat1.hh \
+       OT/Layout/GPOS/MarkMarkPos.hh \
+       OT/Layout/GPOS/MarkRecord.hh \
+       OT/Layout/GPOS/PairPosFormat1.hh \
+       OT/Layout/GPOS/PairPosFormat2.hh \
+       OT/Layout/GPOS/PairPos.hh \
+       OT/Layout/GPOS/PairSet.hh \
+       OT/Layout/GPOS/PairValueRecord.hh \
+       OT/Layout/GPOS/PosLookup.hh \
+       OT/Layout/GPOS/PosLookupSubTable.hh \
+       OT/Layout/GPOS/SinglePosFormat1.hh \
+       OT/Layout/GPOS/SinglePosFormat2.hh \
+       OT/Layout/GPOS/SinglePos.hh \
+       OT/Layout/GPOS/ValueFormat.hh \
+       OT/Layout/GSUB/AlternateSet.hh \
+       OT/Layout/GSUB/AlternateSubstFormat1.hh \
+       OT/Layout/GSUB/AlternateSubst.hh \
+       OT/Layout/GSUB/ChainContextSubst.hh \
+       OT/Layout/GSUB/Common.hh \
+       OT/Layout/GSUB/ContextSubst.hh \
+       OT/Layout/GSUB/ExtensionSubst.hh \
+       OT/Layout/GSUB/GSUB.hh \
+       OT/Layout/GSUB/Ligature.hh \
+       OT/Layout/GSUB/LigatureSet.hh \
+       OT/Layout/GSUB/LigatureSubstFormat1.hh \
+       OT/Layout/GSUB/LigatureSubst.hh \
+       OT/Layout/GSUB/MultipleSubstFormat1.hh \
+       OT/Layout/GSUB/MultipleSubst.hh \
+       OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh \
+       OT/Layout/GSUB/ReverseChainSingleSubst.hh \
+       OT/Layout/GSUB/Sequence.hh \
+       OT/Layout/GSUB/SingleSubstFormat1.hh \
+       OT/Layout/GSUB/SingleSubstFormat2.hh \
+       OT/Layout/GSUB/SingleSubst.hh \
+       OT/Layout/GSUB/SubstLookup.hh \
+       OT/Layout/GSUB/SubstLookupSubTable.hh \
+       OT/name/name.hh \
        hb-ot-layout-gsubgpos.hh \
        hb-ot-layout-jstf-table.hh \
        hb-ot-layout.cc \
@@ -109,30 +191,29 @@ HB_BASE_sources = \
        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-joining-list.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-syllabic.cc \
-       hb-ot-shape-complex-syllabic.hh \
-       hb-ot-shape-complex-thai.cc \
-       hb-ot-shape-complex-use-table.hh \
-       hb-ot-shape-complex-use.cc \
-       hb-ot-shape-complex-vowel-constraints.cc \
-       hb-ot-shape-complex-vowel-constraints.hh \
-       hb-ot-shape-complex.hh \
+       hb-ot-shaper-arabic-fallback.hh \
+       hb-ot-shaper-arabic-joining-list.hh \
+       hb-ot-shaper-arabic-pua.hh \
+       hb-ot-shaper-arabic-table.hh \
+       hb-ot-shaper-arabic-win1256.hh \
+       hb-ot-shaper-arabic.cc \
+       hb-ot-shaper-arabic.hh \
+       hb-ot-shaper-default.cc \
+       hb-ot-shaper-hangul.cc \
+       hb-ot-shaper-hebrew.cc \
+       hb-ot-shaper-indic-table.cc \
+       hb-ot-shaper-indic.cc \
+       hb-ot-shaper-indic.hh \
+       hb-ot-shaper-khmer.cc \
+       hb-ot-shaper-myanmar.cc \
+       hb-ot-shaper-syllabic.cc \
+       hb-ot-shaper-syllabic.hh \
+       hb-ot-shaper-thai.cc \
+       hb-ot-shaper-use-table.hh \
+       hb-ot-shaper-use.cc \
+       hb-ot-shaper-vowel-constraints.cc \
+       hb-ot-shaper-vowel-constraints.hh \
+       hb-ot-shaper.hh \
        hb-ot-shape-fallback.cc \
        hb-ot-shape-fallback.hh \
        hb-ot-shape-normalize.cc \
@@ -144,6 +225,7 @@ HB_BASE_sources = \
        hb-ot-tag.cc \
        hb-ot-var-avar-table.hh \
        hb-ot-var-common.hh \
+       hb-ot-var-cvar-table.hh \
        hb-ot-var-fvar-table.hh \
        hb-ot-var-gvar-table.hh \
        hb-ot-var-hvar-table.hh \
@@ -179,21 +261,23 @@ HB_BASE_sources = \
 
 HB_BASE_RAGEL_GENERATED_sources = \
        hb-buffer-deserialize-json.hh \
-       hb-buffer-deserialize-text.hh \
+       hb-buffer-deserialize-text-glyphs.hh \
+       hb-buffer-deserialize-text-unicode.hh \
        hb-number-parser.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-ot-shaper-indic-machine.hh \
+       hb-ot-shaper-khmer-machine.hh \
+       hb-ot-shaper-myanmar-machine.hh \
+       hb-ot-shaper-use-machine.hh \
        $(NULL)
 HB_BASE_RAGEL_sources = \
        hb-buffer-deserialize-json.rl \
-       hb-buffer-deserialize-text.rl \
+       hb-buffer-deserialize-text-glyphs.rl \
+       hb-buffer-deserialize-text-unicode.rl \
        hb-number-parser.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 \
+       hb-ot-shaper-indic-machine.rl \
+       hb-ot-shaper-khmer-machine.rl \
+       hb-ot-shaper-myanmar-machine.rl \
+       hb-ot-shaper-use-machine.rl \
        $(NULL)
 
 HB_BASE_headers = \
@@ -202,6 +286,7 @@ HB_BASE_headers = \
        hb-blob.h \
        hb-buffer.h \
        hb-common.h \
+       hb-cplusplus.hh \
        hb-deprecated.h \
        hb-draw.h \
        hb-face.h \
@@ -218,6 +303,7 @@ HB_BASE_headers = \
        hb-ot-shape.h \
        hb-ot-var.h \
        hb-ot.h \
+       hb-paint.h \
        hb-set.h \
        hb-shape-plan.h \
        hb-shape.h \
@@ -229,7 +315,7 @@ HB_BASE_headers = \
 
 # Optional Sources and Headers with external deps
 
-HB_FT_sources = hb-ft.cc
+HB_FT_sources = hb-ft.cc hb-ft-colr.hh
 HB_FT_headers = hb-ft.h
 
 HB_GLIB_sources = hb-glib.cc
@@ -252,36 +338,72 @@ HB_GDI_headers = hb-gdi.h
 HB_UNISCRIBE_sources = hb-uniscribe.cc
 HB_UNISCRIBE_headers = hb-uniscribe.h
 
-# Sources for libharfbuzz-gobject and libharfbuzz-icu
 HB_ICU_sources = hb-icu.cc
 HB_ICU_headers = hb-icu.h
 
+HB_WASM_sources = \
+       hb-wasm-api.cc \
+       hb-wasm-api.hh \
+       hb-wasm-api-blob.hh \
+       hb-wasm-api-buffer.hh \
+       hb-wasm-api-common.hh \
+       hb-wasm-api-face.hh \
+       hb-wasm-api-font.hh \
+       hb-wasm-api-shape.hh \
+       hb-wasm-shape.cc \
+       $(NULL)
+HB_WASM_headers = hb-wasm-api.h
+
 # Sources for libharfbuzz-subset
 HB_SUBSET_sources = \
        hb-number.cc \
        hb-number.hh \
        hb-ot-cff1-table.cc \
        hb-ot-cff2-table.cc \
-       hb-ot-color-colrv1-closure.hh \
        hb-ot-post-table-v2subset.hh \
        hb-static.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-input.cc \
        hb-subset-input.hh \
+       hb-subset-instancer-solver.hh \
+       hb-subset-instancer-solver.cc \
+       hb-subset-accelerator.hh \
        hb-subset-plan.cc \
        hb-subset-plan.hh \
+       hb-subset-plan-member-list.hh \
+       hb-subset-repacker.cc \
        hb-subset.cc \
        hb-subset.hh \
        hb-repacker.hh \
+       graph/graph.hh \
+       graph/gsubgpos-graph.hh \
+       graph/gsubgpos-context.hh \
+       graph/gsubgpos-context.cc \
+       graph/coverage-graph.hh \
+       graph/classdef-graph.hh \
+       graph/pairpos-graph.hh \
+       graph/markbasepos-graph.hh \
+       graph/split-helpers.hh \
+       graph/serialize.hh \
+       OT/Color/COLR/colrv1-closure.hh \
        $(NULL)
 
 HB_SUBSET_headers = \
        hb-subset.h \
+       hb-subset-repacker.h \
+       $(NULL)
+
+HB_CAIRO_sources = \
+       hb-cairo.cc \
+       hb-cairo-utils.cc \
+       hb-cairo-utils.hh \
+       hb-static.cc \
+       $(NULL)
+HB_CAIRO_headers = \
+       hb-cairo.h \
        $(NULL)
 
 HB_GOBJECT_DIST_sources = hb-gobject-structs.cc
similarity index 92%
rename from src/hb-ot-color-cbdt-table.hh
rename to src/OT/Color/CBDT/CBDT.hh
index 23fa56c..457039b 100644 (file)
  * Google Author(s): Seigo Nonaka, Calder Kitagawa
  */
 
-#ifndef HB_OT_COLOR_CBDT_TABLE_HH
-#define HB_OT_COLOR_CBDT_TABLE_HH
+#ifndef OT_COLOR_CBDT_CBDT_HH
+#define OT_COLOR_CBDT_CBDT_HH
 
-#include "hb-open-type.hh"
+#include "../../../hb-open-type.hh"
+#include "../../../hb-paint.hh"
 
 /*
  * CBLC -- Color Bitmap Location
@@ -67,7 +68,7 @@ _copy_data_to_cbdt (hb_vector_t<char> *cbdt_prime,
 {
   unsigned int new_len = cbdt_prime->length + length;
   if (unlikely (!cbdt_prime->alloc (new_len))) return false;
-  memcpy (cbdt_prime->arrayZ + cbdt_prime->length, data, length);
+  hb_memcpy (cbdt_prime->arrayZ + cbdt_prime->length, data, length);
   cbdt_prime->length = new_len;
   return true;
 }
@@ -80,12 +81,15 @@ struct SmallGlyphMetrics
     return_trace (c->check_struct (this));
   }
 
-  void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) const
+  void get_extents (hb_font_t *font, hb_glyph_extents_t *extents, bool scale) const
   {
-    extents->x_bearing = font->em_scale_x (bearingX);
-    extents->y_bearing = font->em_scale_y (bearingY);
-    extents->width = font->em_scale_x (width);
-    extents->height = font->em_scale_y (-static_cast<int>(height));
+    extents->x_bearing = bearingX;
+    extents->y_bearing = bearingY;
+    extents->width = width;
+    extents->height = -static_cast<int> (height);
+
+    if (scale)
+      font->scale_glyph_extents (extents);
   }
 
   HBUINT8      height;
@@ -307,7 +311,7 @@ struct IndexSubtable
     }
   }
 
-  bool get_extents (hb_glyph_extents_t *extents HB_UNUSED) const
+  bool get_extents (hb_glyph_extents_t *extents HB_UNUSED, bool scale HB_UNUSED) const
   {
     switch (u.header.indexFormat)
     {
@@ -393,7 +397,6 @@ struct IndexSubtableRecord
     TRACE_SERIALIZE (this);
 
     auto *subtable = c->serializer->start_embed<IndexSubtable> ();
-    if (unlikely (!subtable)) return_trace (false);
     if (unlikely (!c->serializer->extend_min (subtable))) return_trace (false);
 
     auto *old_subtable = get_subtable (base);
@@ -468,13 +471,13 @@ struct IndexSubtableRecord
     if (unlikely (!c->serializer->check_success (records->resize (records->length + 1))))
       return_trace (false);
 
-    (*records)[records->length - 1].firstGlyphIndex = 1;
-    (*records)[records->length - 1].lastGlyphIndex = 0;
+    records->tail ().firstGlyphIndex = 1;
+    records->tail ().lastGlyphIndex = 0;
     bitmap_size_context->size += IndexSubtableRecord::min_size;
 
     c->serializer->push ();
 
-    if (unlikely (!add_new_subtable (c, bitmap_size_context, &((*records)[records->length - 1]), lookup, base, start)))
+    if (unlikely (!add_new_subtable (c, bitmap_size_context, &(records->tail ()), lookup, base, start)))
     {
       c->serializer->pop_discard ();
       c->serializer->revert (snap);
@@ -504,8 +507,8 @@ struct IndexSubtableRecord
     return num_missing;
   }
 
-  bool get_extents (hb_glyph_extents_t *extents, const void *base) const
-  { return (base+offsetToSubtable).get_extents (extents); }
+  bool get_extents (hb_glyph_extents_t *extents, const void *base, bool scale) const
+  { return (base+offsetToSubtable).get_extents (extents, scale); }
 
   bool get_image_data (unsigned int  gid,
                       const void   *base,
@@ -541,7 +544,8 @@ struct IndexSubtableArray
                const IndexSubtableRecord*>> *lookup /* OUT */) const
   {
     bool start_glyph_is_set = false;
-    for (hb_codepoint_t new_gid = 0; new_gid < c->plan->num_output_glyphs (); new_gid++)
+    unsigned num_glyphs = c->plan->num_output_glyphs ();
+    for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++)
     {
       hb_codepoint_t old_gid;
       if (unlikely (!c->plan->old_gid_for_new_gid (new_gid, &old_gid))) continue;
@@ -572,9 +576,6 @@ struct IndexSubtableArray
   {
     TRACE_SUBSET (this);
 
-    auto *dst = c->serializer->start_embed<IndexSubtableArray> ();
-    if (unlikely (!dst)) return_trace (false);
-
     hb_vector_t<hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*>> lookup;
     build_lookup (c, bitmap_size_context, &lookup);
     if (unlikely (!c->serializer->propagate_error (lookup)))
@@ -833,7 +834,7 @@ struct CBDT
     }
 
     bool
-    get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
+    get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents, bool scale = true) const
     {
       const void *base;
       const BitmapSizeTable &strike = this->cblc->choose_strike (font);
@@ -841,7 +842,7 @@ struct CBDT
       if (!subtable_record || !strike.ppemX || !strike.ppemY)
        return false;
 
-      if (subtable_record->get_extents (extents, base))
+      if (subtable_record->get_extents (extents, base, scale))
        return true;
 
       unsigned int image_offset = 0, image_length = 0, image_format = 0;
@@ -858,26 +859,29 @@ struct CBDT
        if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
          return false;
        auto &glyphFormat17 = StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
-       glyphFormat17.glyphMetrics.get_extents (font, extents);
+       glyphFormat17.glyphMetrics.get_extents (font, extents, scale);
        break;
       }
       case 18: {
        if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
          return false;
        auto &glyphFormat18 = StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
-       glyphFormat18.glyphMetrics.get_extents (font, extents);
+       glyphFormat18.glyphMetrics.get_extents (font, extents, scale);
        break;
       }
       default: return false; /* TODO: Support other image formats. */
       }
 
       /* Convert to font units. */
-      float x_scale = upem / (float) strike.ppemX;
-      float y_scale = upem / (float) strike.ppemY;
-      extents->x_bearing = roundf (extents->x_bearing * x_scale);
-      extents->y_bearing = roundf (extents->y_bearing * y_scale);
-      extents->width = roundf (extents->width * x_scale);
-      extents->height = roundf (extents->height * y_scale);
+      if (scale)
+      {
+       float x_scale = upem / (float) strike.ppemX;
+       float y_scale = upem / (float) strike.ppemY;
+       extents->x_bearing = roundf (extents->x_bearing * x_scale);
+       extents->y_bearing = roundf (extents->y_bearing * y_scale);
+       extents->width = roundf (extents->width * x_scale);
+       extents->height = roundf (extents->height * y_scale);
+      }
 
       return true;
     }
@@ -934,6 +938,32 @@ struct CBDT
 
     bool has_data () const { return cbdt.get_length (); }
 
+    bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
+    {
+      hb_glyph_extents_t extents;
+      hb_glyph_extents_t pixel_extents;
+      hb_blob_t *blob = reference_png (font, glyph);
+
+      if (unlikely (blob == hb_blob_get_empty ()))
+        return false;
+
+      if (unlikely (!hb_font_get_glyph_extents (font, glyph, &extents)))
+        return false;
+
+      if (unlikely (!get_extents (font, glyph, &pixel_extents, false)))
+        return false;
+
+      bool ret = funcs->image (data,
+                              blob,
+                              pixel_extents.width, -pixel_extents.height,
+                              HB_PAINT_IMAGE_FORMAT_PNG,
+                              font->slant_xy,
+                              &extents);
+
+      hb_blob_destroy (blob);
+      return ret;
+    }
+
     private:
     hb_blob_ptr_t<CBLC> cblc;
     hb_blob_ptr_t<CBDT> cbdt;
@@ -960,12 +990,10 @@ CBLC::subset (hb_subset_context_t *c) const
 {
   TRACE_SUBSET (this);
 
-  auto *cblc_prime = c->serializer->start_embed<CBLC> ();
-
   // Use a vector as a secondary buffer as the tables need to be built in parallel.
   hb_vector_t<char> cbdt_prime;
 
-  if (unlikely (!cblc_prime)) return_trace (false);
+  auto *cblc_prime = c->serializer->start_embed<CBLC> ();
   if (unlikely (!c->serializer->extend_min (cblc_prime))) return_trace (false);
   cblc_prime->version = version;
 
@@ -994,4 +1022,4 @@ struct CBDT_accelerator_t : CBDT::accelerator_t {
 
 } /* namespace OT */
 
-#endif /* HB_OT_COLOR_CBDT_TABLE_HH */
+#endif /* OT_COLOR_CBDT_CBDT_HH */
similarity index 55%
rename from src/hb-ot-color-colr-table.hh
rename to src/OT/Color/COLR/COLR.hh
index dac755c..60b094e 100644 (file)
  * Google Author(s): Calder Kitagawa
  */
 
-#ifndef HB_OT_COLOR_COLR_TABLE_HH
-#define HB_OT_COLOR_COLR_TABLE_HH
+#ifndef OT_COLOR_COLR_COLR_HH
+#define OT_COLOR_COLR_COLR_HH
 
-#include "hb-open-type.hh"
-#include "hb-ot-layout-common.hh"
-#include "hb-ot-var-common.hh"
+#include "../../../hb.hh"
+#include "../../../hb-open-type.hh"
+#include "../../../hb-ot-var-common.hh"
+#include "../../../hb-paint.hh"
+#include "../../../hb-paint-extents.hh"
 
 /*
  * COLR -- Color
  */
 #define HB_OT_TAG_COLR HB_TAG('C','O','L','R')
 
-#ifndef HB_COLRV1_MAX_NESTING_LEVEL
-#define HB_COLRV1_MAX_NESTING_LEVEL    100
-#endif
-
-#ifndef COLRV1_ENABLE_SUBSETTING
-#define COLRV1_ENABLE_SUBSETTING 1
-#endif
+namespace OT {
+struct hb_paint_context_t;
+}
 
 namespace OT {
 
 struct COLR;
+
+struct Paint;
+
+struct hb_paint_context_t :
+       hb_dispatch_context_t<hb_paint_context_t>
+{
+  const char *get_name () { return "PAINT"; }
+  template <typename T>
+  return_t dispatch (const T &obj) { obj.paint_glyph (this); return hb_empty_t (); }
+  static return_t default_return_value () { return hb_empty_t (); }
+
+  const COLR* get_colr_table () const
+  { return reinterpret_cast<const COLR *> (base); }
+
+public:
+  const void *base;
+  hb_paint_funcs_t *funcs;
+  void *data;
+  hb_font_t *font;
+  unsigned int palette_index;
+  hb_color_t foreground;
+  VarStoreInstancer &instancer;
+  hb_map_t current_glyphs;
+  hb_map_t current_layers;
+  int depth_left = HB_MAX_NESTING_LEVEL;
+  int edge_count = HB_COLRV1_MAX_EDGE_COUNT;
+
+  hb_paint_context_t (const void *base_,
+                     hb_paint_funcs_t *funcs_,
+                     void *data_,
+                      hb_font_t *font_,
+                      unsigned int palette_,
+                      hb_color_t foreground_,
+                     VarStoreInstancer &instancer_) :
+    base (base_),
+    funcs (funcs_),
+    data (data_),
+    font (font_),
+    palette_index (palette_),
+    foreground (foreground_),
+    instancer (instancer_)
+  { }
+
+  hb_color_t get_color (unsigned int color_index, float alpha, hb_bool_t *is_foreground)
+  {
+    hb_color_t color = foreground;
+
+    *is_foreground = true;
+
+    if (color_index != 0xffff)
+    {
+      if (!funcs->custom_palette_color (data, color_index, &color))
+      {
+       unsigned int clen = 1;
+       hb_face_t *face = hb_font_get_face (font);
+
+       hb_ot_color_palette_get_colors (face, palette_index, color_index, &clen, &color);
+      }
+
+      *is_foreground = false;
+    }
+
+    return HB_COLOR (hb_color_get_blue (color),
+                     hb_color_get_green (color),
+                     hb_color_get_red (color),
+                     hb_color_get_alpha (color) * alpha);
+  }
+
+  inline void recurse (const Paint &paint);
+};
+
 struct hb_colrv1_closure_context_t :
        hb_dispatch_context_t<hb_colrv1_closure_context_t>
 {
@@ -102,7 +171,7 @@ struct hb_colrv1_closure_context_t :
                                hb_set_t *glyphs_,
                                hb_set_t *layer_indices_,
                                hb_set_t *palette_indices_,
-                               unsigned nesting_level_left_ = HB_COLRV1_MAX_NESTING_LEVEL) :
+                               unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
                           base (base_),
                           glyphs (glyphs_),
                           layer_indices (layer_indices_),
@@ -145,7 +214,7 @@ struct BaseGlyphRecord
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   public:
@@ -164,6 +233,8 @@ struct BaseGlyphRecord
 template <typename T>
 struct Variable
 {
+  static constexpr bool is_variable = true;
+
   Variable<T>* copy (hb_serialize_context_t *c) const
   {
     TRACE_SERIALIZE (this);
@@ -173,10 +244,15 @@ struct Variable
   void closurev1 (hb_colrv1_closure_context_t* c) const
   { value.closurev1 (c); }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
-    if (!value.subset (c)) return_trace (false);
+    if (!value.subset (c, instancer, varIdxBase)) return_trace (false);
+    if (c->plan->all_axes_pinned)
+      return_trace (true);
+
+    //TODO: update varIdxBase for partial-instancing
     return_trace (c->serializer->embed (varIdxBase));
   }
 
@@ -186,16 +262,39 @@ struct Variable
     return_trace (c->check_struct (this) && value.sanitize (c));
   }
 
+  void paint_glyph (hb_paint_context_t *c) const
+  {
+    TRACE_PAINT (this);
+    value.paint_glyph (c, varIdxBase);
+  }
+
+  void get_color_stop (hb_paint_context_t *c,
+                       hb_color_stop_t *stop,
+                      const VarStoreInstancer &instancer) const
+  {
+    value.get_color_stop (c, stop, varIdxBase, instancer);
+  }
+
+  hb_paint_extend_t get_extend () const
+  {
+    return value.get_extend ();
+  }
+
   protected:
   T      value;
+  public:
   VarIdx varIdxBase;
   public:
-  DEFINE_SIZE_STATIC (4 + T::static_size);
+  DEFINE_SIZE_MIN (VarIdx::static_size + T::min_size);
 };
 
 template <typename T>
 struct NoVariable
 {
+  static constexpr bool is_variable = false;
+
+  static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION;
+
   NoVariable<T>* copy (hb_serialize_context_t *c) const
   {
     TRACE_SERIALIZE (this);
@@ -205,10 +304,11 @@ struct NoVariable
   void closurev1 (hb_colrv1_closure_context_t* c) const
   { value.closurev1 (c); }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
-    return_trace (value.subset (c));
+    return_trace (value.subset (c, instancer, varIdxBase));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -217,9 +317,27 @@ struct NoVariable
     return_trace (c->check_struct (this) && value.sanitize (c));
   }
 
+  void paint_glyph (hb_paint_context_t *c) const
+  {
+    TRACE_PAINT (this);
+    value.paint_glyph (c, varIdxBase);
+  }
+
+  void get_color_stop (hb_paint_context_t *c,
+                       hb_color_stop_t *stop,
+                      const VarStoreInstancer &instancer) const
+  {
+    value.get_color_stop (c, stop, VarIdx::NO_VARIATION, instancer);
+  }
+
+  hb_paint_extend_t get_extend () const
+  {
+    return value.get_extend ();
+  }
+
   T      value;
   public:
-  DEFINE_SIZE_STATIC (T::static_size);
+  DEFINE_SIZE_MIN (T::min_size);
 };
 
 // Color structures
@@ -229,12 +347,21 @@ struct ColorStop
   void closurev1 (hb_colrv1_closure_context_t* c) const
   { c->add_palette_index (paletteIndex); }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer,
+               uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (*this);
     if (unlikely (!out)) return_trace (false);
-    return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex),
+
+    if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+    {
+      out->stopOffset.set_float (stopOffset.to_float(instancer (varIdxBase, 0)));
+      out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 1)));
+    }
+
+    return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex),
                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
   }
 
@@ -244,6 +371,17 @@ struct ColorStop
     return_trace (c->check_struct (this));
   }
 
+  void get_color_stop (hb_paint_context_t *c,
+                       hb_color_stop_t *out,
+                      uint32_t varIdx,
+                      const VarStoreInstancer &instancer) const
+  {
+    out->offset = stopOffset.to_float(instancer (varIdx, 0));
+    out->color = c->get_color (paletteIndex,
+                               alpha.to_float (instancer (varIdx, 1)),
+                               &out->is_foreground);
+  }
+
   F2DOT14      stopOffset;
   HBUINT16     paletteIndex;
   F2DOT14      alpha;
@@ -271,11 +409,11 @@ struct ColorLine
       stop.closurev1 (c);
   }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (this);
-    if (unlikely (!out)) return_trace (false);
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
 
     if (!c->serializer->check_assign (out->extend, extend, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
@@ -283,7 +421,7 @@ struct ColorLine
 
     for (const auto& stop : stops.iter ())
     {
-      if (!stop.subset (c)) return_trace (false);
+      if (!stop.subset (c, instancer)) return_trace (false);
     }
     return_trace (true);
   }
@@ -295,6 +433,52 @@ struct ColorLine
                   stops.sanitize (c));
   }
 
+  /* get up to count stops from start */
+  unsigned int
+  get_color_stops (hb_paint_context_t *c,
+                   unsigned int start,
+                  unsigned int *count,
+                  hb_color_stop_t *color_stops,
+                  const VarStoreInstancer &instancer) const
+  {
+    unsigned int len = stops.len;
+
+    if (count && color_stops)
+    {
+      unsigned int i;
+      for (i = 0; i < *count && start + i < len; i++)
+        stops[start + i].get_color_stop (c, &color_stops[i], instancer);
+      *count = i;
+    }
+
+    return len;
+  }
+
+  HB_INTERNAL static unsigned int static_get_color_stops (hb_color_line_t *color_line,
+                                                         void *color_line_data,
+                                                         unsigned int start,
+                                                         unsigned int *count,
+                                                         hb_color_stop_t *color_stops,
+                                                         void *user_data)
+  {
+    const ColorLine *thiz = (const ColorLine *) color_line_data;
+    hb_paint_context_t *c = (hb_paint_context_t *) user_data;
+    return thiz->get_color_stops (c, start, count, color_stops, c->instancer);
+  }
+
+  hb_paint_extend_t get_extend () const
+  {
+    return (hb_paint_extend_t) (unsigned int) extend;
+  }
+
+  HB_INTERNAL static hb_paint_extend_t static_get_extend (hb_color_line_t *color_line,
+                                                         void *color_line_data,
+                                                         void *user_data)
+  {
+    const ColorLine *thiz = (const ColorLine *) color_line_data;
+    return thiz->get_extend ();
+  }
+
   Extend       extend;
   Array16Of<Var<ColorStop>>    stops;
   public:
@@ -358,26 +542,58 @@ struct Affine2x3
     return_trace (c->check_struct (this));
   }
 
-  HBFixed xx;
-  HBFixed yx;
-  HBFixed xy;
-  HBFixed yy;
-  HBFixed dx;
-  HBFixed dy;
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer,
+               uint32_t varIdxBase) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+    if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+    {
+      out->xx.set_float (xx.to_float(instancer (varIdxBase, 0)));
+      out->yx.set_float (yx.to_float(instancer (varIdxBase, 1)));
+      out->xy.set_float (xy.to_float(instancer (varIdxBase, 2)));
+      out->yy.set_float (yy.to_float(instancer (varIdxBase, 3)));
+      out->dx.set_float (dx.to_float(instancer (varIdxBase, 4)));
+      out->dy.set_float (dy.to_float(instancer (varIdxBase, 5)));
+    }
+    return_trace (true);
+  }
+
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    TRACE_PAINT (this);
+    c->funcs->push_transform (c->data,
+                             xx.to_float (c->instancer (varIdxBase, 0)),
+                             yx.to_float (c->instancer (varIdxBase, 1)),
+                              xy.to_float (c->instancer (varIdxBase, 2)),
+                             yy.to_float (c->instancer (varIdxBase, 3)),
+                              dx.to_float (c->instancer (varIdxBase, 4)),
+                             dy.to_float (c->instancer (varIdxBase, 5)));
+  }
+
+  F16DOT16 xx;
+  F16DOT16 yx;
+  F16DOT16 xy;
+  F16DOT16 yy;
+  F16DOT16 dx;
+  F16DOT16 dy;
   public:
-  DEFINE_SIZE_STATIC (6 * HBFixed::static_size);
+  DEFINE_SIZE_STATIC (6 * F16DOT16::static_size);
 };
 
 struct PaintColrLayers
 {
   void closurev1 (hb_colrv1_closure_context_t* c) const;
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer HB_UNUSED) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
-    return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers->get (firstLayerIndex),
+    return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers.get (firstLayerIndex),
                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
 
     return_trace (true);
@@ -389,6 +605,8 @@ struct PaintColrLayers
     return_trace (c->check_struct (this));
   }
 
+  inline void paint_glyph (hb_paint_context_t *c) const;
+
   HBUINT8      format; /* format = 1 */
   HBUINT8      numLayers;
   HBUINT32     firstLayerIndex;  /* index into COLRv1::layerList */
@@ -401,12 +619,21 @@ struct PaintSolid
   void closurev1 (hb_colrv1_closure_context_t* c) const
   { c->add_palette_index (paletteIndex); }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer,
+               uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (*this);
     if (unlikely (!out)) return_trace (false);
-    return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex),
+
+    if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+      out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 0)));
+
+    if (format == 3 && c->plan->all_axes_pinned)
+        out->format = 2;
+
+    return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex),
                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
   }
 
@@ -416,6 +643,18 @@ struct PaintSolid
     return_trace (c->check_struct (this));
   }
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    TRACE_PAINT (this);
+    hb_bool_t is_foreground;
+    hb_color_t color;
+
+    color = c->get_color (paletteIndex,
+                          alpha.to_float (c->instancer (varIdxBase, 0)),
+                          &is_foreground);
+    c->funcs->color (c->data, is_foreground, color);
+  }
+
   HBUINT8      format; /* format = 2(noVar) or 3(Var)*/
   HBUINT16     paletteIndex;
   F2DOT14      alpha;
@@ -429,13 +668,28 @@ struct PaintLinearGradient
   void closurev1 (hb_colrv1_closure_context_t* c) const
   { (this+colorLine).closurev1 (c); }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer,
+               uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
 
-    return_trace (out->colorLine.serialize_subset (c, colorLine, this));
+    if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+    {
+      out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0));
+      out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1));
+      out->x1 = x1 + (int) roundf (instancer (varIdxBase, 2));
+      out->y1 = y1 + (int) roundf (instancer (varIdxBase, 3));
+      out->x2 = x2 + (int) roundf (instancer (varIdxBase, 4));
+      out->y2 = y2 + (int) roundf (instancer (varIdxBase, 5));
+    }
+
+    if (format == 5 && c->plan->all_axes_pinned)
+        out->format = 4;
+
+    return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -444,6 +698,24 @@ struct PaintLinearGradient
     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
   }
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    TRACE_PAINT (this);
+    hb_color_line_t cl = {
+      (void *) &(this+colorLine),
+      (this+colorLine).static_get_color_stops, c,
+      (this+colorLine).static_get_extend, nullptr
+    };
+
+    c->funcs->linear_gradient (c->data, &cl,
+                              x0 + c->instancer (varIdxBase, 0),
+                              y0 + c->instancer (varIdxBase, 1),
+                              x1 + c->instancer (varIdxBase, 2),
+                              y1 + c->instancer (varIdxBase, 3),
+                              x2 + c->instancer (varIdxBase, 4),
+                              y2 + c->instancer (varIdxBase, 5));
+  }
+
   HBUINT8                      format; /* format = 4(noVar) or 5 (Var) */
   Offset24To<ColorLine<Var>>   colorLine; /* Offset (from beginning of PaintLinearGradient
                                             * table) to ColorLine subtable. */
@@ -463,13 +735,28 @@ struct PaintRadialGradient
   void closurev1 (hb_colrv1_closure_context_t* c) const
   { (this+colorLine).closurev1 (c); }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer,
+               uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
 
-    return_trace (out->colorLine.serialize_subset (c, colorLine, this));
+    if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+    {
+      out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0));
+      out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1));
+      out->radius0 = radius0 + (unsigned) roundf (instancer (varIdxBase, 2));
+      out->x1 = x1 + (int) roundf (instancer (varIdxBase, 3));
+      out->y1 = y1 + (int) roundf (instancer (varIdxBase, 4));
+      out->radius1 = radius1 + (unsigned) roundf (instancer (varIdxBase, 5));
+    }
+
+    if (format == 7 && c->plan->all_axes_pinned)
+        out->format = 6;
+
+    return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -478,6 +765,24 @@ struct PaintRadialGradient
     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
   }
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    TRACE_PAINT (this);
+    hb_color_line_t cl = {
+      (void *) &(this+colorLine),
+      (this+colorLine).static_get_color_stops, c,
+      (this+colorLine).static_get_extend, nullptr
+    };
+
+    c->funcs->radial_gradient (c->data, &cl,
+                              x0 + c->instancer (varIdxBase, 0),
+                              y0 + c->instancer (varIdxBase, 1),
+                              radius0 + c->instancer (varIdxBase, 2),
+                              x1 + c->instancer (varIdxBase, 3),
+                              y1 + c->instancer (varIdxBase, 4),
+                              radius1 + c->instancer (varIdxBase, 5));
+  }
+
   HBUINT8                      format; /* format = 6(noVar) or 7 (Var) */
   Offset24To<ColorLine<Var>>   colorLine; /* Offset (from beginning of PaintRadialGradient
                                             * table) to ColorLine subtable. */
@@ -497,13 +802,26 @@ struct PaintSweepGradient
   void closurev1 (hb_colrv1_closure_context_t* c) const
   { (this+colorLine).closurev1 (c); }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer,
+               uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
 
-    return_trace (out->colorLine.serialize_subset (c, colorLine, this));
+    if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+    {
+      out->centerX = centerX + (int) roundf (instancer (varIdxBase, 0));
+      out->centerY = centerY + (int) roundf (instancer (varIdxBase, 1));
+      out->startAngle.set_float (startAngle.to_float (instancer (varIdxBase, 2)));
+      out->endAngle.set_float (endAngle.to_float (instancer (varIdxBase, 3)));
+    }
+
+    if (format == 9 && c->plan->all_axes_pinned)
+        out->format = 8;
+
+    return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -512,6 +830,22 @@ struct PaintSweepGradient
     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
   }
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    TRACE_PAINT (this);
+    hb_color_line_t cl = {
+      (void *) &(this+colorLine),
+      (this+colorLine).static_get_color_stops, c,
+      (this+colorLine).static_get_extend, nullptr
+    };
+
+    c->funcs->sweep_gradient (c->data, &cl,
+                             centerX + c->instancer (varIdxBase, 0),
+                             centerY + c->instancer (varIdxBase, 1),
+                              (startAngle.to_float (c->instancer (varIdxBase, 2)) + 1) * HB_PI,
+                              (endAngle.to_float   (c->instancer (varIdxBase, 3)) + 1) * HB_PI);
+  }
+
   HBUINT8                      format; /* format = 8(noVar) or 9 (Var) */
   Offset24To<ColorLine<Var>>   colorLine; /* Offset (from beginning of PaintSweepGradient
                                             * table) to ColorLine subtable. */
@@ -523,13 +857,13 @@ struct PaintSweepGradient
   DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size);
 };
 
-struct Paint;
 // Paint a non-COLR glyph, filled as indicated by paint.
 struct PaintGlyph
 {
   void closurev1 (hb_colrv1_closure_context_t* c) const;
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
@@ -539,7 +873,7 @@ struct PaintGlyph
                                        HB_SERIALIZE_ERROR_INT_OVERFLOW))
       return_trace (false);
 
-    return_trace (out->paint.serialize_subset (c, paint, this));
+    return_trace (out->paint.serialize_subset (c, paint, this, instancer));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -548,6 +882,18 @@ struct PaintGlyph
     return_trace (c->check_struct (this) && paint.sanitize (c, this));
   }
 
+  void paint_glyph (hb_paint_context_t *c) const
+  {
+    TRACE_PAINT (this);
+    c->funcs->push_inverse_root_transform (c->data, c->font);
+    c->funcs->push_clip_glyph (c->data, gid, c->font);
+    c->funcs->push_root_transform (c->data, c->font);
+    c->recurse (this+paint);
+    c->funcs->pop_transform (c->data);
+    c->funcs->pop_clip (c->data);
+    c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8              format; /* format = 10 */
   Offset24To<Paint>    paint;  /* Offset (from beginning of PaintGlyph table) to Paint subtable. */
   HBUINT16             gid;
@@ -559,7 +905,8 @@ struct PaintColrGlyph
 {
   void closurev1 (hb_colrv1_closure_context_t* c) const;
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer HB_UNUSED) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
@@ -575,6 +922,8 @@ struct PaintColrGlyph
     return_trace (c->check_struct (this));
   }
 
+  inline void paint_glyph (hb_paint_context_t *c) const;
+
   HBUINT8      format; /* format = 11 */
   HBUINT16     gid;
   public:
@@ -586,13 +935,16 @@ struct PaintTransform
 {
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
-    if (!out->transform.serialize_copy (c->serializer, transform, this)) return_trace (false);
-    return_trace (out->src.serialize_subset (c, src, this));
+    if (!out->transform.serialize_subset (c, transform, this, instancer)) return_trace (false);
+    if (format == 13 && c->plan->all_axes_pinned)
+      out->format = 12;
+    return_trace (out->src.serialize_subset (c, src, this, instancer));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -603,6 +955,14 @@ struct PaintTransform
                   transform.sanitize (c, this));
   }
 
+  void paint_glyph (hb_paint_context_t *c) const
+  {
+    TRACE_PAINT (this);
+    (this+transform).paint_glyph (c);
+    c->recurse (this+src);
+    c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8                      format; /* format = 12(noVar) or 13 (Var) */
   Offset24To<Paint>            src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */
   Offset24To<Var<Affine2x3>>   transform;
@@ -614,13 +974,24 @@ struct PaintTranslate
 {
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer,
+               uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
 
-    return_trace (out->src.serialize_subset (c, src, this));
+    if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+    {
+      out->dx = dx + (int) roundf (instancer (varIdxBase, 0));
+      out->dy = dy + (int) roundf (instancer (varIdxBase, 1));
+    }
+
+    if (format == 15 && c->plan->all_axes_pinned)
+        out->format = 14;
+
+    return_trace (out->src.serialize_subset (c, src, this, instancer));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -629,6 +1000,17 @@ struct PaintTranslate
     return_trace (c->check_struct (this) && src.sanitize (c, this));
   }
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    TRACE_PAINT (this);
+    float ddx = dx + c->instancer (varIdxBase, 0);
+    float ddy = dy + c->instancer (varIdxBase, 1);
+
+    bool p1 = c->funcs->push_translate (c->data, ddx, ddy);
+    c->recurse (this+src);
+    if (p1) c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8              format; /* format = 14(noVar) or 15 (Var) */
   Offset24To<Paint>    src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */
   FWORD                dx;
@@ -641,13 +1023,24 @@ struct PaintScale
 {
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer,
+               uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
 
-    return_trace (out->src.serialize_subset (c, src, this));
+    if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+    {
+      out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0)));
+      out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1)));
+    }
+
+    if (format == 17 && c->plan->all_axes_pinned)
+        out->format = 16;
+
+    return_trace (out->src.serialize_subset (c, src, this, instancer));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -656,6 +1049,17 @@ struct PaintScale
     return_trace (c->check_struct (this) && src.sanitize (c, this));
   }
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    TRACE_PAINT (this);
+    float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
+    float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
+
+    bool p1 = c->funcs->push_scale (c->data, sx, sy);
+    c->recurse (this+src);
+    if (p1) c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8              format; /* format = 16 (noVar) or 17(Var) */
   Offset24To<Paint>    src; /* Offset (from beginning of PaintScale table) to Paint subtable. */
   F2DOT14              scaleX;
@@ -668,13 +1072,26 @@ struct PaintScaleAroundCenter
 {
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer,
+               uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
 
-    return_trace (out->src.serialize_subset (c, src, this));
+    if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+    {
+      out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0)));
+      out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1)));
+      out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2));
+      out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3));
+    }
+
+    if (format == 19 && c->plan->all_axes_pinned)
+        out->format = 18;
+
+    return_trace (out->src.serialize_subset (c, src, this, instancer));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -683,6 +1100,23 @@ struct PaintScaleAroundCenter
     return_trace (c->check_struct (this) && src.sanitize (c, this));
   }
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    TRACE_PAINT (this);
+    float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
+    float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
+    float tCenterX = centerX + c->instancer (varIdxBase, 2);
+    float tCenterY = centerY + c->instancer (varIdxBase, 3);
+
+    bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
+    bool p2 = c->funcs->push_scale (c->data, sx, sy);
+    bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
+    c->recurse (this+src);
+    if (p3) c->funcs->pop_transform (c->data);
+    if (p2) c->funcs->pop_transform (c->data);
+    if (p1) c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8              format; /* format = 18 (noVar) or 19(Var) */
   Offset24To<Paint>    src; /* Offset (from beginning of PaintScaleAroundCenter table) to Paint subtable. */
   F2DOT14      scaleX;
@@ -697,13 +1131,21 @@ struct PaintScaleUniform
 {
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer,
+               uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
 
-    return_trace (out->src.serialize_subset (c, src, this));
+    if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+      out->scale.set_float (scale.to_float (instancer (varIdxBase, 0)));
+
+    if (format == 21 && c->plan->all_axes_pinned)
+        out->format = 20;
+
+    return_trace (out->src.serialize_subset (c, src, this, instancer));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -712,6 +1154,16 @@ struct PaintScaleUniform
     return_trace (c->check_struct (this) && src.sanitize (c, this));
   }
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    TRACE_PAINT (this);
+    float s = scale.to_float (c->instancer (varIdxBase, 0));
+
+    bool p1 = c->funcs->push_scale (c->data, s, s);
+    c->recurse (this+src);
+    if (p1) c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8              format; /* format = 20 (noVar) or 21(Var) */
   Offset24To<Paint>    src; /* Offset (from beginning of PaintScaleUniform table) to Paint subtable. */
   F2DOT14              scale;
@@ -723,13 +1175,25 @@ struct PaintScaleUniformAroundCenter
 {
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer,
+               uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
 
-    return_trace (out->src.serialize_subset (c, src, this));
+    if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+    {
+      out->scale.set_float (scale.to_float (instancer (varIdxBase, 0)));
+      out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1));
+      out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2));
+    }
+
+    if (format == 23 && c->plan->all_axes_pinned)
+        out->format = 22;
+
+    return_trace (out->src.serialize_subset (c, src, this, instancer));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -738,6 +1202,22 @@ struct PaintScaleUniformAroundCenter
     return_trace (c->check_struct (this) && src.sanitize (c, this));
   }
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    TRACE_PAINT (this);
+    float s = scale.to_float (c->instancer (varIdxBase, 0));
+    float tCenterX = centerX + c->instancer (varIdxBase, 1);
+    float tCenterY = centerY + c->instancer (varIdxBase, 2);
+
+    bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
+    bool p2 = c->funcs->push_scale (c->data, s, s);
+    bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
+    c->recurse (this+src);
+    if (p3) c->funcs->pop_transform (c->data);
+    if (p2) c->funcs->pop_transform (c->data);
+    if (p1) c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8              format; /* format = 22 (noVar) or 23(Var) */
   Offset24To<Paint>    src; /* Offset (from beginning of PaintScaleUniformAroundCenter table) to Paint subtable. */
   F2DOT14      scale;
@@ -751,13 +1231,21 @@ struct PaintRotate
 {
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer,
+               uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
 
-    return_trace (out->src.serialize_subset (c, src, this));
+    if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+      out->angle.set_float (angle.to_float (instancer (varIdxBase, 0)));
+
+    if (format == 25 && c->plan->all_axes_pinned)
+      out->format = 24;
+
+    return_trace (out->src.serialize_subset (c, src, this, instancer));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -766,6 +1254,16 @@ struct PaintRotate
     return_trace (c->check_struct (this) && src.sanitize (c, this));
   }
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    TRACE_PAINT (this);
+    float a = angle.to_float (c->instancer (varIdxBase, 0));
+
+    bool p1 = c->funcs->push_rotate (c->data, a);
+    c->recurse (this+src);
+    if (p1) c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8              format; /* format = 24 (noVar) or 25(Var) */
   Offset24To<Paint>    src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */
   F2DOT14              angle;
@@ -777,13 +1275,25 @@ struct PaintRotateAroundCenter
 {
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer,
+               uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
 
-    return_trace (out->src.serialize_subset (c, src, this));
+    if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+    {
+      out->angle.set_float (angle.to_float (instancer (varIdxBase, 0)));
+      out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1));
+      out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2));
+    }
+
+    if (format ==27 && c->plan->all_axes_pinned)
+        out->format = 26;
+
+    return_trace (out->src.serialize_subset (c, src, this, instancer));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -792,6 +1302,22 @@ struct PaintRotateAroundCenter
     return_trace (c->check_struct (this) && src.sanitize (c, this));
   }
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    TRACE_PAINT (this);
+    float a = angle.to_float (c->instancer (varIdxBase, 0));
+    float tCenterX = centerX + c->instancer (varIdxBase, 1);
+    float tCenterY = centerY + c->instancer (varIdxBase, 2);
+
+    bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
+    bool p2 = c->funcs->push_rotate (c->data, a);
+    bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
+    c->recurse (this+src);
+    if (p3) c->funcs->pop_transform (c->data);
+    if (p2) c->funcs->pop_transform (c->data);
+    if (p1) c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8              format; /* format = 26 (noVar) or 27(Var) */
   Offset24To<Paint>    src; /* Offset (from beginning of PaintRotateAroundCenter table) to Paint subtable. */
   F2DOT14      angle;
@@ -805,13 +1331,24 @@ struct PaintSkew
 {
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer,
+               uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
 
-    return_trace (out->src.serialize_subset (c, src, this));
+    if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+    {
+      out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0)));
+      out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1)));
+    }
+
+    if (format == 29 && c->plan->all_axes_pinned)
+        out->format = 28;
+
+    return_trace (out->src.serialize_subset (c, src, this, instancer));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -820,6 +1357,17 @@ struct PaintSkew
     return_trace (c->check_struct (this) && src.sanitize (c, this));
   }
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    TRACE_PAINT (this);
+    float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
+    float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
+
+    bool p1 = c->funcs->push_skew (c->data, sx, sy);
+    c->recurse (this+src);
+    if (p1) c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8              format; /* format = 28(noVar) or 29 (Var) */
   Offset24To<Paint>    src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */
   F2DOT14              xSkewAngle;
@@ -832,13 +1380,26 @@ struct PaintSkewAroundCenter
 {
   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer,
+               uint32_t varIdxBase) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
 
-    return_trace (out->src.serialize_subset (c, src, this));
+    if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+    {
+      out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0)));
+      out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1)));
+      out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2));
+      out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3));
+    }
+
+    if (format == 31 && c->plan->all_axes_pinned)
+        out->format = 30;
+
+    return_trace (out->src.serialize_subset (c, src, this, instancer));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -847,6 +1408,23 @@ struct PaintSkewAroundCenter
     return_trace (c->check_struct (this) && src.sanitize (c, this));
   }
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    TRACE_PAINT (this);
+    float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
+    float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
+    float tCenterX = centerX + c->instancer (varIdxBase, 2);
+    float tCenterY = centerY + c->instancer (varIdxBase, 3);
+
+    bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
+    bool p2 = c->funcs->push_skew (c->data, sx, sy);
+    bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
+    c->recurse (this+src);
+    if (p3) c->funcs->pop_transform (c->data);
+    if (p2) c->funcs->pop_transform (c->data);
+    if (p1) c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8              format; /* format = 30(noVar) or 31 (Var) */
   Offset24To<Paint>    src; /* Offset (from beginning of PaintSkewAroundCenter table) to Paint subtable. */
   F2DOT14      xSkewAngle;
@@ -861,24 +1439,37 @@ struct PaintComposite
 {
   void closurev1 (hb_colrv1_closure_context_t* c) const;
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
 
-    if (!out->src.serialize_subset (c, src, this)) return_trace (false);
-    return_trace (out->backdrop.serialize_subset (c, backdrop, this));
+    bool ret = false;
+    ret |= out->src.serialize_subset (c, src, this, instancer);
+    ret |= out->backdrop.serialize_subset (c, backdrop, this, instancer);
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+                 c->check_ops (this->min_size) && // PainComposite can get exponential
                   src.sanitize (c, this) &&
                   backdrop.sanitize (c, this));
   }
 
+  void paint_glyph (hb_paint_context_t *c) const
+  {
+    TRACE_PAINT (this);
+    c->recurse (this+backdrop);
+    c->funcs->push_group (c->data);
+    c->recurse (this+src);
+    c->funcs->pop_group (c->data, (hb_paint_composite_mode_t) (int) mode);
+  }
+
   HBUINT8              format; /* format = 32 */
   Offset24To<Paint>    src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */
   CompositeMode                mode;   /* If mode is unrecognized use COMPOSITE_CLEAR */
@@ -887,6 +1478,11 @@ struct PaintComposite
   DEFINE_SIZE_STATIC (8);
 };
 
+struct ClipBoxData
+{
+  int xMin, yMin, xMax, yMax;
+};
+
 struct ClipBoxFormat1
 {
   bool sanitize (hb_sanitize_context_t *c) const
@@ -895,6 +1491,36 @@ struct ClipBoxFormat1
     return_trace (c->check_struct (this));
   }
 
+  void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer HB_UNUSED) const
+  {
+    clip_box.xMin = xMin;
+    clip_box.yMin = yMin;
+    clip_box.xMax = xMax;
+    clip_box.yMax = yMax;
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer,
+               uint32_t varIdxBase) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+
+    if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+    {
+      out->xMin = xMin + (int) roundf (instancer (varIdxBase, 0));
+      out->yMin = yMin + (int) roundf (instancer (varIdxBase, 1));
+      out->xMax = xMax + (int) roundf (instancer (varIdxBase, 2));
+      out->yMax = yMax + (int) roundf (instancer (varIdxBase, 3));
+    }
+
+    if (format == 2 && c->plan->all_axes_pinned)
+        out->format = 1;
+
+    return_trace (true);
+  }
+
   public:
   HBUINT8      format; /* format = 1(noVar) or 2(Var)*/
   FWORD                xMin;
@@ -905,25 +1531,39 @@ struct ClipBoxFormat1
   DEFINE_SIZE_STATIC (1 + 4 * FWORD::static_size);
 };
 
-struct ClipBoxFormat2 : Variable<ClipBoxFormat1> {};
+struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
+{
+  void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer) const
+  {
+    value.get_clip_box(clip_box, instancer);
+    if (instancer)
+    {
+      clip_box.xMin += roundf (instancer (varIdxBase, 0));
+      clip_box.yMin += roundf (instancer (varIdxBase, 1));
+      clip_box.xMax += roundf (instancer (varIdxBase, 2));
+      clip_box.yMax += roundf (instancer (varIdxBase, 3));
+    }
+  }
+};
 
 struct ClipBox
 {
-  ClipBox* copy (hb_serialize_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer) const
   {
-    TRACE_SERIALIZE (this);
+    TRACE_SUBSET (this);
     switch (u.format) {
-    case 1: return_trace (reinterpret_cast<ClipBox *> (c->embed (u.format1)));
-    case 2: return_trace (reinterpret_cast<ClipBox *> (c->embed (u.format2)));
-    default:return_trace (nullptr);
+    case 1: return_trace (u.format1.subset (c, instancer, VarIdx::NO_VARIATION));
+    case 2: return_trace (u.format2.subset (c, instancer));
+    default:return_trace (c->default_return_value ());
     }
   }
 
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
@@ -931,6 +1571,28 @@ struct ClipBox
     }
   }
 
+  bool get_extents (hb_glyph_extents_t *extents,
+                    const VarStoreInstancer &instancer) const
+  {
+    ClipBoxData clip_box;
+    switch (u.format) {
+    case 1:
+      u.format1.get_clip_box (clip_box, instancer);
+      break;
+    case 2:
+      u.format2.get_clip_box (clip_box, instancer);
+      break;
+    default:
+      return false;
+    }
+
+    extents->x_bearing = clip_box.xMin;
+    extents->y_bearing = clip_box.yMax;
+    extents->width = clip_box.xMax - clip_box.xMin;
+    extents->height = clip_box.yMin - clip_box.yMax;
+    return true;
+  }
+
   protected:
   union {
   HBUINT8              format;         /* Format identifier */
@@ -941,13 +1603,18 @@ struct ClipBox
 
 struct ClipRecord
 {
-  ClipRecord* copy (hb_serialize_context_t *c, const void *base) const
+  int cmp (hb_codepoint_t g) const
+  { return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; }
+
+  bool subset (hb_subset_context_t *c,
+               const void *base,
+               const VarStoreInstancer &instancer) const
   {
-    TRACE_SERIALIZE (this);
-    auto *out = c->embed (this);
-    if (unlikely (!out)) return_trace (nullptr);
-    if (!out->clipBox.serialize_copy (c, clipBox, base)) return_trace (nullptr);
-    return_trace (out);
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+
+    return_trace (out->clipBox.serialize_subset (c, clipBox, base, instancer));
   }
 
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
@@ -956,6 +1623,13 @@ struct ClipRecord
     return_trace (c->check_struct (this) && clipBox.sanitize (c, base));
   }
 
+  bool get_extents (hb_glyph_extents_t *extents,
+                   const void *base,
+                   const VarStoreInstancer &instancer) const
+  {
+    return (base+clipBox).get_extents (extents, instancer);
+  }
+
   public:
   HBUINT16             startGlyphID;  // first gid clip applies to
   HBUINT16             endGlyphID;    // last gid clip applies to, inclusive
@@ -963,10 +1637,12 @@ struct ClipRecord
   public:
   DEFINE_SIZE_STATIC (7);
 };
+DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord);
 
 struct ClipList
 {
-  unsigned serialize_clip_records (hb_serialize_context_t *c,
+  unsigned serialize_clip_records (hb_subset_context_t *c,
+                                   const VarStoreInstancer &instancer,
                                    const hb_set_t& gids,
                                    const hb_map_t& gid_offset_map) const
   {
@@ -998,7 +1674,7 @@ struct ClipList
       record.endGlyphID = prev_gid;
       record.clipBox = prev_offset;
 
-      if (!c->copy (record, this)) return_trace (0);
+      if (!record.subset (c, this, instancer)) return_trace (0);
       count++;
 
       start_gid = _;
@@ -1012,20 +1688,21 @@ struct ClipList
       record.startGlyphID = start_gid;
       record.endGlyphID = prev_gid;
       record.clipBox = prev_offset;
-      if (!c->copy (record, this)) return_trace (0);
+      if (!record.subset (c, this, instancer)) return_trace (0);
       count++;
     }
     return_trace (count);
   }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (*this);
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
     if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
 
-    const hb_set_t& glyphset = *c->plan->_glyphset_colred;
+    const hb_set_t& glyphset = c->plan->_glyphset_colred;
     const hb_map_t &glyph_map = *c->plan->glyph_map;
 
     hb_map_t new_gid_offset_map;
@@ -1043,7 +1720,7 @@ struct ClipList
       }
     }
 
-    unsigned count = serialize_clip_records (c->serializer, new_gids, new_gid_offset_map);
+    unsigned count = serialize_clip_records (c, instancer, new_gids, new_gid_offset_map);
     if (!count) return_trace (false);
     return_trace (c->serializer->check_assign (out->clips.len, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
   }
@@ -1051,11 +1728,26 @@ struct ClipList
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
+    // TODO Make a formatted struct!
     return_trace (c->check_struct (this) && clips.sanitize (c, this));
   }
 
+  bool
+  get_extents (hb_codepoint_t gid,
+              hb_glyph_extents_t *extents,
+              const VarStoreInstancer &instancer) const
+  {
+    auto *rec = clips.as_array ().bsearch (gid);
+    if (rec)
+    {
+      rec->get_extents (extents, this, instancer);
+      return true;
+    }
+    return false;
+  }
+
   HBUINT8                      format;  // Set to 1.
-  Array32Of<ClipRecord>                clips;  // Clip records, sorted by startGlyphID
+  SortedArray32Of<ClipRecord>  clips;  // Clip records, sorted by startGlyphID
   public:
   DEFINE_SIZE_ARRAY_SIZED (5, clips);
 };
@@ -1068,7 +1760,7 @@ struct Paint
   {
     TRACE_SANITIZE (this);
 
-    if (unlikely (!c->check_start_recursion (HB_COLRV1_MAX_NESTING_LEVEL)))
+    if (unlikely (!c->check_start_recursion (HB_MAX_NESTING_LEVEL)))
       return_trace (c->no_dispatch_return_value ());
 
     return_trace (c->end_recursion (this->dispatch (c, std::forward<Ts> (ds)...)));
@@ -1077,8 +1769,8 @@ struct Paint
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.paintformat1, std::forward<Ts> (ds)...));
     case 2: return_trace (c->dispatch (u.paintformat2, std::forward<Ts> (ds)...));
@@ -1120,38 +1812,40 @@ struct Paint
   union {
   HBUINT8                                      format;
   PaintColrLayers                              paintformat1;
-  PaintSolid                                   paintformat2;
+  NoVariable<PaintSolid>                       paintformat2;
   Variable<PaintSolid>                         paintformat3;
-  PaintLinearGradient<NoVariable>              paintformat4;
+  NoVariable<PaintLinearGradient<NoVariable>>  paintformat4;
   Variable<PaintLinearGradient<Variable>>      paintformat5;
-  PaintRadialGradient<NoVariable>              paintformat6;
+  NoVariable<PaintRadialGradient<NoVariable>>  paintformat6;
   Variable<PaintRadialGradient<Variable>>      paintformat7;
-  PaintSweepGradient<NoVariable>               paintformat8;
+  NoVariable<PaintSweepGradient<NoVariable>>   paintformat8;
   Variable<PaintSweepGradient<Variable>>       paintformat9;
   PaintGlyph                                   paintformat10;
   PaintColrGlyph                               paintformat11;
   PaintTransform<NoVariable>                   paintformat12;
   PaintTransform<Variable>                     paintformat13;
-  PaintTranslate                               paintformat14;
+  NoVariable<PaintTranslate>                   paintformat14;
   Variable<PaintTranslate>                     paintformat15;
-  PaintScale                                   paintformat16;
+  NoVariable<PaintScale>                       paintformat16;
   Variable<PaintScale>                         paintformat17;
-  PaintScaleAroundCenter                       paintformat18;
+  NoVariable<PaintScaleAroundCenter>           paintformat18;
   Variable<PaintScaleAroundCenter>             paintformat19;
-  PaintScaleUniform                            paintformat20;
+  NoVariable<PaintScaleUniform>                        paintformat20;
   Variable<PaintScaleUniform>                  paintformat21;
-  PaintScaleUniformAroundCenter                        paintformat22;
+  NoVariable<PaintScaleUniformAroundCenter>    paintformat22;
   Variable<PaintScaleUniformAroundCenter>      paintformat23;
-  PaintRotate                                  paintformat24;
+  NoVariable<PaintRotate>                      paintformat24;
   Variable<PaintRotate>                                paintformat25;
-  PaintRotateAroundCenter                      paintformat26;
+  NoVariable<PaintRotateAroundCenter>          paintformat26;
   Variable<PaintRotateAroundCenter>            paintformat27;
-  PaintSkew                                    paintformat28;
+  NoVariable<PaintSkew>                                paintformat28;
   Variable<PaintSkew>                          paintformat29;
-  PaintSkewAroundCenter                                paintformat30;
+  NoVariable<PaintSkewAroundCenter>            paintformat30;
   Variable<PaintSkewAroundCenter>              paintformat31;
   PaintComposite                               paintformat32;
   } u;
+  public:
+  DEFINE_SIZE_MIN (2);
 };
 
 struct BaseGlyphPaintRecord
@@ -1160,7 +1854,8 @@ struct BaseGlyphPaintRecord
   { return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
 
   bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map,
-                  const void* src_base, hb_subset_context_t *c) const
+                  const void* src_base, hb_subset_context_t *c,
+                  const VarStoreInstancer &instancer) const
   {
     TRACE_SERIALIZE (this);
     auto *out = s->embed (this);
@@ -1169,7 +1864,7 @@ struct BaseGlyphPaintRecord
                           HB_SERIALIZE_ERROR_INT_OVERFLOW))
       return_trace (false);
 
-    return_trace (out->paint.serialize_subset (c, paint, src_base));
+    return_trace (out->paint.serialize_subset (c, paint, src_base, instancer));
   }
 
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
@@ -1188,19 +1883,20 @@ struct BaseGlyphPaintRecord
 
 struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
 {
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (this);
     if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
-    const hb_set_t* glyphset = c->plan->_glyphset_colred;
+    const hb_set_t* glyphset = &c->plan->_glyphset_colred;
 
     for (const auto& _ : as_array ())
     {
       unsigned gid = _.glyphId;
       if (!glyphset->has (gid)) continue;
 
-      if (_.serialize (c->serializer, c->plan->glyph_map, this, c)) out->len++;
+      if (_.serialize (c->serializer, c->plan->glyph_map, this, c, instancer)) out->len++;
       else return_trace (false);
     }
 
@@ -1219,21 +1915,23 @@ struct LayerList : Array32OfOffset32To<Paint>
   const Paint& get_paint (unsigned i) const
   { return this+(*this)[i]; }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               const VarStoreInstancer &instancer) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (this);
     if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
 
+    bool ret = false;
     for (const auto& _ : + hb_enumerate (*this)
                          | hb_filter (c->plan->colrv1_layers, hb_first))
 
     {
       auto *o = out->serialize_append (c->serializer);
-      if (unlikely (!o) || !o->serialize_subset (c, _.second, this))
-        return_trace (false);
+      if (unlikely (!o)) return_trace (false);
+      ret |= o->serialize_subset (c, _.second, this, instancer);
     }
-    return_trace (true);
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1247,7 +1945,14 @@ struct COLR
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
 
-  bool has_data () const { return numBaseGlyphs; }
+  bool has_v0_data () const { return numBaseGlyphs; }
+  bool has_v1_data () const
+  {
+    if (version == 1)
+      return (this+baseGlyphList).len > 0;
+
+    return false;
+  }
 
   unsigned int get_glyph_layers (hb_codepoint_t       glyph,
                                 unsigned int         start_offset,
@@ -1356,7 +2061,7 @@ struct COLR
                   (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
                   (this+layersZ).sanitize (c, numLayers) &&
                   (version == 0 ||
-                  (COLRV1_ENABLE_SUBSETTING && version == 1 &&
+                  (version == 1 &&
                    baseGlyphList.sanitize (c, this) &&
                    layerList.sanitize (c, this) &&
                    clipList.sanitize (c, this) &&
@@ -1425,9 +2130,8 @@ struct COLR
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-
     const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
-    const hb_set_t& glyphset = *c->plan->_glyphset_colred;
+    const hb_set_t& glyphset = c->plan->_glyphset_colred;
 
     auto base_it =
     + hb_range (c->plan->num_output_glyphs ())
@@ -1476,7 +2180,7 @@ struct COLR
                                  if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid)))
                                    return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
                                  out_layers[i].glyphId = new_gid;
-                                 out_layers[i].colorIdx = c->plan->colr_palettes->get (layers[i].colorIdx);
+                                 out_layers[i].colorIdx = c->plan->colr_palettes.get (layers[i].colorIdx);
                                }
 
                                return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
@@ -1488,7 +2192,7 @@ struct COLR
     if (version == 0 && (!base_it || !layer_it))
       return_trace (false);
 
-    COLR *colr_prime = c->serializer->start_embed<COLR> ();
+    auto *colr_prime = c->serializer->start_embed<COLR> ();
     if (unlikely (!c->serializer->extend_min (colr_prime)))  return_trace (false);
 
     if (version == 0)
@@ -1496,7 +2200,12 @@ struct COLR
 
     auto snap = c->serializer->snapshot ();
     if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false);
-    if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this))
+
+    VarStoreInstancer instancer (varStore ? &(this+varStore) : nullptr,
+                                varIdxMap ? &(this+varIdxMap) : nullptr,
+                                c->plan->normalized_coords.as_array ());
+
+    if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this, instancer))
     {
       if (c->serializer->in_error ()) return_trace (false);
       //no more COLRv1 glyphs: downgrade to version 0
@@ -1506,13 +2215,182 @@ struct COLR
 
     if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false);
 
-    colr_prime->layerList.serialize_subset (c, layerList, this);
-    colr_prime->clipList.serialize_subset (c, clipList, this);
+    colr_prime->layerList.serialize_subset (c, layerList, this, instancer);
+    colr_prime->clipList.serialize_subset (c, clipList, this, instancer);
+    if (!varStore || c->plan->all_axes_pinned)
+      return_trace (true);
+
     colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this);
-    //TODO: subset varStore once it's implemented in fonttools
+    colr_prime->varStore.serialize_copy (c->serializer, varStore, this);
     return_trace (true);
   }
 
+  const Paint *get_base_glyph_paint (hb_codepoint_t glyph) const
+  {
+    const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList;
+    const BaseGlyphPaintRecord* record = get_base_glyph_paintrecord (glyph);
+    if (record)
+    {
+      const Paint &paint = &baseglyph_paintrecords+record->paint;
+      return &paint;
+    }
+    else
+      return nullptr;
+  }
+
+#ifndef HB_NO_PAINT
+  bool
+  get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
+  {
+    if (version != 1)
+      return false;
+
+    VarStoreInstancer instancer (&(this+varStore),
+                                &(this+varIdxMap),
+                                hb_array (font->coords, font->num_coords));
+
+    if (get_clip (glyph, extents, instancer))
+    {
+      font->scale_glyph_extents (extents);
+      return true;
+    }
+
+    auto *extents_funcs = hb_paint_extents_get_funcs ();
+    hb_paint_extents_context_t extents_data;
+    bool ret = paint_glyph (font, glyph, extents_funcs, &extents_data, 0, HB_COLOR(0,0,0,0));
+
+    hb_extents_t e = extents_data.get_extents ();
+    if (e.is_void ())
+    {
+      extents->x_bearing = 0;
+      extents->y_bearing = 0;
+      extents->width = 0;
+      extents->height = 0;
+    }
+    else
+    {
+      extents->x_bearing = e.xmin;
+      extents->y_bearing = e.ymax;
+      extents->width = e.xmax - e.xmin;
+      extents->height = e.ymin - e.ymax;
+    }
+
+    return ret;
+  }
+#endif
+
+  bool
+  has_paint_for_glyph (hb_codepoint_t glyph) const
+  {
+    if (version == 1)
+    {
+      const Paint *paint = get_base_glyph_paint (glyph);
+
+      return paint != nullptr;
+    }
+
+    return false;
+  }
+
+  bool get_clip (hb_codepoint_t glyph,
+                hb_glyph_extents_t *extents,
+                const VarStoreInstancer instancer) const
+  {
+    return (this+clipList).get_extents (glyph,
+                                       extents,
+                                       instancer);
+  }
+
+#ifndef HB_NO_PAINT
+  bool
+  paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const
+  {
+    VarStoreInstancer instancer (&(this+varStore),
+                                &(this+varIdxMap),
+                                hb_array (font->coords, font->num_coords));
+    hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer);
+    c.current_glyphs.add (glyph);
+
+    if (version == 1)
+    {
+      const Paint *paint = get_base_glyph_paint (glyph);
+      if (paint)
+      {
+        // COLRv1 glyph
+
+       VarStoreInstancer instancer (&(this+varStore),
+                                    &(this+varIdxMap),
+                                    hb_array (font->coords, font->num_coords));
+
+       bool is_bounded = true;
+       if (clip)
+       {
+         hb_glyph_extents_t extents;
+         if (get_clip (glyph, &extents, instancer))
+         {
+           font->scale_glyph_extents (&extents);
+           c.funcs->push_clip_rectangle (c.data,
+                                         extents.x_bearing,
+                                         extents.y_bearing + extents.height,
+                                         extents.x_bearing + extents.width,
+                                         extents.y_bearing);
+         }
+         else
+         {
+           auto *extents_funcs = hb_paint_extents_get_funcs ();
+           hb_paint_extents_context_t extents_data;
+
+           paint_glyph (font, glyph,
+                        extents_funcs, &extents_data,
+                        palette_index, foreground,
+                        false);
+
+           hb_extents_t extents = extents_data.get_extents ();
+           is_bounded = extents_data.is_bounded ();
+
+           c.funcs->push_clip_rectangle (c.data,
+                                         extents.xmin,
+                                         extents.ymin,
+                                         extents.xmax,
+                                         extents.ymax);
+         }
+       }
+
+       c.funcs->push_root_transform (c.data, font);
+
+       if (is_bounded)
+         c.recurse (*paint);
+
+       c.funcs->pop_transform (c.data);
+
+       if (clip)
+         c.funcs->pop_clip (c.data);
+
+        return true;
+      }
+    }
+
+    const BaseGlyphRecord *record = get_base_glyph_record (glyph);
+    if (record && ((hb_codepoint_t) record->glyphId == glyph))
+    {
+      // COLRv0 glyph
+      for (const auto &r : (this+layersZ).as_array (numLayers)
+                          .sub_array (record->firstLayerIdx, record->numLayers))
+      {
+        hb_bool_t is_foreground;
+        hb_color_t color = c.get_color (r.colorIdx, 1., &is_foreground);
+        c.funcs->push_clip_glyph (c.data, r.glyphId, c.font);
+        c.funcs->color (c.data, is_foreground, color);
+        c.funcs->pop_clip (c.data);
+      }
+
+      return true;
+    }
+
+    return false;
+  }
+#endif
+
   protected:
   HBUINT16     version;        /* Table version number (starts at 0). */
   HBUINT16     numBaseGlyphs;  /* Number of Base Glyph Records. */
@@ -1535,7 +2413,76 @@ struct COLR_accelerator_t : COLR::accelerator_t {
   COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {}
 };
 
-} /* namespace OT */
+void
+hb_paint_context_t::recurse (const Paint &paint)
+{
+  if (unlikely (depth_left <= 0 || edge_count <= 0)) return;
+  depth_left--;
+  edge_count--;
+  paint.dispatch (this);
+  depth_left++;
+}
+
+void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const
+{
+  TRACE_PAINT (this);
+  const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList ();
+  for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
+  {
+    if (unlikely (c->current_layers.has (i)))
+      continue;
+
+    c->current_layers.add (i);
+
+    const Paint &paint = paint_offset_lists.get_paint (i);
+    c->funcs->push_group (c->data);
+    c->recurse (paint);
+    c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
+
+    c->current_layers.del (i);
+  }
+}
+
+void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
+{
+  TRACE_PAINT (this);
+
+  if (unlikely (c->current_glyphs.has (gid)))
+    return;
 
+  c->current_glyphs.add (gid);
+
+  c->funcs->push_inverse_root_transform (c->data, c->font);
+  if (c->funcs->color_glyph (c->data, gid, c->font))
+  {
+    c->funcs->pop_transform (c->data);
+    c->current_glyphs.del (gid);
+    return;
+  }
+  c->funcs->pop_transform (c->data);
+
+  const COLR *colr_table = c->get_colr_table ();
+  const Paint *paint = colr_table->get_base_glyph_paint (gid);
+
+  hb_glyph_extents_t extents = {0};
+  bool has_clip_box = colr_table->get_clip (gid, &extents, c->instancer);
+
+  if (has_clip_box)
+    c->funcs->push_clip_rectangle (c->data,
+                                  extents.x_bearing,
+                                  extents.y_bearing + extents.height,
+                                  extents.x_bearing + extents.width,
+                                  extents.y_bearing);
+
+  if (paint)
+    c->recurse (*paint);
+
+  if (has_clip_box)
+    c->funcs->pop_clip (c->data);
+
+  c->current_glyphs.del (gid);
+}
+
+} /* namespace OT */
 
-#endif /* HB_OT_COLOR_COLR_TABLE_HH */
+#endif /* OT_COLOR_COLR_COLR_HH */
similarity index 94%
rename from src/hb-ot-color-colrv1-closure.hh
rename to src/OT/Color/COLR/colrv1-closure.hh
index fbaf2ec..705863d 100644 (file)
  *
  */
 
-#ifndef HB_OT_COLR_COLRV1_CLOSURE_HH
-#define HB_OT_COLR_COLRV1_CLOSURE_HH
+#ifndef OT_COLOR_COLR_COLRV1_CLOSURE_HH
+#define OT_COLOR_COLR_COLRV1_CLOSURE_HH
 
-#include "hb-open-type.hh"
-#include "hb-ot-layout-common.hh"
-#include "hb-ot-color-colr-table.hh"
+#include "../../../hb-open-type.hh"
+#include "COLR.hh"
 
 /*
  * COLR -- Color
@@ -105,4 +104,4 @@ HB_INTERNAL void PaintComposite::closurev1 (hb_colrv1_closure_context_t* c) cons
 } /* namespace OT */
 
 
-#endif /* HB_OT_COLR_COLRV1_CLOSURE_HH */
+#endif /* OT_COLOR_COLR_COLRV1_CLOSURE_HH */
similarity index 75%
rename from src/hb-ot-color-cpal-table.hh
rename to src/OT/Color/CPAL/CPAL.hh
index a9deeba..c07716c 100644 (file)
  * Google Author(s): Sascha Brawer
  */
 
-#ifndef HB_OT_COLOR_CPAL_TABLE_HH
-#define HB_OT_COLOR_CPAL_TABLE_HH
+#ifndef OT_COLOR_CPAL_CPAL_HH
+#define OT_COLOR_CPAL_CPAL_HH
 
-#include "hb-open-type.hh"
-#include "hb-ot-color.h"
-#include "hb-ot-name.h"
+#include "../../../hb-open-type.hh"
+#include "../../../hb-ot-color.h"
+#include "../../../hb-ot-name.h"
 
 
 /*
@@ -73,6 +73,30 @@ struct CPALV1Tail
   }
 
   public:
+  void collect_name_ids (const void *base,
+                         unsigned palette_count,
+                         unsigned color_count,
+                         const hb_map_t *color_index_map,
+                         hb_set_t *nameids_to_retain /* OUT */) const
+  {
+    if (paletteLabelsZ)
+    {
+      + (base+paletteLabelsZ).as_array (palette_count)
+      | hb_sink (nameids_to_retain)
+      ;
+    }
+
+    if (colorLabelsZ)
+    {
+      const hb_array_t<const NameID> colorLabels = (base+colorLabelsZ).as_array (color_count);
+      for (unsigned i = 0; i < color_count; i++)
+      {
+        if (!color_index_map->has (i)) continue;
+        nameids_to_retain->add (colorLabels[i]);
+      }
+    }
+  }
+
   bool serialize (hb_serialize_context_t *c,
                   unsigned palette_count,
                   unsigned color_count,
@@ -95,12 +119,10 @@ struct CPALV1Tail
     if (colorLabelsZ)
     {
       c->push ();
-      for (const auto _ : colorLabels)
+      for (unsigned i = 0; i < color_count; i++)
       {
-        if (!color_index_map->has (_)) continue;
-        NameID new_color_idx;
-        new_color_idx = color_index_map->get (_);
-        if (!c->copy<NameID> (new_color_idx))
+        if (!color_index_map->has (i)) continue;
+        if (!c->copy<NameID> (colorLabels[i]))
         {
           c->pop_discard ();
           return_trace (false);
@@ -188,6 +210,13 @@ struct CPAL
     return numColors;
   }
 
+  void collect_name_ids (const hb_map_t *color_index_map,
+                         hb_set_t *nameids_to_retain /* OUT */) const
+  {
+    if (version == 1)
+      v1 ().collect_name_ids (this, numPalettes, numColors, color_index_map, nameids_to_retain);
+  }
+
   private:
   const CPALV1Tail& v1 () const
   {
@@ -197,30 +226,38 @@ struct CPAL
 
   public:
   bool serialize (hb_serialize_context_t *c,
-                  const hb_array_t<const BGRAColor> &color_records,
                   const hb_array_t<const HBUINT16> &color_record_indices,
-                  const hb_map_t &color_record_index_map,
-                  const hb_set_t &retained_color_record_indices) const
+                  const hb_array_t<const BGRAColor> &color_records,
+                  const hb_vector_t<unsigned>& first_color_index_for_layer,
+                  const hb_map_t& first_color_to_layer_index,
+                  const hb_set_t &retained_color_indices) const
   {
     TRACE_SERIALIZE (this);
 
+    // TODO(grieger): limit total final size.
+
     for (const auto idx : color_record_indices)
     {
+      hb_codepoint_t layer_index = first_color_to_layer_index[idx];
+
       HBUINT16 new_idx;
-      if (idx == 0) new_idx = 0;
-      else new_idx = color_record_index_map.get (idx);
+      new_idx = layer_index * retained_color_indices.get_population ();
       if (!c->copy<HBUINT16> (new_idx)) return_trace (false);
     }
 
     c->push ();
-    for (const auto _ : retained_color_record_indices.iter ())
+    for (unsigned first_color_index : first_color_index_for_layer)
     {
-      if (!c->copy<BGRAColor> (color_records[_]))
+      for (hb_codepoint_t color_index : retained_color_indices)
       {
-        c->pop_discard ();
-        return_trace (false);
+        if (!c->copy<BGRAColor> (color_records[first_color_index + color_index]))
+        {
+          c->pop_discard ();
+          return_trace (false);
+        }
       }
     }
+
     c->add_link (colorRecordsZ, c->pop_pack ());
     return_trace (true);
   }
@@ -228,7 +265,9 @@ struct CPAL
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    const hb_map_t *color_index_map = c->plan->colr_palettes;
+    if (!numPalettes) return_trace (false);
+
+    const hb_map_t *color_index_map = &c->plan->colr_palettes;
     if (color_index_map->is_empty ()) return_trace (false);
 
     hb_set_t retained_color_indices;
@@ -242,30 +281,34 @@ struct CPAL
     auto *out = c->serializer->start_embed (*this);
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
 
+
     out->version = version;
     out->numColors = retained_color_indices.get_population ();
     out->numPalettes = numPalettes;
 
-    const hb_array_t<const HBUINT16> colorRecordIndices = colorRecordIndicesZ.as_array (numPalettes);
-    hb_map_t color_record_index_map;
-    hb_set_t retained_color_record_indices;
+    hb_vector_t<unsigned> first_color_index_for_layer;
+    hb_map_t first_color_to_layer_index;
 
-    unsigned record_count = 0;
+    const hb_array_t<const HBUINT16> colorRecordIndices = colorRecordIndicesZ.as_array (numPalettes);
     for (const auto first_color_record_idx : colorRecordIndices)
     {
-      for (unsigned retained_color_idx : retained_color_indices.iter ())
-      {
-        unsigned color_record_idx = first_color_record_idx + retained_color_idx;
-        if (color_record_index_map.has (color_record_idx)) continue;
-        color_record_index_map.set (color_record_idx, record_count);
-        retained_color_record_indices.add (color_record_idx);
-        record_count++;
-      }
+      if (first_color_to_layer_index.has (first_color_record_idx)) continue;
+
+      first_color_index_for_layer.push (first_color_record_idx);
+      first_color_to_layer_index.set (first_color_record_idx,
+                                      first_color_index_for_layer.length - 1);
     }
 
-    out->numColorRecords = record_count;
+    out->numColorRecords = first_color_index_for_layer.length
+                           * retained_color_indices.get_population ();
+
     const hb_array_t<const BGRAColor> color_records = (this+colorRecordsZ).as_array (numColorRecords);
-    if (!out->serialize (c->serializer, color_records, colorRecordIndices, color_record_index_map, retained_color_record_indices))
+    if (!out->serialize (c->serializer,
+                         colorRecordIndices,
+                         color_records,
+                         first_color_index_for_layer,
+                         first_color_to_layer_index,
+                         retained_color_indices))
       return_trace (false);
 
     if (version == 1)
@@ -304,4 +347,4 @@ struct CPAL
 } /* namespace OT */
 
 
-#endif /* HB_OT_COLOR_CPAL_TABLE_HH */
+#endif /* OT_COLOR_CPAL_CPAL_HH */
similarity index 87%
rename from src/hb-ot-color-sbix-table.hh
rename to src/OT/Color/sbix/sbix.hh
index 9741ebd..ce8693c 100644 (file)
  * Google Author(s): Calder Kitagawa
  */
 
-#ifndef HB_OT_COLOR_SBIX_TABLE_HH
-#define HB_OT_COLOR_SBIX_TABLE_HH
+#ifndef OT_COLOR_SBIX_SBIX_HH
+#define OT_COLOR_SBIX_SBIX_HH
 
-#include "hb-open-type.hh"
-#include "hb-ot-layout-common.hh"
+#include "../../../hb-open-type.hh"
+#include "../../../hb-paint.hh"
 
 /*
  * sbix -- Standard Bitmap Graphics
@@ -48,7 +48,6 @@ struct SBIXGlyph
   {
     TRACE_SERIALIZE (this);
     SBIXGlyph* new_glyph = c->start_embed<SBIXGlyph> ();
-    if (unlikely (!new_glyph)) return_trace (nullptr);
     if (unlikely (!c->extend_min (new_glyph))) return_trace (nullptr);
 
     new_glyph->xOffset = xOffset;
@@ -143,7 +142,6 @@ struct SBIXStrike
     unsigned int num_output_glyphs = c->plan->num_output_glyphs ();
 
     auto* out = c->serializer->start_embed<SBIXStrike> ();
-    if (unlikely (!out)) return_trace (false);
     auto snap = c->serializer->snapshot ();
     if (unlikely (!c->serializer->extend (out, num_output_glyphs + 1))) return_trace (false);
     out->ppem = ppem;
@@ -213,10 +211,11 @@ struct sbix
 
     bool get_extents (hb_font_t          *font,
                      hb_codepoint_t      glyph,
-                     hb_glyph_extents_t *extents) const
+                     hb_glyph_extents_t *extents,
+                     bool                scale = true) const
     {
       /* We only support PNG right now, and following function checks type. */
-      return get_png_extents (font, glyph, extents);
+      return get_png_extents (font, glyph, extents, scale);
     }
 
     hb_blob_t *reference_png (hb_font_t      *font,
@@ -231,6 +230,37 @@ struct sbix
                                                  num_glyphs, available_ppem);
     }
 
+    bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
+    {
+      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);
+      hb_glyph_extents_t extents;
+      hb_glyph_extents_t pixel_extents;
+
+      if (blob == hb_blob_get_empty ())
+        return false;
+
+      if (!hb_font_get_glyph_extents (font, glyph, &extents))
+        return false;
+
+      if (unlikely (!get_extents (font, glyph, &pixel_extents, false)))
+        return false;
+
+      bool ret = funcs->image (data,
+                              blob,
+                              pixel_extents.width, -pixel_extents.height,
+                              HB_PAINT_IMAGE_FORMAT_PNG,
+                              font->slant_xy,
+                              &extents);
+
+      hb_blob_destroy (blob);
+      return ret;
+    }
+
     private:
 
     const SBIXStrike &choose_strike (hb_font_t *font) const
@@ -285,7 +315,8 @@ struct sbix
 
     bool get_png_extents (hb_font_t          *font,
                          hb_codepoint_t      glyph,
-                         hb_glyph_extents_t *extents) const
+                         hb_glyph_extents_t *extents,
+                         bool                scale = true) const
     {
       /* Following code is safe to call even without data.
        * But faster to short-circuit. */
@@ -298,28 +329,30 @@ struct sbix
 
       const PNGHeader &png = *blob->as<PNGHeader>();
 
+      if (png.IHDR.height >= 65536 || png.IHDR.width >= 65536)
+      {
+       hb_blob_destroy (blob);
+       return false;
+      }
+
       extents->x_bearing = x_offset;
       extents->y_bearing = png.IHDR.height + y_offset;
       extents->width     = png.IHDR.width;
       extents->height    = -1 * png.IHDR.height;
 
       /* Convert to font units. */
-      if (strike_ppem)
+      if (strike_ppem && scale)
       {
        float scale = font->face->get_upem () / (float) strike_ppem;
-       extents->x_bearing = font->em_scalef_x (extents->x_bearing * scale);
-       extents->y_bearing = font->em_scalef_y (extents->y_bearing * scale);
-       extents->width = font->em_scalef_x (extents->width * scale);
-       extents->height = font->em_scalef_y (extents->height * scale);
-      }
-      else
-      {
-       extents->x_bearing = font->em_scale_x (extents->x_bearing);
-       extents->y_bearing = font->em_scale_y (extents->y_bearing);
-       extents->width = font->em_scale_x (extents->width);
-       extents->height = font->em_scale_y (extents->height);
+       extents->x_bearing = roundf (extents->x_bearing * scale);
+       extents->y_bearing = roundf (extents->y_bearing * scale);
+       extents->width = roundf (extents->width * scale);
+       extents->height = roundf (extents->height * scale);
       }
 
+      if (scale)
+       font->scale_glyph_extents (extents);
+
       hb_blob_destroy (blob);
 
       return strike_ppem;
@@ -353,7 +386,6 @@ struct sbix
     TRACE_SERIALIZE (this);
 
     auto *out = c->serializer->start_embed<Array32OfOffset32To<SBIXStrike>> ();
-    if (unlikely (!out)) return_trace (false);
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
 
     hb_vector_t<Offset32To<SBIXStrike>*> new_strikes;
@@ -388,8 +420,6 @@ struct sbix
   {
     TRACE_SUBSET (this);
 
-    sbix *sbix_prime = c->serializer->start_embed<sbix> ();
-    if (unlikely (!sbix_prime)) return_trace (false);
     if (unlikely (!c->serializer->embed (this->version))) return_trace (false);
     if (unlikely (!c->serializer->embed (this->flags))) return_trace (false);
 
@@ -414,4 +444,4 @@ struct sbix_accelerator_t : sbix::accelerator_t {
 
 } /* namespace OT */
 
-#endif /* HB_OT_COLOR_SBIX_TABLE_HH */
+#endif /* OT_COLOR_SBIX_SBIX_HH */
similarity index 83%
rename from src/hb-ot-color-svg-table.hh
rename to src/OT/Color/svg/svg.hh
index fc649f1..c7d91b8 100644 (file)
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  */
 
-#ifndef HB_OT_COLOR_SVG_TABLE_HH
-#define HB_OT_COLOR_SVG_TABLE_HH
+#ifndef OT_COLOR_SVG_SVG_HH
+#define OT_COLOR_SVG_SVG_HH
 
-#include "hb-open-type.hh"
+#include "../../../hb-open-type.hh"
+#include "../../../hb-blob.hh"
+#include "../../../hb-paint.hh"
 
 /*
  * SVG -- SVG (Scalable Vector Graphics)
@@ -91,8 +93,31 @@ struct SVG
 
     bool has_data () const { return table->has_data (); }
 
+    bool paint_glyph (hb_font_t *font HB_UNUSED, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
+    {
+      if (!has_data ())
+        return false;
+
+      hb_blob_t *blob = reference_blob_for_glyph (glyph);
+
+      if (blob == hb_blob_get_empty ())
+        return false;
+
+      funcs->image (data,
+                   blob,
+                   0, 0,
+                   HB_PAINT_IMAGE_FORMAT_SVG,
+                   font->slant_xy,
+                   nullptr);
+
+      hb_blob_destroy (blob);
+      return true;
+    }
+
     private:
     hb_blob_ptr_t<SVG> table;
+    public:
+    DEFINE_SIZE_STATIC (sizeof (hb_blob_ptr_t<SVG>));
   };
 
   const SVGDocumentIndexEntry &get_glyph_entry (hb_codepoint_t glyph_id) const
@@ -123,4 +148,4 @@ struct SVG_accelerator_t : SVG::accelerator_t {
 } /* namespace OT */
 
 
-#endif /* HB_OT_COLOR_SVG_TABLE_HH */
+#endif /* OT_COLOR_SVG_SVG_HH */
diff --git a/src/OT/Layout/Common/Coverage.hh b/src/OT/Layout/Common/Coverage.hh
new file mode 100644 (file)
index 0000000..25056c9
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * 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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Garret Rieger
+ */
+
+#ifndef OT_LAYOUT_COMMON_COVERAGE_HH
+#define OT_LAYOUT_COMMON_COVERAGE_HH
+
+#include "../types.hh"
+#include "CoverageFormat1.hh"
+#include "CoverageFormat2.hh"
+
+namespace OT {
+namespace Layout {
+namespace Common {
+
+template<typename Iterator>
+static inline void Coverage_serialize (hb_serialize_context_t *c,
+                                       Iterator it);
+
+struct Coverage
+{
+
+  protected:
+  union {
+  HBUINT16                      format;         /* Format identifier */
+  CoverageFormat1_3<SmallTypes> format1;
+  CoverageFormat2_4<SmallTypes> format2;
+#ifndef HB_NO_BEYOND_64K
+  CoverageFormat1_3<MediumTypes>format3;
+  CoverageFormat2_4<MediumTypes>format4;
+#endif
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, format);
+
+#ifndef HB_OPTIMIZE_SIZE
+  HB_ALWAYS_INLINE
+#endif
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!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));
+#ifndef HB_NO_BEYOND_64K
+    case 3: return_trace (u.format3.sanitize (c));
+    case 4: return_trace (u.format4.sanitize (c));
+#endif
+    default:return_trace (true);
+    }
+  }
+
+  /* Has interface. */
+  unsigned operator [] (hb_codepoint_t k) const { return get (k); }
+  bool has (hb_codepoint_t k) const { return (*this)[k] != NOT_COVERED; }
+  /* Predicate. */
+  bool operator () (hb_codepoint_t k) const { return has (k); }
+
+  unsigned int get (hb_codepoint_t k) const { return get_coverage (k); }
+  unsigned int get_coverage (hb_codepoint_t glyph_id) const
+  {
+    switch (u.format) {
+    case 1: return u.format1.get_coverage (glyph_id);
+    case 2: return u.format2.get_coverage (glyph_id);
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.get_coverage (glyph_id);
+    case 4: return u.format4.get_coverage (glyph_id);
+#endif
+    default:return NOT_COVERED;
+    }
+  }
+
+  unsigned get_population () const
+  {
+    switch (u.format) {
+    case 1: return u.format1.get_population ();
+    case 2: return u.format2.get_population ();
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.get_population ();
+    case 4: return u.format4.get_population ();
+#endif
+    default:return NOT_COVERED;
+    }
+  }
+
+  template <typename Iterator,
+      hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+
+    unsigned count = hb_len (glyphs);
+    unsigned num_ranges = 0;
+    hb_codepoint_t last = (hb_codepoint_t) -2;
+    hb_codepoint_t max = 0;
+    bool unsorted = false;
+    for (auto g: glyphs)
+    {
+      if (last != (hb_codepoint_t) -2 && g < last)
+       unsorted = true;
+      if (last + 1 != g)
+       num_ranges++;
+      last = g;
+      if (g > max) max = g;
+    }
+    u.format = !unsorted && count <= num_ranges * 3 ? 1 : 2;
+
+#ifndef HB_NO_BEYOND_64K
+    if (max > 0xFFFFu)
+      u.format += 2;
+    if (unlikely (max > 0xFFFFFFu))
+#else
+    if (unlikely (max > 0xFFFFu))
+#endif
+    {
+      c->check_success (false, HB_SERIALIZE_ERROR_INT_OVERFLOW);
+      return_trace (false);
+    }
+
+    switch (u.format)
+    {
+    case 1: return_trace (u.format1.serialize (c, glyphs));
+    case 2: return_trace (u.format2.serialize (c, glyphs));
+#ifndef HB_NO_BEYOND_64K
+    case 3: return_trace (u.format3.serialize (c, glyphs));
+    case 4: return_trace (u.format4.serialize (c, glyphs));
+#endif
+    default:return_trace (false);
+    }
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto it =
+    + iter ()
+    | hb_take (c->plan->source->get_num_glyphs ())
+    | hb_map_retains_sorting (c->plan->glyph_map_gsub)
+    | hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; })
+    ;
+
+    // Cache the iterator result as it will be iterated multiple times
+    // by the serialize code below.
+    hb_sorted_vector_t<hb_codepoint_t> glyphs (it);
+    Coverage_serialize (c->serializer, glyphs.iter ());
+    return_trace (bool (glyphs));
+  }
+
+  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);
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.intersects (glyphs);
+    case 4: return u.format4.intersects (glyphs);
+#endif
+    default:return false;
+    }
+  }
+  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);
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.intersects_coverage (glyphs, index);
+    case 4: return u.format4.intersects_coverage (glyphs, index);
+#endif
+    default:return false;
+    }
+  }
+
+  /* Might return false if array looks unsorted.
+   * Used for faster rejection of corrupt data. */
+  template <typename set_t>
+  bool collect_coverage (set_t *glyphs) const
+  {
+    switch (u.format)
+    {
+    case 1: return u.format1.collect_coverage (glyphs);
+    case 2: return u.format2.collect_coverage (glyphs);
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.collect_coverage (glyphs);
+    case 4: return u.format4.collect_coverage (glyphs);
+#endif
+    default:return false;
+    }
+  }
+
+  template <typename IterableOut,
+           hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
+  void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const
+  {
+    switch (u.format)
+    {
+    case 1: return u.format1.intersect_set (glyphs, intersect_glyphs);
+    case 2: return u.format2.intersect_set (glyphs, intersect_glyphs);
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.intersect_set (glyphs, intersect_glyphs);
+    case 4: return u.format4.intersect_set (glyphs, intersect_glyphs);
+#endif
+    default:return ;
+    }
+  }
+
+  struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
+  {
+    static constexpr bool is_sorted_iterator = true;
+    iter_t (const Coverage &c_ = Null (Coverage))
+    {
+      hb_memset (this, 0, sizeof (*this));
+      format = c_.u.format;
+      switch (format)
+      {
+      case 1: u.format1.init (c_.u.format1); return;
+      case 2: u.format2.init (c_.u.format2); return;
+#ifndef HB_NO_BEYOND_64K
+      case 3: u.format3.init (c_.u.format3); return;
+      case 4: u.format4.init (c_.u.format4); return;
+#endif
+      default:                               return;
+      }
+    }
+    bool __more__ () const
+    {
+      switch (format)
+      {
+      case 1: return u.format1.__more__ ();
+      case 2: return u.format2.__more__ ();
+#ifndef HB_NO_BEYOND_64K
+      case 3: return u.format3.__more__ ();
+      case 4: return u.format4.__more__ ();
+#endif
+      default:return false;
+      }
+    }
+    void __next__ ()
+    {
+      switch (format)
+      {
+      case 1: u.format1.__next__ (); break;
+      case 2: u.format2.__next__ (); break;
+#ifndef HB_NO_BEYOND_64K
+      case 3: u.format3.__next__ (); break;
+      case 4: u.format4.__next__ (); break;
+#endif
+      default:                   break;
+      }
+    }
+    typedef hb_codepoint_t __item_t__;
+    __item_t__ __item__ () const { return get_glyph (); }
+
+    hb_codepoint_t get_glyph () const
+    {
+      switch (format)
+      {
+      case 1: return u.format1.get_glyph ();
+      case 2: return u.format2.get_glyph ();
+#ifndef HB_NO_BEYOND_64K
+      case 3: return u.format3.get_glyph ();
+      case 4: return u.format4.get_glyph ();
+#endif
+      default:return 0;
+      }
+    }
+    bool operator != (const iter_t& o) const
+    {
+      if (unlikely (format != o.format)) return true;
+      switch (format)
+      {
+      case 1: return u.format1 != o.u.format1;
+      case 2: return u.format2 != o.u.format2;
+#ifndef HB_NO_BEYOND_64K
+      case 3: return u.format3 != o.u.format3;
+      case 4: return u.format4 != o.u.format4;
+#endif
+      default:return false;
+      }
+    }
+    iter_t __end__ () const
+    {
+      iter_t it = {};
+      it.format = format;
+      switch (format)
+      {
+      case 1: it.u.format1 = u.format1.__end__ (); break;
+      case 2: it.u.format2 = u.format2.__end__ (); break;
+#ifndef HB_NO_BEYOND_64K
+      case 3: it.u.format3 = u.format3.__end__ (); break;
+      case 4: it.u.format4 = u.format4.__end__ (); break;
+#endif
+      default: break;
+      }
+      return it;
+    }
+
+    private:
+    unsigned int format;
+    union {
+#ifndef HB_NO_BEYOND_64K
+    CoverageFormat2_4<MediumTypes>::iter_t      format4; /* Put this one first since it's larger; helps shut up compiler. */
+    CoverageFormat1_3<MediumTypes>::iter_t      format3;
+#endif
+    CoverageFormat2_4<SmallTypes>::iter_t       format2; /* Put this one first since it's larger; helps shut up compiler. */
+    CoverageFormat1_3<SmallTypes>::iter_t       format1;
+    } u;
+  };
+  iter_t iter () const { return iter_t (*this); }
+};
+
+template<typename Iterator>
+static inline void
+Coverage_serialize (hb_serialize_context_t *c,
+                    Iterator it)
+{ c->start_embed<Coverage> ()->serialize (c, it); }
+
+}
+}
+}
+
+#endif  // #ifndef OT_LAYOUT_COMMON_COVERAGE_HH
diff --git a/src/OT/Layout/Common/CoverageFormat1.hh b/src/OT/Layout/Common/CoverageFormat1.hh
new file mode 100644 (file)
index 0000000..3f598d4
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * 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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Garret Rieger
+ */
+
+
+#ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT1_HH
+#define OT_LAYOUT_COMMON_COVERAGEFORMAT1_HH
+
+namespace OT {
+namespace Layout {
+namespace Common {
+
+#define NOT_COVERED             ((unsigned int) -1)
+
+template <typename Types>
+struct CoverageFormat1_3
+{
+  friend struct Coverage;
+
+  protected:
+  HBUINT16      coverageFormat; /* Format identifier--format = 1 */
+  SortedArray16Of<typename Types::HBGlyphID>
+                glyphArray;     /* Array of GlyphIDs--in numerical order */
+  public:
+  DEFINE_SIZE_ARRAY (4, glyphArray);
+
+  private:
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (glyphArray.sanitize (c));
+  }
+
+  unsigned int get_coverage (hb_codepoint_t glyph_id) const
+  {
+    unsigned int i;
+    glyphArray.bfind (glyph_id, &i, HB_NOT_FOUND_STORE, NOT_COVERED);
+    return i;
+  }
+
+  unsigned get_population () const
+  {
+    return glyphArray.len;
+  }
+
+  template <typename Iterator,
+      hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (glyphArray.serialize (c, glyphs));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len) / 2)
+    {
+      for (auto g : *glyphs)
+        if (get_coverage (g) != NOT_COVERED)
+         return true;
+      return false;
+    }
+
+    for (const auto& g : glyphArray.as_array ())
+      if (glyphs->has (g))
+        return true;
+    return false;
+  }
+  bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
+  { return glyphs->has (glyphArray[index]); }
+
+  template <typename IterableOut,
+           hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
+  void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const
+  {
+    unsigned count = glyphArray.len;
+    for (unsigned i = 0; i < count; i++)
+      if (glyphs.has (glyphArray[i]))
+        intersect_glyphs << glyphArray[i];
+  }
+
+  template <typename set_t>
+  bool collect_coverage (set_t *glyphs) const
+  { return glyphs->add_sorted_array (glyphArray.as_array ()); }
+
+  public:
+  /* Older compilers need this to be public. */
+  struct iter_t
+  {
+    void init (const struct CoverageFormat1_3 &c_) { c = &c_; i = 0; }
+    bool __more__ () const { return i < c->glyphArray.len; }
+    void __next__ () { i++; }
+    hb_codepoint_t get_glyph () const { return c->glyphArray[i]; }
+    bool operator != (const iter_t& o) const
+    { return i != o.i; }
+    iter_t __end__ () const { iter_t it; it.init (*c); it.i = c->glyphArray.len; return it; }
+
+    private:
+    const struct CoverageFormat1_3 *c;
+    unsigned int i;
+  };
+  private:
+};
+
+}
+}
+}
+
+#endif  // #ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT1_HH
diff --git a/src/OT/Layout/Common/CoverageFormat2.hh b/src/OT/Layout/Common/CoverageFormat2.hh
new file mode 100644 (file)
index 0000000..9c87542
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * 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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Garret Rieger
+ */
+
+#ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT2_HH
+#define OT_LAYOUT_COMMON_COVERAGEFORMAT2_HH
+
+#include "RangeRecord.hh"
+
+namespace OT {
+namespace Layout {
+namespace Common {
+
+template <typename Types>
+struct CoverageFormat2_4
+{
+  friend struct Coverage;
+
+  protected:
+  HBUINT16      coverageFormat; /* Format identifier--format = 2 */
+  SortedArray16Of<RangeRecord<Types>>
+                rangeRecord;    /* Array of glyph ranges--ordered by
+                                 * Start GlyphID. rangeCount entries
+                                 * long */
+  public:
+  DEFINE_SIZE_ARRAY (4, rangeRecord);
+
+  private:
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (rangeRecord.sanitize (c));
+  }
+
+  unsigned int get_coverage (hb_codepoint_t glyph_id) const
+  {
+    const RangeRecord<Types> &range = rangeRecord.bsearch (glyph_id);
+    return likely (range.first <= range.last)
+         ? (unsigned int) range.value + (glyph_id - range.first)
+         : NOT_COVERED;
+  }
+
+  unsigned get_population () const
+  {
+    typename Types::large_int ret = 0;
+    for (const auto &r : rangeRecord)
+      ret += r.get_population ();
+    return ret > UINT_MAX ? UINT_MAX : (unsigned) ret;
+  }
+
+  template <typename Iterator,
+      hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+
+    unsigned num_ranges = 0;
+    hb_codepoint_t last = (hb_codepoint_t) -2;
+    for (auto g: glyphs)
+    {
+      if (last + 1 != g)
+        num_ranges++;
+      last = g;
+    }
+
+    if (unlikely (!rangeRecord.serialize (c, num_ranges))) return_trace (false);
+    if (!num_ranges) return_trace (true);
+
+    unsigned count = 0;
+    unsigned range = (unsigned) -1;
+    last = (hb_codepoint_t) -2;
+    unsigned unsorted = false;
+    for (auto g: glyphs)
+    {
+      if (last + 1 != g)
+      {
+       if (unlikely (last != (hb_codepoint_t) -2 && last + 1 > g))
+         unsorted = true;
+
+        range++;
+        rangeRecord.arrayZ[range].first = g;
+        rangeRecord.arrayZ[range].value = count;
+      }
+      rangeRecord.arrayZ[range].last = g;
+      last = g;
+      count++;
+    }
+
+    if (unlikely (unsorted))
+      rangeRecord.as_array ().qsort (RangeRecord<Types>::cmp_range);
+
+    return_trace (true);
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
+    {
+      for (auto g : *glyphs)
+        if (get_coverage (g) != NOT_COVERED)
+         return true;
+      return false;
+    }
+
+    return hb_any (+ hb_iter (rangeRecord)
+                   | hb_map ([glyphs] (const RangeRecord<Types> &range) { return range.intersects (*glyphs); }));
+  }
+  bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
+  {
+    auto *range = rangeRecord.as_array ().bsearch (index);
+    if (range)
+      return range->intersects (*glyphs);
+    return false;
+  }
+
+  template <typename IterableOut,
+           hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
+  void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const
+  {
+    /* Break out of loop for overlapping, broken, tables,
+     * to avoid fuzzer timouts. */
+    hb_codepoint_t last = 0;
+    for (const auto& range : rangeRecord)
+    {
+      if (unlikely (range.first < last))
+        break;
+      last = range.last;
+      for (hb_codepoint_t g = range.first - 1;
+          glyphs.next (&g) && g <= last;)
+       intersect_glyphs << g;
+    }
+  }
+
+  template <typename set_t>
+  bool collect_coverage (set_t *glyphs) const
+  {
+    for (const auto& range: rangeRecord)
+      if (unlikely (!range.collect_coverage (glyphs)))
+        return false;
+    return true;
+  }
+
+  public:
+  /* Older compilers need this to be public. */
+  struct iter_t
+  {
+    void init (const CoverageFormat2_4 &c_)
+    {
+      c = &c_;
+      coverage = 0;
+      i = 0;
+      j = c->rangeRecord.len ? c->rangeRecord[0].first : 0;
+      if (unlikely (c->rangeRecord[0].first > c->rangeRecord[0].last))
+      {
+        /* Broken table. Skip. */
+        i = c->rangeRecord.len;
+        j = 0;
+      }
+    }
+    bool __more__ () const { return i < c->rangeRecord.len; }
+    void __next__ ()
+    {
+      if (j >= c->rangeRecord[i].last)
+      {
+        i++;
+        if (__more__ ())
+        {
+          unsigned int old = coverage;
+          j = c->rangeRecord.arrayZ[i].first;
+          coverage = c->rangeRecord.arrayZ[i].value;
+          if (unlikely (coverage != old + 1))
+          {
+            /* Broken table. Skip. Important to avoid DoS.
+             * Also, our callers depend on coverage being
+             * consecutive and monotonically increasing,
+             * ie. iota(). */
+           i = c->rangeRecord.len;
+           j = 0;
+           return;
+          }
+        }
+        else
+          j = 0;
+        return;
+      }
+      coverage++;
+      j++;
+    }
+    hb_codepoint_t get_glyph () const { return j; }
+    bool operator != (const iter_t& o) const
+    { return i != o.i || j != o.j; }
+    iter_t __end__ () const
+    {
+      iter_t it;
+      it.init (*c);
+      it.i = c->rangeRecord.len;
+      it.j = 0;
+      return it;
+    }
+
+    private:
+    const struct CoverageFormat2_4 *c;
+    unsigned int i, coverage;
+    hb_codepoint_t j;
+  };
+  private:
+};
+
+}
+}
+}
+
+#endif  // #ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT2_HH
diff --git a/src/OT/Layout/Common/RangeRecord.hh b/src/OT/Layout/Common/RangeRecord.hh
new file mode 100644 (file)
index 0000000..85aacac
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * 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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Garret Rieger
+ */
+
+#ifndef OT_LAYOUT_COMMON_RANGERECORD_HH
+#define OT_LAYOUT_COMMON_RANGERECORD_HH
+
+namespace OT {
+namespace Layout {
+namespace Common {
+
+template <typename Types>
+struct RangeRecord
+{
+  typename Types::HBGlyphID     first;          /* First GlyphID in the range */
+  typename Types::HBGlyphID     last;           /* Last GlyphID in the range */
+  HBUINT16                      value;          /* Value */
+
+  DEFINE_SIZE_STATIC (2 + 2 * Types::size);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  int cmp (hb_codepoint_t g) const
+  { return g < first ? -1 : g <= last ? 0 : +1; }
+
+  HB_INTERNAL static int cmp_range (const void *pa, const void *pb) {
+    const RangeRecord *a = (const RangeRecord *) pa;
+    const RangeRecord *b = (const RangeRecord *) pb;
+    if (a->first < b->first) return -1;
+    if (a->first > b->first) return +1;
+    if (a->last < b->last) return -1;
+    if (a->last > b->last) return +1;
+    if (a->value < b->value) return -1;
+    if (a->value > b->value) return +1;
+    return 0;
+  }
+
+  unsigned get_population () const
+  {
+    if (unlikely (last < first)) return 0;
+    return (last - first + 1);
+  }
+
+  bool intersects (const hb_set_t &glyphs) const
+  { return glyphs.intersects (first, last); }
+
+  template <typename set_t>
+  bool collect_coverage (set_t *glyphs) const
+  { return glyphs->add_range (first, last); }
+};
+
+}
+}
+}
+
+// TODO(garretrieger): This was previously implemented using
+//    DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (OT, RangeRecord, 9);
+//    but that only works when there is only a single namespace level.
+//    The macro should probably be fixed so it can work in this situation.
+extern HB_INTERNAL const unsigned char _hb_Null_OT_RangeRecord[9];
+template <typename Spec>
+struct Null<OT::Layout::Common::RangeRecord<Spec>> {
+  static OT::Layout::Common::RangeRecord<Spec> const & get_null () {
+    return *reinterpret_cast<const OT::Layout::Common::RangeRecord<Spec> *> (_hb_Null_OT_RangeRecord);
+  }
+};
+
+
+#endif  // #ifndef OT_LAYOUT_COMMON_RANGERECORD_HH
diff --git a/src/OT/Layout/GDEF/GDEF.hh b/src/OT/Layout/GDEF/GDEF.hh
new file mode 100644 (file)
index 0000000..dd025c1
--- /dev/null
@@ -0,0 +1,1022 @@
+/*
+ * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * Copyright © 2010,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 OT_LAYOUT_GDEF_GDEF_HH
+#define OT_LAYOUT_GDEF_GDEF_HH
+
+#include "../../../hb-ot-var-common.hh"
+
+#include "../../../hb-font.hh"
+#include "../../../hb-cache.hh"
+
+
+namespace OT {
+
+
+/*
+ * Attachment List Table
+ */
+
+/* Array of contour point indices--in increasing numerical order */
+struct AttachPoint : Array16Of<HBUINT16>
+{
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    return_trace (out->serialize (c->serializer, + iter ()));
+  }
+};
+
+struct AttachList
+{
+  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)
+    {
+      if (point_count)
+       *point_count = 0;
+      return 0;
+    }
+
+    const AttachPoint &points = this+attachPoint[index];
+
+    if (point_count)
+    {
+      + points.as_array ().sub_array (start_offset, point_count)
+      | hb_sink (hb_array (point_array, *point_count))
+      ;
+    }
+
+    return points.len;
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, attachPoint)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
+    return_trace (bool (new_coverage));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
+  }
+
+  protected:
+  Offset16To<Coverage>
+               coverage;               /* Offset to Coverage table -- from
+                                        * beginning of AttachList table */
+  Array16OfOffset16To<AttachPoint>
+               attachPoint;            /* Array of AttachPoint tables
+                                        * in Coverage Index order */
+  public:
+  DEFINE_SIZE_ARRAY (4, attachPoint);
+};
+
+/*
+ * Ligature Caret Table
+ */
+
+struct CaretValueFormat1
+{
+  friend struct CaretValue;
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+    return_trace (true);
+  }
+
+  private:
+  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);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  protected:
+  HBUINT16     caretValueFormat;       /* Format identifier--format = 1 */
+  FWORD                coordinate;             /* X or Y value, in design units */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+struct CaretValueFormat2
+{
+  friend struct CaretValue;
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+    return_trace (true);
+  }
+
+  private:
+  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;
+    font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y);
+    return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  protected:
+  HBUINT16     caretValueFormat;       /* Format identifier--format = 2 */
+  HBUINT16     caretValuePoint;        /* Contour point index on glyph */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+struct CaretValueFormat3
+{
+  friend struct CaretValue;
+
+  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);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (!c->serializer->embed (caretValueFormat)) return_trace (false);
+    if (!c->serializer->embed (coordinate)) return_trace (false);
+
+    unsigned varidx = (this+deviceTable).get_variation_index ();
+    hb_pair_t<unsigned, int> *new_varidx_delta;
+    if (!c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta))
+      return_trace (false);
+
+    uint32_t new_varidx = hb_first (*new_varidx_delta);
+    int delta = hb_second (*new_varidx_delta);
+    if (delta != 0)
+    {
+      if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+        return_trace (false);
+    }
+
+    if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
+      return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
+
+    if (!c->serializer->embed (deviceTable))
+      return_trace (false);
+
+    return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out),
+                                                  hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map));
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  { (this+deviceTable).collect_variation_indices (c); }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
+  }
+
+  protected:
+  HBUINT16     caretValueFormat;       /* Format identifier--format = 3 */
+  FWORD                coordinate;             /* X or Y value, in design units */
+  Offset16To<Device>
+               deviceTable;            /* Offset to Device table for X or Y
+                                        * value--from beginning of CaretValue
+                                        * table */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+struct CaretValue
+{
+  hb_position_t get_caret_value (hb_font_t *font,
+                                hb_direction_t direction,
+                                hb_codepoint_t glyph_id,
+                                const VariationStore &var_store) const
+  {
+    switch (u.format) {
+    case 1: return u.format1.get_caret_value (font, direction);
+    case 2: return u.format2.get_caret_value (font, direction, glyph_id);
+    case 3: return u.format3.get_caret_value (font, direction, var_store);
+    default:return 0;
+    }
+  }
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format);
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    switch (u.format) {
+    case 1:
+    case 2:
+      return;
+    case 3:
+      u.format3.collect_variation_indices (c);
+      return;
+    default: return;
+    }
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!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));
+    case 3: return_trace (u.format3.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  protected:
+  union {
+  HBUINT16             format;         /* Format identifier */
+  CaretValueFormat1    format1;
+  CaretValueFormat2    format2;
+  CaretValueFormat3    format3;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, format);
+};
+
+struct LigGlyph
+{
+  unsigned get_lig_carets (hb_font_t            *font,
+                          hb_direction_t        direction,
+                          hb_codepoint_t        glyph_id,
+                          const VariationStore &var_store,
+                          unsigned              start_offset,
+                          unsigned             *caret_count /* IN/OUT */,
+                          hb_position_t        *caret_array /* OUT */) const
+  {
+    if (caret_count)
+    {
+      + carets.as_array ().sub_array (start_offset, caret_count)
+      | hb_map (hb_add (this))
+      | hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); })
+      | hb_sink (hb_array (caret_array, *caret_count))
+      ;
+    }
+
+    return carets.len;
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    + hb_iter (carets)
+    | hb_apply (subset_offset_array (c, out->carets, this))
+    ;
+
+    return_trace (bool (out->carets));
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    for (const Offset16To<CaretValue>& offset : carets.iter ())
+      (this+offset).collect_variation_indices (c);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (carets.sanitize (c, this));
+  }
+
+  protected:
+  Array16OfOffset16To<CaretValue>
+               carets;                 /* Offset array of CaretValue tables
+                                        * --from beginning of LigGlyph table
+                                        * --in increasing coordinate order */
+  public:
+  DEFINE_SIZE_ARRAY (2, carets);
+};
+
+struct LigCaretList
+{
+  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)
+    {
+      if (caret_count)
+       *caret_count = 0;
+      return 0;
+    }
+    const LigGlyph &lig_glyph = this+ligGlyph[index];
+    return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, ligGlyph)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
+    return_trace (bool (new_coverage));
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    + hb_zip (this+coverage, ligGlyph)
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); })
+    ;
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
+  }
+
+  protected:
+  Offset16To<Coverage>
+               coverage;               /* Offset to Coverage table--from
+                                        * beginning of LigCaretList table */
+  Array16OfOffset16To<LigGlyph>
+               ligGlyph;               /* Array of LigGlyph tables
+                                        * in Coverage Index order */
+  public:
+  DEFINE_SIZE_ARRAY (4, ligGlyph);
+};
+
+
+struct MarkGlyphSetsFormat1
+{
+  bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
+  { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
+
+  template <typename set_t>
+  void collect_coverage (hb_vector_t<set_t> &sets) const
+  {
+     for (const auto &offset : coverage)
+     {
+       const auto &cov = this+offset;
+       cov.collect_coverage (sets.push ());
+     }
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    bool ret = true;
+    for (const Offset32To<Coverage>& offset : coverage.iter ())
+    {
+      auto *o = out->coverage.serialize_append (c->serializer);
+      if (unlikely (!o))
+      {
+       ret = false;
+       break;
+      }
+
+      //not using o->serialize_subset (c, offset, this, out) here because
+      //OTS doesn't allow null offset.
+      //See issue: https://github.com/khaledhosny/ots/issues/172
+      c->serializer->push ();
+      c->dispatch (this+offset);
+      c->serializer->add_link (*o, c->serializer->pop_pack ());
+    }
+
+    return_trace (ret && out->coverage.len);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this));
+  }
+
+  protected:
+  HBUINT16     format;                 /* Format identifier--format = 1 */
+  Array16Of<Offset32To<Coverage>>
+               coverage;               /* Array of long offsets to mark set
+                                        * coverage tables */
+  public:
+  DEFINE_SIZE_ARRAY (4, coverage);
+};
+
+struct MarkGlyphSets
+{
+  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);
+    default:return false;
+    }
+  }
+
+  template <typename set_t>
+  void collect_coverage (hb_vector_t<set_t> &sets) const
+  {
+    switch (u.format) {
+    case 1: u.format1.collect_coverage (sets); return;
+    default:return;
+    }
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    switch (u.format) {
+    case 1: return_trace (u.format1.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);
+    switch (u.format) {
+    case 1: return_trace (u.format1.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  protected:
+  union {
+  HBUINT16             format;         /* Format identifier */
+  MarkGlyphSetsFormat1 format1;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, format);
+};
+
+
+/*
+ * GDEF -- Glyph Definition
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
+ */
+
+
+template <typename Types>
+struct GDEFVersion1_2
+{
+  friend struct GDEF;
+
+  protected:
+  FixedVersion<>version;               /* Version of the GDEF table--currently
+                                        * 0x00010003u */
+  typename Types::template OffsetTo<ClassDef>
+               glyphClassDef;          /* Offset to class definition table
+                                        * for glyph type--from beginning of
+                                        * GDEF header (may be Null) */
+  typename Types::template OffsetTo<AttachList>
+               attachList;             /* Offset to list of glyphs with
+                                        * attachment points--from beginning
+                                        * of GDEF header (may be Null) */
+  typename Types::template OffsetTo<LigCaretList>
+               ligCaretList;           /* Offset to list of positioning points
+                                        * for ligature carets--from beginning
+                                        * of GDEF header (may be Null) */
+  typename Types::template OffsetTo<ClassDef>
+               markAttachClassDef;     /* Offset to class definition table for
+                                        * mark attachment type--from beginning
+                                        * of GDEF header (may be Null) */
+  typename Types::template OffsetTo<MarkGlyphSets>
+               markGlyphSetsDef;       /* Offset to the table of mark set
+                                        * definitions--from beginning of GDEF
+                                        * header (may be NULL).  Introduced
+                                        * in version 0x00010002. */
+  Offset32To<VariationStore>
+               varStore;               /* Offset to the table of Item Variation
+                                        * Store--from beginning of GDEF
+                                        * header (may be NULL).  Introduced
+                                        * in version 0x00010003. */
+  public:
+  DEFINE_SIZE_MIN (4 + 4 * Types::size);
+
+  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 sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (version.sanitize (c) &&
+                 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)));
+  }
+
+  static void remap_varidx_after_instantiation (const hb_map_t& varidx_map,
+                                                hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>>& layout_variation_idx_delta_map /* IN/OUT */)
+  {
+    /* varidx_map is empty which means varstore is empty after instantiation,
+     * no variations, map all varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX.
+     * varidx_map doesn't have original varidx, indicating delta row is all
+     * zeros, map varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */
+    for (auto _ : layout_variation_idx_delta_map.iter_ref ())
+    {
+      /* old_varidx->(varidx, delta) mapping generated for subsetting, then this
+       * varidx is used as key of varidx_map during instantiation */
+      uint32_t varidx = _.second.first;
+      uint32_t *new_varidx;
+      if (varidx_map.has (varidx, &new_varidx))
+        _.second.first = *new_varidx;
+      else
+        _.second.first = HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
+    }
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+
+    bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
+    bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
+    bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
+    bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
+
+    bool subset_markglyphsetsdef = false;
+    if (version.to_int () >= 0x00010002u)
+    {
+      subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
+    }
+
+    bool subset_varstore = false;
+    if (version.to_int () >= 0x00010003u)
+    {
+      if (c->plan->all_axes_pinned)
+        out->varStore = 0;
+      else if (c->plan->normalized_coords)
+      {
+        if (varStore)
+        {
+          item_variations_t item_vars;
+          if (item_vars.instantiate (this+varStore, c->plan, true, true,
+                                     c->plan->gdef_varstore_inner_maps.as_array ()))
+            subset_varstore = out->varStore.serialize_serialize (c->serializer,
+                                                                 item_vars.has_long_word (),
+                                                                 c->plan->axis_tags,
+                                                                 item_vars.get_region_list (),
+                                                                 item_vars.get_vardata_encodings ());
+          remap_varidx_after_instantiation (item_vars.get_varidx_map (),
+                                            c->plan->layout_variation_idx_delta_map);
+        }
+      }
+      else
+        subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
+    }
+
+    if (subset_varstore)
+    {
+      out->version.minor = 3;
+    } else if (subset_markglyphsetsdef) {
+      out->version.minor = 2;
+    } else  {
+      out->version.minor = 0;
+    }
+
+    return_trace (subset_glyphclassdef || subset_attachlist ||
+                 subset_ligcaretlist || subset_markattachclassdef ||
+                 (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
+                 (out->version.to_int () >= 0x00010003u && subset_varstore));
+  }
+};
+
+struct GDEF
+{
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
+
+  enum GlyphClasses {
+    UnclassifiedGlyph  = 0,
+    BaseGlyph          = 1,
+    LigatureGlyph      = 2,
+    MarkGlyph          = 3,
+    ComponentGlyph     = 4
+  };
+
+  unsigned int get_size () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.get_size ();
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.get_size ();
+#endif
+    default: return u.version.static_size;
+    }
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!u.version.sanitize (c))) return_trace (false);
+    switch (u.version.major) {
+    case 1: return_trace (u.version1.sanitize (c));
+#ifndef HB_NO_BEYOND_64K
+    case 2: return_trace (u.version2.sanitize (c));
+#endif
+    default: return_trace (true);
+    }
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.subset (c);
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.subset (c);
+#endif
+    default: return false;
+    }
+  }
+
+  bool has_glyph_classes () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.glyphClassDef != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.glyphClassDef != 0;
+#endif
+    default: return false;
+    }
+  }
+  const ClassDef &get_glyph_class_def () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.glyphClassDef;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.glyphClassDef;
+#endif
+    default: return Null(ClassDef);
+    }
+  }
+  bool has_attach_list () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.attachList != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.attachList != 0;
+#endif
+    default: return false;
+    }
+  }
+  const AttachList &get_attach_list () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.attachList;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.attachList;
+#endif
+    default: return Null(AttachList);
+    }
+  }
+  bool has_lig_carets () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.ligCaretList != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.ligCaretList != 0;
+#endif
+    default: return false;
+    }
+  }
+  const LigCaretList &get_lig_caret_list () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.ligCaretList;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.ligCaretList;
+#endif
+    default: return Null(LigCaretList);
+    }
+  }
+  bool has_mark_attachment_types () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.markAttachClassDef != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.markAttachClassDef != 0;
+#endif
+    default: return false;
+    }
+  }
+  const ClassDef &get_mark_attach_class_def () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.markAttachClassDef;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.markAttachClassDef;
+#endif
+    default: return Null(ClassDef);
+    }
+  }
+  bool has_mark_glyph_sets () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version.to_int () >= 0x00010002u && u.version1.markGlyphSetsDef != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.markGlyphSetsDef != 0;
+#endif
+    default: return false;
+    }
+  }
+  const MarkGlyphSets &get_mark_glyph_sets () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version.to_int () >= 0x00010002u ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets);
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.markGlyphSetsDef;
+#endif
+    default: return Null(MarkGlyphSets);
+    }
+  }
+  bool has_var_store () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version.to_int () >= 0x00010003u && u.version1.varStore != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.varStore != 0;
+#endif
+    default: return false;
+    }
+  }
+  const VariationStore &get_var_store () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(VariationStore);
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.varStore;
+#endif
+    default: return Null(VariationStore);
+    }
+  }
+
+
+  bool has_data () const { return u.version.to_int (); }
+  unsigned int get_glyph_class (hb_codepoint_t glyph) const
+  { return get_glyph_class_def ().get_class (glyph); }
+  void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
+  { get_glyph_class_def ().collect_class (glyphs, klass); }
+
+  unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
+  { return get_mark_attach_class_def ().get_class (glyph); }
+
+  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 get_attach_list ().get_attach_points (glyph_id, start_offset, point_count, point_array); }
+
+  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 get_lig_caret_list ().get_lig_carets (font,
+                                                direction, glyph_id, get_var_store(),
+                                                start_offset, caret_count, caret_array); }
+
+  bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
+  { return get_mark_glyph_sets ().covers (set_index, glyph_id); }
+
+  /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
+   * 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. */
+  unsigned int get_glyph_props (hb_codepoint_t glyph) const
+  {
+    unsigned int klass = get_glyph_class (glyph);
+
+    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), "");
+    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), "");
+    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), "");
+
+    switch (klass) {
+    default:                   return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
+    case BaseGlyph:            return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
+    case LigatureGlyph:                return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
+    case MarkGlyph:
+         klass = get_mark_attachment_type (glyph);
+         return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
+    }
+  }
+
+  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
+                                  hb_face_t *face) const;
+
+  struct accelerator_t
+  {
+    accelerator_t (hb_face_t *face)
+    {
+      table = hb_sanitize_context_t ().reference_table<GDEF> (face);
+      if (unlikely (table->is_blocklisted (table.get_blob (), face)))
+      {
+       hb_blob_destroy (table.get_blob ());
+       table = hb_blob_get_empty ();
+      }
+
+#ifndef HB_NO_GDEF_CACHE
+      table->get_mark_glyph_sets ().collect_coverage (mark_glyph_set_digests);
+#endif
+    }
+    ~accelerator_t () { table.destroy (); }
+
+    unsigned int get_glyph_props (hb_codepoint_t glyph) const
+    {
+      unsigned v;
+
+#ifndef HB_NO_GDEF_CACHE
+      if (glyph_props_cache.get (glyph, &v))
+        return v;
+#endif
+
+      v = table->get_glyph_props (glyph);
+
+#ifndef HB_NO_GDEF_CACHE
+      if (likely (table.get_blob ())) // Don't try setting if we are the null instance!
+       glyph_props_cache.set (glyph, v);
+#endif
+
+      return v;
+
+    }
+
+    bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
+    {
+      return
+#ifndef HB_NO_GDEF_CACHE
+            mark_glyph_set_digests[set_index].may_have (glyph_id) &&
+#endif
+            table->mark_set_covers (set_index, glyph_id);
+    }
+
+    hb_blob_ptr_t<GDEF> table;
+#ifndef HB_NO_GDEF_CACHE
+    hb_vector_t<hb_set_digest_t> mark_glyph_set_digests;
+    mutable hb_cache_t<21, 3, 8> glyph_props_cache;
+#endif
+  };
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  { get_lig_caret_list ().collect_variation_indices (c); }
+
+  void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
+                                      const hb_vector_t<int>& normalized_coords,
+                                      bool calculate_delta, /* not pinned at default */
+                                      bool no_variations, /* all axes pinned */
+                                      hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const
+  {
+    if (!has_var_store ()) return;
+    const VariationStore &var_store = get_var_store ();
+    float *store_cache = var_store.create_cache ();
+    
+    unsigned new_major = 0, new_minor = 0;
+    unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
+    for (unsigned idx : layout_variation_indices->iter ())
+    {
+      int delta = 0;
+      if (calculate_delta)
+        delta = roundf (var_store.get_delta (idx, normalized_coords.arrayZ,
+                                             normalized_coords.length, store_cache));
+
+      if (no_variations)
+      {
+        layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (HB_OT_LAYOUT_NO_VARIATIONS_INDEX, delta));
+        continue;
+      }
+
+      uint16_t major = idx >> 16;
+      if (major >= var_store.get_sub_table_count ()) break;
+      if (major != last_major)
+      {
+       new_minor = 0;
+       ++new_major;
+      }
+
+      unsigned new_idx = (new_major << 16) + new_minor;
+      layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (new_idx, delta));
+      ++new_minor;
+      last_major = major;
+    }
+    var_store.destroy_cache (store_cache);
+  }
+
+  protected:
+  union {
+  FixedVersion<>               version;        /* Version identifier */
+  GDEFVersion1_2<SmallTypes>   version1;
+#ifndef HB_NO_BEYOND_64K
+  GDEFVersion1_2<MediumTypes>  version2;
+#endif
+  } u;
+  public:
+  DEFINE_SIZE_MIN (4);
+};
+
+struct GDEF_accelerator_t : GDEF::accelerator_t {
+  GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {}
+};
+
+} /* namespace OT */
+
+
+#endif /* OT_LAYOUT_GDEF_GDEF_HH */
diff --git a/src/OT/Layout/GPOS/Anchor.hh b/src/OT/Layout/GPOS/Anchor.hh
new file mode 100644 (file)
index 0000000..49e76e7
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef OT_LAYOUT_GPOS_ANCHOR_HH
+#define OT_LAYOUT_GPOS_ANCHOR_HH
+
+#include "AnchorFormat1.hh"
+#include "AnchorFormat2.hh"
+#include "AnchorFormat3.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct Anchor
+{
+  protected:
+  union {
+  HBUINT16              format;         /* Format identifier */
+  AnchorFormat1         format1;
+  AnchorFormat2         format2;
+  AnchorFormat3         format3;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, format);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!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));
+    case 3: return_trace (u.format3.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  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) {
+    case 1: u.format1.get_anchor (c, glyph_id, x, y); return;
+    case 2: u.format2.get_anchor (c, glyph_id, x, y); return;
+    case 3: u.format3.get_anchor (c, glyph_id, x, y); return;
+    default:                                          return;
+    }
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    switch (u.format) {
+    case 1: return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
+    case 2:
+      if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+      {
+        // AnchorFormat 2 just containins extra hinting information, so
+        // if hints are being dropped convert to format 1.
+        return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
+      }
+      return_trace (bool (reinterpret_cast<Anchor *> (u.format2.copy (c->serializer))));
+    case 3: return_trace (u.format3.subset (c));
+    default:return_trace (false);
+    }
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    switch (u.format) {
+    case 1: case 2:
+      return;
+    case 3:
+      u.format3.collect_variation_indices (c);
+      return;
+    default: return;
+    }
+  }
+};
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_ANCHOR_HH
diff --git a/src/OT/Layout/GPOS/AnchorFormat1.hh b/src/OT/Layout/GPOS/AnchorFormat1.hh
new file mode 100644 (file)
index 0000000..738cc31
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef OT_LAYOUT_GPOS_ANCHORFORMAT1_HH
+#define OT_LAYOUT_GPOS_ANCHORFORMAT1_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct AnchorFormat1
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  FWORD         xCoordinate;            /* Horizontal value--in design units */
+  FWORD         yCoordinate;            /* Vertical value--in design units */
+  public:
+  DEFINE_SIZE_STATIC (6);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  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);
+  }
+
+  AnchorFormat1* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    AnchorFormat1* out = c->embed<AnchorFormat1> (this);
+    if (!out) return_trace (out);
+    out->format = 1;
+    return_trace (out);
+  }
+};
+
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_ANCHORFORMAT1_HH
diff --git a/src/OT/Layout/GPOS/AnchorFormat2.hh b/src/OT/Layout/GPOS/AnchorFormat2.hh
new file mode 100644 (file)
index 0000000..70b4d19
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef OT_LAYOUT_GPOS_ANCHORFORMAT2_HH
+#define OT_LAYOUT_GPOS_ANCHORFORMAT2_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct AnchorFormat2
+{
+
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 2 */
+  FWORD         xCoordinate;            /* Horizontal value--in design units */
+  FWORD         yCoordinate;            /* Vertical value--in design units */
+  HBUINT16      anchorPoint;            /* Index to glyph contour point */
+  public:
+  DEFINE_SIZE_STATIC (8);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  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;
+
+#ifdef HB_NO_HINTING
+    *x = font->em_fscale_x (xCoordinate);
+    *y = font->em_fscale_y (yCoordinate);
+    return;
+#endif
+
+    unsigned int x_ppem = font->x_ppem;
+    unsigned int y_ppem = font->y_ppem;
+    hb_position_t cx = 0, cy = 0;
+    bool ret;
+
+    ret = (x_ppem || y_ppem) &&
+          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);
+  }
+
+  AnchorFormat2* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (c->embed<AnchorFormat2> (this));
+  }
+};
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_ANCHORFORMAT2_HH
diff --git a/src/OT/Layout/GPOS/AnchorFormat3.hh b/src/OT/Layout/GPOS/AnchorFormat3.hh
new file mode 100644 (file)
index 0000000..56eda4a
--- /dev/null
@@ -0,0 +1,114 @@
+#ifndef OT_LAYOUT_GPOS_ANCHORFORMAT3_HH
+#define OT_LAYOUT_GPOS_ANCHORFORMAT3_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct AnchorFormat3
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 3 */
+  FWORD         xCoordinate;            /* Horizontal value--in design units */
+  FWORD         yCoordinate;            /* Vertical value--in design units */
+  Offset16To<Device>
+                xDeviceTable;           /* Offset to Device table for X
+                                         * coordinate-- from beginning of
+                                         * Anchor table (may be NULL) */
+  Offset16To<Device>
+                yDeviceTable;           /* Offset to Device table for Y
+                                         * coordinate-- from beginning of
+                                         * Anchor table (may be NULL) */
+  public:
+  DEFINE_SIZE_STATIC (10);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this))) return_trace (false);
+
+    return_trace (xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
+  }
+
+  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);
+
+    if ((font->x_ppem || font->num_coords) && xDeviceTable.sanitize (&c->sanitizer, this))
+      *x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache);
+    if ((font->y_ppem || font->num_coords) && yDeviceTable.sanitize (&c->sanitizer, this))
+      *y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->embed (format))) return_trace (false);
+    if (unlikely (!c->serializer->embed (xCoordinate))) return_trace (false);
+    if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false);
+
+    unsigned x_varidx = xDeviceTable ? (this+xDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
+    if (x_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
+    {
+      hb_pair_t<unsigned, int> *new_varidx_delta;
+      if (!c->plan->layout_variation_idx_delta_map.has (x_varidx, &new_varidx_delta))
+        return_trace (false);
+     
+      x_varidx = hb_first (*new_varidx_delta);
+      int delta = hb_second (*new_varidx_delta);
+      if (delta != 0)
+      {
+        if (!c->serializer->check_assign (out->xCoordinate, xCoordinate + delta,
+                                          HB_SERIALIZE_ERROR_INT_OVERFLOW))
+          return_trace (false);
+      }
+    }
+
+    unsigned y_varidx = yDeviceTable ? (this+yDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
+    if (y_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
+    {
+      hb_pair_t<unsigned, int> *new_varidx_delta;
+      if (!c->plan->layout_variation_idx_delta_map.has (y_varidx, &new_varidx_delta))
+        return_trace (false);
+
+      y_varidx = hb_first (*new_varidx_delta);
+      int delta = hb_second (*new_varidx_delta);
+      if (delta != 0)
+      {
+        if (!c->serializer->check_assign (out->yCoordinate, yCoordinate + delta,
+                                          HB_SERIALIZE_ERROR_INT_OVERFLOW))
+          return_trace (false);
+      }
+    }
+
+    /* in case that all axes are pinned or no variations after instantiation,
+     * both var_idxes will be mapped to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */
+    if (x_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX &&
+        y_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
+      return_trace (c->serializer->check_assign (out->format, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
+
+    if (!c->serializer->embed (xDeviceTable)) return_trace (false);
+    if (!c->serializer->embed (yDeviceTable)) return_trace (false);
+
+    out->xDeviceTable.serialize_copy (c->serializer, xDeviceTable, this, 0, hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map);
+    out->yDeviceTable.serialize_copy (c->serializer, yDeviceTable, this, 0, hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map);
+    return_trace (out);
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    (this+xDeviceTable).collect_variation_indices (c);
+    (this+yDeviceTable).collect_variation_indices (c);
+  }
+};
+
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_ANCHORFORMAT3_HH
diff --git a/src/OT/Layout/GPOS/AnchorMatrix.hh b/src/OT/Layout/GPOS/AnchorMatrix.hh
new file mode 100644 (file)
index 0000000..37ba791
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef OT_LAYOUT_GPOS_ANCHORMATRIX_HH
+#define OT_LAYOUT_GPOS_ANCHORMATRIX_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct AnchorMatrix
+{
+  HBUINT16      rows;                   /* Number of rows */
+  UnsizedArrayOf<Offset16To<Anchor>>
+                matrixZ;                /* Matrix of offsets to Anchor tables--
+                                         * from beginning of AnchorMatrix table */
+  public:
+  DEFINE_SIZE_ARRAY (2, matrixZ);
+
+  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_mul_overflows (rows, cols))) return_trace (false);
+    unsigned int count = rows * cols;
+    if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false);
+
+    if (c->lazy_some_gpos)
+      return_trace (true);
+
+    for (unsigned int i = 0; i < count; i++)
+      if (!matrixZ[i].sanitize (c, this)) return_trace (false);
+    return_trace (true);
+  }
+
+  const Anchor& get_anchor (hb_ot_apply_context_t *c,
+                           unsigned int row, unsigned int col,
+                           unsigned int cols, bool *found) const
+  {
+    *found = false;
+    if (unlikely (row >= rows || col >= cols)) return Null (Anchor);
+    auto &offset = matrixZ[row * cols + col];
+    if (unlikely (!offset.sanitize (&c->sanitizer, this))) return Null (Anchor);
+    *found = !offset.is_null ();
+    return this+offset;
+  }
+
+  template <typename Iterator,
+            hb_requires (hb_is_iterator (Iterator))>
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+                                  Iterator index_iter) const
+  {
+    for (unsigned i : index_iter)
+      (this+matrixZ[i]).collect_variation_indices (c);
+  }
+
+  template <typename Iterator,
+      hb_requires (hb_is_iterator (Iterator))>
+  bool subset (hb_subset_context_t *c,
+               unsigned             num_rows,
+               Iterator             index_iter) const
+  {
+    TRACE_SUBSET (this);
+
+    auto *out = c->serializer->start_embed (this);
+
+    if (!index_iter) return_trace (false);
+    if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
+
+    out->rows = num_rows;
+    bool ret = false;
+    for (const unsigned i : index_iter)
+    {
+      auto *offset = c->serializer->embed (matrixZ[i]);
+      if (!offset) return_trace (false);
+      ret |= offset->serialize_subset (c, matrixZ[i], this);
+    }
+
+    return_trace (ret);
+  }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_ANCHORMATRIX_HH */
diff --git a/src/OT/Layout/GPOS/ChainContextPos.hh b/src/OT/Layout/GPOS/ChainContextPos.hh
new file mode 100644 (file)
index 0000000..d551ac2
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef OT_LAYOUT_GPOS_CHAINCONTEXTPOS_HH
+#define OT_LAYOUT_GPOS_CHAINCONTEXTPOS_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct ChainContextPos : ChainContext {};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_CHAINCONTEXTPOS_HH */
diff --git a/src/OT/Layout/GPOS/Common.hh b/src/OT/Layout/GPOS/Common.hh
new file mode 100644 (file)
index 0000000..4081974
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef OT_LAYOUT_GPOS_COMMON_HH
+#define OT_LAYOUT_GPOS_COMMON_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+enum attach_type_t {
+  ATTACH_TYPE_NONE      = 0X00,
+
+  /* Each attachment should be either a mark or a cursive; can't be both. */
+  ATTACH_TYPE_MARK      = 0X01,
+  ATTACH_TYPE_CURSIVE   = 0X02,
+};
+
+/* buffer **position** var allocations */
+#define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
+#define attach_type() var.u8[2] /* attachment type */
+/* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */
+
+template<typename Iterator, typename SrcLookup>
+static void SinglePos_serialize (hb_serialize_context_t *c,
+                                 const SrcLookup *src,
+                                 Iterator it,
+                                 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
+                                 bool all_axes_pinned);
+
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_COMMON_HH
diff --git a/src/OT/Layout/GPOS/ContextPos.hh b/src/OT/Layout/GPOS/ContextPos.hh
new file mode 100644 (file)
index 0000000..2a01eaa
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef OT_LAYOUT_GPOS_CONTEXTPOS_HH
+#define OT_LAYOUT_GPOS_CONTEXTPOS_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct ContextPos : Context {};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_CONTEXTPOS_HH */
diff --git a/src/OT/Layout/GPOS/CursivePos.hh b/src/OT/Layout/GPOS/CursivePos.hh
new file mode 100644 (file)
index 0000000..0105a9b
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef OT_LAYOUT_GPOS_CURSIVEPOS_HH
+#define OT_LAYOUT_GPOS_CURSIVEPOS_HH
+
+#include "CursivePosFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct CursivePos
+{
+  protected:
+  union {
+  HBUINT16              format;         /* Format identifier */
+  CursivePosFormat1     format1;
+  } u;
+
+  public:
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format);
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_CURSIVEPOS_HH */
diff --git a/src/OT/Layout/GPOS/CursivePosFormat1.hh b/src/OT/Layout/GPOS/CursivePosFormat1.hh
new file mode 100644 (file)
index 0000000..7c42c3f
--- /dev/null
@@ -0,0 +1,309 @@
+#ifndef OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH
+
+#include "Anchor.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct EntryExitRecord
+{
+  friend struct CursivePosFormat1;
+
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+                                  const void *src_base) const
+  {
+    (src_base+entryAnchor).collect_variation_indices (c);
+    (src_base+exitAnchor).collect_variation_indices (c);
+  }
+
+  bool subset (hb_subset_context_t *c,
+              const void *src_base) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+
+    bool ret = false;
+    ret |= out->entryAnchor.serialize_subset (c, entryAnchor, src_base);
+    ret |= out->exitAnchor.serialize_subset (c, exitAnchor, src_base);
+    return_trace (ret);
+  }
+
+  protected:
+  Offset16To<Anchor>
+                entryAnchor;            /* Offset to EntryAnchor table--from
+                                         * beginning of CursivePos
+                                         * subtable--may be NULL */
+  Offset16To<Anchor>
+                exitAnchor;             /* Offset to ExitAnchor table--from
+                                         * beginning of CursivePos
+                                         * subtable--may be NULL */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+static void
+reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent) {
+  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
+  if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
+    return;
+
+  pos[i].attach_chain() = 0;
+
+  unsigned int j = (int) i + chain;
+
+  /* Stop if we see new parent in the chain. */
+  if (j == new_parent)
+    return;
+
+  reverse_cursive_minor_offset (pos, j, direction, new_parent);
+
+  if (HB_DIRECTION_IS_HORIZONTAL (direction))
+    pos[j].y_offset = -pos[i].y_offset;
+  else
+    pos[j].x_offset = -pos[i].x_offset;
+
+  pos[j].attach_chain() = -chain;
+  pos[j].attach_type() = type;
+}
+
+
+struct CursivePosFormat1
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  Offset16To<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of subtable */
+  Array16Of<EntryExitRecord>
+                entryExitRecord;        /* Array of EntryExit records--in
+                                         * Coverage Index order */
+  public:
+  DEFINE_SIZE_ARRAY (6, entryExitRecord);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!coverage.sanitize (c, this)))
+      return_trace (false);
+
+    if (c->lazy_some_gpos)
+      return_trace (entryExitRecord.sanitize_shallow (c));
+    else
+      return_trace (entryExitRecord.sanitize (c, this));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    + hb_zip (this+coverage, entryExitRecord)
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    | hb_apply ([&] (const EntryExitRecord& record) { record.collect_variation_indices (c, this); })
+    ;
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
+
+  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;
+
+    const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
+    if (!this_record.entryAnchor ||
+       unlikely (!this_record.entryAnchor.sanitize (&c->sanitizer, this))) return_trace (false);
+
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset_fast (buffer->idx);
+    unsigned unsafe_from;
+    if (unlikely (!skippy_iter.prev (&unsafe_from)))
+    {
+      buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
+      return_trace (false);
+    }
+
+    const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
+    if (!prev_record.exitAnchor ||
+       unlikely (!prev_record.exitAnchor.sanitize (&c->sanitizer, this)))
+    {
+      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
+      return_trace (false);
+    }
+
+    unsigned int i = skippy_iter.idx;
+    unsigned int j = buffer->idx;
+
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+                         "cursive attaching glyph at %u to glyph at %u",
+                         i, j);
+    }
+
+    buffer->unsafe_to_break (i, j + 1);
+    float entry_x, entry_y, exit_x, exit_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;
+
+    hb_position_t d;
+    /* Main-direction adjustment */
+    switch (c->direction) {
+      case HB_DIRECTION_LTR:
+        pos[i].x_advance  = roundf (exit_x) + pos[i].x_offset;
+
+        d = roundf (entry_x) + pos[j].x_offset;
+        pos[j].x_advance -= d;
+        pos[j].x_offset  -= d;
+        break;
+      case HB_DIRECTION_RTL:
+        d = roundf (exit_x) + pos[i].x_offset;
+        pos[i].x_advance -= d;
+        pos[i].x_offset  -= d;
+
+        pos[j].x_advance  = roundf (entry_x) + pos[j].x_offset;
+        break;
+      case HB_DIRECTION_TTB:
+        pos[i].y_advance  = roundf (exit_y) + pos[i].y_offset;
+
+        d = roundf (entry_y) + pos[j].y_offset;
+        pos[j].y_advance -= d;
+        pos[j].y_offset  -= d;
+        break;
+      case HB_DIRECTION_BTT:
+        d = roundf (exit_y) + pos[i].y_offset;
+        pos[i].y_advance -= d;
+        pos[i].y_offset  -= d;
+
+        pos[j].y_advance  = roundf (entry_y);
+        break;
+      case HB_DIRECTION_INVALID:
+      default:
+        break;
+    }
+
+    /* Cross-direction adjustment */
+
+    /* We attach child to parent (think graph theory and rooted trees whereas
+     * the root stays on baseline and each node aligns itself against its
+     * parent.
+     *
+     * Optimize things for the case of RightToLeft, as that's most common in
+     * Arabic. */
+    unsigned int child  = i;
+    unsigned int parent = j;
+    hb_position_t x_offset = roundf (entry_x - exit_x);
+    hb_position_t y_offset = roundf (entry_y - exit_y);
+    if  (!(c->lookup_props & LookupFlag::RightToLeft))
+    {
+      unsigned int k = child;
+      child = parent;
+      parent = k;
+      x_offset = -x_offset;
+      y_offset = -y_offset;
+    }
+
+    /* If child was already connected to someone else, walk through its old
+     * chain and reverse the link direction, such that the whole tree of its
+     * previous connection now attaches to new parent.  Watch out for case
+     * where new parent is on the path from old chain...
+     */
+    reverse_cursive_minor_offset (pos, child, c->direction, parent);
+
+    pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
+    pos[child].attach_chain() = (int) parent - (int) child;
+    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
+    if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
+      pos[child].y_offset = y_offset;
+    else
+      pos[child].x_offset = x_offset;
+
+    /* If parent was attached to child, separate them.
+     * https://github.com/harfbuzz/harfbuzz/issues/2469
+     */
+    if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain()))
+    {
+      pos[parent].attach_chain() = 0;
+      if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
+       pos[parent].y_offset = 0;
+      else
+       pos[parent].x_offset = 0;
+    }
+
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+                         "cursive attached glyph at %u to glyph at %u",
+                         i, j);
+    }
+
+    buffer->idx++;
+    return_trace (true);
+  }
+
+  template <typename Iterator,
+            hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_subset_context_t *c,
+                  Iterator it,
+                  const void *src_base)
+  {
+    if (unlikely (!c->serializer->extend_min ((*this)))) return;
+    this->format = 1;
+    this->entryExitRecord.len = it.len ();
+
+    for (const EntryExitRecord& entry_record : + it
+                                               | hb_map (hb_second))
+      entry_record.subset (c, src_base);
+
+    auto glyphs =
+    + it
+    | hb_map_retains_sorting (hb_first)
+    ;
+
+    coverage.serialize_serialize (c->serializer, glyphs);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+
+    auto it =
+    + hb_zip (this+coverage, entryExitRecord)
+    | hb_filter (glyphset, hb_first)
+    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const EntryExitRecord&> p) -> hb_pair_t<hb_codepoint_t, const EntryExitRecord&>
+                              { return hb_pair (glyph_map[p.first], p.second);})
+    ;
+
+    bool ret = bool (it);
+    out->serialize (c, it, this);
+    return_trace (ret);
+  }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH */
diff --git a/src/OT/Layout/GPOS/ExtensionPos.hh b/src/OT/Layout/GPOS/ExtensionPos.hh
new file mode 100644 (file)
index 0000000..d1808ad
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef OT_LAYOUT_GPOS_EXTENSIONPOS_HH
+#define OT_LAYOUT_GPOS_EXTENSIONPOS_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct ExtensionPos : Extension<ExtensionPos>
+{
+  typedef struct PosLookupSubTable SubTable;
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_EXTENSIONPOS_HH */
diff --git a/src/OT/Layout/GPOS/GPOS.hh b/src/OT/Layout/GPOS/GPOS.hh
new file mode 100644 (file)
index 0000000..f4af98b
--- /dev/null
@@ -0,0 +1,171 @@
+#ifndef OT_LAYOUT_GPOS_GPOS_HH
+#define OT_LAYOUT_GPOS_GPOS_HH
+
+#include "../../../hb-ot-layout-common.hh"
+#include "../../../hb-ot-layout-gsubgpos.hh"
+#include "Common.hh"
+#include "PosLookup.hh"
+
+namespace OT {
+
+using Layout::GPOS_impl::PosLookup;
+
+namespace Layout {
+
+static void
+propagate_attachment_offsets (hb_glyph_position_t *pos,
+                              unsigned int len,
+                              unsigned int i,
+                              hb_direction_t direction,
+                              unsigned nesting_level = HB_MAX_NESTING_LEVEL);
+
+/*
+ * GPOS -- Glyph Positioning
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/gpos
+ */
+
+struct GPOS : GSUBGPOS
+{
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS;
+
+  using Lookup = PosLookup;
+
+  const PosLookup& get_lookup (unsigned int i) const
+  { return static_cast<const 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);
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    hb_subset_layout_context_t l (c, tableTag);
+    return GSUBGPOS::subset<PosLookup> (&l);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (GSUBGPOS::sanitize<PosLookup> (c));
+  }
+
+  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
+                                   hb_face_t *face) const;
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    for (unsigned i = 0; i < GSUBGPOS::get_lookup_count (); i++)
+    {
+      if (!c->gpos_lookups->has (i)) continue;
+      const PosLookup &l = get_lookup (i);
+      l.dispatch (c);
+    }
+  }
+
+  void closure_lookups (hb_face_t      *face,
+                        const hb_set_t *glyphs,
+                        hb_set_t       *lookup_indexes /* IN/OUT */) const
+  { GSUBGPOS::closure_lookups<PosLookup> (face, glyphs, lookup_indexes); }
+
+  typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t;
+};
+
+
+static void
+propagate_attachment_offsets (hb_glyph_position_t *pos,
+                              unsigned int len,
+                              unsigned int i,
+                              hb_direction_t direction,
+                              unsigned nesting_level)
+{
+  /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
+   * offset of glyph they are attached to. */
+  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
+  if (likely (!chain))
+    return;
+
+  pos[i].attach_chain() = 0;
+
+  unsigned int j = (int) i + chain;
+
+  if (unlikely (j >= len))
+    return;
+
+  if (unlikely (!nesting_level))
+    return;
+
+  propagate_attachment_offsets (pos, len, j, direction, nesting_level - 1);
+
+  assert (!!(type & GPOS_impl::ATTACH_TYPE_MARK) ^ !!(type & GPOS_impl::ATTACH_TYPE_CURSIVE));
+
+  if (type & GPOS_impl::ATTACH_TYPE_CURSIVE)
+  {
+    if (HB_DIRECTION_IS_HORIZONTAL (direction))
+      pos[i].y_offset += pos[j].y_offset;
+    else
+      pos[i].x_offset += pos[j].x_offset;
+  }
+  else /*if (type & GPOS_impl::ATTACH_TYPE_MARK)*/
+  {
+    pos[i].x_offset += pos[j].x_offset;
+    pos[i].y_offset += pos[j].y_offset;
+
+    assert (j < i);
+    if (HB_DIRECTION_IS_FORWARD (direction))
+      for (unsigned int k = j; k < i; k++) {
+        pos[i].x_offset -= pos[k].x_advance;
+        pos[i].y_offset -= pos[k].y_advance;
+      }
+    else
+      for (unsigned int k = j + 1; k < i + 1; k++) {
+        pos[i].x_offset += pos[k].x_advance;
+        pos[i].y_offset += pos[k].y_advance;
+      }
+  }
+}
+
+void
+GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
+{
+  unsigned int count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+    buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
+}
+
+void
+GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
+{
+  //_hb_buffer_assert_gsubgpos_vars (buffer);
+}
+
+void
+GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
+{
+  _hb_buffer_assert_gsubgpos_vars (buffer);
+
+  unsigned int len;
+  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
+  hb_direction_t direction = buffer->props.direction;
+
+  /* Handle attachments */
+  if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
+    for (unsigned i = 0; i < len; i++)
+      propagate_attachment_offsets (pos, len, i, direction);
+
+  if (unlikely (font->slant))
+  {
+    for (unsigned i = 0; i < len; i++)
+      if (unlikely (pos[i].y_offset))
+        pos[i].x_offset += roundf (font->slant_xy * pos[i].y_offset);
+  }
+}
+
+}
+
+struct GPOS_accelerator_t : Layout::GPOS::accelerator_t {
+  GPOS_accelerator_t (hb_face_t *face) : Layout::GPOS::accelerator_t (face) {}
+};
+
+}
+
+#endif  /* OT_LAYOUT_GPOS_GPOS_HH */
diff --git a/src/OT/Layout/GPOS/LigatureArray.hh b/src/OT/Layout/GPOS/LigatureArray.hh
new file mode 100644 (file)
index 0000000..59cca40
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef OT_LAYOUT_GPOS_LIGATUREARRAY_HH
+#define OT_LAYOUT_GPOS_LIGATUREARRAY_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+
+typedef AnchorMatrix LigatureAttach;    /* component-major--
+                                         * in order of writing direction--,
+                                         * mark-minor--
+                                         * ordered by class--zero-based. */
+
+/* Array of LigatureAttach tables ordered by LigatureCoverage Index */
+struct LigatureArray : List16OfOffset16To<LigatureAttach>
+{
+  template <typename Iterator,
+            hb_requires (hb_is_iterator (Iterator))>
+  bool subset (hb_subset_context_t *c,
+               Iterator             coverage,
+               unsigned             class_count,
+               const hb_map_t      *klass_mapping) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+
+    auto *out = c->serializer->start_embed (this);
+    if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
+
+    bool ret = false;
+    for (const auto _ : + hb_zip (coverage, *this)
+                  | hb_filter (glyphset, hb_first))
+    {
+      auto *matrix = out->serialize_append (c->serializer);
+      if (unlikely (!matrix)) return_trace (false);
+
+      const LigatureAttach& src = (this + _.second);
+      auto indexes =
+          + hb_range (src.rows * class_count)
+          | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
+          ;
+      ret |= matrix->serialize_subset (c,
+                                      _.second,
+                                      this,
+                                      src.rows,
+                                      indexes);
+    }
+    return_trace (ret);
+  }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_LIGATUREARRAY_HH */
diff --git a/src/OT/Layout/GPOS/MarkArray.hh b/src/OT/Layout/GPOS/MarkArray.hh
new file mode 100644 (file)
index 0000000..0887cc1
--- /dev/null
@@ -0,0 +1,128 @@
+#ifndef OT_LAYOUT_GPOS_MARKARRAY_HH
+#define OT_LAYOUT_GPOS_MARKARRAY_HH
+
+#include "AnchorMatrix.hh"
+#include "MarkRecord.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct MarkArray : Array16Of<MarkRecord>        /* Array of MarkRecords--in Coverage order */
+{
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (Array16Of<MarkRecord>::sanitize (c, this));
+  }
+
+  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;
+    const MarkRecord &record = Array16Of<MarkRecord>::operator[](mark_index);
+    unsigned int mark_class = record.klass;
+
+    const Anchor& mark_anchor = this + record.markAnchor;
+    bool found;
+    const Anchor& glyph_anchor = anchors.get_anchor (c, glyph_index, mark_class, class_count, &found);
+    /* If this subtable doesn't have an anchor for this base and this class,
+     * return false such that the subsequent subtables have a chance at it. */
+    if (unlikely (!found)) return_trace (false);
+
+    float mark_x, mark_y, base_x, base_y;
+
+    buffer->unsafe_to_break (glyph_pos, buffer->idx + 1);
+    mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y);
+    glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
+
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+                         "attaching mark glyph at %u to glyph at %u",
+                         c->buffer->idx, glyph_pos);
+    }
+
+    hb_glyph_position_t &o = buffer->cur_pos();
+    o.x_offset = roundf (base_x - mark_x);
+    o.y_offset = roundf (base_y - mark_y);
+    o.attach_type() = ATTACH_TYPE_MARK;
+    o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
+    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
+
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+                         "attached mark glyph at %u to glyph at %u",
+                         c->buffer->idx, glyph_pos);
+    }
+
+    buffer->idx++;
+    return_trace (true);
+  }
+
+  template <typename Iterator,
+      hb_requires (hb_is_iterator (Iterator))>
+  bool subset (hb_subset_context_t *c,
+               Iterator             coverage,
+               const hb_map_t      *klass_mapping) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+
+    auto* out = c->serializer->start_embed (this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    auto mark_iter =
+    + hb_zip (coverage, this->iter ())
+    | hb_filter (glyphset, hb_first)
+    | hb_map (hb_second)
+    ;
+
+    bool ret = false;
+    unsigned new_length = 0;
+    for (const auto& mark_record : mark_iter) {
+      ret |= mark_record.subset (c, this, klass_mapping);
+      new_length++;
+    }
+
+    if (unlikely (!c->serializer->check_assign (out->len, new_length,
+                                                HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)))
+      return_trace (false);
+
+    return_trace (ret);
+  }
+};
+
+HB_INTERNAL inline
+void Markclass_closure_and_remap_indexes (const Coverage  &mark_coverage,
+                                          const MarkArray &mark_array,
+                                          const hb_set_t  &glyphset,
+                                          hb_map_t*        klass_mapping /* INOUT */)
+{
+  hb_set_t orig_classes;
+
+  + hb_zip (mark_coverage, mark_array)
+  | hb_filter (glyphset, hb_first)
+  | hb_map (hb_second)
+  | hb_map (&MarkRecord::get_class)
+  | hb_sink (orig_classes)
+  ;
+
+  unsigned idx = 0;
+  for (auto klass : orig_classes.iter ())
+  {
+    if (klass_mapping->has (klass)) continue;
+    klass_mapping->set (klass, idx);
+    idx++;
+  }
+}
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKARRAY_HH */
diff --git a/src/OT/Layout/GPOS/MarkBasePos.hh b/src/OT/Layout/GPOS/MarkBasePos.hh
new file mode 100644 (file)
index 0000000..cd2fc7c
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef OT_LAYOUT_GPOS_MARKBASEPOS_HH
+#define OT_LAYOUT_GPOS_MARKBASEPOS_HH
+
+#include "MarkBasePosFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct MarkBasePos
+{
+  protected:
+  union {
+  HBUINT16                             format;         /* Format identifier */
+  MarkBasePosFormat1_2<SmallTypes>     format1;
+#ifndef HB_NO_BEYOND_64K
+  MarkBasePosFormat1_2<MediumTypes>    format2;
+#endif
+  } u;
+
+  public:
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format);
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+#ifndef HB_NO_BEYOND_64K
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
+    default:return_trace (c->default_return_value ());
+    }
+  }
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKBASEPOS_HH */
diff --git a/src/OT/Layout/GPOS/MarkBasePosFormat1.hh b/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
new file mode 100644 (file)
index 0000000..1b8f3c8
--- /dev/null
@@ -0,0 +1,243 @@
+#ifndef OT_LAYOUT_GPOS_MARKBASEPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_MARKBASEPOSFORMAT1_HH
+
+#include "MarkArray.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+typedef AnchorMatrix BaseArray;         /* base-major--
+                                         * in order of BaseCoverage Index--,
+                                         * mark-minor--
+                                         * ordered by class--zero-based. */
+
+template <typename Types>
+struct MarkBasePosFormat1_2
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  typename Types::template OffsetTo<Coverage>
+                markCoverage;           /* Offset to MarkCoverage table--from
+                                         * beginning of MarkBasePos subtable */
+  typename Types::template OffsetTo<Coverage>
+                baseCoverage;           /* Offset to BaseCoverage table--from
+                                         * beginning of MarkBasePos subtable */
+  HBUINT16      classCount;             /* Number of classes defined for marks */
+  typename Types::template OffsetTo<MarkArray>
+                markArray;              /* Offset to MarkArray table--from
+                                         * beginning of MarkBasePos subtable */
+  typename Types::template OffsetTo<BaseArray>
+                baseArray;              /* Offset to BaseArray table--from
+                                         * beginning of MarkBasePos subtable */
+
+  public:
+  DEFINE_SIZE_STATIC (4 + 4 * Types::size);
+
+    bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  markCoverage.sanitize (c, this) &&
+                  baseCoverage.sanitize (c, this) &&
+                  markArray.sanitize (c, this) &&
+                  baseArray.sanitize (c, this, (unsigned int) classCount));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    return (this+markCoverage).intersects (glyphs) &&
+           (this+baseCoverage).intersects (glyphs);
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    + hb_zip (this+markCoverage, this+markArray)
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
+    ;
+
+    hb_map_t klass_mapping;
+    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);
+
+    unsigned basecount = (this+baseArray).rows;
+    auto base_iter =
+    + hb_zip (this+baseCoverage, hb_range (basecount))
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    ;
+
+    hb_sorted_vector_t<unsigned> base_indexes;
+    for (const unsigned row : base_iter)
+    {
+      + hb_range ((unsigned) classCount)
+      | hb_filter (klass_mapping)
+      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+      | hb_sink (base_indexes)
+      ;
+    }
+    (this+baseArray).collect_variation_indices (c, base_indexes.iter ());
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
+    if (unlikely (!(this+baseCoverage).collect_coverage (c->input))) return;
+  }
+
+  const Coverage &get_coverage () const { return this+markCoverage; }
+
+  static inline bool accept (hb_buffer_t *buffer, unsigned idx)
+  {
+    /* We only want to attach to the first of a MultipleSubst sequence.
+     * https://github.com/harfbuzz/harfbuzz/issues/740
+     * Reject others...
+     * ...but stop if we find a mark in the MultipleSubst sequence:
+     * https://github.com/harfbuzz/harfbuzz/issues/1020 */
+    return !_hb_glyph_info_multiplied (&buffer->info[idx]) ||
+          0 == _hb_glyph_info_get_lig_comp (&buffer->info[idx]) ||
+          (idx == 0 ||
+           _hb_glyph_info_is_mark (&buffer->info[idx - 1]) ||
+           !_hb_glyph_info_multiplied (&buffer->info[idx - 1]) ||
+           _hb_glyph_info_get_lig_id (&buffer->info[idx]) !=
+           _hb_glyph_info_get_lig_id (&buffer->info[idx - 1]) ||
+           _hb_glyph_info_get_lig_comp (&buffer->info[idx]) !=
+           _hb_glyph_info_get_lig_comp (&buffer->info[idx - 1]) + 1
+           );
+  }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (mark_index == NOT_COVERED)) return_trace (false);
+
+    /* Now we search backwards for a non-mark glyph.
+     * We don't use skippy_iter.prev() to avoid O(n^2) behavior. */
+
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
+
+    if (c->last_base_until > buffer->idx)
+    {
+      c->last_base_until = 0;
+      c->last_base = -1;
+    }
+    unsigned j;
+    for (j = buffer->idx; j > c->last_base_until; j--)
+    {
+      auto match = skippy_iter.match (buffer->info[j - 1]);
+      if (match == skippy_iter.MATCH)
+      {
+        // https://github.com/harfbuzz/harfbuzz/issues/4124
+       if (!accept (buffer, j - 1) &&
+           NOT_COVERED == (this+baseCoverage).get_coverage  (buffer->info[j - 1].codepoint))
+         match = skippy_iter.SKIP;
+      }
+      if (match == skippy_iter.MATCH)
+      {
+       c->last_base = (signed) j - 1;
+       break;
+      }
+    }
+    c->last_base_until = buffer->idx;
+    if (c->last_base == -1)
+    {
+      buffer->unsafe_to_concat_from_outbuffer (0, buffer->idx + 1);
+      return_trace (false);
+    }
+
+    unsigned idx = (unsigned) c->last_base;
+
+    /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
+    //if (!_hb_glyph_info_is_base_glyph (&buffer->info[idx])) { return_trace (false); }
+
+    unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[idx].codepoint);
+    if (base_index == NOT_COVERED)
+    {
+      buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
+      return_trace (false);
+    }
+
+    return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, idx));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_map_t klass_mapping;
+    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
+
+    if (!klass_mapping.get_population ()) return_trace (false);
+    out->classCount = klass_mapping.get_population ();
+
+    auto mark_iter =
+    + hb_zip (this+markCoverage, this+markArray)
+    | hb_filter (glyphset, hb_first)
+    ;
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + mark_iter
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    if (!out->markCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
+      return_trace (false);
+
+    if (unlikely (!out->markArray.serialize_subset (c, markArray, this,
+                                                   (this+markCoverage).iter (),
+                                                   &klass_mapping)))
+      return_trace (false);
+
+    unsigned basecount = (this+baseArray).rows;
+    auto base_iter =
+    + hb_zip (this+baseCoverage, hb_range (basecount))
+    | hb_filter (glyphset, hb_first)
+    ;
+
+    new_coverage.reset ();
+    + base_iter
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
+      return_trace (false);
+
+    hb_sorted_vector_t<unsigned> base_indexes;
+    for (const unsigned row : + base_iter
+                              | hb_map (hb_second))
+    {
+      + hb_range ((unsigned) classCount)
+      | hb_filter (klass_mapping)
+      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+      | hb_sink (base_indexes)
+      ;
+    }
+
+    return_trace (out->baseArray.serialize_subset (c, baseArray, this,
+                                                  base_iter.len (),
+                                                  base_indexes.iter ()));
+  }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKBASEPOSFORMAT1_HH */
diff --git a/src/OT/Layout/GPOS/MarkLigPos.hh b/src/OT/Layout/GPOS/MarkLigPos.hh
new file mode 100644 (file)
index 0000000..739c325
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef OT_LAYOUT_GPOS_MARKLIGPOS_HH
+#define OT_LAYOUT_GPOS_MARKLIGPOS_HH
+
+#include "MarkLigPosFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct MarkLigPos
+{
+  protected:
+  union {
+  HBUINT16                             format;         /* Format identifier */
+  MarkLigPosFormat1_2<SmallTypes>      format1;
+#ifndef HB_NO_BEYOND_64K
+  MarkLigPosFormat1_2<MediumTypes>     format2;
+#endif
+  } u;
+
+  public:
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format);
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+#ifndef HB_NO_BEYOND_64K
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
+    default:return_trace (c->default_return_value ());
+    }
+  }
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKLIGPOS_HH */
diff --git a/src/OT/Layout/GPOS/MarkLigPosFormat1.hh b/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
new file mode 100644 (file)
index 0000000..d6bee27
--- /dev/null
@@ -0,0 +1,224 @@
+#ifndef OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH
+
+#include "LigatureArray.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+
+template <typename Types>
+struct MarkLigPosFormat1_2
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  typename Types::template OffsetTo<Coverage>
+                markCoverage;           /* Offset to Mark Coverage table--from
+                                         * beginning of MarkLigPos subtable */
+  typename Types::template OffsetTo<Coverage>
+                ligatureCoverage;       /* Offset to Ligature Coverage
+                                         * table--from beginning of MarkLigPos
+                                         * subtable */
+  HBUINT16      classCount;             /* Number of defined mark classes */
+  typename Types::template OffsetTo<MarkArray>
+                markArray;              /* Offset to MarkArray table--from
+                                         * beginning of MarkLigPos subtable */
+  typename Types::template OffsetTo<LigatureArray>
+                ligatureArray;          /* Offset to LigatureArray table--from
+                                         * beginning of MarkLigPos subtable */
+  public:
+  DEFINE_SIZE_STATIC (4 + 4 * Types::size);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  markCoverage.sanitize (c, this) &&
+                  ligatureCoverage.sanitize (c, this) &&
+                  markArray.sanitize (c, this) &&
+                  ligatureArray.sanitize (c, this, (unsigned int) classCount));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    return (this+markCoverage).intersects (glyphs) &&
+           (this+ligatureCoverage).intersects (glyphs);
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    + hb_zip (this+markCoverage, this+markArray)
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
+    ;
+
+    hb_map_t klass_mapping;
+    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);
+
+    unsigned ligcount = (this+ligatureArray).len;
+    auto lig_iter =
+    + hb_zip (this+ligatureCoverage, hb_range (ligcount))
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    ;
+
+    const LigatureArray& lig_array = this+ligatureArray;
+    for (const unsigned i : lig_iter)
+    {
+      hb_sorted_vector_t<unsigned> lig_indexes;
+      unsigned row_count = lig_array[i].rows;
+      for (unsigned row : + hb_range (row_count))
+      {
+        + hb_range ((unsigned) classCount)
+        | hb_filter (klass_mapping)
+        | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+        | hb_sink (lig_indexes)
+        ;
+      }
+
+      lig_array[i].collect_variation_indices (c, lig_indexes.iter ());
+    }
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
+    if (unlikely (!(this+ligatureCoverage).collect_coverage (c->input))) return;
+  }
+
+  const Coverage &get_coverage () const { return this+markCoverage; }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (mark_index == NOT_COVERED)) return_trace (false);
+
+    /* Now we search backwards for a non-mark glyph */
+
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
+
+    if (c->last_base_until > buffer->idx)
+    {
+      c->last_base_until = 0;
+      c->last_base = -1;
+    }
+    unsigned j;
+    for (j = buffer->idx; j > c->last_base_until; j--)
+    {
+      auto match = skippy_iter.match (buffer->info[j - 1]);
+      if (match == skippy_iter.MATCH)
+      {
+       c->last_base = (signed) j - 1;
+       break;
+      }
+    }
+    c->last_base_until = buffer->idx;
+    if (c->last_base == -1)
+    {
+      buffer->unsafe_to_concat_from_outbuffer (0, buffer->idx + 1);
+      return_trace (false);
+    }
+
+    unsigned idx = (unsigned) c->last_base;
+
+    /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
+    //if (!_hb_glyph_info_is_ligature (&buffer->info[idx])) { return_trace (false); }
+
+    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[idx].codepoint);
+    if (lig_index == NOT_COVERED)
+    {
+      buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
+      return_trace (false);
+    }
+
+    const LigatureArray& lig_array = this+ligatureArray;
+    const LigatureAttach& lig_attach = lig_array[lig_index];
+
+    /* Find component to attach to */
+    unsigned int comp_count = lig_attach.rows;
+    if (unlikely (!comp_count))
+    {
+      buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
+      return_trace (false);
+    }
+
+    /* We must now check whether the ligature ID of the current mark glyph
+     * is identical to the ligature ID of the found ligature.  If yes, we
+     * can directly use the component index.  If not, we attach the mark
+     * glyph to the last component of the ligature. */
+    unsigned int comp_index;
+    unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[idx]);
+    unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
+    unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
+    if (lig_id && lig_id == mark_id && mark_comp > 0)
+      comp_index = hb_min (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
+    else
+      comp_index = comp_count - 1;
+
+    return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, idx));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = c->plan->glyph_map_gsub;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_map_t klass_mapping;
+    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
+
+    if (!klass_mapping.get_population ()) return_trace (false);
+    out->classCount = klass_mapping.get_population ();
+
+    auto mark_iter =
+    + hb_zip (this+markCoverage, this+markArray)
+    | hb_filter (glyphset, hb_first)
+    ;
+
+    auto new_mark_coverage =
+    + mark_iter
+    | hb_map_retains_sorting (hb_first)
+    | hb_map_retains_sorting (glyph_map)
+    ;
+
+    if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage))
+      return_trace (false);
+
+    if (unlikely (!out->markArray.serialize_subset (c, markArray, this,
+                                                   (this+markCoverage).iter (),
+                                                   &klass_mapping)))
+      return_trace (false);
+
+    auto new_ligature_coverage =
+    + hb_iter (this + ligatureCoverage)
+    | hb_take ((this + ligatureArray).len)
+    | hb_map_retains_sorting (glyph_map)
+    | hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; })
+    ;
+
+    if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage))
+      return_trace (false);
+
+    return_trace (out->ligatureArray.serialize_subset (c, ligatureArray, this,
+                                                      hb_iter (this+ligatureCoverage),
+                                                      classCount, &klass_mapping));
+  }
+
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH */
diff --git a/src/OT/Layout/GPOS/MarkMarkPos.hh b/src/OT/Layout/GPOS/MarkMarkPos.hh
new file mode 100644 (file)
index 0000000..cddd2a3
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef OT_LAYOUT_GPOS_MARKMARKPOS_HH
+#define OT_LAYOUT_GPOS_MARKMARKPOS_HH
+
+#include "MarkMarkPosFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct MarkMarkPos
+{
+  protected:
+  union {
+  HBUINT16                             format;         /* Format identifier */
+  MarkMarkPosFormat1_2<SmallTypes>     format1;
+#ifndef HB_NO_BEYOND_64K
+  MarkMarkPosFormat1_2<MediumTypes>    format2;
+#endif
+  } u;
+
+  public:
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format);
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+#ifndef HB_NO_BEYOND_64K
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
+    default:return_trace (c->default_return_value ());
+    }
+  }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKMARKPOS_HH */
diff --git a/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh b/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
new file mode 100644 (file)
index 0000000..70cf071
--- /dev/null
@@ -0,0 +1,230 @@
+#ifndef OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH
+
+#include "MarkMarkPosFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+typedef AnchorMatrix Mark2Array;        /* mark2-major--
+                                         * in order of Mark2Coverage Index--,
+                                         * mark1-minor--
+                                         * ordered by class--zero-based. */
+
+template <typename Types>
+struct MarkMarkPosFormat1_2
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  typename Types::template OffsetTo<Coverage>
+                mark1Coverage;          /* Offset to Combining Mark1 Coverage
+                                         * table--from beginning of MarkMarkPos
+                                         * subtable */
+  typename Types::template OffsetTo<Coverage>
+                mark2Coverage;          /* Offset to Combining Mark2 Coverage
+                                         * table--from beginning of MarkMarkPos
+                                         * subtable */
+  HBUINT16      classCount;             /* Number of defined mark classes */
+  typename Types::template OffsetTo<MarkArray>
+                mark1Array;             /* Offset to Mark1Array table--from
+                                         * beginning of MarkMarkPos subtable */
+  typename Types::template OffsetTo<Mark2Array>
+                mark2Array;             /* Offset to Mark2Array table--from
+                                         * beginning of MarkMarkPos subtable */
+  public:
+  DEFINE_SIZE_STATIC (4 + 4 * Types::size);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  mark1Coverage.sanitize (c, this) &&
+                  mark2Coverage.sanitize (c, this) &&
+                  mark1Array.sanitize (c, this) &&
+                  mark2Array.sanitize (c, this, (unsigned int) classCount));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    return (this+mark1Coverage).intersects (glyphs) &&
+           (this+mark2Coverage).intersects (glyphs);
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    + hb_zip (this+mark1Coverage, this+mark1Array)
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+mark1Array)); })
+    ;
+
+    hb_map_t klass_mapping;
+    Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, *c->glyph_set, &klass_mapping);
+
+    unsigned mark2_count = (this+mark2Array).rows;
+    auto mark2_iter =
+    + hb_zip (this+mark2Coverage, hb_range (mark2_count))
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    ;
+
+    hb_sorted_vector_t<unsigned> mark2_indexes;
+    for (const unsigned row : mark2_iter)
+    {
+      + hb_range ((unsigned) classCount)
+      | hb_filter (klass_mapping)
+      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+      | hb_sink (mark2_indexes)
+      ;
+    }
+    (this+mark2Array).collect_variation_indices (c, mark2_indexes.iter ());
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+mark1Coverage).collect_coverage (c->input))) return;
+    if (unlikely (!(this+mark2Coverage).collect_coverage (c->input))) return;
+  }
+
+  const Coverage &get_coverage () const { return this+mark1Coverage; }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (mark1_index == NOT_COVERED)) return_trace (false);
+
+    /* now we search backwards for a suitable mark glyph until a non-mark glyph */
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset_fast (buffer->idx);
+    skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags);
+    unsigned unsafe_from;
+    if (unlikely (!skippy_iter.prev (&unsafe_from)))
+    {
+      buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
+      return_trace (false);
+    }
+
+    if (likely (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])))
+    {
+      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
+      return_trace (false);
+    }
+
+    unsigned int j = skippy_iter.idx;
+
+    unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
+    unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
+    unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
+    unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
+
+    if (likely (id1 == id2))
+    {
+      if (id1 == 0) /* Marks belonging to the same base. */
+        goto good;
+      else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
+        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. */
+      if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
+        goto good;
+    }
+
+    /* Didn't match. */
+    buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
+    return_trace (false);
+
+    good:
+    unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
+    if (mark2_index == NOT_COVERED)
+    {
+      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
+      return_trace (false);
+    }
+
+    return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_map_t klass_mapping;
+    Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, glyphset, &klass_mapping);
+
+    if (!klass_mapping.get_population ()) return_trace (false);
+    out->classCount = klass_mapping.get_population ();
+
+    auto mark1_iter =
+    + hb_zip (this+mark1Coverage, this+mark1Array)
+    | hb_filter (glyphset, hb_first)
+    ;
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + mark1_iter
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
+      return_trace (false);
+
+    if (unlikely (!out->mark1Array.serialize_subset (c, mark1Array, this,
+                                                    (this+mark1Coverage).iter (),
+                                                    &klass_mapping)))
+      return_trace (false);
+
+    unsigned mark2count = (this+mark2Array).rows;
+    auto mark2_iter =
+    + hb_zip (this+mark2Coverage, hb_range (mark2count))
+    | hb_filter (glyphset, hb_first)
+    ;
+
+    new_coverage.reset ();
+    + mark2_iter
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
+      return_trace (false);
+
+    hb_sorted_vector_t<unsigned> mark2_indexes;
+    for (const unsigned row : + mark2_iter
+                              | hb_map (hb_second))
+    {
+      + hb_range ((unsigned) classCount)
+      | hb_filter (klass_mapping)
+      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+      | hb_sink (mark2_indexes)
+      ;
+    }
+
+    return_trace (out->mark2Array.serialize_subset (c, mark2Array, this,
+                                                   mark2_iter.len (),
+                                                   mark2_indexes.iter ()));
+
+  }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH */
diff --git a/src/OT/Layout/GPOS/MarkRecord.hh b/src/OT/Layout/GPOS/MarkRecord.hh
new file mode 100644 (file)
index 0000000..3d11c77
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef OT_LAYOUT_GPOS_MARKRECORD_HH
+#define OT_LAYOUT_GPOS_MARKRECORD_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct MarkRecord
+{
+  friend struct MarkArray;
+
+  public:
+  HBUINT16      klass;                  /* Class defined for this mark */
+  Offset16To<Anchor>
+                markAnchor;             /* Offset to Anchor table--from
+                                         * beginning of MarkArray table */
+  public:
+  DEFINE_SIZE_STATIC (4);
+
+  unsigned get_class () const { return (unsigned) klass; }
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
+  }
+
+  bool subset (hb_subset_context_t    *c,
+              const void             *src_base,
+              const hb_map_t         *klass_mapping) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+
+    out->klass = klass_mapping->get (klass);
+    return_trace (out->markAnchor.serialize_subset (c, markAnchor, src_base));
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+                                  const void *src_base) const
+  {
+    (src_base+markAnchor).collect_variation_indices (c);
+  }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKRECORD_HH */
diff --git a/src/OT/Layout/GPOS/PairPos.hh b/src/OT/Layout/GPOS/PairPos.hh
new file mode 100644 (file)
index 0000000..c13d4f4
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef OT_LAYOUT_GPOS_PAIRPOS_HH
+#define OT_LAYOUT_GPOS_PAIRPOS_HH
+
+#include "PairPosFormat1.hh"
+#include "PairPosFormat2.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct PairPos
+{
+  protected:
+  union {
+  HBUINT16                     format;         /* Format identifier */
+  PairPosFormat1_3<SmallTypes> format1;
+  PairPosFormat2_4<SmallTypes> format2;
+#ifndef HB_NO_BEYOND_64K
+  PairPosFormat1_3<MediumTypes>        format3;
+  PairPosFormat2_4<MediumTypes>        format4;
+#endif
+  } u;
+
+  public:
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format);
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#ifndef HB_NO_BEYOND_64K
+    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+    case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+#endif
+    default:return_trace (c->default_return_value ());
+    }
+  }
+};
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_PAIRPOS_HH
diff --git a/src/OT/Layout/GPOS/PairPosFormat1.hh b/src/OT/Layout/GPOS/PairPosFormat1.hh
new file mode 100644 (file)
index 0000000..e4a2006
--- /dev/null
@@ -0,0 +1,217 @@
+#ifndef OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
+
+#include "PairSet.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+
+template <typename Types>
+struct PairPosFormat1_3
+{
+  using PairSet = GPOS_impl::PairSet<Types>;
+  using PairValueRecord = GPOS_impl::PairValueRecord<Types>;
+
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  typename Types::template OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of subtable */
+  ValueFormat   valueFormat[2];         /* [0] Defines the types of data in
+                                         * ValueRecord1--for the first glyph
+                                         * in the pair--may be zero (0) */
+                                        /* [1] Defines the types of data in
+                                         * ValueRecord2--for the second glyph
+                                         * in the pair--may be zero (0) */
+  Array16Of<typename Types::template OffsetTo<PairSet>>
+                pairSet;                /* Array of PairSet tables
+                                         * ordered by Coverage Index */
+  public:
+  DEFINE_SIZE_ARRAY (8 + Types::size, pairSet);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+
+    if (!c->check_struct (this)) return_trace (false);
+
+    unsigned int len1 = valueFormat[0].get_len ();
+    unsigned int len2 = valueFormat[1].get_len ();
+    typename PairSet::sanitize_closure_t closure =
+    {
+      valueFormat,
+      len1,
+      PairSet::get_size (len1, len2)
+    };
+
+    return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    auto &cov = this+coverage;
+
+    if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4)
+    {
+      for (hb_codepoint_t g : glyphs->iter())
+      {
+       unsigned i = cov.get_coverage (g);
+       if ((this+pairSet[i]).intersects (glyphs, valueFormat))
+         return true;
+      }
+      return false;
+    }
+
+    return
+    + hb_zip (cov, pairSet)
+    | hb_filter (*glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map ([glyphs, this] (const typename Types::template OffsetTo<PairSet> &_)
+              { return (this+_).intersects (glyphs, valueFormat); })
+    | hb_any
+    ;
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    if ((!valueFormat[0].has_device ()) && (!valueFormat[1].has_device ())) return;
+
+    auto it =
+    + hb_zip (this+coverage, pairSet)
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    ;
+
+    if (!it) return;
+    + it
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const PairSet& _) { _.collect_variation_indices (c, valueFormat); })
+    ;
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+    unsigned int count = pairSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+pairSet[i]).collect_glyphs (c, valueFormat);
+  }
+
+  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;
+    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset_fast (buffer->idx);
+    unsigned unsafe_to;
+    if (unlikely (!skippy_iter.next (&unsafe_to)))
+    {
+      buffer->unsafe_to_concat (buffer->idx, unsafe_to);
+      return_trace (false);
+    }
+
+    return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+    out->valueFormat[0] = valueFormat[0];
+    out->valueFormat[1] = valueFormat[1];
+    if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+    {
+      hb_pair_t<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset);
+      out->valueFormat[0] = newFormats.first;
+      out->valueFormat[1] = newFormats.second;
+    }
+
+    if (c->plan->all_axes_pinned)
+    {
+      out->valueFormat[0] = out->valueFormat[0].drop_device_table_flags ();
+      out->valueFormat[1] = out->valueFormat[1].drop_device_table_flags ();
+    }
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+
+    + hb_zip (this+coverage, pairSet)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter ([this, c, out] (const typename Types::template OffsetTo<PairSet>& _)
+                 {
+                   auto snap = c->serializer->snapshot ();
+                   auto *o = out->pairSet.serialize_append (c->serializer);
+                   if (unlikely (!o)) return false;
+                   bool ret = o->serialize_subset (c, _, this, valueFormat, out->valueFormat);
+                   if (!ret)
+                   {
+                     out->pairSet.pop ();
+                     c->serializer->revert (snap);
+                   }
+                   return ret;
+                 },
+                 hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
+
+    return_trace (bool (new_coverage));
+  }
+
+
+  hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const
+  {
+    unsigned record_size = PairSet::get_size (valueFormat);
+
+    unsigned format1 = 0;
+    unsigned format2 = 0;
+    for (const auto & _ :
+         + hb_zip (this+coverage, pairSet)
+         | hb_filter (glyphset, hb_first)
+         | hb_map (hb_second)
+       )
+    {
+      const PairSet& set = (this + _);
+      const PairValueRecord *record = &set.firstPairValueRecord;
+
+      unsigned count = set.len;
+      for (unsigned i = 0; i < count; i++)
+      {
+        if (record->intersects (glyphset))
+        {
+          format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 ());
+          format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]));
+        }
+        record = &StructAtOffset<const PairValueRecord> (record, record_size);
+      }
+
+      if (format1 == valueFormat[0] && format2 == valueFormat[1])
+        break;
+    }
+
+    return hb_pair (format1, format2);
+  }
+};
+
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
diff --git a/src/OT/Layout/GPOS/PairPosFormat2.hh b/src/OT/Layout/GPOS/PairPosFormat2.hh
new file mode 100644 (file)
index 0000000..4adb1ef
--- /dev/null
@@ -0,0 +1,359 @@
+#ifndef OT_LAYOUT_GPOS_PAIRPOSFORMAT2_HH
+#define OT_LAYOUT_GPOS_PAIRPOSFORMAT2_HH
+
+#include "ValueFormat.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+template <typename Types>
+struct PairPosFormat2_4
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 2 */
+  typename Types::template OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of subtable */
+  ValueFormat   valueFormat1;           /* ValueRecord definition--for the
+                                         * first glyph of the pair--may be zero
+                                         * (0) */
+  ValueFormat   valueFormat2;           /* ValueRecord definition--for the
+                                         * second glyph of the pair--may be
+                                         * zero (0) */
+  typename Types::template OffsetTo<ClassDef>
+                classDef1;              /* Offset to ClassDef table--from
+                                         * beginning of PairPos subtable--for
+                                         * the first glyph of the pair */
+  typename Types::template OffsetTo<ClassDef>
+                classDef2;              /* Offset to ClassDef table--from
+                                         * beginning of PairPos subtable--for
+                                         * the second glyph of the pair */
+  HBUINT16      class1Count;            /* Number of classes in ClassDef1
+                                         * table--includes Class0 */
+  HBUINT16      class2Count;            /* Number of classes in ClassDef2
+                                         * table--includes Class0 */
+  ValueRecord   values;                 /* Matrix of value pairs:
+                                         * class1-major, class2-minor,
+                                         * Each entry has value1 and value2 */
+  public:
+  DEFINE_SIZE_ARRAY (10 + 3 * Types::size, values);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!(c->check_struct (this)
+       && coverage.sanitize (c, this)
+       && classDef1.sanitize (c, this)
+       && classDef2.sanitize (c, this))) return_trace (false);
+
+    unsigned int len1 = valueFormat1.get_len ();
+    unsigned int len2 = valueFormat2.get_len ();
+    unsigned int stride = HBUINT16::static_size * (len1 + len2);
+    unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
+    return_trace (c->check_range ((const void *) values,
+                                  count,
+                                  stride) &&
+                 (c->lazy_some_gpos ||
+                  (valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
+                   valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride))));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    return (this+coverage).intersects (glyphs) &&
+           (this+classDef2).intersects (glyphs);
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    if (!intersects (c->glyph_set)) return;
+    if ((!valueFormat1.has_device ()) && (!valueFormat2.has_device ())) return;
+
+    hb_set_t klass1_glyphs, klass2_glyphs;
+    if (!(this+classDef1).collect_coverage (&klass1_glyphs)) return;
+    if (!(this+classDef2).collect_coverage (&klass2_glyphs)) return;
+
+    hb_set_t class1_set, class2_set;
+    for (const unsigned cp : + c->glyph_set->iter () | hb_filter (this + coverage))
+    {
+      if (!klass1_glyphs.has (cp)) class1_set.add (0);
+      else
+      {
+        unsigned klass1 = (this+classDef1).get (cp);
+        class1_set.add (klass1);
+      }
+    }
+
+    class2_set.add (0);
+    for (const unsigned cp : + c->glyph_set->iter () | hb_filter (klass2_glyphs))
+    {
+      unsigned klass2 = (this+classDef2).get (cp);
+      class2_set.add (klass2);
+    }
+
+    if (class1_set.is_empty ()
+        || class2_set.is_empty ()
+        || (class2_set.get_population() == 1 && class2_set.has(0)))
+      return;
+
+    unsigned len1 = valueFormat1.get_len ();
+    unsigned len2 = valueFormat2.get_len ();
+    const hb_array_t<const Value> values_array = values.as_array ((unsigned)class1Count * (unsigned) class2Count * (len1 + len2));
+    for (const unsigned class1_idx : class1_set.iter ())
+    {
+      for (const unsigned class2_idx : class2_set.iter ())
+      {
+        unsigned start_offset = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
+        if (valueFormat1.has_device ())
+          valueFormat1.collect_variation_indices (c, this, values_array.sub_array (start_offset, len1));
+
+        if (valueFormat2.has_device ())
+          valueFormat2.collect_variation_indices (c, this, values_array.sub_array (start_offset+len1, len2));
+      }
+    }
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+    if (unlikely (!(this+classDef2).collect_coverage (c->input))) return;
+  }
+
+  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;
+    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset_fast (buffer->idx);
+    unsigned unsafe_to;
+    if (unlikely (!skippy_iter.next (&unsafe_to)))
+    {
+      buffer->unsafe_to_concat (buffer->idx, unsafe_to);
+      return_trace (false);
+    }
+
+    unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
+    if (!klass2)
+    {
+      buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
+      return_trace (false);
+    }
+
+    unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
+    if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
+    {
+      buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
+      return_trace (false);
+    }
+
+    unsigned int len1 = valueFormat1.get_len ();
+    unsigned int len2 = valueFormat2.get_len ();
+    unsigned int record_len = len1 + len2;
+
+    const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
+
+    bool applied_first = false, applied_second = false;
+
+
+    /* Isolate simple kerning and apply it half to each side.
+     * Results in better cursor positioning / underline drawing.
+     *
+     * Disabled, because causes issues... :-(
+     * https://github.com/harfbuzz/harfbuzz/issues/3408
+     * https://github.com/harfbuzz/harfbuzz/pull/3235#issuecomment-1029814978
+     */
+#ifndef HB_SPLIT_KERN
+    if (false)
+#endif
+    {
+      if (!len2)
+      {
+        const hb_direction_t dir = buffer->props.direction;
+        const bool horizontal = HB_DIRECTION_IS_HORIZONTAL (dir);
+        const bool backward = HB_DIRECTION_IS_BACKWARD (dir);
+        unsigned mask = horizontal ? ValueFormat::xAdvance : ValueFormat::yAdvance;
+        if (backward)
+          mask |= mask >> 2; /* Add eg. xPlacement in RTL. */
+        /* Add Devices. */
+        mask |= mask << 4;
+
+        if (valueFormat1 & ~mask)
+          goto bail;
+
+        /* Is simple kern. Apply value on an empty position slot,
+         * then split it between sides. */
+
+        hb_glyph_position_t pos{};
+        if (valueFormat1.apply_value (c, this, v, pos))
+        {
+          hb_position_t *src  = &pos.x_advance;
+          hb_position_t *dst1 = &buffer->cur_pos().x_advance;
+          hb_position_t *dst2 = &buffer->pos[skippy_iter.idx].x_advance;
+          unsigned i = horizontal ? 0 : 1;
+
+          hb_position_t kern  = src[i];
+          hb_position_t kern1 = kern >> 1;
+          hb_position_t kern2 = kern - kern1;
+
+          if (!backward)
+          {
+            dst1[i] += kern1;
+            dst2[i] += kern2;
+            dst2[i + 2] += kern2;
+          }
+          else
+          {
+            dst1[i] += kern1;
+            dst1[i + 2] += src[i + 2] - kern2;
+            dst2[i] += kern2;
+          }
+
+          applied_first = applied_second = kern != 0;
+          goto success;
+        }
+        goto boring;
+      }
+    }
+    bail:
+
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+                         "try kerning glyphs at %u,%u",
+                         c->buffer->idx, skippy_iter.idx);
+    }
+
+    applied_first = len1 && valueFormat1.apply_value (c, this, v, buffer->cur_pos());
+    applied_second = len2 && valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
+
+    if (applied_first || applied_second)
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+       c->buffer->message (c->font,
+                           "kerned glyphs at %u,%u",
+                           c->buffer->idx, skippy_iter.idx);
+      }
+
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+                         "tried kerning glyphs at %u,%u",
+                         c->buffer->idx, skippy_iter.idx);
+    }
+
+    success:
+    if (applied_first || applied_second)
+      buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1);
+    else
+    boring:
+      buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
+
+    if (len2)
+    {
+      skippy_iter.idx++;
+      // https://github.com/harfbuzz/harfbuzz/issues/3824
+      // https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116
+      buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1);
+    }
+
+    buffer->idx = skippy_iter.idx;
+
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_map_t klass1_map;
+    out->classDef1.serialize_subset (c, classDef1, this, &klass1_map, true, true, &(this + coverage));
+    out->class1Count = klass1_map.get_population ();
+
+    hb_map_t klass2_map;
+    out->classDef2.serialize_subset (c, classDef2, this, &klass2_map, true, false);
+    out->class2Count = klass2_map.get_population ();
+
+    unsigned len1 = valueFormat1.get_len ();
+    unsigned len2 = valueFormat2.get_len ();
+
+    hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2);
+    if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+      newFormats = compute_effective_value_formats (klass1_map, klass2_map);
+
+    out->valueFormat1 = newFormats.first;
+    out->valueFormat2 = newFormats.second;
+
+    if (c->plan->all_axes_pinned)
+    {
+      out->valueFormat1 = out->valueFormat1.drop_device_table_flags ();
+      out->valueFormat2 = out->valueFormat2.drop_device_table_flags ();
+    }
+
+    unsigned total_len = len1 + len2;
+    hb_vector_t<unsigned> class2_idxs (+ hb_range ((unsigned) class2Count) | hb_filter (klass2_map));
+    for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
+    {
+      for (unsigned class2_idx : class2_idxs)
+      {
+        unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * total_len;
+        valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], &c->plan->layout_variation_idx_delta_map);
+        valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], &c->plan->layout_variation_idx_delta_map);
+      }
+    }
+
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto it =
+    + hb_iter (this+coverage)
+    | hb_filter (glyphset)
+    | hb_map_retains_sorting (glyph_map)
+    ;
+
+    out->coverage.serialize_serialize (c->serializer, it);
+    return_trace (out->class1Count && out->class2Count && bool (it));
+  }
+
+
+  hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_map_t& klass1_map,
+                                                                 const hb_map_t& klass2_map) const
+  {
+    unsigned len1 = valueFormat1.get_len ();
+    unsigned len2 = valueFormat2.get_len ();
+    unsigned record_size = len1 + len2;
+
+    unsigned format1 = 0;
+    unsigned format2 = 0;
+
+    for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
+    {
+      for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
+      {
+        unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * record_size;
+        format1 = format1 | valueFormat1.get_effective_format (&values[idx]);
+        format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]);
+      }
+
+      if (format1 == valueFormat1 && format2 == valueFormat2)
+        break;
+    }
+
+    return hb_pair (format1, format2);
+  }
+};
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_PAIRPOSFORMAT2_HH
diff --git a/src/OT/Layout/GPOS/PairSet.hh b/src/OT/Layout/GPOS/PairSet.hh
new file mode 100644 (file)
index 0000000..db301bb
--- /dev/null
@@ -0,0 +1,208 @@
+#ifndef OT_LAYOUT_GPOS_PAIRSET_HH
+#define OT_LAYOUT_GPOS_PAIRSET_HH
+
+#include "PairValueRecord.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+
+template <typename Types>
+struct PairSet
+{
+  template <typename Types2>
+  friend struct PairPosFormat1_3;
+
+  using PairValueRecord = GPOS_impl::PairValueRecord<Types>;
+
+  protected:
+  HBUINT16              len;    /* Number of PairValueRecords */
+  PairValueRecord       firstPairValueRecord;
+                                /* Array of PairValueRecords--ordered
+                                 * by GlyphID of the second glyph */
+  public:
+  DEFINE_SIZE_MIN (2);
+
+  static unsigned get_size (unsigned len1, unsigned len2)
+  {
+    return Types::HBGlyphID::static_size + Value::static_size * (len1 + len2);
+  }
+  static unsigned get_size (const ValueFormat valueFormats[2])
+  {
+    unsigned len1 = valueFormats[0].get_len ();
+    unsigned len2 = valueFormats[1].get_len ();
+    return get_size (len1, len2);
+  }
+
+  struct sanitize_closure_t
+  {
+    const ValueFormat *valueFormats;
+    unsigned int len1; /* valueFormats[0].get_len() */
+    unsigned int stride; /* bytes */
+  };
+
+  bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
+  {
+    TRACE_SANITIZE (this);
+    if (!(c->check_struct (this)
+       && c->check_range (&firstPairValueRecord,
+                          len,
+                          closure->stride))) return_trace (false);
+
+    unsigned int count = len;
+    const PairValueRecord *record = &firstPairValueRecord;
+    return_trace (c->lazy_some_gpos ||
+                 (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
+                   closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride)));
+  }
+
+  bool intersects (const hb_set_t *glyphs,
+                   const ValueFormat *valueFormats) const
+  {
+    unsigned record_size = get_size (valueFormats);
+
+    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
+  {
+    unsigned record_size = get_size (valueFormats);
+
+    const PairValueRecord *record = &firstPairValueRecord;
+    c->input->add_array (&record->secondGlyph, len, record_size);
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+                                  const ValueFormat *valueFormats) const
+  {
+    unsigned record_size = get_size (valueFormats);
+
+    const PairValueRecord *record = &firstPairValueRecord;
+    unsigned count = len;
+    for (unsigned i = 0; i < count; i++)
+    {
+      if (c->glyph_set->has (record->secondGlyph))
+      { record->collect_variation_indices (c, valueFormats, this); }
+
+      record = &StructAtOffset<const PairValueRecord> (record, record_size);
+    }
+  }
+
+  bool apply (hb_ot_apply_context_t *c,
+              const ValueFormat *valueFormats,
+              unsigned int pos) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int len1 = valueFormats[0].get_len ();
+    unsigned int len2 = valueFormats[1].get_len ();
+    unsigned record_size = get_size (len1, len2);
+
+    const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint,
+                                                &firstPairValueRecord,
+                                                len,
+                                                record_size);
+    if (record)
+    {
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+       c->buffer->message (c->font,
+                           "try kerning glyphs at %u,%u",
+                           c->buffer->idx, pos);
+      }
+
+      bool applied_first = len1 && valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
+      bool applied_second = len2 && valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
+
+      if (applied_first || applied_second)
+       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+       {
+         c->buffer->message (c->font,
+                             "kerned glyphs at %u,%u",
+                             c->buffer->idx, pos);
+       }
+
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+       c->buffer->message (c->font,
+                           "tried kerning glyphs at %u,%u",
+                           c->buffer->idx, pos);
+      }
+
+      if (applied_first || applied_second)
+        buffer->unsafe_to_break (buffer->idx, pos + 1);
+
+      if (len2)
+      {
+       pos++;
+      // https://github.com/harfbuzz/harfbuzz/issues/3824
+      // https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116
+      buffer->unsafe_to_break (buffer->idx, pos + 1);
+      }
+
+      buffer->idx = pos;
+      return_trace (true);
+    }
+    buffer->unsafe_to_concat (buffer->idx, pos + 1);
+    return_trace (false);
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const ValueFormat valueFormats[2],
+               const ValueFormat newFormats[2]) const
+  {
+    TRACE_SUBSET (this);
+    auto snap = c->serializer->snapshot ();
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->len = 0;
+
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    unsigned len1 = valueFormats[0].get_len ();
+    unsigned len2 = valueFormats[1].get_len ();
+    unsigned record_size = get_size (len1, len2);
+
+    typename PairValueRecord::context_t context =
+    {
+      this,
+      valueFormats,
+      newFormats,
+      len1,
+      &glyph_map,
+      &c->plan->layout_variation_idx_delta_map
+    };
+
+    const PairValueRecord *record = &firstPairValueRecord;
+    unsigned count = len, num = 0;
+    for (unsigned i = 0; i < count; i++)
+    {
+      if (glyphset.has (record->secondGlyph)
+         && record->subset (c, &context)) num++;
+      record = &StructAtOffset<const PairValueRecord> (record, record_size);
+    }
+
+    out->len = num;
+    if (!num) c->serializer->revert (snap);
+    return_trace (num);
+  }
+};
+
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_PAIRSET_HH
diff --git a/src/OT/Layout/GPOS/PairValueRecord.hh b/src/OT/Layout/GPOS/PairValueRecord.hh
new file mode 100644 (file)
index 0000000..72bf0e9
--- /dev/null
@@ -0,0 +1,99 @@
+#ifndef OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
+#define OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
+
+#include "ValueFormat.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+
+template <typename Types>
+struct PairValueRecord
+{
+  template <typename Types2>
+  friend struct PairSet;
+
+  protected:
+  typename Types::HBGlyphID
+               secondGlyph;            /* GlyphID of second glyph in the
+                                         * pair--first glyph is listed in the
+                                         * Coverage table */
+  ValueRecord   values;                 /* Positioning data for the first glyph
+                                         * followed by for second glyph */
+  public:
+  DEFINE_SIZE_ARRAY (Types::HBGlyphID::static_size, values);
+
+  int cmp (hb_codepoint_t k) const
+  { return secondGlyph.cmp (k); }
+
+  struct context_t
+  {
+    const void          *base;
+    const ValueFormat   *valueFormats;
+    const ValueFormat   *newFormats;
+    unsigned            len1; /* valueFormats[0].get_len() */
+    const hb_map_t      *glyph_map;
+    const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map;
+  };
+
+  bool subset (hb_subset_context_t *c,
+               context_t *closure) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *s = c->serializer;
+    auto *out = s->start_embed (*this);
+    if (unlikely (!s->extend_min (out))) return_trace (false);
+
+    out->secondGlyph = (*closure->glyph_map)[secondGlyph];
+
+    closure->valueFormats[0].copy_values (s,
+                                          closure->newFormats[0],
+                                          closure->base, &values[0],
+                                          closure->layout_variation_idx_delta_map);
+    closure->valueFormats[1].copy_values (s,
+                                          closure->newFormats[1],
+                                          closure->base,
+                                          &values[closure->len1],
+                                          closure->layout_variation_idx_delta_map);
+
+    return_trace (true);
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+                                  const ValueFormat *valueFormats,
+                                  const void *base) const
+  {
+    unsigned record1_len = valueFormats[0].get_len ();
+    unsigned record2_len = valueFormats[1].get_len ();
+    const hb_array_t<const Value> values_array = values.as_array (record1_len + record2_len);
+
+    if (valueFormats[0].has_device ())
+      valueFormats[0].collect_variation_indices (c, base, values_array.sub_array (0, record1_len));
+
+    if (valueFormats[1].has_device ())
+      valueFormats[1].collect_variation_indices (c, base, values_array.sub_array (record1_len, record2_len));
+  }
+
+  bool intersects (const hb_set_t& glyphset) const
+  {
+    return glyphset.has(secondGlyph);
+  }
+
+  const Value* get_values_1 () const
+  {
+    return &values[0];
+  }
+
+  const Value* get_values_2 (ValueFormat format1) const
+  {
+    return &values[format1.get_len ()];
+  }
+};
+
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
diff --git a/src/OT/Layout/GPOS/PosLookup.hh b/src/OT/Layout/GPOS/PosLookup.hh
new file mode 100644 (file)
index 0000000..c4e57bb
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef OT_LAYOUT_GPOS_POSLOOKUP_HH
+#define OT_LAYOUT_GPOS_POSLOOKUP_HH
+
+#include "PosLookupSubTable.hh"
+#include "../../../hb-ot-layout-common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct PosLookup : Lookup
+{
+  using SubTable = PosLookupSubTable;
+
+  const SubTable& get_subtable (unsigned int i) const
+  { return Lookup::get_subtable<SubTable> (i); }
+
+  bool is_reverse () const
+  {
+    return false;
+  }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    return_trace (dispatch (c));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    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); }
+
+  hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
+  {
+    if (c->is_lookup_visited (this_index))
+      return hb_closure_lookups_context_t::default_return_value ();
+
+    c->set_lookup_visited (this_index);
+    if (!intersects (c->glyphs))
+    {
+      c->set_lookup_inactive (this_index);
+      return hb_closure_lookups_context_t::default_return_value ();
+    }
+
+    hb_closure_lookups_context_t::return_t ret = dispatch (c);
+    return ret;
+  }
+
+  template <typename set_t>
+  void collect_coverage (set_t *glyphs) const
+  {
+    hb_collect_coverage_context_t<set_t> c (glyphs);
+    dispatch (&c);
+  }
+
+  template <typename context_t>
+  static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); }
+
+  bool subset (hb_subset_context_t *c) const
+  { return Lookup::subset<SubTable> (c); }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  { return Lookup::sanitize<SubTable> (c); }
+};
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GPOS_POSLOOKUP_HH */
diff --git a/src/OT/Layout/GPOS/PosLookupSubTable.hh b/src/OT/Layout/GPOS/PosLookupSubTable.hh
new file mode 100644 (file)
index 0000000..c19fbc3
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef OT_LAYOUT_GPOS_POSLOOKUPSUBTABLE_HH
+#define OT_LAYOUT_GPOS_POSLOOKUPSUBTABLE_HH
+
+#include "SinglePos.hh"
+#include "PairPos.hh"
+#include "CursivePos.hh"
+#include "MarkBasePos.hh"
+#include "MarkLigPos.hh"
+#include "MarkMarkPos.hh"
+#include "ContextPos.hh"
+#include "ChainContextPos.hh"
+#include "ExtensionPos.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct PosLookupSubTable
+{
+  friend struct ::OT::Lookup;
+  friend struct PosLookup;
+
+  enum Type {
+    Single              = 1,
+    Pair                = 2,
+    Cursive             = 3,
+    MarkBase            = 4,
+    MarkLig             = 5,
+    MarkMark            = 6,
+    Context             = 7,
+    ChainContext        = 8,
+    Extension           = 9
+  };
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
+  {
+    TRACE_DISPATCH (this, lookup_type);
+    switch (lookup_type) {
+    case Single:                return_trace (u.single.dispatch (c, std::forward<Ts> (ds)...));
+    case Pair:                  return_trace (u.pair.dispatch (c, std::forward<Ts> (ds)...));
+    case Cursive:               return_trace (u.cursive.dispatch (c, std::forward<Ts> (ds)...));
+    case MarkBase:              return_trace (u.markBase.dispatch (c, std::forward<Ts> (ds)...));
+    case MarkLig:               return_trace (u.markLig.dispatch (c, std::forward<Ts> (ds)...));
+    case MarkMark:              return_trace (u.markMark.dispatch (c, std::forward<Ts> (ds)...));
+    case Context:               return_trace (u.context.dispatch (c, std::forward<Ts> (ds)...));
+    case ChainContext:          return_trace (u.chainContext.dispatch (c, std::forward<Ts> (ds)...));
+    case Extension:             return_trace (u.extension.dispatch (c, std::forward<Ts> (ds)...));
+    default:                    return_trace (c->default_return_value ());
+    }
+  }
+
+  bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const
+  {
+    hb_intersects_context_t c (glyphs);
+    return dispatch (&c, lookup_type);
+  }
+
+  protected:
+  union {
+  SinglePos             single;
+  PairPos               pair;
+  CursivePos            cursive;
+  MarkBasePos           markBase;
+  MarkLigPos            markLig;
+  MarkMarkPos           markMark;
+  ContextPos            context;
+  ChainContextPos       chainContext;
+  ExtensionPos          extension;
+  } u;
+  public:
+  DEFINE_SIZE_MIN (0);
+};
+
+}
+}
+}
+
+#endif  /* HB_OT_LAYOUT_GPOS_POSLOOKUPSUBTABLE_HH */
diff --git a/src/OT/Layout/GPOS/SinglePos.hh b/src/OT/Layout/GPOS/SinglePos.hh
new file mode 100644 (file)
index 0000000..3af6c49
--- /dev/null
@@ -0,0 +1,100 @@
+#ifndef OT_LAYOUT_GPOS_SINGLEPOS_HH
+#define OT_LAYOUT_GPOS_SINGLEPOS_HH
+
+#include "SinglePosFormat1.hh"
+#include "SinglePosFormat2.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct SinglePos
+{
+  protected:
+  union {
+  HBUINT16              format;         /* Format identifier */
+  SinglePosFormat1      format1;
+  SinglePosFormat2      format2;
+  } u;
+
+  public:
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  unsigned get_format (Iterator glyph_val_iter_pairs)
+  {
+    hb_array_t<const Value> first_val_iter = hb_second (*glyph_val_iter_pairs);
+
+    for (const auto iter : glyph_val_iter_pairs)
+      for (const auto _ : hb_zip (iter.second, first_val_iter))
+        if (_.first != _.second)
+          return 2;
+
+    return 1;
+  }
+
+  template<typename Iterator,
+      typename SrcLookup,
+      hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+                  const SrcLookup* src,
+                  Iterator glyph_val_iter_pairs,
+                  const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
+                  bool all_axes_pinned)
+  {
+    if (unlikely (!c->extend_min (u.format))) return;
+    unsigned format = 2;
+    ValueFormat new_format = src->get_value_format ();
+
+    if (all_axes_pinned)
+      new_format = new_format.drop_device_table_flags ();
+
+    if (glyph_val_iter_pairs)
+      format = get_format (glyph_val_iter_pairs);
+
+    u.format = format;
+    switch (u.format) {
+    case 1: u.format1.serialize (c,
+                                 src,
+                                 glyph_val_iter_pairs,
+                                 new_format,
+                                 layout_variation_idx_delta_map);
+      return;
+    case 2: u.format2.serialize (c,
+                                 src,
+                                 glyph_val_iter_pairs,
+                                 new_format,
+                                 layout_variation_idx_delta_map);
+      return;
+    default:return;
+    }
+  }
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format);
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+};
+
+
+template<typename Iterator, typename SrcLookup>
+static void
+SinglePos_serialize (hb_serialize_context_t *c,
+                     const SrcLookup *src,
+                     Iterator it,
+                     const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
+                     bool all_axes_pinned)
+{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_delta_map, all_axes_pinned); }
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_SINGLEPOS_HH */
diff --git a/src/OT/Layout/GPOS/SinglePosFormat1.hh b/src/OT/Layout/GPOS/SinglePosFormat1.hh
new file mode 100644 (file)
index 0000000..dff1f73
--- /dev/null
@@ -0,0 +1,165 @@
+#ifndef OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH
+
+#include "Common.hh"
+#include "ValueFormat.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct SinglePosFormat1
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  Offset16To<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of subtable */
+  ValueFormat   valueFormat;            /* Defines the types of data in the
+                                         * ValueRecord */
+  ValueRecord   values;                 /* Defines positioning
+                                         * value(s)--applied to all glyphs in
+                                         * the Coverage table */
+  public:
+  DEFINE_SIZE_ARRAY (6, values);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  coverage.sanitize (c, this) &&
+                  /* The coverage  table may use a range to represent a set
+                   * of glyphs, which means a small number of bytes can
+                   * generate a large glyph set. Manually modify the
+                   * sanitizer max ops to take this into account.
+                   *
+                   * Note: This check *must* be right after coverage sanitize. */
+                  c->check_ops ((this + coverage).get_population () >> 1) &&
+                  valueFormat.sanitize_value (c, this, values));
+
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    if (!valueFormat.has_device ()) return;
+
+    hb_set_t intersection;
+    (this+coverage).intersect_set (*c->glyph_set, intersection);
+    if (!intersection) return;
+
+    valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ()));
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
+
+  const Coverage &get_coverage () const { return this+coverage; }
+
+  ValueFormat get_value_format () const { return valueFormat; }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+                         "positioning glyph at %u",
+                         c->buffer->idx);
+    }
+
+    valueFormat.apply_value (c, this, values, buffer->cur_pos());
+
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+                         "positioned glyph at %u",
+                         c->buffer->idx);
+    }
+
+    buffer->idx++;
+    return_trace (true);
+  }
+
+  bool
+  position_single (hb_font_t           *font,
+                  hb_blob_t           *table_blob,
+                  hb_direction_t       direction,
+                  hb_codepoint_t       gid,
+                  hb_glyph_position_t &pos) const
+  {
+    unsigned int index = (this+coverage).get_coverage  (gid);
+    if (likely (index == NOT_COVERED)) return false;
+
+    /* This is ugly... */
+    hb_buffer_t buffer;
+    buffer.props.direction = direction;
+    OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob);
+
+    valueFormat.apply_value (&c, this, values, pos);
+    return true;
+  }
+
+  template<typename Iterator,
+      typename SrcLookup,
+      hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+                  const SrcLookup *src,
+                  Iterator it,
+                  ValueFormat newFormat,
+                  const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map)
+  {
+    if (unlikely (!c->extend_min (this))) return;
+    if (unlikely (!c->check_assign (valueFormat,
+                                    newFormat,
+                                    HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
+
+    for (const hb_array_t<const Value>& _ : + it | hb_map (hb_second))
+    {
+      src->get_value_format ().copy_values (c, newFormat, src,  &_, layout_variation_idx_delta_map);
+      // Only serialize the first entry in the iterator, the rest are assumed to
+      // be the same.
+      break;
+    }
+
+    auto glyphs =
+    + it
+    | hb_map_retains_sorting (hb_first)
+    ;
+
+    coverage.serialize_serialize (c, glyphs);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    hb_set_t intersection;
+    (this+coverage).intersect_set (glyphset, intersection);
+
+    auto it =
+    + hb_iter (intersection)
+    | hb_map_retains_sorting (glyph_map)
+    | hb_zip (hb_repeat (values.as_array (valueFormat.get_len ())))
+    ;
+
+    bool ret = bool (it);
+    SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned);
+    return_trace (ret);
+  }
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH */
diff --git a/src/OT/Layout/GPOS/SinglePosFormat2.hh b/src/OT/Layout/GPOS/SinglePosFormat2.hh
new file mode 100644 (file)
index 0000000..168ad3b
--- /dev/null
@@ -0,0 +1,177 @@
+#ifndef OT_LAYOUT_GPOS_SINGLEPOSFORMAT2_HH
+#define OT_LAYOUT_GPOS_SINGLEPOSFORMAT2_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct SinglePosFormat2
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 2 */
+  Offset16To<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of subtable */
+  ValueFormat   valueFormat;            /* Defines the types of data in the
+                                         * ValueRecord */
+  HBUINT16      valueCount;             /* Number of ValueRecords */
+  ValueRecord   values;                 /* Array of ValueRecords--positioning
+                                         * values applied to glyphs */
+  public:
+  DEFINE_SIZE_ARRAY (8, values);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  coverage.sanitize (c, this) &&
+                  valueFormat.sanitize_values (c, this, values, valueCount));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    if (!valueFormat.has_device ()) return;
+
+    auto it =
+    + hb_zip (this+coverage, hb_range ((unsigned) valueCount))
+    | hb_filter (c->glyph_set, hb_first)
+    ;
+
+    if (!it) return;
+
+    unsigned sub_length = valueFormat.get_len ();
+    const hb_array_t<const Value> values_array = values.as_array (valueCount * sub_length);
+
+    for (unsigned i : + it
+                      | hb_map (hb_second))
+      valueFormat.collect_variation_indices (c, this, values_array.sub_array (i * sub_length, sub_length));
+
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
+
+  const Coverage &get_coverage () const { return this+coverage; }
+
+  ValueFormat get_value_format () const { return valueFormat; }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    if (unlikely (index >= valueCount)) return_trace (false);
+
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+                         "positioning glyph at %u",
+                         c->buffer->idx);
+    }
+
+    valueFormat.apply_value (c, this,
+                             &values[index * valueFormat.get_len ()],
+                             buffer->cur_pos());
+
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+                         "positioned glyph at %u",
+                         c->buffer->idx);
+    }
+
+    buffer->idx++;
+    return_trace (true);
+  }
+
+  bool
+  position_single (hb_font_t           *font,
+                  hb_blob_t           *table_blob,
+                  hb_direction_t       direction,
+                  hb_codepoint_t       gid,
+                  hb_glyph_position_t &pos) const
+  {
+    unsigned int index = (this+coverage).get_coverage  (gid);
+    if (likely (index == NOT_COVERED)) return false;
+    if (unlikely (index >= valueCount)) return false;
+
+    /* This is ugly... */
+    hb_buffer_t buffer;
+    buffer.props.direction = direction;
+    OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob);
+
+    valueFormat.apply_value (&c, this,
+                             &values[index * valueFormat.get_len ()],
+                             pos);
+    return true;
+  }
+
+
+  template<typename Iterator,
+      typename SrcLookup,
+      hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+                  const SrcLookup *src,
+                  Iterator it,
+                  ValueFormat newFormat,
+                  const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map)
+  {
+    auto out = c->extend_min (this);
+    if (unlikely (!out)) return;
+    if (unlikely (!c->check_assign (valueFormat, newFormat, HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
+    if (unlikely (!c->check_assign (valueCount, it.len (), HB_SERIALIZE_ERROR_ARRAY_OVERFLOW))) return;
+
+    + it
+    | hb_map (hb_second)
+    | hb_apply ([&] (hb_array_t<const Value> _)
+    { src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_delta_map); })
+    ;
+
+    auto glyphs =
+    + it
+    | hb_map_retains_sorting (hb_first)
+    ;
+
+    coverage.serialize_serialize (c, glyphs);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    unsigned sub_length = valueFormat.get_len ();
+    auto values_array = values.as_array (valueCount * sub_length);
+
+    auto it =
+    + hb_zip (this+coverage, hb_range ((unsigned) valueCount))
+    | hb_filter (glyphset, hb_first)
+    | hb_map_retains_sorting ([&] (const hb_pair_t<hb_codepoint_t, unsigned>& _)
+                              {
+                                return hb_pair (glyph_map[_.first],
+                                                values_array.sub_array (_.second * sub_length,
+                                                                        sub_length));
+                              })
+    ;
+
+    bool ret = bool (it);
+    SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned);
+    return_trace (ret);
+  }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_SINGLEPOSFORMAT2_HH */
diff --git a/src/OT/Layout/GPOS/ValueFormat.hh b/src/OT/Layout/GPOS/ValueFormat.hh
new file mode 100644 (file)
index 0000000..461a13d
--- /dev/null
@@ -0,0 +1,412 @@
+#ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH
+#define OT_LAYOUT_GPOS_VALUEFORMAT_HH
+
+#include "../../../hb-ot-layout-gsubgpos.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+typedef HBUINT16 Value;
+
+typedef UnsizedArrayOf<Value> ValueRecord;
+
+struct ValueFormat : HBUINT16
+{
+  enum Flags {
+    xPlacement  = 0x0001u,      /* Includes horizontal adjustment for placement */
+    yPlacement  = 0x0002u,      /* Includes vertical adjustment for placement */
+    xAdvance    = 0x0004u,      /* Includes horizontal adjustment for advance */
+    yAdvance    = 0x0008u,      /* Includes vertical adjustment for advance */
+    xPlaDevice  = 0x0010u,      /* Includes horizontal Device table for placement */
+    yPlaDevice  = 0x0020u,      /* Includes vertical Device table for placement */
+    xAdvDevice  = 0x0040u,      /* Includes horizontal Device table for advance */
+    yAdvDevice  = 0x0080u,      /* Includes vertical Device table for advance */
+    ignored     = 0x0F00u,      /* Was used in TrueType Open for MM fonts */
+    reserved    = 0xF000u,      /* For future use */
+
+    devices     = 0x00F0u       /* Mask for having any Device table */
+  };
+
+/* All fields are options.  Only those available advance the value pointer. */
+#if 0
+  HBINT16               xPlacement;     /* Horizontal adjustment for
+                                         * placement--in design units */
+  HBINT16               yPlacement;     /* Vertical adjustment for
+                                         * placement--in design units */
+  HBINT16               xAdvance;       /* Horizontal adjustment for
+                                         * advance--in design units (only used
+                                         * for horizontal writing) */
+  HBINT16               yAdvance;       /* Vertical adjustment for advance--in
+                                         * design units (only used for vertical
+                                         * writing) */
+  Offset16To<Device>    xPlaDevice;     /* Offset to Device table for
+                                         * horizontal placement--measured from
+                                         * beginning of PosTable (may be NULL) */
+  Offset16To<Device>    yPlaDevice;     /* Offset to Device table for vertical
+                                         * placement--measured from beginning
+                                         * of PosTable (may be NULL) */
+  Offset16To<Device>    xAdvDevice;     /* Offset to Device table for
+                                         * horizontal advance--measured from
+                                         * beginning of PosTable (may be NULL) */
+  Offset16To<Device>    yAdvDevice;     /* Offset to Device table for vertical
+                                         * advance--measured from beginning of
+                                         * PosTable (may be NULL) */
+#endif
+
+  IntType& operator = (uint16_t i) { v = i; return *this; }
+
+  unsigned int get_len () const  { return hb_popcount ((unsigned int) *this); }
+  unsigned int get_size () const { return get_len () * Value::static_size; }
+
+  hb_vector_t<unsigned> get_device_table_indices () const {
+    unsigned i = 0;
+    hb_vector_t<unsigned> result;
+    unsigned format = *this;
+
+    if (format & xPlacement) i++;
+    if (format & yPlacement) i++;
+    if (format & xAdvance)   i++;
+    if (format & yAdvance)   i++;
+
+    if (format & xPlaDevice) result.push (i++);
+    if (format & yPlaDevice) result.push (i++);
+    if (format & xAdvDevice) result.push (i++);
+    if (format & yAdvDevice) result.push (i++);
+
+    return result;
+  }
+
+  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 ret;
+
+    hb_font_t *font = c->font;
+    bool horizontal =
+#ifndef HB_NO_VERTICAL
+      HB_DIRECTION_IS_HORIZONTAL (c->direction)
+#else
+      true
+#endif
+      ;
+
+    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, &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, &ret));
+      values++;
+    }
+
+    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 ret;
+
+    const VariationStore &store = c->var_store;
+    auto *cache = c->var_store_cache;
+
+    /* pixel -> fractional pixel */
+    if (format & xPlaDevice)
+    {
+      if (use_x_device) glyph_pos.x_offset  += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache);
+      values++;
+    }
+    if (format & yPlaDevice)
+    {
+      if (use_y_device) glyph_pos.y_offset  += get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache);
+      values++;
+    }
+    if (format & xAdvDevice)
+    {
+      if (horizontal && use_x_device) glyph_pos.x_advance += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache);
+      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 -= get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache);
+      values++;
+    }
+    return ret;
+  }
+
+  unsigned int get_effective_format (const Value *values) const
+  {
+    unsigned int format = *this;
+    for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) {
+      if (format & flag) should_drop (*values++, (Flags) flag, &format);
+    }
+
+    return format;
+  }
+
+  template<typename Iterator,
+      hb_requires (hb_is_iterator (Iterator))>
+  unsigned int get_effective_format (Iterator it) const {
+    unsigned int new_format = 0;
+
+    for (const hb_array_t<const Value>& values : it)
+      new_format = new_format | get_effective_format (&values);
+
+    return new_format;
+  }
+
+  void copy_values (hb_serialize_context_t *c,
+                    unsigned int new_format,
+                    const void *base,
+                    const Value *values,
+                    const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
+  {
+    unsigned int format = *this;
+    if (!format) return;
+
+    HBINT16 *x_placement = nullptr, *y_placement = nullptr, *x_adv = nullptr, *y_adv = nullptr;
+    if (format & xPlacement) x_placement = copy_value (c, new_format, xPlacement, *values++);
+    if (format & yPlacement) y_placement = copy_value (c, new_format, yPlacement, *values++);
+    if (format & xAdvance)   x_adv = copy_value (c, new_format, xAdvance, *values++);
+    if (format & yAdvance)   y_adv = copy_value (c, new_format, yAdvance, *values++);
+
+    if (!has_device ())
+      return;
+
+    if (format & xPlaDevice)
+    {
+      add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map);
+      copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xPlaDevice);
+    }
+
+    if (format & yPlaDevice)
+    {
+      add_delta_to_value (y_placement, base, values, layout_variation_idx_delta_map);
+      copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yPlaDevice);
+    }
+
+    if (format & xAdvDevice)
+    {
+      add_delta_to_value (x_adv, base, values, layout_variation_idx_delta_map);
+      copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xAdvDevice);
+    }
+
+    if (format & yAdvDevice)
+    {
+      add_delta_to_value (y_adv, base, values, layout_variation_idx_delta_map);
+      copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yAdvDevice);
+    }
+  }
+
+  HBINT16* copy_value (hb_serialize_context_t *c,
+                       unsigned int new_format,
+                       Flags flag,
+                       Value value) const
+  {
+    // Filter by new format.
+    if (!(new_format & flag)) return nullptr;
+    return reinterpret_cast<HBINT16 *> (c->copy (value));
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+                                  const void *base,
+                                  const hb_array_t<const Value>& values) const
+  {
+    unsigned format = *this;
+    unsigned i = 0;
+    if (format & xPlacement) i++;
+    if (format & yPlacement) i++;
+    if (format & xAdvance) i++;
+    if (format & yAdvance) i++;
+    if (format & xPlaDevice)
+    {
+      (base + get_device (&(values[i]))).collect_variation_indices (c);
+      i++;
+    }
+
+    if (format & ValueFormat::yPlaDevice)
+    {
+      (base + get_device (&(values[i]))).collect_variation_indices (c);
+      i++;
+    }
+
+    if (format & ValueFormat::xAdvDevice)
+    {
+      (base + get_device (&(values[i]))).collect_variation_indices (c);
+      i++;
+    }
+
+    if (format & ValueFormat::yAdvDevice)
+    {
+      (base + get_device (&(values[i]))).collect_variation_indices (c);
+      i++;
+    }
+  }
+
+  unsigned drop_device_table_flags () const
+  {
+    unsigned format = *this;
+    for (unsigned flag = xPlaDevice; flag <= yAdvDevice; flag = flag << 1)
+      format = format & ~flag;
+
+    return format;
+  }
+
+  private:
+  bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
+  {
+    unsigned int format = *this;
+
+    if (format & xPlacement) values++;
+    if (format & yPlacement) values++;
+    if (format & xAdvance)   values++;
+    if (format & yAdvance)   values++;
+
+    if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
+    if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
+    if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
+    if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
+
+    return true;
+  }
+
+  static inline Offset16To<Device>& get_device (Value* value)
+  {
+    return *static_cast<Offset16To<Device> *> (value);
+  }
+  static inline const Offset16To<Device>& get_device (const Value* value)
+  {
+    return *static_cast<const Offset16To<Device> *> (value);
+  }
+  static inline const Device& get_device (const Value* value,
+                                         bool *worked,
+                                         const void *base,
+                                         hb_sanitize_context_t &c)
+  {
+    if (worked) *worked |= bool (*value);
+    auto &offset = *static_cast<const Offset16To<Device> *> (value);
+
+    if (unlikely (!offset.sanitize (&c, base)))
+      return Null(Device);
+
+    return base + offset;
+  }
+
+  void add_delta_to_value (HBINT16 *value,
+                           const void *base,
+                           const Value *src_value,
+                           const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
+  {
+    if (!value) return;
+    unsigned varidx = (base + get_device (src_value)).get_variation_index ();
+    hb_pair_t<unsigned, int> *varidx_delta;
+    if (!layout_variation_idx_delta_map->has (varidx, &varidx_delta)) return;
+
+    *value += hb_second (*varidx_delta);
+  }
+
+  bool copy_device (hb_serialize_context_t *c, const void *base,
+                    const Value *src_value,
+                    const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
+                    unsigned int new_format, Flags flag) const
+  {
+    // Filter by new format.
+    if (!(new_format & flag)) return true;
+
+    Value       *dst_value = c->copy (*src_value);
+
+    if (!dst_value) return false;
+    if (*dst_value == 0) return true;
+
+    *dst_value = 0;
+    c->push ();
+    if ((base + get_device (src_value)).copy (c, layout_variation_idx_delta_map))
+    {
+      c->add_link (*dst_value, c->pop_pack ());
+      return true;
+    }
+    else
+    {
+      c->pop_discard ();
+      return false;
+    }
+  }
+
+  static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr)
+  {
+    if (worked) *worked |= bool (*value);
+    return *reinterpret_cast<const HBINT16 *> (value);
+  }
+
+  public:
+
+  bool has_device () const
+  {
+    unsigned int format = *this;
+    return (format & devices) != 0;
+  }
+
+  bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
+  {
+    TRACE_SANITIZE (this);
+
+    if (unlikely (!c->check_range (values, get_size ()))) return_trace (false);
+
+    if (c->lazy_some_gpos)
+      return_trace (true);
+
+    return_trace (!has_device () || sanitize_value_devices (c, base, values));
+  }
+
+  bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
+  {
+    TRACE_SANITIZE (this);
+    unsigned size = get_size ();
+
+    if (!c->check_range (values, count, size)) return_trace (false);
+
+    if (c->lazy_some_gpos)
+      return_trace (true);
+
+    return_trace (sanitize_values_stride_unsafe (c, base, values, count, size));
+  }
+
+  /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
+  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);
+
+    if (!has_device ()) return_trace (true);
+
+    for (unsigned int i = 0; i < count; i++) {
+      if (!sanitize_value_devices (c, base, values))
+        return_trace (false);
+      values = &StructAtOffset<const Value> (values, stride);
+    }
+
+    return_trace (true);
+  }
+
+ private:
+
+  void should_drop (Value value, Flags flag, unsigned int* format) const
+  {
+    if (value) return;
+    *format = *format & ~flag;
+  }
+
+};
+
+}
+}
+}
+
+#endif  // #ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH
diff --git a/src/OT/Layout/GSUB/AlternateSet.hh b/src/OT/Layout/GSUB/AlternateSet.hh
new file mode 100644 (file)
index 0000000..b446611
--- /dev/null
@@ -0,0 +1,126 @@
+#ifndef OT_LAYOUT_GSUB_ALTERNATESET_HH
+#define OT_LAYOUT_GSUB_ALTERNATESET_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+template <typename Types>
+struct AlternateSet
+{
+  protected:
+  Array16Of<typename Types::HBGlyphID>
+                alternates;             /* Array of alternate GlyphIDs--in
+                                         * arbitrary order */
+  public:
+  DEFINE_SIZE_ARRAY (2, alternates);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (alternates.sanitize (c));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return hb_any (alternates, glyphs); }
+
+  void closure (hb_closure_context_t *c) const
+  { c->output->add_array (alternates.arrayZ, alternates.len); }
+
+  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_VALUE, randomize feature if it is the rand feature. */
+    if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
+    {
+      /* Maybe we can do better than unsafe-to-break all; but since we are
+       * changing random state, it would be hard to track that.  Good 'nough. */
+      c->buffer->unsafe_to_break (0, c->buffer->len);
+      alt_index = c->random_number () % count + 1;
+    }
+
+    if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
+
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->sync_so_far ();
+      c->buffer->message (c->font,
+                         "replacing glyph at %u (alternate substitution)",
+                         c->buffer->idx);
+    }
+
+    c->replace_glyph (alternates[alt_index - 1]);
+
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+                         "replaced glyph at %u (alternate substitution)",
+                         c->buffer->idx - 1u);
+    }
+
+    return_trace (true);
+  }
+
+  unsigned
+  get_alternates (unsigned        start_offset,
+                  unsigned       *alternate_count  /* IN/OUT.  May be NULL. */,
+                  hb_codepoint_t *alternate_glyphs /* OUT.     May be NULL. */) const
+  {
+    if (alternates.len && alternate_count)
+    {
+      + alternates.as_array ().sub_array (start_offset, alternate_count)
+      | hb_sink (hb_array (alternate_glyphs, *alternate_count))
+      ;
+    }
+    return alternates.len;
+  }
+
+  template <typename Iterator,
+            hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c,
+                  Iterator alts)
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (alternates.serialize (c, alts));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto it =
+      + hb_iter (alternates)
+      | hb_filter (glyphset)
+      | hb_map (glyph_map)
+      ;
+
+    auto *out = c->serializer->start_embed (*this);
+    return_trace (out->serialize (c->serializer, it) &&
+                  out->alternates);
+  }
+};
+
+}
+}
+}
+
+
+#endif /* OT_LAYOUT_GSUB_ALTERNATESET_HH */
diff --git a/src/OT/Layout/GSUB/AlternateSubst.hh b/src/OT/Layout/GSUB/AlternateSubst.hh
new file mode 100644 (file)
index 0000000..04a052a
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef OT_LAYOUT_GSUB_ALTERNATESUBST_HH
+#define OT_LAYOUT_GSUB_ALTERNATESUBST_HH
+
+#include "AlternateSubstFormat1.hh"
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct AlternateSubst
+{
+  protected:
+  union {
+  HBUINT16                             format;         /* Format identifier */
+  AlternateSubstFormat1_2<SmallTypes>  format1;
+#ifndef HB_NO_BEYOND_64K
+  AlternateSubstFormat1_2<MediumTypes> format2;
+#endif
+  } u;
+  public:
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format);
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+#ifndef HB_NO_BEYOND_64K
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  /* TODO This function is unused and not updated to 24bit GIDs. Should be done by using
+   * iterators. While at it perhaps using iterator of arrays of hb_codepoint_t instead. */
+  bool serialize (hb_serialize_context_t *c,
+                  hb_sorted_array_t<const HBGlyphID16> glyphs,
+                  hb_array_t<const unsigned int> alternate_len_list,
+                  hb_array_t<const HBGlyphID16> alternate_glyphs_list)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (u.format))) return_trace (false);
+    unsigned int format = 1;
+    u.format = format;
+    switch (u.format) {
+    case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list));
+    default:return_trace (false);
+    }
+  }
+
+  /* TODO subset() should choose format. */
+
+};
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_ALTERNATESUBST_HH */
diff --git a/src/OT/Layout/GSUB/AlternateSubstFormat1.hh b/src/OT/Layout/GSUB/AlternateSubstFormat1.hh
new file mode 100644 (file)
index 0000000..adec65d
--- /dev/null
@@ -0,0 +1,128 @@
+#ifndef OT_LAYOUT_GSUB_ALTERNATESUBSTFORMAT1_HH
+#define OT_LAYOUT_GSUB_ALTERNATESUBSTFORMAT1_HH
+
+#include "AlternateSet.hh"
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+template <typename Types>
+struct AlternateSubstFormat1_2
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  typename Types::template OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of Substitution table */
+  Array16Of<typename Types::template OffsetTo<AlternateSet<Types>>>
+                alternateSet;           /* Array of AlternateSet tables
+                                         * ordered by Coverage Index */
+  public:
+  DEFINE_SIZE_ARRAY (2 + 2 * Types::size, alternateSet);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
+  bool may_have_non_1to1 () const
+  { return false; }
+
+  void closure (hb_closure_context_t *c) const
+  {
+    + hb_zip (this+coverage, alternateSet)
+    | hb_filter (c->parent_active_glyphs (), hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const AlternateSet<Types> &_) { _.closure (c); })
+    ;
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+    + hb_zip (this+coverage, alternateSet)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const AlternateSet<Types> &_) { _.collect_glyphs (c); })
+    ;
+  }
+
+  const Coverage &get_coverage () const { return this+coverage; }
+
+  bool would_apply (hb_would_apply_context_t *c) const
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+
+  unsigned
+  get_glyph_alternates (hb_codepoint_t  gid,
+                        unsigned        start_offset,
+                        unsigned       *alternate_count  /* IN/OUT.  May be NULL. */,
+                        hb_codepoint_t *alternate_glyphs /* OUT.     May be NULL. */) const
+  { return (this+alternateSet[(this+coverage).get_coverage (gid)])
+           .get_alternates (start_offset, alternate_count, alternate_glyphs); }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    return_trace ((this+alternateSet[index]).apply (c));
+  }
+
+  bool serialize (hb_serialize_context_t *c,
+                  hb_sorted_array_t<const HBGlyphID16> glyphs,
+                  hb_array_t<const unsigned int> alternate_len_list,
+                  hb_array_t<const HBGlyphID16> alternate_glyphs_list)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    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_serialize (c, alternate_glyphs_list.sub_array (0, alternate_len))))
+        return_trace (false);
+      alternate_glyphs_list += alternate_len;
+    }
+    return_trace (coverage.serialize_serialize (c, glyphs));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, alternateSet)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (subset_offset_array (c, out->alternateSet, this), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
+    return_trace (bool (new_coverage));
+  }
+};
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_ALTERNATESUBSTFORMAT1_HH */
diff --git a/src/OT/Layout/GSUB/ChainContextSubst.hh b/src/OT/Layout/GSUB/ChainContextSubst.hh
new file mode 100644 (file)
index 0000000..08fd779
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef OT_LAYOUT_GSUB_CHAINCONTEXTSUBST_HH
+#define OT_LAYOUT_GSUB_CHAINCONTEXTSUBST_HH
+
+// TODO(garretrieger): move to new layout.
+#include "../../../hb-ot-layout-gsubgpos.hh"
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct ChainContextSubst : ChainContext {};
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_CHAINCONTEXTSUBST_HH */
diff --git a/src/OT/Layout/GSUB/Common.hh b/src/OT/Layout/GSUB/Common.hh
new file mode 100644 (file)
index 0000000..b849494
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef OT_LAYOUT_GSUB_COMMON_HH
+#define OT_LAYOUT_GSUB_COMMON_HH
+
+#include "../../../hb-serialize.hh"
+#include "../../../hb-ot-layout-gsubgpos.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+template<typename Iterator>
+static void SingleSubst_serialize (hb_serialize_context_t *c,
+                                   Iterator it);
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_COMMON_HH */
diff --git a/src/OT/Layout/GSUB/ContextSubst.hh b/src/OT/Layout/GSUB/ContextSubst.hh
new file mode 100644 (file)
index 0000000..9f8cb46
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef OT_LAYOUT_GSUB_CONTEXTSUBST_HH
+#define OT_LAYOUT_GSUB_CONTEXTSUBST_HH
+
+// TODO(garretrieger): move to new layout.
+#include "../../../hb-ot-layout-gsubgpos.hh"
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct ContextSubst : Context {};
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_CONTEXTSUBST_HH */
diff --git a/src/OT/Layout/GSUB/ExtensionSubst.hh b/src/OT/Layout/GSUB/ExtensionSubst.hh
new file mode 100644 (file)
index 0000000..831a7df
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef OT_LAYOUT_GSUB_EXTENSIONSUBST_HH
+#define OT_LAYOUT_GSUB_EXTENSIONSUBST_HH
+
+// TODO(garretrieger): move to new layout.
+#include "../../../hb-ot-layout-gsubgpos.hh"
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct ExtensionSubst : Extension<ExtensionSubst>
+{
+  typedef struct SubstLookupSubTable SubTable;
+  bool is_reverse () const;
+};
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_EXTENSIONSUBST_HH */
diff --git a/src/OT/Layout/GSUB/GSUB.hh b/src/OT/Layout/GSUB/GSUB.hh
new file mode 100644 (file)
index 0000000..900cf60
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef OT_LAYOUT_GSUB_GSUB_HH
+#define OT_LAYOUT_GSUB_GSUB_HH
+
+#include "../../../hb-ot-layout-gsubgpos.hh"
+#include "Common.hh"
+#include "SubstLookup.hh"
+
+namespace OT {
+
+using Layout::GSUB_impl::SubstLookup;
+
+namespace Layout {
+
+/*
+ * GSUB -- Glyph Substitution
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
+ */
+
+struct GSUB : GSUBGPOS
+{
+  using Lookup = SubstLookup;
+
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
+
+  const SubstLookup& get_lookup (unsigned int i) const
+  { return static_cast<const SubstLookup &> (GSUBGPOS::get_lookup (i)); }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    hb_subset_layout_context_t l (c, tableTag);
+    return GSUBGPOS::subset<SubstLookup> (&l);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (GSUBGPOS::sanitize<SubstLookup> (c));
+  }
+
+  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
+                                   hb_face_t *face) const;
+
+  void closure_lookups (hb_face_t      *face,
+                        const hb_set_t *glyphs,
+                        hb_set_t       *lookup_indexes /* IN/OUT */) const
+  { GSUBGPOS::closure_lookups<SubstLookup> (face, glyphs, lookup_indexes); }
+
+  typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
+};
+
+
+}
+
+struct GSUB_accelerator_t : Layout::GSUB::accelerator_t {
+  GSUB_accelerator_t (hb_face_t *face) : Layout::GSUB::accelerator_t (face) {}
+};
+
+
+}
+
+#endif  /* OT_LAYOUT_GSUB_GSUB_HH */
diff --git a/src/OT/Layout/GSUB/Ligature.hh b/src/OT/Layout/GSUB/Ligature.hh
new file mode 100644 (file)
index 0000000..402ed12
--- /dev/null
@@ -0,0 +1,190 @@
+#ifndef OT_LAYOUT_GSUB_LIGATURE_HH
+#define OT_LAYOUT_GSUB_LIGATURE_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+template <typename Types>
+struct Ligature
+{
+  public:
+  typename Types::HBGlyphID
+               ligGlyph;               /* GlyphID of ligature to substitute */
+  HeadlessArray16Of<typename Types::HBGlyphID>
+               component;              /* Array of component GlyphIDs--start
+                                         * with the second  component--ordered
+                                         * in writing direction */
+  public:
+  DEFINE_SIZE_ARRAY (Types::size + 2, component);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return hb_all (component, glyphs); }
+
+  bool intersects_lig_glyph (const hb_set_t *glyphs) const
+  { return glyphs->has(ligGlyph); }
+
+  void closure (hb_closure_context_t *c) const
+  {
+    if (!intersects (c->glyphs)) return;
+    c->output->add (ligGlyph);
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    c->input->add_array (component.arrayZ, component.get_length ());
+    c->output->add (ligGlyph);
+  }
+
+  bool would_apply (hb_would_apply_context_t *c) const
+  {
+    if (c->len != component.lenP1)
+      return false;
+
+    for (unsigned int i = 1; i < c->len; i++)
+      if (likely (c->glyphs[i] != component[i]))
+        return false;
+
+    return true;
+  }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    unsigned int count = component.lenP1;
+
+    if (unlikely (!count)) return_trace (false);
+
+    /* Special-case to make it in-place and not consider this
+     * as a "ligated" substitution. */
+    if (unlikely (count == 1))
+    {
+
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+       c->buffer->sync_so_far ();
+       c->buffer->message (c->font,
+                           "replacing glyph at %u (ligature substitution)",
+                           c->buffer->idx);
+      }
+
+      c->replace_glyph (ligGlyph);
+
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+       c->buffer->message (c->font,
+                           "replaced glyph at %u (ligature substitution)",
+                           c->buffer->idx - 1u);
+      }
+
+      return_trace (true);
+    }
+
+    unsigned int total_component_count = 0;
+
+    unsigned int match_end = 0;
+    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
+
+    if (likely (!match_input (c, count,
+                              &component[1],
+                              match_glyph,
+                              nullptr,
+                              &match_end,
+                              match_positions,
+                              &total_component_count)))
+    {
+      c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
+      return_trace (false);
+    }
+
+    unsigned pos = 0;
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      unsigned delta = c->buffer->sync_so_far ();
+
+      pos = c->buffer->idx;
+
+      char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0};
+      char *p = buf;
+
+      match_end += delta;
+      for (unsigned i = 0; i < count; i++)
+      {
+       match_positions[i] += delta;
+       if (i)
+         *p++ = ',';
+       snprintf (p, sizeof(buf) - (p - buf), "%u", match_positions[i]);
+       p += strlen(p);
+      }
+
+      c->buffer->message (c->font,
+                         "ligating glyphs at %s",
+                         buf);
+    }
+
+    ligate_input (c,
+                  count,
+                  match_positions,
+                  match_end,
+                  ligGlyph,
+                  total_component_count);
+
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->sync_so_far ();
+      c->buffer->message (c->font,
+                         "ligated glyph at %u",
+                         pos);
+    }
+
+    return_trace (true);
+  }
+
+  template <typename Iterator,
+            hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c,
+                  hb_codepoint_t ligature,
+                  Iterator components /* Starting from second */)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    ligGlyph = ligature;
+    if (unlikely (!component.serialize (c, components))) return_trace (false);
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c, unsigned coverage_idx) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false);
+    // Ensure Coverage table is always packed after this.
+    c->serializer->add_virtual_link (coverage_idx);
+
+    auto it =
+      + hb_iter (component)
+      | hb_map (glyph_map)
+      ;
+
+    auto *out = c->serializer->start_embed (*this);
+    return_trace (out->serialize (c->serializer,
+                                  glyph_map[ligGlyph],
+                                  it));  }
+};
+
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_LIGATURE_HH */
diff --git a/src/OT/Layout/GSUB/LigatureSet.hh b/src/OT/Layout/GSUB/LigatureSet.hh
new file mode 100644 (file)
index 0000000..0866543
--- /dev/null
@@ -0,0 +1,188 @@
+#ifndef OT_LAYOUT_GSUB_LIGATURESET_HH
+#define OT_LAYOUT_GSUB_LIGATURESET_HH
+
+#include "Common.hh"
+#include "Ligature.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+template <typename Types>
+struct LigatureSet
+{
+  protected:
+  Array16OfOffset16To<Ligature<Types>>
+                ligature;               /* Array LigatureSet tables
+                                         * ordered by preference */
+  public:
+  DEFINE_SIZE_ARRAY (2, ligature);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (ligature.sanitize (c, this));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    return
+    + hb_iter (ligature)
+    | hb_map (hb_add (this))
+    | hb_map ([glyphs] (const Ligature<Types> &_) { return _.intersects (glyphs); })
+    | hb_any
+    ;
+  }
+
+  bool intersects_lig_glyph (const hb_set_t *glyphs) const
+  {
+    return
+    + hb_iter (ligature)
+    | hb_map (hb_add (this))
+    | hb_map ([glyphs] (const Ligature<Types> &_) { 
+      return _.intersects_lig_glyph (glyphs) && _.intersects (glyphs);
+    })
+    | hb_any
+    ;
+  }
+
+  void closure (hb_closure_context_t *c) const
+  {
+    + hb_iter (ligature)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const Ligature<Types> &_) { _.closure (c); })
+    ;
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    + hb_iter (ligature)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const Ligature<Types> &_) { _.collect_glyphs (c); })
+    ;
+  }
+
+  bool would_apply (hb_would_apply_context_t *c) const
+  {
+    return
+    + hb_iter (ligature)
+    | hb_map (hb_add (this))
+    | hb_map ([c] (const Ligature<Types> &_) { return _.would_apply (c); })
+    | hb_any
+    ;
+  }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+
+    unsigned int num_ligs = ligature.len;
+
+#ifndef HB_NO_OT_RULESETS_FAST_PATH
+    if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 4)
+#endif
+    {
+    slow:
+      for (unsigned int i = 0; i < num_ligs; i++)
+      {
+       const auto &lig = this+ligature.arrayZ[i];
+       if (lig.apply (c)) return_trace (true);
+      }
+      return_trace (false);
+    }
+
+    /* This version is optimized for speed by matching the first component
+     * of the ligature here, instead of calling into the ligation code.
+     *
+     * This is replicated in ChainRuleSet and RuleSet. */
+
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (c->buffer->idx);
+    skippy_iter.set_match_func (match_always, nullptr);
+    skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
+    unsigned unsafe_to;
+    hb_codepoint_t first = (unsigned) -1;
+    bool matched = skippy_iter.next (&unsafe_to);
+    if (likely (matched))
+    {
+      first = c->buffer->info[skippy_iter.idx].codepoint;
+      unsafe_to = skippy_iter.idx + 1;
+
+      if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
+      {
+       /* Can't use the fast path if eg. the next char is a default-ignorable
+        * or other skippable. */
+        goto slow;
+      }
+    }
+    else
+      goto slow;
+
+    bool unsafe_to_concat = false;
+
+    for (unsigned int i = 0; i < num_ligs; i++)
+    {
+      const auto &lig = this+ligature.arrayZ[i];
+      if (unlikely (lig.component.lenP1 <= 1) ||
+         lig.component.arrayZ[0] == first)
+      {
+       if (lig.apply (c))
+       {
+         if (unsafe_to_concat)
+           c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
+         return_trace (true);
+       }
+      }
+      else if (likely (lig.component.lenP1 > 1))
+        unsafe_to_concat = true;
+    }
+    if (likely (unsafe_to_concat))
+      c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
+
+    return_trace (false);
+  }
+
+  bool serialize (hb_serialize_context_t *c,
+                  hb_array_t<const HBGlyphID16> ligatures,
+                  hb_array_t<const unsigned int> component_count_list,
+                  hb_array_t<const HBGlyphID16> &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, ligatures.length))) return_trace (false);
+    for (unsigned int i = 0; i < ligatures.length; i++)
+    {
+      unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
+      if (unlikely (!ligature[i].serialize_serialize (c,
+                                                      ligatures[i],
+                                                      component_list.sub_array (0, component_count))))
+        return_trace (false);
+      component_list += component_count;
+    }
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c, unsigned coverage_idx) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    + hb_iter (ligature)
+    | hb_filter (subset_offset_array (c, out->ligature, this, coverage_idx))
+    | hb_drain
+    ;
+
+    if (bool (out->ligature))
+      // Ensure Coverage table is always packed after this.
+      c->serializer->add_virtual_link (coverage_idx);
+
+    return_trace (bool (out->ligature));
+  }
+};
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_LIGATURESET_HH */
diff --git a/src/OT/Layout/GSUB/LigatureSubst.hh b/src/OT/Layout/GSUB/LigatureSubst.hh
new file mode 100644 (file)
index 0000000..18f6e35
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef OT_LAYOUT_GSUB_LIGATURESUBST_HH
+#define OT_LAYOUT_GSUB_LIGATURESUBST_HH
+
+#include "Common.hh"
+#include "LigatureSubstFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct LigatureSubst
+{
+  protected:
+  union {
+  HBUINT16                             format;         /* Format identifier */
+  LigatureSubstFormat1_2<SmallTypes>   format1;
+#ifndef HB_NO_BEYOND_64K
+  LigatureSubstFormat1_2<MediumTypes>  format2;
+#endif
+  } u;
+
+  public:
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format);
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+#ifndef HB_NO_BEYOND_64K
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  /* TODO This function is only used by small GIDs, and not updated to 24bit GIDs. Should
+   * be done by using iterators. While at it perhaps using iterator of arrays of hb_codepoint_t
+   * instead. */
+  bool serialize (hb_serialize_context_t *c,
+                  hb_sorted_array_t<const HBGlyphID16> first_glyphs,
+                  hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
+                  hb_array_t<const HBGlyphID16> ligatures_list,
+                  hb_array_t<const unsigned int> component_count_list,
+                  hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (u.format))) return_trace (false);
+    unsigned int format = 1;
+    u.format = format;
+    switch (u.format) {
+    case 1: return_trace (u.format1.serialize (c,
+                                               first_glyphs,
+                                               ligature_per_first_glyph_count_list,
+                                               ligatures_list,
+                                               component_count_list,
+                                               component_list));
+    default:return_trace (false);
+    }
+  }
+
+  /* TODO subset() should choose format. */
+
+};
+
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_LIGATURESUBST_HH */
diff --git a/src/OT/Layout/GSUB/LigatureSubstFormat1.hh b/src/OT/Layout/GSUB/LigatureSubstFormat1.hh
new file mode 100644 (file)
index 0000000..5c7df97
--- /dev/null
@@ -0,0 +1,166 @@
+#ifndef OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH
+#define OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH
+
+#include "Common.hh"
+#include "LigatureSet.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+template <typename Types>
+struct LigatureSubstFormat1_2
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  typename Types::template OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of Substitution table */
+  Array16Of<typename Types::template OffsetTo<LigatureSet<Types>>>
+                ligatureSet;            /* Array LigatureSet tables
+                                         * ordered by Coverage Index */
+  public:
+  DEFINE_SIZE_ARRAY (4 + Types::size, ligatureSet);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    return
+    + hb_zip (this+coverage, ligatureSet)
+    | hb_filter (*glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map ([this, glyphs] (const typename Types::template OffsetTo<LigatureSet<Types>> &_)
+              { return (this+_).intersects (glyphs); })
+    | hb_any
+    ;
+  }
+
+  bool may_have_non_1to1 () const
+  { return true; }
+
+  void closure (hb_closure_context_t *c) const
+  {
+    + hb_zip (this+coverage, ligatureSet)
+    | hb_filter (c->parent_active_glyphs (), hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const LigatureSet<Types> &_) { _.closure (c); })
+    ;
+
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+
+    + hb_zip (this+coverage, ligatureSet)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const LigatureSet<Types> &_) { _.collect_glyphs (c); })
+    ;
+  }
+
+  const Coverage &get_coverage () const { return this+coverage; }
+
+  bool would_apply (hb_would_apply_context_t *c) const
+  {
+    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
+    if (likely (index == NOT_COVERED)) return false;
+
+    const auto &lig_set = this+ligatureSet[index];
+    return lig_set.would_apply (c);
+  }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    const auto &lig_set = this+ligatureSet[index];
+    return_trace (lig_set.apply (c));
+  }
+
+  bool serialize (hb_serialize_context_t *c,
+                  hb_sorted_array_t<const HBGlyphID16> first_glyphs,
+                  hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
+                  hb_array_t<const HBGlyphID16> ligatures_list,
+                  hb_array_t<const unsigned int> component_count_list,
+                  hb_array_t<const HBGlyphID16> 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, 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_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_serialize (c, first_glyphs));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    // Due to a bug in some older versions of windows 7 the Coverage table must be
+    // packed after the LigatureSet and Ligature tables, so serialize Coverage first
+    // which places it last in the packed order.
+    hb_set_t new_coverage;
+    + hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this)))
+    | hb_filter (glyphset, hb_first)
+    | hb_filter ([&] (const LigatureSet<Types>& _) {
+      return _.intersects_lig_glyph (&glyphset);
+    }, hb_second)
+    | hb_map (hb_first)
+    | hb_sink (new_coverage);
+
+    if (!c->serializer->push<Coverage> ()
+        ->serialize (c->serializer,
+                     + new_coverage.iter () | hb_map_retains_sorting (glyph_map)))
+    {
+      c->serializer->pop_discard ();
+      return_trace (false);
+    }
+
+    unsigned coverage_idx = c->serializer->pop_pack ();
+     c->serializer->add_link (out->coverage, coverage_idx);
+
+    + hb_zip (this+coverage, ligatureSet)
+    | hb_filter (new_coverage, hb_first)
+    | hb_map (hb_second)
+    // to ensure that the repacker always orders the coverage table after the LigatureSet
+    // and LigatureSubtable's they will be linked to the Coverage table via a virtual link
+    // the coverage table object idx is passed down to facilitate this.
+    | hb_apply (subset_offset_array (c, out->ligatureSet, this, coverage_idx))
+    ;
+
+    return_trace (bool (new_coverage));
+  }
+};
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH */
diff --git a/src/OT/Layout/GSUB/MultipleSubst.hh b/src/OT/Layout/GSUB/MultipleSubst.hh
new file mode 100644 (file)
index 0000000..742c858
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef OT_LAYOUT_GSUB_MULTIPLESUBST_HH
+#define OT_LAYOUT_GSUB_MULTIPLESUBST_HH
+
+#include "Common.hh"
+#include "MultipleSubstFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct MultipleSubst
+{
+  protected:
+  union {
+  HBUINT16                             format;         /* Format identifier */
+  MultipleSubstFormat1_2<SmallTypes>   format1;
+#ifndef HB_NO_BEYOND_64K
+  MultipleSubstFormat1_2<MediumTypes>  format2;
+#endif
+  } u;
+
+  public:
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format);
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+#ifndef HB_NO_BEYOND_64K
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  template<typename Iterator,
+           hb_requires (hb_is_sorted_iterator (Iterator))>
+  bool serialize (hb_serialize_context_t *c,
+                 Iterator it)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (u.format))) return_trace (false);
+    unsigned int format = 1;
+    u.format = format;
+    switch (u.format) {
+    case 1: return_trace (u.format1.serialize (c, it));
+    default:return_trace (false);
+    }
+  }
+
+  /* TODO subset() should choose format. */
+
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_MULTIPLESUBST_HH */
diff --git a/src/OT/Layout/GSUB/MultipleSubstFormat1.hh b/src/OT/Layout/GSUB/MultipleSubstFormat1.hh
new file mode 100644 (file)
index 0000000..3b4bd11
--- /dev/null
@@ -0,0 +1,130 @@
+#ifndef OT_LAYOUT_GSUB_MULTIPLESUBSTFORMAT1_HH
+#define OT_LAYOUT_GSUB_MULTIPLESUBSTFORMAT1_HH
+
+#include "Common.hh"
+#include "Sequence.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+template <typename Types>
+struct MultipleSubstFormat1_2
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  typename Types::template OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of Substitution table */
+  Array16Of<typename Types::template OffsetTo<Sequence<Types>>>
+                sequence;               /* Array of Sequence tables
+                                         * ordered by Coverage Index */
+  public:
+  DEFINE_SIZE_ARRAY (4 + Types::size, sequence);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
+  bool may_have_non_1to1 () const
+  { return true; }
+
+  void closure (hb_closure_context_t *c) const
+  {
+    + hb_zip (this+coverage, sequence)
+    | hb_filter (c->parent_active_glyphs (), hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const Sequence<Types> &_) { _.closure (c); })
+    ;
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+    + hb_zip (this+coverage, sequence)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const Sequence<Types> &_) { _.collect_glyphs (c); })
+    ;
+  }
+
+  const Coverage &get_coverage () const { return this+coverage; }
+
+  bool would_apply (hb_would_apply_context_t *c) const
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    return_trace ((this+sequence[index]).apply (c));
+  }
+
+  template<typename Iterator,
+           hb_requires (hb_is_sorted_iterator (Iterator))>
+  bool serialize (hb_serialize_context_t *c,
+                 Iterator it)
+  {
+    TRACE_SERIALIZE (this);
+    auto sequences =
+      + it
+      | hb_map (hb_second)
+      ;
+    auto glyphs =
+      + it
+      | hb_map_retains_sorting (hb_first)
+      ;
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+
+    if (unlikely (!sequence.serialize (c, sequences.length))) return_trace (false);
+
+    for (auto& pair : hb_zip (sequences, sequence))
+    {
+      if (unlikely (!pair.second
+                   .serialize_serialize (c, pair.first)))
+        return_trace (false);
+    }
+
+    return_trace (coverage.serialize_serialize (c, glyphs));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, sequence)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (subset_offset_array (c, out->sequence, this), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
+    return_trace (bool (new_coverage));
+  }
+};
+
+}
+}
+}
+
+
+#endif /* OT_LAYOUT_GSUB_MULTIPLESUBSTFORMAT1_HH */
diff --git a/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh b/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh
new file mode 100644 (file)
index 0000000..5ad463f
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBST_HH
+#define OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBST_HH
+
+#include "Common.hh"
+#include "ReverseChainSingleSubstFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct ReverseChainSingleSubst
+{
+  protected:
+  union {
+  HBUINT16                              format;         /* Format identifier */
+  ReverseChainSingleSubstFormat1        format1;
+  } u;
+
+  public:
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format);
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+};
+
+}
+}
+}
+
+#endif  /* HB_OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBST_HH */
diff --git a/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh b/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
new file mode 100644 (file)
index 0000000..916fa28
--- /dev/null
@@ -0,0 +1,243 @@
+#ifndef OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBSTFORMAT1_HH
+#define OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBSTFORMAT1_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct ReverseChainSingleSubstFormat1
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  Offset16To<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of table */
+  Array16OfOffset16To<Coverage>
+                backtrack;              /* Array of coverage tables
+                                         * in backtracking sequence, in glyph
+                                         * sequence order */
+  Array16OfOffset16To<Coverage>
+                lookaheadX;             /* Array of coverage tables
+                                         * in lookahead sequence, in glyph
+                                         * sequence order */
+  Array16Of<HBGlyphID16>
+                substituteX;            /* Array of substitute
+                                         * GlyphIDs--ordered by Coverage Index */
+  public:
+  DEFINE_SIZE_MIN (10);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
+      return_trace (false);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
+    if (!lookahead.sanitize (c, this))
+      return_trace (false);
+    const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
+    return_trace (substitute.sanitize (c));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    if (!(this+coverage).intersects (glyphs))
+      return false;
+
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (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;
+  }
+
+  bool may_have_non_1to1 () const
+  { return false; }
+
+  void closure (hb_closure_context_t *c) const
+  {
+    if (!intersects (c->glyphs)) return;
+
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
+    const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
+
+    + hb_zip (this+coverage, substitute)
+    | hb_filter (c->parent_active_glyphs (), hb_first)
+    | hb_map (hb_second)
+    | hb_sink (c->output)
+    ;
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+
+    unsigned int count;
+
+    count = backtrack.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (unlikely (!(this+backtrack[i]).collect_coverage (c->before))) return;
+
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
+    count = lookahead.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (unlikely (!(this+lookahead[i]).collect_coverage (c->after))) return;
+
+    const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
+    count = substitute.len;
+    c->output->add_array (substitute.arrayZ, substitute.len);
+  }
+
+  const Coverage &get_coverage () const { return this+coverage; }
+
+  bool would_apply (hb_would_apply_context_t *c) const
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
+      return_trace (false); /* No chaining to this type */
+
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
+    const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
+
+    if (unlikely (index >= substitute.len)) return_trace (false);
+
+    unsigned int start_index = 0, end_index = 0;
+    if (match_backtrack (c,
+                         backtrack.len, (HBUINT16 *) backtrack.arrayZ,
+                         match_coverage, this,
+                         &start_index) &&
+        match_lookahead (c,
+                         lookahead.len, (HBUINT16 *) lookahead.arrayZ,
+                         match_coverage, this,
+                         c->buffer->idx + 1, &end_index))
+    {
+      c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
+
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+       c->buffer->message (c->font,
+                           "replacing glyph at %u (reverse chaining substitution)",
+                           c->buffer->idx);
+      }
+
+      c->replace_glyph_inplace (substitute[index]);
+
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+       c->buffer->message (c->font,
+                           "replaced glyph at %u (reverse chaining substitution)",
+                           c->buffer->idx);
+      }
+
+      /* Note: We DON'T decrease buffer->idx.  The main loop does it
+       * for us.  This is useful for preventing surprises if someone
+       * calls us through a Context lookup. */
+      return_trace (true);
+    }
+    else
+    {
+      c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index);
+      return_trace (false);
+    }
+  }
+
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  bool serialize_coverage_offset_array (hb_subset_context_t *c, Iterator it) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> ();
+
+    if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
+      return_trace (false);
+
+    for (auto& offset : it) {
+      auto *o = out->serialize_append (c->serializer);
+      if (unlikely (!o) || !o->serialize_subset (c, offset, this))
+        return_trace (false);
+    }
+
+    return_trace (true);
+  }
+
+  template<typename Iterator, typename BacktrackIterator, typename LookaheadIterator,
+           hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_pair_t)),
+           hb_requires (hb_is_iterator (BacktrackIterator)),
+           hb_requires (hb_is_iterator (LookaheadIterator))>
+  bool serialize (hb_subset_context_t *c,
+                  Iterator coverage_subst_iter,
+                  BacktrackIterator backtrack_iter,
+                  LookaheadIterator lookahead_iter) const
+  {
+    TRACE_SERIALIZE (this);
+
+    auto *out = c->serializer->start_embed (this);
+    if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
+    if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false);
+
+    if (!serialize_coverage_offset_array (c, backtrack_iter)) return_trace (false);
+    if (!serialize_coverage_offset_array (c, lookahead_iter)) return_trace (false);
+
+    auto *substitute_out = c->serializer->start_embed<Array16Of<HBGlyphID16>> ();
+    auto substitutes =
+    + coverage_subst_iter
+    | hb_map (hb_second)
+    ;
+
+    auto glyphs =
+    + coverage_subst_iter
+    | hb_map_retains_sorting (hb_first)
+    ;
+    if (unlikely (! c->serializer->check_success (substitute_out->serialize (c->serializer, substitutes))))
+        return_trace (false);
+
+    if (unlikely (!out->coverage.serialize_serialize (c->serializer, glyphs)))
+      return_trace (false);
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
+    const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
+
+    auto it =
+    + hb_zip (this+coverage, substitute)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (glyphset, hb_second)
+    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t
+                              { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
+    ;
+
+    return_trace (bool (it) && serialize (c, it, backtrack.iter (), lookahead.iter ()));
+  }
+};
+
+}
+}
+}
+
+#endif  /* HB_OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBSTFORMAT1_HH */
diff --git a/src/OT/Layout/GSUB/Sequence.hh b/src/OT/Layout/GSUB/Sequence.hh
new file mode 100644 (file)
index 0000000..a26cf8c
--- /dev/null
@@ -0,0 +1,165 @@
+#ifndef OT_LAYOUT_GSUB_SEQUENCE_HH
+#define OT_LAYOUT_GSUB_SEQUENCE_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+template <typename Types>
+struct Sequence
+{
+  protected:
+  Array16Of<typename Types::HBGlyphID>
+                substitute;             /* String of GlyphIDs to substitute */
+  public:
+  DEFINE_SIZE_ARRAY (2, substitute);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (substitute.sanitize (c));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return hb_all (substitute, glyphs); }
+
+  void closure (hb_closure_context_t *c) const
+  { 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); }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    unsigned int count = substitute.len;
+
+    /* Special-case to make it in-place and not consider this
+     * as a "multiplied" substitution. */
+    if (unlikely (count == 1))
+    {
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+       c->buffer->sync_so_far ();
+       c->buffer->message (c->font,
+                           "replacing glyph at %u (multiple substitution)",
+                           c->buffer->idx);
+      }
+
+      c->replace_glyph (substitute.arrayZ[0]);
+
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+       c->buffer->message (c->font,
+                           "replaced glyph at %u (multiple substitution)",
+                           c->buffer->idx - 1u);
+      }
+
+      return_trace (true);
+    }
+    /* Spec disallows this, but Uniscribe allows it.
+     * https://github.com/harfbuzz/harfbuzz/issues/253 */
+    else if (unlikely (count == 0))
+    {
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+       c->buffer->sync_so_far ();
+       c->buffer->message (c->font,
+                           "deleting glyph at %u (multiple substitution)",
+                           c->buffer->idx);
+      }
+
+      c->buffer->delete_glyph ();
+
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+       c->buffer->sync_so_far ();
+       c->buffer->message (c->font,
+                           "deleted glyph at %u (multiple substitution)",
+                           c->buffer->idx);
+      }
+
+      return_trace (true);
+    }
+
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->sync_so_far ();
+      c->buffer->message (c->font,
+                         "multiplying glyph at %u",
+                         c->buffer->idx);
+    }
+
+    unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
+                         HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
+    unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur());
+
+    for (unsigned int i = 0; i < count; i++)
+    {
+      /* If is attached to a ligature, don't disturb that.
+       * https://github.com/harfbuzz/harfbuzz/issues/3069 */
+      if (!lig_id)
+        _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
+      c->output_glyph_for_component (substitute.arrayZ[i], klass);
+    }
+    c->buffer->skip_glyph ();
+
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->sync_so_far ();
+
+      char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0};
+      char *p = buf;
+
+      for (unsigned i = c->buffer->idx - count; i < c->buffer->idx; i++)
+      {
+       if (buf < p)
+         *p++ = ',';
+       snprintf (p, sizeof(buf) - (p - buf), "%u", i);
+       p += strlen(p);
+      }
+
+      c->buffer->message (c->font,
+                         "multiplied glyphs at %s",
+                         buf);
+    }
+
+    return_trace (true);
+  }
+
+  template <typename Iterator,
+            hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c,
+                  Iterator subst)
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (substitute.serialize (c, subst));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    if (!intersects (&glyphset)) return_trace (false);
+
+    auto it =
+    + hb_iter (substitute)
+    | hb_map (glyph_map)
+    ;
+
+    auto *out = c->serializer->start_embed (*this);
+    return_trace (out->serialize (c->serializer, it));
+  }
+};
+
+
+}
+}
+}
+
+
+#endif /* OT_LAYOUT_GSUB_SEQUENCE_HH */
diff --git a/src/OT/Layout/GSUB/SingleSubst.hh b/src/OT/Layout/GSUB/SingleSubst.hh
new file mode 100644 (file)
index 0000000..181c9e5
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef OT_LAYOUT_GSUB_SINGLESUBST_HH
+#define OT_LAYOUT_GSUB_SINGLESUBST_HH
+
+#include "Common.hh"
+#include "SingleSubstFormat1.hh"
+#include "SingleSubstFormat2.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct SingleSubst
+{
+  protected:
+  union {
+  HBUINT16                             format;         /* Format identifier */
+  SingleSubstFormat1_3<SmallTypes>     format1;
+  SingleSubstFormat2_4<SmallTypes>     format2;
+#ifndef HB_NO_BEYOND_64K
+  SingleSubstFormat1_3<MediumTypes>    format3;
+  SingleSubstFormat2_4<MediumTypes>    format4;
+#endif
+  } u;
+
+  public:
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format);
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#ifndef HB_NO_BEYOND_64K
+    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+    case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+#endif
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  template<typename Iterator,
+           hb_requires (hb_is_sorted_source_of (Iterator,
+                                                const hb_codepoint_pair_t))>
+  bool serialize (hb_serialize_context_t *c,
+                  Iterator glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (u.format))) return_trace (false);
+    unsigned format = 2;
+    unsigned delta = 0;
+    if (glyphs)
+    {
+      format = 1;
+      hb_codepoint_t mask = 0xFFFFu;
+
+#ifndef HB_NO_BEYOND_64K
+       if (+ glyphs
+          | hb_map_retains_sorting (hb_second)
+          | hb_filter ([] (hb_codepoint_t gid) { return gid > 0xFFFFu; }))
+       {
+        format += 2;
+        mask = 0xFFFFFFu;
+       }
+#endif
+
+      auto get_delta = [=] (hb_codepoint_pair_t _)
+                       { return (unsigned) (_.second - _.first) & mask; };
+      delta = get_delta (*glyphs);
+      if (!hb_all (++(+glyphs), delta, get_delta)) format += 1;
+    }
+
+    u.format = format;
+    switch (u.format) {
+    case 1: return_trace (u.format1.serialize (c,
+                                               + glyphs
+                                               | hb_map_retains_sorting (hb_first),
+                                               delta));
+    case 2: return_trace (u.format2.serialize (c, glyphs));
+#ifndef HB_NO_BEYOND_64K
+    case 3: return_trace (u.format3.serialize (c,
+                                               + glyphs
+                                               | hb_map_retains_sorting (hb_first),
+                                               delta));
+    case 4: return_trace (u.format4.serialize (c, glyphs));
+#endif
+    default:return_trace (false);
+    }
+  }
+};
+
+template<typename Iterator>
+static void
+SingleSubst_serialize (hb_serialize_context_t *c,
+                       Iterator it)
+{ c->start_embed<SingleSubst> ()->serialize (c, it); }
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_SINGLESUBST_HH */
diff --git a/src/OT/Layout/GSUB/SingleSubstFormat1.hh b/src/OT/Layout/GSUB/SingleSubstFormat1.hh
new file mode 100644 (file)
index 0000000..850be86
--- /dev/null
@@ -0,0 +1,204 @@
+#ifndef OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH
+#define OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+template <typename Types>
+struct SingleSubstFormat1_3
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  typename Types::template OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of Substitution table */
+  typename Types::HBUINT
+                deltaGlyphID;           /* Add to original GlyphID to get
+                                         * substitute GlyphID, modulo 0x10000 */
+
+  public:
+  DEFINE_SIZE_STATIC (2 + 2 * Types::size);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  coverage.sanitize (c, this) &&
+                  /* The coverage  table may use a range to represent a set
+                   * of glyphs, which means a small number of bytes can
+                   * generate a large glyph set. Manually modify the
+                   * sanitizer max ops to take this into account.
+                   *
+                   * Note: This check *must* be right after coverage sanitize. */
+                  c->check_ops ((this + coverage).get_population () >> 1));
+  }
+
+  hb_codepoint_t get_mask () const
+  { return (1 << (8 * Types::size)) - 1; }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
+  bool may_have_non_1to1 () const
+  { return false; }
+
+  void closure (hb_closure_context_t *c) const
+  {
+    hb_codepoint_t d = deltaGlyphID;
+    hb_codepoint_t mask = get_mask ();
+
+    /* Help fuzzer avoid this function as much. */
+    unsigned pop = (this+coverage).get_population ();
+    if (pop >= mask)
+      return;
+
+    hb_set_t intersection;
+    (this+coverage).intersect_set (c->parent_active_glyphs (), intersection);
+
+    /* In degenerate fuzzer-found fonts, but not real fonts,
+     * this table can keep adding new glyphs in each round of closure.
+     * Refuse to close-over, if it maps glyph range to overlapping range. */
+    hb_codepoint_t min_before = intersection.get_min ();
+    hb_codepoint_t max_before = intersection.get_max ();
+    hb_codepoint_t min_after = (min_before + d) & mask;
+    hb_codepoint_t max_after = (max_before + d) & mask;
+    if (intersection.get_population () == max_before - min_before + 1 &&
+       ((min_before <= min_after && min_after <= max_before) ||
+        (min_before <= max_after && max_after <= max_before)))
+      return;
+
+    + hb_iter (intersection)
+    | hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; })
+    | hb_sink (c->output)
+    ;
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+    hb_codepoint_t d = deltaGlyphID;
+    hb_codepoint_t mask = get_mask ();
+
+    + hb_iter (this+coverage)
+    | hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; })
+    | hb_sink (c->output)
+    ;
+  }
+
+  const Coverage &get_coverage () const { return this+coverage; }
+
+  bool would_apply (hb_would_apply_context_t *c) const
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+
+  unsigned
+  get_glyph_alternates (hb_codepoint_t  glyph_id,
+                        unsigned        start_offset,
+                        unsigned       *alternate_count  /* IN/OUT.  May be NULL. */,
+                        hb_codepoint_t *alternate_glyphs /* OUT.     May be NULL. */) const
+  {
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
+    if (likely (index == NOT_COVERED))
+    {
+      if (alternate_count)
+        *alternate_count = 0;
+      return 0;
+    }
+
+    if (alternate_count && *alternate_count)
+    {
+      hb_codepoint_t d = deltaGlyphID;
+      hb_codepoint_t mask = get_mask ();
+
+      glyph_id = (glyph_id + d) & mask;
+
+      *alternate_glyphs = glyph_id;
+      *alternate_count = 1;
+    }
+
+    return 1;
+  }
+
+  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);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    hb_codepoint_t d = deltaGlyphID;
+    hb_codepoint_t mask = get_mask ();
+
+    glyph_id = (glyph_id + d) & mask;
+
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->sync_so_far ();
+      c->buffer->message (c->font,
+                         "replacing glyph at %u (single substitution)",
+                         c->buffer->idx);
+    }
+
+    c->replace_glyph (glyph_id);
+
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+                         "replaced glyph at %u (single substitution)",
+                         c->buffer->idx - 1u);
+    }
+
+    return_trace (true);
+  }
+
+  template<typename Iterator,
+           hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c,
+                  Iterator glyphs,
+                  unsigned delta)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
+    c->check_assign (deltaGlyphID, delta, HB_SERIALIZE_ERROR_INT_OVERFLOW);
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    hb_codepoint_t d = deltaGlyphID;
+    hb_codepoint_t mask = get_mask ();
+
+    hb_set_t intersection;
+    (this+coverage).intersect_set (glyphset, intersection);
+
+    auto it =
+    + hb_iter (intersection)
+    | hb_map_retains_sorting ([d, mask] (hb_codepoint_t g) {
+                                return hb_codepoint_pair_t (g,
+                                                            (g + d) & mask); })
+    | hb_filter (glyphset, hb_second)
+    | hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t
+                              { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
+    ;
+
+    bool ret = bool (it);
+    SingleSubst_serialize (c->serializer, it);
+    return_trace (ret);
+  }
+};
+
+}
+}
+}
+
+
+#endif /* OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH */
diff --git a/src/OT/Layout/GSUB/SingleSubstFormat2.hh b/src/OT/Layout/GSUB/SingleSubstFormat2.hh
new file mode 100644 (file)
index 0000000..9c651ab
--- /dev/null
@@ -0,0 +1,176 @@
+#ifndef OT_LAYOUT_GSUB_SINGLESUBSTFORMAT2_HH
+#define OT_LAYOUT_GSUB_SINGLESUBSTFORMAT2_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+template <typename Types>
+struct SingleSubstFormat2_4
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 2 */
+  typename Types::template OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of Substitution table */
+  Array16Of<typename Types::HBGlyphID>
+                substitute;             /* Array of substitute
+                                         * GlyphIDs--ordered by Coverage Index */
+
+  public:
+  DEFINE_SIZE_ARRAY (4 + Types::size, substitute);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
+  bool may_have_non_1to1 () const
+  { return false; }
+
+  void closure (hb_closure_context_t *c) const
+  {
+    auto &cov = this+coverage;
+    auto &glyph_set = c->parent_active_glyphs ();
+
+    if (substitute.len > glyph_set.get_population () * 4)
+    {
+      for (auto g : glyph_set)
+      {
+       unsigned i = cov.get_coverage (g);
+       if (i == NOT_COVERED || i >= substitute.len)
+         continue;
+       c->output->add (substitute.arrayZ[i]);
+      }
+
+      return;
+    }
+
+    + hb_zip (cov, substitute)
+    | hb_filter (glyph_set, hb_first)
+    | hb_map (hb_second)
+    | hb_sink (c->output)
+    ;
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+    + hb_zip (this+coverage, substitute)
+    | hb_map (hb_second)
+    | hb_sink (c->output)
+    ;
+  }
+
+  const Coverage &get_coverage () const { return this+coverage; }
+
+  bool would_apply (hb_would_apply_context_t *c) const
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+
+  unsigned
+  get_glyph_alternates (hb_codepoint_t  glyph_id,
+                        unsigned        start_offset,
+                        unsigned       *alternate_count  /* IN/OUT.  May be NULL. */,
+                        hb_codepoint_t *alternate_glyphs /* OUT.     May be NULL. */) const
+  {
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
+    if (likely (index == NOT_COVERED))
+    {
+      if (alternate_count)
+        *alternate_count = 0;
+      return 0;
+    }
+
+    if (alternate_count && *alternate_count)
+    {
+      glyph_id = substitute[index];
+
+      *alternate_glyphs = glyph_id;
+      *alternate_count = 1;
+    }
+
+    return 1;
+  }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    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);
+
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->sync_so_far ();
+      c->buffer->message (c->font,
+                         "replacing glyph at %u (single substitution)",
+                         c->buffer->idx);
+    }
+
+    c->replace_glyph (substitute[index]);
+
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+                         "replaced glyph at %u (single substitution)",
+                         c->buffer->idx - 1u);
+    }
+
+    return_trace (true);
+  }
+
+  template<typename Iterator,
+           hb_requires (hb_is_sorted_source_of (Iterator,
+                                                hb_codepoint_pair_t))>
+  bool serialize (hb_serialize_context_t *c,
+                  Iterator it)
+  {
+    TRACE_SERIALIZE (this);
+    auto substitutes =
+      + it
+      | hb_map (hb_second)
+      ;
+    auto glyphs =
+      + it
+      | hb_map_retains_sorting (hb_first)
+      ;
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
+    if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto it =
+    + hb_zip (this+coverage, substitute)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (glyphset, hb_second)
+    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const typename Types::HBGlyphID &> p) -> hb_codepoint_pair_t
+                              { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
+    ;
+
+    bool ret = bool (it);
+    SingleSubst_serialize (c->serializer, it);
+    return_trace (ret);
+  }
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_SINGLESUBSTFORMAT2_HH */
diff --git a/src/OT/Layout/GSUB/SubstLookup.hh b/src/OT/Layout/GSUB/SubstLookup.hh
new file mode 100644 (file)
index 0000000..d49dcc0
--- /dev/null
@@ -0,0 +1,220 @@
+#ifndef OT_LAYOUT_GSUB_SUBSTLOOKUP_HH
+#define OT_LAYOUT_GSUB_SUBSTLOOKUP_HH
+
+#include "Common.hh"
+#include "SubstLookupSubTable.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct SubstLookup : Lookup
+{
+  using SubTable = SubstLookupSubTable;
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  { return Lookup::sanitize<SubTable> (c); }
+
+  const SubTable& get_subtable (unsigned int i) const
+  { return Lookup::get_subtable<SubTable> (i); }
+
+  static inline bool lookup_type_is_reverse (unsigned int lookup_type)
+  { return lookup_type == SubTable::ReverseChainSingle; }
+
+  bool is_reverse () const
+  {
+    unsigned int type = get_type ();
+    if (unlikely (type == SubTable::Extension))
+      return get_subtable (0).u.extension.is_reverse ();
+    return lookup_type_is_reverse (type);
+  }
+
+  bool may_have_non_1to1 () const
+  {
+    hb_have_non_1to1_context_t c;
+    return dispatch (&c);
+  }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    return_trace (dispatch (c));
+  }
+
+  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
+  {
+    if (!c->should_visit_lookup (this_index))
+      return hb_closure_context_t::default_return_value ();
+
+    c->set_recurse_func (dispatch_closure_recurse_func);
+
+    hb_closure_context_t::return_t ret = dispatch (c);
+
+    c->flush ();
+
+    return ret;
+  }
+
+  hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
+  {
+    if (c->is_lookup_visited (this_index))
+      return hb_closure_lookups_context_t::default_return_value ();
+
+    c->set_lookup_visited (this_index);
+    if (!intersects (c->glyphs))
+    {
+      c->set_lookup_inactive (this_index);
+      return hb_closure_lookups_context_t::default_return_value ();
+    }
+
+    hb_closure_lookups_context_t::return_t ret = dispatch (c);
+    return ret;
+  }
+
+  hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
+    return dispatch (c);
+  }
+
+  template <typename set_t>
+  void collect_coverage (set_t *glyphs) const
+  {
+    hb_collect_coverage_context_t<set_t> c (glyphs);
+    dispatch (&c);
+  }
+
+  bool would_apply (hb_would_apply_context_t *c,
+                    const hb_ot_layout_lookup_accelerator_t *accel) const
+  {
+    if (unlikely (!c->len)) return false;
+    if (!accel->may_have (c->glyphs[0])) return false;
+      return dispatch (c);
+  }
+
+  template<typename Glyphs, typename Substitutes,
+          hb_requires (hb_is_sorted_source_of (Glyphs,
+                                               const hb_codepoint_t) &&
+                       hb_is_source_of (Substitutes,
+                                        const hb_codepoint_t))>
+  bool serialize_single (hb_serialize_context_t *c,
+                         uint32_t lookup_props,
+                         Glyphs glyphs,
+                         Substitutes substitutes)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
+    if (c->push<SubTable> ()->u.single.serialize (c, hb_zip (glyphs, substitutes)))
+    {
+      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
+      return_trace (true);
+    }
+    c->pop_discard ();
+    return_trace (false);
+  }
+
+  template<typename Iterator,
+           hb_requires (hb_is_sorted_iterator (Iterator))>
+  bool serialize (hb_serialize_context_t *c,
+                 uint32_t lookup_props,
+                 Iterator it)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
+    if (c->push<SubTable> ()->u.multiple.
+        serialize (c, it))
+    {
+      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
+      return_trace (true);
+    }
+    c->pop_discard ();
+    return_trace (false);
+  }
+
+  bool serialize_alternate (hb_serialize_context_t *c,
+                            uint32_t lookup_props,
+                            hb_sorted_array_t<const HBGlyphID16> glyphs,
+                            hb_array_t<const unsigned int> alternate_len_list,
+                            hb_array_t<const HBGlyphID16> alternate_glyphs_list)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
+
+    if (c->push<SubTable> ()->u.alternate.
+        serialize (c,
+                   glyphs,
+                   alternate_len_list,
+                   alternate_glyphs_list))
+    {
+      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
+      return_trace (true);
+    }
+    c->pop_discard ();
+    return_trace (false);
+  }
+
+  bool serialize_ligature (hb_serialize_context_t *c,
+                           uint32_t lookup_props,
+                           hb_sorted_array_t<const HBGlyphID16> first_glyphs,
+                           hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
+                           hb_array_t<const HBGlyphID16> ligatures_list,
+                           hb_array_t<const unsigned int> component_count_list,
+                           hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
+    if (c->push<SubTable> ()->u.ligature.
+        serialize (c,
+                   first_glyphs,
+                   ligature_per_first_glyph_count_list,
+                   ligatures_list,
+                   component_count_list,
+                   component_list))
+    {
+      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
+      return_trace (true);
+    }
+    c->pop_discard ();
+    return_trace (false);
+  }
+
+  template <typename context_t>
+  static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
+
+  static inline typename hb_closure_context_t::return_t closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index);
+
+  static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index)
+  {
+    if (!c->should_visit_lookup (lookup_index))
+      return hb_empty_t ();
+
+    hb_closure_context_t::return_t ret = closure_glyphs_recurse_func (c, lookup_index, covered_seq_indices, seq_index, end_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, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); }
+
+  bool subset (hb_subset_context_t *c) const
+  { return Lookup::subset<SubTable> (c); }
+};
+
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_SUBSTLOOKUP_HH */
diff --git a/src/OT/Layout/GSUB/SubstLookupSubTable.hh b/src/OT/Layout/GSUB/SubstLookupSubTable.hh
new file mode 100644 (file)
index 0000000..a525fba
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef OT_LAYOUT_GSUB_SUBSTLOOKUPSUBTABLE_HH
+#define OT_LAYOUT_GSUB_SUBSTLOOKUPSUBTABLE_HH
+
+#include "Common.hh"
+#include "SingleSubst.hh"
+#include "MultipleSubst.hh"
+#include "AlternateSubst.hh"
+#include "LigatureSubst.hh"
+#include "ContextSubst.hh"
+#include "ChainContextSubst.hh"
+#include "ExtensionSubst.hh"
+#include "ReverseChainSingleSubst.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB_impl {
+
+struct SubstLookupSubTable
+{
+  friend struct ::OT::Lookup;
+  friend struct SubstLookup;
+
+  protected:
+  union {
+  SingleSubst                   single;
+  MultipleSubst                 multiple;
+  AlternateSubst                alternate;
+  LigatureSubst                 ligature;
+  ContextSubst                  context;
+  ChainContextSubst             chainContext;
+  ExtensionSubst                extension;
+  ReverseChainSingleSubst       reverseChainContextSingle;
+  } u;
+  public:
+  DEFINE_SIZE_MIN (0);
+
+  enum Type {
+    Single              = 1,
+    Multiple            = 2,
+    Alternate           = 3,
+    Ligature            = 4,
+    Context             = 5,
+    ChainContext        = 6,
+    Extension           = 7,
+    ReverseChainSingle  = 8
+  };
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
+  {
+    TRACE_DISPATCH (this, lookup_type);
+    switch (lookup_type) {
+    case Single:                return_trace (u.single.dispatch (c, std::forward<Ts> (ds)...));
+    case Multiple:              return_trace (u.multiple.dispatch (c, std::forward<Ts> (ds)...));
+    case Alternate:             return_trace (u.alternate.dispatch (c, std::forward<Ts> (ds)...));
+    case Ligature:              return_trace (u.ligature.dispatch (c, std::forward<Ts> (ds)...));
+    case Context:               return_trace (u.context.dispatch (c, std::forward<Ts> (ds)...));
+    case ChainContext:          return_trace (u.chainContext.dispatch (c, std::forward<Ts> (ds)...));
+    case Extension:             return_trace (u.extension.dispatch (c, std::forward<Ts> (ds)...));
+    case ReverseChainSingle:    return_trace (u.reverseChainContextSingle.dispatch (c, std::forward<Ts> (ds)...));
+    default:                    return_trace (c->default_return_value ());
+    }
+  }
+
+  bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const
+  {
+    hb_intersects_context_t c (glyphs);
+    return dispatch (&c, lookup_type);
+  }
+};
+
+
+}
+}
+}
+
+#endif  /* HB_OT_LAYOUT_GSUB_SUBSTLOOKUPSUBTABLE_HH */
diff --git a/src/OT/Layout/types.hh b/src/OT/Layout/types.hh
new file mode 100644 (file)
index 0000000..6a43403
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * 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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Garret Rieger
+ */
+
+#ifndef OT_LAYOUT_TYPES_HH
+#define OT_LAYOUT_TYPES_HH
+
+namespace OT {
+namespace Layout {
+
+struct SmallTypes {
+  static constexpr unsigned size = 2;
+  using large_int = uint32_t;
+  using HBUINT = HBUINT16;
+  using HBGlyphID = HBGlyphID16;
+  using Offset = Offset16;
+  template <typename Type, bool has_null=true>
+  using OffsetTo = OT::Offset16To<Type, has_null>;
+  template <typename Type>
+  using ArrayOf = OT::Array16Of<Type>;
+  template <typename Type>
+  using SortedArrayOf = OT::SortedArray16Of<Type>;
+};
+
+struct MediumTypes {
+  static constexpr unsigned size = 3;
+  using large_int = uint64_t;
+  using HBUINT = HBUINT24;
+  using HBGlyphID = HBGlyphID24;
+  using Offset = Offset24;
+  template <typename Type, bool has_null=true>
+  using OffsetTo = OT::Offset24To<Type, has_null>;
+  template <typename Type>
+  using ArrayOf = OT::Array24Of<Type>;
+  template <typename Type>
+  using SortedArrayOf = OT::SortedArray24Of<Type>;
+};
+
+}
+}
+
+#endif  /* OT_LAYOUT_TYPES_HH */
diff --git a/src/OT/glyf/CompositeGlyph.hh b/src/OT/glyf/CompositeGlyph.hh
new file mode 100644 (file)
index 0000000..60858a5
--- /dev/null
@@ -0,0 +1,434 @@
+#ifndef OT_GLYF_COMPOSITEGLYPH_HH
+#define OT_GLYF_COMPOSITEGLYPH_HH
+
+
+#include "../../hb-open-type.hh"
+#include "composite-iter.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+struct CompositeGlyphRecord
+{
+  protected:
+  enum composite_glyph_flag_t
+  {
+    ARG_1_AND_2_ARE_WORDS      = 0x0001,
+    ARGS_ARE_XY_VALUES         = 0x0002,
+    ROUND_XY_TO_GRID           = 0x0004,
+    WE_HAVE_A_SCALE            = 0x0008,
+    MORE_COMPONENTS            = 0x0020,
+    WE_HAVE_AN_X_AND_Y_SCALE   = 0x0040,
+    WE_HAVE_A_TWO_BY_TWO       = 0x0080,
+    WE_HAVE_INSTRUCTIONS       = 0x0100,
+    USE_MY_METRICS             = 0x0200,
+    OVERLAP_COMPOUND           = 0x0400,
+    SCALED_COMPONENT_OFFSET    = 0x0800,
+    UNSCALED_COMPONENT_OFFSET  = 0x1000,
+#ifndef HB_NO_BEYOND_64K
+    GID_IS_24BIT               = 0x2000
+#endif
+  };
+
+  public:
+  unsigned int get_size () const
+  {
+    unsigned int size = min_size;
+    /* glyphIndex is 24bit instead of 16bit */
+#ifndef HB_NO_BEYOND_64K
+    if (flags & GID_IS_24BIT) size += HBGlyphID24::static_size - HBGlyphID16::static_size;
+#endif
+    /* 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;
+  }
+
+  void drop_instructions_flag ()  { flags = (uint16_t) flags & ~WE_HAVE_INSTRUCTIONS; }
+  void set_overlaps_flag ()
+  {
+    flags = (uint16_t) flags | OVERLAP_COMPOUND;
+  }
+
+  bool has_instructions ()  const { return   flags & WE_HAVE_INSTRUCTIONS; }
+
+  bool has_more ()          const { return   flags & MORE_COMPONENTS; }
+  bool is_use_my_metrics () const { return   flags & USE_MY_METRICS; }
+  bool is_anchored ()       const { return !(flags & ARGS_ARE_XY_VALUES); }
+  void get_anchor_points (unsigned int &point1, unsigned int &point2) const
+  {
+    const auto *p = &StructAfter<const HBUINT8> (flags);
+#ifndef HB_NO_BEYOND_64K
+    if (flags & GID_IS_24BIT)
+      p += HBGlyphID24::static_size;
+    else
+#endif
+      p += HBGlyphID16::static_size;
+    if (flags & ARG_1_AND_2_ARE_WORDS)
+    {
+      point1 = ((const HBUINT16 *) p)[0];
+      point2 = ((const HBUINT16 *) p)[1];
+    }
+    else
+    {
+      point1 = p[0];
+      point2 = p[1];
+    }
+  }
+
+  static void transform (const float (&matrix)[4],
+                        hb_array_t<contour_point_t> points)
+  {
+    if (matrix[0] != 1.f || matrix[1] != 0.f ||
+       matrix[2] != 0.f || matrix[3] != 1.f)
+      for (auto &point : points)
+        point.transform (matrix);
+  }
+
+  static void translate (const contour_point_t &trans,
+                        hb_array_t<contour_point_t> points)
+  {
+    if (HB_OPTIMIZE_SIZE_VAL)
+    {
+      if (trans.x != 0.f || trans.y != 0.f)
+        for (auto &point : points)
+         point.translate (trans);
+    }
+    else
+    {
+      if (trans.x != 0.f && trans.y != 0.f)
+        for (auto &point : points)
+         point.translate (trans);
+      else
+      {
+       if (trans.x != 0.f)
+         for (auto &point : points)
+           point.x += trans.x;
+       else if (trans.y != 0.f)
+         for (auto &point : points)
+           point.y += trans.y;
+      }
+    }
+  }
+
+  void transform_points (hb_array_t<contour_point_t> points,
+                        const float (&matrix)[4],
+                        const contour_point_t &trans) const
+  {
+    if (scaled_offsets ())
+    {
+      translate (trans, points);
+      transform (matrix, points);
+    }
+    else
+    {
+      transform (matrix, points);
+      translate (trans, points);
+    }
+  }
+
+  bool get_points (contour_point_vector_t &points) const
+  {
+    float matrix[4];
+    contour_point_t trans;
+    get_transformation (matrix, trans);
+    if (unlikely (!points.alloc (points.length + 4))) return false; // For phantom points
+    points.push (trans);
+    return true;
+  }
+
+  unsigned compile_with_point (const contour_point_t &point,
+                               char *out) const
+  {
+    const HBINT8 *p = &StructAfter<const HBINT8> (flags);
+#ifndef HB_NO_BEYOND_64K
+    if (flags & GID_IS_24BIT)
+      p += HBGlyphID24::static_size;
+    else
+#endif
+      p += HBGlyphID16::static_size;
+
+    unsigned len = get_size ();
+    unsigned len_before_val = (const char *)p - (const char *)this;
+    if (flags & ARG_1_AND_2_ARE_WORDS)
+    {
+      // no overflow, copy value
+      hb_memcpy (out, this, len);
+
+      HBINT16 *o = reinterpret_cast<HBINT16 *> (out + len_before_val);
+      o[0] = roundf (point.x);
+      o[1] = roundf (point.y);
+    }
+    else
+    {
+      int new_x = roundf (point.x);
+      int new_y = roundf (point.y);
+      if (new_x <= 127 && new_x >= -128 &&
+          new_y <= 127 && new_y >= -128)
+      {
+        hb_memcpy (out, this, len);
+        HBINT8 *o = reinterpret_cast<HBINT8 *> (out + len_before_val);
+        o[0] = new_x;
+        o[1] = new_y;
+      }
+      else
+      {
+        // new point value has an int8 overflow
+        hb_memcpy (out, this, len_before_val);
+        
+        //update flags
+        CompositeGlyphRecord *o = reinterpret_cast<CompositeGlyphRecord *> (out);
+        o->flags = flags | ARG_1_AND_2_ARE_WORDS;
+        out += len_before_val;
+
+        HBINT16 new_value;
+        new_value = new_x;
+        hb_memcpy (out, &new_value, HBINT16::static_size);
+        out += HBINT16::static_size;
+
+        new_value = new_y;
+        hb_memcpy (out, &new_value, HBINT16::static_size);
+        out += HBINT16::static_size;
+
+        hb_memcpy (out, p+2, len - len_before_val - 2);
+        len += 2;
+      }
+    }
+    return len;
+  }
+
+  protected:
+  bool scaled_offsets () const
+  { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
+
+  public:
+  bool get_transformation (float (&matrix)[4], contour_point_t &trans) const
+  {
+    matrix[0] = matrix[3] = 1.f;
+    matrix[1] = matrix[2] = 0.f;
+
+    const auto *p = &StructAfter<const HBINT8> (flags);
+#ifndef HB_NO_BEYOND_64K
+    if (flags & GID_IS_24BIT)
+      p += HBGlyphID24::static_size;
+    else
+#endif
+      p += HBGlyphID16::static_size;
+    int tx, ty;
+    if (flags & ARG_1_AND_2_ARE_WORDS)
+    {
+      tx = *(const HBINT16 *) p;
+      p += HBINT16::static_size;
+      ty = *(const HBINT16 *) p;
+      p += HBINT16::static_size;
+    }
+    else
+    {
+      tx = *p++;
+      ty = *p++;
+    }
+    if (is_anchored ()) tx = ty = 0;
+
+    trans.init ((float) tx, (float) ty);
+
+    {
+      const F2DOT14 *points = (const F2DOT14 *) p;
+      if (flags & WE_HAVE_A_SCALE)
+      {
+       matrix[0] = matrix[3] = points[0].to_float ();
+       return true;
+      }
+      else if (flags & WE_HAVE_AN_X_AND_Y_SCALE)
+      {
+       matrix[0] = points[0].to_float ();
+       matrix[3] = points[1].to_float ();
+       return true;
+      }
+      else if (flags & WE_HAVE_A_TWO_BY_TWO)
+      {
+       matrix[0] = points[0].to_float ();
+       matrix[1] = points[1].to_float ();
+       matrix[2] = points[2].to_float ();
+       matrix[3] = points[3].to_float ();
+       return true;
+      }
+    }
+    return tx || ty;
+  }
+
+  hb_codepoint_t get_gid () const
+  {
+#ifndef HB_NO_BEYOND_64K
+    if (flags & GID_IS_24BIT)
+      return StructAfter<const HBGlyphID24> (flags);
+    else
+#endif
+      return StructAfter<const HBGlyphID16> (flags);
+  }
+  void set_gid (hb_codepoint_t gid)
+  {
+#ifndef HB_NO_BEYOND_64K
+    if (flags & GID_IS_24BIT)
+      StructAfter<HBGlyphID24> (flags) = gid;
+    else
+#endif
+      /* TODO assert? */
+      StructAfter<HBGlyphID16> (flags) = gid;
+  }
+
+#ifndef HB_NO_BEYOND_64K
+  void lower_gid_24_to_16 ()
+  {
+    hb_codepoint_t gid = get_gid ();
+    if (!(flags & GID_IS_24BIT) || gid > 0xFFFFu)
+      return;
+
+    /* Lower the flag and move the rest of the struct down. */
+
+    unsigned size = get_size ();
+    char *end = (char *) this + size;
+    char *p = &StructAfter<char> (flags);
+    p += HBGlyphID24::static_size;
+
+    flags = flags & ~GID_IS_24BIT;
+    set_gid (gid);
+
+    memmove (p - HBGlyphID24::static_size + HBGlyphID16::static_size, p, end - p);
+  }
+#endif
+
+  protected:
+  HBUINT16     flags;
+  HBUINT24     pad;
+  public:
+  DEFINE_SIZE_MIN (4);
+};
+
+using composite_iter_t = composite_iter_tmpl<CompositeGlyphRecord>;
+
+struct CompositeGlyph
+{
+  const GlyphHeader &header;
+  hb_bytes_t bytes;
+  CompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
+    header (header_), bytes (bytes_) {}
+
+  composite_iter_t iter () const
+  { return composite_iter_t (bytes, &StructAfter<CompositeGlyphRecord, GlyphHeader> (header)); }
+
+  unsigned int instructions_length (hb_bytes_t bytes) const
+  {
+    unsigned int start = bytes.length;
+    unsigned int end = bytes.length;
+    const CompositeGlyphRecord *last = nullptr;
+    for (auto &item : iter ())
+      last = &item;
+    if (unlikely (!last)) return 0;
+
+    if (last->has_instructions ())
+      start = (char *) last - &bytes + last->get_size ();
+    if (unlikely (start > end)) return 0;
+    return end - start;
+  }
+
+  /* Trimming for composites not implemented.
+   * If removing hints it falls out of that. */
+  const hb_bytes_t trim_padding () const { return bytes; }
+
+  void drop_hints ()
+  {
+    for (const auto &_ : iter ())
+      const_cast<CompositeGlyphRecord &> (_).drop_instructions_flag ();
+  }
+
+  /* Chop instructions off the end */
+  void drop_hints_bytes (hb_bytes_t &dest_start) const
+  { dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); }
+
+  void set_overlaps_flag ()
+  {
+    CompositeGlyphRecord& glyph_chain = const_cast<CompositeGlyphRecord &> (
+       StructAfter<CompositeGlyphRecord, GlyphHeader> (header));
+    if (!bytes.check_range(&glyph_chain, CompositeGlyphRecord::min_size))
+      return;
+    glyph_chain.set_overlaps_flag ();
+  }
+
+  bool compile_bytes_with_deltas (const hb_bytes_t &source_bytes,
+                                  const contour_point_vector_t &points_with_deltas,
+                                  hb_bytes_t &dest_bytes /* OUT */)
+  {
+    if (source_bytes.length <= GlyphHeader::static_size ||
+        header.numberOfContours != -1)
+    {
+      dest_bytes = hb_bytes_t ();
+      return true;
+    }
+
+    unsigned source_len = source_bytes.length - GlyphHeader::static_size;
+
+    /* try to allocate more memories than source glyph bytes
+     * in case that there might be an overflow for int8 value
+     * and we would need to use int16 instead */
+    char *o = (char *) hb_calloc (source_len * 2, sizeof (char));
+    if (unlikely (!o)) return false;
+
+    const CompositeGlyphRecord *c = reinterpret_cast<const CompositeGlyphRecord *> (source_bytes.arrayZ + GlyphHeader::static_size);
+    auto it = composite_iter_t (hb_bytes_t ((const char *)c, source_len), c);
+
+    char *p = o;
+    unsigned i = 0, source_comp_len = 0;
+    for (const auto &component : it)
+    {
+      /* last 4 points in points_with_deltas are phantom points and should not be included */
+      if (i >= points_with_deltas.length - 4) {
+        hb_free (o);
+        return false;
+      }
+
+      unsigned comp_len = component.get_size ();
+      if (component.is_anchored ())
+      {
+        hb_memcpy (p, &component, comp_len);
+        p += comp_len;
+      }
+      else
+      {
+        unsigned new_len = component.compile_with_point (points_with_deltas[i], p);
+        p += new_len;
+      }
+      i++;
+      source_comp_len += comp_len;
+    }
+
+    //copy instructions if any
+    if (source_len > source_comp_len)
+    {
+      unsigned instr_len = source_len - source_comp_len;
+      hb_memcpy (p, (const char *)c + source_comp_len, instr_len);
+      p += instr_len;
+    }
+
+    unsigned len = p - o;
+    dest_bytes = hb_bytes_t (o, len);
+    return true;
+  }
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_COMPOSITEGLYPH_HH */
diff --git a/src/OT/glyf/Glyph.hh b/src/OT/glyf/Glyph.hh
new file mode 100644 (file)
index 0000000..5ea6119
--- /dev/null
@@ -0,0 +1,680 @@
+#ifndef OT_GLYF_GLYPH_HH
+#define OT_GLYF_GLYPH_HH
+
+
+#include "../../hb-open-type.hh"
+
+#include "GlyphHeader.hh"
+#include "SimpleGlyph.hh"
+#include "CompositeGlyph.hh"
+#include "VarCompositeGlyph.hh"
+#include "coord-setter.hh"
+
+
+namespace OT {
+
+struct glyf_accelerator_t;
+
+namespace glyf_impl {
+
+
+enum phantom_point_index_t
+{
+  PHANTOM_LEFT   = 0,
+  PHANTOM_RIGHT  = 1,
+  PHANTOM_TOP    = 2,
+  PHANTOM_BOTTOM = 3,
+  PHANTOM_COUNT  = 4
+};
+
+struct Glyph
+{
+  enum glyph_type_t {
+    EMPTY,
+    SIMPLE,
+    COMPOSITE,
+#ifndef HB_NO_VAR_COMPOSITES
+    VAR_COMPOSITE,
+#endif
+  };
+
+  public:
+  composite_iter_t get_composite_iterator () const
+  {
+    if (type != COMPOSITE) return composite_iter_t ();
+    return CompositeGlyph (*header, bytes).iter ();
+  }
+  var_composite_iter_t get_var_composite_iterator () const
+  {
+#ifndef HB_NO_VAR_COMPOSITES
+    if (type != VAR_COMPOSITE) return var_composite_iter_t ();
+    return VarCompositeGlyph (*header, bytes).iter ();
+#else
+    return var_composite_iter_t ();
+#endif
+  }
+
+  const hb_bytes_t trim_padding () const
+  {
+    switch (type) {
+#ifndef HB_NO_VAR_COMPOSITES
+    case VAR_COMPOSITE: return VarCompositeGlyph (*header, bytes).trim_padding ();
+#endif
+    case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
+    case SIMPLE:    return SimpleGlyph (*header, bytes).trim_padding ();
+    case EMPTY:     return bytes;
+    default:        return bytes;
+    }
+  }
+
+  void drop_hints ()
+  {
+    switch (type) {
+#ifndef HB_NO_VAR_COMPOSITES
+    case VAR_COMPOSITE: return; // No hinting
+#endif
+    case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
+    case SIMPLE:    SimpleGlyph (*header, bytes).drop_hints (); return;
+    case EMPTY:     return;
+    }
+  }
+
+  void set_overlaps_flag ()
+  {
+    switch (type) {
+#ifndef HB_NO_VAR_COMPOSITES
+    case VAR_COMPOSITE: return; // No overlaps flag
+#endif
+    case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
+    case SIMPLE:    SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
+    case EMPTY:     return;
+    }
+  }
+
+  void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
+  {
+    switch (type) {
+#ifndef HB_NO_VAR_COMPOSITES
+    case VAR_COMPOSITE: return; // No hinting
+#endif
+    case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
+    case SIMPLE:    SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
+    case EMPTY:     return;
+    }
+  }
+
+  bool get_all_points_without_var (const hb_face_t *face,
+                                   contour_point_vector_t &points /* OUT */) const
+  {
+    switch (type) {
+    case SIMPLE:
+      if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points)))
+        return false;
+      break;
+    case COMPOSITE:
+    {
+      for (auto &item : get_composite_iterator ())
+        if (unlikely (!item.get_points (points))) return false;
+      break;
+    }
+#ifndef HB_NO_VAR_COMPOSITES
+    case VAR_COMPOSITE:
+    {
+      for (auto &item : get_var_composite_iterator ())
+        if (unlikely (!item.get_points (points))) return false;
+      break;
+    }
+#endif
+    case EMPTY:
+      break;
+    }
+
+    /* Init phantom points */
+    if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
+    hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
+    {
+      int lsb = 0;
+      int h_delta = face->table.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ?
+                    (int) header->xMin - lsb : 0;
+      HB_UNUSED int tsb = 0;
+      int v_orig  = (int) header->yMax +
+#ifndef HB_NO_VERTICAL
+                    ((void) face->table.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb)
+#else
+                    0
+#endif
+                    ;
+      unsigned h_adv = face->table.hmtx->get_advance_without_var_unscaled (gid);
+      unsigned v_adv =
+#ifndef HB_NO_VERTICAL
+                       face->table.vmtx->get_advance_without_var_unscaled (gid)
+#else
+                       - face->get_upem ()
+#endif
+                       ;
+      phantoms[PHANTOM_LEFT].x = h_delta;
+      phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta;
+      phantoms[PHANTOM_TOP].y = v_orig;
+      phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
+    }
+    return true;
+  }
+
+  void update_mtx (const hb_subset_plan_t *plan,
+                   int xMin, int xMax,
+                   int yMin, int yMax,
+                   const contour_point_vector_t &all_points) const
+  {
+    hb_codepoint_t new_gid = 0;
+    if (!plan->new_gid_for_old_gid (gid, &new_gid))
+      return;
+
+    if (type != EMPTY)
+    {
+      plan->bounds_width_vec[new_gid] = xMax - xMin;
+      plan->bounds_height_vec[new_gid] = yMax - yMin;
+    }
+
+    unsigned len = all_points.length;
+    float leftSideX = all_points[len - 4].x;
+    float rightSideX = all_points[len - 3].x;
+    float topSideY = all_points[len - 2].y;
+    float bottomSideY = all_points[len - 1].y;
+
+    uint32_t hash = hb_hash (new_gid);
+
+    signed hori_aw = roundf (rightSideX - leftSideX);
+    if (hori_aw < 0) hori_aw = 0;
+    int lsb = roundf (xMin - leftSideX);
+    plan->hmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) hori_aw, lsb));
+    //flag value should be computed using non-empty glyphs
+    if (type != EMPTY && lsb != xMin)
+      plan->head_maxp_info.allXMinIsLsb = false;
+
+    signed vert_aw = roundf (topSideY - bottomSideY);
+    if (vert_aw < 0) vert_aw = 0;
+    int tsb = roundf (topSideY - yMax);
+    plan->vmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) vert_aw, tsb));
+  }
+
+  bool compile_header_bytes (const hb_subset_plan_t *plan,
+                             const contour_point_vector_t &all_points,
+                             hb_bytes_t &dest_bytes /* OUT */) const
+  {
+    GlyphHeader *glyph_header = nullptr;
+    if (!plan->pinned_at_default && type != EMPTY && all_points.length >= 4)
+    {
+      glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size);
+      if (unlikely (!glyph_header)) return false;
+    }
+
+    float xMin = 0, xMax = 0;
+    float yMin = 0, yMax = 0;
+    if (all_points.length > 4)
+    {
+      xMin = xMax = all_points[0].x;
+      yMin = yMax = all_points[0].y;
+
+      unsigned count = all_points.length - 4;
+      for (unsigned i = 1; i < count; i++)
+      {
+       float x = all_points[i].x;
+       float y = all_points[i].y;
+       xMin = hb_min (xMin, x);
+       xMax = hb_max (xMax, x);
+       yMin = hb_min (yMin, y);
+       yMax = hb_max (yMax, y);
+      }
+    }
+
+
+    // These are destined for storage in a 16 bit field to clamp the values to
+    // fit into a 16 bit signed integer.
+    int rounded_xMin = hb_clamp (roundf (xMin), -32768.0f, 32767.0f);
+    int rounded_xMax = hb_clamp (roundf (xMax), -32768.0f, 32767.0f);
+    int rounded_yMin = hb_clamp (roundf (yMin), -32768.0f, 32767.0f);
+    int rounded_yMax = hb_clamp (roundf (yMax), -32768.0f, 32767.0f);
+
+    update_mtx (plan, rounded_xMin, rounded_xMax, rounded_yMin, rounded_yMax, all_points);
+
+    if (type != EMPTY)
+    {
+      plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, rounded_xMin);
+      plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, rounded_yMin);
+      plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, rounded_xMax);
+      plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, rounded_yMax);
+    }
+
+    /* when pinned at default, no need to compile glyph header
+     * and for empty glyphs: all_points only include phantom points.
+     * just update metrics and then return */
+    if (!glyph_header)
+      return true;
+
+    glyph_header->numberOfContours = header->numberOfContours;
+
+    glyph_header->xMin = rounded_xMin;
+    glyph_header->yMin = rounded_yMin;
+    glyph_header->xMax = rounded_xMax;
+    glyph_header->yMax = rounded_yMax;
+
+    dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size);
+    return true;
+  }
+
+  bool compile_bytes_with_deltas (const hb_subset_plan_t *plan,
+                                  hb_font_t *font,
+                                  const glyf_accelerator_t &glyf,
+                                  hb_bytes_t &dest_start,  /* IN/OUT */
+                                  hb_bytes_t &dest_end /* OUT */)
+  {
+    contour_point_vector_t all_points, points_with_deltas;
+    unsigned composite_contours = 0;
+    head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info;
+    unsigned *composite_contours_p = &composite_contours;
+
+    // don't compute head/maxp values when glyph has no contours(type is EMPTY)
+    // also ignore .notdef glyph when --notdef-outline is not enabled
+    if (type == EMPTY ||
+        (gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)))
+    {
+      head_maxp_info_p = nullptr;
+      composite_contours_p = nullptr;
+    }
+
+    if (!get_points (font, glyf, all_points, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false))
+      return false;
+
+    // .notdef, set type to empty so we only update metrics and don't compile bytes for
+    // it
+    if (gid == 0 &&
+        !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
+    {
+      type = EMPTY;
+      dest_start = hb_bytes_t ();
+      dest_end = hb_bytes_t ();
+    }
+
+    //dont compile bytes when pinned at default, just recalculate bounds
+    if (!plan->pinned_at_default)
+    {
+      switch (type)
+      {
+#ifndef HB_NO_VAR_COMPOSITES
+      case VAR_COMPOSITE:
+       // TODO
+       dest_end = hb_bytes_t ();
+       break;
+#endif
+
+      case COMPOSITE:
+        if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
+                                                                        points_with_deltas,
+                                                                        dest_end))
+          return false;
+        break;
+      case SIMPLE:
+        if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points,
+                                                                     plan->flags & HB_SUBSET_FLAGS_NO_HINTING,
+                                                                     dest_end))
+          return false;
+        break;
+      case EMPTY:
+        /* set empty bytes for empty glyph
+         * do not use source glyph's pointers */
+        dest_start = hb_bytes_t ();
+        dest_end = hb_bytes_t ();
+        break;
+      }
+    }
+
+    if (!compile_header_bytes (plan, all_points, dest_start))
+    {
+      dest_end.fini ();
+      return false;
+    }
+    return true;
+  }
+
+
+  /* Note: Recursively calls itself.
+   * all_points includes phantom points
+   */
+  template <typename accelerator_t>
+  bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
+                  contour_point_vector_t &all_points /* OUT */,
+                  contour_point_vector_t *points_with_deltas = nullptr, /* OUT */
+                  head_maxp_info_t * head_maxp_info = nullptr, /* OUT */
+                  unsigned *composite_contours = nullptr, /* OUT */
+                  bool shift_points_hori = true,
+                  bool use_my_metrics = true,
+                  bool phantom_only = false,
+                  hb_array_t<int> coords = hb_array_t<int> (),
+                  hb_map_t *current_glyphs = nullptr,
+                  unsigned int depth = 0,
+                  unsigned *edge_count = nullptr) const
+  {
+    if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
+    unsigned stack_edge_count = 0;
+    if (!edge_count) edge_count = &stack_edge_count;
+    if (unlikely (*edge_count > HB_GLYF_MAX_EDGE_COUNT)) return false;
+    (*edge_count)++;
+
+    hb_map_t current_glyphs_stack;
+    if (current_glyphs == nullptr)
+      current_glyphs = &current_glyphs_stack;
+
+    if (head_maxp_info)
+    {
+      head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth);
+    }
+
+    if (!coords)
+      coords = hb_array (font->coords, font->num_coords);
+
+    contour_point_vector_t stack_points;
+    contour_point_vector_t &points = type == SIMPLE ? all_points : stack_points;
+    unsigned old_length = points.length;
+
+    switch (type) {
+    case SIMPLE:
+      if (depth == 0 && head_maxp_info)
+        head_maxp_info->maxContours = hb_max (head_maxp_info->maxContours, (unsigned) header->numberOfContours);
+      if (depth > 0 && composite_contours)
+        *composite_contours += (unsigned) header->numberOfContours;
+      if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (all_points, phantom_only)))
+       return false;
+      break;
+    case COMPOSITE:
+    {
+      for (auto &item : get_composite_iterator ())
+        if (unlikely (!item.get_points (points))) return false;
+      break;
+    }
+#ifndef HB_NO_VAR_COMPOSITES
+    case VAR_COMPOSITE:
+    {
+      for (auto &item : get_var_composite_iterator ())
+        if (unlikely (!item.get_points (points))) return false;
+      break;
+    }
+#endif
+    case EMPTY:
+      break;
+    }
+
+    /* Init phantom points */
+    if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
+    hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
+    {
+      int lsb = 0;
+      int h_delta = glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ?
+                   (int) header->xMin - lsb : 0;
+      HB_UNUSED int tsb = 0;
+      int v_orig  = (int) header->yMax +
+#ifndef HB_NO_VERTICAL
+                   ((void) glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb)
+#else
+                   0
+#endif
+                   ;
+      unsigned h_adv = glyf_accelerator.hmtx->get_advance_without_var_unscaled (gid);
+      unsigned v_adv =
+#ifndef HB_NO_VERTICAL
+                      glyf_accelerator.vmtx->get_advance_without_var_unscaled (gid)
+#else
+                      - font->face->get_upem ()
+#endif
+                      ;
+      phantoms[PHANTOM_LEFT].x = h_delta;
+      phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta;
+      phantoms[PHANTOM_TOP].y = v_orig;
+      phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
+    }
+
+#ifndef HB_NO_VAR
+    if (coords)
+      glyf_accelerator.gvar->apply_deltas_to_points (gid,
+                                                    coords,
+                                                    points.as_array ().sub_array (old_length),
+                                                    phantom_only && type == SIMPLE);
+#endif
+
+    // mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
+    // with child glyphs' points
+    if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE)
+    {
+      if (unlikely (!points_with_deltas->resize (points.length))) return false;
+      *points_with_deltas = points;
+    }
+
+    switch (type) {
+    case SIMPLE:
+      if (depth == 0 && head_maxp_info)
+        head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, all_points.length - old_length - 4);
+      break;
+    case COMPOSITE:
+    {
+      unsigned int comp_index = 0;
+      for (auto &item : get_composite_iterator ())
+      {
+       hb_codepoint_t item_gid = item.get_gid ();
+
+        if (unlikely (current_glyphs->has (item_gid)))
+         continue;
+
+       current_glyphs->add (item_gid);
+
+       unsigned old_count = all_points.length;
+
+       if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
+                     !glyf_accelerator.glyph_for_gid (item_gid)
+                                      .get_points (font,
+                                                   glyf_accelerator,
+                                                   all_points,
+                                                   points_with_deltas,
+                                                   head_maxp_info,
+                                                   composite_contours,
+                                                   shift_points_hori,
+                                                   use_my_metrics,
+                                                   phantom_only,
+                                                   coords,
+                                                   current_glyphs,
+                                                   depth + 1,
+                                                   edge_count)))
+       {
+         current_glyphs->del (item_gid);
+         return false;
+       }
+
+       auto comp_points = all_points.as_array ().sub_array (old_count);
+
+       /* Copy phantom points from component if USE_MY_METRICS flag set */
+       if (use_my_metrics && item.is_use_my_metrics ())
+         for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
+           phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
+
+       if (comp_points) // Empty in case of phantom_only
+       {
+         float matrix[4];
+         contour_point_t default_trans;
+         item.get_transformation (matrix, default_trans);
+
+         /* Apply component transformation & translation (with deltas applied) */
+         item.transform_points (comp_points, matrix, points[comp_index]);
+       }
+
+       if (item.is_anchored () && !phantom_only)
+       {
+         unsigned int p1, p2;
+         item.get_anchor_points (p1, p2);
+         if (likely (p1 < all_points.length && p2 < comp_points.length))
+         {
+           contour_point_t delta;
+           delta.init (all_points[p1].x - comp_points[p2].x,
+                       all_points[p1].y - comp_points[p2].y);
+
+           item.translate (delta, comp_points);
+         }
+       }
+
+       all_points.resize (all_points.length - PHANTOM_COUNT);
+
+       if (all_points.length > HB_GLYF_MAX_POINTS)
+       {
+         current_glyphs->del (item_gid);
+         return false;
+       }
+
+       comp_index++;
+        current_glyphs->del (item_gid);
+      }
+
+      if (head_maxp_info && depth == 0)
+      {
+        if (composite_contours)
+          head_maxp_info->maxCompositeContours = hb_max (head_maxp_info->maxCompositeContours, *composite_contours);
+        head_maxp_info->maxCompositePoints = hb_max (head_maxp_info->maxCompositePoints, all_points.length);
+        head_maxp_info->maxComponentElements = hb_max (head_maxp_info->maxComponentElements, comp_index);
+      }
+      all_points.extend (phantoms);
+    } break;
+#ifndef HB_NO_VAR_COMPOSITES
+    case VAR_COMPOSITE:
+    {
+      hb_array_t<contour_point_t> points_left = points.as_array ();
+      for (auto &item : get_var_composite_iterator ())
+      {
+       hb_codepoint_t item_gid = item.get_gid ();
+
+        if (unlikely (current_glyphs->has (item_gid)))
+         continue;
+
+       current_glyphs->add (item_gid);
+
+       unsigned item_num_points = item.get_num_points ();
+       hb_array_t<contour_point_t> record_points = points_left.sub_array (0, item_num_points);
+       assert (record_points.length == item_num_points);
+
+       auto component_coords = coords;
+       /* Copying coords is expensive; so we have put an arbitrary
+        * limit on the max number of coords for now. */
+       if (item.is_reset_unspecified_axes () ||
+           coords.length > HB_GLYF_VAR_COMPOSITE_MAX_AXES)
+         component_coords = hb_array<int> ();
+
+       coord_setter_t coord_setter (component_coords);
+       item.set_variations (coord_setter, record_points);
+
+       unsigned old_count = all_points.length;
+
+       if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
+                     !glyf_accelerator.glyph_for_gid (item_gid)
+                                      .get_points (font,
+                                                   glyf_accelerator,
+                                                   all_points,
+                                                   points_with_deltas,
+                                                   head_maxp_info,
+                                                   nullptr,
+                                                   shift_points_hori,
+                                                   use_my_metrics,
+                                                   phantom_only,
+                                                   coord_setter.get_coords (),
+                                                   current_glyphs,
+                                                   depth + 1,
+                                                   edge_count)))
+       {
+         current_glyphs->del (item_gid);
+         return false;
+       }
+
+       auto comp_points = all_points.as_array ().sub_array (old_count);
+
+       /* Apply component transformation */
+       if (comp_points) // Empty in case of phantom_only
+         item.transform_points (record_points, comp_points);
+
+       /* Copy phantom points from component if USE_MY_METRICS flag set */
+       if (use_my_metrics && item.is_use_my_metrics ())
+         for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
+           phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
+
+       all_points.resize (all_points.length - PHANTOM_COUNT);
+
+       if (all_points.length > HB_GLYF_MAX_POINTS)
+       {
+         current_glyphs->del (item_gid);
+         return false;
+       }
+
+       points_left += item_num_points;
+
+        current_glyphs->del (item_gid);
+      }
+      all_points.extend (phantoms);
+    } break;
+#endif
+    case EMPTY:
+      all_points.extend (phantoms);
+      break;
+    }
+
+    if (depth == 0 && shift_points_hori) /* Apply at top level */
+    {
+      /* Undocumented rasterizer behavior:
+       * Shift points horizontally by the updated left side bearing
+       */
+      int v = -phantoms[PHANTOM_LEFT].x;
+      if (v)
+        for (auto &point : all_points)
+         point.x += v;
+    }
+
+    return !all_points.in_error ();
+  }
+
+  bool get_extents_without_var_scaled (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator,
+                                      hb_glyph_extents_t *extents) const
+  {
+    if (type == EMPTY) return true; /* Empty glyph; zero extents. */
+    return header->get_extents_without_var_scaled (font, glyf_accelerator, gid, extents);
+  }
+
+  hb_bytes_t get_bytes () const { return bytes; }
+  glyph_type_t get_type () const { return type; }
+  const GlyphHeader *get_header () const { return header; }
+
+  Glyph () : bytes (),
+             header (bytes.as<GlyphHeader> ()),
+             gid (-1),
+             type(EMPTY)
+  {}
+
+  Glyph (hb_bytes_t bytes_,
+        hb_codepoint_t gid_ = (unsigned) -1) : bytes (bytes_),
+                                                header (bytes.as<GlyphHeader> ()),
+                                                gid (gid_)
+  {
+    int num_contours = header->numberOfContours;
+    if (unlikely (num_contours == 0)) type = EMPTY;
+    else if (num_contours > 0) type = SIMPLE;
+    else if (num_contours == -1) type = COMPOSITE;
+#ifndef HB_NO_VAR_COMPOSITES
+    else if (num_contours == -2) type = VAR_COMPOSITE;
+#endif
+    else type = EMPTY; // Spec deviation; Spec says COMPOSITE, but not seen in the wild.
+  }
+
+  protected:
+  hb_bytes_t bytes;
+  const GlyphHeader *header;
+  hb_codepoint_t gid;
+  glyph_type_t type;
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_GLYPH_HH */
diff --git a/src/OT/glyf/GlyphHeader.hh b/src/OT/glyf/GlyphHeader.hh
new file mode 100644 (file)
index 0000000..a43b669
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef OT_GLYF_GLYPHHEADER_HH
+#define OT_GLYF_GLYPHHEADER_HH
+
+
+#include "../../hb-open-type.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+struct GlyphHeader
+{
+  bool has_data () const { return numberOfContours; }
+
+  template <typename accelerator_t>
+  bool get_extents_without_var_scaled (hb_font_t *font, const accelerator_t &glyf_accelerator,
+                                      hb_codepoint_t gid, hb_glyph_extents_t *extents) const
+  {
+    /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */
+    /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */
+    int lsb = hb_min (xMin, xMax);
+    (void) glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb);
+    extents->x_bearing = lsb;
+    extents->y_bearing = hb_max (yMin, yMax);
+    extents->width     = hb_max (xMin, xMax) - hb_min (xMin, xMax);
+    extents->height    = hb_min (yMin, yMax) - hb_max (yMin, yMax);
+
+    font->scale_glyph_extents (extents);
+
+    return true;
+  }
+
+  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. */
+  FWORD        xMin;   /* Minimum x for coordinate data. */
+  FWORD        yMin;   /* Minimum y for coordinate data. */
+  FWORD        xMax;   /* Maximum x for coordinate data. */
+  FWORD        yMax;   /* Maximum y for coordinate data. */
+  public:
+  DEFINE_SIZE_STATIC (10);
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_GLYPHHEADER_HH */
diff --git a/src/OT/glyf/SimpleGlyph.hh b/src/OT/glyf/SimpleGlyph.hh
new file mode 100644 (file)
index 0000000..1d42cc2
--- /dev/null
@@ -0,0 +1,348 @@
+#ifndef OT_GLYF_SIMPLEGLYPH_HH
+#define OT_GLYF_SIMPLEGLYPH_HH
+
+
+#include "../../hb-open-type.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+struct SimpleGlyph
+{
+  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_OVERLAP_SIMPLE = 0x40,
+    FLAG_CUBIC          = 0x80
+  };
+
+  const GlyphHeader &header;
+  hb_bytes_t bytes;
+  SimpleGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
+    header (header_), bytes (bytes_) {}
+
+  unsigned int instruction_len_offset () const
+  { return GlyphHeader::static_size + 2 * header.numberOfContours; }
+
+  unsigned int length (unsigned int instruction_len) const
+  { return instruction_len_offset () + 2 + instruction_len; }
+
+  bool has_instructions_length () const
+  {
+    return instruction_len_offset () + 2 <= bytes.length;
+  }
+
+  unsigned int instructions_length () const
+  {
+    unsigned int instruction_length_offset = instruction_len_offset ();
+    if (unlikely (instruction_length_offset + 2 > bytes.length)) return 0;
+
+    const HBUINT16 &instructionLength = StructAtOffset<HBUINT16> (&bytes, instruction_length_offset);
+    /* Out of bounds of the current glyph */
+    if (unlikely (length (instructionLength) > bytes.length)) return 0;
+    return instructionLength;
+  }
+
+  const hb_bytes_t trim_padding () const
+  {
+    /* based on FontTools _g_l_y_f.py::trim */
+    const uint8_t *glyph = (uint8_t*) bytes.arrayZ;
+    const uint8_t *glyph_end = glyph + bytes.length;
+    /* simple glyph w/contours, possibly trimmable */
+    glyph += instruction_len_offset ();
+
+    if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t ();
+    unsigned int num_coordinates = StructAtOffset<HBUINT16> (glyph - 2, 0) + 1;
+    unsigned int num_instructions = StructAtOffset<HBUINT16> (glyph, 0);
+
+    glyph += 2 + num_instructions;
+
+    unsigned int coord_bytes = 0;
+    unsigned int coords_with_flags = 0;
+    while (glyph < glyph_end)
+    {
+      uint8_t flag = *glyph;
+      glyph++;
+
+      unsigned int repeat = 1;
+      if (flag & FLAG_REPEAT)
+      {
+       if (unlikely (glyph >= glyph_end)) return hb_bytes_t ();
+       repeat = *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;
+
+      coord_bytes += (xBytes + yBytes) * repeat;
+      coords_with_flags += repeat;
+      if (coords_with_flags >= num_coordinates) break;
+    }
+
+    if (unlikely (coords_with_flags != num_coordinates)) return hb_bytes_t ();
+    return bytes.sub_array (0, bytes.length + coord_bytes - (glyph_end - glyph));
+  }
+
+  /* zero instruction length */
+  void drop_hints ()
+  {
+    if (!has_instructions_length ()) return;
+    GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header);
+    (HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0;
+  }
+
+  void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
+  {
+    unsigned int instructions_len = instructions_length ();
+    unsigned int glyph_length = length (instructions_len);
+    dest_start = bytes.sub_array (0, glyph_length - instructions_len);
+    dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length);
+  }
+
+  void set_overlaps_flag ()
+  {
+    if (unlikely (!header.numberOfContours)) return;
+
+    unsigned flags_offset = length (instructions_length ());
+    if (unlikely (flags_offset + 1 > bytes.length)) return;
+
+    HBUINT8 &first_flag = (HBUINT8 &) StructAtOffset<HBUINT16> (&bytes, flags_offset);
+    first_flag = (uint8_t) first_flag | FLAG_OVERLAP_SIMPLE;
+  }
+
+  static bool read_flags (const HBUINT8 *&p /* IN/OUT */,
+                         hb_array_t<contour_point_t> points_ /* IN/OUT */,
+                         const HBUINT8 *end)
+  {
+    unsigned count = points_.length;
+    for (unsigned int i = 0; i < count;)
+    {
+      if (unlikely (p + 1 > end)) return false;
+      uint8_t flag = *p++;
+      points_.arrayZ[i++].flag = flag;
+      if (flag & FLAG_REPEAT)
+      {
+       if (unlikely (p + 1 > end)) return false;
+       unsigned int repeat_count = *p++;
+       unsigned stop = hb_min (i + repeat_count, count);
+       for (; i < stop; i++)
+         points_.arrayZ[i].flag = flag;
+      }
+    }
+    return true;
+  }
+
+  static bool read_points (const HBUINT8 *&p /* IN/OUT */,
+                          hb_array_t<contour_point_t> points_ /* IN/OUT */,
+                          const HBUINT8 *end,
+                          float contour_point_t::*m,
+                          const simple_glyph_flag_t short_flag,
+                          const simple_glyph_flag_t same_flag)
+  {
+    int v = 0;
+
+    for (auto &point : points_)
+    {
+      unsigned flag = point.flag;
+      if (flag & short_flag)
+      {
+       if (unlikely (p + 1 > end)) return false;
+       if (flag & same_flag)
+         v += *p++;
+       else
+         v -= *p++;
+      }
+      else
+      {
+       if (!(flag & same_flag))
+       {
+         if (unlikely (p + HBINT16::static_size > end)) return false;
+         v += *(const HBINT16 *) p;
+         p += HBINT16::static_size;
+       }
+      }
+      point.*m = v;
+    }
+    return true;
+  }
+
+  bool get_contour_points (contour_point_vector_t &points /* OUT */,
+                          bool phantom_only = false) const
+  {
+    const HBUINT16 *endPtsOfContours = &StructAfter<HBUINT16> (header);
+    int num_contours = header.numberOfContours;
+    assert (num_contours > 0);
+    /* One extra item at the end, for the instruction-count below. */
+    if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false;
+    unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
+
+    unsigned old_length = points.length;
+    points.alloc (points.length + num_points + 4, true); // Allocate for phantom points, to avoid a possible copy
+    if (unlikely (!points.resize (points.length + num_points, false))) return false;
+    auto points_ = points.as_array ().sub_array (old_length);
+    if (!phantom_only)
+      hb_memset (points_.arrayZ, 0, sizeof (contour_point_t) * num_points);
+    if (phantom_only) return true;
+
+    for (int i = 0; i < num_contours; i++)
+      points_[endPtsOfContours[i]].is_end_point = true;
+
+    /* Skip instructions */
+    const HBUINT8 *p = &StructAtOffset<HBUINT8> (&endPtsOfContours[num_contours + 1],
+                                                endPtsOfContours[num_contours]);
+
+    if (unlikely ((const char *) p < bytes.arrayZ)) return false; /* Unlikely overflow */
+    const HBUINT8 *end = (const HBUINT8 *) (bytes.arrayZ + bytes.length);
+    if (unlikely (p >= end)) return false;
+
+    /* Read x & y coordinates */
+    return read_flags (p, points_, end)
+        && read_points (p, points_, end, &contour_point_t::x,
+                       FLAG_X_SHORT, FLAG_X_SAME)
+       && read_points (p, points_, end, &contour_point_t::y,
+                       FLAG_Y_SHORT, FLAG_Y_SAME);
+  }
+
+  static void encode_coord (int value,
+                            unsigned &flag,
+                            const simple_glyph_flag_t short_flag,
+                            const simple_glyph_flag_t same_flag,
+                            hb_vector_t<uint8_t> &coords /* OUT */)
+  {
+    if (value == 0)
+    {
+      flag |= same_flag;
+    }
+    else if (value >= -255 && value <= 255)
+    {
+      flag |= short_flag;
+      if (value > 0) flag |= same_flag;
+      else value = -value;
+
+      coords.arrayZ[coords.length++] = (uint8_t) value;
+    }
+    else
+    {
+      int16_t val = value;
+      coords.arrayZ[coords.length++] = val >> 8;
+      coords.arrayZ[coords.length++] = val & 0xff;
+    }
+  }
+
+  static void encode_flag (unsigned flag,
+                           unsigned &repeat,
+                           unsigned lastflag,
+                           hb_vector_t<uint8_t> &flags /* OUT */)
+  {
+    if (flag == lastflag && repeat != 255)
+    {
+      repeat++;
+      if (repeat == 1)
+      {
+        /* We know there's room. */
+        flags.arrayZ[flags.length++] = flag;
+      }
+      else
+      {
+        unsigned len = flags.length;
+        flags.arrayZ[len-2] = flag | FLAG_REPEAT;
+        flags.arrayZ[len-1] = repeat;
+      }
+    }
+    else
+    {
+      repeat = 0;
+      flags.arrayZ[flags.length++] = flag;
+    }
+  }
+
+  bool compile_bytes_with_deltas (const contour_point_vector_t &all_points,
+                                  bool no_hinting,
+                                  hb_bytes_t &dest_bytes /* OUT */)
+  {
+    if (header.numberOfContours == 0 || all_points.length <= 4)
+    {
+      dest_bytes = hb_bytes_t ();
+      return true;
+    }
+    unsigned num_points = all_points.length - 4;
+
+    hb_vector_t<uint8_t> flags, x_coords, y_coords;
+    if (unlikely (!flags.alloc (num_points, true))) return false;
+    if (unlikely (!x_coords.alloc (2*num_points, true))) return false;
+    if (unlikely (!y_coords.alloc (2*num_points, true))) return false;
+
+    unsigned lastflag = 255, repeat = 0;
+    int prev_x = 0, prev_y = 0;
+
+    for (unsigned i = 0; i < num_points; i++)
+    {
+      unsigned flag = all_points.arrayZ[i].flag;
+      flag &= FLAG_ON_CURVE | FLAG_OVERLAP_SIMPLE | FLAG_CUBIC;
+
+      int cur_x = roundf (all_points.arrayZ[i].x);
+      int cur_y = roundf (all_points.arrayZ[i].y);
+      encode_coord (cur_x - prev_x, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords);
+      encode_coord (cur_y - prev_y, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords);
+      encode_flag (flag, repeat, lastflag, flags);
+
+      prev_x = cur_x;
+      prev_y = cur_y;
+      lastflag = flag;
+    }
+
+    unsigned len_before_instrs = 2 * header.numberOfContours + 2;
+    unsigned len_instrs = instructions_length ();
+    unsigned total_len = len_before_instrs + flags.length + x_coords.length + y_coords.length;
+
+    if (!no_hinting)
+      total_len += len_instrs;
+
+    char *p = (char *) hb_malloc (total_len);
+    if (unlikely (!p)) return false;
+
+    const char *src = bytes.arrayZ + GlyphHeader::static_size;
+    char *cur = p;
+    hb_memcpy (p, src, len_before_instrs);
+
+    cur += len_before_instrs;
+    src += len_before_instrs;
+
+    if (!no_hinting)
+    {
+      hb_memcpy (cur, src, len_instrs);
+      cur += len_instrs;
+    }
+
+    hb_memcpy (cur, flags.arrayZ, flags.length);
+    cur += flags.length;
+
+    hb_memcpy (cur, x_coords.arrayZ, x_coords.length);
+    cur += x_coords.length;
+
+    hb_memcpy (cur, y_coords.arrayZ, y_coords.length);
+
+    dest_bytes = hb_bytes_t (p, total_len);
+    return true;
+  }
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_SIMPLEGLYPH_HH */
diff --git a/src/OT/glyf/SubsetGlyph.hh b/src/OT/glyf/SubsetGlyph.hh
new file mode 100644 (file)
index 0000000..8099d3c
--- /dev/null
@@ -0,0 +1,152 @@
+#ifndef OT_GLYF_SUBSETGLYPH_HH
+#define OT_GLYF_SUBSETGLYPH_HH
+
+
+#include "../../hb-open-type.hh"
+
+
+namespace OT {
+
+struct glyf_accelerator_t;
+
+namespace glyf_impl {
+
+
+struct SubsetGlyph
+{
+  hb_codepoint_t old_gid;
+  Glyph source_glyph;
+  hb_bytes_t dest_start;  /* region of source_glyph to copy first */
+  hb_bytes_t dest_end;    /* region of source_glyph to copy second */
+  bool allocated;
+
+  bool serialize (hb_serialize_context_t *c,
+                 bool use_short_loca,
+                 const hb_subset_plan_t *plan) const
+  {
+    TRACE_SERIALIZE (this);
+
+    hb_bytes_t dest_glyph = dest_start.copy (c);
+    hb_bytes_t end_copy = dest_end.copy (c);
+    if (!end_copy.arrayZ || !dest_glyph.arrayZ) {
+      return false;
+    }
+
+    dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + end_copy.length);
+    unsigned int pad_length = use_short_loca ? padding () : 0;
+    DEBUG_MSG (SUBSET, nullptr, "serialize %u byte glyph, width %u pad %u", dest_glyph.length, dest_glyph.length + pad_length, pad_length);
+
+    HBUINT8 pad;
+    pad = 0;
+    while (pad_length > 0)
+    {
+      (void) c->embed (pad);
+      pad_length--;
+    }
+
+    if (unlikely (!dest_glyph.length)) return_trace (true);
+
+    /* update components gids. */
+    for (auto &_ : Glyph (dest_glyph).get_composite_iterator ())
+    {
+      hb_codepoint_t new_gid;
+      if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
+       const_cast<CompositeGlyphRecord &> (_).set_gid (new_gid);
+    }
+#ifndef HB_NO_VAR_COMPOSITES
+    for (auto &_ : Glyph (dest_glyph).get_var_composite_iterator ())
+    {
+      hb_codepoint_t new_gid;
+      if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
+       const_cast<VarCompositeGlyphRecord &> (_).set_gid (new_gid);
+    }
+#endif
+
+#ifndef HB_NO_BEYOND_64K
+    auto it = Glyph (dest_glyph).get_composite_iterator ();
+    if (it)
+    {
+      /* lower GID24 to GID16 in components if possible.
+       *
+       * TODO: VarComposite. Not as critical, since VarComposite supports
+       * gid24 from the first version. */
+      char *p = it ? (char *) &*it : nullptr;
+      char *q = p;
+      const char *end = dest_glyph.arrayZ + dest_glyph.length;
+      while (it)
+      {
+       auto &rec = const_cast<CompositeGlyphRecord &> (*it);
+       ++it;
+
+       q += rec.get_size ();
+
+       rec.lower_gid_24_to_16 ();
+
+       unsigned size = rec.get_size ();
+
+       memmove (p, &rec, size);
+
+       p += size;
+      }
+      memmove (p, q, end - q);
+      p += end - q;
+
+      /* We want to shorten the glyph, but we can't do that without
+       * updating the length in the loca table, which is already
+       * written out :-(.  So we just fill the rest of the glyph with
+       * harmless instructions, since that's what they will be
+       * interpreted as.
+       *
+       * Should move the lowering to _populate_subset_glyphs() to
+       * fix this issue. */
+
+      hb_memset (p, 0x7A /* TrueType instruction ROFF; harmless */, end - p);
+      p += end - p;
+      dest_glyph = hb_bytes_t (dest_glyph.arrayZ, p - (char *) dest_glyph.arrayZ);
+
+      // TODO: Padding; & trim serialized bytes.
+      // TODO: Update length in loca. Ugh.
+    }
+#endif
+
+    if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+      Glyph (dest_glyph).drop_hints ();
+
+    if (plan->flags & HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG)
+      Glyph (dest_glyph).set_overlaps_flag ();
+
+    return_trace (true);
+  }
+
+  bool compile_bytes_with_deltas (const hb_subset_plan_t *plan,
+                                  hb_font_t *font,
+                                  const glyf_accelerator_t &glyf)
+  {
+    allocated = source_glyph.compile_bytes_with_deltas (plan, font, glyf, dest_start, dest_end);
+    return allocated;
+  }
+
+  void free_compiled_bytes ()
+  {
+    if (likely (allocated)) {
+      allocated = false;
+      dest_start.fini ();
+      dest_end.fini ();
+    }
+  }
+
+  void drop_hints_bytes ()
+  { source_glyph.drop_hints_bytes (dest_start, dest_end); }
+
+  unsigned int      length () const { return dest_start.length + dest_end.length; }
+  /* pad to 2 to ensure 2-byte loca will be ok */
+  unsigned int     padding () const { return length () % 2; }
+  unsigned int padded_size () const { return length () + padding (); }
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_SUBSETGLYPH_HH */
diff --git a/src/OT/glyf/VarCompositeGlyph.hh b/src/OT/glyf/VarCompositeGlyph.hh
new file mode 100644 (file)
index 0000000..50cbece
--- /dev/null
@@ -0,0 +1,401 @@
+#ifndef OT_GLYF_VARCOMPOSITEGLYPH_HH
+#define OT_GLYF_VARCOMPOSITEGLYPH_HH
+
+
+#include "../../hb-open-type.hh"
+#include "coord-setter.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+struct VarCompositeGlyphRecord
+{
+  protected:
+  enum var_composite_glyph_flag_t
+  {
+    USE_MY_METRICS             = 0x0001,
+    AXIS_INDICES_ARE_SHORT     = 0x0002,
+    UNIFORM_SCALE              = 0x0004,
+    HAVE_TRANSLATE_X           = 0x0008,
+    HAVE_TRANSLATE_Y           = 0x0010,
+    HAVE_ROTATION              = 0x0020,
+    HAVE_SCALE_X               = 0x0040,
+    HAVE_SCALE_Y               = 0x0080,
+    HAVE_SKEW_X                        = 0x0100,
+    HAVE_SKEW_Y                        = 0x0200,
+    HAVE_TCENTER_X             = 0x0400,
+    HAVE_TCENTER_Y             = 0x0800,
+    GID_IS_24BIT               = 0x1000,
+    AXES_HAVE_VARIATION                = 0x2000,
+    RESET_UNSPECIFIED_AXES     = 0x4000,
+  };
+
+  public:
+
+  unsigned int get_size () const
+  {
+    unsigned fl = flags;
+    unsigned int size = min_size;
+
+    unsigned axis_width = (fl & AXIS_INDICES_ARE_SHORT) ? 4 : 3;
+    size += numAxes * axis_width;
+
+    if (fl & GID_IS_24BIT)     size += 1;
+
+    // 2 bytes each for the following flags
+    fl = fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y |
+              HAVE_ROTATION |
+              HAVE_SCALE_X | HAVE_SCALE_Y |
+              HAVE_SKEW_X | HAVE_SKEW_Y |
+              HAVE_TCENTER_X | HAVE_TCENTER_Y);
+    size += hb_popcount (fl) * 2;
+
+    return size;
+  }
+
+  bool has_more () const { return true; }
+
+  bool is_use_my_metrics () const { return flags & USE_MY_METRICS; }
+  bool is_reset_unspecified_axes () const { return flags & RESET_UNSPECIFIED_AXES; }
+
+  hb_codepoint_t get_gid () const
+  {
+    if (flags & GID_IS_24BIT)
+      return * (const HBGlyphID24 *) &pad;
+    else
+      return * (const HBGlyphID16 *) &pad;
+  }
+
+  void set_gid (hb_codepoint_t gid)
+  {
+    if (flags & GID_IS_24BIT)
+      * (HBGlyphID24 *) &pad = gid;
+    else
+      * (HBGlyphID16 *) &pad = gid;
+  }
+
+  unsigned get_numAxes () const
+  {
+    return numAxes;
+  }
+
+  unsigned get_num_points () const
+  {
+    unsigned fl = flags;
+    unsigned num = 0;
+    if (fl & AXES_HAVE_VARIATION)                      num += numAxes;
+
+    /* Hopefully faster code, relying on the value of the flags. */
+    fl = (((fl & (HAVE_TRANSLATE_Y | HAVE_SCALE_Y | HAVE_SKEW_Y | HAVE_TCENTER_Y)) >> 1) | fl) &
+         (HAVE_TRANSLATE_X | HAVE_ROTATION | HAVE_SCALE_X | HAVE_SKEW_X | HAVE_TCENTER_X);
+    num += hb_popcount (fl);
+    return num;
+
+    /* Slower but more readable code. */
+    if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))    num++;
+    if (fl & HAVE_ROTATION)                            num++;
+    if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y))            num++;
+    if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y))              num++;
+    if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y))                num++;
+    return num;
+  }
+
+  void transform_points (hb_array_t<const contour_point_t> record_points,
+                        hb_array_t<contour_point_t> points) const
+  {
+    float matrix[4];
+    contour_point_t trans;
+
+    get_transformation_from_points (record_points.arrayZ, matrix, trans);
+
+    auto arrayZ = points.arrayZ;
+    unsigned count = points.length;
+
+    if (matrix[0] != 1.f || matrix[1] != 0.f ||
+       matrix[2] != 0.f || matrix[3] != 1.f)
+      for (unsigned i = 0; i < count; i++)
+        arrayZ[i].transform (matrix);
+
+    if (trans.x != 0.f || trans.y != 0.f)
+      for (unsigned i = 0; i < count; i++)
+        arrayZ[i].translate (trans);
+  }
+
+  static inline void transform (float (&matrix)[4], contour_point_t &trans,
+                               float (other)[6])
+  {
+    // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L268
+    float xx1 = other[0];
+    float xy1 = other[1];
+    float yx1 = other[2];
+    float yy1 = other[3];
+    float dx1 = other[4];
+    float dy1 = other[5];
+    float xx2 = matrix[0];
+    float xy2 = matrix[1];
+    float yx2 = matrix[2];
+    float yy2 = matrix[3];
+    float dx2 = trans.x;
+    float dy2 = trans.y;
+
+    matrix[0] = xx1*xx2 + xy1*yx2;
+    matrix[1] = xx1*xy2 + xy1*yy2;
+    matrix[2] = yx1*xx2 + yy1*yx2;
+    matrix[3] = yx1*xy2 + yy1*yy2;
+    trans.x = xx2*dx1 + yx2*dy1 + dx2;
+    trans.y = xy2*dx1 + yy2*dy1 + dy2;
+  }
+
+  static void translate (float (&matrix)[4], contour_point_t &trans,
+                        float translateX, float translateY)
+  {
+    if (!translateX && !translateY)
+      return;
+
+    trans.x += matrix[0] * translateX + matrix[2] * translateY;
+    trans.y += matrix[1] * translateX + matrix[3] * translateY;
+  }
+
+  static void scale (float (&matrix)[4], contour_point_t &trans,
+                    float scaleX, float scaleY)
+  {
+    if (scaleX == 1.f && scaleY == 1.f)
+      return;
+
+    matrix[0] *= scaleX;
+    matrix[1] *= scaleX;
+    matrix[2] *= scaleY;
+    matrix[3] *= scaleY;
+  }
+
+  static void rotate (float (&matrix)[4], contour_point_t &trans,
+                     float rotation)
+  {
+    if (!rotation)
+      return;
+
+    // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240
+    rotation = rotation * HB_PI;
+    float c;
+    float s;
+#ifdef HAVE_SINCOSF
+    sincosf (rotation, &s, &c);
+#else
+    c = cosf (rotation);
+    s = sinf (rotation);
+#endif
+    float other[6] = {c, s, -s, c, 0.f, 0.f};
+    transform (matrix, trans, other);
+  }
+
+  static void skew (float (&matrix)[4], contour_point_t &trans,
+                   float skewX, float skewY)
+  {
+    if (!skewX && !skewY)
+      return;
+
+    // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255
+    skewX = skewX * HB_PI;
+    skewY = skewY * HB_PI;
+    float other[6] = {1.f,
+                     skewY ? tanf (skewY) : 0.f,
+                     skewX ? tanf (skewX) : 0.f,
+                     1.f,
+                     0.f, 0.f};
+    transform (matrix, trans, other);
+  }
+
+  bool get_points (contour_point_vector_t &points) const
+  {
+    unsigned num_points = get_num_points ();
+
+    points.alloc (points.length + num_points + 4); // For phantom points
+    if (unlikely (!points.resize (points.length + num_points, false))) return false;
+    contour_point_t *rec_points = points.arrayZ + (points.length - num_points);
+    hb_memset (rec_points, 0, num_points * sizeof (rec_points[0]));
+
+    unsigned fl = flags;
+
+    unsigned num_axes = numAxes;
+    unsigned axis_width = (fl & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
+    unsigned axes_size = num_axes * axis_width;
+
+    const F2DOT14 *q = (const F2DOT14 *) (axes_size +
+                                         (fl & GID_IS_24BIT ? 3 : 2) +
+                                         (const HBUINT8 *) &pad);
+
+    unsigned count = num_axes;
+    if (fl & AXES_HAVE_VARIATION)
+    {
+      for (unsigned i = 0; i < count; i++)
+       rec_points++->x = q++->to_int ();
+    }
+    else
+      q += count;
+
+    const HBUINT16 *p = (const HBUINT16 *) q;
+
+    if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
+    {
+      int translateX = (fl & HAVE_TRANSLATE_X) ? * (const FWORD *) p++ : 0;
+      int translateY = (fl & HAVE_TRANSLATE_Y) ? * (const FWORD *) p++ : 0;
+      rec_points->x = translateX;
+      rec_points->y = translateY;
+      rec_points++;
+    }
+    if (fl & HAVE_ROTATION)
+    {
+      int rotation = (fl & HAVE_ROTATION) ? ((const F4DOT12 *) p++)->to_int () : 0;
+      rec_points->x = rotation;
+      rec_points++;
+    }
+    if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y))
+    {
+      int scaleX = (fl & HAVE_SCALE_X) ? ((const F6DOT10 *) p++)->to_int () : 1 << 10;
+      int scaleY = (fl & HAVE_SCALE_Y) ? ((const F6DOT10 *) p++)->to_int () : 1 << 10;
+      if ((fl & UNIFORM_SCALE) && !(fl & HAVE_SCALE_Y))
+       scaleY = scaleX;
+      rec_points->x = scaleX;
+      rec_points->y = scaleY;
+      rec_points++;
+    }
+    if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y))
+    {
+      int skewX = (fl & HAVE_SKEW_X) ? ((const F4DOT12 *) p++)->to_int () : 0;
+      int skewY = (fl & HAVE_SKEW_Y) ? ((const F4DOT12 *) p++)->to_int () : 0;
+      rec_points->x = skewX;
+      rec_points->y = skewY;
+      rec_points++;
+    }
+    if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
+    {
+      int tCenterX = (fl & HAVE_TCENTER_X) ? * (const FWORD *) p++ : 0;
+      int tCenterY = (fl & HAVE_TCENTER_Y) ? * (const FWORD *) p++ : 0;
+      rec_points->x = tCenterX;
+      rec_points->y = tCenterY;
+      rec_points++;
+    }
+
+    return true;
+  }
+
+  void get_transformation_from_points (const contour_point_t *rec_points,
+                                      float (&matrix)[4], contour_point_t &trans) const
+  {
+    unsigned fl = flags;
+
+    if (fl & AXES_HAVE_VARIATION)
+      rec_points += numAxes;
+
+    matrix[0] = matrix[3] = 1.f;
+    matrix[1] = matrix[2] = 0.f;
+    trans.init (0.f, 0.f);
+
+    float translateX = 0.f;
+    float translateY = 0.f;
+    float rotation = 0.f;
+    float scaleX = 1.f;
+    float scaleY = 1.f;
+    float skewX = 0.f;
+    float skewY = 0.f;
+    float tCenterX = 0.f;
+    float tCenterY = 0.f;
+
+    if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
+    {
+      translateX = rec_points->x;
+      translateY = rec_points->y;
+      rec_points++;
+    }
+    if (fl & HAVE_ROTATION)
+    {
+      rotation = rec_points->x / (1 << 12);
+      rec_points++;
+    }
+    if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y))
+    {
+      scaleX = rec_points->x / (1 << 10);
+      scaleY = rec_points->y / (1 << 10);
+      rec_points++;
+    }
+    if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y))
+    {
+      skewX = rec_points->x / (1 << 12);
+      skewY = rec_points->y / (1 << 12);
+      rec_points++;
+    }
+    if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
+    {
+      tCenterX = rec_points->x;
+      tCenterY = rec_points->y;
+      rec_points++;
+    }
+
+    translate (matrix, trans, translateX + tCenterX, translateY + tCenterY);
+    rotate (matrix, trans, rotation);
+    scale (matrix, trans, scaleX, scaleY);
+    skew (matrix, trans, -skewX, skewY);
+    translate (matrix, trans, -tCenterX, -tCenterY);
+  }
+
+  void set_variations (coord_setter_t &setter,
+                      hb_array_t<contour_point_t> rec_points) const
+  {
+    bool have_variations = flags & AXES_HAVE_VARIATION;
+    unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
+    unsigned num_axes = numAxes;
+
+    const HBUINT8  *p = (const HBUINT8 *)  (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24BIT ? 3 : 2));
+    const HBUINT16 *q = (const HBUINT16 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24BIT ? 3 : 2));
+
+    const F2DOT14 *a = (const F2DOT14 *) ((HBUINT8 *) (axis_width == 1 ? (p + num_axes) : (HBUINT8 *) (q + num_axes)));
+
+    unsigned count = num_axes;
+    for (unsigned i = 0; i < count; i++)
+    {
+      unsigned axis_index = axis_width == 1 ? (unsigned) *p++ : (unsigned) *q++;
+
+      signed v = have_variations ? rec_points.arrayZ[i].x : a++->to_int ();
+
+      v = hb_clamp (v, -(1<<14), (1<<14));
+      setter[axis_index] = v;
+    }
+  }
+
+  protected:
+  HBUINT16     flags;
+  HBUINT8      numAxes;
+  HBUINT16     pad;
+  public:
+  DEFINE_SIZE_MIN (5);
+};
+
+using var_composite_iter_t = composite_iter_tmpl<VarCompositeGlyphRecord>;
+
+struct VarCompositeGlyph
+{
+  const GlyphHeader &header;
+  hb_bytes_t bytes;
+  VarCompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
+    header (header_), bytes (bytes_) {}
+
+  var_composite_iter_t iter () const
+  { return var_composite_iter_t (bytes, &StructAfter<VarCompositeGlyphRecord, GlyphHeader> (header)); }
+
+  const hb_bytes_t trim_padding () const
+  {
+    unsigned length = GlyphHeader::static_size;
+    for (auto &comp : iter ())
+      length += comp.get_size ();
+    return bytes.sub_array (0, length);
+  }
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_VARCOMPOSITEGLYPH_HH */
diff --git a/src/OT/glyf/composite-iter.hh b/src/OT/glyf/composite-iter.hh
new file mode 100644 (file)
index 0000000..d05701f
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef OT_GLYF_COMPOSITE_ITER_HH
+#define OT_GLYF_COMPOSITE_ITER_HH
+
+
+#include "../../hb.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+template <typename CompositeGlyphRecord>
+struct composite_iter_tmpl : hb_iter_with_fallback_t<composite_iter_tmpl<CompositeGlyphRecord>,
+                                                    const CompositeGlyphRecord &>
+{
+  typedef const CompositeGlyphRecord *__item_t__;
+  composite_iter_tmpl (hb_bytes_t glyph_, __item_t__ current_) :
+      glyph (glyph_), current (nullptr), current_size (0)
+  {
+    set_current (current_);
+  }
+
+  composite_iter_tmpl () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {}
+
+  const CompositeGlyphRecord & __item__ () const { return *current; }
+  bool __more__ () const { return current; }
+  void __next__ ()
+  {
+    if (!current->has_more ()) { current = nullptr; return; }
+
+    set_current (&StructAtOffset<CompositeGlyphRecord> (current, current_size));
+  }
+  composite_iter_tmpl __end__ () const { return composite_iter_tmpl (); }
+  bool operator != (const composite_iter_tmpl& o) const
+  { return current != o.current; }
+
+
+  void set_current (__item_t__ current_)
+  {
+    if (!glyph.check_range (current_, CompositeGlyphRecord::min_size))
+    {
+      current = nullptr;
+      current_size = 0;
+      return;
+    }
+    unsigned size = current_->get_size ();
+    if (!glyph.check_range (current_, size))
+    {
+      current = nullptr;
+      current_size = 0;
+      return;
+    }
+
+    current = current_;
+    current_size = size;
+  }
+
+  private:
+  hb_bytes_t glyph;
+  __item_t__ current;
+  unsigned current_size;
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+#endif /* OT_GLYF_COMPOSITE_ITER_HH */
diff --git a/src/OT/glyf/coord-setter.hh b/src/OT/glyf/coord-setter.hh
new file mode 100644 (file)
index 0000000..cf05929
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef OT_GLYF_COORD_SETTER_HH
+#define OT_GLYF_COORD_SETTER_HH
+
+
+#include "../../hb.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+struct coord_setter_t
+{
+  coord_setter_t (hb_array_t<int> coords) :
+    coords (coords) {}
+
+  int& operator [] (unsigned idx)
+  {
+    if (unlikely (idx >= HB_GLYF_VAR_COMPOSITE_MAX_AXES))
+      return Crap(int);
+    if (coords.length < idx + 1)
+      coords.resize (idx + 1);
+    return coords[idx];
+  }
+
+  hb_array_t<int> get_coords ()
+  { return coords.as_array (); }
+
+  hb_vector_t<int> coords;
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+#endif /* OT_GLYF_COORD_SETTER_HH */
diff --git a/src/OT/glyf/glyf-helpers.hh b/src/OT/glyf/glyf-helpers.hh
new file mode 100644 (file)
index 0000000..d0a5a13
--- /dev/null
@@ -0,0 +1,127 @@
+#ifndef OT_GLYF_GLYF_HELPERS_HH
+#define OT_GLYF_GLYF_HELPERS_HH
+
+
+#include "../../hb-open-type.hh"
+#include "../../hb-subset-plan.hh"
+
+#include "loca.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+template<typename IteratorIn, typename TypeOut,
+        hb_requires (hb_is_source_of (IteratorIn, unsigned int))>
+static void
+_write_loca (IteratorIn&& it,
+            const hb_sorted_vector_t<hb_codepoint_pair_t> new_to_old_gid_list,
+            bool short_offsets,
+            TypeOut *dest,
+            unsigned num_offsets)
+{
+  unsigned right_shift = short_offsets ? 1 : 0;
+  unsigned offset = 0;
+  TypeOut value;
+  value = 0;
+  *dest++ = value;
+  hb_codepoint_t last = 0;
+  for (auto _ : new_to_old_gid_list)
+  {
+    hb_codepoint_t gid = _.first;
+    for (; last < gid; last++)
+    {
+      DEBUG_MSG (SUBSET, nullptr, "loca entry empty offset %u", offset);
+      *dest++ = value;
+    }
+
+    unsigned padded_size = *it++;
+    offset += padded_size;
+    DEBUG_MSG (SUBSET, nullptr, "loca entry gid %u offset %u padded-size %u", gid, offset, padded_size);
+    value = offset >> right_shift;
+    *dest++ = value;
+
+    last++; // Skip over gid
+  }
+  unsigned num_glyphs = num_offsets - 1;
+  for (; last < num_glyphs; last++)
+  {
+    DEBUG_MSG (SUBSET, nullptr, "loca entry empty offset %u", offset);
+    *dest++ = value;
+  }
+}
+
+static bool
+_add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca)
+{
+  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;
+
+  head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr);
+  head_prime->indexToLocFormat = use_short_loca ? 0 : 1;
+  if (plan->normalized_coords)
+  {
+    head_prime->xMin = plan->head_maxp_info.xMin;
+    head_prime->xMax = plan->head_maxp_info.xMax;
+    head_prime->yMin = plan->head_maxp_info.yMin;
+    head_prime->yMax = plan->head_maxp_info.yMax;
+
+    unsigned orig_flag = head_prime->flags;
+    if (plan->head_maxp_info.allXMinIsLsb)
+      orig_flag |= 1 << 1;
+    else
+      orig_flag &= ~(1 << 1);
+    head_prime->flags = orig_flag;
+  }
+  bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob);
+
+  hb_blob_destroy (head_prime_blob);
+  return success;
+}
+
+template<typename Iterator,
+        hb_requires (hb_is_source_of (Iterator, unsigned int))>
+static bool
+_add_loca_and_head (hb_subset_context_t *c,
+                   Iterator padded_offsets,
+                   bool use_short_loca)
+{
+  unsigned num_offsets = c->plan->num_output_glyphs () + 1;
+  unsigned entry_size = use_short_loca ? 2 : 4;
+
+  char *loca_prime_data = (char *) hb_malloc (entry_size * num_offsets);
+
+  if (unlikely (!loca_prime_data)) return false;
+
+  DEBUG_MSG (SUBSET, nullptr, "loca entry_size %u num_offsets %u size %u",
+            entry_size, num_offsets, entry_size * num_offsets);
+
+  if (use_short_loca)
+    _write_loca (padded_offsets, c->plan->new_to_old_gid_list, true, (HBUINT16 *) loca_prime_data, num_offsets);
+  else
+    _write_loca (padded_offsets, c->plan->new_to_old_gid_list, false, (HBUINT32 *) loca_prime_data, num_offsets);
+
+  hb_blob_t *loca_blob = hb_blob_create (loca_prime_data,
+                                        entry_size * num_offsets,
+                                        HB_MEMORY_MODE_WRITABLE,
+                                        loca_prime_data,
+                                        hb_free);
+
+  bool result = c->plan->add_table (HB_OT_TAG_loca, loca_blob)
+            && _add_head_and_set_loca_version (c->plan, use_short_loca);
+
+  hb_blob_destroy (loca_blob);
+  return result;
+}
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_GLYF_HELPERS_HH */
diff --git a/src/OT/glyf/glyf.hh b/src/OT/glyf/glyf.hh
new file mode 100644 (file)
index 0000000..6300cf4
--- /dev/null
@@ -0,0 +1,504 @@
+#ifndef OT_GLYF_GLYF_HH
+#define OT_GLYF_GLYF_HH
+
+
+#include "../../hb-open-type.hh"
+#include "../../hb-ot-head-table.hh"
+#include "../../hb-ot-hmtx-table.hh"
+#include "../../hb-ot-var-gvar-table.hh"
+#include "../../hb-draw.hh"
+#include "../../hb-paint.hh"
+
+#include "glyf-helpers.hh"
+#include "Glyph.hh"
+#include "SubsetGlyph.hh"
+#include "loca.hh"
+#include "path-builder.hh"
+
+
+namespace OT {
+
+
+/*
+ * glyf -- TrueType Glyph Data
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf
+ */
+#define HB_OT_TAG_glyf HB_TAG('g','l','y','f')
+
+struct glyf
+{
+  friend struct glyf_accelerator_t;
+
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf;
+
+  static bool has_valid_glyf_format(const hb_face_t* face)
+  {
+    const OT::head &head = *face->table.head;
+    return head.indexToLocFormat <= 1 && head.glyphDataFormat <= 1;
+  }
+
+  bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
+  {
+    TRACE_SANITIZE (this);
+    /* Runtime checks as eager sanitizing each glyph is costy */
+    return_trace (true);
+  }
+
+  /* requires source of SubsetGlyph complains the identifier isn't declared */
+  template <typename Iterator>
+  bool serialize (hb_serialize_context_t *c,
+                 Iterator it,
+                  bool use_short_loca,
+                 const hb_subset_plan_t *plan)
+  {
+    TRACE_SERIALIZE (this);
+
+    unsigned init_len = c->length ();
+    for (auto &_ : it)
+      if (unlikely (!_.serialize (c, use_short_loca, plan)))
+        return false;
+
+    /* As a special case when all glyph in the font are empty, add a zero byte
+     * to the table, so that OTS doesn’t reject it, and to make the table work
+     * on Windows as well.
+     * See https://github.com/khaledhosny/ots/issues/52 */
+    if (init_len == c->length ())
+    {
+      HBUINT8 empty_byte;
+      empty_byte = 0;
+      c->copy (empty_byte);
+    }
+    return_trace (true);
+  }
+
+  /* Byte region(s) per glyph to output
+     unpadded, hints removed if so requested
+     If we fail to process a glyph we produce an empty (0-length) glyph */
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+
+    if (!has_valid_glyf_format (c->plan->source)) {
+      // glyf format is unknown don't attempt to subset it.
+      DEBUG_MSG (SUBSET, nullptr,
+                 "unkown glyf format, dropping from subset.");
+      return_trace (false);
+    }
+
+    hb_font_t *font = nullptr;
+    if (c->plan->normalized_coords)
+    {
+      font = _create_font_for_instancing (c->plan);
+      if (unlikely (!font))
+       return_trace (false);
+    }
+
+    hb_vector_t<unsigned> padded_offsets;
+    if (unlikely (!padded_offsets.alloc (c->plan->new_to_old_gid_list.length, true)))
+      return_trace (false);
+
+    hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
+    if (!_populate_subset_glyphs (c->plan, font, glyphs))
+    {
+      hb_font_destroy (font);
+      return_trace (false);
+    }
+
+    if (font)
+      hb_font_destroy (font);
+
+    unsigned max_offset = 0;
+    for (auto &g : glyphs)
+    {
+      unsigned size = g.padded_size ();
+      padded_offsets.push (size);
+      max_offset += size;
+    }
+
+    bool use_short_loca = false;
+    if (likely (!c->plan->force_long_loca))
+      use_short_loca = max_offset < 0x1FFFF;
+
+    if (!use_short_loca)
+    {
+      padded_offsets.resize (0);
+      for (auto &g : glyphs)
+       padded_offsets.push (g.length ());
+    }
+
+    auto *glyf_prime = c->serializer->start_embed <glyf> ();
+    bool result = glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan);
+    if (c->plan->normalized_coords && !c->plan->pinned_at_default)
+      _free_compiled_subset_glyphs (glyphs);
+
+    if (unlikely (!c->serializer->check_success (glyf_impl::_add_loca_and_head (c,
+                                                padded_offsets.iter (),
+                                                use_short_loca))))
+      return_trace (false);
+
+    return result;
+  }
+
+  bool
+  _populate_subset_glyphs (const hb_subset_plan_t   *plan,
+                          hb_font_t                *font,
+                          hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const;
+
+  hb_font_t *
+  _create_font_for_instancing (const hb_subset_plan_t *plan) const;
+
+  void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> &glyphs) const
+  {
+    for (auto &g : glyphs)
+      g.free_compiled_bytes ();
+  }
+
+  protected:
+  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 (hb_face_t *face)
+  {
+    short_offset = false;
+    num_glyphs = 0;
+    loca_table = nullptr;
+    glyf_table = nullptr;
+#ifndef HB_NO_VAR
+    gvar = nullptr;
+#endif
+    hmtx = nullptr;
+#ifndef HB_NO_VERTICAL
+    vmtx = nullptr;
+#endif
+    const OT::head &head = *face->table.head;
+    if (!glyf::has_valid_glyf_format (face))
+      /* Unknown format.  Leave num_glyphs=0, that takes care of disabling us. */
+      return;
+    short_offset = 0 == head.indexToLocFormat;
+
+    loca_table = face->table.loca.get_blob (); // Needs no destruct!
+    glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
+#ifndef HB_NO_VAR
+    gvar = face->table.gvar;
+#endif
+    hmtx = face->table.hmtx;
+#ifndef HB_NO_VERTICAL
+    vmtx = face->table.vmtx;
+#endif
+
+    num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
+    num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ());
+  }
+  ~glyf_accelerator_t ()
+  {
+    glyf_table.destroy ();
+  }
+
+  bool has_data () const { return num_glyphs; }
+
+  protected:
+  template<typename T>
+  bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const
+  {
+    if (gid >= num_glyphs) return false;
+
+    /* Making this allocfree is not that easy
+       https://github.com/harfbuzz/harfbuzz/issues/2095
+       mostly because of gvar handling in VF fonts,
+       perhaps a separate path for non-VF fonts can be considered */
+    contour_point_vector_t all_points;
+
+    bool phantom_only = !consumer.is_consuming_contour_points ();
+    if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, nullptr, nullptr, true, true, phantom_only)))
+      return false;
+
+    unsigned count = all_points.length;
+    assert (count >= glyf_impl::PHANTOM_COUNT);
+    count -= glyf_impl::PHANTOM_COUNT;
+
+    if (consumer.is_consuming_contour_points ())
+    {
+      for (auto &point : all_points.as_array ().sub_array (0, count))
+       consumer.consume_point (point);
+      consumer.points_end ();
+    }
+
+    /* Where to write phantoms, nullptr if not requested */
+    contour_point_t *phantoms = consumer.get_phantoms_sink ();
+    if (phantoms)
+      for (unsigned i = 0; i < glyf_impl::PHANTOM_COUNT; ++i)
+       phantoms[i] = all_points.arrayZ[count + i];
+
+    return true;
+  }
+
+  public:
+
+#ifndef HB_NO_VAR
+  struct points_aggregator_t
+  {
+    hb_font_t *font;
+    hb_glyph_extents_t *extents;
+    contour_point_t *phantoms;
+    bool scaled;
+
+    struct contour_bounds_t
+    {
+      contour_bounds_t () { min_x = min_y = FLT_MAX; max_x = max_y = -FLT_MAX; }
+
+      void add (const contour_point_t &p)
+      {
+       min_x = hb_min (min_x, p.x);
+       min_y = hb_min (min_y, p.y);
+       max_x = hb_max (max_x, p.x);
+       max_y = hb_max (max_y, p.y);
+      }
+
+      bool empty () const { return (min_x >= max_x) || (min_y >= max_y); }
+
+      void get_extents (hb_font_t *font, hb_glyph_extents_t *extents, bool scaled)
+      {
+       if (unlikely (empty ()))
+       {
+         extents->width = 0;
+         extents->x_bearing = 0;
+         extents->height = 0;
+         extents->y_bearing = 0;
+         return;
+       }
+       {
+         extents->x_bearing = roundf (min_x);
+         extents->width = roundf (max_x - extents->x_bearing);
+         extents->y_bearing = roundf (max_y);
+         extents->height = roundf (min_y - extents->y_bearing);
+
+         if (scaled)
+           font->scale_glyph_extents (extents);
+       }
+      }
+
+      protected:
+      float min_x, min_y, max_x, max_y;
+    } bounds;
+
+    points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_, bool scaled_)
+    {
+      font = font_;
+      extents = extents_;
+      phantoms = phantoms_;
+      scaled = scaled_;
+      if (extents) bounds = contour_bounds_t ();
+    }
+
+    HB_ALWAYS_INLINE
+    void consume_point (const contour_point_t &point) { bounds.add (point); }
+    void points_end () { bounds.get_extents (font, extents, scaled); }
+
+    bool is_consuming_contour_points () { return extents; }
+    contour_point_t *get_phantoms_sink () { return phantoms; }
+  };
+
+  unsigned
+  get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
+  {
+    if (unlikely (gid >= num_glyphs)) return 0;
+
+    bool success = false;
+
+    contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
+    if (font->num_coords)
+      success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false));
+
+    if (unlikely (!success))
+      return
+#ifndef HB_NO_VERTICAL
+       is_vertical ? vmtx->get_advance_without_var_unscaled (gid) :
+#endif
+       hmtx->get_advance_without_var_unscaled (gid);
+
+    float result = is_vertical
+                ? phantoms[glyf_impl::PHANTOM_TOP].y - phantoms[glyf_impl::PHANTOM_BOTTOM].y
+                : phantoms[glyf_impl::PHANTOM_RIGHT].x - phantoms[glyf_impl::PHANTOM_LEFT].x;
+    return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2);
+  }
+
+  bool get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical, int *lsb) const
+  {
+    if (unlikely (gid >= num_glyphs)) return false;
+
+    hb_glyph_extents_t extents;
+
+    contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
+    if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms, false))))
+      return false;
+
+    *lsb = is_vertical
+        ? roundf (phantoms[glyf_impl::PHANTOM_TOP].y) - extents.y_bearing
+        : roundf (phantoms[glyf_impl::PHANTOM_LEFT].x);
+    return true;
+  }
+#endif
+
+  bool get_leading_bearing_without_var_unscaled (hb_codepoint_t gid, bool is_vertical, int *lsb) const
+  {
+    if (unlikely (gid >= num_glyphs)) return false;
+    if (is_vertical) return false; // TODO Humm, what to do here?
+
+    *lsb = glyph_for_gid (gid).get_header ()->xMin;
+    return true;
+  }
+
+  public:
+  bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
+  {
+    if (unlikely (gid >= num_glyphs)) return false;
+
+#ifndef HB_NO_VAR
+    if (font->num_coords)
+      return get_points (font, gid, points_aggregator_t (font, extents, nullptr, true));
+#endif
+    return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents);
+  }
+
+  bool paint_glyph (hb_font_t *font, hb_codepoint_t gid, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const
+  {
+    funcs->push_clip_glyph (data, gid, font);
+    funcs->color (data, true, foreground);
+    funcs->pop_clip (data);
+
+    return true;
+  }
+
+  const glyf_impl::Glyph
+  glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const
+  {
+    if (unlikely (gid >= num_glyphs)) return glyf_impl::Glyph ();
+
+    unsigned int start_offset, end_offset;
+
+    if (short_offset)
+    {
+      const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ;
+      start_offset = 2 * offsets[gid];
+      end_offset   = 2 * offsets[gid + 1];
+    }
+    else
+    {
+      const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ;
+      start_offset = offsets[gid];
+      end_offset   = offsets[gid + 1];
+    }
+
+    if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ()))
+      return glyf_impl::Glyph ();
+
+    glyf_impl::Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset,
+                            end_offset - start_offset), gid);
+    return needs_padding_removal ? glyf_impl::Glyph (glyph.trim_padding (), gid) : glyph;
+  }
+
+  bool
+  get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
+  { return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session)); }
+
+#ifndef HB_NO_VAR
+  const gvar_accelerator_t *gvar;
+#endif
+  const hmtx_accelerator_t *hmtx;
+#ifndef HB_NO_VERTICAL
+  const vmtx_accelerator_t *vmtx;
+#endif
+
+  private:
+  bool short_offset;
+  unsigned int num_glyphs;
+  hb_blob_ptr_t<loca> loca_table;
+  hb_blob_ptr_t<glyf> glyf_table;
+};
+
+
+inline bool
+glyf::_populate_subset_glyphs (const hb_subset_plan_t   *plan,
+                              hb_font_t *font,
+                              hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const
+{
+  OT::glyf_accelerator_t glyf (plan->source);
+  if (!glyphs.alloc (plan->new_to_old_gid_list.length, true)) return false;
+
+  for (const auto &pair : plan->new_to_old_gid_list)
+  {
+    hb_codepoint_t new_gid = pair.first;
+    hb_codepoint_t old_gid = pair.second;
+    glyf_impl::SubsetGlyph *p = glyphs.push ();
+    glyf_impl::SubsetGlyph& subset_glyph = *p;
+    subset_glyph.old_gid = old_gid;
+
+    if (unlikely (old_gid == 0 && new_gid == 0 &&
+                  !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) &&
+                  !plan->normalized_coords)
+      subset_glyph.source_glyph = glyf_impl::Glyph ();
+    else
+    {
+      /* If plan has an accelerator, the preprocessing step already trimmed glyphs.
+       * Don't trim them again! */
+      subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, !plan->accelerator);
+    }
+
+    if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+      subset_glyph.drop_hints_bytes ();
+    else
+      subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
+
+    if (font)
+    {
+      if (unlikely (!subset_glyph.compile_bytes_with_deltas (plan, font, glyf)))
+      {
+        // when pinned at default, only bounds are updated, thus no need to free
+        if (!plan->pinned_at_default)
+          _free_compiled_subset_glyphs (glyphs);
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+inline hb_font_t *
+glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const
+{
+  hb_font_t *font = hb_font_create (plan->source);
+  if (unlikely (font == hb_font_get_empty ())) return nullptr;
+
+  hb_vector_t<hb_variation_t> vars;
+  if (unlikely (!vars.alloc (plan->user_axes_location.get_population (), true)))
+  {
+    hb_font_destroy (font);
+    return nullptr;
+  }
+
+  for (auto _ : plan->user_axes_location)
+  {
+    hb_variation_t var;
+    var.tag = _.first;
+    var.value = _.second.middle;
+    vars.push (var);
+  }
+
+#ifndef HB_NO_VAR
+  hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location.get_population ());
+#endif
+  return font;
+}
+
+
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_GLYF_HH */
diff --git a/src/OT/glyf/loca.hh b/src/OT/glyf/loca.hh
new file mode 100644 (file)
index 0000000..4481cba
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef OT_GLYF_LOCA_HH
+#define OT_GLYF_LOCA_HH
+
+
+#include "../../hb-open-type.hh"
+
+
+namespace OT {
+
+
+/*
+ * loca -- Index to Location
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/loca
+ */
+#define HB_OT_TAG_loca HB_TAG('l','o','c','a')
+
+struct loca
+{
+  friend struct glyf;
+  friend struct glyf_accelerator_t;
+
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_loca;
+
+  bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (true);
+  }
+
+  protected:
+  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. */
+};
+
+
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_LOCA_HH */
diff --git a/src/OT/glyf/path-builder.hh b/src/OT/glyf/path-builder.hh
new file mode 100644 (file)
index 0000000..f550524
--- /dev/null
@@ -0,0 +1,190 @@
+#ifndef OT_GLYF_PATH_BUILDER_HH
+#define OT_GLYF_PATH_BUILDER_HH
+
+
+#include "../../hb.hh"
+
+
+namespace OT {
+namespace glyf_impl {
+
+
+struct path_builder_t
+{
+  hb_font_t *font;
+  hb_draw_session_t *draw_session;
+
+  struct optional_point_t
+  {
+    optional_point_t () {}
+    optional_point_t (float x_, float y_) : has_data (true), x (x_), y (y_) {}
+    operator bool () const { return has_data; }
+
+    bool has_data = false;
+    float x;
+    float y;
+
+    optional_point_t mid (optional_point_t p)
+    { return optional_point_t ((x + p.x) * 0.5f, (y + p.y) * 0.5f); }
+  } first_oncurve, first_offcurve, first_offcurve2, last_offcurve, last_offcurve2;
+
+  path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) :
+    font (font_), draw_session (&draw_session_) {}
+
+  /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287
+     See also:
+     * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html
+     * https://stackoverflow.com/a/20772557
+     *
+     * Cubic support added. */
+  HB_ALWAYS_INLINE
+  void consume_point (const contour_point_t &point)
+  {
+    bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE;
+#ifdef HB_NO_CUBIC_GLYF
+    bool is_cubic = false;
+#else
+    bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC);
+#endif
+    optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y));
+    if (unlikely (!first_oncurve))
+    {
+      if (is_on_curve)
+      {
+       first_oncurve = p;
+       draw_session->move_to (p.x, p.y);
+      }
+      else
+      {
+       if (is_cubic && !first_offcurve2)
+       {
+         first_offcurve2 = first_offcurve;
+         first_offcurve = p;
+       }
+       else if (first_offcurve)
+       {
+         optional_point_t mid = first_offcurve.mid (p);
+         first_oncurve = mid;
+         last_offcurve = p;
+         draw_session->move_to (mid.x, mid.y);
+       }
+       else
+         first_offcurve = p;
+      }
+    }
+    else
+    {
+      if (last_offcurve)
+      {
+       if (is_on_curve)
+       {
+         if (last_offcurve2)
+         {
+           draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
+                                   last_offcurve.x, last_offcurve.y,
+                                   p.x, p.y);
+           last_offcurve2 = optional_point_t ();
+         }
+         else
+           draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
+                                      p.x, p.y);
+         last_offcurve = optional_point_t ();
+       }
+       else
+       {
+         if (is_cubic && !last_offcurve2)
+         {
+           last_offcurve2 = last_offcurve;
+           last_offcurve = p;
+         }
+         else
+         {
+           optional_point_t mid = last_offcurve.mid (p);
+
+           if (is_cubic)
+           {
+             draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
+                                     last_offcurve.x, last_offcurve.y,
+                                     mid.x, mid.y);
+             last_offcurve2 = optional_point_t ();
+           }
+           else
+             draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
+                                        mid.x, mid.y);
+           last_offcurve = p;
+         }
+       }
+      }
+      else
+      {
+       if (is_on_curve)
+         draw_session->line_to (p.x, p.y);
+       else
+         last_offcurve = p;
+      }
+    }
+
+    if (unlikely (point.is_end_point))
+    {
+      if (first_offcurve && last_offcurve)
+      {
+       optional_point_t mid = last_offcurve.mid (first_offcurve2 ?
+                                                 first_offcurve2 :
+                                                 first_offcurve);
+       if (last_offcurve2)
+         draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
+                                 last_offcurve.x, last_offcurve.y,
+                                 mid.x, mid.y);
+       else
+         draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
+                                    mid.x, mid.y);
+       last_offcurve = optional_point_t ();
+      }
+      /* now check the rest */
+
+      if (first_offcurve && first_oncurve)
+      {
+        if (first_offcurve2)
+         draw_session->cubic_to (first_offcurve2.x, first_offcurve2.y,
+                                 first_offcurve.x, first_offcurve.y,
+                                 first_oncurve.x, first_oncurve.y);
+       else
+         draw_session->quadratic_to (first_offcurve.x, first_offcurve.y,
+                                    first_oncurve.x, first_oncurve.y);
+      }
+      else if (last_offcurve && first_oncurve)
+      {
+       if (last_offcurve2)
+         draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
+                                 last_offcurve.x, last_offcurve.y,
+                                 first_oncurve.x, first_oncurve.y);
+       else
+         draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
+                                    first_oncurve.x, first_oncurve.y);
+      }
+      else if (first_oncurve)
+       draw_session->line_to (first_oncurve.x, first_oncurve.y);
+      else if (first_offcurve)
+      {
+       float x = first_offcurve.x, y = first_offcurve.y;
+       draw_session->move_to (x, y);
+       draw_session->quadratic_to (x, y, x, y);
+      }
+
+      /* Getting ready for the next contour */
+      first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t ();
+      draw_session->close_path ();
+    }
+  }
+  void points_end () {}
+
+  bool is_consuming_contour_points () { return true; }
+  contour_point_t *get_phantoms_sink () { return nullptr; }
+};
+
+
+} /* namespace glyf_impl */
+} /* namespace OT */
+
+
+#endif /* OT_GLYF_PATH_BUILDER_HH */
diff --git a/src/OT/name/name.hh b/src/OT/name/name.hh
new file mode 100644 (file)
index 0000000..c8de101
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+ * Copyright © 2011,2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef OT_NAME_NAME_HH
+#define OT_NAME_NAME_HH
+
+#include "../../hb-open-type.hh"
+#include "../../hb-ot-name-language.hh"
+#include "../../hb-aat-layout.hh"
+#include "../../hb-utf.hh"
+
+
+namespace OT {
+
+template <typename in_utf_t, typename out_utf_t>
+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)--; /* Save 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;
+}
+
+#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
+{
+  hb_language_t language (hb_face_t *face) const
+  {
+#ifndef HB_NO_OT_NAME_LANGUAGE
+    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);
+
+#ifndef HB_NO_OT_NAME_LANGUAGE_AAT
+    if (p == 0)
+      return face->table.ltag->get_language (l);
+#endif
+
+#endif
+    return HB_LANGUAGE_INVALID;
+  }
+
+  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;
+  }
+
+  NameRecord* copy (hb_serialize_context_t *c, const void *base
+#ifdef HB_EXPERIMENTAL_API
+                    , const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides
+#endif
+                   ) const
+  {
+    TRACE_SERIALIZE (this);
+    HB_UNUSED auto snap = c->snapshot ();
+    auto *out = c->embed (this);
+    if (unlikely (!out)) return_trace (nullptr);
+#ifdef HB_EXPERIMENTAL_API
+    hb_ot_name_record_ids_t record_ids (platformID, encodingID, languageID, nameID);
+    hb_bytes_t* name_bytes;
+
+    if (name_table_overrides->has (record_ids, &name_bytes)) {
+      hb_bytes_t encoded_bytes = *name_bytes;
+      char *name_str_utf16_be = nullptr;
+
+      if (platformID != 1)
+      {
+        unsigned text_size = hb_ot_name_convert_utf<hb_utf8_t, hb_utf16_be_t> (*name_bytes, nullptr, nullptr);
+  
+        text_size++; // needs to consider NULL terminator for use in hb_ot_name_convert_utf()
+        unsigned byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size;
+        name_str_utf16_be = (char *) hb_calloc (byte_len, 1);
+        if (!name_str_utf16_be)
+        {
+          c->revert (snap);
+          return_trace (nullptr);
+        }
+        hb_ot_name_convert_utf<hb_utf8_t, hb_utf16_be_t> (*name_bytes, &text_size,
+                                                          (hb_utf16_be_t::codepoint_t *) name_str_utf16_be);
+  
+        unsigned encoded_byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size;
+        if (!encoded_byte_len || !c->check_assign (out->length, encoded_byte_len, HB_SERIALIZE_ERROR_INT_OVERFLOW)) {
+          c->revert (snap);
+          hb_free (name_str_utf16_be);
+          return_trace (nullptr);
+        }
+  
+        encoded_bytes = hb_bytes_t (name_str_utf16_be, encoded_byte_len);
+      }
+      else
+      {
+        // mac platform, copy the UTF-8 string(all ascii characters) as is
+        if (!c->check_assign (out->length, encoded_bytes.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) {
+          c->revert (snap);
+          return_trace (nullptr);
+        }
+      }
+
+      out->offset = 0;
+      c->push ();
+      encoded_bytes.copy (c);
+      c->add_link (out->offset, c->pop_pack (), hb_serialize_context_t::Tail, 0);
+      hb_free (name_str_utf16_be);
+    }
+    else
+#endif
+    {
+      out->offset.serialize_copy (c, offset, base, 0, hb_serialize_context_t::Tail, length);
+    }
+    return_trace (out);
+  }
+
+  bool isUnicode () const
+  {
+    unsigned int p = platformID;
+    unsigned int e = encodingID;
+
+    return (p == 0 ||
+           (p == 3 && (e == 0 || e == 1 || e == 10)));
+  }
+
+  static int cmp (const void *pa, const void *pb)
+  {
+    const NameRecord *a = (const NameRecord *)pa;
+    const NameRecord *b = (const NameRecord *)pb;
+
+    if (a->platformID != b->platformID)
+      return a->platformID - b->platformID;
+
+    if (a->encodingID != b->encodingID)
+      return a->encodingID - b->encodingID;
+
+    if (a->languageID != b->languageID)
+      return a->languageID - b->languageID;
+
+    if (a->nameID != b->nameID)
+      return a->nameID - b->nameID;
+
+    if (a->length != b->length)
+      return a->length - b->length;
+
+    return 0;
+  }
+
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && offset.sanitize (c, base, length));
+  }
+
+  HBUINT16     platformID;     /* Platform ID. */
+  HBUINT16     encodingID;     /* Platform-specific encoding ID. */
+  HBUINT16     languageID;     /* Language ID. */
+  HBUINT16     nameID;         /* Name ID. */
+  HBUINT16     length;         /* String length (in bytes). */
+  NNOffset16To<UnsizedArrayOf<HBUINT8>>
+               offset;         /* String offset from start of storage area (in bytes). */
+  public:
+  DEFINE_SIZE_STATIC (12);
+};
+
+static int
+_hb_ot_name_entry_cmp_key (const void *pa, const void *pb, bool exact)
+{
+  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;
+
+  if (a->language == b->language) return 0;
+  if (!a->language) return -1;
+  if (!b->language) return +1;
+
+  const char *astr = hb_language_to_string (a->language);
+  const char *bstr = hb_language_to_string (b->language);
+
+  signed c = strcmp (astr, bstr);
+
+  // 'a' is the user request, and 'b' is string in the font.
+  // If eg. user asks for "en-us" and font has "en", approve.
+  if (!exact && c &&
+      hb_language_matches (b->language, a->language))
+    return 0;
+
+  return c;
+}
+
+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, true);
+  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;
+
+  if (a->entry_index != b->entry_index)
+    return a->entry_index - b->entry_index;
+
+  return 0;
+}
+
+struct name
+{
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_name;
+
+  unsigned int get_size () const
+  { return min_size + count * nameRecordZ.item_size; }
+
+  template <typename Iterator,
+           hb_requires (hb_is_source_of (Iterator, const NameRecord &))>
+  bool serialize (hb_serialize_context_t *c,
+                 Iterator it,
+                 const void *src_string_pool
+#ifdef HB_EXPERIMENTAL_API
+                  , const hb_vector_t<hb_ot_name_record_ids_t>& insert_name_records
+                 , const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides
+#endif
+                 )
+  {
+    TRACE_SERIALIZE (this);
+
+    if (unlikely (!c->extend_min ((*this))))  return_trace (false);
+
+    unsigned total_count = it.len ()
+#ifdef HB_EXPERIMENTAL_API
+        + insert_name_records.length
+#endif
+        ;
+    this->format = 0;
+    if (!c->check_assign (this->count, total_count, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+      return false;
+
+    NameRecord *name_records = (NameRecord *) hb_calloc (total_count, NameRecord::static_size);
+    if (unlikely (!name_records)) return_trace (false);
+
+    hb_array_t<NameRecord> records (name_records, total_count);
+
+    for (const NameRecord& record : it)
+    {
+      hb_memcpy (name_records, &record, NameRecord::static_size);
+      name_records++;
+    }
+
+#ifdef HB_EXPERIMENTAL_API
+    for (unsigned i = 0; i < insert_name_records.length; i++)
+    {
+      const hb_ot_name_record_ids_t& ids = insert_name_records[i];
+      NameRecord record;
+      record.platformID = ids.platform_id;
+      record.encodingID = ids.encoding_id;
+      record.languageID = ids.language_id;
+      record.nameID = ids.name_id;
+      record.length = 0; // handled in NameRecord copy()
+      record.offset = 0;
+      hb_memcpy (name_records, &record, NameRecord::static_size);
+      name_records++;
+    }
+#endif
+
+    records.qsort ();
+
+    c->copy_all (records,
+                src_string_pool
+#ifdef HB_EXPERIMENTAL_API
+                , name_table_overrides
+#endif
+                );
+    hb_free (records.arrayZ);
+
+
+    if (unlikely (c->ran_out_of_room ())) return_trace (false);
+
+    this->stringOffset = c->length ();
+
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    auto *name_prime = c->serializer->start_embed<name> ();
+
+#ifdef HB_EXPERIMENTAL_API
+    const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides =
+        &c->plan->name_table_overrides;
+#endif
+    
+    auto it =
+    + nameRecordZ.as_array (count)
+    | hb_filter (c->plan->name_ids, &NameRecord::nameID)
+    | hb_filter (c->plan->name_languages, &NameRecord::languageID)
+    | hb_filter ([&] (const NameRecord& namerecord) {
+      return
+          (c->plan->flags & HB_SUBSET_FLAGS_NAME_LEGACY)
+          || namerecord.isUnicode ();
+    })
+#ifdef HB_EXPERIMENTAL_API
+    | hb_filter ([&] (const NameRecord& namerecord) {
+      if (name_table_overrides->is_empty ())
+        return true;
+      hb_ot_name_record_ids_t rec_ids (namerecord.platformID,
+                                       namerecord.encodingID,
+                                       namerecord.languageID,
+                                       namerecord.nameID);
+
+      hb_bytes_t *p;
+      if (name_table_overrides->has (rec_ids, &p) &&
+          (*p).length == 0)
+        return false;
+      return true;
+    })
+#endif
+    ;
+
+#ifdef HB_EXPERIMENTAL_API
+    hb_hashmap_t<hb_ot_name_record_ids_t, unsigned> retained_name_record_ids;
+    for (const NameRecord& rec : it)
+    {
+      hb_ot_name_record_ids_t rec_ids (rec.platformID,
+                                       rec.encodingID,
+                                       rec.languageID,
+                                       rec.nameID);
+      retained_name_record_ids.set (rec_ids, 1);
+    }
+
+    hb_vector_t<hb_ot_name_record_ids_t> insert_name_records;
+    if (!name_table_overrides->is_empty ())
+    {
+      if (unlikely (!insert_name_records.alloc (name_table_overrides->get_population (), true)))
+        return false;
+      for (const auto& record_ids : name_table_overrides->keys ())
+      {
+        if (name_table_overrides->get (record_ids).length == 0)
+          continue;
+        if (retained_name_record_ids.has (record_ids))
+          continue;
+        insert_name_records.push (record_ids);
+      }
+    }
+#endif
+
+    return name_prime->serialize (c->serializer, it,
+                                 std::addressof (this + stringOffset)
+#ifdef HB_EXPERIMENTAL_API
+                                 , insert_name_records
+                                 , name_table_overrides
+#endif
+                                 );
+  }
+
+  bool sanitize_records (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    const void *string_pool = (this+stringOffset).arrayZ;
+    return_trace (nameRecordZ.sanitize (c, count, string_pool));
+  }
+
+  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 (nameRecordZ.arrayZ, count) &&
+                 c->check_range (this, stringOffset) &&
+                 sanitize_records (c));
+  }
+
+  struct accelerator_t
+  {
+    accelerator_t (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.alloc (all_names.length, true);
+
+      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);
+    }
+    ~accelerator_t ()
+    {
+      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 = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names,
+                                                   this->names.length,
+                                                   sizeof (hb_ot_name_entry_t),
+                                                   _hb_ot_name_entry_cmp_key,
+                                                   true);
+
+      if (!entry)
+      {
+       entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names,
+                           this->names.length,
+                           sizeof (hb_ot_name_entry_t),
+                           _hb_ot_name_entry_cmp_key,
+                           false);
+      }
+
+      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;
+  };
+
+  public:
+  /* We only implement format 0 for now. */
+  HBUINT16     format;         /* Format selector (=0/1). */
+  HBUINT16     count;          /* Number of name records. */
+  NNOffset16To<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, nameRecordZ);
+};
+
+#undef entry_index
+#undef entry_score
+
+struct name_accelerator_t : name::accelerator_t {
+  name_accelerator_t (hb_face_t *face) : name::accelerator_t (face) {}
+};
+
+} /* namespace OT */
+
+
+#endif /* OT_NAME_NAME_HH */
index b7532a7..fe18eda 100755 (executable)
@@ -2,13 +2,23 @@
 
 import sys, os
 
-os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
+srcdir = os.getenv ('srcdir', os.path.dirname (__file__))
+base_srcdir = os.getenv ('base_srcdir', srcdir)
+
+os.chdir (srcdir)
+
+def removeprefix(s):
+       abs_path = os.path.join(base_srcdir, s)
+       return os.path.relpath(abs_path, srcdir)
+
 
 HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \
        [x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')]
-HBSOURCES = [os.path.basename (x) for x in os.getenv ('HBSOURCES', '').split ()] or \
-       [x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))]
-
+HBSOURCES = [
+    removeprefix(x) for x in os.getenv ('HBSOURCES', '').split ()
+] or [
+    x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))
+]
 stat = 0
 
 for x in HBHEADERS:
index 0ad42cd..35ae6be 100755 (executable)
@@ -2,21 +2,33 @@
 
 import sys, os, re
 
-os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
+srcdir = os.getenv ('srcdir', os.path.dirname (__file__))
+base_srcdir = os.getenv ('base_srcdir', srcdir)
+
+os.chdir (srcdir)
+
+def removeprefix(s):
+       abs_path = os.path.join(base_srcdir, s)
+       return os.path.relpath(abs_path, srcdir)
+
 
 HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \
        [x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')]
-HBSOURCES = [os.path.basename (x) for x in os.getenv ('HBSOURCES', '').split ()] or \
-       [x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))]
+HBSOURCES = [
+    removeprefix(x) for x in os.getenv ('HBSOURCES', '').split ()
+] or [
+    x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))
+]
+
 
 stat = 0
 
 for x in HBHEADERS + HBSOURCES:
        if not x.endswith ('h') or x == 'hb-gobject-structs.h': continue
-       tag = x.upper ().replace ('.', '_').replace ('-', '_')
+       tag = x.upper ().replace ('.', '_').replace ('-', '_').replace(os.path.sep, '_').replace('/', '_')
        with open (x, 'r', encoding='utf-8') as f: content = f.read ()
        if len (re.findall (tag + r'\b', content)) != 3:
-               print ('Ouch, header file %s does not have correct preprocessor guards' % x)
+               print ('Ouch, header file %s does not have correct preprocessor guards. Expected: %s' % (x, tag))
                stat = 1
 
 sys.exit (stat)
index 88eaa2e..fc95874 100755 (executable)
@@ -2,12 +2,24 @@
 
 import sys, os, re
 
-os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
+srcdir = os.getenv ('srcdir', os.path.dirname (__file__))
+base_srcdir = os.getenv ('base_srcdir', srcdir)
+
+os.chdir (srcdir)
+
+def removeprefix(s):
+       abs_path = os.path.join(base_srcdir, s)
+       return os.path.relpath(abs_path, srcdir)
 
 HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \
        [x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')]
-HBSOURCES = [os.path.basename (x) for x in os.getenv ('HBSOURCES', '').split ()] or \
-       [x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))]
+
+HBSOURCES = [
+    removeprefix(x) for x in os.getenv ('HBSOURCES', '').split ()
+] or [
+    x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))
+]
+
 
 stat = 0
 
@@ -25,7 +37,7 @@ for x in HBSOURCES:
        with open (x, 'r', encoding='utf-8') as f: content = f.read ()
        includes = re.findall (r'#.*include.*', content)
        if includes:
-               if not len (re.findall (r'"hb.*\.hh"', includes[0])):
+               if not len (re.findall (r'".*\.hh"', includes[0])):
                        print ('failure on %s' % x)
                        stat = 1
 
index 85b7265..e70d5f8 100755 (executable)
@@ -19,7 +19,7 @@ stat = 0
 tested = False
 
 # harfbuzz-icu links to libstdc++ because icu does.
-for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-gobject']:
+for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-gobject', 'harfbuzz-cairo']:
        for suffix in ['so', 'dylib']:
                so = os.path.join (libs, 'lib%s.%s' % (soname, suffix))
                if not os.path.exists (so): continue
index edd5874..c6e2db1 100755 (executable)
@@ -14,7 +14,7 @@ if sys.version_info < (3, 5):
        print ('check-static-inits.py: needs python 3.5 for recursive support in glob')
        sys.exit (77)
 
-OBJS = glob.glob (os.path.join (builddir, libs, '**', 'hb*.o'), recursive=True)
+OBJS = glob.glob (os.path.join (builddir, libs, '**', '*hb*.o'), recursive=True)
 if not OBJS:
        print ('check-static-inits.py: object files not found; skipping test')
        sys.exit (77)
index 385959b..91bf8b0 100755 (executable)
@@ -17,12 +17,12 @@ if not nm:
        print ('check-symbols.py: \'nm\' not found; skipping test')
        sys.exit (77)
 
-cxxflit = shutil.which ('c++filt')
+cxxfilt = shutil.which ('c++filt')
 
 tested = False
 stat = 0
 
-for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject']:
+for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject', 'harfbuzz-cairo']:
        for suffix in ['so', 'dylib']:
                so = os.path.join (builddir, libs, 'lib%s.%s' % (soname, suffix))
                if not os.path.exists (so): continue
@@ -31,13 +31,13 @@ for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject'
                symprefix = '_' if suffix == 'dylib' else ''
 
                EXPORTED_SYMBOLS = [s.split ()[2]
-                                   for s in re.findall (r'^.+ [BCDGIRST] .+$', subprocess.check_output (nm.split() + [so]).decode ('utf-8'), re.MULTILINE)
+                                   for s in re.findall (r'^.+ [BCDGIRSTu] .+$', subprocess.check_output (nm.split() + [so]).decode ('utf-8'), re.MULTILINE)
                                    if not re.match (r'.* %s(%s)\b' % (symprefix, IGNORED_SYMBOLS), s)]
 
-               # run again c++flit also if is available
-               if cxxflit:
+               # run again c++filt also if is available
+               if cxxfilt:
                        EXPORTED_SYMBOLS = subprocess.check_output (
-                               [cxxflit], input='\n'.join (EXPORTED_SYMBOLS).encode ()
+                               [cxxfilt], input='\n'.join (EXPORTED_SYMBOLS).encode ()
                        ).decode ('utf-8').splitlines ()
 
                prefix = (symprefix + os.path.basename (so)).replace ('libharfbuzz', 'hb').replace ('-', '_').split ('.')[0]
old mode 100644 (file)
new mode 100755 (executable)
index 8162a4a..7ec7425 100755 (executable)
@@ -94,13 +94,13 @@ for h in headers:
                print (" * %s" % (l.strip ()))
 print (" */")
 print ()
-print ("#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH")
-print ("#define HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH")
+print ("#ifndef HB_OT_SHAPER_ARABIC_JOINING_LIST_HH")
+print ("#define HB_OT_SHAPER_ARABIC_JOINING_LIST_HH")
 print ()
 
 print_has_arabic_joining (read (files[1]), read_joining_uu (files[0]))
 
 print ()
-print ("#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH */")
+print ("#endif /* HB_OT_SHAPER_ARABIC_JOINING_LIST_HH */")
 print ()
 print ("/* == End of generated function == */")
index 621d5b6..8278d7d 100755 (executable)
@@ -153,12 +153,29 @@ def print_joining_table(f):
                print ("#undef %s" % (short))
        print ()
 
+LIGATURES = (
+       0xF2EE, 0xFC08, 0xFC0E, 0xFC12, 0xFC32, 0xFC3F, 0xFC40, 0xFC41, 0xFC42,
+       0xFC44, 0xFC4E, 0xFC5E, 0xFC60, 0xFC61, 0xFC62, 0xFC6A, 0xFC6D, 0xFC6F,
+       0xFC70, 0xFC73, 0xFC75, 0xFC86, 0xFC8F, 0xFC91, 0xFC94, 0xFC9C, 0xFC9D,
+       0xFC9E, 0xFC9F, 0xFCA1, 0xFCA2, 0xFCA3, 0xFCA4, 0xFCA8, 0xFCAA, 0xFCAC,
+       0xFCB0, 0xFCC9, 0xFCCA, 0xFCCB, 0xFCCC, 0xFCCD, 0xFCCE, 0xFCCF, 0xFCD0,
+       0xFCD1, 0xFCD2, 0xFCD3, 0xFCD5, 0xFCDA, 0xFCDB, 0xFCDC, 0xFCDD, 0xFD30,
+       0xFD88, 0xFEF5, 0xFEF6, 0xFEF7, 0xFEF8, 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC,
+       0xF201, 0xF211, 0xF2EE,
+)
+
 def print_shaping_table(f):
 
        shapes = {}
        ligatures = {}
        names = {}
-       for line in f:
+       lines = f.readlines()
+       lines += [
+               "F201;PUA ARABIC LIGATURE LELLAH ISOLATED FORM;Lo;0;AL;<isolated> 0644 0644 0647;;;;N;;;;;",
+               "F211;PUA ARABIC LIGATURE LAM WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0644 0645 062C;;;;N;;;;;",
+               "F2EE;PUA ARABIC LIGATURE SHADDA WITH FATHATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064B 0651;;;;N;;;;;",
+       ]
+       for line in lines:
 
                fields = [x.strip () for x in line.split (';')]
                if fields[5][0:1] != '<':
@@ -166,14 +183,19 @@ def print_shaping_table(f):
 
                items = fields[5].split (' ')
                shape, items = items[0][1:-1], tuple (int (x, 16) for x in items[1:])
+               c = int (fields[0], 16)
 
                if not shape in ['initial', 'medial', 'isolated', 'final']:
                        continue
 
-               c = int (fields[0], 16)
                if len (items) != 1:
-                       # We only care about lam-alef ligatures
-                       if len (items) != 2 or items[0] != 0x0644 or items[1] not in [0x0622, 0x0623, 0x0625, 0x0627]:
+                       # Mark ligatures start with space and are in visual order, so we
+                       # remove the space and reverse the items.
+                       if items[0] == 0x0020:
+                               items = items[:0:-1]
+                               shape = None
+                       # We only care about a subset of ligatures
+                       if c not in LIGATURES:
                                continue
 
                        # Save ligature
@@ -209,34 +231,99 @@ def print_shaping_table(f):
        print ("#define SHAPING_TABLE_LAST      0x%04Xu" % max_u)
        print ()
 
-       ligas = {}
-       for pair in ligatures.keys ():
-               for shape in ligatures[pair]:
-                       c = ligatures[pair][shape]
-                       if shape == 'isolated':
-                               liga = (shapes[pair[0]]['initial'], shapes[pair[1]]['final'])
-                       elif shape == 'final':
-                               liga = (shapes[pair[0]]['medial'], shapes[pair[1]]['final'])
+       ligas_2 = {}
+       ligas_3 = {}
+       ligas_mark_2 = {}
+       for key in ligatures.keys ():
+               for shape in ligatures[key]:
+                       c = ligatures[key][shape]
+                       if len(key) == 3:
+                               if shape == 'isolated':
+                                       liga = (shapes[key[0]]['initial'], shapes[key[1]]['medial'], shapes[key[2]]['final'])
+                               elif shape == 'final':
+                                       liga = (shapes[key[0]]['medial'], shapes[key[1]]['medial'], shapes[key[2]]['final'])
+                               elif shape == 'initial':
+                                       liga = (shapes[key[0]]['initial'], shapes[key[1]]['medial'], shapes[key[2]]['medial'])
+                               else:
+                                       raise Exception ("Unexpected shape", shape)
+                               if liga[0] not in ligas_3:
+                                       ligas_3[liga[0]] = []
+                               ligas_3[liga[0]].append ((liga[1], liga[2], c))
+                       elif len(key) == 2:
+                               if shape is None:
+                                       liga = key
+                                       if liga[0] not in ligas_mark_2:
+                                               ligas_mark_2[liga[0]] = []
+                                       ligas_mark_2[liga[0]].append ((liga[1], c))
+                                       continue
+                               elif shape == 'isolated':
+                                       liga = (shapes[key[0]]['initial'], shapes[key[1]]['final'])
+                               elif shape == 'final':
+                                       liga = (shapes[key[0]]['medial'], shapes[key[1]]['final'])
+                               elif shape == 'initial':
+                                       liga = (shapes[key[0]]['initial'], shapes[key[1]]['medial'])
+                               else:
+                                       raise Exception ("Unexpected shape", shape)
+                               if liga[0] not in ligas_2:
+                                       ligas_2[liga[0]] = []
+                               ligas_2[liga[0]].append ((liga[1], c))
                        else:
-                               raise Exception ("Unexpected shape", shape)
-                       if liga[0] not in ligas:
-                               ligas[liga[0]] = []
-                       ligas[liga[0]].append ((liga[1], c))
-       max_i = max (len (ligas[l]) for l in ligas)
+                               raise Exception ("Unexpected number of ligature components", key)
+       max_i = max (len (ligas_2[l]) for l in ligas_2)
        print ()
        print ("static const struct ligature_set_t {")
        print (" uint16_t first;")
        print (" struct ligature_pairs_t {")
-       print ("   uint16_t second;")
+       print ("   uint16_t components[1];")
        print ("   uint16_t ligature;")
        print (" } ligatures[%d];" % max_i)
        print ("} ligature_table[] =")
        print ("{")
-       for first in sorted (ligas.keys ()):
+       for first in sorted (ligas_2.keys ()):
+
+               print ("  { 0x%04Xu, {" % (first))
+               for liga in ligas_2[first]:
+                       print ("    { {0x%04Xu}, 0x%04Xu }, /* %s */" % (liga[0], liga[1], names[liga[1]]))
+               print ("  }},")
+
+       print ("};")
+       print ()
+
+       max_i = max (len (ligas_mark_2[l]) for l in ligas_mark_2)
+       print ()
+       print ("static const struct ligature_mark_set_t {")
+       print (" uint16_t first;")
+       print (" struct ligature_pairs_t {")
+       print ("   uint16_t components[1];")
+       print ("   uint16_t ligature;")
+       print (" } ligatures[%d];" % max_i)
+       print ("} ligature_mark_table[] =")
+       print ("{")
+       for first in sorted (ligas_mark_2.keys ()):
+
+               print ("  { 0x%04Xu, {" % (first))
+               for liga in ligas_mark_2[first]:
+                       print ("    { {0x%04Xu}, 0x%04Xu }, /* %s */" % (liga[0], liga[1], names[liga[1]]))
+               print ("  }},")
+
+       print ("};")
+       print ()
+
+       max_i = max (len (ligas_3[l]) for l in ligas_3)
+       print ()
+       print ("static const struct ligature_3_set_t {")
+       print (" uint16_t first;")
+       print (" struct ligature_triplets_t {")
+       print ("   uint16_t components[2];")
+       print ("   uint16_t ligature;")
+       print (" } ligatures[%d];" % max_i)
+       print ("} ligature_3_table[] =")
+       print ("{")
+       for first in sorted (ligas_3.keys ()):
 
                print ("  { 0x%04Xu, {" % (first))
-               for liga in ligas[first]:
-                       print ("    { 0x%04Xu, 0x%04Xu }, /* %s */" % (liga[0], liga[1], names[liga[1]]))
+               for liga in ligas_3[first]:
+                       print ("    { {0x%04Xu, 0x%04Xu}, 0x%04Xu}, /* %s */" % (liga[0], liga[1], liga[2], names[liga[2]]))
                print ("  }},")
 
        print ("};")
@@ -257,8 +344,8 @@ for h in headers:
                print (" * %s" % (l.strip()))
 print (" */")
 print ()
-print ("#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH")
-print ("#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH")
+print ("#ifndef HB_OT_SHAPER_ARABIC_TABLE_HH")
+print ("#define HB_OT_SHAPER_ARABIC_TABLE_HH")
 print ()
 
 read_blocks (files[2])
@@ -266,6 +353,6 @@ print_joining_table (files[0])
 print_shaping_table (files[1])
 
 print ()
-print ("#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH */")
+print ("#endif /* HB_OT_SHAPER_ARABIC_TABLE_HH */")
 print ()
 print ("/* == End of generated table == */")
index b46d346..c34976a 100755 (executable)
@@ -19,23 +19,11 @@ symbols = sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re
 if '--experimental-api' not in sys.argv:
        # Move these to harfbuzz-sections.txt when got stable
        experimental_symbols = \
-"""hb_font_draw_glyph
-hb_draw_funcs_t
-hb_draw_close_path_func_t
-hb_draw_cubic_to_func_t
-hb_draw_line_to_func_t
-hb_draw_move_to_func_t
-hb_draw_quadratic_to_func_t
-hb_draw_funcs_create
-hb_draw_funcs_destroy
-hb_draw_funcs_is_immutable
-hb_draw_funcs_make_immutable
-hb_draw_funcs_reference
-hb_draw_funcs_set_close_path_func
-hb_draw_funcs_set_cubic_to_func
-hb_draw_funcs_set_line_to_func
-hb_draw_funcs_set_move_to_func
-hb_draw_funcs_set_quadratic_to_func""".splitlines ()
+"""hb_shape_justify
+hb_subset_repack_or_fail
+hb_subset_input_override_name_table
+hb_subset_input_set_axis_range
+""".splitlines ()
        symbols = [x for x in symbols if x not in experimental_symbols]
 symbols = "\n".join (symbols)
 
index 0ee8fec..42a3fb8 100755 (executable)
@@ -65,7 +65,7 @@ for typ, s in ranges.items():
                for i in range(start, end + 1):
                        arr[i] = 1
 
-       sol = packTab.pack_table(arr, 0, compression=3)
+       sol = packTab.pack_table(arr, 0, compression=9)
        code = packTab.Code('_hb_emoji')
        sol.genCode(code, 'is_'+typ)
        code.print_c(linkage='static inline')
@@ -91,8 +91,8 @@ with open(sys.argv[2]) as f:
             continue
         sequences.append(line)
 
-with open("../test/shaping/data/in-house/tests/emoji-clusters.tests", "w") as f:
+with open("../test/shape/data/in-house/tests/emoji-clusters.tests", "w") as f:
     for sequence in sequences:
-        f.write("../fonts/AdobeBlank2.ttf:--no-glyph-names --no-positions --font-funcs=ot")
-        f.write(":" + ",".join(sequence))
-        f.write(":[" + "|".join("1=0" for c in sequence) + "]\n")
+        f.write("../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot")
+        f.write(";" + ",".join(sequence))
+        f.write(";[" + "|".join("1=0" for c in sequence) + "]\n")
index b25bcc7..2273840 100755 (executable)
@@ -9,10 +9,16 @@ if len (sys.argv) < 3:
 
 OUTPUT = sys.argv[1]
 CURRENT_SOURCE_DIR = sys.argv[2]
-sources = sys.argv[3:]
+
+# make sure input files are unique
+sources = sorted(set(sys.argv[3:]))
 
 with open (OUTPUT, "wb") as f:
-       f.write ("".join ('#include "{}"\n'.format (os.path.basename (x)) for x in sources if x.endswith (".cc")).encode ())
+       f.write ("".join ('#include "{}"\n'.format (os.path.relpath (os.path.abspath (x), CURRENT_SOURCE_DIR)) for x in sources if x.endswith (".cc")).encode ())
 
-# copy it also to src/
-shutil.copyfile (OUTPUT, os.path.join (CURRENT_SOURCE_DIR, os.path.basename (OUTPUT)))
+# copy it also to the source tree, but only if it has changed
+baseline_filename = os.path.join (CURRENT_SOURCE_DIR, os.path.basename (OUTPUT))
+with open(baseline_filename, "rb") as baseline:
+       with open(OUTPUT, "rb") as generated:
+               if baseline.read() != generated.read():
+                       shutil.copyfile (OUTPUT, baseline_filename)
index 4fac0a0..06018ed 100755 (executable)
@@ -32,5 +32,9 @@ with open (INPUT, "r", encoding='utf-8') as template:
                        .replace ("@HB_VERSION@", version)
                        .encode ())
 
-# copy it also to src/
-shutil.copyfile (OUTPUT, os.path.join (CURRENT_SOURCE_DIR, os.path.basename (OUTPUT)))
+# copy it also to the source tree, but only if it has changed
+baseline_filename = os.path.join (CURRENT_SOURCE_DIR, os.path.basename (OUTPUT))
+with open(baseline_filename, "rb") as baseline:
+       with open(OUTPUT, "rb") as generated:
+               if baseline.read() != generated.read():
+                       shutil.copyfile (OUTPUT, baseline_filename)
index 367e55e..4ef9702 100755 (executable)
@@ -26,7 +26,6 @@ ALLOWED_BLOCKS = [
        'Telugu',
        'Kannada',
        'Malayalam',
-       'Sinhala',
        'Myanmar',
        'Khmer',
        'Vedic Extensions',
@@ -41,8 +40,7 @@ files = [open (x, encoding='utf-8') for x in sys.argv[1:]]
 
 headers = [[f.readline () for i in range (2)] for f in files]
 
-data = [{} for _ in files]
-values = [{} for _ in files]
+unicode_data = [{} for _ in files]
 for i, f in enumerate (files):
        for line in f:
 
@@ -64,15 +62,12 @@ for i, f in enumerate (files):
                t = fields[1]
 
                for u in range (start, end + 1):
-                       data[i][u] = t
-               values[i][t] = values[i].get (t, 0) + end - start + 1
+                       unicode_data[i][u] = t
 
 # Merge data into one dict:
 defaults = ('Other', 'Not_Applicable', 'No_Block')
-for i,v in enumerate (defaults):
-       values[i][v] = values[i].get (v, 0) + 1
 combined = {}
-for i,d in enumerate (data):
+for i,d in enumerate (unicode_data):
        for u,v in d.items ():
                if i == 2 and not u in combined:
                        continue
@@ -80,14 +75,415 @@ for i,d in enumerate (data):
                        combined[u] = list (defaults)
                combined[u][i] = v
 combined = {k:v for k,v in combined.items() if k in ALLOWED_SINGLES or v[2] in ALLOWED_BLOCKS}
-data = combined
-del combined
+
+
+# Convert categories & positions types
+
+categories = {
+  'indic' : [
+    'X',
+    'C',
+    'V',
+    'N',
+    'H',
+    'ZWNJ',
+    'ZWJ',
+    'M',
+    'SM',
+    'A',
+    'VD',
+    'PLACEHOLDER',
+    'DOTTEDCIRCLE',
+    'RS',
+    'MPst',
+    'Repha',
+    'Ra',
+    'CM',
+    'Symbol',
+    'CS',
+  ],
+  'khmer' : [
+    'VAbv',
+    'VBlw',
+    'VPre',
+    'VPst',
+
+    'Robatic',
+    'Xgroup',
+    'Ygroup',
+  ],
+  'myanmar' : [
+    'VAbv',
+    'VBlw',
+    'VPre',
+    'VPst',
+
+    'IV',
+    'As',
+    'DB',
+    'GB',
+    'MH',
+    'MR',
+    'MW',
+    'MY',
+    'PT',
+    'VS',
+    'ML',
+  ],
+}
+
+category_map = {
+  'Other'                      : 'X',
+  'Avagraha'                   : 'Symbol',
+  'Bindu'                      : 'SM',
+  'Brahmi_Joining_Number'      : 'PLACEHOLDER', # Don't care.
+  'Cantillation_Mark'          : 'A',
+  'Consonant'                  : 'C',
+  'Consonant_Dead'             : 'C',
+  'Consonant_Final'            : 'CM',
+  'Consonant_Head_Letter'      : 'C',
+  'Consonant_Initial_Postfixed'        : 'C', # TODO
+  'Consonant_Killer'           : 'M', # U+17CD only.
+  'Consonant_Medial'           : 'CM',
+  'Consonant_Placeholder'      : 'PLACEHOLDER',
+  'Consonant_Preceding_Repha'  : 'Repha',
+  'Consonant_Prefixed'         : 'X', # Don't care.
+  'Consonant_Subjoined'                : 'CM',
+  'Consonant_Succeeding_Repha' : 'CM',
+  'Consonant_With_Stacker'     : 'CS',
+  'Gemination_Mark'            : 'SM', # https://github.com/harfbuzz/harfbuzz/issues/552
+  'Invisible_Stacker'          : 'H',
+  'Joiner'                     : 'ZWJ',
+  'Modifying_Letter'           : 'X',
+  'Non_Joiner'                 : 'ZWNJ',
+  'Nukta'                      : 'N',
+  'Number'                     : 'PLACEHOLDER',
+  'Number_Joiner'              : 'PLACEHOLDER', # Don't care.
+  'Pure_Killer'                        : 'M', # Is like a vowel matra.
+  'Register_Shifter'           : 'RS',
+  'Syllable_Modifier'          : 'SM',
+  'Tone_Letter'                        : 'X',
+  'Tone_Mark'                  : 'N',
+  'Virama'                     : 'H',
+  'Visarga'                    : 'SM',
+  'Vowel'                      : 'V',
+  'Vowel_Dependent'            : 'M',
+  'Vowel_Independent'          : 'V',
+}
+position_map = {
+  'Not_Applicable'             : 'END',
+
+  'Left'                       : 'PRE_C',
+  'Top'                                : 'ABOVE_C',
+  'Bottom'                     : 'BELOW_C',
+  'Right'                      : 'POST_C',
+
+  # These should resolve to the position of the last part of the split sequence.
+  'Bottom_And_Right'           : 'POST_C',
+  'Left_And_Right'             : 'POST_C',
+  'Top_And_Bottom'             : 'BELOW_C',
+  'Top_And_Bottom_And_Left'    : 'BELOW_C',
+  'Top_And_Bottom_And_Right'   : 'POST_C',
+  'Top_And_Left'               : 'ABOVE_C',
+  'Top_And_Left_And_Right'     : 'POST_C',
+  'Top_And_Right'              : 'POST_C',
+
+  'Overstruck'                 : 'AFTER_MAIN',
+  'Visual_order_left'          : 'PRE_M',
+}
+
+category_overrides = {
+
+  # These are the variation-selectors. They only appear in the Myanmar grammar
+  # but are not Myanmar-specific
+  0xFE00: 'VS',
+  0xFE01: 'VS',
+  0xFE02: 'VS',
+  0xFE03: 'VS',
+  0xFE04: 'VS',
+  0xFE05: 'VS',
+  0xFE06: 'VS',
+  0xFE07: 'VS',
+  0xFE08: 'VS',
+  0xFE09: 'VS',
+  0xFE0A: 'VS',
+  0xFE0B: 'VS',
+  0xFE0C: 'VS',
+  0xFE0D: 'VS',
+  0xFE0E: 'VS',
+  0xFE0F: 'VS',
+
+  # These appear in the OT Myanmar spec, but are not Myanmar-specific
+  0x2015: 'PLACEHOLDER',
+  0x2022: 'PLACEHOLDER',
+  0x25FB: 'PLACEHOLDER',
+  0x25FC: 'PLACEHOLDER',
+  0x25FD: 'PLACEHOLDER',
+  0x25FE: 'PLACEHOLDER',
+
+
+  # Indic
+
+  0x0930: 'Ra', # Devanagari
+  0x09B0: 'Ra', # Bengali
+  0x09F0: 'Ra', # Bengali
+  0x0A30: 'Ra', # Gurmukhi     No Reph
+  0x0AB0: 'Ra', # Gujarati
+  0x0B30: 'Ra', # Oriya
+  0x0BB0: 'Ra', # Tamil        No Reph
+  0x0C30: 'Ra', # Telugu       Reph formed only with ZWJ
+  0x0CB0: 'Ra', # Kannada
+  0x0D30: 'Ra', # Malayalam    No Reph, Logical Repha
+
+  # The following act more like the Bindus.
+  0x0953: 'SM',
+  0x0954: 'SM',
+
+  # U+0A40 GURMUKHI VOWEL SIGN II may be preceded by U+0A02 GURMUKHI SIGN BINDI.
+  0x0A40: 'MPst',
+
+  # The following act like consonants.
+  0x0A72: 'C',
+  0x0A73: 'C',
+  0x1CF5: 'C',
+  0x1CF6: 'C',
+
+  # TODO: The following should only be allowed after a Visarga.
+  # For now, just treat them like regular tone marks.
+  0x1CE2: 'A',
+  0x1CE3: 'A',
+  0x1CE4: 'A',
+  0x1CE5: 'A',
+  0x1CE6: 'A',
+  0x1CE7: 'A',
+  0x1CE8: 'A',
+
+  # TODO: The following should only be allowed after some of
+  # the nasalization marks, maybe only for U+1CE9..U+1CF1.
+  # For now, just treat them like tone marks.
+  0x1CED: 'A',
+
+  # The following take marks in standalone clusters, similar to Avagraha.
+  0xA8F2: 'Symbol',
+  0xA8F3: 'Symbol',
+  0xA8F4: 'Symbol',
+  0xA8F5: 'Symbol',
+  0xA8F6: 'Symbol',
+  0xA8F7: 'Symbol',
+  0x1CE9: 'Symbol',
+  0x1CEA: 'Symbol',
+  0x1CEB: 'Symbol',
+  0x1CEC: 'Symbol',
+  0x1CEE: 'Symbol',
+  0x1CEF: 'Symbol',
+  0x1CF0: 'Symbol',
+  0x1CF1: 'Symbol',
+
+  0x0A51: 'M', # https://github.com/harfbuzz/harfbuzz/issues/524
+
+  # According to ScriptExtensions.txt, these Grantha marks may also be used in Tamil,
+  # so the Indic shaper needs to know their categories.
+  0x11301: 'SM',
+  0x11302: 'SM',
+  0x11303: 'SM',
+  0x1133B: 'N',
+  0x1133C: 'N',
+
+  0x0AFB: 'N', # https://github.com/harfbuzz/harfbuzz/issues/552
+  0x0B55: 'N', # https://github.com/harfbuzz/harfbuzz/issues/2849
+
+  0x09FC: 'PLACEHOLDER', # https://github.com/harfbuzz/harfbuzz/pull/1613
+  0x0C80: 'PLACEHOLDER', # https://github.com/harfbuzz/harfbuzz/pull/623
+  0x0D04: 'PLACEHOLDER', # https://github.com/harfbuzz/harfbuzz/pull/3511
+
+  0x25CC: 'DOTTEDCIRCLE',
+
+
+  # Khmer
+
+  0x179A: 'Ra',
+
+  0x17CC: 'Robatic',
+  0x17C9: 'Robatic',
+  0x17CA: 'Robatic',
+
+  0x17C6: 'Xgroup',
+  0x17CB: 'Xgroup',
+  0x17CD: 'Xgroup',
+  0x17CE: 'Xgroup',
+  0x17CF: 'Xgroup',
+  0x17D0: 'Xgroup',
+  0x17D1: 'Xgroup',
+
+  0x17C7: 'Ygroup',
+  0x17C8: 'Ygroup',
+  0x17DD: 'Ygroup',
+  0x17D3: 'Ygroup', # Just guessing. Uniscribe doesn't categorize it.
+
+  0x17D9: 'PLACEHOLDER', # https://github.com/harfbuzz/harfbuzz/issues/2384
+
+
+  # Myanmar
+
+  # https://docs.microsoft.com/en-us/typography/script-development/myanmar#analyze
+
+  0x104E: 'C', # The spec says C, IndicSyllableCategory says Consonant_Placeholder
+
+  0x1004: 'Ra',
+  0x101B: 'Ra',
+  0x105A: 'Ra',
+
+  0x1032: 'A',
+  0x1036: 'A',
+
+  0x103A: 'As',
+
+  #0x1040: 'D0', # XXX The spec says D0, but Uniscribe doesn't seem to do.
+
+  0x103E: 'MH',
+  0x1060: 'ML',
+  0x103C: 'MR',
+  0x103D: 'MW',
+  0x1082: 'MW',
+  0x103B: 'MY',
+  0x105E: 'MY',
+  0x105F: 'MY',
+
+  0x1063: 'PT',
+  0x1064: 'PT',
+  0x1069: 'PT',
+  0x106A: 'PT',
+  0x106B: 'PT',
+  0x106C: 'PT',
+  0x106D: 'PT',
+  0xAA7B: 'PT',
+
+  0x1038: 'SM',
+  0x1087: 'SM',
+  0x1088: 'SM',
+  0x1089: 'SM',
+  0x108A: 'SM',
+  0x108B: 'SM',
+  0x108C: 'SM',
+  0x108D: 'SM',
+  0x108F: 'SM',
+  0x109A: 'SM',
+  0x109B: 'SM',
+  0x109C: 'SM',
+
+  0x104A: 'PLACEHOLDER',
+}
+position_overrides = {
+
+  0x0A51: 'BELOW_C', # https://github.com/harfbuzz/harfbuzz/issues/524
+
+  0x0B01: 'BEFORE_SUB', # Oriya Bindu is BeforeSub in the spec.
+}
+
+def matra_pos_left(u, block):
+  return "PRE_M"
+def matra_pos_right(u, block):
+  if block == 'Devanagari':    return  'AFTER_SUB'
+  if block == 'Bengali':       return  'AFTER_POST'
+  if block == 'Gurmukhi':      return  'AFTER_POST'
+  if block == 'Gujarati':      return  'AFTER_POST'
+  if block == 'Oriya':         return  'AFTER_POST'
+  if block == 'Tamil':         return  'AFTER_POST'
+  if block == 'Telugu':                return  'BEFORE_SUB' if u <= 0x0C42 else 'AFTER_SUB'
+  if block == 'Kannada':       return  'BEFORE_SUB' if u < 0x0CC3 or u > 0x0CD6 else 'AFTER_SUB'
+  if block == 'Malayalam':     return  'AFTER_POST'
+  return 'AFTER_SUB'
+def matra_pos_top(u, block):
+  # BENG and MLYM don't have top matras.
+  if block == 'Devanagari':    return  'AFTER_SUB'
+  if block == 'Gurmukhi':      return  'AFTER_POST' # Deviate from spec
+  if block == 'Gujarati':      return  'AFTER_SUB'
+  if block == 'Oriya':         return  'AFTER_MAIN'
+  if block == 'Tamil':         return  'AFTER_SUB'
+  if block == 'Telugu':                return  'BEFORE_SUB'
+  if block == 'Kannada':       return  'BEFORE_SUB'
+  return 'AFTER_SUB'
+def matra_pos_bottom(u, block):
+  if block == 'Devanagari':    return  'AFTER_SUB'
+  if block == 'Bengali':       return  'AFTER_SUB'
+  if block == 'Gurmukhi':      return  'AFTER_POST'
+  if block == 'Gujarati':      return  'AFTER_POST'
+  if block == 'Oriya':         return  'AFTER_SUB'
+  if block == 'Tamil':         return  'AFTER_POST'
+  if block == 'Telugu':                return  'BEFORE_SUB'
+  if block == 'Kannada':       return  'BEFORE_SUB'
+  if block == 'Malayalam':     return  'AFTER_POST'
+  return "AFTER_SUB"
+def indic_matra_position(u, pos, block): # Reposition matra
+  if pos == 'PRE_C':   return matra_pos_left(u, block)
+  if pos == 'POST_C':  return matra_pos_right(u, block)
+  if pos == 'ABOVE_C': return matra_pos_top(u, block)
+  if pos == 'BELOW_C': return matra_pos_bottom(u, block)
+  assert (False)
+
+def position_to_category(pos):
+  if pos == 'PRE_C':   return 'VPre'
+  if pos == 'ABOVE_C': return 'VAbv'
+  if pos == 'BELOW_C': return 'VBlw'
+  if pos == 'POST_C':  return 'VPst'
+  assert(False)
+
+
+defaults = (category_map[defaults[0]], position_map[defaults[1]], defaults[2])
+
+indic_data = {}
+for k, (cat, pos, block) in combined.items():
+  cat = category_map[cat]
+  pos = position_map[pos]
+  indic_data[k] = (cat, pos, block)
+
+for k,new_cat in category_overrides.items():
+  (cat, pos, _) = indic_data.get(k, defaults)
+  indic_data[k] = (new_cat, pos, unicode_data[2][k])
+
+# We only expect position for certain types
+positioned_categories = ('CM', 'SM', 'RS', 'H', 'M', 'MPst')
+for k, (cat, pos, block) in indic_data.items():
+  if cat not in positioned_categories:
+    pos = 'END'
+    indic_data[k] = (cat, pos, block)
+
+# Position overrides are more complicated
+
+# Keep in sync with CONSONANT_FLAGS in the shaper
+consonant_categories = ('C', 'CS', 'Ra','CM', 'V', 'PLACEHOLDER', 'DOTTEDCIRCLE')
+matra_categories = ('M', 'MPst')
+smvd_categories = ('SM', 'VD', 'A', 'Symbol')
+for k, (cat, pos, block) in indic_data.items():
+  if cat in consonant_categories:
+    pos = 'BASE_C'
+  elif cat in matra_categories:
+    if block.startswith('Khmer') or block.startswith('Myanmar'):
+      cat = position_to_category(pos)
+    else:
+      pos = indic_matra_position(k, pos, block)
+  elif cat in smvd_categories:
+    pos = 'SMVD';
+  indic_data[k] = (cat, pos, block)
+
+for k,new_pos in position_overrides.items():
+  (cat, pos, _) = indic_data.get(k, defaults)
+  indic_data[k] = (cat, new_pos, unicode_data[2][k])
+
+
+values = [{_: 1} for _ in defaults]
+for vv in indic_data.values():
+  for i,v in enumerate(vv):
+    values[i][v] = values[i].get (v, 0) + 1
+
+
+
 
 # Move the outliers NO-BREAK SPACE and DOTTED CIRCLE out
 singles = {}
 for u in ALLOWED_SINGLES:
-       singles[u] = data[u]
-       del data[u]
+       singles[u] = indic_data[u]
+       del indic_data[u]
 
 print ("/* == Start of generated table == */")
 print ("/*")
@@ -106,37 +502,63 @@ print ('#include "hb.hh"')
 print ()
 print ('#ifndef HB_NO_OT_SHAPE')
 print ()
-print ('#include "hb-ot-shape-complex-indic.hh"')
+print ('#include "hb-ot-shaper-indic.hh"')
+print ()
+print ('#pragma GCC diagnostic push')
+print ('#pragma GCC diagnostic ignored "-Wunused-macros"')
+print ()
+
+# Print categories
+for shaper in categories:
+  print ('#include "hb-ot-shaper-%s-machine.hh"' % shaper)
+print ()
+done = {}
+for shaper, shaper_cats in categories.items():
+  print ('/* %s */' % shaper)
+  for cat in shaper_cats:
+    v = shaper[0].upper()
+    if cat not in done:
+      print ("#define OT_%s %s_Cat(%s)" % (cat, v, cat))
+      done[cat] = v
+    else:
+      print ('static_assert (OT_%s == %s_Cat(%s), "");' % (cat, v, cat))
 print ()
 
 # Shorten values
 short = [{
-       "Bindu":                'Bi',
-       "Cantillation_Mark":    'Ca',
-       "Joiner":               'ZWJ',
-       "Non_Joiner":           'ZWNJ',
-       "Number":               'Nd',
-       "Visarga":              'Vs',
-       "Vowel":                'Vo',
-       "Vowel_Dependent":      'M',
-       "Consonant_Prefixed":   'CPrf',
-       "Other":                'x',
+       "Repha":                'Rf',
+       "PLACEHOLDER":          'GB',
+       "DOTTEDCIRCLE":         'DC',
+       "VPst":                 'VR',
+       "VPre":                 'VL',
+       "Robatic":              'Rt',
+       "Xgroup":               'Xg',
+       "Ygroup":               'Yg',
+       "As":                   'As',
 },{
-       "Not_Applicable":       'x',
+       "END":                  'X',
+       "BASE_C":               'C',
+       "ABOVE_C":              'T',
+       "BELOW_C":              'B',
+       "POST_C":               'R',
+       "PRE_C":                'L',
+       "PRE_M":                'LM',
+       "AFTER_MAIN":           'A',
+       "AFTER_SUB":            'AS',
+       "BEFORE_SUB":           'BS',
+       "AFTER_POST":           'AP',
+       "SMVD":                 'SM',
 }]
 all_shorts = [{},{}]
 
 # Add some of the values, to make them more readable, and to avoid duplicates
 
-
 for i in range (2):
        for v,s in short[i].items ():
                all_shorts[i][s] = v
 
-what = ["INDIC_SYLLABIC_CATEGORY", "INDIC_MATRA_CATEGORY"]
-what_short = ["ISC", "IMC"]
-print ('#pragma GCC diagnostic push')
-print ('#pragma GCC diagnostic ignored "-Wunused-macros"')
+what = ["OT", "POS"]
+what_short = ["_OT", "_POS"]
 cat_defs = []
 for i in range (2):
        vv = sorted (values[i].keys ())
@@ -150,7 +572,7 @@ for i in range (2):
                                raise Exception ("Duplicate short value alias", v, all_shorts[i][s])
                        all_shorts[i][s] = v
                        short[i][v] = s
-               cat_defs.append ((what_short[i] + '_' + s, what[i] + '_' + v.upper (), str (values[i][v]), v))
+               cat_defs.append ((what_short[i] + '_' + s, what[i] + '_' + (v.upper () if i else v), str (values[i][v]), v))
 
 maxlen_s = max ([len (c[0]) for c in cat_defs])
 maxlen_l = max ([len (c[1]) for c in cat_defs])
@@ -163,7 +585,9 @@ for s in what_short:
 print ()
 print ('#pragma GCC diagnostic pop')
 print ()
-print ("#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)")
+print ("#define INDIC_COMBINE_CATEGORIES(S,M) ((S) | ((M) << 8))")
+print ()
+print ("#define _(S,M) INDIC_COMBINE_CATEGORIES (%s_##S, %s_##M)" % tuple(what_short))
 print ()
 print ()
 
@@ -193,7 +617,7 @@ def print_block (block, start, end, data):
        if block:
                last_block = block
 
-uu = sorted (data.keys ())
+uu = sorted (indic_data)
 
 last = -100000
 num = 0
@@ -204,17 +628,17 @@ print ("static const uint16_t indic_table[] = {")
 for u in uu:
        if u <= last:
                continue
-       block = data[u][2]
+       block = indic_data[u][2]
 
        start = u//8*8
        end = start+1
-       while end in uu and block == data[end][2]:
+       while end in uu and block == indic_data[end][2]:
                end += 1
        end = (end-1)//8*8 + 7
 
        if start != last + 1:
-               if start - last <= 1+16*3:
-                       print_block (None, last+1, start-1, data)
+               if start - last <= 1+16*2:
+                       print_block (None, last+1, start-1, indic_data)
                else:
                        if last >= 0:
                                ends.append (last + 1)
@@ -224,7 +648,7 @@ for u in uu:
                        print ("#define indic_offset_0x%04xu %d" % (start, offset))
                        starts.append (start)
 
-       print_block (block, start, end, data)
+       print_block (block, start, end, indic_data)
        last = end
 ends.append (last + 1)
 offset += ends[-1] - starts[-1]
@@ -254,10 +678,11 @@ for p in sorted(pages):
 print ("    default:")
 print ("      break;")
 print ("  }")
-print ("  return _(x,x);")
+print ("  return _(X,X);")
 print ("}")
 print ()
 print ("#undef _")
+print ("#undef INDIC_COMBINE_CATEGORIES")
 for i in range (2):
        print ()
        vv = sorted (values[i].keys ())
@@ -269,6 +694,6 @@ print ('#endif')
 print ()
 print ("/* == End of generated table == */")
 
-# Maintain at least 30% occupancy in the table */
-if occupancy < 30:
+# Maintain at least 50% occupancy in the table */
+if occupancy < 50:
        raise Exception ("Table too sparse, please investigate: ", occupancy)
index f8fb05f..7e15c08 100755 (executable)
@@ -894,7 +894,6 @@ 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.
@@ -944,33 +943,39 @@ def get_matching_language_name (intersection, candidates):
 def same_tag (bcp_47_tag, ot_tags):
        return len (bcp_47_tag) == 3 and len (ot_tags) == 1 and bcp_47_tag == ot_tags[0].lower ()
 
-for language, tags in sorted (ot.from_bcp_47.items ()):
-       if language == '' or '-' in language:
-               continue
-       commented_out = same_tag (language, tags)
-       for i, tag in enumerate (tags, start=1):
-               print ('%s{\"%s\",\t%s},' % ('/*' if commented_out else '  ', language, hb_tag (tag)), end='')
-               if commented_out:
-                       print ('*/', end='')
-               print ('\t/* ', end='')
-               bcp_47_name = bcp_47.names.get (language, '')
-               bcp_47_name_candidates = bcp_47_name.split ('\n')
-               ot_name = ot.names[tag]
-               scope = bcp_47.scopes.get (language, '')
-               if tag == DEFAULT_LANGUAGE_SYSTEM:
-                       write (f'{bcp_47_name_candidates[0]}{scope} != {ot.names[language.upper ()]}')
-               else:
-                       intersection = language_name_intersection (bcp_47_name, ot_name)
-                       if not intersection:
-                               write ('%s%s -> %s' % (bcp_47_name_candidates[0], scope, ot_name))
+for language_len in (2, 3):
+       if language_len == 3:
+               print ('#ifndef HB_NO_LANGUAGE_LONG')
+       print ('static const LangTag ot_languages%d[] = {' % language_len)
+       for language, tags in sorted (ot.from_bcp_47.items ()):
+               if language == '' or '-' in language:
+                       continue
+               if len(language) != language_len: continue
+               commented_out = same_tag (language, tags)
+               for i, tag in enumerate (tags, start=1):
+                       print ('%s{%s,\t%s},' % ('/*' if commented_out else '  ', hb_tag (language), hb_tag (tag)), end='')
+                       if commented_out:
+                               print ('*/', end='')
+                       print ('\t/* ', end='')
+                       bcp_47_name = bcp_47.names.get (language, '')
+                       bcp_47_name_candidates = bcp_47_name.split ('\n')
+                       ot_name = ot.names[tag]
+                       scope = bcp_47.scopes.get (language, '')
+                       if tag == DEFAULT_LANGUAGE_SYSTEM:
+                               write (f'{bcp_47_name_candidates[0]}{scope} != {ot.names[language.upper ()]}')
                        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_name) else ot_name, scope))
-               print (' */')
-
-print ('};')
-print ()
+                               intersection = language_name_intersection (bcp_47_name, ot_name)
+                               if not intersection:
+                                       write ('%s%s -> %s' % (bcp_47_name_candidates[0], scope, ot_name))
+                               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_name) else ot_name, scope))
+                       print (' */')
+       print ('};')
+       if language_len == 3:
+               print ('#endif')
+       print ()
 
 print ('/**')
 print (' * hb_ot_tags_from_complex_language:')
@@ -986,19 +991,19 @@ 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 ('static inline 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):
+def print_subtag_matches (subtag, string, new_line):
        if subtag:
                if new_line:
                        print ()
                        print ('\t&& ', end='')
-               print ('subtag_matches (lang_str, limit, "-%s")' % subtag, end='')
+               print ('subtag_matches (%s, limit, "-%s", %i)' % (string, subtag, 1 + len (subtag)), end='')
 
 complex_tags = collections.defaultdict (list)
 for initial, group in itertools.groupby ((lt_tags for lt_tags in [
@@ -1009,6 +1014,24 @@ for initial, group in itertools.groupby ((lt_tags for lt_tags in [
                key=lambda lt_tags: lt_tags[0].get_group ()):
        complex_tags[initial] += group
 
+# Calculate the min length of the subtags outside the switch
+min_subtag_len = 100
+for initial, items in sorted (complex_tags.items ()):
+       if initial != 'und':
+               continue
+       for lt, tags in items:
+               if not tags:
+                       continue
+               subtag_len = 0
+               subtag_len += 1 + len (lt.script) if lt.script is not None else 0
+               subtag_len += 1 + len (lt.region) if lt.region is not None else 0
+               subtag_len += 1 + len (lt.variant) if lt.variant is not None else 0
+               min_subtag_len = min(subtag_len, min_subtag_len)
+
+print ('  if (limit - lang_str >= %d)' % (min_subtag_len + 2))
+print ('  {')
+print ("    const char *p = strchr (lang_str, '-');")
+print ("    if (!p || p >= limit || limit - p < %i) goto out;" % min_subtag_len)
 for initial, items in sorted (complex_tags.items ()):
        if initial != 'und':
                continue
@@ -1018,29 +1041,31 @@ for initial, items in sorted (complex_tags.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 ('    if (', end='')
+               print_subtag_matches (lt.script, 'p', False)
+               print_subtag_matches (lt.region, 'p', False)
+               print_subtag_matches (lt.variant, 'p', False)
                print (')')
-               print ('  {')
-               write ('    /* %s */' % bcp_47.get_name (lt))
+               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]]))
+                       write ('      tags[0] = %s;  /* %s */' % (hb_tag (tags[0]), ot.names[tags[0]]))
                        print ()
-                       print ('    *count = 1;')
+                       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 ('      };')
+                       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 ('  }')
+print ('out:')
 
 print ('  switch (lang_str[0])')
 print ('  {')
@@ -1067,10 +1092,10 @@ for initial, items in sorted (complex_tags.items ()):
                        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 (script, True)
-               print_subtag_matches (region, True)
-               print_subtag_matches (lt.variant, True)
+                               print ('lang_matches (&lang_str[1], limit, "%s", %i)' % (string_literal, len (string_literal)), end='')
+               print_subtag_matches (script, 'lang_str', True)
+               print_subtag_matches (region, 'lang_str', True)
+               print_subtag_matches (lt.variant, 'lang_str', True)
                print (')')
                print ('    {')
                write ('      /* %s */' % bcp_47.get_name (lt))
@@ -1109,7 +1134,7 @@ 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 ('static inline hb_language_t')
 print ('hb_ot_ambiguous_tag_to_language (hb_tag_t tag)')
 print ('{')
 print ('  switch (tag)')
index 35fba2d..d85ae4f 100755 (executable)
@@ -25,14 +25,28 @@ hb_common_h = 'hb-common.h' if len (sys.argv) < 3 else sys.argv[2]
 
 logging.info('Preparing data tables...')
 
+
+# This is how the data is encoded:
+#
+# General_Category (gc), Canonical_Combining_Class (ccc),
+# and Script (sc) are encoded as integers.
+#
+# Mirroring character (bmg) is encoded as difference from
+# the original character.
+#
+# Composition & Decomposition (dm) are encoded elaborately,
+# as discussed below.
+
 gc = [u['gc'] for u in ucd]
 ccc = [int(u['ccc']) for u in ucd]
 bmg = [int(v, 16) - int(u) if v else 0 for u,v in enumerate(u['bmg'] for u in ucd)]
-#gc_ccc_non0 = set((cat,klass) for cat,klass in zip(gc,ccc) if klass)
-#gc_bmg_non0 = set((cat,mirr) for cat,mirr in zip(gc, bmg) if mirr)
-
 sc = [u['sc'] for u in ucd]
 
+
+# Prepare Compose / Decompose data
+#
+# This code is very dense.  See hb_ucd_compose() / hb_ucd_decompose() for the logic.
+
 dm = {i:tuple(int(v, 16) for v in u['dm'].split()) for i,u in enumerate(ucd)
       if u['dm'] != '#' and u['dt'] == 'can' and not (0xAC00 <= i < 0xAC00+11172)}
 ce = {i for i,u in enumerate(ucd) if u['Comp_Ex'] == 'Y'}
@@ -63,6 +77,9 @@ dm_order = {None: 0}
 dm_order.update(dm1_order)
 dm_order.update(dm2_order)
 
+
+# Prepare General_Category / Script mapping arrays
+
 gc_order = dict()
 for i,v in enumerate(('Cc', 'Cf', 'Cn', 'Co', 'Cs', 'Ll', 'Lm', 'Lo', 'Lt', 'Lu',
                       'Mc', 'Me', 'Mn', 'Nd', 'Nl', 'No', 'Pc', 'Pd', 'Pe', 'Pf',
@@ -83,10 +100,18 @@ for line in open(hb_common_h):
     sc_order[i] = tag
     sc_array.append(name)
 
-DEFAULT = 1
-COMPACT = 3
-SLOPPY  = 5
 
+# Write out main data
+
+DEFAULT = 'DEFAULT'
+COMPACT = 'COMPACT'
+SLOPPY  = 'SLOPPY'
+
+compression_level = {
+    DEFAULT: 5,
+    COMPACT: 9,
+    SLOPPY:  9,
+}
 
 logging.info('Generating output...')
 print("/* == Start of generated table == */")
@@ -104,6 +129,9 @@ print()
 print('#include "hb.hh"')
 print()
 
+
+# Write mapping data
+
 code = packTab.Code('_hb_ucd')
 sc_array, _ = code.addArray('hb_script_t', 'sc_map', sc_array)
 dm1_p0_array, _ = code.addArray('uint16_t', 'dm1_p0_map', dm1_p0_array)
@@ -120,18 +148,24 @@ datasets = [
     ('dm', dm, None, dm_order),
 ]
 
-for compression in (DEFAULT, COMPACT, SLOPPY):
+
+# Write main data
+
+for step in (DEFAULT, COMPACT, SLOPPY):
+    compression = compression_level[step]
     logging.info('  Compression=%d:' % compression)
     print()
-    if compression == DEFAULT:
+    if step == DEFAULT:
         print('#ifndef HB_OPTIMIZE_SIZE')
-    elif compression == COMPACT:
+    elif step == COMPACT:
         print('#elif !defined(HB_NO_UCD_UNASSIGNED)')
-    else:
+    elif step == SLOPPY:
         print('#else')
+    else:
+        assert False
     print()
 
-    if compression == SLOPPY:
+    if step == SLOPPY:
         for i in range(len(gc)):
             if (i % 128) and gc[i] == 'Cn':
                 gc[i] = gc[i - 1]
@@ -157,6 +191,7 @@ for compression in (DEFAULT, COMPACT, SLOPPY):
 
     print()
 
+
 print('#endif')
 print()
 
index 34540ca..4e87b84 100755 (executable)
@@ -1,6 +1,9 @@
 #!/usr/bin/env python3
 # flake8: noqa: F821
 
+import logging
+logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
+
 """usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt ArabicShaping.txt DerivedCoreProperties.txt UnicodeData.txt Blocks.txt Scripts.txt IndicSyllabicCategory-Additional.txt IndicPositionalCategory-Additional.txt
 
 Input files:
@@ -39,7 +42,7 @@ for j in range(7, 9):
                headers[j - 1].append(line)
 headers.append (["UnicodeData.txt does not have a header."])
 
-data = [{} for _ in files]
+unicode_data = [{} for _ in files]
 values = [{} for _ in files]
 for i, f in enumerate (files):
        for line in f:
@@ -73,38 +76,16 @@ for i, f in enumerate (files):
 
                i0 = i if i < 7 else i - 7
                for u in range (start, end + 1):
-                       data[i0][u] = t
+                       unicode_data[i0][u] = t
                values[i0][t] = values[i0].get (t, 0) + end - start + 1
 
 defaults = ('Other', 'Not_Applicable', 'jt_X', '', 'Cn', 'No_Block', 'Unknown')
 
-# TODO Characters that are not in Unicode Indic files, but used in USE
-data[0][0x1B61] = defaults[0]
-data[0][0x1B63] = defaults[0]
-data[0][0x1B64] = defaults[0]
-data[0][0x1B65] = defaults[0]
-data[0][0x1B66] = defaults[0]
-data[0][0x1B67] = defaults[0]
-data[0][0x1B69] = defaults[0]
-data[0][0x1B6A] = defaults[0]
-data[0][0x2060] = defaults[0]
-# TODO https://github.com/harfbuzz/harfbuzz/pull/1685
-data[0][0x1B5B] = 'Consonant_Placeholder'
-data[0][0x1B5C] = 'Consonant_Placeholder'
-data[0][0x1B5F] = 'Consonant_Placeholder'
-data[0][0x1B62] = 'Consonant_Placeholder'
-data[0][0x1B68] = 'Consonant_Placeholder'
-# TODO https://github.com/harfbuzz/harfbuzz/issues/1035
-data[0][0x11C44] = 'Consonant_Placeholder'
-data[0][0x11C45] = 'Consonant_Placeholder'
-# TODO https://github.com/harfbuzz/harfbuzz/pull/1399
-data[0][0x111C8] = 'Consonant_Placeholder'
-
 # Merge data into one dict:
 for i,v in enumerate (defaults):
        values[i][v] = values[i].get (v, 0) + 1
 combined = {}
-for i,d in enumerate (data):
+for i,d in enumerate (unicode_data):
        for u,v in d.items ():
                if not u in combined:
                        if i >= 4:
@@ -112,8 +93,6 @@ for i,d in enumerate (data):
                        combined[u] = list (defaults)
                combined[u][i] = v
 combined = {k: v for k, v in combined.items() if v[6] not in DISABLED_SCRIPTS}
-data = combined
-del combined
 
 
 property_names = [
@@ -158,8 +137,13 @@ property_names = [
        'Number_Joiner',
        'Number',
        'Brahmi_Joining_Number',
+       'Symbol_Modifier',
        'Hieroglyph',
        'Hieroglyph_Joiner',
+       'Hieroglyph_Mark_Begin',
+       'Hieroglyph_Mark_End',
+       'Hieroglyph_Mirror',
+       'Hieroglyph_Modifier',
        'Hieroglyph_Segment_Begin',
        'Hieroglyph_Segment_End',
        # Indic_Positional_Category
@@ -226,8 +210,8 @@ def is_BASE_OTHER(U, UISC, UDI, UGC, AJT):
        if UISC == Consonant_Placeholder: return True
        return U in [0x2015, 0x2022, 0x25FB, 0x25FC, 0x25FD, 0x25FE]
 def is_CGJ(U, UISC, UDI, UGC, AJT):
-       # Also includes VARIATION_SELECTOR, WJ, and ZWJ
-       return U == 0x200D or UDI and UGC in [Mc, Me, Mn]
+       # Also includes VARIATION_SELECTOR and ZWJ
+       return UISC == Joiner or UDI and UGC in [Mc, Me, Mn]
 def is_CONS_FINAL(U, UISC, UDI, UGC, AJT):
        return ((UISC == Consonant_Final and UGC != Lo) or
                UISC == Consonant_Succeeding_Repha)
@@ -238,39 +222,45 @@ def is_CONS_MED(U, UISC, UDI, UGC, AJT):
        return (UISC == Consonant_Medial and UGC != Lo or
                UISC == Consonant_Initial_Postfixed)
 def is_CONS_MOD(U, UISC, UDI, UGC, AJT):
-       return (UISC in [Nukta, Gemination_Mark, Consonant_Killer] and
-               not is_SYM_MOD(U, UISC, UDI, UGC, AJT))
+       return UISC in [Nukta, Gemination_Mark, Consonant_Killer]
 def is_CONS_SUB(U, UISC, UDI, UGC, AJT):
        return UISC == Consonant_Subjoined and UGC != Lo
 def is_CONS_WITH_STACKER(U, UISC, UDI, UGC, AJT):
        return UISC == Consonant_With_Stacker
 def is_HALANT(U, UISC, UDI, UGC, AJT):
-       return (UISC in [Virama, Invisible_Stacker]
-               and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UDI, UGC, AJT)
-               and not is_SAKOT(U, UISC, UDI, UGC, AJT))
+       return UISC == Virama and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UDI, UGC, AJT)
 def is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UDI, UGC, AJT):
        # Split off of HALANT
-       # https://github.com/harfbuzz/harfbuzz/issues/1379
-       return U == 0x1134D
+       return U == 0x0DCA
 def is_HALANT_NUM(U, UISC, UDI, UGC, AJT):
        return UISC == Number_Joiner
 def is_HIEROGLYPH(U, UISC, UDI, UGC, AJT):
        return UISC == Hieroglyph
 def is_HIEROGLYPH_JOINER(U, UISC, UDI, UGC, AJT):
        return UISC == Hieroglyph_Joiner
+def is_HIEROGLYPH_MIRROR(U, UISC, UDI, UGC, AJT):
+       return UISC == Hieroglyph_Mirror
+def is_HIEROGLYPH_MOD(U, UISC, UDI, UGC, AJT):
+       return UISC == Hieroglyph_Modifier
 def is_HIEROGLYPH_SEGMENT_BEGIN(U, UISC, UDI, UGC, AJT):
-       return UISC == Hieroglyph_Segment_Begin
+       return UISC in [Hieroglyph_Mark_Begin, Hieroglyph_Segment_Begin]
 def is_HIEROGLYPH_SEGMENT_END(U, UISC, UDI, UGC, AJT):
-       return UISC == Hieroglyph_Segment_End
+       return UISC in [Hieroglyph_Mark_End, Hieroglyph_Segment_End]
+def is_INVISIBLE_STACKER(U, UISC, UDI, UGC, AJT):
+       # Split off of HALANT
+       return (UISC == Invisible_Stacker
+               and not is_SAKOT(U, UISC, UDI, UGC, AJT)
+       )
 def is_ZWNJ(U, UISC, UDI, UGC, AJT):
        return UISC == Non_Joiner
 def is_OTHER(U, UISC, UDI, UGC, AJT):
-       # Also includes BASE_IND, Rsv, and SYM
-       return ((UGC in [Cn, Po] or UISC in [Consonant_Dead, Joiner, Modifying_Letter, Other])
+       # Also includes BASE_IND and SYM
+       return ((UGC == Po or UISC in [Consonant_Dead, Joiner, Modifying_Letter, Other])
                and not is_BASE(U, UISC, UDI, UGC, AJT)
                and not is_BASE_OTHER(U, UISC, UDI, UGC, AJT)
                and not is_CGJ(U, UISC, UDI, UGC, AJT)
                and not is_SYM_MOD(U, UISC, UDI, UGC, AJT)
+               and not is_Word_Joiner(U, UISC, UDI, UGC, AJT)
        )
 def is_REPHA(U, UISC, UDI, UGC, AJT):
        return UISC in [Consonant_Preceding_Repha, Consonant_Prefixed]
@@ -278,15 +268,19 @@ def is_SAKOT(U, UISC, UDI, UGC, AJT):
        # Split off of HALANT
        return U == 0x1A60
 def is_SYM_MOD(U, UISC, UDI, UGC, AJT):
-       return U in [0x1B6B, 0x1B6C, 0x1B6D, 0x1B6E, 0x1B6F, 0x1B70, 0x1B71, 0x1B72, 0x1B73]
+       return UISC == Symbol_Modifier
 def is_VOWEL(U, UISC, UDI, UGC, AJT):
-       # https://github.com/harfbuzz/harfbuzz/issues/376
        return (UISC == Pure_Killer or
-               (UGC != Lo and UISC in [Vowel, Vowel_Dependent] and U not in [0xAA29]))
+               UGC != Lo and UISC in [Vowel, Vowel_Dependent])
 def is_VOWEL_MOD(U, UISC, UDI, UGC, AJT):
-       # https://github.com/harfbuzz/harfbuzz/issues/376
        return (UISC in [Tone_Mark, Cantillation_Mark, Register_Shifter, Visarga] or
-               (UGC != Lo and (UISC == Bindu or U in [0xAA29])))
+               UGC != Lo and UISC == Bindu)
+def is_Word_Joiner(U, UISC, UDI, UGC, AJT):
+       # Also includes Rsv
+       return (UDI and U not in [0x115F, 0x1160, 0x3164, 0xFFA0, 0x1BCA0, 0x1BCA1, 0x1BCA2, 0x1BCA3]
+               and UISC == Other
+               and not is_CGJ(U, UISC, UDI, UGC, AJT)
+       ) or UGC == Cn
 
 use_mapping = {
        'B':    is_BASE,
@@ -302,7 +296,10 @@ use_mapping = {
        'H':    is_HALANT,
        'HVM':  is_HALANT_OR_VOWEL_MODIFIER,
        'HN':   is_HALANT_NUM,
+       'IS':   is_INVISIBLE_STACKER,
        'G':    is_HIEROGLYPH,
+       'HM':   is_HIEROGLYPH_MOD,
+       'HR':   is_HIEROGLYPH_MIRROR,
        'J':    is_HIEROGLYPH_JOINER,
        'SB':   is_HIEROGLYPH_SEGMENT_BEGIN,
        'SE':   is_HIEROGLYPH_SEGMENT_END,
@@ -313,6 +310,7 @@ use_mapping = {
        'SM':   is_SYM_MOD,
        'V':    is_VOWEL,
        'VM':   is_VOWEL_MOD,
+       'WJ':   is_Word_Joiner,
 }
 
 use_positions = {
@@ -348,7 +346,10 @@ use_positions = {
                'Blw': [Bottom],
        },
        'H': None,
+       'HM': None,
+       'HR': None,
        'HVM': None,
+       'IS': None,
        'B': None,
        'FM': {
                'Abv': [Top],
@@ -373,36 +374,19 @@ def map_to_use(data):
                # TODO: These don't have UISC assigned in Unicode 13.0.0, but have UIPC
                if 0x0F18 <= U <= 0x0F19 or 0x0F3E <= U <= 0x0F3F: UISC = Vowel_Dependent
 
-               # TODO: https://github.com/harfbuzz/harfbuzz/pull/627
-               if 0x1BF2 <= U <= 0x1BF3: UISC = Nukta; UIPC = Bottom
-
                # TODO: U+1CED should only be allowed after some of
                # the nasalization marks, maybe only for U+1CE9..U+1CF1.
                if U == 0x1CED: UISC = Tone_Mark
 
-               # TODO: https://github.com/microsoft/font-tools/issues/1
-               if U == 0xA982: UISC = Consonant_Succeeding_Repha
-
                values = [k for k,v in items if v(U, UISC, UDI, UGC, AJT)]
                assert len(values) == 1, "%s %s %s %s %s %s" % (hex(U), UISC, UDI, UGC, AJT, values)
                USE = values[0]
 
                # Resolve Indic_Positional_Category
 
-               # TODO: These should die, but have UIPC in Unicode 13.0.0
-               if U in [0x953, 0x954]: UIPC = Not_Applicable
-
-               # TODO: These are not in USE's override list that we have, nor are they in Unicode 13.0.0
-               if 0xA926 <= U <= 0xA92A: UIPC = Top
                # TODO: https://github.com/harfbuzz/harfbuzz/pull/1037
                #  and https://github.com/harfbuzz/harfbuzz/issues/1631
                if U in [0x11302, 0x11303, 0x114C1]: UIPC = Top
-               if 0x1CF8 <= U <= 0x1CF9: UIPC = Top
-
-               # TODO: https://github.com/harfbuzz/harfbuzz/pull/982
-               # also  https://github.com/harfbuzz/harfbuzz/issues/1012
-               if 0x1112A <= U <= 0x1112B: UIPC = Top
-               if 0x11131 <= U <= 0x11132: UIPC = Top
 
                assert (UIPC in [Not_Applicable, Visual_Order_Left] or U == 0x0F7F or
                        USE in use_positions), "%s %s %s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UDI, UGC, AJT)
@@ -416,8 +400,7 @@ def map_to_use(data):
                out[U] = (USE, UBlock)
        return out
 
-defaults = ('O', 'No_Block')
-data = map_to_use(data)
+use_data = map_to_use(combined)
 
 print ("/* == Start of generated table == */")
 print ("/*")
@@ -432,18 +415,18 @@ for h in headers:
                print (" * %s" % (l.strip()))
 print (" */")
 print ()
-print ("#ifndef HB_OT_SHAPE_COMPLEX_USE_TABLE_HH")
-print ("#define HB_OT_SHAPE_COMPLEX_USE_TABLE_HH")
+print ("#ifndef HB_OT_SHAPER_USE_TABLE_HH")
+print ("#define HB_OT_SHAPER_USE_TABLE_HH")
 print ()
 print ('#include "hb.hh"')
 print ()
-print ('#include "hb-ot-shape-complex-use-machine.hh"')
+print ('#include "hb-ot-shaper-use-machine.hh"')
 print ()
 
 total = 0
 used = 0
 last_block = None
-def print_block (block, start, end, data):
+def print_block (block, start, end, use_data):
        global total, used, last_block
        if block and block != last_block:
                print ()
@@ -458,17 +441,23 @@ def print_block (block, start, end, data):
                if u % 16 == 0:
                        print ()
                        print ("  /* %04X */" % u, end='')
-               if u in data:
+               if u in use_data:
                        num += 1
-               d = data.get (u, defaults)
-               print ("%6s," % d[0], end='')
+               d = use_data.get (u)
+               if d is not None:
+                       d = d[0]
+               elif u in unicode_data[4]:
+                       d = 'O'
+               else:
+                       d = 'WJ'
+               print ("%6s," % d, end='')
 
        total += end - start + 1
        used += num
        if block:
                last_block = block
 
-uu = sorted (data.keys ())
+uu = sorted (use_data.keys ())
 
 last = -100000
 num = 0
@@ -487,61 +476,34 @@ for k,v in sorted(use_positions.items()):
                print ("#define %s      USE(%s)" % (tag, tag))
 print ('#pragma GCC diagnostic pop')
 print ("")
-print ("static const uint8_t use_table[] = {")
-for u in uu:
-       if u <= last:
-               continue
-       if data[u][0] == 'O':
-               continue
-       block = data[u][1]
-
-       start = u//8*8
-       end = start+1
-       while end in uu and block == data[end][1]:
-               end += 1
-       end = (end-1)//8*8 + 7
-
-       if start != last + 1:
-               if start - last <= 1+16*3:
-                       print_block (None, last+1, start-1, data)
-               else:
-                       if last >= 0:
-                               ends.append (last + 1)
-                               offset += ends[-1] - starts[-1]
-                       print ()
-                       print ()
-                       print ("#define use_offset_0x%04xu %d" % (start, offset))
-                       starts.append (start)
 
-       print_block (block, start, end, data)
-       last = end
-ends.append (last + 1)
-offset += ends[-1] - starts[-1]
-print ()
-print ()
-occupancy = used * 100. / total
-page_bits = 12
-print ("}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy))
-print ()
-print ("static inline uint8_t")
-print ("hb_use_get_category (hb_codepoint_t u)")
-print ("{")
-print ("  switch (u >> %d)" % page_bits)
-print ("  {")
-pages = set([u>>page_bits for u in starts+ends])
-for p in sorted(pages):
-       print ("    case 0x%0Xu:" % p)
-       for (start,end) in zip (starts, ends):
-               if p not in [start>>page_bits, end>>page_bits]: continue
-               offset = "use_offset_0x%04xu" % start
-               print ("      if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return use_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset))
-       print ("      break;")
-       print ("")
-print ("    default:")
-print ("      break;")
-print ("  }")
-print ("  return USE(O);")
-print ("}")
+
+import packTab
+data = {u:v[0] for u,v in use_data.items()}
+
+DEFAULT = 5
+COMPACT = 9
+for compression in (DEFAULT, COMPACT):
+
+    logging.info('  Compression=%d:' % compression)
+    print()
+    if compression == DEFAULT:
+        print('#ifndef HB_OPTIMIZE_SIZE')
+    elif compression == COMPACT:
+        print('#else')
+    else:
+        assert False
+    print()
+
+    code = packTab.Code('hb_use')
+    sol = packTab.pack_table(data, compression=compression, default='O')
+    logging.info('      FullCost=%d' % (sol.fullCost))
+    sol.genCode(code, f'get_category')
+    code.print_c(linkage='static inline')
+    print ()
+
+print('#endif')
+
 print ()
 for k in sorted(use_mapping.keys()):
        if k in use_positions and use_positions[k]: continue
@@ -553,9 +515,5 @@ for k,v in sorted(use_positions.items()):
                print ("#undef %s" % tag)
 print ()
 print ()
-print ("#endif /* HB_OT_SHAPE_COMPLEX_USE_TABLE_HH */")
+print ("#endif /* HB_OT_SHAPER_USE_TABLE_HH */")
 print ("/* == End of generated table == */")
-
-# Maintain at least 50% occupancy in the table */
-if occupancy < 50:
-       raise Exception ("Table too sparse, please investigate: ", occupancy)
index 42afd28..3c1f621 100755 (executable)
@@ -5,7 +5,7 @@
 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``.
+``hb_ot_shaper_t``.
 
 usage: ./gen-vowel-constraints.py ms-use/IndicShapingInvalidCluster.txt Scripts.txt
 
@@ -166,7 +166,7 @@ print ('#include "hb.hh"')
 print ()
 print ('#ifndef HB_NO_OT_SHAPE')
 print ()
-print ('#include "hb-ot-shape-complex-vowel-constraints.hh"')
+print ('#include "hb-ot-shaper-vowel-constraints.hh"')
 print ()
 print ('static void')
 print ('_output_dotted_circle (hb_buffer_t *buffer)')
@@ -188,7 +188,7 @@ print ('_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB
 print ('\t\t\t\t       hb_buffer_t              *buffer,')
 print ('\t\t\t\t       hb_font_t                *font HB_UNUSED)')
 print ('{')
-print ('#ifdef HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS')
+print ('#ifdef HB_NO_OT_SHAPER_VOWEL_CONSTRAINTS')
 print ('  return;')
 print ('#endif')
 print ('  if (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)')
diff --git a/src/graph/classdef-graph.hh b/src/graph/classdef-graph.hh
new file mode 100644 (file)
index 0000000..c143288
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Copyright © 2022  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
+ */
+
+#include "graph.hh"
+#include "../hb-ot-layout-common.hh"
+
+#ifndef GRAPH_CLASSDEF_GRAPH_HH
+#define GRAPH_CLASSDEF_GRAPH_HH
+
+namespace graph {
+
+struct ClassDefFormat1 : public OT::ClassDefFormat1_3<SmallTypes>
+{
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    constexpr unsigned min_size = OT::ClassDefFormat1_3<SmallTypes>::min_size;
+    if (vertex_len < min_size) return false;
+    return vertex_len >= min_size + classValue.get_size () - classValue.len.get_size ();
+  }
+};
+
+struct ClassDefFormat2 : public OT::ClassDefFormat2_4<SmallTypes>
+{
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    constexpr unsigned min_size = OT::ClassDefFormat2_4<SmallTypes>::min_size;
+    if (vertex_len < min_size) return false;
+    return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size ();
+  }
+};
+
+struct ClassDef : public OT::ClassDef
+{
+  template<typename It>
+  static bool add_class_def (gsubgpos_graph_context_t& c,
+                             unsigned parent_id,
+                             unsigned link_position,
+                             It glyph_and_class,
+                             unsigned max_size)
+  {
+    unsigned class_def_prime_id = c.graph.new_node (nullptr, nullptr);
+    auto& class_def_prime_vertex = c.graph.vertices_[class_def_prime_id];
+    if (!make_class_def (c, glyph_and_class, class_def_prime_id, max_size))
+      return false;
+
+    auto* class_def_link = c.graph.vertices_[parent_id].obj.real_links.push ();
+    class_def_link->width = SmallTypes::size;
+    class_def_link->objidx = class_def_prime_id;
+    class_def_link->position = link_position;
+    class_def_prime_vertex.add_parent (parent_id);
+
+    return true;
+  }
+
+  template<typename It>
+  static bool make_class_def (gsubgpos_graph_context_t& c,
+                              It glyph_and_class,
+                              unsigned dest_obj,
+                              unsigned max_size)
+  {
+    char* buffer = (char*) hb_calloc (1, max_size);
+    hb_serialize_context_t serializer (buffer, max_size);
+    OT::ClassDef_serialize (&serializer, glyph_and_class);
+    serializer.end_serialize ();
+    if (serializer.in_error ())
+    {
+      hb_free (buffer);
+      return false;
+    }
+
+    hb_bytes_t class_def_copy = serializer.copy_bytes ();
+    if (!class_def_copy.arrayZ) return false;
+    // Give ownership to the context, it will cleanup the buffer.
+    if (!c.add_buffer ((char *) class_def_copy.arrayZ))
+    {
+      hb_free ((char *) class_def_copy.arrayZ);
+      return false;
+    }
+
+    auto& obj = c.graph.vertices_[dest_obj].obj;
+    obj.head = (char *) class_def_copy.arrayZ;
+    obj.tail = obj.head + class_def_copy.length;
+
+    hb_free (buffer);
+    return true;
+  }
+
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    if (vertex_len < OT::ClassDef::min_size) return false;
+    switch (u.format)
+    {
+    case 1: return ((ClassDefFormat1*)this)->sanitize (vertex);
+    case 2: return ((ClassDefFormat2*)this)->sanitize (vertex);
+#ifndef HB_NO_BEYOND_64K
+    // Not currently supported
+    case 3:
+    case 4:
+#endif
+    default: return false;
+    }
+  }
+};
+
+
+struct class_def_size_estimator_t
+{
+  template<typename It>
+  class_def_size_estimator_t (It glyph_and_class)
+      : gids_consecutive (true), num_ranges_per_class (), glyphs_per_class ()
+  {
+    unsigned last_gid = (unsigned) -1;
+    for (auto p : + glyph_and_class)
+    {
+      unsigned gid = p.first;
+      unsigned klass = p.second;
+
+      if (last_gid != (unsigned) -1 && gid != last_gid + 1)
+        gids_consecutive = false;
+      last_gid = gid;
+
+      hb_set_t* glyphs;
+      if (glyphs_per_class.has (klass, &glyphs) && glyphs) {
+        glyphs->add (gid);
+        continue;
+      }
+
+      hb_set_t new_glyphs;
+      new_glyphs.add (gid);
+      glyphs_per_class.set (klass, std::move (new_glyphs));
+    }
+
+    if (in_error ()) return;
+
+    for (unsigned klass : glyphs_per_class.keys ())
+    {
+      if (!klass) continue; // class 0 doesn't get encoded.
+
+      const hb_set_t& glyphs = glyphs_per_class.get (klass);
+      hb_codepoint_t start = HB_SET_VALUE_INVALID;
+      hb_codepoint_t end = HB_SET_VALUE_INVALID;
+
+      unsigned count = 0;
+      while (glyphs.next_range (&start, &end))
+        count++;
+
+      num_ranges_per_class.set (klass, count);
+    }
+  }
+
+  // Incremental increase in the Coverage and ClassDef table size
+  // (worst case) if all glyphs associated with 'klass' were added.
+  unsigned incremental_coverage_size (unsigned klass) const
+  {
+    // Coverage takes 2 bytes per glyph worst case,
+    return 2 * glyphs_per_class.get (klass).get_population ();
+  }
+
+  // Incremental increase in the Coverage and ClassDef table size
+  // (worst case) if all glyphs associated with 'klass' were added.
+  unsigned incremental_class_def_size (unsigned klass) const
+  {
+    // ClassDef takes 6 bytes per range
+    unsigned class_def_2_size = 6 * num_ranges_per_class.get (klass);
+    if (gids_consecutive)
+    {
+      // ClassDef1 takes 2 bytes per glyph, but only can be used
+      // when gids are consecutive.
+      return hb_min (2 * glyphs_per_class.get (klass).get_population (), class_def_2_size);
+    }
+
+    return class_def_2_size;
+  }
+
+  bool in_error ()
+  {
+    if (num_ranges_per_class.in_error ()) return true;
+    if (glyphs_per_class.in_error ()) return true;
+
+    for (const hb_set_t& s : glyphs_per_class.values ())
+    {
+      if (s.in_error ()) return true;
+    }
+    return false;
+  }
+
+ private:
+  bool gids_consecutive;
+  hb_hashmap_t<unsigned, unsigned> num_ranges_per_class;
+  hb_hashmap_t<unsigned, hb_set_t> glyphs_per_class;
+};
+
+
+}
+
+#endif  // GRAPH_CLASSDEF_GRAPH_HH
diff --git a/src/graph/coverage-graph.hh b/src/graph/coverage-graph.hh
new file mode 100644 (file)
index 0000000..4f44e07
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright © 2022  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
+ */
+
+#include "graph.hh"
+#include "../OT/Layout/Common/Coverage.hh"
+
+#ifndef GRAPH_COVERAGE_GRAPH_HH
+#define GRAPH_COVERAGE_GRAPH_HH
+
+namespace graph {
+
+struct CoverageFormat1 : public OT::Layout::Common::CoverageFormat1_3<SmallTypes>
+{
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    constexpr unsigned min_size = OT::Layout::Common::CoverageFormat1_3<SmallTypes>::min_size;
+    if (vertex_len < min_size) return false;
+    return vertex_len >= min_size + glyphArray.get_size () - glyphArray.len.get_size ();
+  }
+};
+
+struct CoverageFormat2 : public OT::Layout::Common::CoverageFormat2_4<SmallTypes>
+{
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    constexpr unsigned min_size = OT::Layout::Common::CoverageFormat2_4<SmallTypes>::min_size;
+    if (vertex_len < min_size) return false;
+    return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size ();
+  }
+};
+
+struct Coverage : public OT::Layout::Common::Coverage
+{
+  static Coverage* clone_coverage (gsubgpos_graph_context_t& c,
+                                   unsigned coverage_id,
+                                   unsigned new_parent_id,
+                                   unsigned link_position,
+                                   unsigned start, unsigned end)
+
+  {
+    unsigned coverage_size = c.graph.vertices_[coverage_id].table_size ();
+    auto& coverage_v = c.graph.vertices_[coverage_id];
+    Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
+    if (!coverage_table || !coverage_table->sanitize (coverage_v))
+      return nullptr;
+
+    auto new_coverage =
+        + hb_zip (coverage_table->iter (), hb_range ())
+        | hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) {
+          return p.second >= start && p.second < end;
+        })
+        | hb_map_retains_sorting (hb_first)
+        ;
+
+    return add_coverage (c, new_parent_id, link_position, new_coverage, coverage_size);
+  }
+
+  template<typename It>
+  static Coverage* add_coverage (gsubgpos_graph_context_t& c,
+                                 unsigned parent_id,
+                                 unsigned link_position,
+                                 It glyphs,
+                                 unsigned max_size)
+  {
+    unsigned coverage_prime_id = c.graph.new_node (nullptr, nullptr);
+    auto& coverage_prime_vertex = c.graph.vertices_[coverage_prime_id];
+    if (!make_coverage (c, glyphs, coverage_prime_id, max_size))
+      return nullptr;
+
+    auto* coverage_link = c.graph.vertices_[parent_id].obj.real_links.push ();
+    coverage_link->width = SmallTypes::size;
+    coverage_link->objidx = coverage_prime_id;
+    coverage_link->position = link_position;
+    coverage_prime_vertex.add_parent (parent_id);
+
+    return (Coverage*) coverage_prime_vertex.obj.head;
+  }
+
+  template<typename It>
+  static bool make_coverage (gsubgpos_graph_context_t& c,
+                             It glyphs,
+                             unsigned dest_obj,
+                             unsigned max_size)
+  {
+    char* buffer = (char*) hb_calloc (1, max_size);
+    hb_serialize_context_t serializer (buffer, max_size);
+    OT::Layout::Common::Coverage_serialize (&serializer, glyphs);
+    serializer.end_serialize ();
+    if (serializer.in_error ())
+    {
+      hb_free (buffer);
+      return false;
+    }
+
+    hb_bytes_t coverage_copy = serializer.copy_bytes ();
+    if (!coverage_copy.arrayZ) return false;
+    // Give ownership to the context, it will cleanup the buffer.
+    if (!c.add_buffer ((char *) coverage_copy.arrayZ))
+    {
+      hb_free ((char *) coverage_copy.arrayZ);
+      return false;
+    }
+
+    auto& obj = c.graph.vertices_[dest_obj].obj;
+    obj.head = (char *) coverage_copy.arrayZ;
+    obj.tail = obj.head + coverage_copy.length;
+
+    hb_free (buffer);
+    return true;
+  }
+
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    if (vertex_len < OT::Layout::Common::Coverage::min_size) return false;
+    switch (u.format)
+    {
+    case 1: return ((CoverageFormat1*)this)->sanitize (vertex);
+    case 2: return ((CoverageFormat2*)this)->sanitize (vertex);
+#ifndef HB_NO_BEYOND_64K
+    // Not currently supported
+    case 3:
+    case 4:
+#endif
+    default: return false;
+    }
+  }
+};
+
+
+}
+
+#endif  // GRAPH_COVERAGE_GRAPH_HH
diff --git a/src/graph/graph.hh b/src/graph/graph.hh
new file mode 100644 (file)
index 0000000..2b4e1b2
--- /dev/null
@@ -0,0 +1,1517 @@
+/*
+ * Copyright © 2022  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
+ */
+
+#include "../hb-set.hh"
+#include "../hb-priority-queue.hh"
+#include "../hb-serialize.hh"
+
+#ifndef GRAPH_GRAPH_HH
+#define GRAPH_GRAPH_HH
+
+namespace graph {
+
+/**
+ * Represents a serialized table in the form of a graph.
+ * Provides methods for modifying and reordering the graph.
+ */
+struct graph_t
+{
+  struct vertex_t
+  {
+    hb_serialize_context_t::object_t obj;
+    int64_t distance = 0 ;
+    unsigned space = 0 ;
+    unsigned start = 0;
+    unsigned end = 0;
+    unsigned priority = 0;
+    private:
+    unsigned incoming_edges_ = 0;
+    unsigned single_parent = (unsigned) -1;
+    hb_hashmap_t<unsigned, unsigned> parents;
+    public:
+
+    auto parents_iter () const HB_AUTO_RETURN
+    (
+      hb_concat (
+       hb_iter (&single_parent, single_parent != (unsigned) -1),
+       parents.keys_ref ()
+      )
+    )
+
+    bool in_error () const
+    {
+      return parents.in_error ();
+    }
+
+    bool link_positions_valid (unsigned num_objects, bool removed_nil)
+    {
+      hb_set_t assigned_bytes;
+      for (const auto& l : obj.real_links)
+      {
+        if (l.objidx >= num_objects
+            || (removed_nil && !l.objidx))
+        {
+          DEBUG_MSG (SUBSET_REPACK, nullptr,
+                     "Invalid graph. Invalid object index.");
+          return false;
+        }
+
+        unsigned start = l.position;
+        unsigned end = start + l.width - 1;
+
+        if (unlikely (l.width < 2 || l.width > 4))
+        {
+          DEBUG_MSG (SUBSET_REPACK, nullptr,
+                     "Invalid graph. Invalid link width.");
+          return false;
+        }
+
+        if (unlikely (end >= table_size ()))
+        {
+          DEBUG_MSG (SUBSET_REPACK, nullptr,
+                     "Invalid graph. Link position is out of bounds.");
+          return false;
+        }
+
+        if (unlikely (assigned_bytes.intersects (start, end)))
+        {
+          DEBUG_MSG (SUBSET_REPACK, nullptr,
+                     "Invalid graph. Found offsets whose positions overlap.");
+          return false;
+        }
+
+        assigned_bytes.add_range (start, end);
+      }
+
+      return !assigned_bytes.in_error ();
+    }
+
+    void normalize ()
+    {
+      obj.real_links.qsort ();
+      for (auto& l : obj.real_links)
+      {
+        for (unsigned i = 0; i < l.width; i++)
+        {
+          obj.head[l.position + i] = 0;
+        }
+      }
+    }
+
+    bool equals (const vertex_t& other,
+                 const graph_t& graph,
+                 const graph_t& other_graph,
+                 unsigned depth) const
+    {
+      if (!(as_bytes () == other.as_bytes ()))
+      {
+        DEBUG_MSG (SUBSET_REPACK, nullptr,
+                   "vertex [%lu] bytes != [%lu] bytes, depth = %u",
+                   (unsigned long) table_size (),
+                   (unsigned long) other.table_size (),
+                   depth);
+
+        auto a = as_bytes ();
+        auto b = other.as_bytes ();
+        while (a || b)
+        {
+          DEBUG_MSG (SUBSET_REPACK, nullptr,
+                     "  0x%x %s 0x%x", (unsigned) *a, (*a == *b) ? "==" : "!=", (unsigned) *b);
+          a++;
+          b++;
+        }
+        return false;
+      }
+
+      return links_equal (obj.real_links, other.obj.real_links, graph, other_graph, depth);
+    }
+
+    hb_bytes_t as_bytes () const
+    {
+      return hb_bytes_t (obj.head, table_size ());
+    }
+
+    friend void swap (vertex_t& a, vertex_t& b)
+    {
+      hb_swap (a.obj, b.obj);
+      hb_swap (a.distance, b.distance);
+      hb_swap (a.space, b.space);
+      hb_swap (a.single_parent, b.single_parent);
+      hb_swap (a.parents, b.parents);
+      hb_swap (a.incoming_edges_, b.incoming_edges_);
+      hb_swap (a.start, b.start);
+      hb_swap (a.end, b.end);
+      hb_swap (a.priority, b.priority);
+    }
+
+    hb_hashmap_t<unsigned, unsigned>
+    position_to_index_map () const
+    {
+      hb_hashmap_t<unsigned, unsigned> result;
+
+      result.alloc (obj.real_links.length);
+      for (const auto& l : obj.real_links) {
+        result.set (l.position, l.objidx);
+      }
+
+      return result;
+    }
+
+    bool is_shared () const
+    {
+      return parents.get_population () > 1;
+    }
+
+    unsigned incoming_edges () const
+    {
+      if (HB_DEBUG_SUBSET_REPACK)
+       {
+       assert (incoming_edges_ == (single_parent != (unsigned) -1) +
+               (parents.values_ref () | hb_reduce (hb_add, 0)));
+       }
+      return incoming_edges_;
+    }
+
+    void reset_parents ()
+    {
+      incoming_edges_ = 0;
+      single_parent = (unsigned) -1;
+      parents.reset ();
+    }
+
+    void add_parent (unsigned parent_index)
+    {
+      assert (parent_index != (unsigned) -1);
+      if (incoming_edges_ == 0)
+      {
+       single_parent = parent_index;
+       incoming_edges_ = 1;
+       return;
+      }
+      else if (single_parent != (unsigned) -1)
+      {
+        assert (incoming_edges_ == 1);
+       if (!parents.set (single_parent, 1))
+         return;
+       single_parent = (unsigned) -1;
+      }
+
+      unsigned *v;
+      if (parents.has (parent_index, &v))
+      {
+        (*v)++;
+       incoming_edges_++;
+      }
+      else if (parents.set (parent_index, 1))
+       incoming_edges_++;
+    }
+
+    void remove_parent (unsigned parent_index)
+    {
+      if (parent_index == single_parent)
+      {
+       single_parent = (unsigned) -1;
+       incoming_edges_--;
+       return;
+      }
+
+      unsigned *v;
+      if (parents.has (parent_index, &v))
+      {
+       incoming_edges_--;
+       if (*v > 1)
+         (*v)--;
+       else
+         parents.del (parent_index);
+
+       if (incoming_edges_ == 1)
+       {
+         single_parent = *parents.keys ();
+         parents.reset ();
+       }
+      }
+    }
+
+    void remove_real_link (unsigned child_index, const void* offset)
+    {
+      unsigned count = obj.real_links.length;
+      for (unsigned i = 0; i < count; i++)
+      {
+        auto& link = obj.real_links.arrayZ[i];
+        if (link.objidx != child_index)
+          continue;
+
+        if ((obj.head + link.position) != offset)
+          continue;
+
+        obj.real_links.remove_unordered (i);
+        return;
+      }
+    }
+
+    bool remap_parents (const hb_vector_t<unsigned>& id_map)
+    {
+      if (single_parent != (unsigned) -1)
+      {
+        assert (single_parent < id_map.length);
+       single_parent = id_map[single_parent];
+       return true;
+      }
+
+      hb_hashmap_t<unsigned, unsigned> new_parents;
+      new_parents.alloc (parents.get_population ());
+      for (auto _ : parents)
+      {
+       assert (_.first < id_map.length);
+       assert (!new_parents.has (id_map[_.first]));
+       new_parents.set (id_map[_.first], _.second);
+      }
+
+      if (parents.in_error() || new_parents.in_error ())
+        return false;
+
+      parents = std::move (new_parents);
+      return true;
+    }
+
+    void remap_parent (unsigned old_index, unsigned new_index)
+    {
+      if (single_parent != (unsigned) -1)
+      {
+        if (single_parent == old_index)
+         single_parent = new_index;
+        return;
+      }
+
+      const unsigned *pv;
+      if (parents.has (old_index, &pv))
+      {
+        unsigned v = *pv;
+       if (!parents.set (new_index, v))
+          incoming_edges_ -= v;
+       parents.del (old_index);
+
+        if (incoming_edges_ == 1)
+       {
+         single_parent = *parents.keys ();
+         parents.reset ();
+       }
+      }
+    }
+
+    bool is_leaf () const
+    {
+      return !obj.real_links.length && !obj.virtual_links.length;
+    }
+
+    bool raise_priority ()
+    {
+      if (has_max_priority ()) return false;
+      priority++;
+      return true;
+    }
+
+    bool has_max_priority () const {
+      return priority >= 3;
+    }
+
+    size_t table_size () const {
+      return obj.tail - obj.head;
+    }
+
+    int64_t modified_distance (unsigned order) const
+    {
+      // TODO(garretrieger): once priority is high enough, should try
+      // setting distance = 0 which will force to sort immediately after
+      // it's parent where possible.
+
+      int64_t modified_distance =
+          hb_min (hb_max(distance + distance_modifier (), 0), 0x7FFFFFFFFFF);
+      if (has_max_priority ()) {
+        modified_distance = 0;
+      }
+      return (modified_distance << 18) | (0x003FFFF & order);
+    }
+
+    int64_t distance_modifier () const
+    {
+      if (!priority) return 0;
+      int64_t table_size = obj.tail - obj.head;
+
+      if (priority == 1)
+        return -table_size / 2;
+
+      return -table_size;
+    }
+
+   private:
+    bool links_equal (const hb_vector_t<hb_serialize_context_t::object_t::link_t>& this_links,
+                      const hb_vector_t<hb_serialize_context_t::object_t::link_t>& other_links,
+                      const graph_t& graph,
+                      const graph_t& other_graph,
+                      unsigned depth) const
+    {
+      auto a = this_links.iter ();
+      auto b = other_links.iter ();
+
+      while (a && b)
+      {
+        const auto& link_a = *a;
+        const auto& link_b = *b;
+
+        if (link_a.width != link_b.width ||
+            link_a.is_signed != link_b.is_signed ||
+            link_a.whence != link_b.whence ||
+            link_a.position != link_b.position ||
+            link_a.bias != link_b.bias)
+          return false;
+
+        if (!graph.vertices_[link_a.objidx].equals (
+                other_graph.vertices_[link_b.objidx], graph, other_graph, depth + 1))
+          return false;
+
+        a++;
+        b++;
+      }
+
+      if (bool (a) != bool (b))
+        return false;
+
+      return true;
+    }
+  };
+
+  template <typename T>
+  struct vertex_and_table_t
+  {
+    vertex_and_table_t () : index (0), vertex (nullptr), table (nullptr)
+    {}
+
+    unsigned index;
+    vertex_t* vertex;
+    T* table;
+
+    operator bool () {
+       return table && vertex;
+    }
+  };
+
+  /*
+   * A topological sorting of an object graph. Ordered
+   * in reverse serialization order (first object in the
+   * serialization is at the end of the list). This matches
+   * the 'packed' object stack used internally in the
+   * serializer
+   */
+  template<typename T>
+  graph_t (const T& objects)
+      : parents_invalid (true),
+        distance_invalid (true),
+        positions_invalid (true),
+        successful (true),
+        buffers ()
+  {
+    num_roots_for_space_.push (1);
+    bool removed_nil = false;
+    vertices_.alloc (objects.length);
+    vertices_scratch_.alloc (objects.length);
+    unsigned count = objects.length;
+    for (unsigned i = 0; i < count; i++)
+    {
+      // If this graph came from a serialization buffer object 0 is the
+      // nil object. We don't need it for our purposes here so drop it.
+      if (i == 0 && !objects.arrayZ[i])
+      {
+        removed_nil = true;
+        continue;
+      }
+
+      vertex_t* v = vertices_.push ();
+      if (check_success (!vertices_.in_error ()))
+        v->obj = *objects.arrayZ[i];
+
+      check_success (v->link_positions_valid (count, removed_nil));
+
+      if (!removed_nil) continue;
+      // Fix indices to account for removed nil object.
+      for (auto& l : v->obj.all_links_writer ()) {
+        l.objidx--;
+      }
+    }
+  }
+
+  ~graph_t ()
+  {
+    for (char* b : buffers)
+      hb_free (b);
+  }
+
+  bool operator== (const graph_t& other) const
+  {
+    return root ().equals (other.root (), *this, other, 0);
+  }
+
+  void print () const {
+    for (int i = vertices_.length - 1; i >= 0; i--)
+    {
+      const auto& v = vertices_[i];
+      printf("%d: %u [", i, (unsigned int)v.table_size());
+      for (const auto &l : v.obj.real_links) {
+        printf("%u, ", l.objidx);
+      }
+      printf("]\n");
+    }
+  }
+
+  // Sorts links of all objects in a consistent manner and zeroes all offsets.
+  void normalize ()
+  {
+    for (auto& v : vertices_.writer ())
+      v.normalize ();
+  }
+
+  bool in_error () const
+  {
+    return !successful ||
+        vertices_.in_error () ||
+        num_roots_for_space_.in_error ();
+  }
+
+  const vertex_t& root () const
+  {
+    return vertices_[root_idx ()];
+  }
+
+  unsigned root_idx () const
+  {
+    // Object graphs are in reverse order, the first object is at the end
+    // of the vector. Since the graph is topologically sorted it's safe to
+    // assume the first object has no incoming edges.
+    return vertices_.length - 1;
+  }
+
+  const hb_serialize_context_t::object_t& object (unsigned i) const
+  {
+    return vertices_[i].obj;
+  }
+
+  bool add_buffer (char* buffer)
+  {
+    buffers.push (buffer);
+    return !buffers.in_error ();
+  }
+
+  /*
+   * Adds a 16 bit link from parent_id to child_id
+   */
+  template<typename T>
+  void add_link (T* offset,
+                 unsigned parent_id,
+                 unsigned child_id)
+  {
+    auto& v = vertices_[parent_id];
+    auto* link = v.obj.real_links.push ();
+    link->width = 2;
+    link->objidx = child_id;
+    link->position = (char*) offset - (char*) v.obj.head;
+    vertices_[child_id].add_parent (parent_id);
+  }
+
+  /*
+   * Generates a new topological sorting of graph ordered by the shortest
+   * distance to each node if positions are marked as invalid.
+   */
+  void sort_shortest_distance_if_needed ()
+  {
+    if (!positions_invalid) return;
+    sort_shortest_distance ();
+  }
+
+
+  /*
+   * Generates a new topological sorting of graph ordered by the shortest
+   * distance to each node.
+   */
+  void sort_shortest_distance ()
+  {
+    positions_invalid = true;
+
+    if (vertices_.length <= 1) {
+      // Graph of 1 or less doesn't need sorting.
+      return;
+    }
+
+    update_distances ();
+
+    hb_priority_queue_t<int64_t> queue;
+    hb_vector_t<vertex_t> &sorted_graph = vertices_scratch_;
+    if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return;
+    hb_vector_t<unsigned> id_map;
+    if (unlikely (!check_success (id_map.resize (vertices_.length)))) return;
+
+    hb_vector_t<unsigned> removed_edges;
+    if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return;
+    update_parents ();
+
+    queue.insert (root ().modified_distance (0), root_idx ());
+    int new_id = root_idx ();
+    unsigned order = 1;
+    while (!queue.in_error () && !queue.is_empty ())
+    {
+      unsigned next_id = queue.pop_minimum().second;
+
+      sorted_graph[new_id] = std::move (vertices_[next_id]);
+      const vertex_t& next = sorted_graph[new_id];
+
+      if (unlikely (!check_success(new_id >= 0))) {
+        // We are out of ids. Which means we've visited a node more than once.
+        // This graph contains a cycle which is not allowed.
+        DEBUG_MSG (SUBSET_REPACK, nullptr, "Invalid graph. Contains cycle.");
+        return;
+      }
+
+      id_map[next_id] = new_id--;
+
+      for (const auto& link : next.obj.all_links ()) {
+        removed_edges[link.objidx]++;
+        if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx]))
+          // Add the order that the links were encountered to the priority.
+          // This ensures that ties between priorities objects are broken in a consistent
+          // way. More specifically this is set up so that if a set of objects have the same
+          // distance they'll be added to the topological order in the order that they are
+          // referenced from the parent object.
+          queue.insert (vertices_[link.objidx].modified_distance (order++),
+                        link.objidx);
+      }
+    }
+
+    check_success (!queue.in_error ());
+    check_success (!sorted_graph.in_error ());
+
+    check_success (remap_all_obj_indices (id_map, &sorted_graph));
+    vertices_ = std::move (sorted_graph);
+
+    if (!check_success (new_id == -1))
+      print_orphaned_nodes ();
+  }
+
+  /*
+   * Finds the set of nodes (placed into roots) that should be assigned unique spaces.
+   * More specifically this looks for the top most 24 bit or 32 bit links in the graph.
+   * Some special casing is done that is specific to the layout of GSUB/GPOS tables.
+   */
+  void find_space_roots (hb_set_t& visited, hb_set_t& roots)
+  {
+    int root_index = (int) root_idx ();
+    for (int i = root_index; i >= 0; i--)
+    {
+      if (visited.has (i)) continue;
+
+      // Only real links can form 32 bit spaces
+      for (auto& l : vertices_[i].obj.real_links)
+      {
+        if (l.is_signed || l.width < 3)
+          continue;
+
+        if (i == root_index && l.width == 3)
+          // Ignore 24bit links from the root node, this skips past the single 24bit
+          // pointer to the lookup list.
+          continue;
+
+        if (l.width == 3)
+        {
+          // A 24bit offset forms a root, unless there is 32bit offsets somewhere
+          // in it's subgraph, then those become the roots instead. This is to make sure
+          // that extension subtables beneath a 24bit lookup become the spaces instead
+          // of the offset to the lookup.
+          hb_set_t sub_roots;
+          find_32bit_roots (l.objidx, sub_roots);
+          if (sub_roots) {
+            for (unsigned sub_root_idx : sub_roots) {
+              roots.add (sub_root_idx);
+              find_subgraph (sub_root_idx, visited);
+            }
+            continue;
+          }
+        }
+
+        roots.add (l.objidx);
+        find_subgraph (l.objidx, visited);
+      }
+    }
+  }
+
+  template <typename T, typename ...Ts>
+  vertex_and_table_t<T> as_table (unsigned parent, const void* offset, Ts... ds)
+  {
+    return as_table_from_index<T> (index_for_offset (parent, offset), std::forward<Ts>(ds)...);
+  }
+
+  template <typename T, typename ...Ts>
+  vertex_and_table_t<T> as_mutable_table (unsigned parent, const void* offset, Ts... ds)
+  {
+    return as_table_from_index<T> (mutable_index_for_offset (parent, offset), std::forward<Ts>(ds)...);
+  }
+
+  template <typename T, typename ...Ts>
+  vertex_and_table_t<T> as_table_from_index (unsigned index, Ts... ds)
+  {
+    if (index >= vertices_.length)
+      return vertex_and_table_t<T> ();
+
+    vertex_and_table_t<T> r;
+    r.vertex = &vertices_[index];
+    r.table = (T*) r.vertex->obj.head;
+    r.index = index;
+    if (!r.table)
+      return vertex_and_table_t<T> ();
+
+    if (!r.table->sanitize (*(r.vertex), std::forward<Ts>(ds)...))
+      return vertex_and_table_t<T> ();
+
+    return r;
+  }
+
+  // Finds the object id of the object pointed to by the offset at 'offset'
+  // within object[node_idx].
+  unsigned index_for_offset (unsigned node_idx, const void* offset) const
+  {
+    const auto& node = object (node_idx);
+    if (offset < node.head || offset >= node.tail) return -1;
+
+    unsigned count = node.real_links.length;
+    for (unsigned i = 0; i < count; i++)
+    {
+      // Use direct access for increased performance, this is a hot method.
+      const auto& link = node.real_links.arrayZ[i];
+      if (offset != node.head + link.position)
+        continue;
+      return link.objidx;
+    }
+
+    return -1;
+  }
+
+  // Finds the object id of the object pointed to by the offset at 'offset'
+  // within object[node_idx]. Ensures that the returned object is safe to mutate.
+  // That is, if the original child object is shared by parents other than node_idx
+  // it will be duplicated and the duplicate will be returned instead.
+  unsigned mutable_index_for_offset (unsigned node_idx, const void* offset)
+  {
+    unsigned child_idx = index_for_offset (node_idx, offset);
+    auto& child = vertices_[child_idx];
+    for (unsigned p : child.parents_iter ())
+    {
+      if (p != node_idx) {
+        return duplicate (node_idx, child_idx);
+      }
+    }
+
+    return child_idx;
+  }
+
+
+  /*
+   * Assign unique space numbers to each connected subgraph of 24 bit and/or 32 bit offset(s).
+   * Currently, this is implemented specifically tailored to the structure of a GPOS/GSUB
+   * (including with 24bit offsets) table.
+   */
+  bool assign_spaces ()
+  {
+    update_parents ();
+
+    hb_set_t visited;
+    hb_set_t roots;
+    find_space_roots (visited, roots);
+
+    // Mark everything not in the subgraphs of the roots as visited. This prevents
+    // subgraphs from being connected via nodes not in those subgraphs.
+    visited.invert ();
+
+    if (!roots) return false;
+
+    while (roots)
+    {
+      uint32_t next = HB_SET_VALUE_INVALID;
+      if (unlikely (!check_success (!roots.in_error ()))) break;
+      if (!roots.next (&next)) break;
+
+      hb_set_t connected_roots;
+      find_connected_nodes (next, roots, visited, connected_roots);
+      if (unlikely (!check_success (!connected_roots.in_error ()))) break;
+
+      isolate_subgraph (connected_roots);
+      if (unlikely (!check_success (!connected_roots.in_error ()))) break;
+
+      unsigned next_space = this->next_space ();
+      num_roots_for_space_.push (0);
+      for (unsigned root : connected_roots)
+      {
+        DEBUG_MSG (SUBSET_REPACK, nullptr, "Subgraph %u gets space %u", root, next_space);
+        vertices_[root].space = next_space;
+        num_roots_for_space_[next_space] = num_roots_for_space_[next_space] + 1;
+        distance_invalid = true;
+        positions_invalid = true;
+      }
+
+      // TODO(grieger): special case for GSUB/GPOS use extension promotions to move 16 bit space
+      //                into the 32 bit space as needed, instead of using isolation.
+    }
+
+
+
+    return true;
+  }
+
+  /*
+   * Isolates the subgraph of nodes reachable from root. Any links to nodes in the subgraph
+   * that originate from outside of the subgraph will be removed by duplicating the linked to
+   * object.
+   *
+   * Indices stored in roots will be updated if any of the roots are duplicated to new indices.
+   */
+  bool isolate_subgraph (hb_set_t& roots)
+  {
+    update_parents ();
+    hb_map_t subgraph;
+
+    // incoming edges to root_idx should be all 32 bit in length so we don't need to de-dup these
+    // set the subgraph incoming edge count to match all of root_idx's incoming edges
+    hb_set_t parents;
+    for (unsigned root_idx : roots)
+    {
+      subgraph.set (root_idx, wide_parents (root_idx, parents));
+      find_subgraph (root_idx, subgraph);
+    }
+    if (subgraph.in_error ())
+      return false;
+
+    unsigned original_root_idx = root_idx ();
+    hb_map_t index_map;
+    bool made_changes = false;
+    for (auto entry : subgraph.iter ())
+    {
+      assert (entry.first < vertices_.length);
+      const auto& node = vertices_[entry.first];
+      unsigned subgraph_incoming_edges = entry.second;
+
+      if (subgraph_incoming_edges < node.incoming_edges ())
+      {
+        // Only  de-dup objects with incoming links from outside the subgraph.
+        made_changes = true;
+        duplicate_subgraph (entry.first, index_map);
+      }
+    }
+
+    if (in_error ())
+      return false;
+
+    if (!made_changes)
+      return false;
+
+    if (original_root_idx != root_idx ()
+        && parents.has (original_root_idx))
+    {
+      // If the root idx has changed since parents was determined, update root idx in parents
+      parents.add (root_idx ());
+      parents.del (original_root_idx);
+    }
+
+    auto new_subgraph =
+        + subgraph.keys ()
+        | hb_map([&] (uint32_t node_idx) {
+          const uint32_t *v;
+          if (index_map.has (node_idx, &v)) return *v;
+          return node_idx;
+        })
+        ;
+
+    remap_obj_indices (index_map, new_subgraph);
+    remap_obj_indices (index_map, parents.iter (), true);
+
+    // Update roots set with new indices as needed.
+    for (auto next : roots)
+    {
+      const uint32_t *v;
+      if (index_map.has (next, &v))
+      {
+        roots.del (next);
+        roots.add (*v);
+      }
+    }
+
+    return true;
+  }
+
+  void find_subgraph (unsigned node_idx, hb_map_t& subgraph)
+  {
+    for (const auto& link : vertices_[node_idx].obj.all_links ())
+    {
+      hb_codepoint_t *v;
+      if (subgraph.has (link.objidx, &v))
+      {
+        (*v)++;
+        continue;
+      }
+      subgraph.set (link.objidx, 1);
+      find_subgraph (link.objidx, subgraph);
+    }
+  }
+
+  void find_subgraph (unsigned node_idx, hb_set_t& subgraph)
+  {
+    if (subgraph.has (node_idx)) return;
+    subgraph.add (node_idx);
+    for (const auto& link : vertices_[node_idx].obj.all_links ())
+      find_subgraph (link.objidx, subgraph);
+  }
+
+  size_t find_subgraph_size (unsigned node_idx, hb_set_t& subgraph, unsigned max_depth = -1)
+  {
+    if (subgraph.has (node_idx)) return 0;
+    subgraph.add (node_idx);
+
+    const auto& o = vertices_[node_idx].obj;
+    size_t size = o.tail - o.head;
+    if (max_depth == 0)
+      return size;
+
+    for (const auto& link : o.all_links ())
+      size += find_subgraph_size (link.objidx, subgraph, max_depth - 1);
+    return size;
+  }
+
+  /*
+   * Finds the topmost children of 32bit offsets in the subgraph starting
+   * at node_idx. Found indices are placed into 'found'.
+   */
+  void find_32bit_roots (unsigned node_idx, hb_set_t& found)
+  {
+    for (const auto& link : vertices_[node_idx].obj.all_links ())
+    {
+      if (!link.is_signed && link.width == 4) {
+        found.add (link.objidx);
+        continue;
+      }
+      find_32bit_roots (link.objidx, found);
+    }
+  }
+
+  /*
+   * Moves the child of old_parent_idx pointed to by old_offset to a new
+   * vertex at the new_offset.
+   */
+  template<typename O>
+  void move_child (unsigned old_parent_idx,
+                   const O* old_offset,
+                   unsigned new_parent_idx,
+                   const O* new_offset)
+  {
+    distance_invalid = true;
+    positions_invalid = true;
+
+    auto& old_v = vertices_[old_parent_idx];
+    auto& new_v = vertices_[new_parent_idx];
+
+    unsigned child_id = index_for_offset (old_parent_idx,
+                                          old_offset);
+
+    auto* new_link = new_v.obj.real_links.push ();
+    new_link->width = O::static_size;
+    new_link->objidx = child_id;
+    new_link->position = (const char*) new_offset - (const char*) new_v.obj.head;
+
+    auto& child = vertices_[child_id];
+    child.add_parent (new_parent_idx);
+
+    old_v.remove_real_link (child_id, old_offset);
+    child.remove_parent (old_parent_idx);
+  }
+
+  /*
+   * duplicates all nodes in the subgraph reachable from node_idx. Does not re-assign
+   * links. index_map is updated with mappings from old id to new id. If a duplication has already
+   * been performed for a given index, then it will be skipped.
+   */
+  void duplicate_subgraph (unsigned node_idx, hb_map_t& index_map)
+  {
+    if (index_map.has (node_idx))
+      return;
+
+    unsigned clone_idx = duplicate (node_idx);
+    if (!check_success (clone_idx != (unsigned) -1))
+      return;
+
+    index_map.set (node_idx, clone_idx);
+    for (const auto& l : object (node_idx).all_links ()) {
+      duplicate_subgraph (l.objidx, index_map);
+    }
+  }
+
+  /*
+   * Creates a copy of node_idx and returns it's new index.
+   */
+  unsigned duplicate (unsigned node_idx)
+  {
+    positions_invalid = true;
+    distance_invalid = true;
+
+    auto* clone = vertices_.push ();
+    auto& child = vertices_[node_idx];
+    if (vertices_.in_error ()) {
+      return -1;
+    }
+
+    clone->obj.head = child.obj.head;
+    clone->obj.tail = child.obj.tail;
+    clone->distance = child.distance;
+    clone->space = child.space;
+    clone->reset_parents ();
+
+    unsigned clone_idx = vertices_.length - 2;
+    for (const auto& l : child.obj.real_links)
+    {
+      clone->obj.real_links.push (l);
+      vertices_[l.objidx].add_parent (clone_idx);
+    }
+    for (const auto& l : child.obj.virtual_links)
+    {
+      clone->obj.virtual_links.push (l);
+      vertices_[l.objidx].add_parent (clone_idx);
+    }
+
+    check_success (!clone->obj.real_links.in_error ());
+    check_success (!clone->obj.virtual_links.in_error ());
+
+    // The last object is the root of the graph, so swap back the root to the end.
+    // The root's obj idx does change, however since it's root nothing else refers to it.
+    // all other obj idx's will be unaffected.
+    hb_swap (vertices_[vertices_.length - 2], *clone);
+
+    // Since the root moved, update the parents arrays of all children on the root.
+    for (const auto& l : root ().obj.all_links ())
+      vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
+
+    return clone_idx;
+  }
+
+  /*
+   * Creates a copy of child and re-assigns the link from
+   * parent to the clone. The copy is a shallow copy, objects
+   * linked from child are not duplicated.
+   */
+  unsigned duplicate_if_shared (unsigned parent_idx, unsigned child_idx)
+  {
+    unsigned new_idx = duplicate (parent_idx, child_idx);
+    if (new_idx == (unsigned) -1) return child_idx;
+    return new_idx;
+  }
+
+
+  /*
+   * Creates a copy of child and re-assigns the link from
+   * parent to the clone. The copy is a shallow copy, objects
+   * linked from child are not duplicated.
+   */
+  unsigned duplicate (unsigned parent_idx, unsigned child_idx)
+  {
+    update_parents ();
+
+    unsigned links_to_child = 0;
+    for (const auto& l : vertices_[parent_idx].obj.all_links ())
+    {
+      if (l.objidx == child_idx) links_to_child++;
+    }
+
+    if (vertices_[child_idx].incoming_edges () <= links_to_child)
+    {
+      // Can't duplicate this node, doing so would orphan the original one as all remaining links
+      // to child are from parent.
+      DEBUG_MSG (SUBSET_REPACK, nullptr, "  Not duplicating %u => %u",
+                 parent_idx, child_idx);
+      return -1;
+    }
+
+    DEBUG_MSG (SUBSET_REPACK, nullptr, "  Duplicating %u => %u",
+               parent_idx, child_idx);
+
+    unsigned clone_idx = duplicate (child_idx);
+    if (clone_idx == (unsigned) -1) return false;
+    // duplicate shifts the root node idx, so if parent_idx was root update it.
+    if (parent_idx == clone_idx) parent_idx++;
+
+    auto& parent = vertices_[parent_idx];
+    for (auto& l : parent.obj.all_links_writer ())
+    {
+      if (l.objidx != child_idx)
+        continue;
+
+      reassign_link (l, parent_idx, clone_idx);
+    }
+
+    return clone_idx;
+  }
+
+
+  /*
+   * Adds a new node to the graph, not connected to anything.
+   */
+  unsigned new_node (char* head, char* tail)
+  {
+    positions_invalid = true;
+    distance_invalid = true;
+
+    auto* clone = vertices_.push ();
+    if (vertices_.in_error ()) {
+      return -1;
+    }
+
+    clone->obj.head = head;
+    clone->obj.tail = tail;
+    clone->distance = 0;
+    clone->space = 0;
+
+    unsigned clone_idx = vertices_.length - 2;
+
+    // The last object is the root of the graph, so swap back the root to the end.
+    // The root's obj idx does change, however since it's root nothing else refers to it.
+    // all other obj idx's will be unaffected.
+    hb_swap (vertices_[vertices_.length - 2], *clone);
+
+    // Since the root moved, update the parents arrays of all children on the root.
+    for (const auto& l : root ().obj.all_links ())
+      vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
+
+    return clone_idx;
+  }
+
+  /*
+   * Raises the sorting priority of all children.
+   */
+  bool raise_childrens_priority (unsigned parent_idx)
+  {
+    DEBUG_MSG (SUBSET_REPACK, nullptr, "  Raising priority of all children of %u",
+               parent_idx);
+    // This operation doesn't change ordering until a sort is run, so no need
+    // to invalidate positions. It does not change graph structure so no need
+    // to update distances or edge counts.
+    auto& parent = vertices_[parent_idx].obj;
+    bool made_change = false;
+    for (auto& l : parent.all_links_writer ())
+      made_change |= vertices_[l.objidx].raise_priority ();
+    return made_change;
+  }
+
+  bool is_fully_connected ()
+  {
+    update_parents();
+
+    if (root().incoming_edges ())
+      // Root cannot have parents.
+      return false;
+
+    for (unsigned i = 0; i < root_idx (); i++)
+    {
+      if (!vertices_[i].incoming_edges ())
+        return false;
+    }
+    return true;
+  }
+
+#if 0
+  /*
+   * Saves the current graph to a packed binary format which the repacker fuzzer takes
+   * as a seed.
+   */
+  void save_fuzzer_seed (hb_tag_t tag) const
+  {
+    FILE* f = fopen ("./repacker_fuzzer_seed", "w");
+    fwrite ((void*) &tag, sizeof (tag), 1, f);
+
+    uint16_t num_objects = vertices_.length;
+    fwrite ((void*) &num_objects, sizeof (num_objects), 1, f);
+
+    for (const auto& v : vertices_)
+    {
+      uint16_t blob_size = v.table_size ();
+      fwrite ((void*) &blob_size, sizeof (blob_size), 1, f);
+      fwrite ((const void*) v.obj.head, blob_size, 1, f);
+    }
+
+    uint16_t link_count = 0;
+    for (const auto& v : vertices_)
+      link_count += v.obj.real_links.length;
+
+    fwrite ((void*) &link_count, sizeof (link_count), 1, f);
+
+    typedef struct
+    {
+      uint16_t parent;
+      uint16_t child;
+      uint16_t position;
+      uint8_t width;
+    } link_t;
+
+    for (unsigned i = 0; i < vertices_.length; i++)
+    {
+      for (const auto& l : vertices_[i].obj.real_links)
+      {
+        link_t link {
+          (uint16_t) i, (uint16_t) l.objidx,
+          (uint16_t) l.position, (uint8_t) l.width
+        };
+        fwrite ((void*) &link, sizeof (link), 1, f);
+      }
+    }
+
+    fclose (f);
+  }
+#endif
+
+  void print_orphaned_nodes ()
+  {
+    if (!DEBUG_ENABLED(SUBSET_REPACK)) return;
+
+    DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected.");
+    parents_invalid = true;
+    update_parents();
+
+    if (root().incoming_edges ()) {
+      DEBUG_MSG (SUBSET_REPACK, nullptr, "Root node has incoming edges.");
+    }
+
+    for (unsigned i = 0; i < root_idx (); i++)
+    {
+      const auto& v = vertices_[i];
+      if (!v.incoming_edges ())
+        DEBUG_MSG (SUBSET_REPACK, nullptr, "Node %u is orphaned.", i);
+    }
+  }
+
+  unsigned num_roots_for_space (unsigned space) const
+  {
+    return num_roots_for_space_[space];
+  }
+
+  unsigned next_space () const
+  {
+    return num_roots_for_space_.length;
+  }
+
+  void move_to_new_space (const hb_set_t& indices)
+  {
+    num_roots_for_space_.push (0);
+    unsigned new_space = num_roots_for_space_.length - 1;
+
+    for (unsigned index : indices) {
+      auto& node = vertices_[index];
+      num_roots_for_space_[node.space] = num_roots_for_space_[node.space] - 1;
+      num_roots_for_space_[new_space] = num_roots_for_space_[new_space] + 1;
+      node.space = new_space;
+      distance_invalid = true;
+      positions_invalid = true;
+    }
+  }
+
+  unsigned space_for (unsigned index, unsigned* root = nullptr) const
+  {
+  loop:
+    assert (index < vertices_.length);
+    const auto& node = vertices_[index];
+    if (node.space)
+    {
+      if (root != nullptr)
+        *root = index;
+      return node.space;
+    }
+
+    if (!node.incoming_edges ())
+    {
+      if (root)
+        *root = index;
+      return 0;
+    }
+
+    index = *node.parents_iter ();
+    goto loop;
+  }
+
+  void err_other_error () { this->successful = false; }
+
+  size_t total_size_in_bytes () const {
+    size_t total_size = 0;
+    unsigned count = vertices_.length;
+    for (unsigned i = 0; i < count; i++) {
+      size_t size = vertices_.arrayZ[i].obj.tail - vertices_.arrayZ[i].obj.head;
+      total_size += size;
+    }
+    return total_size;
+  }
+
+
+ private:
+
+  /*
+   * Returns the numbers of incoming edges that are 24 or 32 bits wide.
+   */
+  unsigned wide_parents (unsigned node_idx, hb_set_t& parents) const
+  {
+    unsigned count = 0;
+    for (unsigned p : vertices_[node_idx].parents_iter ())
+    {
+      // Only real links can be wide
+      for (const auto& l : vertices_[p].obj.real_links)
+      {
+        if (l.objidx == node_idx
+            && (l.width == 3 || l.width == 4)
+            && !l.is_signed)
+        {
+          count++;
+          parents.add (p);
+        }
+      }
+    }
+    return count;
+  }
+
+  bool check_success (bool success)
+  { return this->successful && (success || ((void) err_other_error (), false)); }
+
+ public:
+  /*
+   * Creates a map from objid to # of incoming edges.
+   */
+  void update_parents ()
+  {
+    if (!parents_invalid) return;
+
+    unsigned count = vertices_.length;
+
+    for (unsigned i = 0; i < count; i++)
+      vertices_.arrayZ[i].reset_parents ();
+
+    for (unsigned p = 0; p < count; p++)
+    {
+      for (auto& l : vertices_.arrayZ[p].obj.all_links ())
+        vertices_[l.objidx].add_parent (p);
+    }
+
+    for (unsigned i = 0; i < count; i++)
+      // parents arrays must be accurate or downstream operations like cycle detection
+      // and sorting won't work correctly.
+      check_success (!vertices_.arrayZ[i].in_error ());
+
+    parents_invalid = false;
+  }
+
+  /*
+   * compute the serialized start and end positions for each vertex.
+   */
+  void update_positions ()
+  {
+    if (!positions_invalid) return;
+
+    unsigned current_pos = 0;
+    for (int i = root_idx (); i >= 0; i--)
+    {
+      auto& v = vertices_[i];
+      v.start = current_pos;
+      current_pos += v.obj.tail - v.obj.head;
+      v.end = current_pos;
+    }
+
+    positions_invalid = false;
+  }
+
+  /*
+   * Finds the distance to each object in the graph
+   * from the initial node.
+   */
+  void update_distances ()
+  {
+    if (!distance_invalid) return;
+
+    // Uses Dijkstra's algorithm to find all of the shortest distances.
+    // https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
+    //
+    // Implementation Note:
+    // Since our priority queue doesn't support fast priority decreases
+    // we instead just add new entries into the queue when a priority changes.
+    // Redundant ones are filtered out later on by the visited set.
+    // According to https://www3.cs.stonybrook.edu/~rezaul/papers/TR-07-54.pdf
+    // for practical performance this is faster then using a more advanced queue
+    // (such as a fibonacci queue) with a fast decrease priority.
+    unsigned count = vertices_.length;
+    for (unsigned i = 0; i < count; i++)
+      vertices_.arrayZ[i].distance = hb_int_max (int64_t);
+    vertices_.tail ().distance = 0;
+
+    hb_priority_queue_t<int64_t> queue;
+    queue.insert (0, vertices_.length - 1);
+
+    hb_vector_t<bool> visited;
+    visited.resize (vertices_.length);
+
+    while (!queue.in_error () && !queue.is_empty ())
+    {
+      unsigned next_idx = queue.pop_minimum ().second;
+      if (visited[next_idx]) continue;
+      const auto& next = vertices_[next_idx];
+      int64_t next_distance = vertices_[next_idx].distance;
+      visited[next_idx] = true;
+
+      for (const auto& link : next.obj.all_links ())
+      {
+        if (visited[link.objidx]) continue;
+
+        const auto& child = vertices_.arrayZ[link.objidx].obj;
+        unsigned link_width = link.width ? link.width : 4; // treat virtual offsets as 32 bits wide
+        int64_t child_weight = (child.tail - child.head) +
+                               ((int64_t) 1 << (link_width * 8)) * (vertices_.arrayZ[link.objidx].space + 1);
+        int64_t child_distance = next_distance + child_weight;
+
+        if (child_distance < vertices_.arrayZ[link.objidx].distance)
+        {
+          vertices_.arrayZ[link.objidx].distance = child_distance;
+          queue.insert (child_distance, link.objidx);
+        }
+      }
+    }
+
+    check_success (!queue.in_error ());
+    if (!check_success (queue.is_empty ()))
+    {
+      print_orphaned_nodes ();
+      return;
+    }
+
+    distance_invalid = false;
+  }
+
+ private:
+  /*
+   * Updates a link in the graph to point to a different object. Corrects the
+   * parents vector on the previous and new child nodes.
+   */
+  void reassign_link (hb_serialize_context_t::object_t::link_t& link,
+                      unsigned parent_idx,
+                      unsigned new_idx)
+  {
+    unsigned old_idx = link.objidx;
+    link.objidx = new_idx;
+    vertices_[old_idx].remove_parent (parent_idx);
+    vertices_[new_idx].add_parent (parent_idx);
+  }
+
+  /*
+   * Updates all objidx's in all links using the provided mapping. Corrects incoming edge counts.
+   */
+  template<typename Iterator, hb_requires (hb_is_iterator (Iterator))>
+  void remap_obj_indices (const hb_map_t& id_map,
+                          Iterator subgraph,
+                          bool only_wide = false)
+  {
+    if (!id_map) return;
+    for (unsigned i : subgraph)
+    {
+      for (auto& link : vertices_[i].obj.all_links_writer ())
+      {
+        const uint32_t *v;
+        if (!id_map.has (link.objidx, &v)) continue;
+        if (only_wide && !(link.width == 4 && !link.is_signed)) continue;
+
+        reassign_link (link, i, *v);
+      }
+    }
+  }
+
+  /*
+   * Updates all objidx's in all links using the provided mapping.
+   */
+  bool remap_all_obj_indices (const hb_vector_t<unsigned>& id_map,
+                              hb_vector_t<vertex_t>* sorted_graph) const
+  {
+    unsigned count = sorted_graph->length;
+    for (unsigned i = 0; i < count; i++)
+    {
+      if (!(*sorted_graph)[i].remap_parents (id_map))
+        return false;
+      for (auto& link : sorted_graph->arrayZ[i].obj.all_links_writer ())
+      {
+        link.objidx = id_map[link.objidx];
+      }
+    }
+    return true;
+  }
+
+  /*
+   * Finds all nodes in targets that are reachable from start_idx, nodes in visited will be skipped.
+   * For this search the graph is treated as being undirected.
+   *
+   * Connected targets will be added to connected and removed from targets. All visited nodes
+   * will be added to visited.
+   */
+  void find_connected_nodes (unsigned start_idx,
+                             hb_set_t& targets,
+                             hb_set_t& visited,
+                             hb_set_t& connected)
+  {
+    if (unlikely (!check_success (!visited.in_error ()))) return;
+    if (visited.has (start_idx)) return;
+    visited.add (start_idx);
+
+    if (targets.has (start_idx))
+    {
+      targets.del (start_idx);
+      connected.add (start_idx);
+    }
+
+    const auto& v = vertices_[start_idx];
+
+    // Graph is treated as undirected so search children and parents of start_idx
+    for (const auto& l : v.obj.all_links ())
+      find_connected_nodes (l.objidx, targets, visited, connected);
+
+    for (unsigned p : v.parents_iter ())
+      find_connected_nodes (p, targets, visited, connected);
+  }
+
+ public:
+  // TODO(garretrieger): make private, will need to move most of offset overflow code into graph.
+  hb_vector_t<vertex_t> vertices_;
+  hb_vector_t<vertex_t> vertices_scratch_;
+ private:
+  bool parents_invalid;
+  bool distance_invalid;
+  bool positions_invalid;
+  bool successful;
+  hb_vector_t<unsigned> num_roots_for_space_;
+  hb_vector_t<char*> buffers;
+};
+
+}
+
+#endif  // GRAPH_GRAPH_HH
diff --git a/src/graph/gsubgpos-context.cc b/src/graph/gsubgpos-context.cc
new file mode 100644 (file)
index 0000000..d66eb49
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright © 2022  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
+ */
+
+#include "gsubgpos-graph.hh"
+
+namespace graph {
+
+gsubgpos_graph_context_t::gsubgpos_graph_context_t (hb_tag_t table_tag_,
+                                                    graph_t& graph_)
+    : table_tag (table_tag_),
+      graph (graph_),
+      lookup_list_index (0),
+      lookups ()
+{
+  if (table_tag_ != HB_OT_TAG_GPOS
+      &&  table_tag_ != HB_OT_TAG_GSUB)
+    return;
+
+  GSTAR* gstar = graph::GSTAR::graph_to_gstar (graph_);
+  if (gstar) {
+    gstar->find_lookups (graph, lookups);
+    lookup_list_index = gstar->get_lookup_list_index (graph_);
+  }
+}
+
+unsigned gsubgpos_graph_context_t::create_node (unsigned size)
+{
+  char* buffer = (char*) hb_calloc (1, size);
+  if (!buffer)
+    return -1;
+
+  if (!add_buffer (buffer)) {
+    // Allocation did not get stored for freeing later.
+    hb_free (buffer);
+    return -1;
+  }
+
+  return graph.new_node (buffer, buffer + size);
+}
+
+unsigned gsubgpos_graph_context_t::num_non_ext_subtables ()  {
+  unsigned count = 0;
+  for (auto l : lookups.values ())
+  {
+    if (l->is_extension (table_tag)) continue;
+    count += l->number_of_subtables ();
+  }
+  return count;
+}
+
+}
diff --git a/src/graph/gsubgpos-context.hh b/src/graph/gsubgpos-context.hh
new file mode 100644 (file)
index 0000000..b25d538
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright © 2022  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
+ */
+
+#include "graph.hh"
+#include "../hb-ot-layout-gsubgpos.hh"
+
+#ifndef GRAPH_GSUBGPOS_CONTEXT_HH
+#define GRAPH_GSUBGPOS_CONTEXT_HH
+
+namespace graph {
+
+struct Lookup;
+
+struct gsubgpos_graph_context_t
+{
+  hb_tag_t table_tag;
+  graph_t& graph;
+  unsigned lookup_list_index;
+  hb_hashmap_t<unsigned, graph::Lookup*> lookups;
+  hb_hashmap_t<unsigned, unsigned> subtable_to_extension;
+
+  HB_INTERNAL gsubgpos_graph_context_t (hb_tag_t table_tag_,
+                                        graph_t& graph_);
+
+  HB_INTERNAL unsigned create_node (unsigned size);
+
+  bool add_buffer (char* buffer)
+  {
+    return graph.add_buffer (buffer);
+  }
+
+ private:
+  HB_INTERNAL unsigned num_non_ext_subtables ();
+};
+
+}
+
+#endif  // GRAPH_GSUBGPOS_CONTEXT
diff --git a/src/graph/gsubgpos-graph.hh b/src/graph/gsubgpos-graph.hh
new file mode 100644 (file)
index 0000000..12fcbdc
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * Copyright © 2022  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
+ */
+
+#include "graph.hh"
+#include "../hb-ot-layout-gsubgpos.hh"
+#include "../OT/Layout/GSUB/ExtensionSubst.hh"
+#include "gsubgpos-context.hh"
+#include "pairpos-graph.hh"
+#include "markbasepos-graph.hh"
+
+#ifndef GRAPH_GSUBGPOS_GRAPH_HH
+#define GRAPH_GSUBGPOS_GRAPH_HH
+
+namespace graph {
+
+struct Lookup;
+
+template<typename T>
+struct ExtensionFormat1 : public OT::ExtensionFormat1<T>
+{
+  void reset(unsigned type)
+  {
+    this->format = 1;
+    this->extensionLookupType = type;
+    this->extensionOffset = 0;
+  }
+
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    return vertex_len >= OT::ExtensionFormat1<T>::static_size;
+  }
+
+  unsigned get_lookup_type () const
+  {
+    return this->extensionLookupType;
+  }
+
+  unsigned get_subtable_index (graph_t& graph, unsigned this_index) const
+  {
+    return graph.index_for_offset (this_index, &this->extensionOffset);
+  }
+};
+
+struct Lookup : public OT::Lookup
+{
+  unsigned number_of_subtables () const
+  {
+    return subTable.len;
+  }
+
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    if (vertex_len < OT::Lookup::min_size) return false;
+    return vertex_len >= this->get_size ();
+  }
+
+  bool is_extension (hb_tag_t table_tag) const
+  {
+    return lookupType == extension_type (table_tag);
+  }
+
+  bool make_extension (gsubgpos_graph_context_t& c,
+                       unsigned this_index)
+  {
+    unsigned type = lookupType;
+    unsigned ext_type = extension_type (c.table_tag);
+    if (!ext_type || is_extension (c.table_tag))
+    {
+      // NOOP
+      return true;
+    }
+
+    DEBUG_MSG (SUBSET_REPACK, nullptr,
+               "Promoting lookup type %u (obj %u) to extension.",
+               type,
+               this_index);
+
+    for (unsigned i = 0; i < subTable.len; i++)
+    {
+      unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
+      if (!make_subtable_extension (c,
+                                    this_index,
+                                    subtable_index))
+        return false;
+    }
+
+    lookupType = ext_type;
+    return true;
+  }
+
+  bool split_subtables_if_needed (gsubgpos_graph_context_t& c,
+                                  unsigned this_index)
+  {
+    unsigned type = lookupType;
+    bool is_ext = is_extension (c.table_tag);
+
+    if (c.table_tag != HB_OT_TAG_GPOS)
+      return true;
+
+    if (!is_ext &&
+        type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair &&
+        type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase)
+      return true;
+
+    hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>> all_new_subtables;
+    for (unsigned i = 0; i < subTable.len; i++)
+    {
+      unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
+      unsigned parent_index = this_index;
+      if (is_ext) {
+        unsigned ext_subtable_index = subtable_index;
+        parent_index = ext_subtable_index;
+        ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
+            (ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*)
+            c.graph.object (ext_subtable_index).head;
+        if (!extension || !extension->sanitize (c.graph.vertices_[ext_subtable_index]))
+          continue;
+
+        subtable_index = extension->get_subtable_index (c.graph, ext_subtable_index);
+        type = extension->get_lookup_type ();
+        if (type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair
+            && type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase)
+          continue;
+      }
+
+      hb_vector_t<unsigned> new_sub_tables;
+      switch (type)
+      {
+      case 2:
+        new_sub_tables = split_subtable<PairPos> (c, parent_index, subtable_index); break;
+      case 4:
+        new_sub_tables = split_subtable<MarkBasePos> (c, parent_index, subtable_index); break;
+      default:
+        break;
+      }
+      if (new_sub_tables.in_error ()) return false;
+      if (!new_sub_tables) continue;
+      hb_pair_t<unsigned, hb_vector_t<unsigned>>* entry = all_new_subtables.push ();
+      entry->first = i;
+      entry->second = std::move (new_sub_tables);
+    }
+
+    if (all_new_subtables) {
+      return add_sub_tables (c, this_index, type, all_new_subtables);
+    }
+
+    return true;
+  }
+
+  template<typename T>
+  hb_vector_t<unsigned> split_subtable (gsubgpos_graph_context_t& c,
+                                        unsigned parent_idx,
+                                        unsigned objidx)
+  {
+    T* sub_table = (T*) c.graph.object (objidx).head;
+    if (!sub_table || !sub_table->sanitize (c.graph.vertices_[objidx]))
+      return hb_vector_t<unsigned> ();
+
+    return sub_table->split_subtables (c, parent_idx, objidx);
+  }
+
+  bool add_sub_tables (gsubgpos_graph_context_t& c,
+                       unsigned this_index,
+                       unsigned type,
+                       hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>>& subtable_ids)
+  {
+    bool is_ext = is_extension (c.table_tag);
+    auto& v = c.graph.vertices_[this_index];
+    fix_existing_subtable_links (c, this_index, subtable_ids);
+
+    unsigned new_subtable_count = 0;
+    for (const auto& p : subtable_ids)
+      new_subtable_count += p.second.length;
+
+    size_t new_size = v.table_size ()
+                      + new_subtable_count * OT::Offset16::static_size;
+    char* buffer = (char*) hb_calloc (1, new_size);
+    if (!buffer) return false;
+    if (!c.add_buffer (buffer))
+    {
+      hb_free (buffer);
+     return false;
+    }
+    hb_memcpy (buffer, v.obj.head, v.table_size());
+
+    v.obj.head = buffer;
+    v.obj.tail = buffer + new_size;
+
+    Lookup* new_lookup = (Lookup*) buffer;
+
+    unsigned shift = 0;
+    new_lookup->subTable.len = subTable.len + new_subtable_count;
+    for (const auto& p : subtable_ids)
+    {
+      unsigned offset_index = p.first + shift + 1;
+      shift += p.second.length;
+
+      for (unsigned subtable_id : p.second)
+      {
+        if (is_ext)
+        {
+          unsigned ext_id = create_extension_subtable (c, subtable_id, type);
+          c.graph.vertices_[subtable_id].add_parent (ext_id);
+          subtable_id = ext_id;
+        }
+
+        auto* link = v.obj.real_links.push ();
+        link->width = 2;
+        link->objidx = subtable_id;
+        link->position = (char*) &new_lookup->subTable[offset_index++] -
+                         (char*) new_lookup;
+        c.graph.vertices_[subtable_id].add_parent (this_index);
+      }
+    }
+
+    // Repacker sort order depends on link order, which we've messed up so resort it.
+    v.obj.real_links.qsort ();
+
+    // The head location of the lookup has changed, invalidating the lookups map entry
+    // in the context. Update the map.
+    c.lookups.set (this_index, new_lookup);
+    return true;
+  }
+
+  void fix_existing_subtable_links (gsubgpos_graph_context_t& c,
+                                    unsigned this_index,
+                                    hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>>& subtable_ids)
+  {
+    auto& v = c.graph.vertices_[this_index];
+    Lookup* lookup = (Lookup*) v.obj.head;
+
+    unsigned shift = 0;
+    for (const auto& p : subtable_ids)
+    {
+      unsigned insert_index = p.first + shift;
+      unsigned pos_offset = p.second.length * OT::Offset16::static_size;
+      unsigned insert_offset = (char*) &lookup->subTable[insert_index] - (char*) lookup;
+      shift += p.second.length;
+
+      for (auto& l : v.obj.all_links_writer ())
+      {
+        if (l.position > insert_offset) l.position += pos_offset;
+      }
+    }
+  }
+
+  unsigned create_extension_subtable (gsubgpos_graph_context_t& c,
+                                      unsigned subtable_index,
+                                      unsigned type)
+  {
+    unsigned extension_size = OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::static_size;
+
+    unsigned ext_index = c.create_node (extension_size);
+    if (ext_index == (unsigned) -1)
+      return -1;
+
+    auto& ext_vertex = c.graph.vertices_[ext_index];
+    ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
+        (ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*) ext_vertex.obj.head;
+    extension->reset (type);
+
+    // Make extension point at the subtable.
+    auto* l = ext_vertex.obj.real_links.push ();
+
+    l->width = 4;
+    l->objidx = subtable_index;
+    l->position = 4;
+
+    return ext_index;
+  }
+
+  bool make_subtable_extension (gsubgpos_graph_context_t& c,
+                                unsigned lookup_index,
+                                unsigned subtable_index)
+  {
+    unsigned type = lookupType;
+    unsigned ext_index = -1;
+    unsigned* existing_ext_index = nullptr;
+    if (c.subtable_to_extension.has(subtable_index, &existing_ext_index)) {
+      ext_index = *existing_ext_index;
+    } else {    
+      ext_index = create_extension_subtable(c, subtable_index, type);
+      c.subtable_to_extension.set(subtable_index, ext_index);
+    }
+
+    if (ext_index == (unsigned) -1)
+      return false;
+
+    auto& subtable_vertex = c.graph.vertices_[subtable_index];
+    auto& lookup_vertex = c.graph.vertices_[lookup_index];
+    for (auto& l : lookup_vertex.obj.real_links.writer ())
+    {
+      if (l.objidx == subtable_index) {
+        // Change lookup to point at the extension.
+        l.objidx = ext_index;
+        if (existing_ext_index)
+          subtable_vertex.remove_parent(lookup_index);
+      }
+    }
+
+    // Make extension point at the subtable.
+    auto& ext_vertex = c.graph.vertices_[ext_index];
+    ext_vertex.add_parent (lookup_index);
+    if (!existing_ext_index)
+      subtable_vertex.remap_parent (lookup_index, ext_index);
+
+    return true;
+  }
+
+ private:
+  unsigned extension_type (hb_tag_t table_tag) const
+  {
+    switch (table_tag)
+    {
+    case HB_OT_TAG_GPOS: return 9;
+    case HB_OT_TAG_GSUB: return 7;
+    default: return 0;
+    }
+  }
+};
+
+template <typename T>
+struct LookupList : public OT::LookupList<T>
+{
+  bool sanitize (const graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    if (vertex_len < OT::LookupList<T>::min_size) return false;
+    return vertex_len >= OT::LookupList<T>::item_size * this->len;
+  }
+};
+
+struct GSTAR : public OT::GSUBGPOS
+{
+  static GSTAR* graph_to_gstar (graph_t& graph)
+  {
+    const auto& r = graph.root ();
+
+    GSTAR* gstar = (GSTAR*) r.obj.head;
+    if (!gstar || !gstar->sanitize (r))
+      return nullptr;
+
+    return gstar;
+  }
+
+  const void* get_lookup_list_field_offset () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.get_lookup_list_offset ();
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.get_lookup_list_offset ();
+#endif
+    default: return 0;
+    }
+  }
+
+  bool sanitize (const graph_t::vertex_t& vertex)
+  {
+    int64_t len = vertex.obj.tail - vertex.obj.head;
+    if (len < OT::GSUBGPOS::min_size) return false;
+    return len >= get_size ();
+  }
+
+  void find_lookups (graph_t& graph,
+                     hb_hashmap_t<unsigned, Lookup*>& lookups /* OUT */)
+  {
+    switch (u.version.major) {
+      case 1: find_lookups<SmallTypes> (graph, lookups); break;
+#ifndef HB_NO_BEYOND_64K
+      case 2: find_lookups<MediumTypes> (graph, lookups); break;
+#endif
+    }
+  }
+
+  unsigned get_lookup_list_index (graph_t& graph)
+  {
+    return graph.index_for_offset (graph.root_idx (),
+                                   get_lookup_list_field_offset());
+  }
+
+  template<typename Types>
+  void find_lookups (graph_t& graph,
+                     hb_hashmap_t<unsigned, Lookup*>& lookups /* OUT */)
+  {
+    unsigned lookup_list_idx = get_lookup_list_index (graph);
+    const LookupList<Types>* lookupList =
+        (const LookupList<Types>*) graph.object (lookup_list_idx).head;
+    if (!lookupList || !lookupList->sanitize (graph.vertices_[lookup_list_idx]))
+      return;
+
+    for (unsigned i = 0; i < lookupList->len; i++)
+    {
+      unsigned lookup_idx = graph.index_for_offset (lookup_list_idx, &(lookupList->arrayZ[i]));
+      Lookup* lookup = (Lookup*) graph.object (lookup_idx).head;
+      if (!lookup || !lookup->sanitize (graph.vertices_[lookup_idx])) continue;
+      lookups.set (lookup_idx, lookup);
+    }
+  }
+};
+
+
+
+
+}
+
+#endif  /* GRAPH_GSUBGPOS_GRAPH_HH */
diff --git a/src/graph/markbasepos-graph.hh b/src/graph/markbasepos-graph.hh
new file mode 100644 (file)
index 0000000..ae5ebd0
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+ * Copyright © 2022  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
+ */
+
+#ifndef GRAPH_MARKBASEPOS_GRAPH_HH
+#define GRAPH_MARKBASEPOS_GRAPH_HH
+
+#include "split-helpers.hh"
+#include "coverage-graph.hh"
+#include "../OT/Layout/GPOS/MarkBasePos.hh"
+#include "../OT/Layout/GPOS/PosLookupSubTable.hh"
+
+namespace graph {
+
+struct AnchorMatrix : public OT::Layout::GPOS_impl::AnchorMatrix
+{
+  bool sanitize (graph_t::vertex_t& vertex, unsigned class_count) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    if (vertex_len < AnchorMatrix::min_size) return false;
+
+    return vertex_len >= AnchorMatrix::min_size +
+        OT::Offset16::static_size * class_count * this->rows;
+  }
+
+  bool shrink (gsubgpos_graph_context_t& c,
+               unsigned this_index,
+               unsigned old_class_count,
+               unsigned new_class_count)
+  {
+    if (new_class_count >= old_class_count) return false;
+    auto& o = c.graph.vertices_[this_index].obj;
+    unsigned base_count = rows;
+    o.tail = o.head +
+             AnchorMatrix::min_size +
+             OT::Offset16::static_size * base_count * new_class_count;
+
+    // Reposition links into the new indexing scheme.
+    for (auto& link : o.real_links.writer ())
+    {
+      unsigned index = (link.position - 2) / 2;
+      unsigned base = index / old_class_count;
+      unsigned klass = index % old_class_count;
+      if (klass >= new_class_count)
+        // should have already been removed
+        return false;
+
+      unsigned new_index = base * new_class_count + klass;
+
+      link.position = (char*) &(this->matrixZ[new_index]) - (char*) this;
+    }
+
+    return true;
+  }
+
+  unsigned clone (gsubgpos_graph_context_t& c,
+                  unsigned this_index,
+                  unsigned start,
+                  unsigned end,
+                  unsigned class_count)
+  {
+    unsigned base_count = rows;
+    unsigned new_class_count = end - start;
+    unsigned size = AnchorMatrix::min_size +
+                    OT::Offset16::static_size * new_class_count * rows;
+    unsigned prime_id = c.create_node (size);
+    if (prime_id == (unsigned) -1) return -1;
+    AnchorMatrix* prime = (AnchorMatrix*) c.graph.object (prime_id).head;
+    prime->rows = base_count;
+
+    auto& o = c.graph.vertices_[this_index].obj;
+    int num_links = o.real_links.length;
+    for (int i = 0; i < num_links; i++)
+    {
+      const auto& link = o.real_links[i];
+      unsigned old_index = (link.position - 2) / OT::Offset16::static_size;
+      unsigned klass = old_index % class_count;
+      if (klass < start || klass >= end) continue;
+
+      unsigned base = old_index / class_count;
+      unsigned new_klass = klass - start;
+      unsigned new_index = base * new_class_count + new_klass;
+
+
+      unsigned child_idx = link.objidx;
+      c.graph.add_link (&(prime->matrixZ[new_index]),
+                        prime_id,
+                        child_idx);
+
+      auto& child = c.graph.vertices_[child_idx];
+      child.remove_parent (this_index);
+
+      o.real_links.remove_unordered (i);
+      num_links--;
+      i--;
+    }
+
+    return prime_id;
+  }
+};
+
+struct MarkArray : public OT::Layout::GPOS_impl::MarkArray
+{
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    unsigned min_size = MarkArray::min_size;
+    if (vertex_len < min_size) return false;
+
+    return vertex_len >= get_size ();
+  }
+
+  bool shrink (gsubgpos_graph_context_t& c,
+               const hb_hashmap_t<unsigned, unsigned>& mark_array_links,
+               unsigned this_index,
+               unsigned new_class_count)
+  {
+    auto& o = c.graph.vertices_[this_index].obj;
+    for (const auto& link : o.real_links)
+      c.graph.vertices_[link.objidx].remove_parent (this_index);
+    o.real_links.reset ();
+
+    unsigned new_index = 0;
+    for (const auto& record : this->iter ())
+    {
+      unsigned klass = record.klass;
+      if (klass >= new_class_count) continue;
+
+      (*this)[new_index].klass = klass;
+      unsigned position = (char*) &record.markAnchor - (char*) this;
+      unsigned* objidx;
+      if (!mark_array_links.has (position, &objidx))
+      {
+        new_index++;
+        continue;
+      }
+
+      c.graph.add_link (&(*this)[new_index].markAnchor, this_index, *objidx);
+      new_index++;
+    }
+
+    this->len = new_index;
+    o.tail = o.head + MarkArray::min_size +
+             OT::Layout::GPOS_impl::MarkRecord::static_size * new_index;
+    return true;
+  }
+
+  unsigned clone (gsubgpos_graph_context_t& c,
+                  unsigned this_index,
+                  const hb_hashmap_t<unsigned, unsigned>& pos_to_index,
+                  hb_set_t& marks,
+                  unsigned start_class)
+  {
+    unsigned size = MarkArray::min_size +
+                    OT::Layout::GPOS_impl::MarkRecord::static_size *
+                    marks.get_population ();
+    unsigned prime_id = c.create_node (size);
+    if (prime_id == (unsigned) -1) return -1;
+    MarkArray* prime = (MarkArray*) c.graph.object (prime_id).head;
+    prime->len = marks.get_population ();
+
+
+    unsigned i = 0;
+    for (hb_codepoint_t mark : marks)
+    {
+      (*prime)[i].klass = (*this)[mark].klass - start_class;
+      unsigned offset_pos = (char*) &((*this)[mark].markAnchor) - (char*) this;
+      unsigned* anchor_index;
+      if (pos_to_index.has (offset_pos, &anchor_index))
+        c.graph.move_child (this_index,
+                            &((*this)[mark].markAnchor),
+                            prime_id,
+                            &((*prime)[i].markAnchor));
+
+      i++;
+    }
+
+    return prime_id;
+  }
+};
+
+struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<SmallTypes>
+{
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    return vertex_len >= MarkBasePosFormat1::static_size;
+  }
+
+  hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+                                         unsigned parent_index,
+                                         unsigned this_index)
+  {
+    hb_set_t visited;
+
+    const unsigned base_coverage_id = c.graph.index_for_offset (this_index, &baseCoverage);
+    const unsigned base_size =
+        OT::Layout::GPOS_impl::MarkBasePosFormat1_2<SmallTypes>::min_size +
+        MarkArray::min_size +
+        AnchorMatrix::min_size +
+        c.graph.vertices_[base_coverage_id].table_size ();
+
+    hb_vector_t<class_info_t> class_to_info = get_class_info (c, this_index);
+
+    unsigned class_count = classCount;
+    auto base_array = c.graph.as_table<AnchorMatrix> (this_index,
+                                                      &baseArray,
+                                                      class_count);
+    if (!base_array) return hb_vector_t<unsigned> ();
+    unsigned base_count = base_array.table->rows;
+
+    unsigned partial_coverage_size = 4;
+    unsigned accumulated = base_size;
+    hb_vector_t<unsigned> split_points;
+
+    for (unsigned klass = 0; klass < class_count; klass++)
+    {
+      class_info_t& info = class_to_info[klass];
+      partial_coverage_size += OT::HBUINT16::static_size * info.marks.get_population ();
+      unsigned accumulated_delta =
+          OT::Layout::GPOS_impl::MarkRecord::static_size * info.marks.get_population () +
+          OT::Offset16::static_size * base_count;
+
+      for (unsigned objidx : info.child_indices)
+        accumulated_delta += c.graph.find_subgraph_size (objidx, visited);
+
+      accumulated += accumulated_delta;
+      unsigned total = accumulated + partial_coverage_size;
+
+      if (total >= (1 << 16))
+      {
+        split_points.push (klass);
+        accumulated = base_size + accumulated_delta;
+        partial_coverage_size = 4 + OT::HBUINT16::static_size * info.marks.get_population ();
+        visited.clear (); // node sharing isn't allowed between splits.
+      }
+    }
+
+
+    const unsigned mark_array_id = c.graph.index_for_offset (this_index, &markArray);
+    split_context_t split_context {
+      c,
+      this,
+      c.graph.duplicate_if_shared (parent_index, this_index),
+      std::move (class_to_info),
+      c.graph.vertices_[mark_array_id].position_to_index_map (),
+    };
+
+    return actuate_subtable_split<split_context_t> (split_context, split_points);
+  }
+
+ private:
+
+  struct class_info_t {
+    hb_set_t marks;
+    hb_vector_t<unsigned> child_indices;
+  };
+
+  struct split_context_t {
+    gsubgpos_graph_context_t& c;
+    MarkBasePosFormat1* thiz;
+    unsigned this_index;
+    hb_vector_t<class_info_t> class_to_info;
+    hb_hashmap_t<unsigned, unsigned> mark_array_links;
+
+    hb_set_t marks_for (unsigned start, unsigned end)
+    {
+      hb_set_t marks;
+      for (unsigned klass = start; klass < end; klass++)
+      {
+        + class_to_info[klass].marks.iter ()
+        | hb_sink (marks)
+        ;
+      }
+      return marks;
+    }
+
+    unsigned original_count ()
+    {
+      return thiz->classCount;
+    }
+
+    unsigned clone_range (unsigned start, unsigned end)
+    {
+      return thiz->clone_range (*this, this->this_index, start, end);
+    }
+
+    bool shrink (unsigned count)
+    {
+      return thiz->shrink (*this, this->this_index, count);
+    }
+  };
+
+  hb_vector_t<class_info_t> get_class_info (gsubgpos_graph_context_t& c,
+                                            unsigned this_index)
+  {
+    hb_vector_t<class_info_t> class_to_info;
+
+    unsigned class_count = classCount;
+    if (!class_count) return class_to_info;
+
+    if (!class_to_info.resize (class_count))
+      return hb_vector_t<class_info_t>();
+
+    auto mark_array = c.graph.as_table<MarkArray> (this_index, &markArray);
+    if (!mark_array) return hb_vector_t<class_info_t> ();
+    unsigned mark_count = mark_array.table->len;
+    for (unsigned mark = 0; mark < mark_count; mark++)
+    {
+      unsigned klass = (*mark_array.table)[mark].get_class ();
+      if (klass >= class_count) continue;
+      class_to_info[klass].marks.add (mark);
+    }
+
+    for (const auto& link : mark_array.vertex->obj.real_links)
+    {
+      unsigned mark = (link.position - 2) /
+                     OT::Layout::GPOS_impl::MarkRecord::static_size;
+      unsigned klass = (*mark_array.table)[mark].get_class ();
+      if (klass >= class_count) continue;
+      class_to_info[klass].child_indices.push (link.objidx);
+    }
+
+    unsigned base_array_id =
+        c.graph.index_for_offset (this_index, &baseArray);
+    auto& base_array_v = c.graph.vertices_[base_array_id];
+
+    for (const auto& link : base_array_v.obj.real_links)
+    {
+      unsigned index = (link.position - 2) / OT::Offset16::static_size;
+      unsigned klass = index % class_count;
+      class_to_info[klass].child_indices.push (link.objidx);
+    }
+
+    return class_to_info;
+  }
+
+  bool shrink (split_context_t& sc,
+               unsigned this_index,
+               unsigned count)
+  {
+    DEBUG_MSG (SUBSET_REPACK, nullptr,
+               "  Shrinking MarkBasePosFormat1 (%u) to [0, %u).",
+               this_index,
+               count);
+
+    unsigned old_count = classCount;
+    if (count >= old_count)
+      return true;
+
+    classCount = count;
+
+    auto mark_coverage = sc.c.graph.as_mutable_table<Coverage> (this_index,
+                                                                &markCoverage);
+    if (!mark_coverage) return false;
+    hb_set_t marks = sc.marks_for (0, count);
+    auto new_coverage =
+        + hb_enumerate (mark_coverage.table->iter ())
+        | hb_filter (marks, hb_first)
+        | hb_map_retains_sorting (hb_second)
+        ;
+    if (!Coverage::make_coverage (sc.c, + new_coverage,
+                                  mark_coverage.index,
+                                  4 + 2 * marks.get_population ()))
+      return false;
+
+
+    auto base_array = sc.c.graph.as_mutable_table<AnchorMatrix> (this_index,
+                                                                 &baseArray,
+                                                                 old_count);
+    if (!base_array || !base_array.table->shrink (sc.c,
+                                                  base_array.index,
+                                                  old_count,
+                                                  count))
+      return false;
+
+    auto mark_array = sc.c.graph.as_mutable_table<MarkArray> (this_index,
+                                                              &markArray);
+    if (!mark_array || !mark_array.table->shrink (sc.c,
+                                                  sc.mark_array_links,
+                                                  mark_array.index,
+                                                  count))
+      return false;
+
+    return true;
+  }
+
+  // Create a new MarkBasePos that has all of the data for classes from [start, end).
+  unsigned clone_range (split_context_t& sc,
+                        unsigned this_index,
+                        unsigned start, unsigned end) const
+  {
+    DEBUG_MSG (SUBSET_REPACK, nullptr,
+               "  Cloning MarkBasePosFormat1 (%u) range [%u, %u).", this_index, start, end);
+
+    graph_t& graph = sc.c.graph;
+    unsigned prime_size = OT::Layout::GPOS_impl::MarkBasePosFormat1_2<SmallTypes>::static_size;
+
+    unsigned prime_id = sc.c.create_node (prime_size);
+    if (prime_id == (unsigned) -1) return -1;
+
+    MarkBasePosFormat1* prime = (MarkBasePosFormat1*) graph.object (prime_id).head;
+    prime->format = this->format;
+    unsigned new_class_count = end - start;
+    prime->classCount = new_class_count;
+
+    unsigned base_coverage_id =
+        graph.index_for_offset (sc.this_index, &baseCoverage);
+    graph.add_link (&(prime->baseCoverage), prime_id, base_coverage_id);
+    graph.duplicate (prime_id, base_coverage_id);
+
+    auto mark_coverage = sc.c.graph.as_table<Coverage> (this_index,
+                                                        &markCoverage);
+    if (!mark_coverage) return false;
+    hb_set_t marks = sc.marks_for (start, end);
+    auto new_coverage =
+        + hb_enumerate (mark_coverage.table->iter ())
+        | hb_filter (marks, hb_first)
+        | hb_map_retains_sorting (hb_second)
+        ;
+    if (!Coverage::add_coverage (sc.c,
+                                 prime_id,
+                                 2,
+                                 + new_coverage,
+                                 marks.get_population () * 2 + 4))
+      return -1;
+
+    auto mark_array =
+        graph.as_table <MarkArray> (sc.this_index, &markArray);
+    if (!mark_array) return -1;
+    unsigned new_mark_array =
+        mark_array.table->clone (sc.c,
+                                 mark_array.index,
+                                 sc.mark_array_links,
+                                 marks,
+                                 start);
+    graph.add_link (&(prime->markArray), prime_id, new_mark_array);
+
+    unsigned class_count = classCount;
+    auto base_array =
+        graph.as_table<AnchorMatrix> (sc.this_index, &baseArray, class_count);
+    if (!base_array) return -1;
+    unsigned new_base_array =
+        base_array.table->clone (sc.c,
+                                 base_array.index,
+                                 start, end, this->classCount);
+    graph.add_link (&(prime->baseArray), prime_id, new_base_array);
+
+    return prime_id;
+  }
+};
+
+
+struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos
+{
+  hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+                                         unsigned parent_index,
+                                         unsigned this_index)
+  {
+    switch (u.format) {
+    case 1:
+      return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
+#ifndef HB_NO_BEYOND_64K
+    case 2: HB_FALLTHROUGH;
+      // Don't split 24bit MarkBasePos's.
+#endif
+    default:
+      return hb_vector_t<unsigned> ();
+    }
+  }
+
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    if (vertex_len < u.format.get_size ()) return false;
+
+    switch (u.format) {
+    case 1:
+      return ((MarkBasePosFormat1*)(&u.format1))->sanitize (vertex);
+#ifndef HB_NO_BEYOND_64K
+    case 2: HB_FALLTHROUGH;
+#endif
+    default:
+      // We don't handle format 3 and 4 here.
+      return false;
+    }
+  }
+};
+
+
+}
+
+#endif  // GRAPH_MARKBASEPOS_GRAPH_HH
diff --git a/src/graph/pairpos-graph.hh b/src/graph/pairpos-graph.hh
new file mode 100644 (file)
index 0000000..ad158cc
--- /dev/null
@@ -0,0 +1,647 @@
+/*
+ * Copyright © 2022  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
+ */
+
+#ifndef GRAPH_PAIRPOS_GRAPH_HH
+#define GRAPH_PAIRPOS_GRAPH_HH
+
+#include "split-helpers.hh"
+#include "coverage-graph.hh"
+#include "classdef-graph.hh"
+#include "../OT/Layout/GPOS/PairPos.hh"
+#include "../OT/Layout/GPOS/PosLookupSubTable.hh"
+
+namespace graph {
+
+struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>
+{
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size;
+    if (vertex_len < min_size) return false;
+
+    return vertex_len >=
+        min_size + pairSet.get_size () - pairSet.len.get_size();
+  }
+
+  hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+                                         unsigned parent_index,
+                                         unsigned this_index)
+  {
+    hb_set_t visited;
+
+    const unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
+    const unsigned coverage_size = c.graph.vertices_[coverage_id].table_size ();
+    const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size;
+
+    unsigned partial_coverage_size = 4;
+    unsigned accumulated = base_size;
+    hb_vector_t<unsigned> split_points;
+    for (unsigned i = 0; i < pairSet.len; i++)
+    {
+      unsigned pair_set_index = pair_set_graph_index (c, this_index, i);
+      unsigned accumulated_delta =
+          c.graph.find_subgraph_size (pair_set_index, visited) +
+          SmallTypes::size; // for PairSet offset.
+      partial_coverage_size += OT::HBUINT16::static_size;
+
+      accumulated += accumulated_delta;
+      unsigned total = accumulated + hb_min (partial_coverage_size, coverage_size);
+
+      if (total >= (1 << 16))
+      {
+        split_points.push (i);
+        accumulated = base_size + accumulated_delta;
+        partial_coverage_size = 6;
+        visited.clear (); // node sharing isn't allowed between splits.
+      }
+    }
+
+    split_context_t split_context {
+      c,
+      this,
+      c.graph.duplicate_if_shared (parent_index, this_index),
+    };
+
+    return actuate_subtable_split<split_context_t> (split_context, split_points);
+  }
+
+ private:
+
+  struct split_context_t {
+    gsubgpos_graph_context_t& c;
+    PairPosFormat1* thiz;
+    unsigned this_index;
+
+    unsigned original_count ()
+    {
+      return thiz->pairSet.len;
+    }
+
+    unsigned clone_range (unsigned start, unsigned end)
+    {
+      return thiz->clone_range (this->c, this->this_index, start, end);
+    }
+
+    bool shrink (unsigned count)
+    {
+      return thiz->shrink (this->c, this->this_index, count);
+    }
+  };
+
+  bool shrink (gsubgpos_graph_context_t& c,
+               unsigned this_index,
+               unsigned count)
+  {
+    DEBUG_MSG (SUBSET_REPACK, nullptr,
+               "  Shrinking PairPosFormat1 (%u) to [0, %u).",
+               this_index,
+               count);
+    unsigned old_count = pairSet.len;
+    if (count >= old_count)
+      return true;
+
+    pairSet.len = count;
+    c.graph.vertices_[this_index].obj.tail -= (old_count - count) * SmallTypes::size;
+
+    auto coverage = c.graph.as_mutable_table<Coverage> (this_index, &this->coverage);
+    if (!coverage) return false;
+
+    unsigned coverage_size = coverage.vertex->table_size ();
+    auto new_coverage =
+        + hb_zip (coverage.table->iter (), hb_range ())
+        | hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) {
+          return p.second < count;
+        })
+        | hb_map_retains_sorting (hb_first)
+        ;
+
+    return Coverage::make_coverage (c, new_coverage, coverage.index, coverage_size);
+  }
+
+  // Create a new PairPos including PairSet's from start (inclusive) to end (exclusive).
+  // Returns object id of the new object.
+  unsigned clone_range (gsubgpos_graph_context_t& c,
+                        unsigned this_index,
+                        unsigned start, unsigned end) const
+  {
+    DEBUG_MSG (SUBSET_REPACK, nullptr,
+               "  Cloning PairPosFormat1 (%u) range [%u, %u).", this_index, start, end);
+
+    unsigned num_pair_sets = end - start;
+    unsigned prime_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size
+                          + num_pair_sets * SmallTypes::size;
+
+    unsigned pair_pos_prime_id = c.create_node (prime_size);
+    if (pair_pos_prime_id == (unsigned) -1) return -1;
+
+    PairPosFormat1* pair_pos_prime = (PairPosFormat1*) c.graph.object (pair_pos_prime_id).head;
+    pair_pos_prime->format = this->format;
+    pair_pos_prime->valueFormat[0] = this->valueFormat[0];
+    pair_pos_prime->valueFormat[1] = this->valueFormat[1];
+    pair_pos_prime->pairSet.len = num_pair_sets;
+
+    for (unsigned i = start; i < end; i++)
+    {
+      c.graph.move_child<> (this_index,
+                            &pairSet[i],
+                            pair_pos_prime_id,
+                            &pair_pos_prime->pairSet[i - start]);
+    }
+
+    unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
+    if (!Coverage::clone_coverage (c,
+                                   coverage_id,
+                                   pair_pos_prime_id,
+                                   2,
+                                   start, end))
+      return -1;
+
+    return pair_pos_prime_id;
+  }
+
+
+
+  unsigned pair_set_graph_index (gsubgpos_graph_context_t& c, unsigned this_index, unsigned i) const
+  {
+    return c.graph.index_for_offset (this_index, &pairSet[i]);
+  }
+};
+
+struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>
+{
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    size_t vertex_len = vertex.table_size ();
+    unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size;
+    if (vertex_len < min_size) return false;
+
+    const unsigned class1_count = class1Count;
+    return vertex_len >=
+        min_size + class1_count * get_class1_record_size ();
+  }
+
+  hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+                                         unsigned parent_index,
+                                         unsigned this_index)
+  {
+    const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size;
+    const unsigned class_def_2_size = size_of (c, this_index, &classDef2);
+    const Coverage* coverage = get_coverage (c, this_index);
+    const ClassDef* class_def_1 = get_class_def_1 (c, this_index);
+    auto gid_and_class =
+        + coverage->iter ()
+        | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
+          return hb_codepoint_pair_t (gid, class_def_1->get_class (gid));
+        })
+        ;
+    class_def_size_estimator_t estimator (gid_and_class);
+
+    const unsigned class1_count = class1Count;
+    const unsigned class2_count = class2Count;
+    const unsigned class1_record_size = get_class1_record_size ();
+
+    const unsigned value_1_len = valueFormat1.get_len ();
+    const unsigned value_2_len = valueFormat2.get_len ();
+    const unsigned total_value_len = value_1_len + value_2_len;
+
+    unsigned accumulated = base_size;
+    unsigned coverage_size = 4;
+    unsigned class_def_1_size = 4;
+    unsigned max_coverage_size = coverage_size;
+    unsigned max_class_def_1_size = class_def_1_size;
+
+    hb_vector_t<unsigned> split_points;
+
+    hb_hashmap_t<unsigned, unsigned> device_tables = get_all_device_tables (c, this_index);
+    hb_vector_t<unsigned> format1_device_table_indices = valueFormat1.get_device_table_indices ();
+    hb_vector_t<unsigned> format2_device_table_indices = valueFormat2.get_device_table_indices ();
+    bool has_device_tables = bool(format1_device_table_indices) || bool(format2_device_table_indices);
+
+    hb_set_t visited;
+    for (unsigned i = 0; i < class1_count; i++)
+    {
+      unsigned accumulated_delta = class1_record_size;
+      coverage_size += estimator.incremental_coverage_size (i);
+      class_def_1_size += estimator.incremental_class_def_size (i);
+      max_coverage_size = hb_max (max_coverage_size, coverage_size);
+      max_class_def_1_size = hb_max (max_class_def_1_size, class_def_1_size);
+
+      if (has_device_tables) {
+        for (unsigned j = 0; j < class2_count; j++)
+        {
+          unsigned value1_index = total_value_len * (class2_count * i + j);
+          unsigned value2_index = value1_index + value_1_len;
+          accumulated_delta += size_of_value_record_children (c,
+                                                        device_tables,
+                                                        format1_device_table_indices,
+                                                        value1_index,
+                                                        visited);
+          accumulated_delta += size_of_value_record_children (c,
+                                                        device_tables,
+                                                        format2_device_table_indices,
+                                                        value2_index,
+                                                        visited);
+        }
+      }
+
+      accumulated += accumulated_delta;
+      unsigned total = accumulated
+                       + coverage_size + class_def_1_size + class_def_2_size
+                       // The largest object will pack last and can exceed the size limit.
+                       - hb_max (hb_max (coverage_size, class_def_1_size), class_def_2_size);
+      if (total >= (1 << 16))
+      {
+        split_points.push (i);
+        // split does not include i, so add the size for i when we reset the size counters.
+        accumulated = base_size + accumulated_delta;
+        coverage_size = 4 + estimator.incremental_coverage_size (i);
+        class_def_1_size = 4 + estimator.incremental_class_def_size (i);
+        visited.clear (); // node sharing isn't allowed between splits.
+      }
+    }
+
+    split_context_t split_context {
+      c,
+      this,
+      c.graph.duplicate_if_shared (parent_index, this_index),
+      class1_record_size,
+      total_value_len,
+      value_1_len,
+      value_2_len,
+      max_coverage_size,
+      max_class_def_1_size,
+      device_tables,
+      format1_device_table_indices,
+      format2_device_table_indices
+    };
+
+    return actuate_subtable_split<split_context_t> (split_context, split_points);
+  }
+ private:
+
+  struct split_context_t
+  {
+    gsubgpos_graph_context_t& c;
+    PairPosFormat2* thiz;
+    unsigned this_index;
+    unsigned class1_record_size;
+    unsigned value_record_len;
+    unsigned value1_record_len;
+    unsigned value2_record_len;
+    unsigned max_coverage_size;
+    unsigned max_class_def_size;
+
+    const hb_hashmap_t<unsigned, unsigned>& device_tables;
+    const hb_vector_t<unsigned>& format1_device_table_indices;
+    const hb_vector_t<unsigned>& format2_device_table_indices;
+
+    unsigned original_count ()
+    {
+      return thiz->class1Count;
+    }
+
+    unsigned clone_range (unsigned start, unsigned end)
+    {
+      return thiz->clone_range (*this, start, end);
+    }
+
+    bool shrink (unsigned count)
+    {
+      return thiz->shrink (*this, count);
+    }
+  };
+
+  size_t get_class1_record_size () const
+  {
+    const size_t class2_count = class2Count;
+    return
+        class2_count * (valueFormat1.get_size () + valueFormat2.get_size ());
+  }
+
+  unsigned clone_range (split_context_t& split_context,
+                        unsigned start, unsigned end) const
+  {
+    DEBUG_MSG (SUBSET_REPACK, nullptr,
+               "  Cloning PairPosFormat2 (%u) range [%u, %u).", split_context.this_index, start, end);
+
+    graph_t& graph = split_context.c.graph;
+
+    unsigned num_records = end - start;
+    unsigned prime_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size
+                          + num_records * split_context.class1_record_size;
+
+    unsigned pair_pos_prime_id = split_context.c.create_node (prime_size);
+    if (pair_pos_prime_id == (unsigned) -1) return -1;
+
+    PairPosFormat2* pair_pos_prime =
+        (PairPosFormat2*) graph.object (pair_pos_prime_id).head;
+    pair_pos_prime->format = this->format;
+    pair_pos_prime->valueFormat1 = this->valueFormat1;
+    pair_pos_prime->valueFormat2 = this->valueFormat2;
+    pair_pos_prime->class1Count = num_records;
+    pair_pos_prime->class2Count = this->class2Count;
+    clone_class1_records (split_context,
+                          pair_pos_prime_id,
+                          start,
+                          end);
+
+    unsigned coverage_id =
+        graph.index_for_offset (split_context.this_index, &coverage);
+    unsigned class_def_1_id =
+        graph.index_for_offset (split_context.this_index, &classDef1);
+    auto& coverage_v = graph.vertices_[coverage_id];
+    auto& class_def_1_v = graph.vertices_[class_def_1_id];
+    Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
+    ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head;
+    if (!coverage_table
+        || !coverage_table->sanitize (coverage_v)
+        || !class_def_1_table
+        || !class_def_1_table->sanitize (class_def_1_v))
+      return -1;
+
+    auto klass_map =
+    + coverage_table->iter ()
+    | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
+      return hb_codepoint_pair_t (gid, class_def_1_table->get_class (gid));
+    })
+    | hb_filter ([&] (hb_codepoint_t klass) {
+      return klass >= start && klass < end;
+    }, hb_second)
+    | hb_map_retains_sorting ([&] (hb_codepoint_pair_t gid_and_class) {
+      // Classes must be from 0...N so subtract start
+      return hb_codepoint_pair_t (gid_and_class.first, gid_and_class.second - start);
+    })
+    ;
+
+    if (!Coverage::add_coverage (split_context.c,
+                                 pair_pos_prime_id,
+                                 2,
+                                 + klass_map | hb_map_retains_sorting (hb_first),
+                                 split_context.max_coverage_size))
+      return -1;
+
+    // classDef1
+    if (!ClassDef::add_class_def (split_context.c,
+                                  pair_pos_prime_id,
+                                  8,
+                                  + klass_map,
+                                  split_context.max_class_def_size))
+      return -1;
+
+    // classDef2
+    unsigned class_def_2_id =
+        graph.index_for_offset (split_context.this_index, &classDef2);
+    auto* class_def_link = graph.vertices_[pair_pos_prime_id].obj.real_links.push ();
+    class_def_link->width = SmallTypes::size;
+    class_def_link->objidx = class_def_2_id;
+    class_def_link->position = 10;
+    graph.vertices_[class_def_2_id].add_parent (pair_pos_prime_id);
+    graph.duplicate (pair_pos_prime_id, class_def_2_id);
+
+    return pair_pos_prime_id;
+  }
+
+  void clone_class1_records (split_context_t& split_context,
+                             unsigned pair_pos_prime_id,
+                             unsigned start, unsigned end) const
+  {
+    PairPosFormat2* pair_pos_prime =
+        (PairPosFormat2*) split_context.c.graph.object (pair_pos_prime_id).head;
+
+    char* start_addr = ((char*)&values[0]) + start * split_context.class1_record_size;
+    unsigned num_records = end - start;
+    hb_memcpy (&pair_pos_prime->values[0],
+            start_addr,
+            num_records * split_context.class1_record_size);
+
+    if (!split_context.format1_device_table_indices
+        && !split_context.format2_device_table_indices)
+      // No device tables to move over.
+      return;
+
+    unsigned class2_count = class2Count;
+    for (unsigned i = start; i < end; i++)
+    {
+      for (unsigned j = 0; j < class2_count; j++)
+      {
+        unsigned value1_index = split_context.value_record_len * (class2_count * i + j);
+        unsigned value2_index = value1_index + split_context.value1_record_len;
+
+        unsigned new_value1_index = split_context.value_record_len * (class2_count * (i - start) + j);
+        unsigned new_value2_index = new_value1_index + split_context.value1_record_len;
+
+        transfer_device_tables (split_context,
+                                pair_pos_prime_id,
+                                split_context.format1_device_table_indices,
+                                value1_index,
+                                new_value1_index);
+
+        transfer_device_tables (split_context,
+                                pair_pos_prime_id,
+                                split_context.format2_device_table_indices,
+                                value2_index,
+                                new_value2_index);
+      }
+    }
+  }
+
+  void transfer_device_tables (split_context_t& split_context,
+                               unsigned pair_pos_prime_id,
+                               const hb_vector_t<unsigned>& device_table_indices,
+                               unsigned old_value_record_index,
+                               unsigned new_value_record_index) const
+  {
+    PairPosFormat2* pair_pos_prime =
+        (PairPosFormat2*) split_context.c.graph.object (pair_pos_prime_id).head;
+
+    for (unsigned i : device_table_indices)
+    {
+      OT::Offset16* record = (OT::Offset16*) &values[old_value_record_index + i];
+      unsigned record_position = ((char*) record) - ((char*) this);
+      if (!split_context.device_tables.has (record_position)) continue;
+
+      split_context.c.graph.move_child (
+          split_context.this_index,
+          record,
+          pair_pos_prime_id,
+          (OT::Offset16*) &pair_pos_prime->values[new_value_record_index + i]);
+    }
+  }
+
+  bool shrink (split_context_t& split_context,
+               unsigned count)
+  {
+    DEBUG_MSG (SUBSET_REPACK, nullptr,
+               "  Shrinking PairPosFormat2 (%u) to [0, %u).",
+               split_context.this_index,
+               count);
+    unsigned old_count = class1Count;
+    if (count >= old_count)
+      return true;
+
+    graph_t& graph = split_context.c.graph;
+    class1Count = count;
+    graph.vertices_[split_context.this_index].obj.tail -=
+        (old_count - count) * split_context.class1_record_size;
+
+    auto coverage =
+        graph.as_mutable_table<Coverage> (split_context.this_index, &this->coverage);
+    if (!coverage) return false;
+
+    auto class_def_1 =
+        graph.as_mutable_table<ClassDef> (split_context.this_index, &classDef1);
+    if (!class_def_1) return false;
+
+    auto klass_map =
+    + coverage.table->iter ()
+    | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
+      return hb_codepoint_pair_t (gid, class_def_1.table->get_class (gid));
+    })
+    | hb_filter ([&] (hb_codepoint_t klass) {
+      return klass < count;
+    }, hb_second)
+    ;
+
+    auto new_coverage = + klass_map | hb_map_retains_sorting (hb_first);
+    if (!Coverage::make_coverage (split_context.c,
+                                  + new_coverage,
+                                  coverage.index,
+                                  // existing ranges my not be kept, worst case size is a format 1
+                                  // coverage table.
+                                  4 + new_coverage.len() * 2))
+      return false;
+
+    return ClassDef::make_class_def (split_context.c,
+                                     + klass_map,
+                                     class_def_1.index,
+                                     class_def_1.vertex->table_size ());
+  }
+
+  hb_hashmap_t<unsigned, unsigned>
+  get_all_device_tables (gsubgpos_graph_context_t& c,
+                         unsigned this_index) const
+  {
+    const auto& v = c.graph.vertices_[this_index];
+    return v.position_to_index_map ();
+  }
+
+  const Coverage* get_coverage (gsubgpos_graph_context_t& c,
+                          unsigned this_index) const
+  {
+    unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
+    auto& coverage_v = c.graph.vertices_[coverage_id];
+
+    Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
+    if (!coverage_table || !coverage_table->sanitize (coverage_v))
+      return &Null(Coverage);
+    return coverage_table;
+  }
+
+  const ClassDef* get_class_def_1 (gsubgpos_graph_context_t& c,
+                                   unsigned this_index) const
+  {
+    unsigned class_def_1_id = c.graph.index_for_offset (this_index, &classDef1);
+    auto& class_def_1_v = c.graph.vertices_[class_def_1_id];
+
+    ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head;
+    if (!class_def_1_table || !class_def_1_table->sanitize (class_def_1_v))
+      return &Null(ClassDef);
+    return class_def_1_table;
+  }
+
+  unsigned size_of_value_record_children (gsubgpos_graph_context_t& c,
+                                          const hb_hashmap_t<unsigned, unsigned>& device_tables,
+                                          const hb_vector_t<unsigned> device_table_indices,
+                                          unsigned value_record_index,
+                                          hb_set_t& visited)
+  {
+    unsigned size = 0;
+    for (unsigned i : device_table_indices)
+    {
+      OT::Layout::GPOS_impl::Value* record = &values[value_record_index + i];
+      unsigned record_position = ((char*) record) - ((char*) this);
+      unsigned* obj_idx;
+      if (!device_tables.has (record_position, &obj_idx)) continue;
+      size += c.graph.find_subgraph_size (*obj_idx, visited);
+    }
+    return size;
+  }
+
+  unsigned size_of (gsubgpos_graph_context_t& c,
+                    unsigned this_index,
+                    const void* offset) const
+  {
+    const unsigned id = c.graph.index_for_offset (this_index, offset);
+    return c.graph.vertices_[id].table_size ();
+  }
+};
+
+struct PairPos : public OT::Layout::GPOS_impl::PairPos
+{
+  hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+                                         unsigned parent_index,
+                                         unsigned this_index)
+  {
+    switch (u.format) {
+    case 1:
+      return ((PairPosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
+    case 2:
+      return ((PairPosFormat2*)(&u.format2))->split_subtables (c, parent_index, this_index);
+#ifndef HB_NO_BEYOND_64K
+    case 3: HB_FALLTHROUGH;
+    case 4: HB_FALLTHROUGH;
+      // Don't split 24bit PairPos's.
+#endif
+    default:
+      return hb_vector_t<unsigned> ();
+    }
+  }
+
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    if (vertex_len < u.format.get_size ()) return false;
+
+    switch (u.format) {
+    case 1:
+      return ((PairPosFormat1*)(&u.format1))->sanitize (vertex);
+    case 2:
+      return ((PairPosFormat2*)(&u.format2))->sanitize (vertex);
+#ifndef HB_NO_BEYOND_64K
+    case 3: HB_FALLTHROUGH;
+    case 4: HB_FALLTHROUGH;
+#endif
+    default:
+      // We don't handle format 3 and 4 here.
+      return false;
+    }
+  }
+};
+
+}
+
+#endif  // GRAPH_PAIRPOS_GRAPH_HH
diff --git a/src/graph/serialize.hh b/src/graph/serialize.hh
new file mode 100644 (file)
index 0000000..06e4bf4
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Copyright © 2022  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
+ */
+
+#ifndef GRAPH_SERIALIZE_HH
+#define GRAPH_SERIALIZE_HH
+
+namespace graph {
+
+struct overflow_record_t
+{
+  unsigned parent;
+  unsigned child;
+
+  bool operator != (const overflow_record_t o) const
+  { return !(*this == o); }
+
+  inline bool operator == (const overflow_record_t& o) const
+  {
+    return parent == o.parent &&
+        child == o.child;
+  }
+
+  inline uint32_t hash () const
+  {
+    uint32_t current = 0;
+    current = current * 31 + hb_hash (parent);
+    current = current * 31 + hb_hash (child);
+    return current;
+  }
+};
+
+inline
+int64_t compute_offset (
+    const graph_t& graph,
+    unsigned parent_idx,
+    const hb_serialize_context_t::object_t::link_t& link)
+{
+  const auto& parent = graph.vertices_[parent_idx];
+  const auto& child = graph.vertices_[link.objidx];
+  int64_t offset = 0;
+  switch ((hb_serialize_context_t::whence_t) link.whence) {
+    case hb_serialize_context_t::whence_t::Head:
+      offset = child.start - parent.start; break;
+    case hb_serialize_context_t::whence_t::Tail:
+      offset = child.start - parent.end; break;
+    case hb_serialize_context_t::whence_t::Absolute:
+      offset = child.start; break;
+  }
+
+  assert (offset >= link.bias);
+  offset -= link.bias;
+  return offset;
+}
+
+inline
+bool is_valid_offset (int64_t offset,
+                      const hb_serialize_context_t::object_t::link_t& link)
+{
+  if (unlikely (!link.width))
+    // Virtual links can't overflow.
+    return link.is_signed || offset >= 0;
+
+  if (link.is_signed)
+  {
+    if (link.width == 4)
+      return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31);
+    else
+      return offset >= -(1 << 15) && offset < (1 << 15);
+  }
+  else
+  {
+    if (link.width == 4)
+      return offset >= 0 && offset < ((int64_t) 1 << 32);
+    else if (link.width == 3)
+      return offset >= 0 && offset < ((int32_t) 1 << 24);
+    else
+      return offset >= 0 && offset < (1 << 16);
+  }
+}
+
+/*
+ * Will any offsets overflow on graph when it's serialized?
+ */
+inline bool
+will_overflow (graph_t& graph,
+               hb_vector_t<overflow_record_t>* overflows = nullptr)
+{
+  if (overflows) overflows->resize (0);
+  graph.update_positions ();
+
+  hb_hashmap_t<overflow_record_t*, bool> record_set;
+  const auto& vertices = graph.vertices_;
+  for (int parent_idx = vertices.length - 1; parent_idx >= 0; parent_idx--)
+  {
+    // Don't need to check virtual links for overflow
+    for (const auto& link : vertices.arrayZ[parent_idx].obj.real_links)
+    {
+      int64_t offset = compute_offset (graph, parent_idx, link);
+      if (likely (is_valid_offset (offset, link)))
+        continue;
+
+      if (!overflows) return true;
+
+      overflow_record_t r;
+      r.parent = parent_idx;
+      r.child = link.objidx;
+      if (record_set.has(&r)) continue; // don't keep duplicate overflows.
+
+      overflows->push (r);
+      record_set.set(&r, true);
+    }
+  }
+
+  if (!overflows) return false;
+  return overflows->length;
+}
+
+inline
+void print_overflows (graph_t& graph,
+                      const hb_vector_t<overflow_record_t>& overflows)
+{
+  if (!DEBUG_ENABLED(SUBSET_REPACK)) return;
+
+  graph.update_parents ();
+  int limit = 10;
+  for (const auto& o : overflows)
+  {
+    if (!limit--) break;
+    const auto& parent = graph.vertices_[o.parent];
+    const auto& child = graph.vertices_[o.child];
+    DEBUG_MSG (SUBSET_REPACK, nullptr,
+               "  overflow from "
+               "%4u (%4u in, %4u out, space %2u) => "
+               "%4u (%4u in, %4u out, space %2u)",
+               o.parent,
+               parent.incoming_edges (),
+               parent.obj.real_links.length + parent.obj.virtual_links.length,
+               graph.space_for (o.parent),
+               o.child,
+               child.incoming_edges (),
+               child.obj.real_links.length + child.obj.virtual_links.length,
+               graph.space_for (o.child));
+  }
+  if (overflows.length > 10) {
+    DEBUG_MSG (SUBSET_REPACK, nullptr, "  ... plus %u more overflows.", overflows.length - 10);
+  }
+}
+
+template <typename O> inline void
+serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link,
+                        char* head,
+                        hb_serialize_context_t* c)
+{
+  OT::Offset<O>* offset = reinterpret_cast<OT::Offset<O>*> (head + link.position);
+  *offset = 0;
+  c->add_link (*offset,
+               // serializer has an extra nil object at the start of the
+               // object array. So all id's are +1 of what our id's are.
+               link.objidx + 1,
+               (hb_serialize_context_t::whence_t) link.whence,
+               link.bias);
+}
+
+inline
+void serialize_link (const hb_serialize_context_t::object_t::link_t& link,
+                     char* head,
+                     hb_serialize_context_t* c)
+{
+  switch (link.width)
+  {
+    case 0:
+      // Virtual links aren't serialized.
+      return;
+    case 4:
+      if (link.is_signed)
+      {
+        serialize_link_of_type<OT::HBINT32> (link, head, c);
+      } else {
+        serialize_link_of_type<OT::HBUINT32> (link, head, c);
+      }
+      return;
+    case 2:
+      if (link.is_signed)
+      {
+        serialize_link_of_type<OT::HBINT16> (link, head, c);
+      } else {
+        serialize_link_of_type<OT::HBUINT16> (link, head, c);
+      }
+      return;
+    case 3:
+      serialize_link_of_type<OT::HBUINT24> (link, head, c);
+      return;
+    default:
+      // Unexpected link width.
+      assert (0);
+  }
+}
+
+/*
+ * serialize graph into the provided serialization buffer.
+ */
+inline hb_blob_t* serialize (const graph_t& graph)
+{
+  hb_vector_t<char> buffer;
+  size_t size = graph.total_size_in_bytes ();
+
+  if (!size) return hb_blob_get_empty ();
+
+  if (!buffer.alloc (size)) {
+    DEBUG_MSG (SUBSET_REPACK, nullptr, "Unable to allocate output buffer.");
+    return nullptr;
+  }
+  hb_serialize_context_t c((void *) buffer, size);
+
+  c.start_serialize<void> ();
+  const auto& vertices = graph.vertices_;
+  for (unsigned i = 0; i < vertices.length; i++) {
+    c.push ();
+
+    size_t size = vertices[i].obj.tail - vertices[i].obj.head;
+    char* start = c.allocate_size <char> (size);
+    if (!start) {
+      DEBUG_MSG (SUBSET_REPACK, nullptr, "Buffer out of space.");
+      return nullptr;
+    }
+
+    hb_memcpy (start, vertices[i].obj.head, size);
+
+    // Only real links needs to be serialized.
+    for (const auto& link : vertices[i].obj.real_links)
+      serialize_link (link, start, &c);
+
+    // All duplications are already encoded in the graph, so don't
+    // enable sharing during packing.
+    c.pop_pack (false);
+  }
+  c.end_serialize ();
+
+  if (c.in_error ()) {
+    DEBUG_MSG (SUBSET_REPACK, nullptr, "Error during serialization. Err flag: %d",
+               c.errors);
+    return nullptr;
+  }
+
+  return c.copy_blob ();
+}
+
+} // namespace graph
+
+#endif // GRAPH_SERIALIZE_HH
diff --git a/src/graph/split-helpers.hh b/src/graph/split-helpers.hh
new file mode 100644 (file)
index 0000000..61fd7c2
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2022  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
+ */
+
+#ifndef GRAPH_SPLIT_HELPERS_HH
+#define GRAPH_SPLIT_HELPERS_HH
+
+namespace graph {
+
+template<typename Context>
+HB_INTERNAL
+hb_vector_t<unsigned> actuate_subtable_split (Context& split_context,
+                                              const hb_vector_t<unsigned>& split_points)
+{
+  hb_vector_t<unsigned> new_objects;
+  if (!split_points)
+    return new_objects;
+
+  for (unsigned i = 0; i < split_points.length; i++)
+  {
+    unsigned start = split_points[i];
+    unsigned end = (i < split_points.length - 1)
+                   ? split_points[i + 1]
+                   : split_context.original_count ();
+    unsigned id = split_context.clone_range (start, end);
+
+    if (id == (unsigned) -1)
+    {
+      new_objects.reset ();
+      new_objects.allocated = -1; // mark error
+      return new_objects;
+    }
+    new_objects.push (id);
+  }
+
+  if (!split_context.shrink (split_points[0]))
+  {
+    new_objects.reset ();
+    new_objects.allocated = -1; // mark error
+  }
+
+  return new_objects;
+}
+
+}
+
+#endif  // GRAPH_SPLIT_HELPERS_HH
diff --git a/src/graph/test-classdef-graph.cc b/src/graph/test-classdef-graph.cc
new file mode 100644 (file)
index 0000000..266be5e
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright © 2022  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
+ */
+
+#include "gsubgpos-context.hh"
+#include "classdef-graph.hh"
+
+typedef hb_codepoint_pair_t gid_and_class_t;
+typedef hb_vector_t<gid_and_class_t> gid_and_class_list_t;
+
+
+static bool incremental_size_is (const gid_and_class_list_t& list, unsigned klass,
+                                 unsigned cov_expected, unsigned class_def_expected)
+{
+  graph::class_def_size_estimator_t estimator (list.iter ());
+
+  unsigned result = estimator.incremental_coverage_size (klass);
+  if (result != cov_expected)
+  {
+    printf ("FAIL: coverage expected size %u but was %u\n", cov_expected, result);
+    return false;
+  }
+
+  result = estimator.incremental_class_def_size (klass);
+  if (result != class_def_expected)
+  {
+    printf ("FAIL: class def expected size %u but was %u\n", class_def_expected, result);
+    return false;
+  }
+
+  return true;
+}
+
+static void test_class_and_coverage_size_estimates ()
+{
+  gid_and_class_list_t empty = {
+  };
+  assert (incremental_size_is (empty, 0, 0, 0));
+  assert (incremental_size_is (empty, 1, 0, 0));
+
+  gid_and_class_list_t class_zero = {
+    {5, 0},
+  };
+  assert (incremental_size_is (class_zero, 0, 2, 0));
+
+  gid_and_class_list_t consecutive = {
+    {4, 0},
+    {5, 0},
+    {6, 1},
+    {7, 1},
+    {8, 2},
+    {9, 2},
+    {10, 2},
+    {11, 2},
+  };
+  assert (incremental_size_is (consecutive, 0, 4, 0));
+  assert (incremental_size_is (consecutive, 1, 4, 4));
+  assert (incremental_size_is (consecutive, 2, 8, 6));
+
+  gid_and_class_list_t non_consecutive = {
+    {4, 0},
+    {5, 0},
+
+    {6, 1},
+    {7, 1},
+
+    {9, 2},
+    {10, 2},
+    {11, 2},
+    {12, 2},
+  };
+  assert (incremental_size_is (non_consecutive, 0, 4, 0));
+  assert (incremental_size_is (non_consecutive, 1, 4, 6));
+  assert (incremental_size_is (non_consecutive, 2, 8, 6));
+
+  gid_and_class_list_t multiple_ranges = {
+    {4, 0},
+    {5, 0},
+
+    {6, 1},
+    {7, 1},
+
+    {9, 1},
+
+    {11, 1},
+    {12, 1},
+    {13, 1},
+  };
+  assert (incremental_size_is (multiple_ranges, 0, 4, 0));
+  assert (incremental_size_is (multiple_ranges, 1, 2 * 6, 3 * 6));
+}
+
+int
+main (int argc, char **argv)
+{
+  test_class_and_coverage_size_estimates ();
+}
diff --git a/src/harfbuzz-cairo.pc.in b/src/harfbuzz-cairo.pc.in
new file mode 100644 (file)
index 0000000..df97ff1
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=%prefix%
+exec_prefix=%exec_prefix%
+libdir=%libdir%
+includedir=%includedir%
+
+Name: harfbuzz cairo integration
+Description: HarfBuzz cairo integration
+Version: %VERSION%
+
+Requires: harfbuzz = %VERSION%
+Libs: -L${libdir} -lharfbuzz-cairo
+Cflags: -I${includedir}/harfbuzz
index 304410d..6abe2d6 100644 (file)
@@ -1,86 +1,32 @@
-# Set these variables so that the `${prefix}/lib` expands to something we can
-# remove.
-set(_harfbuzz_remove_string "REMOVE_ME")
-set(exec_prefix "${_harfbuzz_remove_string}")
-set(prefix "${_harfbuzz_remove_string}")
+@PACKAGE_INIT@
 
-# Compute the installation prefix by stripping components from our current
-# location.
-get_filename_component(_harfbuzz_prefix "${CMAKE_CURRENT_LIST_DIR}" DIRECTORY)
-get_filename_component(_harfbuzz_prefix "${_harfbuzz_prefix}" DIRECTORY)
-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)
-
-# Get the include subdir.
-set(_harfbuzz_includedir "@includedir@")
-string(REPLACE "${_harfbuzz_remove_string}/" "" _harfbuzz_includedir "${_harfbuzz_includedir}")
-
-# Extract version information from libtool.
-set(_harfbuzz_version_info "@HB_LIBTOOL_VERSION_INFO@")
-string(REPLACE ":" ";" _harfbuzz_version_info "${_harfbuzz_version_info}")
-list(GET _harfbuzz_version_info 0
-  _harfbuzz_current)
-list(GET _harfbuzz_version_info 1
-  _harfbuzz_revision)
-list(GET _harfbuzz_version_info 2
-  _harfbuzz_age)
-unset(_harfbuzz_version_info)
-
-if (APPLE)
-  set(_harfbuzz_lib_suffix ".0${CMAKE_SHARED_LIBRARY_SUFFIX}")
-elseif (UNIX)
-  set(_harfbuzz_lib_suffix "${CMAKE_SHARED_LIBRARY_SUFFIX}.0.${_harfbuzz_current}.${_harfbuzz_revision}")
-else ()
-  # Unsupported.
-  set(harfbuzz_FOUND 0)
-endif ()
+set_and_check(HARFBUZZ_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
 
 # Add the libraries.
-add_library(harfbuzz::harfbuzz SHARED IMPORTED)
+add_library(harfbuzz::harfbuzz @HB_LIBRARY_TYPE@ IMPORTED)
 set_target_properties(harfbuzz::harfbuzz PROPERTIES
-  INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
-  IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz${_harfbuzz_lib_suffix}")
+  INTERFACE_INCLUDE_DIRECTORIES "@PACKAGE_INCLUDE_INSTALL_DIR@"
+  IMPORTED_LOCATION "@PACKAGE_CMAKE_INSTALL_LIBDIR@/@HB_LIB_PREFIX@harfbuzz@HB_LIB_SUFFIX@")
 
-add_library(harfbuzz::icu SHARED IMPORTED)
+add_library(harfbuzz::icu @HB_LIBRARY_TYPE@ IMPORTED)
 set_target_properties(harfbuzz::icu PROPERTIES
-  INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
+  INTERFACE_INCLUDE_DIRECTORIES "@PACKAGE_INCLUDE_INSTALL_DIR@"
   INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
-  IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz-icu${_harfbuzz_lib_suffix}")
+  IMPORTED_LOCATION "@PACKAGE_CMAKE_INSTALL_LIBDIR@/@HB_LIB_PREFIX@harfbuzz-icu@HB_LIB_SUFFIX@")
 
-add_library(harfbuzz::subset SHARED IMPORTED)
+add_library(harfbuzz::subset @HB_LIBRARY_TYPE@ IMPORTED)
 set_target_properties(harfbuzz::subset PROPERTIES
-  INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
+  INTERFACE_INCLUDE_DIRECTORIES "@PACKAGE_INCLUDE_INSTALL_DIR@"
   INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
-  IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz-subset${_harfbuzz_lib_suffix}")
+  IMPORTED_LOCATION "@PACKAGE_CMAKE_INSTALL_LIBDIR@/@HB_LIB_PREFIX@harfbuzz-subset@HB_LIB_SUFFIX@")
 
 # Only add the gobject library if it was built.
-set(_harfbuzz_have_gobject "@have_gobject@")
-if (_harfbuzz_have_gobject)
-  add_library(harfbuzz::gobject SHARED IMPORTED)
+if (@HB_HAVE_GOBJECT@)
+  add_library(harfbuzz::gobject @HB_LIBRARY_TYPE@ IMPORTED)
   set_target_properties(harfbuzz::gobject PROPERTIES
-    INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
+    INTERFACE_INCLUDE_DIRECTORIES "@PACKAGE_INCLUDE_INSTALL_DIR@"
     INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
-    IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz-gobject${_harfbuzz_lib_suffix}")
+    IMPORTED_LOCATION "@PACKAGE_CMAKE_INSTALL_LIBDIR@/@HB_LIB_PREFIX@harfbuzz-gobject@HB_LIB_SUFFIX@")
 endif ()
 
-# Clean out variables we used in our scope.
-unset(_harfbuzz_lib_suffix)
-unset(_harfbuzz_current)
-unset(_harfbuzz_revision)
-unset(_harfbuzz_age)
-unset(_harfbuzz_includedir)
-unset(_harfbuzz_libdir)
-unset(_harfbuzz_prefix)
-unset(exec_prefix)
-unset(prefix)
-unset(_harfbuzz_remove_string)
+check_required_components(harfbuzz)
diff --git a/src/harfbuzz-subset.cc b/src/harfbuzz-subset.cc
new file mode 100644 (file)
index 0000000..c0e23b3
--- /dev/null
@@ -0,0 +1,62 @@
+#include "graph/gsubgpos-context.cc"
+#include "hb-aat-layout.cc"
+#include "hb-aat-map.cc"
+#include "hb-blob.cc"
+#include "hb-buffer-serialize.cc"
+#include "hb-buffer-verify.cc"
+#include "hb-buffer.cc"
+#include "hb-common.cc"
+#include "hb-draw.cc"
+#include "hb-face-builder.cc"
+#include "hb-face.cc"
+#include "hb-fallback-shape.cc"
+#include "hb-font.cc"
+#include "hb-map.cc"
+#include "hb-number.cc"
+#include "hb-ot-cff1-table.cc"
+#include "hb-ot-cff2-table.cc"
+#include "hb-ot-color.cc"
+#include "hb-ot-face.cc"
+#include "hb-ot-font.cc"
+#include "hb-ot-layout.cc"
+#include "hb-ot-map.cc"
+#include "hb-ot-math.cc"
+#include "hb-ot-meta.cc"
+#include "hb-ot-metrics.cc"
+#include "hb-ot-name.cc"
+#include "hb-ot-shape-fallback.cc"
+#include "hb-ot-shape-normalize.cc"
+#include "hb-ot-shape.cc"
+#include "hb-ot-shaper-arabic.cc"
+#include "hb-ot-shaper-default.cc"
+#include "hb-ot-shaper-hangul.cc"
+#include "hb-ot-shaper-hebrew.cc"
+#include "hb-ot-shaper-indic-table.cc"
+#include "hb-ot-shaper-indic.cc"
+#include "hb-ot-shaper-khmer.cc"
+#include "hb-ot-shaper-myanmar.cc"
+#include "hb-ot-shaper-syllabic.cc"
+#include "hb-ot-shaper-thai.cc"
+#include "hb-ot-shaper-use.cc"
+#include "hb-ot-shaper-vowel-constraints.cc"
+#include "hb-ot-tag.cc"
+#include "hb-ot-var.cc"
+#include "hb-outline.cc"
+#include "hb-paint-extents.cc"
+#include "hb-paint.cc"
+#include "hb-set.cc"
+#include "hb-shape-plan.cc"
+#include "hb-shape.cc"
+#include "hb-shaper.cc"
+#include "hb-static.cc"
+#include "hb-style.cc"
+#include "hb-subset-cff-common.cc"
+#include "hb-subset-cff1.cc"
+#include "hb-subset-cff2.cc"
+#include "hb-subset-input.cc"
+#include "hb-subset-instancer-solver.cc"
+#include "hb-subset-plan.cc"
+#include "hb-subset-repacker.cc"
+#include "hb-subset.cc"
+#include "hb-ucd.cc"
+#include "hb-unicode.cc"
index 5da64b3..ca13c70 100644 (file)
@@ -3,10 +3,10 @@ exec_prefix=%exec_prefix%
 libdir=%libdir%
 includedir=%includedir%
 
-Name: harfbuzz
+Name: harfbuzz subsetter
 Description: HarfBuzz font subsetter
 Version: %VERSION%
 
-Requires: harfbuzz
+Requires: harfbuzz = %VERSION%
 Libs: -L${libdir} -lharfbuzz-subset
 Cflags: -I${includedir}/harfbuzz
index b6a5957..26e2bc1 100644 (file)
@@ -5,10 +5,17 @@
 #include "hb-buffer-verify.cc"
 #include "hb-buffer.cc"
 #include "hb-common.cc"
+#include "hb-coretext.cc"
+#include "hb-directwrite.cc"
 #include "hb-draw.cc"
+#include "hb-face-builder.cc"
 #include "hb-face.cc"
 #include "hb-fallback-shape.cc"
 #include "hb-font.cc"
+#include "hb-ft.cc"
+#include "hb-gdi.cc"
+#include "hb-glib.cc"
+#include "hb-graphite2.cc"
 #include "hb-map.cc"
 #include "hb-number.cc"
 #include "hb-ot-cff1-table.cc"
 #include "hb-ot-meta.cc"
 #include "hb-ot-metrics.cc"
 #include "hb-ot-name.cc"
-#include "hb-ot-shape-complex-arabic.cc"
-#include "hb-ot-shape-complex-default.cc"
-#include "hb-ot-shape-complex-hangul.cc"
-#include "hb-ot-shape-complex-hebrew.cc"
-#include "hb-ot-shape-complex-indic-table.cc"
-#include "hb-ot-shape-complex-indic.cc"
-#include "hb-ot-shape-complex-khmer.cc"
-#include "hb-ot-shape-complex-myanmar.cc"
-#include "hb-ot-shape-complex-syllabic.cc"
-#include "hb-ot-shape-complex-thai.cc"
-#include "hb-ot-shape-complex-use.cc"
-#include "hb-ot-shape-complex-vowel-constraints.cc"
 #include "hb-ot-shape-fallback.cc"
 #include "hb-ot-shape-normalize.cc"
 #include "hb-ot-shape.cc"
+#include "hb-ot-shaper-arabic.cc"
+#include "hb-ot-shaper-default.cc"
+#include "hb-ot-shaper-hangul.cc"
+#include "hb-ot-shaper-hebrew.cc"
+#include "hb-ot-shaper-indic-table.cc"
+#include "hb-ot-shaper-indic.cc"
+#include "hb-ot-shaper-khmer.cc"
+#include "hb-ot-shaper-myanmar.cc"
+#include "hb-ot-shaper-syllabic.cc"
+#include "hb-ot-shaper-thai.cc"
+#include "hb-ot-shaper-use.cc"
+#include "hb-ot-shaper-vowel-constraints.cc"
 #include "hb-ot-tag.cc"
 #include "hb-ot-var.cc"
+#include "hb-outline.cc"
+#include "hb-paint-extents.cc"
+#include "hb-paint.cc"
 #include "hb-set.cc"
 #include "hb-shape-plan.cc"
 #include "hb-shape.cc"
 #include "hb-style.cc"
 #include "hb-ucd.cc"
 #include "hb-unicode.cc"
-#include "hb-glib.cc"
-#include "hb-ft.cc"
-#include "hb-graphite2.cc"
 #include "hb-uniscribe.cc"
-#include "hb-gdi.cc"
-#include "hb-directwrite.cc"
-#include "hb-coretext.cc"
+#include "hb-wasm-api.cc"
+#include "hb-wasm-shape.cc"
index b52844e..bf12d2e 100644 (file)
@@ -42,7 +42,7 @@ struct BaselineTableFormat0Part
   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:
@@ -78,7 +78,7 @@ struct BaselineTableFormat2Part
   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:
index 1db0f1d..672f80e 100644 (file)
@@ -28,6 +28,7 @@
 #define HB_AAT_LAYOUT_COMMON_HH
 
 #include "hb-aat-layout.hh"
+#include "hb-aat-map.hh"
 #include "hb-open-type.hh"
 
 namespace OT {
@@ -39,6 +40,43 @@ namespace AAT {
 using namespace OT;
 
 
+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;
+  const OT::GDEF *gdef_table;
+  const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
+  hb_mask_t subtable_flags = 0;
+
+  /* Unused. For debug tracing only. */
+  unsigned int lookup_index;
+
+  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; }
+};
+
+
 /*
  * Lookup Table
  */
@@ -415,18 +453,7 @@ struct Lookup
   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 <typename T>
-struct Null<AAT::Lookup<T>> {
-  static AAT::Lookup<T> const & get_null ()
-  { return *reinterpret_cast<const AAT::Lookup<T> *> (_hb_Null_AAT_Lookup); }
-};
-namespace AAT {
+DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2);
 
 enum { DELETED_GLYPH = 0xFFFF };
 
@@ -437,7 +464,8 @@ enum { DELETED_GLYPH = 0xFFFF };
 template <typename T>
 struct Entry
 {
-  bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
+  // This does seem like it's ever called.
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     /* Note, we don't recurse-sanitize data because we don't access it.
@@ -465,7 +493,8 @@ struct Entry
 template <>
 struct Entry<void>
 {
-  bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const
+  // This does seem like it's ever called.
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
@@ -681,6 +710,13 @@ struct ObsoleteTypes
                                     const void *base,
                                     const T *array)
   {
+    /* https://github.com/harfbuzz/harfbuzz/issues/3483 */
+    /* If offset is less than base, return an offset that would
+     * result in an address half a 32bit address-space away,
+     * to make sure sanitize fails even on 32bit builds. */
+    if (unlikely (offset < unsigned ((const char *) array - (const char *) base)))
+      return INT_MAX / T::static_size;
+
     /* https://github.com/harfbuzz/harfbuzz/issues/2816 */
     return (offset - unsigned ((const char *) array - (const char *) base)) / T::static_size;
   }
@@ -744,16 +780,44 @@ struct StateTableDriver
              num_glyphs (face_->get_num_glyphs ()) {}
 
   template <typename context_t>
-  void drive (context_t *c)
+  void drive (context_t *c, hb_aat_apply_context_t *ac)
   {
     if (!c->in_place)
       buffer->clear_output ();
 
     int state = StateTableT::STATE_START_OF_TEXT;
+    // If there's only one range, we already checked the flag.
+    auto *last_range = ac->range_flags && (ac->range_flags->length > 1) ? &(*ac->range_flags)[0] : nullptr;
     for (buffer->idx = 0; buffer->successful;)
     {
+      /* This block is copied in NoncontextualSubtable::apply. Keep in sync. */
+      if (last_range)
+      {
+       auto *range = last_range;
+       if (buffer->idx < buffer->len)
+       {
+         unsigned cluster = buffer->cur().cluster;
+         while (cluster < range->cluster_first)
+           range--;
+         while (cluster > range->cluster_last)
+           range++;
+
+
+         last_range = range;
+       }
+       if (!(range->flags & ac->subtable_flags))
+       {
+         if (buffer->idx == buffer->len || unlikely (!buffer->successful))
+           break;
+
+         state = StateTableT::STATE_START_OF_TEXT;
+         (void) buffer->next_glyph ();
+         continue;
+       }
+      }
+
       unsigned int klass = buffer->idx < buffer->len ?
-                          machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
+                          machine.get_class (buffer->cur().codepoint, num_glyphs) :
                           (unsigned) StateTableT::CLASS_END_OF_TEXT;
       DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
       const EntryT &entry = machine.get_entry (state, klass);
@@ -787,43 +851,41 @@ struct StateTableDriver
        *
        *   https://github.com/harfbuzz/harfbuzz/issues/2860
        */
-      const EntryT *wouldbe_entry;
-      bool safe_to_break =
-       /* 1. */
-       !c->is_actionable (this, entry)
-      &&
-       /* 2. */
-       (
-         /* 2a. */
-         state == StateTableT::STATE_START_OF_TEXT
-       ||
-         /* 2b. */
-         (
-           (entry.flags & context_t::DontAdvance) &&
-           next_state == StateTableT::STATE_START_OF_TEXT
-         )
-       ||
-         /* 2c. */
-         (
-           wouldbe_entry = &machine.get_entry (StateTableT::STATE_START_OF_TEXT, klass)
-         ,
-           /* 2c'. */
-           !c->is_actionable (this, *wouldbe_entry)
-         &&
-           /* 2c". */
-           (
-             next_state == machine.new_state (wouldbe_entry->newState)
-           &&
-             (entry.flags & context_t::DontAdvance) == (wouldbe_entry->flags & context_t::DontAdvance)
-           )
-         )
-       )
-      &&
-       /* 3. */
-       !c->is_actionable (this, machine.get_entry (state, StateTableT::CLASS_END_OF_TEXT))
-      ;
-
-      if (!safe_to_break && buffer->backtrack_len () && buffer->idx < buffer->len)
+
+      const auto is_safe_to_break_extra = [&]()
+      {
+          /* 2c. */
+          const auto wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass);
+      
+          /* 2c'. */
+          if (c->is_actionable (this, wouldbe_entry))
+              return false;
+      
+          /* 2c". */
+          return next_state == machine.new_state(wouldbe_entry.newState)
+              && (entry.flags & context_t::DontAdvance) == (wouldbe_entry.flags & context_t::DontAdvance);
+      };
+      
+      const auto is_safe_to_break = [&]()
+      {
+          /* 1. */
+          if (c->is_actionable (this, entry))
+              return false;
+      
+          /* 2. */
+          // This one is meh, I know...
+          const auto ok =
+                 state == StateTableT::STATE_START_OF_TEXT
+              || ((entry.flags & context_t::DontAdvance) && next_state == StateTableT::STATE_START_OF_TEXT)
+              || is_safe_to_break_extra();
+          if (!ok)
+              return false;
+      
+          /* 3. */
+          return !c->is_actionable (this, machine.get_entry (state, StateTableT::CLASS_END_OF_TEXT));
+      };
+
+      if (!is_safe_to_break () && buffer->backtrack_len () && buffer->idx < buffer->len)
        buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
 
       c->transition (this, entry);
@@ -849,41 +911,6 @@ struct StateTableDriver
 };
 
 
-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;
-  const OT::GDEF *gdef_table;
-
-  /* Unused. For debug tracing only. */
-  unsigned int lookup_index;
-
-  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 */
 
 
index 573f0cf..815a1fd 100644 (file)
@@ -62,7 +62,7 @@ struct SettingName
   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:
index 0bf9bd2..8fd3990 100644 (file)
@@ -48,7 +48,7 @@ struct ActionSubrecordHeader
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   HBUINT16     actionClass;    /* The JustClass value associated with this
@@ -65,14 +65,14 @@ struct DecompositionAction
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   ActionSubrecordHeader
                header;
-  HBFixed      lowerLimit;     /* If the distance factor is less than this value,
+  F16DOT16     lowerLimit;     /* If the distance factor is less than this value,
                                 * then the ligature is decomposed. */
-  HBFixed      upperLimit;     /* If the distance factor is greater than this value,
+  F16DOT16     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
@@ -112,13 +112,13 @@ struct ConditionalAddGlyphAction
   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:
   ActionSubrecordHeader
                header;
-  HBFixed      substThreshold; /* Distance growth factor (in ems) at which
+  F16DOT16     substThreshold; /* Distance growth factor (in ems) at which
                                 * this glyph is replaced and the growth factor
                                 * recalculated. */
   HBGlyphID16  addGlyph;       /* Glyph to be added as kashida. If this value is
@@ -137,7 +137,7 @@ struct DuctileGlyphAction
   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:
@@ -146,13 +146,13 @@ struct DuctileGlyphAction
   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. */
-  HBFixed      minimumLimit;   /* The lowest value for the ductility axis that
+  F16DOT16     minimumLimit;   /* The lowest value for the ductility axis that
                                 * still yields an acceptable appearance. Normally
                                 * this will be 1.0. */
-  HBFixed      noStretchValue; /* This is the default value that corresponds to
+  F16DOT16     noStretchValue; /* This is the default value that corresponds to
                                 * no change in appearance. Normally, this will
                                 * be 1.0. */
-  HBFixed      maximumLimit;   /* The highest value for the ductility axis that
+  F16DOT16     maximumLimit;   /* The highest value for the ductility axis that
                                 * still yields an acceptable appearance. */
   public:
   DEFINE_SIZE_STATIC (22);
@@ -163,7 +163,7 @@ struct RepeatedAddGlyphAction
   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:
@@ -271,14 +271,14 @@ struct JustWidthDeltaEntry
   };
 
   protected:
-  HBFixed      beforeGrowLimit;/* The ratio by which the advance width of the
+  F16DOT16     beforeGrowLimit;/* The ratio by which the advance width of the
                                 * glyph is permitted to grow on the left or top side. */
-  HBFixed      beforeShrinkLimit;
+  F16DOT16     beforeShrinkLimit;
                                /* The ratio by which the advance width of the
                                 * glyph is permitted to shrink on the left or top side. */
-  HBFixed      afterGrowLimit; /* The ratio by which the advance width of the glyph
+  F16DOT16     afterGrowLimit; /* The ratio by which the advance width of the glyph
                                 * is permitted to shrink on the left or top side. */
-  HBFixed      afterShrinkLimit;
+  F16DOT16     afterShrinkLimit;
                                /* The ratio by which the advance width of the glyph
                                 * is at most permitted to shrink on the right or
                                 * bottom side. */
@@ -294,7 +294,7 @@ struct WidthDeltaPair
   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:
index 0354b47..35d7c84 100644 (file)
@@ -287,7 +287,7 @@ struct KerxSubTableFormat1
               * in the 'kern' table example. */
              if (v == -0x8000)
              {
-               o.attach_type() = ATTACH_TYPE_NONE;
+               o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_NONE;
                o.attach_chain() = 0;
                o.y_offset = 0;
              }
@@ -310,7 +310,7 @@ struct KerxSubTableFormat1
              /* CoreText doesn't do crossStream kerning in vertical.  We do. */
              if (v == -0x8000)
              {
-               o.attach_type() = ATTACH_TYPE_NONE;
+               o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_NONE;
                o.attach_chain() = 0;
                o.x_offset = 0;
              }
@@ -350,7 +350,7 @@ struct KerxSubTableFormat1
     driver_context_t dc (this, c);
 
     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face);
-    driver.drive (&dc);
+    driver.drive (&dc, c);
 
     return_trace (true);
   }
@@ -567,7 +567,7 @@ struct KerxSubTableFormat4
          }
          break;
        }
-       o.attach_type() = ATTACH_TYPE_MARK;
+       o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_MARK;
        o.attach_chain() = (int) mark - (int) buffer->idx;
        buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
       }
@@ -594,7 +594,7 @@ struct KerxSubTableFormat4
     driver_context_t dc (this, c);
 
     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face);
-    driver.drive (&dc);
+    driver.drive (&dc, c);
 
     return_trace (true);
   }
@@ -751,7 +751,7 @@ struct KerxSubTableHeader
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   public:
@@ -869,6 +869,8 @@ struct KerxTable
 
   bool apply (AAT::hb_aat_apply_context_t *c) const
   {
+    c->buffer->unsafe_to_concat ();
+
     typedef typename T::SubTable SubTable;
 
     bool ret = false;
@@ -889,7 +891,7 @@ struct KerxTable
       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 subtable %d", c->lookup_index))
+      if (!c->buffer->message (c->font, "start subtable %u", c->lookup_index))
        goto skip;
 
       if (!seenCrossStream &&
@@ -901,7 +903,7 @@ struct KerxTable
        unsigned int count = c->buffer->len;
        for (unsigned int i = 0; i < count; i++)
        {
-         pos[i].attach_type() = ATTACH_TYPE_CURSIVE;
+         pos[i].attach_type() = OT::Layout::GPOS_impl::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
@@ -921,7 +923,7 @@ struct KerxTable
       if (reverse)
        c->buffer->reverse ();
 
-      (void) c->buffer->message (c->font, "end subtable %d", c->lookup_index);
+      (void) c->buffer->message (c->font, "end subtable %u", c->lookup_index);
 
     skip:
       st = &StructAfter<SubTable> (*st);
index 2f99510..f41ecc1 100644 (file)
@@ -123,7 +123,7 @@ struct RearrangementSubtable
        bool reverse_l = 3 == (m >> 4);
        bool reverse_r = 3 == (m & 0x0F);
 
-       if (end - start >= l + r)
+       if (end - start >= l + r && end-start <= HB_MAX_CONTEXT_LENGTH)
        {
          buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
          buffer->merge_clusters (start, end);
@@ -131,14 +131,14 @@ struct RearrangementSubtable
          hb_glyph_info_t *info = buffer->info;
          hb_glyph_info_t buf[4];
 
-         memcpy (buf, info + start, l * sizeof (buf[0]));
-         memcpy (buf + 2, info + end - r, r * sizeof (buf[0]));
+         hb_memcpy (buf, info + start, l * sizeof (buf[0]));
+         hb_memcpy (buf + 2, info + end - r, r * sizeof (buf[0]));
 
          if (l != r)
            memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0]));
 
-         memcpy (info + start, buf + 2, r * sizeof (buf[0]));
-         memcpy (info + end - l, buf, l * sizeof (buf[0]));
+         hb_memcpy (info + start, buf + 2, r * sizeof (buf[0]));
+         hb_memcpy (info + end - l, buf, l * sizeof (buf[0]));
          if (reverse_l)
          {
            buf[0] = info[end - 1];
@@ -169,7 +169,7 @@ struct RearrangementSubtable
     driver_context_t dc (this);
 
     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
-    driver.drive (&dc);
+    driver.drive (&dc, c);
 
     return_trace (dc.ret);
   }
@@ -325,7 +325,7 @@ struct ContextualSubtable
     driver_context_t dc (this, c);
 
     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
-    driver.drive (&dc);
+    driver.drive (&dc, c);
 
     return_trace (dc.ret);
   }
@@ -525,7 +525,7 @@ struct LigatureSubtable
          if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
          ligature_idx += componentData;
 
-         DEBUG_MSG (APPLY, nullptr, "Action store %u last %u",
+         DEBUG_MSG (APPLY, nullptr, "Action store %d last %d",
                     bool (action & LigActionStore),
                     bool (action & LigActionLast));
          if (action & (LigActionStore | LigActionLast))
@@ -577,7 +577,7 @@ struct LigatureSubtable
     driver_context_t dc (this, c);
 
     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
-    driver.drive (&dc);
+    driver.drive (&dc, c);
 
     return_trace (dc.ret);
   }
@@ -618,8 +618,27 @@ struct NoncontextualSubtable
 
     hb_glyph_info_t *info = c->buffer->info;
     unsigned int count = c->buffer->len;
+    // If there's only one range, we already checked the flag.
+    auto *last_range = c->range_flags && (c->range_flags->length > 1) ? &(*c->range_flags)[0] : nullptr;
     for (unsigned int i = 0; i < count; i++)
     {
+      /* This block copied from StateTableDriver::drive. Keep in sync. */
+      if (last_range)
+      {
+       auto *range = last_range;
+       {
+         unsigned cluster = info[i].cluster;
+         while (cluster < range->cluster_first)
+           range--;
+         while (cluster > range->cluster_last)
+           range++;
+
+         last_range = range;
+       }
+       if (!(range->flags & c->subtable_flags))
+         continue;
+      }
+
       const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
       if (replacement)
       {
@@ -820,7 +839,7 @@ struct InsertionSubtable
     driver_context_t dc (this, c);
 
     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
-    driver.drive (&dc);
+    driver.drive (&dc, c);
 
     return_trace (dc.ret);
   }
@@ -968,7 +987,7 @@ struct Chain
        // Check whether this type/setting pair was requested in the map, and if so, apply its flags.
        // (The search here only looks at the type and setting fields of feature_info_t.)
        hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 };
-       if (map->features.bsearch (info))
+       if (map->current_features.bsearch (info))
        {
          flags &= feature.disableFlags;
          flags |= feature.enableFlags;
@@ -980,13 +999,21 @@ struct Chain
          setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS;
          goto retry;
        }
+#ifndef HB_NO_AAT
+       else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE && setting &&
+                /* TODO: Rudimentary language matching. */
+                hb_language_matches (map->face->table.ltag->get_language (setting - 1), map->props.language))
+       {
+         flags &= feature.disableFlags;
+         flags |= feature.enableFlags;
+       }
+#endif
       }
     }
     return flags;
   }
 
-  void apply (hb_aat_apply_context_t *c,
-             hb_mask_t flags) const
+  void apply (hb_aat_apply_context_t *c) const
   {
     const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
     unsigned int count = subtableCount;
@@ -994,8 +1021,10 @@ struct Chain
     {
       bool reverse;
 
-      if (!(subtable->subFeatureFlags & flags))
+      if (hb_none (hb_iter (c->range_flags) |
+                  hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); })))
        goto skip;
+      c->subtable_flags = subtable->subFeatureFlags;
 
       if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
          HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
@@ -1034,18 +1063,18 @@ struct Chain
                bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
                HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
 
-      if (!c->buffer->message (c->font, "start chainsubtable %d", c->lookup_index))
+      if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index))
        goto skip;
 
       if (reverse)
-       _hb_ot_layout_reverse_graphemes (c->buffer);
+       c->buffer->reverse ();
 
       subtable->apply (c);
 
       if (reverse)
-       _hb_ot_layout_reverse_graphemes (c->buffer);
+       c->buffer->reverse ();
 
-      (void) c->buffer->message (c->font, "end chainsubtable %d", c->lookup_index);
+      (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index);
 
       if (unlikely (!c->buffer->successful)) return;
 
@@ -1111,22 +1140,31 @@ struct mortmorx
   {
     const Chain<Types> *chain = &firstChain;
     unsigned int count = chainCount;
+    if (unlikely (!map->chain_flags.resize (count)))
+      return;
     for (unsigned int i = 0; i < count; i++)
     {
-      map->chain_flags.push (chain->compile_flags (mapper));
+      map->chain_flags[i].push (hb_aat_map_t::range_flags_t {chain->compile_flags (mapper),
+                                                            mapper->range_first,
+                                                            mapper->range_last});
       chain = &StructAfter<Chain<Types>> (*chain);
     }
   }
 
-  void apply (hb_aat_apply_context_t *c) const
+  void apply (hb_aat_apply_context_t *c,
+             const hb_aat_map_t &map) const
   {
     if (unlikely (!c->buffer->successful)) return;
+
+    c->buffer->unsafe_to_concat ();
+
     c->set_lookup_index (0);
     const Chain<Types> *chain = &firstChain;
     unsigned int count = chainCount;
     for (unsigned int i = 0; i < count; i++)
     {
-      chain->apply (c, c->plan->aat_map.chain_flags[i]);
+      c->range_flags = &map.chain_flags[i];
+      chain->apply (c);
       if (unlikely (!c->buffer->successful)) return;
       chain = &StructAfter<Chain<Types>> (*chain);
     }
index b1a1512..51b650f 100644 (file)
@@ -42,7 +42,7 @@ struct OpticalBounds
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   FWORD                leftSide;
index 68bcb23..c72c086 100644 (file)
@@ -62,7 +62,7 @@ struct TrackTableEntry
   }
 
   protected:
-  HBFixed      track;          /* Track value for this record. */
+  F16DOT16     track;          /* Track value for this record. */
   NameID       trackNameID;    /* The 'name' table index for this track.
                                 * (a short word or phrase like "loose"
                                 * or "very tight") */
@@ -82,7 +82,7 @@ struct TrackData
                        const void *base) const
   {
     unsigned int sizes = nSizes;
-    hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
+    hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
 
     float s0 = size_table[idx].to_float ();
     float s1 = size_table[idx + 1].to_float ();
@@ -111,16 +111,16 @@ struct TrackData
        break;
       }
     }
-    if (!trackTableEntry) return 0.;
+    if (!trackTableEntry) return 0;
 
     /*
      * Choose size.
      */
     unsigned int sizes = nSizes;
-    if (!sizes) return 0.;
+    if (!sizes) return 0;
     if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
 
-    hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
+    hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
     unsigned int size_index;
     for (size_index = 0; size_index < sizes - 1; size_index++)
       if (size_table[size_index].to_float () >= ptem)
@@ -141,7 +141,7 @@ struct TrackData
   protected:
   HBUINT16     nTracks;        /* Number of separate tracks included in this table. */
   HBUINT16     nSizes;         /* Number of point sizes included in this table. */
-  NNOffset32To<UnsizedArrayOf<HBFixed>>
+  NNOffset32To<UnsizedArrayOf<F16DOT16>>
                sizeTable;      /* Offset from start of the tracking table to
                                 * Array[nSizes] of size values.. */
   UnsizedArrayOf<TrackTableEntry>
index e2d4de2..5e4cea2 100644 (file)
@@ -55,7 +55,13 @@ AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *p
                                                       buffer (buffer_),
                                                       sanitizer (),
                                                       ankr_table (&Null (AAT::ankr)),
-                                                      gdef_table (face->table.GDEF->table),
+                                                      gdef_table (
+#ifndef HB_NO_OT_LAYOUT
+                                                        face->table.GDEF->table
+#else
+                                                        &Null (GDEF)
+#endif
+                                                      ),
                                                       lookup_index (0)
 {
   sanitizer.init (blob);
@@ -108,7 +114,7 @@ static const hb_aat_feature_mapping_t feature_mappings[] =
   {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','i','s','t'), (hb_aat_layout_feature_type_t) 40,                  (hb_aat_layout_feature_selector_t) 0,                          (hb_aat_layout_feature_selector_t) 1},
   {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},
@@ -131,6 +137,7 @@ static const hb_aat_feature_mapping_t feature_mappings[] =
   {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','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES,               HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_ON,          HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_OFF},
   {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},
@@ -170,6 +177,7 @@ static const hb_aat_feature_mapping_t feature_mappings[] =
   {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 ('v','r','t','r'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION,   (hb_aat_layout_feature_selector_t) 2,                          (hb_aat_layout_feature_selector_t) 3},
   {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},
 };
 
@@ -228,7 +236,7 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
  *
  * <note>Note: does not examine the `GSUB` table.</note>
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.3.0
  */
@@ -242,15 +250,23 @@ hb_aat_layout_has_substitution (hb_face_t *face)
 void
 hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
                          hb_font_t *font,
-                         hb_buffer_t *buffer)
+                         hb_buffer_t *buffer,
+                         const hb_feature_t *features,
+                         unsigned num_features)
 {
+  hb_aat_map_builder_t builder (font->face, plan->props);
+  for (unsigned i = 0; i < num_features; i++)
+    builder.add_feature (features[i]);
+  hb_aat_map_t map;
+  builder.compile (map);
+
   hb_blob_t *morx_blob = font->face->table.morx.get_blob ();
   const AAT::morx& morx = *morx_blob->as<AAT::morx> ();
   if (morx.has_data ())
   {
     AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob);
     if (!buffer->message (font, "start table morx")) return;
-    morx.apply (&c);
+    morx.apply (&c, map);
     (void) buffer->message (font, "end table morx");
     return;
   }
@@ -261,7 +277,7 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
   {
     AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob);
     if (!buffer->message (font, "start table mort")) return;
-    mort.apply (&c);
+    mort.apply (&c, map);
     (void) buffer->message (font, "end table mort");
     return;
   }
@@ -287,7 +303,7 @@ is_deleted_glyph (const hb_glyph_info_t *info)
 void
 hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
 {
-  hb_ot_layout_delete_glyphs_inplace (buffer, is_deleted_glyph);
+  buffer->delete_glyphs_inplace (is_deleted_glyph);
 }
 
 /**
@@ -299,7 +315,7 @@ hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
  *
  * <note>Note: does not examine the `GPOS` table.</note>
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.3.0
  */
@@ -332,7 +348,7 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
  * Tests whether the specified face includes any tracking information
  * in the `trak` table.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.3.0
  */
index 5e4e3bd..15c382a 100644 (file)
@@ -53,7 +53,9 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
 HB_INTERNAL void
 hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
                          hb_font_t *font,
-                         hb_buffer_t *buffer);
+                         hb_buffer_t *buffer,
+                         const hb_feature_t *features,
+                         unsigned num_features);
 
 HB_INTERNAL void
 hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer);
index 2c38c35..5bdb800 100644 (file)
 #include "hb-aat-layout-feat-table.hh"
 
 
-void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value)
+void hb_aat_map_builder_t::add_feature (const hb_feature_t &feature)
 {
   if (!face->table.feat->has_data ()) return;
 
-  if (tag == HB_TAG ('a','a','l','t'))
+  if (feature.tag == HB_TAG ('a','a','l','t'))
   {
     if (!face->table.feat->exposes_feature (HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES))
       return;
-    feature_info_t *info = features.push();
-    info->type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES;
-    info->setting = (hb_aat_layout_feature_selector_t) value;
-    info->seq = features.length;
-    info->is_exclusive = true;
+    feature_range_t *range = features.push();
+    range->start = feature.start;
+    range->end = feature.end;
+    range->info.type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES;
+    range->info.setting = (hb_aat_layout_feature_selector_t) feature.value;
+    range->info.seq = features.length;
+    range->info.is_exclusive = true;
     return;
   }
 
-  const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (tag);
+  const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (feature.tag);
   if (!mapping) return;
 
-  const AAT::FeatureName* feature = &face->table.feat->get_feature (mapping->aatFeatureType);
-  if (!feature->has_data ())
+  const AAT::FeatureName* feature_name = &face->table.feat->get_feature (mapping->aatFeatureType);
+  if (!feature_name->has_data ())
   {
     /* Special case: Chain::compile_flags will fall back to the deprecated version of
      * small-caps if necessary, so we need to check for that possibility.
@@ -64,38 +66,106 @@ void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value)
     if (mapping->aatFeatureType == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE &&
        mapping->selectorToEnable == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS)
     {
-      feature = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE);
-      if (!feature->has_data ()) return;
+      feature_name = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE);
+      if (!feature_name->has_data ()) return;
     }
     else return;
   }
 
-  feature_info_t *info = features.push();
-  info->type = mapping->aatFeatureType;
-  info->setting = value ? mapping->selectorToEnable : mapping->selectorToDisable;
-  info->seq = features.length;
-  info->is_exclusive = feature->is_exclusive ();
+  feature_range_t *range = features.push();
+  range->start = feature.start;
+  range->end = feature.end;
+  range->info.type = mapping->aatFeatureType;
+  range->info.setting = feature.value ? mapping->selectorToEnable : mapping->selectorToDisable;
+  range->info.seq = features.length;
+  range->info.is_exclusive = feature_name->is_exclusive ();
 }
 
 void
 hb_aat_map_builder_t::compile (hb_aat_map_t  &m)
 {
-  /* Sort features and merge duplicates */
-  if (features.length)
+  /* Compute active features per range, and compile each. */
+
+  /* Sort features by start/end events. */
+  hb_vector_t<feature_event_t> feature_events;
+  for (unsigned int i = 0; i < features.length; i++)
+  {
+    auto &feature = features[i];
+
+    if (features[i].start == features[i].end)
+      continue;
+
+    feature_event_t *event;
+
+    event = feature_events.push ();
+    event->index = features[i].start;
+    event->start = true;
+    event->feature = feature.info;
+
+    event = feature_events.push ();
+    event->index = features[i].end;
+    event->start = false;
+    event->feature = feature.info;
+  }
+  feature_events.qsort ();
+  /* Add a strategic final event. */
+  {
+    feature_info_t feature;
+    feature.seq = features.length + 1;
+
+    feature_event_t *event = feature_events.push ();
+    event->index = -1; /* This value does magic. */
+    event->start = false;
+    event->feature = feature;
+  }
+
+  /* Scan events and save features for each range. */
+  hb_sorted_vector_t<feature_info_t> active_features;
+  unsigned int last_index = 0;
+  for (unsigned int i = 0; i < feature_events.length; i++)
   {
-    features.qsort ();
-    unsigned int j = 0;
-    for (unsigned int i = 1; i < features.length; i++)
-      if (features[i].type != features[j].type ||
-         /* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off
-          * respectively, so we mask out the low-order bit when checking for "duplicates"
-          * (selectors referring to the same feature setting) here. */
-         (!features[i].is_exclusive && ((features[i].setting & ~1) != (features[j].setting & ~1))))
-       features[++j] = features[i];
-    features.shrink (j + 1);
+    feature_event_t *event = &feature_events[i];
+
+    if (event->index != last_index)
+    {
+      /* Save a snapshot of active features and the range. */
+
+      /* Sort features and merge duplicates */
+      current_features = active_features;
+      range_first = last_index;
+      range_last = event->index - 1;
+      if (current_features.length)
+      {
+       current_features.qsort ();
+       unsigned int j = 0;
+       for (unsigned int i = 1; i < current_features.length; i++)
+         if (current_features[i].type != current_features[j].type ||
+             /* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off
+              * respectively, so we mask out the low-order bit when checking for "duplicates"
+              * (selectors referring to the same feature setting) here. */
+             (!current_features[i].is_exclusive && ((current_features[i].setting & ~1) != (current_features[j].setting & ~1))))
+           current_features[++j] = current_features[i];
+       current_features.shrink (j + 1);
+      }
+
+      hb_aat_layout_compile_map (this, &m);
+
+      last_index = event->index;
+    }
+
+    if (event->start)
+    {
+      active_features.push (event->feature);
+    } else {
+      feature_info_t *feature = active_features.lsearch (event->feature);
+      if (feature)
+       active_features.remove_ordered (feature - active_features.arrayZ);
+    }
   }
 
-  hb_aat_layout_compile_map (this, &m);
+  for (auto &chain_flags : m.chain_flags)
+    // With our above setup this value is one less than desired; adjust it.
+    chain_flags.tail().cluster_last = HB_FEATURE_GLOBAL_END;
 }
 
 
index 5a0fa70..cb22ffe 100644 (file)
@@ -35,16 +35,15 @@ struct hb_aat_map_t
   friend struct hb_aat_map_builder_t;
 
   public:
-
-  void init ()
+  struct range_flags_t
   {
-    memset (this, 0, sizeof (*this));
-    chain_flags.init ();
-  }
-  void fini () { chain_flags.fini (); }
+    hb_mask_t flags;
+    unsigned cluster_first;
+    unsigned cluster_last; // end - 1
+  };
 
   public:
-  hb_vector_t<hb_mask_t> chain_flags;
+  hb_vector_t<hb_sorted_vector_t<range_flags_t>> chain_flags;
 };
 
 struct hb_aat_map_builder_t
@@ -52,10 +51,11 @@ 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_) {}
+                                   const hb_segment_properties_t props_) :
+                                     face (face_),
+                                     props (props_) {}
 
-  HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value=1);
+  HB_INTERNAL void add_feature (const hb_feature_t &feature);
 
   HB_INTERNAL void compile (hb_aat_map_t  &m);
 
@@ -77,7 +77,7 @@ struct hb_aat_map_builder_t
            return (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
     }
 
-    /* compares type & setting only, not is_exclusive flag or seq number */
+    /* compares type & setting only */
     int cmp (const feature_info_t& f) const
     {
       return (f.type != type) ? (f.type < type ? -1 : 1) :
@@ -85,11 +85,38 @@ struct hb_aat_map_builder_t
     }
   };
 
+  struct feature_range_t
+  {
+    feature_info_t info;
+    unsigned start;
+    unsigned end;
+  };
+
+  private:
+  struct feature_event_t
+  {
+    unsigned int index;
+    bool start;
+    feature_info_t feature;
+
+    HB_INTERNAL 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 :
+            a->start < b->start ? -1 : a->start > b->start ? 1 :
+            feature_info_t::cmp (&a->feature, &b->feature);
+    }
+  };
+
   public:
   hb_face_t *face;
+  hb_segment_properties_t props;
 
   public:
-  hb_sorted_vector_t<feature_info_t> features;
+  hb_sorted_vector_t<feature_range_t> features;
+  hb_sorted_vector_t<feature_info_t> current_features;
+  unsigned range_first = HB_FEATURE_GLOBAL_START;
+  unsigned range_last = HB_FEATURE_GLOBAL_END;
 };
 
 
index 550b8a4..ea97057 100644 (file)
@@ -59,7 +59,7 @@
          static inline constexpr T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \
          static inline constexpr T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \
          static inline constexpr T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \
-         static inline constexpr T operator ~ (T r) { return T (~(unsigned int) r); } \
+         static inline constexpr unsigned operator ~ (T r) { return (~(unsigned) 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; } \
@@ -87,6 +87,19 @@ static inline constexpr uint16_t hb_uint16_swap (uint16_t v)
 static inline constexpr uint32_t hb_uint32_swap (uint32_t v)
 { return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
 
+#ifndef HB_FAST_INT_ACCESS
+#if defined(__OPTIMIZE__) && \
+    defined(__BYTE_ORDER) && \
+    (__BYTE_ORDER == __BIG_ENDIAN || \
+     (__BYTE_ORDER == __LITTLE_ENDIAN && \
+      hb_has_builtin(__builtin_bswap16) && \
+      hb_has_builtin(__builtin_bswap32)))
+#define HB_FAST_INT_ACCESS 1
+#else
+#define HB_FAST_INT_ACCESS 0
+#endif
+#endif
+
 template <typename Type, int Bytes = sizeof (Type)>
 struct BEInt;
 template <typename Type>
@@ -101,23 +114,29 @@ struct BEInt<Type, 1>
 template <typename Type>
 struct BEInt<Type, 2>
 {
+  struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
+
   public:
   BEInt () = default;
-  constexpr BEInt (Type V) : v {uint8_t ((V >>  8) & 0xFF),
-                               uint8_t ((V      ) & 0xFF)} {}
 
-  struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
-  constexpr 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 */
+  BEInt (Type V)
+#if HB_FAST_INT_ACCESS
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+  { ((packed_uint16_t *) v)->v = __builtin_bswap16 (V); }
+#else /* __BYTE_ORDER == __BIG_ENDIAN */
+  { ((packed_uint16_t *) v)->v = V; }
+#endif
+#else
+    : v {uint8_t ((V >>  8) & 0xFF),
+        uint8_t ((V      ) & 0xFF)} {}
+#endif
+
+  constexpr operator Type () const {
+#if HB_FAST_INT_ACCESS
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-    return __builtin_bswap16 (((packed_uint16_t *) this)->v);
+    return __builtin_bswap16 (((packed_uint16_t *) v)->v);
 #else /* __BYTE_ORDER == __BIG_ENDIAN */
-    return ((packed_uint16_t *) this)->v;
+    return ((packed_uint16_t *) v)->v;
 #endif
 #else
     return (v[0] <<  8)
@@ -144,16 +163,39 @@ struct BEInt<Type, 3>
 template <typename Type>
 struct BEInt<Type, 4>
 {
+  struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
+
   public:
   BEInt () = default;
-  constexpr BEInt (Type V) : v {uint8_t ((V >> 24) & 0xFF),
-                               uint8_t ((V >> 16) & 0xFF),
-                               uint8_t ((V >>  8) & 0xFF),
-                               uint8_t ((V      ) & 0xFF)} {}
-  constexpr operator Type () const { return (v[0] << 24)
-                                         + (v[1] << 16)
-                                         + (v[2] <<  8)
-                                         + (v[3]      ); }
+
+  BEInt (Type V)
+#if HB_FAST_INT_ACCESS
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+  { ((packed_uint32_t *) v)->v = __builtin_bswap32 (V); }
+#else /* __BYTE_ORDER == __BIG_ENDIAN */
+  { ((packed_uint32_t *) v)->v = V; }
+#endif
+#else
+    : v {uint8_t ((V >> 24) & 0xFF),
+        uint8_t ((V >> 16) & 0xFF),
+        uint8_t ((V >>  8) & 0xFF),
+        uint8_t ((V      ) & 0xFF)} {}
+#endif
+
+  constexpr operator Type () const {
+#if HB_FAST_INT_ACCESS
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+    return __builtin_bswap32 (((packed_uint32_t *) v)->v);
+#else /* __BYTE_ORDER == __BIG_ENDIAN */
+    return ((packed_uint32_t *) v)->v;
+#endif
+#else
+    return (v[0] << 24)
+        + (v[1] << 16)
+        + (v[2] <<  8)
+        + (v[3]      );
+#endif
+  }
   private: uint8_t v[4];
 };
 
@@ -211,13 +253,100 @@ struct
 }
 HB_FUNCOBJ (hb_bool);
 
-template <typename T>
-static inline
-T hb_coerce (const T v) { return v; }
-template <typename T, typename V,
-         hb_enable_if (!hb_is_same (hb_decay<T>, hb_decay<V>) && std::is_pointer<V>::value)>
-static inline
-T hb_coerce (const V v) { return *v; }
+
+/* The MIT License
+
+   Copyright (C) 2012 Zilong Tan (eric.zltan@gmail.com)
+
+   Permission is hereby granted, free of charge, to any person
+   obtaining a copy of this software and associated documentation
+   files (the "Software"), to deal in the Software without
+   restriction, including without limitation the rights to use, copy,
+   modify, merge, publish, distribute, sublicense, and/or sell copies
+   of the Software, and to permit persons to whom the Software is
+   furnished to do so, subject to the following conditions:
+
+   The above copyright notice and this permission notice shall be
+   included in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+   SOFTWARE.
+*/
+
+
+// Compression function for Merkle-Damgard construction.
+// This function is generated using the framework provided.
+#define mix(h) (                                       \
+                       (void) ((h) ^= (h) >> 23),              \
+                       (void) ((h) *= 0x2127599bf4325c37ULL),  \
+                       (h) ^= (h) >> 47)
+
+static inline uint64_t fasthash64(const void *buf, size_t len, uint64_t seed)
+{
+       struct __attribute__((packed)) packed_uint64_t { uint64_t v; };
+       const uint64_t    m = 0x880355f21e6d1965ULL;
+       const packed_uint64_t *pos = (const packed_uint64_t *)buf;
+       const packed_uint64_t *end = pos + (len / 8);
+       const unsigned char *pos2;
+       uint64_t h = seed ^ (len * m);
+       uint64_t v;
+
+#ifndef HB_OPTIMIZE_SIZE
+       if (((uintptr_t) pos & 7) == 0)
+       {
+         while (pos != end)
+         {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+           v  = * (const uint64_t *) (pos++);
+#pragma GCC diagnostic pop
+           h ^= mix(v);
+           h *= m;
+         }
+       }
+       else
+#endif
+       {
+         while (pos != end)
+         {
+           v  = pos++->v;
+           h ^= mix(v);
+           h *= m;
+         }
+       }
+
+       pos2 = (const unsigned char*)pos;
+       v = 0;
+
+       switch (len & 7) {
+       case 7: v ^= (uint64_t)pos2[6] << 48; HB_FALLTHROUGH;
+       case 6: v ^= (uint64_t)pos2[5] << 40; HB_FALLTHROUGH;
+       case 5: v ^= (uint64_t)pos2[4] << 32; HB_FALLTHROUGH;
+       case 4: v ^= (uint64_t)pos2[3] << 24; HB_FALLTHROUGH;
+       case 3: v ^= (uint64_t)pos2[2] << 16; HB_FALLTHROUGH;
+       case 2: v ^= (uint64_t)pos2[1] <<  8; HB_FALLTHROUGH;
+       case 1: v ^= (uint64_t)pos2[0];
+               h ^= mix(v);
+               h *= m;
+       }
+
+       return mix(h);
+}
+
+static inline uint32_t fasthash32(const void *buf, size_t len, uint32_t seed)
+{
+       // the following trick converts the 64-bit hashcode to Fermat
+       // residue, which shall retain information from both the higher
+       // and lower parts of hashcode.
+        uint64_t h = fasthash64(buf, len, seed);
+       return h - (h >> 32);
+}
 
 struct
 {
@@ -226,22 +355,24 @@ struct
   template <typename T> constexpr auto
   impl (const T& v, hb_priority<2>) const HB_RETURN (uint32_t, hb_deref (v).hash ())
 
-/* Sadly, we must give further hints to VS2015 to build the following template item */
-#if !defined (_MSC_VER) || defined (__clang__) || (_MSC_VER >= 1910)
-  template <typename T> constexpr auto
-  impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, std::hash<hb_decay<decltype (hb_deref (v))>>{} (hb_deref (v)))
-#else
-  template <typename T> constexpr auto
-  impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, std::hash<hb_decay<decltype (hb_deref (v).hash ())>>{} (hb_deref (v)))
-#endif
+  // Horrible: std:hash() of integers seems to be identity in gcc / clang?!
+  // https://github.com/harfbuzz/harfbuzz/pull/4228
+  //
+  // For performance characteristics see:
+  // https://github.com/harfbuzz/harfbuzz/pull/4228#issuecomment-1565079537
+  template <typename T,
+           hb_enable_if (std::is_integral<T>::value && sizeof (T) <= sizeof (uint32_t))> constexpr auto
+  impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, (uint32_t) v * 2654435761u /* Knuh's multiplicative hash */)
+  template <typename T,
+           hb_enable_if (std::is_integral<T>::value && sizeof (T) > sizeof (uint32_t))> constexpr auto
+  impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, (uint32_t) (v ^ (v >> 32)) * 2654435761u /* Knuth's multiplicative hash */)
 
   template <typename T,
-           hb_enable_if (std::is_integral<T>::value)> constexpr auto
-  impl (const T& v, hb_priority<0>) const HB_AUTO_RETURN
-  (
-    /* Knuth's multiplicative method: */
-    (uint32_t) v * 2654435761u
-  )
+           hb_enable_if (std::is_floating_point<T>::value)> constexpr auto
+  impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, fasthash32 (std::addressof (v), sizeof (T), 0xf437ffe6))
+
+  template <typename T> constexpr auto
+  impl (const T& v, hb_priority<0>) const HB_RETURN (uint32_t, std::hash<hb_decay<decltype (hb_deref (v))>>{} (hb_deref (v)))
 
   public:
 
@@ -488,6 +619,17 @@ struct
 }
 HB_FUNCOBJ (hb_equal);
 
+struct
+{
+  template <typename T> void
+  operator () (T& a, T& b) const
+  {
+    using std::swap; // allow ADL
+    swap (a, b);
+  }
+}
+HB_FUNCOBJ (hb_swap);
+
 
 template <typename T1, typename T2>
 struct hb_pair_t
@@ -500,11 +642,11 @@ struct hb_pair_t
            hb_enable_if (std::is_default_constructible<U1>::value &&
                          std::is_default_constructible<U2>::value)>
   hb_pair_t () : first (), second () {}
-  hb_pair_t (T1 a, T2 b) : first (a), second (b) {}
+  hb_pair_t (T1 a, T2 b) : first (std::forward<T1> (a)), second (std::forward<T2> (b)) {}
 
   template <typename Q1, typename Q2,
            hb_enable_if (hb_is_convertible (T1, Q1) &&
-                         hb_is_convertible (T2, T2))>
+                         hb_is_convertible (T2, Q2))>
   operator hb_pair_t<Q1, Q2> () { return hb_pair_t<Q1, Q2> (first, second); }
 
   hb_pair_t<T1, T2> reverse () const
@@ -517,13 +659,33 @@ struct hb_pair_t
   bool operator > (const pair_t& o) const { return first > o.first || (first == o.first && second > o.second); }
   bool operator <= (const pair_t& o) const { return !(*this > o); }
 
+  static int cmp (const void *pa, const void *pb)
+  {
+    pair_t *a = (pair_t *) pa;
+    pair_t *b = (pair_t *) pb;
+
+    if (a->first < b->first) return -1;
+    if (a->first > b->first) return +1;
+    if (a->second < b->second) return -1;
+    if (a->second > b->second) return +1;
+    return 0;
+  }
+
+  friend void swap (hb_pair_t& a, hb_pair_t& b)
+  {
+    hb_swap (a.first, b.first);
+    hb_swap (a.second, b.second);
+  }
+
+
   T1 first;
   T2 second;
 };
-#define hb_pair_t(T1,T2) hb_pair_t<T1, T2>
 template <typename T1, typename T2> static inline hb_pair_t<T1, T2>
 hb_pair (T1&& a, T2&& b) { return hb_pair_t<T1, T2> (a, b); }
 
+typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
+
 struct
 {
   template <typename Pair> constexpr typename Pair::first_t
@@ -546,14 +708,14 @@ struct
 {
   template <typename T, typename T2> constexpr auto
   operator () (T&& a, T2&& b) const HB_AUTO_RETURN
-  (a <= b ? std::forward<T> (a) : std::forward<T2> (b))
+  (a <= b ? a : b)
 }
 HB_FUNCOBJ (hb_min);
 struct
 {
   template <typename T, typename T2> constexpr auto
   operator () (T&& a, T2&& b) const HB_AUTO_RETURN
-  (a >= b ? std::forward<T> (a) : std::forward<T2> (b))
+  (a >= b ? a : b)
 }
 HB_FUNCOBJ (hb_max);
 struct
@@ -564,17 +726,6 @@ struct
 }
 HB_FUNCOBJ (hb_clamp);
 
-struct
-{
-  template <typename T> void
-  operator () (T& a, T& b) const
-  {
-    using std::swap; // allow ADL
-    swap (a, b);
-  }
-}
-HB_FUNCOBJ (hb_swap);
-
 /*
  * Bithacks.
  */
@@ -584,13 +735,17 @@ template <typename T>
 static inline unsigned int
 hb_popcount (T v)
 {
-#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+#if hb_has_builtin(__builtin_popcount)
   if (sizeof (T) <= sizeof (unsigned int))
     return __builtin_popcount (v);
+#endif
 
+#if hb_has_builtin(__builtin_popcountl)
   if (sizeof (T) <= sizeof (unsigned long))
     return __builtin_popcountl (v);
+#endif
 
+#if hb_has_builtin(__builtin_popcountll)
   if (sizeof (T) <= sizeof (unsigned long long))
     return __builtin_popcountll (v);
 #endif
@@ -606,8 +761,10 @@ hb_popcount (T v)
 
   if (sizeof (T) == 8)
   {
-    unsigned int shift = 32;
-    return hb_popcount<uint32_t> ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift));
+    uint64_t y = (uint64_t) v;
+    y -= ((y >> 1) & 0x5555555555555555ull);
+    y = (y & 0x3333333333333333ull) + (y >> 2 & 0x3333333333333333ull);
+    return ((y + (y >> 4)) & 0xf0f0f0f0f0f0f0full) * 0x101010101010101ull >> 56;
   }
 
   if (sizeof (T) == 16)
@@ -627,13 +784,17 @@ hb_bit_storage (T v)
 {
   if (unlikely (!v)) return 0;
 
-#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+#if hb_has_builtin(__builtin_clz)
   if (sizeof (T) <= sizeof (unsigned int))
     return sizeof (unsigned int) * 8 - __builtin_clz (v);
+#endif
 
+#if hb_has_builtin(__builtin_clzl)
   if (sizeof (T) <= sizeof (unsigned long))
     return sizeof (unsigned long) * 8 - __builtin_clzl (v);
+#endif
 
+#if hb_has_builtin(__builtin_clzll)
   if (sizeof (T) <= sizeof (unsigned long long))
     return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
 #endif
@@ -701,13 +862,17 @@ hb_ctz (T v)
 {
   if (unlikely (!v)) return 8 * sizeof (T);
 
-#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+#if hb_has_builtin(__builtin_ctz)
   if (sizeof (T) <= sizeof (unsigned int))
     return __builtin_ctz (v);
+#endif
 
+#if hb_has_builtin(__builtin_ctzl)
   if (sizeof (T) <= sizeof (unsigned long))
     return __builtin_ctzl (v);
+#endif
 
+#if hb_has_builtin(__builtin_ctzll)
   if (sizeof (T) <= sizeof (unsigned long long))
     return __builtin_ctzll (v);
 #endif
@@ -823,7 +988,7 @@ static inline void *
 hb_memset (void *s, int c, unsigned int n)
 {
   /* It's illegal to pass NULL to memset(), even if n is zero. */
-  if (unlikely (!n)) return 0;
+  if (unlikely (!n)) return s;
   return memset (s, c, n);
 }
 
@@ -843,14 +1008,14 @@ hb_in_range (T u, T lo, T hi)
   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)
+hb_in_ranges (T u, T lo1, T hi1)
 {
-  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
+  return hb_in_range (u, lo1, hi1);
 }
-template <typename T> static inline bool
-hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
+template <typename T, typename ...Ts> static inline bool
+hb_in_ranges (T u, T lo1, T hi1, Ts... ds)
 {
-  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
+  return hb_in_range<T> (u, lo1, hi1) || hb_in_ranges<T> (u, ds...);
 }
 
 
@@ -858,10 +1023,18 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
  * Overflow checking.
  */
 
-/* Consider __builtin_mul_overflow use here also */
 static inline bool
-hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
+hb_unsigned_mul_overflows (unsigned int count, unsigned int size, unsigned *result = nullptr)
 {
+#if hb_has_builtin(__builtin_mul_overflow)
+  unsigned stack_result;
+  if (!result)
+    result = &stack_result;
+  return __builtin_mul_overflow (count, size, result);
+#endif
+
+  if (result)
+    *result = count * size;
   return (size > 0) && (count >= ((unsigned int) -1) / size);
 }
 
@@ -962,7 +1135,7 @@ void hb_qsort(void *base, size_t nel, size_t width,
               [void *arg]);
 */
 
-#define SORT_R_SWAP(a,b,tmp) ((tmp) = (a), (a) = (b), (b) = (tmp))
+#define SORT_R_SWAP(a,b,tmp) ((void) ((tmp) = (a)), (void) ((a) = (b)), (b) = (tmp))
 
 /* swap a and b */
 /* a and b must not be equal! */
@@ -1153,9 +1326,12 @@ hb_qsort (void *base, size_t nel, size_t width,
 }
 
 
-template <typename T, typename T2, typename T3> static inline void
-hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *), T3 *array2)
+template <typename T, typename T2, typename T3 = int> static inline void
+hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *), T3 *array2 = nullptr)
 {
+  static_assert (hb_is_trivially_copy_assignable (T), "");
+  static_assert (hb_is_trivially_copy_assignable (T3), "");
+
   for (unsigned int i = 1; i < len; i++)
   {
     unsigned int j = i;
@@ -1178,12 +1354,6 @@ hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *)
   }
 }
 
-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)
 {
@@ -1311,47 +1481,62 @@ struct
 HB_FUNCOBJ (hb_dec);
 
 
-/* Compiler-assisted vectorization. */
-
-/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
- * basically a fixed-size bitset. */
-template <typename elt_t, unsigned int byte_size>
-struct hb_vector_size_t
+/* Adapted from kurbo implementation with extra parameters added,
+ * and finding for a particular range instead of 0.
+ *
+ * For documentation and implementation see:
+ *
+ * [ITP method]: https://en.wikipedia.org/wiki/ITP_Method
+ * [An Enhancement of the Bisection Method Average Performance Preserving Minmax Optimality]: https://dl.acm.org/doi/10.1145/3423597
+ * https://docs.rs/kurbo/0.8.1/kurbo/common/fn.solve_itp.html
+ * https://github.com/linebender/kurbo/blob/fd839c25ea0c98576c7ce5789305822675a89938/src/common.rs#L162-L248
+ */
+template <typename func_t>
+double solve_itp (func_t f,
+                 double a, double b,
+                 double epsilon,
+                 double min_y, double max_y,
+                 double &ya, double &yb, double &y)
 {
-  elt_t& operator [] (unsigned int i) { return v[i]; }
-  const elt_t& operator [] (unsigned int i) const { return v[i]; }
-
-  void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); }
-
-  template <typename Op>
-  hb_vector_size_t process (const Op& op) const
-  {
-    hb_vector_size_t r;
-    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
-      r.v[i] = op (v[i]);
-    return r;
-  }
-  template <typename Op>
-  hb_vector_size_t process (const Op& op, const hb_vector_size_t &o) const
+  unsigned n1_2 = (unsigned) (hb_max (ceil (log2 ((b - a) / epsilon)) - 1.0, 0.0));
+  const unsigned n0 = 1; // Hardwired
+  const double k1 = 0.2 / (b - a); // Hardwired.
+  unsigned nmax = n0 + n1_2;
+  double scaled_epsilon = epsilon * double (1llu << nmax);
+  double _2_epsilon = 2.0 * epsilon;
+  while (b - a > _2_epsilon)
   {
-    hb_vector_size_t r;
-    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
-      r.v[i] = op (v[i], o.v[i]);
-    return r;
+    double x1_2 = 0.5 * (a + b);
+    double r = scaled_epsilon - 0.5 * (b - a);
+    double xf = (yb * a - ya * b) / (yb - ya);
+    double sigma = x1_2 - xf;
+    double b_a = b - a;
+    // This has k2 = 2 hardwired for efficiency.
+    double b_a_k2 = b_a * b_a;
+    double delta = k1 * b_a_k2;
+    int sigma_sign = sigma >= 0 ? +1 : -1;
+    double xt = delta <= fabs (x1_2 - xf) ? xf + delta * sigma_sign : x1_2;
+    double xitp = fabs (xt - x1_2) <= r ? xt : x1_2 - r * sigma_sign;
+    double yitp = f (xitp);
+    if (yitp > max_y)
+    {
+      b = xitp;
+      yb = yitp;
+    }
+    else if (yitp < min_y)
+    {
+      a = xitp;
+      ya = yitp;
+    }
+    else
+    {
+      y = yitp;
+      return xitp;
+    }
+    scaled_epsilon *= 0.5;
   }
-  hb_vector_size_t operator | (const hb_vector_size_t &o) const
-  { return process (hb_bitwise_or, o); }
-  hb_vector_size_t operator & (const hb_vector_size_t &o) const
-  { return process (hb_bitwise_and, o); }
-  hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
-  { return process (hb_bitwise_xor, o); }
-  hb_vector_size_t operator ~ () const
-  { return process (hb_bitwise_neg); }
-
-  private:
-  static_assert (0 == byte_size % sizeof (elt_t), "");
-  elt_t v[byte_size / sizeof (elt_t)];
-};
+  return 0.5 * (a + b);
+}
 
 
 #endif /* HB_ALGS_HH */
index 1d1476d..760f902 100644 (file)
@@ -56,7 +56,6 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
   hb_array_t& operator= (const hb_array_t&) = default;
   hb_array_t& operator= (hb_array_t&&) = default;
 
-  constexpr hb_array_t (std::nullptr_t) : hb_array_t () {}
   constexpr hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_) {}
   template <unsigned int length_>
   constexpr hb_array_t (Type (&array_)[length_]) : hb_array_t (array_, length_) {}
@@ -76,11 +75,25 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
    */
   typedef Type& __item_t__;
   static constexpr bool is_random_access_iterator = true;
+  static constexpr bool has_fast_len = true;
+  Type& __item__ () const
+  {
+    if (unlikely (!length)) return CrapOrNull (Type);
+    return *arrayZ;
+  }
   Type& __item_at__ (unsigned i) const
   {
     if (unlikely (i >= length)) return CrapOrNull (Type);
     return arrayZ[i];
   }
+  void __next__ ()
+  {
+    if (unlikely (!length))
+      return;
+    length--;
+    backwards_length++;
+    arrayZ++;
+  }
   void __forward__ (unsigned n)
   {
     if (unlikely (n > length))
@@ -89,6 +102,14 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
     backwards_length += n;
     arrayZ += n;
   }
+  void __prev__ ()
+  {
+    if (unlikely (!backwards_length))
+      return;
+    length++;
+    backwards_length--;
+    arrayZ--;
+  }
   void __rewind__ (unsigned n)
   {
     if (unlikely (n > backwards_length))
@@ -101,10 +122,17 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
   /* Ouch. The operator== compares the contents of the array.  For range-based for loops,
    * it's best if we can just compare arrayZ, though comparing contents is still fast,
    * but also would require that Type has operator==.  As such, we optimize this operator
-   * for range-based for loop and just compare arrayZ.  No need to compare length, as we
-   * assume we're only compared to .end(). */
+   * for range-based for loop and just compare arrayZ and length.
+   *
+   * The above comment is outdated now because we implemented separate begin/end to
+   * objects that were using hb_array_t for range-based loop before. */
   bool operator != (const hb_array_t& o) const
-  { return arrayZ != o.arrayZ; }
+  { return this->arrayZ != o.arrayZ || this->length != o.length; }
+
+  /* Faster range-based for loop without bounds-check. */
+  Type *begin () const { return arrayZ; }
+  Type *end () const { return arrayZ + length; }
+
 
   /* Extra operators.
    */
@@ -114,10 +142,15 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
 
   HB_INTERNAL bool operator == (const hb_array_t &o) const;
 
-  uint32_t hash () const {
-    uint32_t current = 0;
-    for (unsigned int i = 0; i < this->length; i++) {
-      current = current * 31 + hb_hash (this->arrayZ[i]);
+  uint32_t hash () const
+  {
+    // FNV-1a hash function
+    // https://github.com/harfbuzz/harfbuzz/pull/4228
+    uint32_t current = /*cbf29ce4*/0x84222325;
+    for (auto &v : *this)
+    {
+      current = current ^ hb_hash (v);
+      current = current * 16777619;
     }
     return current;
   }
@@ -186,23 +219,18 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
 
   hb_sorted_array_t<Type> qsort (int (*cmp_)(const void*, const void*))
   {
+    //static_assert (hb_enable_if (hb_is_trivially_copy_assignable(Type)), "");
     if (likely (length))
       hb_qsort (arrayZ, length, this->get_item_size (), cmp_);
     return hb_sorted_array_t<Type> (*this);
   }
   hb_sorted_array_t<Type> qsort ()
   {
+    //static_assert (hb_enable_if (hb_is_trivially_copy_assignable(Type)), "");
     if (likely (length))
       hb_qsort (arrayZ, length, this->get_item_size (), Type::cmp);
     return hb_sorted_array_t<Type> (*this);
   }
-  void qsort (unsigned int start, unsigned int end)
-  {
-    end = hb_min (end, length);
-    assert (start <= end);
-    if (likely (start < end))
-      hb_qsort (arrayZ + start, end - start, this->get_item_size (), Type::cmp);
-  }
 
   /*
    * Other methods.
@@ -221,11 +249,8 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
     if (end < start + 2)
       return;
 
-    for (unsigned lhs = start, rhs = end - 1; lhs < rhs; lhs++, rhs--) {
-      Type temp = arrayZ[rhs];
-      arrayZ[rhs] = arrayZ[lhs];
-      arrayZ[lhs] = temp;
-    }
+    for (unsigned lhs = start, rhs = end - 1; lhs < rhs; lhs++, rhs--)
+      hb_swap (arrayZ[rhs], arrayZ[lhs]);
   }
 
   hb_array_t sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
@@ -267,17 +292,31 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
   void fini ()
   { hb_free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
 
-  template <typename hb_serialize_context_t>
+  template <typename hb_serialize_context_t,
+           typename U = Type,
+           hb_enable_if (!(sizeof (U) < sizeof (long long) && hb_is_trivially_copy_assignable(hb_decay<Type>)))>
   hb_array_t copy (hb_serialize_context_t *c) const
   {
     TRACE_SERIALIZE (this);
     auto* out = c->start_embed (arrayZ);
-    if (unlikely (!c->extend_size (out, get_size ()))) return_trace (hb_array_t ());
+    if (unlikely (!c->extend_size (out, get_size (), false))) return_trace (hb_array_t ());
     for (unsigned i = 0; i < length; i++)
       out[i] = arrayZ[i]; /* TODO: add version that calls c->copy() */
     return_trace (hb_array_t (out, length));
   }
 
+  template <typename hb_serialize_context_t,
+           typename U = Type,
+           hb_enable_if (sizeof (U) < sizeof (long long) && hb_is_trivially_copy_assignable(hb_decay<Type>))>
+  hb_array_t copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    auto* out = c->start_embed (arrayZ);
+    if (unlikely (!c->extend_size (out, get_size (), false))) return_trace (hb_array_t ());
+    hb_memcpy (out, arrayZ, get_size ());
+    return_trace (hb_array_t (out, length));
+  }
+
   template <typename hb_sanitize_context_t>
   bool sanitize (hb_sanitize_context_t *c) const
   { return c->check_array (arrayZ, length); }
@@ -292,6 +331,9 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
   unsigned int backwards_length = 0;
 };
 template <typename T> inline hb_array_t<T>
+hb_array ()
+{ return hb_array_t<T> (); }
+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>
@@ -300,13 +342,14 @@ hb_array (T (&array_)[length_])
 
 template <typename Type>
 struct hb_sorted_array_t :
-       hb_iter_t<hb_sorted_array_t<Type>, Type&>,
-       hb_array_t<Type>
+       hb_array_t<Type>,
+       hb_iter_t<hb_sorted_array_t<Type>, Type&>
 {
   typedef hb_iter_t<hb_sorted_array_t, Type&> iter_base_t;
   HB_ITER_USING (iter_base_t);
   static constexpr bool is_random_access_iterator = true;
   static constexpr bool is_sorted_iterator = true;
+  static constexpr bool has_fast_len = true;
 
   hb_sorted_array_t () = default;
   hb_sorted_array_t (const hb_sorted_array_t&) = default;
@@ -314,7 +357,6 @@ struct hb_sorted_array_t :
   hb_sorted_array_t& operator= (const hb_sorted_array_t&) = default;
   hb_sorted_array_t& operator= (hb_sorted_array_t&&) = default;
 
-  constexpr hb_sorted_array_t (std::nullptr_t) : hb_sorted_array_t () {}
   constexpr hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {}
   template <unsigned int length_>
   constexpr hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {}
@@ -322,17 +364,24 @@ struct hb_sorted_array_t :
   template <typename U,
            hb_enable_if (hb_is_cr_convertible(U, Type))>
   constexpr hb_sorted_array_t (const hb_array_t<U> &o) :
-    hb_iter_t<hb_sorted_array_t, Type&> (),
-    hb_array_t<Type> (o) {}
+    hb_array_t<Type> (o),
+    hb_iter_t<hb_sorted_array_t, Type&> () {}
   template <typename U,
            hb_enable_if (hb_is_cr_convertible(U, Type))>
   hb_sorted_array_t& operator = (const hb_array_t<U> &o)
   { hb_array_t<Type> (*this) = o; return *this; }
 
   /* Iterator implementation. */
+
+  /* See comment in hb_array_of::operator != */
   bool operator != (const hb_sorted_array_t& o) const
   { return this->arrayZ != o.arrayZ || this->length != o.length; }
 
+  /* Faster range-based for loop without bounds-check. */
+  Type *begin () const { return this->arrayZ; }
+  Type *end () const { return this->arrayZ + this->length; }
+
+
   hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
   { return hb_sorted_array_t (((const hb_array_t<Type> *) (this))->sub_array (start_offset, seg_count)); }
   hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const
@@ -384,15 +433,16 @@ struct hb_sorted_array_t :
     }
     return false;
   }
-  template <typename T>
-  bool bsearch_impl (const T &x, unsigned *pos) const
+  template <typename T, typename ...Ts>
+  bool bsearch_impl (const T &x, unsigned *pos, Ts... ds) const
   {
     return hb_bsearch_impl (pos,
                            x,
                            this->arrayZ,
                            this->length,
                            sizeof (Type),
-                           _hb_cmp_method<T, Type>);
+                           _hb_cmp_method<T, Type, Ts...>,
+                           std::forward<Ts> (ds)...);
   }
 };
 template <typename T> inline hb_sorted_array_t<T>
@@ -403,7 +453,7 @@ hb_sorted_array (T (&array_)[length_])
 { return hb_sorted_array_t<T> (array_); }
 
 template <typename T>
-bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const
+inline bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const
 {
   if (o.length != this->length) return false;
   for (unsigned int i = 0; i < this->length; i++) {
@@ -411,24 +461,37 @@ bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const
   }
   return true;
 }
+template <>
+inline bool hb_array_t<const char>::operator == (const hb_array_t<const char> &o) const
+{
+  if (o.length != this->length) return false;
+  return 0 == hb_memcmp (arrayZ, o.arrayZ, length);
+}
+template <>
+inline bool hb_array_t<const unsigned char>::operator == (const hb_array_t<const unsigned char> &o) const
+{
+  if (o.length != this->length) return false;
+  return 0 == hb_memcmp (arrayZ, o.arrayZ, length);
+}
+
 
-/* TODO Specialize operator== for hb_bytes_t and hb_ubytes_t. */
+/* Specialize hash() for byte arrays. */
 
+#ifndef HB_OPTIMIZE_SIZE_MORE
 template <>
-inline uint32_t hb_array_t<const char>::hash () const {
-  uint32_t current = 0;
-  for (unsigned int i = 0; i < this->length; i++)
-    current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u);
-  return current;
+inline uint32_t hb_array_t<const char>::hash () const
+{
+  // https://github.com/harfbuzz/harfbuzz/pull/4228
+  return fasthash32(arrayZ, length, 0xf437ffe6 /* magic? */);
 }
 
 template <>
-inline uint32_t hb_array_t<const unsigned char>::hash () const {
-  uint32_t current = 0;
-  for (unsigned int i = 0; i < this->length; i++)
-    current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u);
-  return current;
+inline uint32_t hb_array_t<const unsigned char>::hash () const
+{
+  // https://github.com/harfbuzz/harfbuzz/pull/4228
+  return fasthash32(arrayZ, length, 0xf437ffe6 /* magic? */);
 }
+#endif
 
 
 typedef hb_array_t<const char> hb_bytes_t;
index e640d1b..303dfe6 100644 (file)
@@ -84,11 +84,11 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
 #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> const *> (AI)->load (std::memory_order_relaxed))
-#define hb_atomic_int_impl_get(AI)             (reinterpret_cast<std::atomic<int> const *> (AI)->load (std::memory_order_acquire))
+#define hb_atomic_int_impl_add(AI, V)          (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
+#define hb_atomic_int_impl_set_relaxed(AI, V)  (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_relaxed))
+#define hb_atomic_int_impl_set(AI, V)          (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_release))
+#define hb_atomic_int_impl_get_relaxed(AI)     (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_relaxed))
+#define hb_atomic_int_impl_get(AI)             (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> const *> (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*> const *> (P)->load (std::memory_order_relaxed))
@@ -111,6 +111,24 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
 #endif
 
 
+/* This should never be disabled, even under HB_NO_MT.
+ * except that MSVC gives me an internal compiler error, so disabled there.
+ *
+ * https://github.com/harfbuzz/harfbuzz/pull/4119
+ */
+#ifndef _hb_compiler_memory_r_barrier
+#if defined(__ATOMIC_ACQUIRE) // gcc-like
+#define _hb_compiler_memory_r_barrier() asm volatile("": : :"memory")
+#elif !defined(_MSC_VER)
+#include <atomic>
+#define _hb_compiler_memory_r_barrier() std::atomic_signal_fence (std::memory_order_acquire)
+#else
+#define _hb_compiler_memory_r_barrier() do {} while (0)
+#endif
+#endif
+
+
+
 #ifndef _hb_memory_r_barrier
 #define _hb_memory_r_barrier()                 _hb_memory_barrier ()
 #endif
@@ -132,24 +150,47 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
 #endif
 #ifndef hb_atomic_int_impl_set
 inline void hb_atomic_int_impl_set (int *AI, int v)    { _hb_memory_w_barrier (); *AI = v; }
+inline void hb_atomic_int_impl_set (short *AI, short 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; }
+inline short hb_atomic_int_impl_get (const short *AI)  { short 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
 
 
+struct hb_atomic_short_t
+{
+  hb_atomic_short_t () = default;
+  constexpr hb_atomic_short_t (short v) : v (v) {}
+
+  hb_atomic_short_t& operator = (short v_) { set_relaxed (v_); return *this; }
+  operator short () const { return get_relaxed (); }
+
+  void set_relaxed (short v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
+  void set_release (short v_) { hb_atomic_int_impl_set (&v, v_); }
+  short get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
+  short get_acquire () const { return hb_atomic_int_impl_get (&v); }
+  short inc () { return hb_atomic_int_impl_add (&v,  1); }
+  short dec () { return hb_atomic_int_impl_add (&v, -1); }
+
+  short v = 0;
+};
+
 struct hb_atomic_int_t
 {
   hb_atomic_int_t () = default;
   constexpr hb_atomic_int_t (int v) : v (v) {}
 
+  hb_atomic_int_t& operator = (int v_) { set_relaxed (v_); return *this; }
+  operator int () const { return get_relaxed (); }
+
   void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
-  void set (int v_) { hb_atomic_int_impl_set (&v, v_); }
+  void set_release (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 get_acquire () 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); }
 
@@ -163,15 +204,16 @@ struct hb_atomic_ptr_t
 
   hb_atomic_ptr_t () = default;
   constexpr hb_atomic_ptr_t (T* v) : v (v) {}
+  hb_atomic_ptr_t (const hb_atomic_ptr_t &other) = delete;
 
   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); }
+  T *get_acquire () 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 * operator -> () const                    { return get_acquire (); }
+  template <typename C> operator C * () const { return get_acquire (); }
 
   T *v = nullptr;
 };
index a9e1278..f541472 100644 (file)
@@ -39,6 +39,12 @@ struct hb_bimap_t
     back_map.reset ();
   }
 
+  void alloc (unsigned pop)
+  {
+    forw_map.alloc (pop);
+    back_map.alloc (pop);
+  }
+
   bool in_error () const { return forw_map.in_error () || back_map.in_error (); }
 
   void set (hb_codepoint_t lhs, hb_codepoint_t rhs)
@@ -48,17 +54,18 @@ struct hb_bimap_t
     if (unlikely (rhs == HB_MAP_VALUE_INVALID)) { del (lhs); return; }
 
     forw_map.set (lhs, rhs);
-    if (in_error ()) return;
+    if (unlikely (in_error ())) return;
 
     back_map.set (rhs, lhs);
-    if (in_error ()) forw_map.del (lhs);
+    if (unlikely (in_error ())) forw_map.del (lhs);
   }
 
   hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); }
   hb_codepoint_t backward (hb_codepoint_t rhs) const { return back_map.get (rhs); }
 
   hb_codepoint_t operator [] (hb_codepoint_t lhs) const { return get (lhs); }
-  bool has (hb_codepoint_t lhs, hb_codepoint_t *vp = nullptr) const { return forw_map.has (lhs, vp); }
+  bool has (hb_codepoint_t lhs) const { return forw_map.has (lhs); }
+
 
   void del (hb_codepoint_t lhs)
   {
@@ -72,18 +79,45 @@ struct hb_bimap_t
     back_map.clear ();
   }
 
-  bool is_empty () const { return get_population () == 0; }
+  bool is_empty () const { return forw_map.is_empty (); }
 
   unsigned int get_population () const { return forw_map.get_population (); }
 
   protected:
   hb_map_t  forw_map;
   hb_map_t  back_map;
+
+  public:
+  auto keys () const HB_AUTO_RETURN (+ forw_map.keys())
+  auto values () const HB_AUTO_RETURN (+ forw_map.values())
+  auto iter () const HB_AUTO_RETURN (+ forw_map.iter())
 };
 
-/* Inremental bimap: only lhs is given, rhs is incrementally assigned */
-struct hb_inc_bimap_t : hb_bimap_t
+/* Incremental bimap: only lhs is given, rhs is incrementally assigned */
+struct hb_inc_bimap_t
 {
+  bool in_error () const { return forw_map.in_error () || back_map.in_error (); }
+
+  unsigned int get_population () const { return forw_map.get_population (); }
+
+  void reset ()
+  {
+    forw_map.reset ();
+    back_map.reset ();
+  }
+
+  void alloc (unsigned pop)
+  {
+    forw_map.alloc (pop);
+    back_map.alloc (pop);
+  }
+
+  void clear ()
+  {
+    forw_map.clear ();
+    back_map.resize (0);
+  }
+
   /* Add a mapping from lhs to rhs with a unique value if lhs is unknown.
    * Return the rhs value as the result.
    */
@@ -92,29 +126,42 @@ struct hb_inc_bimap_t : hb_bimap_t
     hb_codepoint_t  rhs = forw_map[lhs];
     if (rhs == HB_MAP_VALUE_INVALID)
     {
-      rhs = next_value++;
-      set (lhs, rhs);
+      rhs = back_map.length;
+      forw_map.set (lhs, rhs);
+      back_map.push (lhs);
     }
     return rhs;
   }
 
   hb_codepoint_t skip ()
-  { return next_value++; }
+  {
+    hb_codepoint_t start = back_map.length;
+    back_map.push (HB_MAP_VALUE_INVALID);
+    return start;
+  }
+
+  hb_codepoint_t skip (unsigned count)
+  {
+    hb_codepoint_t start = back_map.length;
+    back_map.alloc (back_map.length + count);
+    for (unsigned i = 0; i < count; i++)
+      back_map.push (HB_MAP_VALUE_INVALID);
+    return start;
+  }
 
   hb_codepoint_t get_next_value () const
-  { return next_value; }
+  { return back_map.length; }
 
   void add_set (const hb_set_t *set)
   {
-    hb_codepoint_t i = HB_SET_VALUE_INVALID;
-    while (hb_set_next (set, &i)) add (i);
+    for (auto i : *set) add (i);
   }
 
   /* Create an identity map. */
   bool identity (unsigned int size)
   {
     clear ();
-    for (hb_codepoint_t i = 0; i < size; i++) set (i, i);
+    for (hb_codepoint_t i = 0; i < size; i++) add (i);
     return !in_error ();
   }
 
@@ -129,20 +176,30 @@ struct hb_inc_bimap_t : hb_bimap_t
   {
     hb_codepoint_t  count = get_population ();
     hb_vector_t <hb_codepoint_t> work;
-    work.resize (count);
+    if (unlikely (!work.resize (count, false))) return;
 
     for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
-      work[rhs] = back_map[rhs];
+      work.arrayZ[rhs] = back_map[rhs];
 
     work.qsort (cmp_id);
 
     clear ();
     for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
-      set (work[rhs], rhs);
+      add (work.arrayZ[rhs]);
   }
 
+  hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); }
+  hb_codepoint_t backward (hb_codepoint_t rhs) const { return back_map[rhs]; }
+
+  hb_codepoint_t operator [] (hb_codepoint_t lhs) const { return get (lhs); }
+  bool has (hb_codepoint_t lhs) const { return forw_map.has (lhs); }
+
   protected:
-  unsigned int next_value = 0;
+  hb_map_t forw_map;
+  hb_vector_t<hb_codepoint_t> back_map;
+
+  public:
+  auto keys () const HB_AUTO_RETURN (+ back_map.iter())
 };
 
 #endif /* HB_BIMAP_HH */
index 263be3d..869c678 100644 (file)
 
 #include "hb.hh"
 
+
+/* Compiler-assisted vectorization. */
+
+/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
+ * basically a fixed-size bitset. We can't use the compiler type because hb_vector_t cannot
+ * guarantee alignment requirements. */
+template <typename elt_t, unsigned int byte_size>
+struct hb_vector_size_t
+{
+  elt_t& operator [] (unsigned int i) { return v[i]; }
+  const elt_t& operator [] (unsigned int i) const { return v[i]; }
+
+  void init0 ()
+  {
+    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
+      v[i] = 0;
+  }
+  void init1 ()
+  {
+    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
+      v[i] = (elt_t) -1;
+  }
+
+  template <typename Op>
+  hb_vector_size_t process (const Op& op) const
+  {
+    hb_vector_size_t r;
+    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
+      r.v[i] = op (v[i]);
+    return r;
+  }
+  template <typename Op>
+  hb_vector_size_t process (const Op& op, const hb_vector_size_t &o) const
+  {
+    hb_vector_size_t r;
+    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
+      r.v[i] = op (v[i], o.v[i]);
+    return r;
+  }
+  hb_vector_size_t operator | (const hb_vector_size_t &o) const
+  { return process (hb_bitwise_or, o); }
+  hb_vector_size_t operator & (const hb_vector_size_t &o) const
+  { return process (hb_bitwise_and, o); }
+  hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
+  { return process (hb_bitwise_xor, o); }
+  hb_vector_size_t operator ~ () const
+  { return process (hb_bitwise_neg); }
+
+  hb_array_t<const elt_t> iter () const
+  { return hb_array (v); }
+
+  private:
+  static_assert (0 == byte_size % sizeof (elt_t), "");
+  elt_t v[byte_size / sizeof (elt_t)];
+};
+
+
 struct hb_bit_page_t
 {
-  void init0 () { v.clear (); }
-  void init1 () { v.clear (0xFF); }
+  void init0 () { v.init0 (); population = 0; }
+  void init1 () { v.init1 (); population = PAGE_BITS; }
 
-  constexpr unsigned len () const
+  void dirty () { population = UINT_MAX; }
+
+  static inline constexpr unsigned len ()
   { return ARRAY_LENGTH_CONST (v); }
 
+  operator bool () const { return !is_empty (); }
   bool is_empty () const
   {
-    for (unsigned int i = 0; i < len (); i++)
-      if (v[i])
-       return false;
-    return true;
+    if (has_population ()) return !population;
+    return
+    + hb_iter (v)
+    | hb_none
+    ;
+  }
+  uint32_t hash () const
+  {
+    return hb_bytes_t ((const char *) &v, sizeof (v)).hash ();
   }
 
-  void add (hb_codepoint_t g) { elt (g) |= mask (g); }
-  void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
-  void set (hb_codepoint_t g, bool v) { if (v) add (g); else del (g); }
+  void add (hb_codepoint_t g) { elt (g) |= mask (g); dirty (); }
+  void del (hb_codepoint_t g) { elt (g) &= ~mask (g); dirty (); }
+  void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); }
   bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
 
   void add_range (hb_codepoint_t a, hb_codepoint_t b)
@@ -59,51 +124,131 @@ struct hb_bit_page_t
       *la |= (mask (b) << 1) - mask(a);
     else
     {
-      *la |= ~(mask (a) - 1);
+      *la |= ~(mask (a) - 1llu);
       la++;
 
-      memset (la, 0xff, (char *) lb - (char *) la);
+      hb_memset (la, 0xff, (char *) lb - (char *) la);
 
-      *lb |= ((mask (b) << 1) - 1);
+      *lb |= ((mask (b) << 1) - 1llu);
     }
+    dirty ();
   }
   void del_range (hb_codepoint_t a, hb_codepoint_t b)
   {
     elt_t *la = &elt (a);
     elt_t *lb = &elt (b);
     if (la == lb)
-      *la &= ~((mask (b) << 1) - mask(a));
+      *la &= ~((mask (b) << 1llu) - mask(a));
     else
     {
       *la &= mask (a) - 1;
       la++;
 
-      memset (la, 0, (char *) lb - (char *) la);
+      hb_memset (la, 0, (char *) lb - (char *) la);
 
-      *lb &= ~((mask (b) << 1) - 1);
+      *lb &= ~((mask (b) << 1) - 1llu);
     }
+    dirty ();
   }
   void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v)
   { if (v) add_range (a, b); else del_range (a, b); }
 
+
+  // Writes out page values to the array p. Returns the number of values
+  // written. At most size codepoints will be written.
+  unsigned int write (uint32_t        base,
+                     unsigned int    start_value,
+                     hb_codepoint_t *p,
+                     unsigned int    size) const
+  {
+    unsigned int start_v = start_value / ELT_BITS;
+    unsigned int start_bit = start_value & ELT_MASK;
+    unsigned int count = 0;
+    for (unsigned i = start_v; i < len () && count < size; i++)
+    {
+      elt_t bits = v[i];
+      uint32_t v_base = base | (i * ELT_BITS);
+      for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++)
+      {
+       if ((elt_t(1) << j) & bits) {
+         *p++ = v_base | j;
+         count++;
+       }
+      }
+      start_bit = 0;
+    }
+    return count;
+  }
+
+  // Writes out the values NOT in this page to the array p. Returns the
+  // number of values written. At most size codepoints will be written.
+  // Returns the number of codepoints written. next_value holds the next value
+  // that should be written (if not present in this page). This is used to fill
+  // any missing value gaps between this page and the previous page, if any.
+  // next_value is updated to one more than the last value present in this page.
+  unsigned int write_inverted (uint32_t        base,
+                              unsigned int    start_value,
+                              hb_codepoint_t *p,
+                              unsigned int    size,
+                              hb_codepoint_t *next_value) const
+  {
+    unsigned int start_v = start_value / ELT_BITS;
+    unsigned int start_bit = start_value & ELT_MASK;
+    unsigned int count = 0;
+    for (unsigned i = start_v; i < len () && count < size; i++)
+    {
+      elt_t bits = v[i];
+      uint32_t v_offset = i * ELT_BITS;
+      for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++)
+      {
+       if ((elt_t(1) << j) & bits)
+       {
+         hb_codepoint_t value = base | v_offset | j;
+         // Emit all the missing values from next_value up to value - 1.
+         for (hb_codepoint_t k = *next_value; k < value && count < size; k++)
+         {
+           *p++ = k;
+           count++;
+         }
+         // Skip over this value;
+         *next_value = value + 1;
+       }
+      }
+      start_bit = 0;
+    }
+    return count;
+  }
+
+  bool operator == (const hb_bit_page_t &other) const { return is_equal (other); }
   bool is_equal (const hb_bit_page_t &other) const
   {
-    return 0 == hb_memcmp (&v, &other.v, sizeof (v));
+    for (unsigned i = 0; i < len (); i++)
+      if (v[i] != other.v[i])
+       return false;
+    return true;
   }
+  bool operator <= (const hb_bit_page_t &larger_page) const { return is_subset (larger_page); }
   bool is_subset (const hb_bit_page_t &larger_page) const
   {
+    if (has_population () && larger_page.has_population () &&
+       population > larger_page.population)
+      return false;
+
     for (unsigned i = 0; i < len (); i++)
       if (~larger_page.v[i] & v[i])
        return false;
     return true;
   }
 
+  bool has_population () const { return population != UINT_MAX; }
   unsigned int get_population () const
   {
-    unsigned int pop = 0;
-    for (unsigned int i = 0; i < len (); i++)
-      pop += hb_popcount (v[i]);
-    return pop;
+    if (has_population ()) return population;
+    population =
+    + hb_iter (v)
+    | hb_reduce ([] (unsigned pop, const elt_t &_) { return pop + hb_popcount (_); }, 0u)
+    ;
+    return population;
   }
 
   bool next (hb_codepoint_t *codepoint) const
@@ -177,8 +322,11 @@ struct hb_bit_page_t
   static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
 
   typedef unsigned long long elt_t;
-  static constexpr unsigned PAGE_BITS = 512;
+  static constexpr unsigned PAGE_BITS_LOG_2 = 9; // 512 bits
+  static constexpr unsigned PAGE_BITS = 1 << PAGE_BITS_LOG_2;
+  static_assert (1 << PAGE_BITS_LOG_2 == PAGE_BITS, "");
   static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
+  static constexpr unsigned PAGE_BITMASK = PAGE_BITS - 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; }
@@ -187,6 +335,7 @@ struct hb_bit_page_t
 
   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, "");
@@ -195,9 +344,9 @@ struct hb_bit_page_t
   const elt_t& elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; }
   static constexpr elt_t mask (hb_codepoint_t g) { return elt_t (1) << (g & ELT_MASK); }
 
+  mutable unsigned population;
   vector_t v;
 };
-static_assert (hb_bit_page_t::PAGE_BITS == sizeof (hb_bit_page_t) * 8, "");
 
 
 #endif /* HB_BIT_PAGE_HH */
index 0832b0f..e765a47 100644 (file)
@@ -38,10 +38,10 @@ struct hb_bit_set_invertible_t
   bool inverted = false;
 
   hb_bit_set_invertible_t () = default;
-  hb_bit_set_invertible_t (hb_bit_set_invertible_t& o) = default;
-  hb_bit_set_invertible_t (hb_bit_set_invertible_t&& o) = default;
+  hb_bit_set_invertible_t (const hb_bit_set_invertible_t& o) = default;
+  hb_bit_set_invertible_t (hb_bit_set_invertible_t&& other) : hb_bit_set_invertible_t () { hb_swap (*this, other); }
   hb_bit_set_invertible_t& operator= (const hb_bit_set_invertible_t& o) = default;
-  hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& o) = default;
+  hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& other) { hb_swap (*this, other); return *this; }
   friend void swap (hb_bit_set_invertible_t &a, hb_bit_set_invertible_t &b)
   {
     if (likely (!a.s.successful || !b.s.successful))
@@ -56,6 +56,7 @@ struct hb_bit_set_invertible_t
   bool in_error () const { return s.in_error (); }
   explicit operator bool () const { return !is_empty (); }
 
+  void alloc (unsigned sz) { s.alloc (sz); }
   void reset ()
   {
     s.reset ();
@@ -73,12 +74,19 @@ struct hb_bit_set_invertible_t
       inverted = !inverted;
   }
 
+  bool is_inverted () const
+  {
+    return inverted;
+  }
+
   bool is_empty () const
   {
     hb_codepoint_t v = INVALID;
     next (&v);
     return v == INVALID;
   }
+  uint32_t hash () const { return s.hash () ^ (uint32_t) inverted; }
+
   hb_codepoint_t get_min () const
   {
     hb_codepoint_t v = INVALID;
@@ -97,7 +105,7 @@ struct hb_bit_set_invertible_t
 
   void add (hb_codepoint_t g) { unlikely (inverted) ? s.del (g) : s.add (g); }
   bool add_range (hb_codepoint_t a, hb_codepoint_t b)
-  { return unlikely (inverted) ? (s.del_range (a, b), true) : s.add_range (a, b); }
+  { return unlikely (inverted) ? ((void) s.del_range (a, b), true) : s.add_range (a, b); }
 
   template <typename T>
   void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
@@ -120,17 +128,15 @@ struct hb_bit_set_invertible_t
   bool get (hb_codepoint_t g) const { return s.get (g) ^ inverted; }
 
   /* Has interface. */
-  static constexpr bool SENTINEL = false;
-  typedef bool value_t;
-  value_t operator [] (hb_codepoint_t k) const { return get (k); }
-  bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+  bool operator [] (hb_codepoint_t k) const { return get (k); }
+  bool has (hb_codepoint_t k) const { return (*this)[k]; }
   /* Predicate. */
   bool operator () (hb_codepoint_t k) const { return has (k); }
 
   /* Sink interface. */
   hb_bit_set_invertible_t& operator << (hb_codepoint_t v)
   { add (v); return *this; }
-  hb_bit_set_invertible_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
+  hb_bit_set_invertible_t& operator << (const hb_codepoint_pair_t& range)
   { add_range (range.first, range.second); return *this; }
 
   bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
@@ -156,7 +162,7 @@ struct hb_bit_set_invertible_t
       auto it1 = iter ();
       auto it2 = other.iter ();
       return hb_all (+ hb_zip (it1, it2)
-                    | hb_map ([](hb_pair_t<hb_codepoint_t, hb_codepoint_t> _) { return _.first == _.second; }));
+                    | hb_map ([](hb_codepoint_pair_t _) { return _.first == _.second; }));
     }
   }
 
@@ -323,6 +329,14 @@ struct hb_bit_set_invertible_t
     return true;
   }
 
+  unsigned int next_many (hb_codepoint_t  codepoint,
+                         hb_codepoint_t *out,
+                         unsigned int    size) const
+  {
+    return inverted ? s.next_many_inverted (codepoint, out, size)
+                   : s.next_many (codepoint, out, size);
+  }
+
   static constexpr hb_codepoint_t INVALID = hb_bit_set_t::INVALID;
 
   /*
@@ -331,6 +345,7 @@ struct hb_bit_set_invertible_t
   struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
   {
     static constexpr bool is_sorted_iterator = true;
+    static constexpr bool has_fast_len = true;
     iter_t (const hb_bit_set_invertible_t &s_ = Null (hb_bit_set_invertible_t),
            bool init = true) : s (&s_), v (INVALID), l(0)
     {
@@ -349,7 +364,7 @@ struct hb_bit_set_invertible_t
     unsigned __len__ () const { return l; }
     iter_t end () const { return iter_t (*s, false); }
     bool operator != (const iter_t& o) const
-    { return s != o.s || v != o.v; }
+    { return v != o.v || s != o.s; }
 
     protected:
     const hb_bit_set_invertible_t *s;
index a471ee4..1dbcce5 100644 (file)
@@ -30,7 +30,6 @@
 
 #include "hb.hh"
 #include "hb-bit-page.hh"
-#include "hb-machinery.hh"
 
 
 struct hb_bit_set_t
@@ -38,7 +37,7 @@ struct hb_bit_set_t
   hb_bit_set_t () = default;
   ~hb_bit_set_t () = default;
 
-  hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other); }
+  hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other, true); }
   hb_bit_set_t ( hb_bit_set_t&& other) : hb_bit_set_t () { hb_swap (*this, other); }
   hb_bit_set_t& operator= (const hb_bit_set_t& other) { set (other); return *this; }
   hb_bit_set_t& operator= (hb_bit_set_t&& other) { hb_swap (*this, other); return *this; }
@@ -78,25 +77,36 @@ struct hb_bit_set_t
 
   bool successful = true; /* Allocations successful */
   mutable unsigned int population = 0;
-  mutable unsigned int last_page_lookup = 0;
+  mutable hb_atomic_int_t last_page_lookup = 0;
   hb_sorted_vector_t<page_map_t> page_map;
   hb_vector_t<page_t> pages;
 
   void err () { if (successful) successful = false; } /* TODO Remove */
   bool in_error () const { return !successful; }
 
-  bool resize (unsigned int count)
+  bool resize (unsigned int count, bool clear = true, bool exact_size = false)
   {
     if (unlikely (!successful)) return false;
-    if (unlikely (!pages.resize (count) || !page_map.resize (count)))
+
+    if (pages.length == 0 && count == 1)
+      exact_size = true; // Most sets are small and local
+
+    if (unlikely (!pages.resize (count, clear, exact_size) || !page_map.resize (count, clear, exact_size)))
     {
-      pages.resize (page_map.length);
+      pages.resize (page_map.length, clear, exact_size);
       successful = false;
       return false;
     }
     return true;
   }
 
+  void alloc (unsigned sz)
+  {
+    sz >>= (page_t::PAGE_BITS_LOG_2 - 1);
+    pages.alloc (sz);
+    page_map.alloc (sz);
+  }
+
   void reset ()
   {
     successful = true;
@@ -119,6 +129,18 @@ struct hb_bit_set_t
   }
   explicit operator bool () const { return !is_empty (); }
 
+  uint32_t hash () const
+  {
+    uint32_t h = 0;
+    for (auto &map : page_map)
+    {
+      auto &page = pages.arrayZ[map.index];
+      if (unlikely (page.is_empty ())) continue;
+      h = h * 31 + hb_hash (map.major) + hb_hash (page);
+    }
+    return h;
+  }
+
   private:
   void dirty () { population = UINT_MAX; }
   public:
@@ -160,6 +182,16 @@ struct hb_bit_set_t
     return true;
   }
 
+  /* Duplicated here from hb-machinery.hh to avoid including it. */
+  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<const Type*> ((const char *) P + offset);
+#pragma GCC diagnostic pop
+  }
+
   template <typename T>
   void set_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
   {
@@ -175,7 +207,7 @@ struct hb_bit_set_t
       unsigned int end = major_start (m + 1);
       do
       {
-        if (v || page) /* The v check is to optimize out the page check if v is true. */
+        if (g != INVALID && (v || page)) /* The v check is to optimize out the page check if v is true. */
          page->set (g, v);
 
        array = &StructAtOffsetUnaligned<T> (array, stride);
@@ -203,7 +235,7 @@ struct hb_bit_set_t
   bool set_sorted_array (bool v, 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;
+    if (unlikely (!count)) return true;
     dirty ();
     hb_codepoint_t g = *array;
     hb_codepoint_t last_g = g;
@@ -219,10 +251,10 @@ struct hb_bit_set_t
        if (g < last_g) return false;
        last_g = g;
 
-        if (v || page) /* The v check is to optimize out the page check if v is true. */
+        if (g != INVALID && (v || page)) /* The v check is to optimize out the page check if v is true. */
          page->add (g);
 
-       array = (const T *) ((const char *) array + stride);
+       array = &StructAtOffsetUnaligned<T> (array, stride);
        count--;
       }
       while (count && (g = *array, g < end));
@@ -315,17 +347,15 @@ struct hb_bit_set_t
   }
 
   /* Has interface. */
-  static constexpr bool SENTINEL = false;
-  typedef bool value_t;
-  value_t operator [] (hb_codepoint_t k) const { return get (k); }
-  bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+  bool operator [] (hb_codepoint_t k) const { return get (k); }
+  bool has (hb_codepoint_t k) const { return (*this)[k]; }
   /* Predicate. */
   bool operator () (hb_codepoint_t k) const { return has (k); }
 
   /* Sink interface. */
   hb_bit_set_t& operator << (hb_codepoint_t v)
   { add (v); return *this; }
-  hb_bit_set_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
+  hb_bit_set_t& operator << (const hb_codepoint_pair_t& range)
   { add_range (range.first, range.second); return *this; }
 
   bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
@@ -333,23 +363,22 @@ struct hb_bit_set_t
     hb_codepoint_t c = first - 1;
     return next (&c) && c <= last;
   }
-  void set (const hb_bit_set_t &other)
+  void set (const hb_bit_set_t &other, bool exact_size = false)
   {
     if (unlikely (!successful)) return;
     unsigned int count = other.pages.length;
-    if (unlikely (!resize (count)))
+    if (unlikely (!resize (count, false, exact_size)))
       return;
     population = other.population;
 
-    /* TODO switch to vector operator =. */
-    hb_memcpy ((void *) pages, (const void *) other.pages, count * pages.item_size);
-    hb_memcpy ((void *) page_map, (const void *) other.page_map, count * page_map.item_size);
+    page_map = other.page_map;
+    pages = other.pages;
   }
 
   bool is_equal (const hb_bit_set_t &other) const
   {
     if (has_population () && other.has_population () &&
-       get_population () != other.get_population ())
+       population != other.population)
       return false;
 
     unsigned int na = pages.length;
@@ -377,7 +406,7 @@ struct hb_bit_set_t
   bool is_subset (const hb_bit_set_t &larger_set) const
   {
     if (has_population () && larger_set.has_population () &&
-       get_population () != larger_set.get_population ())
+       population > larger_set.population)
       return false;
 
     uint32_t spi = 0;
@@ -386,7 +415,6 @@ struct hb_bit_set_t
       uint32_t spm = page_map[spi].major;
       uint32_t lpm = larger_set.page_map[lpi].major;
       auto sp = page_at (spi);
-      auto lp = larger_set.page_at (lpi);
 
       if (spm < lpm && !sp.is_empty ())
         return false;
@@ -394,6 +422,7 @@ struct hb_bit_set_t
       if (lpm < spm)
         continue;
 
+      auto lp = larger_set.page_at (lpi);
       if (!sp.is_subset (lp))
         return false;
 
@@ -410,7 +439,7 @@ struct hb_bit_set_t
   private:
   bool allocate_compact_workspace (hb_vector_t<unsigned>& workspace)
   {
-    if (unlikely (!workspace.resize (pages.length)))
+    if (unlikely (!workspace.resize_exact (pages.length)))
     {
       successful = false;
       return false;
@@ -451,12 +480,10 @@ struct hb_bit_set_t
   }
   public:
 
-  template <typename Op>
-  void process (const Op& op, const hb_bit_set_t &other)
+  void process_ (hb_bit_page_t::vector_t (*op) (const hb_bit_page_t::vector_t &, const hb_bit_page_t::vector_t &),
+                bool passthru_left, bool passthru_right,
+                const hb_bit_set_t &other)
   {
-    const bool passthru_left = op (1, 0);
-    const bool passthru_right = op (0, 1);
-
     if (unlikely (!successful)) return;
 
     dirty ();
@@ -528,21 +555,22 @@ struct hb_bit_set_t
     b = nb;
     for (; a && b; )
     {
-      if (page_map[a - 1].major == other.page_map[b - 1].major)
+      if (page_map.arrayZ[a - 1].major == other.page_map.arrayZ[b - 1].major)
       {
        a--;
        b--;
        count--;
-       page_map[count] = page_map[a];
+       page_map.arrayZ[count] = page_map.arrayZ[a];
        page_at (count).v = op (page_at (a).v, other.page_at (b).v);
+       page_at (count).dirty ();
       }
-      else if (page_map[a - 1].major > other.page_map[b - 1].major)
+      else if (page_map.arrayZ[a - 1].major > other.page_map.arrayZ[b - 1].major)
       {
        a--;
        if (passthru_left)
        {
          count--;
-         page_map[count] = page_map[a];
+         page_map.arrayZ[count] = page_map.arrayZ[a];
        }
       }
       else
@@ -551,9 +579,9 @@ struct hb_bit_set_t
        if (passthru_right)
        {
          count--;
-         page_map[count].major = other.page_map[b].major;
-         page_map[count].index = next_page++;
-         page_at (count).v = other.page_at (b).v;
+         page_map.arrayZ[count].major = other.page_map.arrayZ[b].major;
+         page_map.arrayZ[count].index = next_page++;
+         page_at (count) = other.page_at (b);
        }
       }
     }
@@ -562,20 +590,29 @@ struct hb_bit_set_t
       {
        a--;
        count--;
-       page_map[count] = page_map [a];
+       page_map.arrayZ[count] = page_map.arrayZ[a];
       }
     if (passthru_right)
       while (b)
       {
        b--;
        count--;
-       page_map[count].major = other.page_map[b].major;
-       page_map[count].index = next_page++;
-       page_at (count).v = other.page_at (b).v;
+       page_map.arrayZ[count].major = other.page_map.arrayZ[b].major;
+       page_map.arrayZ[count].index = next_page++;
+       page_at (count) = other.page_at (b);
       }
     assert (!count);
     resize (newCount);
   }
+  template <typename Op>
+  static hb_bit_page_t::vector_t
+  op_ (const hb_bit_page_t::vector_t &a, const hb_bit_page_t::vector_t &b)
+  { return Op{} (a, b); }
+  template <typename Op>
+  void process (const Op& op, const hb_bit_set_t &other)
+  {
+    process_ (op_<Op>, op (1, 0), op (0, 1), other);
+  }
 
   void union_ (const hb_bit_set_t &other) { process (hb_bitwise_or, other); }
   void intersect (const hb_bit_set_t &other) { process (hb_bitwise_and, other); }
@@ -584,8 +621,6 @@ struct hb_bit_set_t
 
   bool next (hb_codepoint_t *codepoint) const
   {
-    // TODO: this should be merged with prev() as both implementations
-    //       are very similar.
     if (unlikely (*codepoint == INVALID)) {
       *codepoint = get_min ();
       return *codepoint != INVALID;
@@ -602,6 +637,7 @@ struct hb_bit_set_t
         *codepoint = INVALID;
         return false;
       }
+      last_page_lookup = i;
     }
 
     const auto* pages_array = pages.arrayZ;
@@ -611,7 +647,6 @@ struct hb_bit_set_t
       if (pages_array[current.index].next (codepoint))
       {
         *codepoint += current.major * page_t::PAGE_BITS;
-        last_page_lookup = i;
         return true;
       }
       i++;
@@ -619,7 +654,7 @@ struct hb_bit_set_t
 
     for (; i < page_map.length; i++)
     {
-      const page_map_t &current = page_map.arrayZ[i];
+      const page_map_t &current = page_map_array[i];
       hb_codepoint_t m = pages_array[current.index].get_min ();
       if (m != INVALID)
       {
@@ -628,7 +663,6 @@ struct hb_bit_set_t
        return true;
       }
     }
-    last_page_lookup = 0;
     *codepoint = INVALID;
     return false;
   }
@@ -642,21 +676,21 @@ struct hb_bit_set_t
     page_map_t map = {get_major (*codepoint), 0};
     unsigned int i;
     page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST);
-    if (i < page_map.length && page_map[i].major == map.major)
+    if (i < page_map.length && page_map.arrayZ[i].major == map.major)
     {
-      if (pages[page_map[i].index].previous (codepoint))
+      if (pages[page_map.arrayZ[i].index].previous (codepoint))
       {
-       *codepoint += page_map[i].major * page_t::PAGE_BITS;
+       *codepoint += page_map.arrayZ[i].major * page_t::PAGE_BITS;
        return true;
       }
     }
     i--;
     for (; (int) i >= 0; i--)
     {
-      hb_codepoint_t m = pages[page_map[i].index].get_max ();
+      hb_codepoint_t m = pages.arrayZ[page_map.arrayZ[i].index].get_max ();
       if (m != INVALID)
       {
-       *codepoint = page_map[i].major * page_t::PAGE_BITS + m;
+       *codepoint = page_map.arrayZ[i].major * page_t::PAGE_BITS + m;
        return true;
       }
     }
@@ -700,6 +734,99 @@ struct hb_bit_set_t
     return true;
   }
 
+  unsigned int next_many (hb_codepoint_t  codepoint,
+                         hb_codepoint_t *out,
+                         unsigned int    size) const
+  {
+    // By default, start at the first bit of the first page of values.
+    unsigned int start_page = 0;
+    unsigned int start_page_value = 0;
+    if (unlikely (codepoint != INVALID))
+    {
+      const auto* page_map_array = page_map.arrayZ;
+      unsigned int major = get_major (codepoint);
+      unsigned int i = last_page_lookup;
+      if (unlikely (i >= page_map.length || page_map_array[i].major != major))
+      {
+       page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST);
+       if (i >= page_map.length)
+         return 0;  // codepoint is greater than our max element.
+      }
+      start_page = i;
+      start_page_value = page_remainder (codepoint + 1);
+      if (unlikely (start_page_value == 0))
+      {
+        // The export-after value was last in the page. Start on next page.
+        start_page++;
+        start_page_value = 0;
+      }
+    }
+
+    unsigned int initial_size = size;
+    for (unsigned int i = start_page; i < page_map.length && size; i++)
+    {
+      uint32_t base = major_start (page_map[i].major);
+      unsigned int n = pages[page_map[i].index].write (base, start_page_value, out, size);
+      out += n;
+      size -= n;
+      start_page_value = 0;
+    }
+    return initial_size - size;
+  }
+
+  unsigned int next_many_inverted (hb_codepoint_t  codepoint,
+                                  hb_codepoint_t *out,
+                                  unsigned int    size) const
+  {
+    unsigned int initial_size = size;
+    // By default, start at the first bit of the first page of values.
+    unsigned int start_page = 0;
+    unsigned int start_page_value = 0;
+    if (unlikely (codepoint != INVALID))
+    {
+      const auto* page_map_array = page_map.arrayZ;
+      unsigned int major = get_major (codepoint);
+      unsigned int i = last_page_lookup;
+      if (unlikely (i >= page_map.length || page_map_array[i].major != major))
+      {
+        page_map.bfind(major, &i, HB_NOT_FOUND_STORE_CLOSEST);
+        if (unlikely (i >= page_map.length))
+        {
+          // codepoint is greater than our max element.
+          while (++codepoint != INVALID && size)
+          {
+            *out++ = codepoint;
+            size--;
+          }
+          return initial_size - size;
+        }
+      }
+      start_page = i;
+      start_page_value = page_remainder (codepoint + 1);
+      if (unlikely (start_page_value == 0))
+      {
+        // The export-after value was last in the page. Start on next page.
+        start_page++;
+        start_page_value = 0;
+      }
+    }
+
+    hb_codepoint_t next_value = codepoint + 1;
+    for (unsigned int i=start_page; i<page_map.length && size; i++)
+    {
+      uint32_t base = major_start (page_map[i].major);
+      unsigned int n = pages[page_map[i].index].write_inverted (base, start_page_value, out, size, &next_value);
+      out += n;
+      size -= n;
+      start_page_value = 0;
+    }
+    while (next_value < HB_SET_VALUE_INVALID && size) {
+      *out++ = next_value++;
+      size--;
+    }
+    return initial_size - size;
+  }
+
   bool has_population () const { return population != UINT_MAX; }
   unsigned int get_population () const
   {
@@ -749,6 +876,7 @@ struct hb_bit_set_t
   struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
   {
     static constexpr bool is_sorted_iterator = true;
+    static constexpr bool has_fast_len = true;
     iter_t (const hb_bit_set_t &s_ = Null (hb_bit_set_t),
            bool init = true) : s (&s_), v (INVALID), l(0)
     {
@@ -781,8 +909,20 @@ struct hb_bit_set_t
 
   page_t *page_for (hb_codepoint_t g, bool insert = false)
   {
-    page_map_t map = {get_major (g), pages.length};
-    unsigned int i;
+    unsigned major = get_major (g);
+
+    /* The extra page_map length is necessary; can't just rely on vector here,
+     * since the next check would be tricked because a null page also has
+     * major==0, which we can't distinguish from an actually major==0 page... */
+    unsigned i = last_page_lookup;
+    if (likely (i < page_map.length))
+    {
+      auto &cached_page = page_map.arrayZ[i];
+      if (cached_page.major == major)
+       return &pages.arrayZ[cached_page.index];
+    }
+
+    page_map_t map = {major, pages.length};
     if (!page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST))
     {
       if (!insert)
@@ -791,26 +931,51 @@ struct hb_bit_set_t
       if (unlikely (!resize (pages.length + 1)))
        return nullptr;
 
-      pages[map.index].init0 ();
-      memmove (page_map + i + 1,
-              page_map + i,
+      pages.arrayZ[map.index].init0 ();
+      memmove (page_map.arrayZ + i + 1,
+              page_map.arrayZ + i,
               (page_map.length - 1 - i) * page_map.item_size);
-      page_map[i] = map;
+      page_map.arrayZ[i] = map;
     }
-    return &pages[page_map[i].index];
+
+    last_page_lookup = i;
+    return &pages.arrayZ[page_map.arrayZ[i].index];
   }
   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);
-    if (found)
-      return &pages[found->index];
-    return nullptr;
+    unsigned major = get_major (g);
+
+    /* The extra page_map length is necessary; can't just rely on vector here,
+     * since the next check would be tricked because a null page also has
+     * major==0, which we can't distinguish from an actually major==0 page... */
+    unsigned i = last_page_lookup;
+    if (likely (i < page_map.length))
+    {
+      auto &cached_page = page_map.arrayZ[i];
+      if (cached_page.major == major)
+       return &pages.arrayZ[cached_page.index];
+    }
+
+    page_map_t key = {major};
+    if (!page_map.bfind (key, &i))
+      return nullptr;
+
+    last_page_lookup = i;
+    return &pages.arrayZ[page_map[i].index];
+  }
+  page_t &page_at (unsigned int i)
+  {
+    assert (i < page_map.length);
+    return pages.arrayZ[page_map.arrayZ[i].index];
+  }
+  const page_t &page_at (unsigned int i) const
+  {
+    assert (i < page_map.length);
+    return pages.arrayZ[page_map.arrayZ[i].index];
   }
-  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; }
+  unsigned int get_major (hb_codepoint_t g) const { return g >> page_t::PAGE_BITS_LOG_2; }
+  unsigned int page_remainder (hb_codepoint_t g) const { return g & page_t::PAGE_BITMASK; }
+  hb_codepoint_t major_start (unsigned int major) const { return major << page_t::PAGE_BITS_LOG_2; }
 };
 
 
index f120002..265effb 100644 (file)
@@ -99,7 +99,7 @@ hb_blob_create (const char        *data,
  * is zero. This is in contrast to hb_blob_create(), which returns the singleton
  * empty blob (as returned by hb_blob_get_empty()) if @length is zero.
  *
- * Return value: New blob, or %NULL if failed.  Destroy with hb_blob_destroy().
+ * Return value: New blob, or `NULL` if failed.  Destroy with hb_blob_destroy().
  *
  * Since: 2.8.2
  **/
@@ -263,8 +263,6 @@ hb_blob_destroy (hb_blob_t *blob)
 {
   if (!hb_object_destroy (blob)) return;
 
-  blob->fini_shallow ();
-
   hb_free (blob);
 }
 
@@ -278,7 +276,7 @@ hb_blob_destroy (hb_blob_t *blob)
  *
  * Attaches a user-data key/data pair to the specified blob.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -305,7 +303,7 @@ hb_blob_set_user_data (hb_blob_t          *blob,
  * Since: 0.9.2
  **/
 void *
-hb_blob_get_user_data (hb_blob_t          *blob,
+hb_blob_get_user_data (const hb_blob_t    *blob,
                       hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (blob, key);
@@ -335,7 +333,7 @@ hb_blob_make_immutable (hb_blob_t *blob)
  *
  * Tests whether a blob is immutable.
  *
- * Return value: %true if @blob is immutable, %false otherwise
+ * Return value: `true` if @blob is immutable, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -369,7 +367,7 @@ hb_blob_get_length (hb_blob_t *blob)
  *
  * Fetches the data from a blob.
  *
- * Returns: (transfer none) (array length=length): the byte data of @blob.
+ * Returns: (nullable) (transfer none) (array length=length): the byte data of @blob.
  *
  * Since: 0.9.2
  **/
@@ -394,7 +392,7 @@ hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
  * fails.
  *
  * Returns: (transfer none) (array length=length): Writable blob data,
- * or %NULL if failed.
+ * or `NULL` if failed.
  *
  * Since: 0.9.2
  **/
@@ -497,7 +495,7 @@ hb_blob_t::try_make_writable ()
 
   DEBUG_MSG_FUNC (BLOB, this, "dupped successfully -> %p\n", this->data);
 
-  memcpy (new_data, this->data, this->length);
+  hb_memcpy (new_data, this->data, this->length);
   this->destroy_user_data ();
   this->mode = HB_MEMORY_MODE_WRITABLE;
   this->data = new_data;
@@ -572,7 +570,7 @@ _open_resource_fork (const char *file_name, hb_mapped_file_t *file)
 
   strncpy (rsrc_name, file_name, name_len);
   strncpy (rsrc_name + name_len, _PATH_RSRCFORKSPEC,
-          sizeof (_PATH_RSRCFORKSPEC) - 1);
+          sizeof (_PATH_RSRCFORKSPEC));
 
   int fd = open (rsrc_name, O_RDONLY | O_BINARY, 0);
   hb_free (rsrc_name);
@@ -620,7 +618,7 @@ hb_blob_create_from_file (const char *file_name)
  * specified binary font file.
  *
  * Returns: An #hb_blob_t pointer with the content of the file,
- * or %NULL if failed.
+ * or `NULL` if failed.
  *
  * Since: 2.8.2
  **/
@@ -631,7 +629,7 @@ hb_blob_create_from_file_or_fail (const char *file_name)
      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 *) hb_calloc (1, sizeof (hb_mapped_file_t));
-  if (unlikely (!file)) return hb_blob_get_empty ();
+  if (unlikely (!file)) return nullptr;
 
   int fd = open (file_name, O_RDONLY | O_BINARY, 0);
   if (unlikely (fd == -1)) goto fail_without_close;
@@ -671,14 +669,14 @@ fail_without_close:
 
 #elif defined(_WIN32) && !defined(HB_NO_MMAP)
   hb_mapped_file_t *file = (hb_mapped_file_t *) hb_calloc (1, sizeof (hb_mapped_file_t));
-  if (unlikely (!file)) return hb_blob_get_empty ();
+  if (unlikely (!file)) return nullptr;
 
   HANDLE fd;
   unsigned int size = strlen (file_name) + 1;
   wchar_t * wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size);
   if (unlikely (!wchar_file_name)) goto fail_without_close;
   mbstowcs (wchar_file_name, file_name, size);
-#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
   {
     CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 };
     ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
@@ -699,7 +697,7 @@ fail_without_close:
 
   if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
 
-#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
   {
     LARGE_INTEGER length;
     GetFileSizeEx (fd, &length);
@@ -712,7 +710,7 @@ fail_without_close:
 #endif
   if (unlikely (!file->mapping)) goto fail;
 
-#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_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);
index 203f9e1..db50067 100644 (file)
@@ -63,7 +63,7 @@ HB_BEGIN_DECLS
  *   HarfBuzz and doing that just once (no reuse!),
  *
  * - If the font is mmap()ed, it's okay to use
- *   @HB_MEMORY_READONLY_MAY_MAKE_WRITABLE, however, using that mode
+ *   @HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, however, using that mode
  *   correctly is very tricky.  Use @HB_MEMORY_MODE_READONLY instead.
  **/
 typedef enum {
@@ -135,7 +135,7 @@ hb_blob_set_user_data (hb_blob_t          *blob,
 
 
 HB_EXTERN void *
-hb_blob_get_user_data (hb_blob_t          *blob,
+hb_blob_get_user_data (const hb_blob_t    *blob,
                       hb_user_data_key_t *key);
 
 
index a3683a6..b1b3b94 100644 (file)
@@ -38,7 +38,7 @@
 
 struct hb_blob_t
 {
-  void fini_shallow () { destroy_user_data (); }
+  ~hb_blob_t () { destroy_user_data (); }
 
   void destroy_user_data ()
   {
@@ -61,12 +61,12 @@ struct hb_blob_t
   public:
   hb_object_header_t header;
 
-  const char *data;
-  unsigned int length;
-  hb_memory_mode_t mode;
+  const char *data = nullptr;
+  unsigned int length = 0;
+  hb_memory_mode_t mode = (hb_memory_mode_t) 0;
 
-  void *user_data;
-  hb_destroy_func_t destroy;
+  void *user_data = nullptr;
+  hb_destroy_func_t destroy = nullptr;
 };
 
 
index e80cfea..1deaaaf 100644 (file)
 #line 36 "hb-buffer-deserialize-json.hh"
 static const unsigned char _deserialize_json_trans_keys[] = {
        0u, 0u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 
-       48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 
-       9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 
-       120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 
-       9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 
-       34u, 92u, 9u, 125u, 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 
-       9u, 125u, 9u, 93u, 9u, 123u, 0u, 0u, 0
+       48u, 57u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 
+       48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 
+       9u, 125u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 
+       34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 
+       9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, 
+       9u, 125u, 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 
+       9u, 123u, 0u, 0u, 0
 };
 
 static const char _deserialize_json_key_spans[] = {
        0, 115, 26, 21, 2, 1, 50, 49, 
-       10, 117, 117, 117, 1, 50, 49, 10, 
-       117, 117, 1, 1, 50, 49, 117, 117, 
-       2, 1, 50, 49, 10, 117, 117, 1, 
-       50, 49, 10, 117, 117, 1, 50, 49, 
-       59, 117, 59, 117, 117, 1, 50, 49, 
-       117, 85, 115, 0
+       10, 117, 117, 85, 117, 1, 50, 49, 
+       10, 117, 117, 1, 1, 50, 49, 117, 
+       117, 2, 1, 50, 49, 10, 117, 117, 
+       1, 50, 49, 10, 117, 117, 1, 1, 
+       50, 49, 117, 117, 1, 50, 49, 59, 
+       117, 59, 117, 117, 1, 50, 49, 117, 
+       115, 0
 };
 
 static const short _deserialize_json_index_offsets[] = {
        0, 0, 116, 143, 165, 168, 170, 221, 
-       271, 282, 400, 518, 636, 638, 689, 739, 
-       750, 868, 986, 988, 990, 1041, 1091, 1209, 
-       1327, 1330, 1332, 1383, 1433, 1444, 1562, 1680, 
-       1682, 1733, 1783, 1794, 1912, 2030, 2032, 2083, 
-       2133, 2193, 2311, 2371, 2489, 2607, 2609, 2660, 
-       2710, 2828, 2914, 3030
+       271, 282, 400, 518, 604, 722, 724, 775, 
+       825, 836, 954, 1072, 1074, 1076, 1127, 1177, 
+       1295, 1413, 1416, 1418, 1469, 1519, 1530, 1648, 
+       1766, 1768, 1819, 1869, 1880, 1998, 2116, 2118, 
+       2120, 2171, 2221, 2339, 2457, 2459, 2510, 2560, 
+       2620, 2738, 2798, 2916, 3034, 3036, 3087, 3137, 
+       3255, 3371
 };
 
 static const char _deserialize_json_indicies[] = {
@@ -82,28 +85,28 @@ static const char _deserialize_json_indicies[] = {
        3, 3, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 3, 1, 4, 1, 
-       5, 1, 6, 7, 1, 1, 8, 1, 
+       5, 1, 6, 7, 1, 8, 9, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 9, 1, 10, 11
-       1, 12, 1, 12, 12, 12, 12, 12
+       1, 1, 1, 1, 10, 1, 11, 12
+       1, 13, 1, 13, 13, 13, 13, 13
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 12, 1, 1, 1, 1, 1, 
+       1, 1, 13, 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, 13, 1, 13, 13
-       13, 13, 13, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 14, 1, 14, 14
+       14, 14, 14, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 13, 1, 1, 
+       1, 1, 1, 1, 1, 14, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 14, 1, 1, 15, 16, 16
-       16, 16, 16, 16, 16, 16, 16, 1, 
-       17, 18, 18, 18, 18, 18, 18, 18
-       18, 18, 1, 19, 19, 19, 19, 19
+       1, 1, 15, 1, 1, 16, 17, 17
+       17, 17, 17, 17, 17, 17, 17, 1, 
+       18, 19, 19, 19, 19, 19, 19, 19
+       19, 19, 1, 20, 20, 20, 20, 20
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 19, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 20, 1, 
+       1, 1, 20, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 21, 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, 
@@ -113,11 +116,11 @@ static const char _deserialize_json_indicies[] = {
        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, 1, 1, 1, 1, 21
-       1, 22, 22, 22, 22, 22, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 22
+       1, 23, 23, 23, 23, 23, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       22, 1, 1, 1, 1, 1, 1, 1, 
+       23, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 3, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
@@ -128,85 +131,94 @@ static const char _deserialize_json_indicies[] = {
        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, 1, 1, 23, 1, 19
-       19, 19, 19, 19, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 24, 1, 25
+       25, 25, 25, 25, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 19, 1, 
+       1, 1, 1, 1, 1, 1, 25, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 20, 1, 1, 1, 18, 18, 
-       18, 18, 18, 18, 18, 18, 18, 18, 
+       1, 1, 26, 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, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 27, 1, 20, 20, 20, 
+       20, 20, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 20, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       21, 1, 1, 1, 19, 19, 19, 19, 
+       19, 19, 19, 19, 19, 19, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 21, 1, 24, 1, 24, 
-       24, 24, 24, 24, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 24, 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, 
-       25, 1, 25, 25, 25, 25, 25, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 25, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 26, 1, 
-       1, 27, 28, 28, 28, 28, 28, 28, 
-       28, 28, 28, 1, 29, 30, 30, 30, 
-       30, 30, 30, 30, 30, 30, 1, 31, 
-       31, 31, 31, 31, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 31, 1, 
+       1, 22, 1, 28, 1, 28, 28, 28, 
+       28, 28, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 32, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 28, 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, 29, 1, 
+       29, 29, 29, 29, 29, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 29, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 30, 1, 1, 31, 
+       32, 32, 32, 32, 32, 32, 32, 32, 
+       32, 1, 33, 34, 34, 34, 34, 34, 
+       34, 34, 34, 34, 1, 35, 35, 35, 
+       35, 35, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 35, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       36, 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, 1, 1, 1, 1, 
-       1, 1, 1, 33, 1, 31, 31, 31, 
-       31, 31, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 31, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       32, 1, 1, 1, 30, 30, 30, 30, 
-       30, 30, 30, 30, 30, 30, 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, 1, 1, 1, 1, 1, 1, 1, 
+       1, 37, 1, 35, 35, 35, 35, 35, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 35, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 36, 1, 
+       1, 1, 34, 34, 34, 34, 34, 34, 
+       34, 34, 34, 34, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 33, 1, 34, 1, 35, 1, 35, 
-       35, 35, 35, 35, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 35, 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, 
-       36, 1, 36, 36, 36, 36, 36, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 37, 
+       1, 38, 1, 39, 1, 39, 39, 39, 
+       39, 39, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 36, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 39, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 37, 38, 38, 38, 38, 38, 38, 
-       38, 38, 38, 1, 39, 39, 39, 39, 
-       39, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 39, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 40, 1, 
+       40, 40, 40, 40, 40, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 40, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 41, 
+       42, 42, 42, 42, 42, 42, 42, 42, 
+       42, 1, 43, 43, 43, 43, 43, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 43, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 44, 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, 
@@ -215,43 +227,42 @@ static const char _deserialize_json_indicies[] = {
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       41, 1, 39, 39, 39, 39, 39, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 45, 1, 
+       43, 43, 43, 43, 43, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 39, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 40, 1, 1, 
-       1, 42, 42, 42, 42, 42, 42, 42, 
-       42, 42, 42, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 43, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 44, 1, 1, 1, 46, 
+       46, 46, 46, 46, 46, 46, 46, 46, 
+       46, 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, 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, 1, 
-       1, 1, 1, 1, 1, 1, 41, 1, 
-       43, 44, 1, 45, 1, 45, 45, 45, 
-       45, 45, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 45, 1, 1, 1, 
+       1, 1, 1, 1, 45, 1, 47, 48, 
+       1, 49, 1, 49, 49, 49, 49, 49, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 46, 1, 
-       46, 46, 46, 46, 46, 1, 1, 1, 
+       1, 1, 49, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 46, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 47, 1, 1, 48, 
-       49, 49, 49, 49, 49, 49, 49, 49, 
-       49, 1, 50, 51, 51, 51, 51, 51, 
-       51, 51, 51, 51, 1, 52, 52, 52, 
-       52, 52, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 50, 1, 50, 50, 
+       50, 50, 50, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 52, 1, 1, 1, 
+       1, 1, 1, 1, 1, 50, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       53, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 51, 1, 1, 52, 53, 53, 
+       53, 53, 53, 53, 53, 53, 53, 1, 
+       54, 55, 55, 55, 55, 55, 55, 55, 
+       55, 55, 1, 56, 56, 56, 56, 56, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 56, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 57, 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, 
@@ -259,42 +270,43 @@ static const char _deserialize_json_indicies[] = {
        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, 54, 1, 52, 52, 52, 52, 52, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 52, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 53, 1, 
-       1, 1, 51, 51, 51, 51, 51, 51, 
-       51, 51, 51, 51, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 58, 
+       1, 56, 56, 56, 56, 56, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       56, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 57, 1, 1, 1, 
+       55, 55, 55, 55, 55, 55, 55, 55, 
+       55, 55, 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, 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, 54, 
-       1, 55, 1, 55, 55, 55, 55, 55, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 55, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 58, 1, 59, 
+       1, 59, 59, 59, 59, 59, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 56, 1, 56, 56, 
-       56, 56, 56, 1, 1, 1, 1, 1, 
+       59, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 56, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 57, 1, 1, 58, 59, 59, 
-       59, 59, 59, 59, 59, 59, 59, 1, 
-       60, 61, 61, 61, 61, 61, 61, 61, 
-       61, 61, 1, 62, 62, 62, 62, 62, 
+       1, 1, 60, 1, 60, 60, 60, 60, 
+       60, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 60, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 62, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 63, 1, 
+       61, 1, 1, 62, 63, 63, 63, 63, 
+       63, 63, 63, 63, 63, 1, 64, 65, 
+       65, 65, 65, 65, 65, 65, 65, 65, 
+       1, 66, 66, 66, 66, 66, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       66, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 67, 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, 
@@ -302,48 +314,42 @@ static const char _deserialize_json_indicies[] = {
        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, 1, 1, 1, 1, 64, 
-       1, 62, 62, 62, 62, 62, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       62, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 63, 1, 1, 1, 
-       61, 61, 61, 61, 61, 61, 61, 61, 
-       61, 61, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 68, 1, 66, 
+       66, 66, 66, 66, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 66, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 67, 1, 1, 1, 65, 65, 
+       65, 65, 65, 65, 65, 65, 65, 65, 
        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, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 64, 1, 65, 
-       1, 65, 65, 65, 65, 65, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       65, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 68, 1, 69, 1, 70, 
+       1, 70, 70, 70, 70, 70, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       70, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 66, 1, 66, 66, 66, 66, 
-       66, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 66, 1, 67, 1, 1, 
+       1, 1, 71, 1, 71, 71, 71, 71, 
+       71, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 68, 69, 69, 69, 69, 
-       69, 69, 69, 69, 69, 1, 71, 70, 
-       70, 70, 70, 70, 70, 70, 70, 70, 
-       70, 70, 70, 70, 70, 70, 70, 70, 
-       70, 70, 70, 70, 70, 70, 70, 70, 
-       70, 70, 70, 70, 70, 70, 70, 70, 
-       70, 70, 70, 70, 70, 70, 70, 70, 
-       70, 70, 70, 70, 70, 70, 70, 70, 
-       70, 70, 70, 70, 70, 70, 70, 70, 
-       72, 70, 73, 73, 73, 73, 73, 1, 
+       1, 1, 1, 71, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 72, 73, 73, 73, 73, 
+       73, 73, 73, 73, 73, 1, 74, 74, 
+       74, 74, 74, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 73, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 74, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 75, 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, 1, 1, 1, 
@@ -352,86 +358,126 @@ static const char _deserialize_json_indicies[] = {
        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, 1, 1, 1, 75, 1, 
-       70, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 76, 1, 74, 74, 74, 74, 
+       74, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 74, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 75, 
+       1, 1, 1, 77, 77, 77, 77, 77, 
+       77, 77, 77, 77, 77, 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, 
+       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, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       76, 1, 78, 1, 78, 78, 78, 78, 
+       78, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 78, 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, 79, 1, 79, 
+       79, 79, 79, 79, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 79, 1, 
+       80, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 81, 82, 
+       82, 82, 82, 82, 82, 82, 82, 82, 
+       1, 84, 83, 83, 83, 83, 83, 83, 
+       83, 83, 83, 83, 83, 83, 83, 83, 
+       83, 83, 83, 83, 83, 83, 83, 83, 
+       83, 83, 83, 83, 83, 83, 83, 83, 
+       83, 83, 83, 83, 83, 83, 83, 83, 
+       83, 83, 83, 83, 83, 83, 83, 83, 
+       83, 83, 83, 83, 83, 83, 83, 83, 
+       83, 83, 83, 85, 83, 86, 86, 86, 
+       86, 86, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 86, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       87, 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, 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, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 70, 1, 76, 76, 76, 76, 
-       76, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 76, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 77, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 88, 1, 83, 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, 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, 1, 1, 1, 83, 1, 89, 
+       89, 89, 89, 89, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 89, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 90, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       78, 1, 76, 76, 76, 76, 76, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 76, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 77, 1, 1, 
-       1, 79, 79, 79, 79, 79, 79, 79, 
-       79, 79, 79, 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, 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, 1, 1, 91, 1, 89, 89, 89, 
+       89, 89, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 78, 1, 
-       80, 1, 80, 80, 80, 80, 80, 1, 
+       1, 1, 1, 1, 89, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       90, 1, 1, 1, 92, 92, 92, 92, 
+       92, 92, 92, 92, 92, 92, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 80, 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, 81, 1, 81, 81, 81, 
-       81, 81, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 81, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 82, 83, 83, 83, 
-       83, 83, 83, 83, 83, 83, 1, 76, 
-       76, 76, 76, 76, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 76, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 77, 1, 1, 1, 84, 84, 
-       84, 84, 84, 84, 84, 84, 84, 84, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 91, 1, 93, 1, 93, 93, 93, 
+       93, 93, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 93, 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, 94, 1, 
+       94, 94, 94, 94, 94, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 94, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 95, 
+       96, 96, 96, 96, 96, 96, 96, 96, 
+       96, 1, 89, 89, 89, 89, 89, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 78, 1, 85, 85, 85, 
-       85, 85, 1, 1, 1, 1, 1, 1, 
+       1, 89, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 90, 1, 1, 
+       1, 97, 97, 97, 97, 97, 97, 97, 
+       97, 97, 97, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 85, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       86, 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, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 87, 1, 0, 0, 0, 0, 0, 
+       1, 1, 1, 1, 1, 1, 91, 1, 
+       0, 0, 0, 0, 0, 1, 1, 1, 
        1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 0, 
        1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 0, 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, 1, 1, 
@@ -442,46 +488,49 @@ static const char _deserialize_json_indicies[] = {
        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, 1, 1, 2, 1, 1, 
-       0
+       1, 1, 2, 1, 1, 0
 };
 
 static const char _deserialize_json_trans_targs[] = {
-       1, 0, 2, 2, 3, 4, 18, 24, 
-       37, 45, 5, 12, 6, 7, 8, 9, 
-       11, 9, 11, 10, 2, 49, 10, 49, 
-       13, 14, 15, 16, 17, 16, 17, 10, 
-       2, 49, 19, 20, 21, 22, 23, 10, 
-       2, 49, 23, 25, 31, 26, 27, 28, 
-       29, 30, 29, 30, 10, 2, 49, 32, 
-       33, 34, 35, 36, 35, 36, 10, 2, 
-       49, 38, 39, 40, 43, 44, 40, 41, 
-       42, 10, 2, 49, 10, 2, 49, 44, 
-       46, 47, 43, 48, 48, 49, 50, 51
+       1, 0, 2, 2, 3, 4, 19, 25, 
+       38, 44, 52, 5, 13, 6, 7, 8, 
+       9, 12, 9, 12, 10, 2, 11, 10, 
+       11, 11, 56, 57, 14, 15, 16, 17, 
+       18, 17, 18, 10, 2, 11, 20, 21, 
+       22, 23, 24, 10, 2, 11, 24, 26, 
+       32, 27, 28, 29, 30, 31, 30, 31, 
+       10, 2, 11, 33, 34, 35, 36, 37, 
+       36, 37, 10, 2, 11, 39, 40, 41, 
+       42, 43, 10, 2, 11, 43, 45, 46, 
+       47, 50, 51, 47, 48, 49, 10, 2, 
+       11, 10, 2, 11, 51, 53, 54, 50, 
+       55, 55
 };
 
 static const char _deserialize_json_trans_actions[] = {
        0, 0, 1, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 2, 2, 
-       2, 0, 0, 3, 3, 4, 0, 5, 
-       0, 0, 2, 2, 2, 0, 0, 6, 
-       6, 7, 0, 0, 0, 2, 2, 8, 
-       8, 9, 0, 0, 0, 0, 0, 2, 
-       2, 2, 0, 0, 10, 10, 11, 0, 
-       0, 2, 2, 2, 0, 0, 12, 12, 
-       13, 0, 0, 2, 14, 14, 0, 15, 
-       0, 16, 16, 17, 18, 18, 19, 15, 
-       0, 0, 20, 20, 21, 0, 0, 0
+       0, 0, 0, 0, 0, 0, 0, 2, 
+       2, 2, 0, 0, 3, 3, 4, 0, 
+       5, 0, 0, 0, 0, 0, 2, 2, 
+       2, 0, 0, 6, 6, 7, 0, 0, 
+       0, 2, 2, 8, 8, 9, 0, 0, 
+       0, 0, 0, 2, 2, 2, 0, 0, 
+       10, 10, 11, 0, 0, 2, 2, 2, 
+       0, 0, 12, 12, 13, 0, 0, 0, 
+       2, 2, 14, 14, 15, 0, 0, 0, 
+       2, 16, 16, 0, 17, 0, 18, 18, 
+       19, 20, 20, 21, 17, 0, 0, 22, 
+       22, 23
 };
 
 static const int deserialize_json_start = 1;
-static const int deserialize_json_first_final = 49;
+static const int deserialize_json_first_final = 56;
 static const int deserialize_json_error = 0;
 
 static const int deserialize_json_en_main = 1;
 
 
-#line 108 "hb-buffer-deserialize-json.rl"
+#line 111 "hb-buffer-deserialize-json.rl"
 
 
 static hb_bool_t
@@ -499,21 +548,19 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer,
   while (p < pe && ISSPACE (*p))
     p++;
   if (p < pe && *p == (buffer->len ? ',' : '['))
-  {
     *end_ptr = ++p;
-  }
 
   const char *tok = nullptr;
   int cs;
   hb_glyph_info_t info = {0};
   hb_glyph_position_t pos = {0};
   
-#line 512 "hb-buffer-deserialize-json.hh"
+#line 559 "hb-buffer-deserialize-json.hh"
        {
        cs = deserialize_json_start;
        }
 
-#line 517 "hb-buffer-deserialize-json.hh"
+#line 564 "hb-buffer-deserialize-json.hh"
        {
        int _slen;
        int _trans;
@@ -541,8 +588,8 @@ _resume:
        case 1:
 #line 38 "hb-buffer-deserialize-json.rl"
        {
-       memset (&info, 0, sizeof (info));
-       memset (&pos , 0, sizeof (pos ));
+       hb_memset (&info, 0, sizeof (info));
+       hb_memset (&pos , 0, sizeof (pos ));
 }
        break;
        case 5:
@@ -561,25 +608,25 @@ _resume:
        tok = p;
 }
        break;
-       case 15:
+       case 17:
 #line 55 "hb-buffer-deserialize-json.rl"
        { if (unlikely (!buffer->ensure_glyphs ())) return false; }
        break;
-       case 21:
+       case 23:
 #line 56 "hb-buffer-deserialize-json.rl"
        { if (unlikely (!buffer->ensure_unicode ())) return false; }
        break;
-       case 16:
+       case 18:
 #line 58 "hb-buffer-deserialize-json.rl"
        {
        /* TODO Unescape \" and \\ if found. */
        if (!hb_font_glyph_from_string (font,
-                                       tok, p - tok,
+                                       tok+1, p - tok - 2, /* Skip "" */
                                        &info.codepoint))
          return false;
 }
        break;
-       case 18:
+       case 20:
 #line 66 "hb-buffer-deserialize-json.rl"
        { if (!parse_uint (tok, p, &info.codepoint)) return false; }
        break;
@@ -604,6 +651,10 @@ _resume:
        { if (!parse_int  (tok, p, &pos.y_advance)) return false; }
        break;
        case 14:
+#line 72 "hb-buffer-deserialize-json.rl"
+       { if (!parse_uint (tok, p, &info.mask    )) return false; }
+       break;
+       case 16:
 #line 51 "hb-buffer-deserialize-json.rl"
        {
        tok = p;
@@ -611,7 +662,7 @@ _resume:
 #line 55 "hb-buffer-deserialize-json.rl"
        { if (unlikely (!buffer->ensure_glyphs ())) return false; }
        break;
-       case 20:
+       case 22:
 #line 51 "hb-buffer-deserialize-json.rl"
        {
        tok = p;
@@ -619,12 +670,12 @@ _resume:
 #line 56 "hb-buffer-deserialize-json.rl"
        { if (unlikely (!buffer->ensure_unicode ())) return false; }
        break;
-       case 17:
+       case 19:
 #line 58 "hb-buffer-deserialize-json.rl"
        {
        /* TODO Unescape \" and \\ if found. */
        if (!hb_font_glyph_from_string (font,
-                                       tok, p - tok,
+                                       tok+1, p - tok - 2, /* Skip "" */
                                        &info.codepoint))
          return false;
 }
@@ -637,7 +688,7 @@ _resume:
        *end_ptr = p;
 }
        break;
-       case 19:
+       case 21:
 #line 66 "hb-buffer-deserialize-json.rl"
        { if (!parse_uint (tok, p, &info.codepoint)) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
@@ -709,7 +760,19 @@ _resume:
        *end_ptr = p;
 }
        break;
-#line 713 "hb-buffer-deserialize-json.hh"
+       case 15:
+#line 72 "hb-buffer-deserialize-json.rl"
+       { if (!parse_uint (tok, p, &info.mask    )) return false; }
+#line 43 "hb-buffer-deserialize-json.rl"
+       {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+       break;
+#line 776 "hb-buffer-deserialize-json.hh"
        }
 
 _again:
@@ -721,7 +784,7 @@ _again:
        _out: {}
        }
 
-#line 136 "hb-buffer-deserialize-json.rl"
+#line 137 "hb-buffer-deserialize-json.rl"
 
 
   *end_ptr = p;
index 382423f..b12dd0f 100644 (file)
@@ -36,8 +36,8 @@ alphtype unsigned char;
 write data;
 
 action clear_item {
-       memset (&info, 0, sizeof (info));
-       memset (&pos , 0, sizeof (pos ));
+       hb_memset (&info, 0, sizeof (info));
+       hb_memset (&pos , 0, sizeof (pos ));
 }
 
 action add_item {
@@ -58,17 +58,18 @@ action ensure_unicode { if (unlikely (!buffer->ensure_unicode ())) return false;
 action parse_glyph_name {
        /* TODO Unescape \" and \\ if found. */
        if (!hb_font_glyph_from_string (font,
-                                       tok, p - tok,
+                                       tok+1, p - tok - 2, /* Skip "" */
                                        &info.codepoint))
          return false;
 }
 
-action parse_codepoint { if (!parse_uint (tok, p, &info.codepoint)) return false; }
-action parse_cluster   { if (!parse_uint (tok, p, &info.cluster )) return false; }
-action parse_x_offset  { if (!parse_int  (tok, p, &pos.x_offset )) return false; }
-action parse_y_offset  { if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-action parse_x_advance { if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-action parse_y_advance { if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+action parse_codepoint { if (!parse_uint (tok, p, &info.codepoint)) return false; }
+action parse_cluster   { if (!parse_uint (tok, p, &info.cluster )) return false; }
+action parse_x_offset  { if (!parse_int  (tok, p, &pos.x_offset )) return false; }
+action parse_y_offset  { if (!parse_int  (tok, p, &pos.y_offset )) return false; }
+action parse_x_advance { if (!parse_int  (tok, p, &pos.x_advance)) return false; }
+action parse_y_advance { if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+action parse_glyph_flags{ if (!parse_uint (tok, p, &info.mask    )) return false; }
 
 unum   = '0' | [1-9] digit*;
 num    = '-'? unum;
@@ -82,13 +83,14 @@ glyph_name = '"' ([^\\"] | '\\' [\\"])* '"';
 parse_glyph_name   = (glyph_name >tok %parse_glyph_name);
 parse_codepoint = (codepoint >tok %parse_codepoint);
 
-glyph  = "\"g\""  colon (parse_glyph_name | parse_codepoint);
-unicode        = "\"u\""  colon parse_codepoint;
-cluster        = "\"cl\"" colon (unum >tok %parse_cluster);
-xoffset        = "\"dx\"" colon (num >tok %parse_x_offset);
-yoffset        = "\"dy\"" colon (num >tok %parse_y_offset);
-xadvance= "\"ax\"" colon (num >tok %parse_x_advance);
-yadvance= "\"ay\"" colon (num >tok %parse_y_advance);
+glyph  =  "\"g\""  colon (parse_glyph_name | parse_codepoint);
+unicode        =  "\"u\""  colon parse_codepoint;
+cluster        =  "\"cl\"" colon (unum >tok %parse_cluster);
+xoffset        =  "\"dx\"" colon (num  >tok %parse_x_offset);
+yoffset        =  "\"dy\"" colon (num  >tok %parse_y_offset);
+xadvance=  "\"ax\"" colon (num  >tok %parse_x_advance);
+yadvance=  "\"ay\"" colon (num  >tok %parse_y_advance);
+glyphflags="\"fl\"" colon (unum >tok %parse_glyph_flags);
 
 element = glyph @ensure_glyphs
        | unicode @ensure_unicode
@@ -96,14 +98,15 @@ element = glyph @ensure_glyphs
        | xoffset
        | yoffset
        | xadvance
-       | yadvance;
+       | yadvance
+       | glyphflags;
 item   =
        ( '{' space* element (comma element)* space* '}')
        >clear_item
        @add_item
        ;
 
-main := space* item (comma item)* space* (','|']')?;
+main := space* item (comma item)* space* (','|']');
 
 }%%
 
@@ -122,9 +125,7 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer,
   while (p < pe && ISSPACE (*p))
     p++;
   if (p < pe && *p == (buffer->len ? ',' : '['))
-  {
     *end_ptr = ++p;
-  }
 
   const char *tok = nullptr;
   int cs;
diff --git a/src/hb-buffer-deserialize-text-glyphs.hh b/src/hb-buffer-deserialize-text-glyphs.hh
new file mode 100644 (file)
index 0000000..ea81273
--- /dev/null
@@ -0,0 +1,692 @@
+
+#line 1 "hb-buffer-deserialize-text-glyphs.rl"
+/*
+ * Copyright © 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.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH
+#define HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH
+
+#include "hb.hh"
+
+
+#line 36 "hb-buffer-deserialize-text-glyphs.hh"
+static const unsigned char _deserialize_text_glyphs_trans_keys[] = {
+       0u, 0u, 48u, 57u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, 
+       48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 43u, 124u, 9u, 124u, 9u, 124u, 
+       9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 
+       9u, 124u, 9u, 124u, 9u, 124u, 0
+};
+
+static const char _deserialize_text_glyphs_key_spans[] = {
+       0, 10, 13, 10, 13, 10, 10, 13, 
+       10, 1, 13, 10, 14, 82, 116, 116, 
+       116, 116, 116, 116, 116, 116, 116, 116, 
+       116, 116, 116
+};
+
+static const short _deserialize_text_glyphs_index_offsets[] = {
+       0, 0, 11, 25, 36, 50, 61, 72, 
+       86, 97, 99, 113, 124, 139, 222, 339, 
+       456, 573, 690, 807, 924, 1041, 1158, 1275, 
+       1392, 1509, 1626
+};
+
+static const char _deserialize_text_glyphs_indicies[] = {
+       0, 2, 2, 2, 2, 2, 2, 
+       2, 2, 2, 1, 3, 1, 1, 4, 
+       5, 5, 5, 5, 5, 5, 5, 5, 
+       5, 1, 6, 7, 7, 7, 7, 7, 
+       7, 7, 7, 7, 1, 8, 1, 1, 
+       9, 10, 10, 10, 10, 10, 10, 10, 
+       10, 10, 1, 11, 12, 12, 12, 12, 
+       12, 12, 12, 12, 12, 1, 13, 14, 
+       14, 14, 14, 14, 14, 14, 14, 14, 
+       1, 15, 1, 1, 16, 17, 17, 17, 
+       17, 17, 17, 17, 17, 17, 1, 18, 
+       19, 19, 19, 19, 19, 19, 19, 19, 
+       19, 1, 20, 1, 21, 1, 1, 22, 
+       23, 23, 23, 23, 23, 23, 23, 23, 
+       23, 1, 24, 25, 25, 25, 25, 25, 
+       25, 25, 25, 25, 1, 20, 1, 1, 
+       1, 19, 19, 19, 19, 19, 19, 19, 
+       19, 19, 19, 1, 26, 26, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 26, 1, 
+       1, 26, 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, 26, 26, 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, 1, 1, 1, 26, 1, 28, 
+       28, 28, 28, 28, 27, 27, 27, 27, 
+       27, 27, 27, 27, 27, 27, 27, 27, 
+       27, 27, 27, 27, 27, 27, 28, 27, 
+       27, 29, 27, 27, 27, 27, 27, 27, 
+       27, 30, 1, 27, 27, 27, 27, 27, 
+       27, 27, 27, 27, 27, 27, 27, 27, 
+       27, 27, 27, 31, 27, 27, 32, 27, 
+       27, 27, 27, 27, 27, 27, 27, 27, 
+       27, 27, 27, 27, 27, 27, 27, 27, 
+       27, 27, 27, 27, 27, 27, 27, 27, 
+       27, 27, 33, 1, 27, 27, 27, 27, 
+       27, 27, 27, 27, 27, 27, 27, 27, 
+       27, 27, 27, 27, 27, 27, 27, 27, 
+       27, 27, 27, 27, 27, 27, 27, 27, 
+       27, 27, 28, 27, 34, 34, 34, 34, 
+       34, 26, 26, 26, 26, 26, 26, 26, 
+       26, 26, 26, 26, 26, 26, 26, 26, 
+       26, 26, 26, 34, 26, 26, 35, 26, 
+       26, 26, 26, 26, 26, 26, 36, 1, 
+       26, 26, 26, 26, 26, 26, 26, 26, 
+       26, 26, 26, 26, 26, 26, 26, 26, 
+       37, 26, 26, 38, 26, 26, 26, 26, 
+       26, 26, 26, 26, 26, 26, 26, 26, 
+       26, 26, 26, 26, 26, 26, 26, 26, 
+       26, 26, 26, 26, 26, 26, 26, 39, 
+       1, 26, 26, 26, 26, 26, 26, 26, 
+       26, 26, 26, 26, 26, 26, 26, 26, 
+       26, 26, 26, 26, 26, 26, 26, 26, 
+       26, 26, 26, 26, 26, 26, 26, 40, 
+       26, 41, 41, 41, 41, 41, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       41, 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, 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, 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, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 42, 1, 43, 43, 
+       43, 43, 43, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 43, 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, 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, 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, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 44, 1, 41, 41, 41, 41, 41, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 41, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 45, 45, 45, 45, 45, 45, 
+       45, 45, 45, 45, 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, 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, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 42, 1, 
+       46, 46, 46, 46, 46, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 46, 
+       1, 1, 47, 1, 1, 1, 1, 1, 
+       1, 1, 1, 48, 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, 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, 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, 49, 1, 50, 50, 50, 
+       50, 50, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 50, 1, 1, 51, 
+       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, 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, 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, 1, 1, 1, 1, 1, 1, 1, 
+       52, 1, 50, 50, 50, 50, 50, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 50, 1, 1, 51, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 12, 12, 12, 12, 12, 12, 12, 
+       12, 12, 12, 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, 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, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 52, 1, 46, 
+       46, 46, 46, 46, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 46, 1, 
+       1, 47, 1, 1, 1, 1, 1, 1, 
+       1, 1, 48, 1, 1, 1, 7, 7, 
+       7, 7, 7, 7, 7, 7, 7, 7, 
+       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, 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, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 49, 1, 53, 53, 53, 53, 
+       53, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 53, 1, 1, 54, 1, 
+       1, 1, 1, 1, 1, 1, 55, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 56, 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, 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, 1, 1, 1, 1, 1, 57, 
+       1, 58, 58, 58, 58, 58, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       58, 1, 1, 59, 1, 1, 1, 1, 
+       1, 1, 1, 60, 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, 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, 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, 61, 1, 58, 58, 
+       58, 58, 58, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 58, 1, 1, 
+       59, 1, 1, 1, 1, 1, 1, 1, 
+       60, 1, 1, 1, 1, 25, 25, 25, 
+       25, 25, 25, 25, 25, 25, 25, 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, 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, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 61, 1, 53, 53, 53, 53, 53, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 53, 1, 1, 54, 1, 1, 
+       1, 1, 1, 1, 1, 55, 1, 1, 
+       1, 1, 62, 62, 62, 62, 62, 62, 
+       62, 62, 62, 62, 1, 1, 1, 1, 
+       1, 1, 56, 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, 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, 1, 1, 1, 1, 1, 57, 1, 
+       0
+};
+
+static const char _deserialize_text_glyphs_trans_targs[] = {
+       16, 0, 18, 3, 19, 22, 19, 22, 
+       5, 20, 21, 20, 21, 23, 26, 8, 
+       9, 12, 9, 12, 10, 11, 24, 25, 
+       24, 25, 15, 15, 14, 1, 2, 6, 
+       7, 13, 15, 1, 2, 6, 7, 13, 
+       14, 17, 14, 17, 14, 18, 17, 1, 
+       4, 14, 17, 1, 14, 17, 1, 2, 
+       7, 14, 17, 1, 2, 14, 26
+};
+
+static const char _deserialize_text_glyphs_trans_actions[] = {
+       1, 0, 1, 1, 1, 1, 0, 0, 
+       1, 1, 1, 0, 0, 1, 1, 1, 
+       1, 1, 0, 0, 2, 1, 1, 1, 
+       0, 0, 0, 4, 3, 5, 5, 5, 
+       5, 4, 6, 7, 7, 7, 7, 0, 
+       6, 8, 8, 0, 0, 0, 9, 10, 
+       10, 9, 11, 12, 11, 13, 14, 14, 
+       14, 13, 15, 16, 16, 15, 0
+};
+
+static const char _deserialize_text_glyphs_eof_actions[] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 3, 6, 
+       8, 0, 8, 9, 11, 11, 9, 13, 
+       15, 15, 13
+};
+
+static const int deserialize_text_glyphs_start = 14;
+static const int deserialize_text_glyphs_first_final = 14;
+static const int deserialize_text_glyphs_error = 0;
+
+static const int deserialize_text_glyphs_en_main = 14;
+
+
+#line 98 "hb-buffer-deserialize-text-glyphs.rl"
+
+
+static hb_bool_t
+_hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer,
+                                   const char *buf,
+                                   unsigned int buf_len,
+                                   const char **end_ptr,
+                                   hb_font_t *font)
+{
+  const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
+
+  /* Ensure we have positions. */
+  (void) hb_buffer_get_glyph_positions (buffer, nullptr);
+
+  while (p < pe && ISSPACE (*p))
+    p++;
+  if (p < pe && *p == (buffer->len ? '|' : '['))
+    *end_ptr = ++p;
+
+  const char *end = strchr ((char *) p, ']');
+  if (end)
+    pe = eof = end;
+  else
+  {
+    end = strrchr ((char *) p, '|');
+    if (end)
+      pe = eof = end;
+    else
+      pe = eof = p;
+  }
+
+  const char *tok = nullptr;
+  int cs;
+  hb_glyph_info_t info = {0};
+  hb_glyph_position_t pos = {0};
+  
+#line 353 "hb-buffer-deserialize-text-glyphs.hh"
+       {
+       cs = deserialize_text_glyphs_start;
+       }
+
+#line 358 "hb-buffer-deserialize-text-glyphs.hh"
+       {
+       int _slen;
+       int _trans;
+       const unsigned char *_keys;
+       const char *_inds;
+       if ( p == pe )
+               goto _test_eof;
+       if ( cs == 0 )
+               goto _out;
+_resume:
+       _keys = _deserialize_text_glyphs_trans_keys + (cs<<1);
+       _inds = _deserialize_text_glyphs_indicies + _deserialize_text_glyphs_index_offsets[cs];
+
+       _slen = _deserialize_text_glyphs_key_spans[cs];
+       _trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
+               (*p) <= _keys[1] ?
+               (*p) - _keys[0] : _slen ];
+
+       cs = _deserialize_text_glyphs_trans_targs[_trans];
+
+       if ( _deserialize_text_glyphs_trans_actions[_trans] == 0 )
+               goto _again;
+
+       switch ( _deserialize_text_glyphs_trans_actions[_trans] ) {
+       case 1:
+#line 51 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       tok = p;
+}
+       break;
+       case 7:
+#line 55 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       /* TODO Unescape delimiters. */
+       if (!hb_font_glyph_from_string (font,
+                                       tok, p - tok,
+                                       &info.codepoint))
+         return false;
+}
+       break;
+       case 14:
+#line 63 "hb-buffer-deserialize-text-glyphs.rl"
+       { if (!parse_uint (tok, p, &info.cluster )) return false; }
+       break;
+       case 2:
+#line 64 "hb-buffer-deserialize-text-glyphs.rl"
+       { if (!parse_int  (tok, p, &pos.x_offset )) return false; }
+       break;
+       case 16:
+#line 65 "hb-buffer-deserialize-text-glyphs.rl"
+       { if (!parse_int  (tok, p, &pos.y_offset )) return false; }
+       break;
+       case 10:
+#line 66 "hb-buffer-deserialize-text-glyphs.rl"
+       { if (!parse_int  (tok, p, &pos.x_advance)) return false; }
+       break;
+       case 12:
+#line 67 "hb-buffer-deserialize-text-glyphs.rl"
+       { if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+       break;
+       case 4:
+#line 38 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       hb_memset (&info, 0, sizeof (info));
+       hb_memset (&pos , 0, sizeof (pos ));
+}
+#line 51 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       tok = p;
+}
+       break;
+       case 6:
+#line 55 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       /* TODO Unescape delimiters. */
+       if (!hb_font_glyph_from_string (font,
+                                       tok, p - tok,
+                                       &info.codepoint))
+         return false;
+}
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+       break;
+       case 13:
+#line 63 "hb-buffer-deserialize-text-glyphs.rl"
+       { if (!parse_uint (tok, p, &info.cluster )) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+       break;
+       case 15:
+#line 65 "hb-buffer-deserialize-text-glyphs.rl"
+       { if (!parse_int  (tok, p, &pos.y_offset )) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+       break;
+       case 9:
+#line 66 "hb-buffer-deserialize-text-glyphs.rl"
+       { if (!parse_int  (tok, p, &pos.x_advance)) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+       break;
+       case 11:
+#line 67 "hb-buffer-deserialize-text-glyphs.rl"
+       { if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+       break;
+       case 8:
+#line 68 "hb-buffer-deserialize-text-glyphs.rl"
+       { if (!parse_uint (tok, p, &info.mask    )) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+       break;
+       case 5:
+#line 38 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       hb_memset (&info, 0, sizeof (info));
+       hb_memset (&pos , 0, sizeof (pos ));
+}
+#line 51 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       tok = p;
+}
+#line 55 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       /* TODO Unescape delimiters. */
+       if (!hb_font_glyph_from_string (font,
+                                       tok, p - tok,
+                                       &info.codepoint))
+         return false;
+}
+       break;
+       case 3:
+#line 38 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       hb_memset (&info, 0, sizeof (info));
+       hb_memset (&pos , 0, sizeof (pos ));
+}
+#line 51 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       tok = p;
+}
+#line 55 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       /* TODO Unescape delimiters. */
+       if (!hb_font_glyph_from_string (font,
+                                       tok, p - tok,
+                                       &info.codepoint))
+         return false;
+}
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+       break;
+#line 554 "hb-buffer-deserialize-text-glyphs.hh"
+       }
+
+_again:
+       if ( cs == 0 )
+               goto _out;
+       if ( ++p != pe )
+               goto _resume;
+       _test_eof: {}
+       if ( p == eof )
+       {
+       switch ( _deserialize_text_glyphs_eof_actions[cs] ) {
+       case 6:
+#line 55 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       /* TODO Unescape delimiters. */
+       if (!hb_font_glyph_from_string (font,
+                                       tok, p - tok,
+                                       &info.codepoint))
+         return false;
+}
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+       break;
+       case 13:
+#line 63 "hb-buffer-deserialize-text-glyphs.rl"
+       { if (!parse_uint (tok, p, &info.cluster )) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+       break;
+       case 15:
+#line 65 "hb-buffer-deserialize-text-glyphs.rl"
+       { if (!parse_int  (tok, p, &pos.y_offset )) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+       break;
+       case 9:
+#line 66 "hb-buffer-deserialize-text-glyphs.rl"
+       { if (!parse_int  (tok, p, &pos.x_advance)) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+       break;
+       case 11:
+#line 67 "hb-buffer-deserialize-text-glyphs.rl"
+       { if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+       break;
+       case 8:
+#line 68 "hb-buffer-deserialize-text-glyphs.rl"
+       { if (!parse_uint (tok, p, &info.mask    )) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+       break;
+       case 3:
+#line 38 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       hb_memset (&info, 0, sizeof (info));
+       hb_memset (&pos , 0, sizeof (pos ));
+}
+#line 51 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       tok = p;
+}
+#line 55 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       /* TODO Unescape delimiters. */
+       if (!hb_font_glyph_from_string (font,
+                                       tok, p - tok,
+                                       &info.codepoint))
+         return false;
+}
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+       {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+       break;
+#line 671 "hb-buffer-deserialize-text-glyphs.hh"
+       }
+       }
+
+       _out: {}
+       }
+
+#line 136 "hb-buffer-deserialize-text-glyphs.rl"
+
+
+  if (pe < orig_pe && *pe == ']')
+  {
+    pe++;
+    if (p == pe)
+      p++;
+  }
+
+  *end_ptr = p;
+
+  return p == pe;
+}
+
+#endif /* HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH */
similarity index 62%
rename from src/hb-buffer-deserialize-text.rl
rename to src/hb-buffer-deserialize-text-glyphs.rl
index a217028..21db14b 100644 (file)
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_BUFFER_DESERIALIZE_TEXT_HH
-#define HB_BUFFER_DESERIALIZE_TEXT_HH
+#ifndef HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH
+#define HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH
 
 #include "hb.hh"
 
 %%{
 
-machine deserialize_text;
+machine deserialize_text_glyphs;
 alphtype unsigned char;
 write data;
 
 action clear_item {
-       memset (&info, 0, sizeof (info));
-       memset (&pos , 0, sizeof (pos ));
+       hb_memset (&info, 0, sizeof (info));
+       hb_memset (&pos , 0, sizeof (pos ));
 }
 
 action add_item {
@@ -52,35 +52,32 @@ action tok {
        tok = p;
 }
 
-action ensure_glyphs { if (unlikely (!buffer->ensure_glyphs ())) return false; }
-action ensure_unicode { if (unlikely (!buffer->ensure_unicode ())) return false; }
-
 action parse_glyph {
-       /* TODO Unescape delimeters. */
+       /* TODO Unescape delimiters. */
        if (!hb_font_glyph_from_string (font,
                                        tok, p - tok,
                                        &info.codepoint))
          return false;
 }
 
-action parse_hexdigits  {if (!parse_hex (tok, p, &info.codepoint )) return false; }
-
-action parse_cluster   { if (!parse_uint (tok, p, &info.cluster )) return false; }
-action parse_x_offset  { if (!parse_int  (tok, p, &pos.x_offset )) return false; }
-action parse_y_offset  { if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-action parse_x_advance { if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-action parse_y_advance { if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+action parse_cluster   { if (!parse_uint (tok, p, &info.cluster )) return false; }
+action parse_x_offset  { if (!parse_int  (tok, p, &pos.x_offset )) return false; }
+action parse_y_offset  { if (!parse_int  (tok, p, &pos.y_offset )) return false; }
+action parse_x_advance { if (!parse_int  (tok, p, &pos.x_advance)) return false; }
+action parse_y_advance { if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+action parse_glyph_flags{ if (!parse_uint (tok, p, &info.mask    )) return false; }
 
 unum  = '0' | [1-9] digit*;
 num    = '-'? unum;
 
 glyph_id = unum;
-glyph_name = ([^\\\]=@+,|] | '\\' [\\\]=@+,|]) *;
+glyph_name = ([^\\\]=@+,#|] | '\\' [\\\]=@+,|]) *;
 
 glyph  = (glyph_id | glyph_name) >tok %parse_glyph;
 cluster        = '=' (unum >tok %parse_cluster);
 offsets        = '@' (num >tok %parse_x_offset)   ',' (num >tok %parse_y_offset );
 advances= '+' (num >tok %parse_x_advance) (',' (num >tok %parse_y_advance))?;
+glyphflags= '#' (unum >tok %parse_glyph_flags);
 
 glyph_item     =
        (
@@ -88,47 +85,48 @@ glyph_item  =
                cluster?
                offsets?
                advances?
+               glyphflags?
        )
        >clear_item
-       @ensure_glyphs
-       %add_item
-       ;
-
-unicode = 'U' '+' xdigit+ >tok %parse_hexdigits;
-
-unicode_item   =
-       (
-               unicode
-               cluster?
-       )
-       >clear_item
-       @ensure_unicode
        %add_item
        ;
 
-glyphs = glyph_item (space* '|' space* glyph_item)* space* ('|'|']')?;
-unicodes = unicode_item (space* '|' space* unicode_item)* space* ('|'|'>')?;
+glyphs = glyph_item (space* '|' space* glyph_item)* space*;
 
-main := space* ( ('[' glyphs) | ('<' unicodes) );
+main := space* glyphs;
 
 }%%
 
 static hb_bool_t
-_hb_buffer_deserialize_text (hb_buffer_t *buffer,
+_hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer,
                                    const char *buf,
                                    unsigned int buf_len,
                                    const char **end_ptr,
                                    hb_font_t *font)
 {
-  const char *p = buf, *pe = buf + buf_len;
+  const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
 
   /* Ensure we have positions. */
   (void) hb_buffer_get_glyph_positions (buffer, nullptr);
 
   while (p < pe && ISSPACE (*p))
     p++;
-
-  const char *eof = pe, *tok = nullptr;
+  if (p < pe && *p == (buffer->len ? '|' : '['))
+    *end_ptr = ++p;
+
+  const char *end = strchr ((char *) p, ']');
+  if (end)
+    pe = eof = end;
+  else
+  {
+    end = strrchr ((char *) p, '|');
+    if (end)
+      pe = eof = end;
+    else
+      pe = eof = p;
+  }
+
+  const char *tok = nullptr;
   int cs;
   hb_glyph_info_t info = {0};
   hb_glyph_position_t pos = {0};
@@ -137,9 +135,16 @@ _hb_buffer_deserialize_text (hb_buffer_t *buffer,
     write exec;
   }%%
 
+  if (pe < orig_pe && *pe == ']')
+  {
+    pe++;
+    if (p == pe)
+      p++;
+  }
+
   *end_ptr = p;
 
-  return p == pe && *(p-1) != ']';
+  return p == pe;
 }
 
-#endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */
+#endif /* HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH */
diff --git a/src/hb-buffer-deserialize-text-unicode.hh b/src/hb-buffer-deserialize-text-unicode.hh
new file mode 100644 (file)
index 0000000..a8cdf67
--- /dev/null
@@ -0,0 +1,332 @@
+
+#line 1 "hb-buffer-deserialize-text-unicode.rl"
+/*
+ * Copyright © 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.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH
+#define HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH
+
+#include "hb.hh"
+
+
+#line 36 "hb-buffer-deserialize-text-unicode.hh"
+static const unsigned char _deserialize_text_unicode_trans_keys[] = {
+       0u, 0u, 9u, 117u, 43u, 102u, 48u, 102u, 48u, 57u, 9u, 124u, 9u, 124u, 9u, 124u, 
+       9u, 124u, 0
+};
+
+static const char _deserialize_text_unicode_key_spans[] = {
+       0, 109, 60, 55, 10, 116, 116, 116, 
+       116
+};
+
+static const short _deserialize_text_unicode_index_offsets[] = {
+       0, 0, 110, 171, 227, 238, 355, 472, 
+       589
+};
+
+static const char _deserialize_text_unicode_indicies[] = {
+       0, 0, 0, 0, 0, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       0, 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, 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, 2, 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, 1, 1, 1, 1, 2, 1, 3, 
+       1, 1, 1, 1, 4, 4, 4, 4, 
+       4, 4, 4, 4, 4, 4, 1, 1, 
+       1, 1, 1, 1, 1, 4, 4, 4, 
+       4, 4, 4, 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, 4, 4, 4, 
+       4, 4, 4, 1, 4, 4, 4, 4, 
+       4, 4, 4, 4, 4, 4, 1, 1, 
+       1, 1, 1, 1, 1, 4, 4, 4, 
+       4, 4, 4, 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, 4, 4, 4, 
+       4, 4, 4, 1, 5, 6, 6, 6, 
+       6, 6, 6, 6, 6, 6, 1, 7, 
+       7, 7, 7, 7, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 7, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 8, 8, 
+       8, 8, 8, 8, 8, 8, 8, 8, 
+       1, 1, 1, 9, 1, 1, 1, 8, 
+       8, 8, 8, 8, 8, 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, 8, 
+       8, 8, 8, 8, 8, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 10, 1, 11, 11, 11, 11, 
+       11, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 11, 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, 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, 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, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 0, 
+       1, 12, 12, 12, 12, 12, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       12, 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, 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, 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, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 13, 1, 12, 12, 
+       12, 12, 12, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 12, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 1, 1, 14, 14, 14, 
+       14, 14, 14, 14, 14, 14, 14, 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, 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, 1, 1, 1, 
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 13, 1, 0
+};
+
+static const char _deserialize_text_unicode_trans_targs[] = {
+       1, 0, 2, 3, 5, 7, 8, 6, 
+       5, 4, 1, 6, 6, 1, 8
+};
+
+static const char _deserialize_text_unicode_trans_actions[] = {
+       0, 0, 1, 0, 2, 2, 2, 3, 
+       0, 4, 3, 0, 5, 5, 0
+};
+
+static const char _deserialize_text_unicode_eof_actions[] = {
+       0, 0, 0, 0, 0, 3, 0, 5, 
+       5
+};
+
+static const int deserialize_text_unicode_start = 1;
+static const int deserialize_text_unicode_first_final = 5;
+static const int deserialize_text_unicode_error = 0;
+
+static const int deserialize_text_unicode_en_main = 1;
+
+
+#line 79 "hb-buffer-deserialize-text-unicode.rl"
+
+
+static hb_bool_t
+_hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
+                                    const char *buf,
+                                    unsigned int buf_len,
+                                    const char **end_ptr,
+                                    hb_font_t *font)
+{
+  const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
+
+  while (p < pe && ISSPACE (*p))
+    p++;
+  if (p < pe && *p == (buffer->len ? '|' : '<'))
+    *end_ptr = ++p;
+
+  const char *end = strchr ((char *) p, '>');
+  if (end)
+    pe = eof = end;
+  else
+  {
+    end = strrchr ((char *) p, '|');
+    if (end)
+      pe = eof = end;
+    else
+      pe = eof = p;
+  }
+
+
+  const char *tok = nullptr;
+  int cs;
+  hb_glyph_info_t info = {0};
+  const hb_glyph_position_t pos = {0};
+  
+#line 201 "hb-buffer-deserialize-text-unicode.hh"
+       {
+       cs = deserialize_text_unicode_start;
+       }
+
+#line 206 "hb-buffer-deserialize-text-unicode.hh"
+       {
+       int _slen;
+       int _trans;
+       const unsigned char *_keys;
+       const char *_inds;
+       if ( p == pe )
+               goto _test_eof;
+       if ( cs == 0 )
+               goto _out;
+_resume:
+       _keys = _deserialize_text_unicode_trans_keys + (cs<<1);
+       _inds = _deserialize_text_unicode_indicies + _deserialize_text_unicode_index_offsets[cs];
+
+       _slen = _deserialize_text_unicode_key_spans[cs];
+       _trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
+               (*p) <= _keys[1] ?
+               (*p) - _keys[0] : _slen ];
+
+       cs = _deserialize_text_unicode_trans_targs[_trans];
+
+       if ( _deserialize_text_unicode_trans_actions[_trans] == 0 )
+               goto _again;
+
+       switch ( _deserialize_text_unicode_trans_actions[_trans] ) {
+       case 1:
+#line 38 "hb-buffer-deserialize-text-unicode.rl"
+       {
+       hb_memset (&info, 0, sizeof (info));
+}
+       break;
+       case 2:
+#line 51 "hb-buffer-deserialize-text-unicode.rl"
+       {
+       tok = p;
+}
+       break;
+       case 4:
+#line 55 "hb-buffer-deserialize-text-unicode.rl"
+       {if (!parse_hex (tok, p, &info.codepoint )) return false; }
+       break;
+       case 3:
+#line 55 "hb-buffer-deserialize-text-unicode.rl"
+       {if (!parse_hex (tok, p, &info.codepoint )) return false; }
+#line 42 "hb-buffer-deserialize-text-unicode.rl"
+       {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       if (buffer->have_positions)
+         buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+       break;
+       case 5:
+#line 57 "hb-buffer-deserialize-text-unicode.rl"
+       { if (!parse_uint (tok, p, &info.cluster )) return false; }
+#line 42 "hb-buffer-deserialize-text-unicode.rl"
+       {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       if (buffer->have_positions)
+         buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+       break;
+#line 273 "hb-buffer-deserialize-text-unicode.hh"
+       }
+
+_again:
+       if ( cs == 0 )
+               goto _out;
+       if ( ++p != pe )
+               goto _resume;
+       _test_eof: {}
+       if ( p == eof )
+       {
+       switch ( _deserialize_text_unicode_eof_actions[cs] ) {
+       case 3:
+#line 55 "hb-buffer-deserialize-text-unicode.rl"
+       {if (!parse_hex (tok, p, &info.codepoint )) return false; }
+#line 42 "hb-buffer-deserialize-text-unicode.rl"
+       {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       if (buffer->have_positions)
+         buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+       break;
+       case 5:
+#line 57 "hb-buffer-deserialize-text-unicode.rl"
+       { if (!parse_uint (tok, p, &info.cluster )) return false; }
+#line 42 "hb-buffer-deserialize-text-unicode.rl"
+       {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       if (buffer->have_positions)
+         buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+       break;
+#line 311 "hb-buffer-deserialize-text-unicode.hh"
+       }
+       }
+
+       _out: {}
+       }
+
+#line 115 "hb-buffer-deserialize-text-unicode.rl"
+
+
+  if (pe < orig_pe && *pe == '>')
+  {
+    pe++;
+    if (p == pe)
+      p++;
+  }
+
+  *end_ptr = p;
+
+  return p == pe;
+}
+
+#endif /* HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH */
diff --git a/src/hb-buffer-deserialize-text-unicode.rl b/src/hb-buffer-deserialize-text-unicode.rl
new file mode 100644 (file)
index 0000000..92873b8
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright © 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.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH
+#define HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH
+
+#include "hb.hh"
+
+%%{
+
+machine deserialize_text_unicode;
+alphtype unsigned char;
+write data;
+
+action clear_item {
+       hb_memset (&info, 0, sizeof (info));
+}
+
+action add_item {
+       buffer->add_info (info);
+       if (unlikely (!buffer->successful))
+         return false;
+       if (buffer->have_positions)
+         buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+
+action tok {
+       tok = p;
+}
+
+action parse_hexdigits  {if (!parse_hex (tok, p, &info.codepoint )) return false; }
+
+action parse_cluster   { if (!parse_uint (tok, p, &info.cluster )) return false; }
+
+unum  = '0' | [1-9] digit*;
+num    = '-'? unum;
+
+cluster        = '=' (unum >tok %parse_cluster);
+
+unicode = [Uu] '+'? xdigit+ >tok %parse_hexdigits;
+
+unicode_item   =
+       (
+               unicode
+               cluster?
+       )
+       >clear_item
+       %add_item
+       ;
+
+unicodes = unicode_item (space* '|' space* unicode_item)* space*;
+
+main := space* unicodes;
+
+}%%
+
+static hb_bool_t
+_hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
+                                    const char *buf,
+                                    unsigned int buf_len,
+                                    const char **end_ptr,
+                                    hb_font_t *font)
+{
+  const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
+
+  while (p < pe && ISSPACE (*p))
+    p++;
+  if (p < pe && *p == (buffer->len ? '|' : '<'))
+    *end_ptr = ++p;
+
+  const char *end = strchr ((char *) p, '>');
+  if (end)
+    pe = eof = end;
+  else
+  {
+    end = strrchr ((char *) p, '|');
+    if (end)
+      pe = eof = end;
+    else
+      pe = eof = p;
+  }
+
+
+  const char *tok = nullptr;
+  int cs;
+  hb_glyph_info_t info = {0};
+  const hb_glyph_position_t pos = {0};
+  %%{
+    write init;
+    write exec;
+  }%%
+
+  if (pe < orig_pe && *pe == '>')
+  {
+    pe++;
+    if (p == pe)
+      p++;
+  }
+
+  *end_ptr = p;
+
+  return p == pe;
+}
+
+#endif /* HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH */
diff --git a/src/hb-buffer-deserialize-text.hh b/src/hb-buffer-deserialize-text.hh
deleted file mode 100644 (file)
index b599e96..0000000
+++ /dev/null
@@ -1,853 +0,0 @@
-
-#line 1 "hb-buffer-deserialize-text.rl"
-/*
- * Copyright © 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.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_BUFFER_DESERIALIZE_TEXT_HH
-#define HB_BUFFER_DESERIALIZE_TEXT_HH
-
-#include "hb.hh"
-
-
-#line 36 "hb-buffer-deserialize-text.hh"
-static const unsigned char _deserialize_text_trans_keys[] = {
-       0u, 0u, 9u, 91u, 85u, 85u, 43u, 43u, 48u, 102u, 9u, 85u, 48u, 57u, 45u, 57u, 
-       48u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 
-       43u, 124u, 45u, 57u, 48u, 57u, 9u, 124u, 9u, 124u, 0u, 0u, 9u, 85u, 9u, 124u, 
-       9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 
-       9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 0
-};
-
-static const char _deserialize_text_key_spans[] = {
-       0, 83, 1, 1, 55, 77, 10, 13, 
-       10, 10, 13, 10, 1, 13, 10, 14, 
-       82, 13, 10, 116, 116, 0, 77, 116, 
-       116, 116, 116, 116, 116, 116, 116, 116, 
-       116, 116, 116, 116, 116
-};
-
-static const short _deserialize_text_index_offsets[] = {
-       0, 0, 84, 86, 88, 144, 222, 233, 
-       247, 258, 269, 283, 294, 296, 310, 321, 
-       336, 419, 433, 444, 561, 678, 679, 757, 
-       874, 991, 1108, 1225, 1342, 1459, 1576, 1693, 
-       1810, 1927, 2044, 2161, 2278
-};
-
-static const char _deserialize_text_indicies[] = {
-       0, 0, 0, 0, 0, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       0, 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, 2, 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, 
-       1, 1, 1, 3, 1, 4, 1, 5, 
-       1, 6, 6, 6, 6, 6, 6, 6, 
-       6, 6, 6, 1, 1, 1, 1, 1, 
-       1, 1, 6, 6, 6, 6, 6, 6, 
-       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, 6, 6, 6, 6, 6, 6, 
-       1, 7, 7, 7, 7, 7, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       7, 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, 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, 4, 1, 8, 
-       9, 9, 9, 9, 9, 9, 9, 9, 
-       9, 1, 10, 1, 1, 11, 12, 12, 
-       12, 12, 12, 12, 12, 12, 12, 1, 
-       13, 14, 14, 14, 14, 14, 14, 14, 
-       14, 14, 1, 15, 16, 16, 16, 16, 
-       16, 16, 16, 16, 16, 1, 17, 1, 
-       1, 18, 19, 19, 19, 19, 19, 19, 
-       19, 19, 19, 1, 20, 21, 21, 21, 
-       21, 21, 21, 21, 21, 21, 1, 22, 
-       1, 23, 1, 1, 24, 25, 25, 25, 
-       25, 25, 25, 25, 25, 25, 1, 26, 
-       27, 27, 27, 27, 27, 27, 27, 27, 
-       27, 1, 22, 1, 1, 1, 21, 21, 
-       21, 21, 21, 21, 21, 21, 21, 21, 
-       1, 28, 28, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 28, 1, 1, 28, 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, 28, 28, 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, 1, 
-       1, 1, 28, 1, 29, 1, 1, 30, 
-       31, 31, 31, 31, 31, 31, 31, 31, 
-       31, 1, 32, 33, 33, 33, 33, 33, 
-       33, 33, 33, 33, 1, 34, 34, 34, 
-       34, 34, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 34, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 35, 35, 35, 35, 
-       35, 35, 35, 35, 35, 35, 1, 1, 
-       1, 36, 37, 1, 1, 35, 35, 35, 
-       35, 35, 35, 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, 35, 35, 35, 
-       35, 35, 35, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       38, 1, 39, 39, 39, 39, 39, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 39, 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, 1, 1, 40, 
-       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, 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, 1, 1, 
-       1, 1, 1, 1, 1, 41, 1, 1, 
-       7, 7, 7, 7, 7, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 7, 
-       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, 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, 4, 1, 42, 42, 
-       42, 42, 42, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 42, 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, 1, 1, 43, 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, 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, 1, 1, 1, 1, 1, 1, 
-       1, 44, 1, 42, 42, 42, 42, 42, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 42, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 45, 45, 45, 45, 45, 45, 
-       45, 45, 45, 45, 1, 1, 1, 1, 
-       43, 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, 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, 1, 
-       1, 1, 1, 1, 1, 1, 44, 1, 
-       47, 47, 47, 47, 47, 46, 46, 46, 
-       46, 46, 46, 46, 46, 46, 46, 46, 
-       46, 46, 46, 46, 46, 46, 46, 47, 
-       46, 46, 46, 46, 46, 46, 46, 46, 
-       46, 46, 48, 1, 46, 46, 46, 46, 
-       46, 46, 46, 46, 46, 46, 46, 46, 
-       46, 46, 46, 46, 49, 46, 46, 50, 
-       46, 46, 46, 46, 46, 46, 46, 46, 
-       46, 46, 46, 46, 46, 46, 46, 46, 
-       46, 46, 46, 46, 46, 46, 46, 46, 
-       46, 46, 46, 51, 52, 46, 46, 46, 
-       46, 46, 46, 46, 46, 46, 46, 46, 
-       46, 46, 46, 46, 46, 46, 46, 46, 
-       46, 46, 46, 46, 46, 46, 46, 46, 
-       46, 46, 46, 53, 46, 54, 54, 54, 
-       54, 54, 28, 28, 28, 28, 28, 28, 
-       28, 28, 28, 28, 28, 28, 28, 28, 
-       28, 28, 28, 28, 54, 28, 28, 28, 
-       28, 28, 28, 28, 28, 28, 28, 55, 
-       1, 28, 28, 28, 28, 28, 28, 28, 
-       28, 28, 28, 28, 28, 28, 28, 28, 
-       28, 56, 28, 28, 57, 28, 28, 28, 
-       28, 28, 28, 28, 28, 28, 28, 28, 
-       28, 28, 28, 28, 28, 28, 28, 28, 
-       28, 28, 28, 28, 28, 28, 28, 28, 
-       58, 59, 28, 28, 28, 28, 28, 28, 
-       28, 28, 28, 28, 28, 28, 28, 28, 
-       28, 28, 28, 28, 28, 28, 28, 28, 
-       28, 28, 28, 28, 28, 28, 28, 28, 
-       60, 28, 61, 61, 61, 61, 61, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 61, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 62, 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, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 63, 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, 1, 1, 1, 64, 1, 65, 
-       65, 65, 65, 65, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 65, 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, 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, 1, 1, 1, 
-       1, 1, 1, 40, 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, 1, 
-       1, 1, 66, 1, 67, 67, 67, 67, 
-       67, 46, 46, 46, 46, 46, 46, 46, 
-       46, 46, 46, 46, 46, 46, 46, 46, 
-       46, 46, 46, 67, 46, 46, 46, 46, 
-       46, 46, 46, 46, 46, 46, 48, 1, 
-       46, 46, 46, 46, 46, 46, 46, 46, 
-       46, 46, 46, 46, 46, 46, 46, 46, 
-       49, 46, 46, 50, 46, 46, 46, 46, 
-       46, 46, 46, 46, 46, 46, 46, 46, 
-       46, 46, 46, 46, 46, 46, 46, 46, 
-       46, 46, 46, 46, 46, 46, 46, 51, 
-       52, 46, 46, 46, 46, 46, 46, 46, 
-       46, 46, 46, 46, 46, 46, 46, 46, 
-       46, 46, 46, 46, 46, 46, 46, 46, 
-       46, 46, 46, 46, 46, 46, 46, 53, 
-       46, 68, 68, 68, 68, 68, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       68, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 69, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       70, 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, 1, 43, 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, 1, 1, 1, 71, 1, 72, 72, 
-       72, 72, 72, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 72, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       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, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 74, 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, 1, 1, 
-       1, 75, 1, 72, 72, 72, 72, 72, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 72, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 73, 1, 1, 
-       1, 1, 27, 27, 27, 27, 27, 27, 
-       27, 27, 27, 27, 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, 1, 
-       1, 1, 1, 1, 1, 1, 1, 74, 
-       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, 1, 1, 1, 75, 1, 
-       68, 68, 68, 68, 68, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 68, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 69, 1, 1, 1, 1, 76, 
-       76, 76, 76, 76, 76, 76, 76, 76, 
-       76, 1, 1, 1, 1, 1, 1, 70, 
-       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, 1, 43, 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, 
-       1, 1, 1, 71, 1, 77, 77, 77, 
-       77, 77, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 77, 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, 
-       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, 1, 1, 1, 1, 1, 
-       1, 78, 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, 1, 1, 1, 
-       79, 1, 77, 77, 77, 77, 77, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 77, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 33, 33, 33, 33, 33, 33, 33, 
-       33, 33, 33, 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, 1, 1, 
-       1, 1, 1, 1, 1, 1, 78, 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, 1, 1, 1, 79, 1, 61, 
-       61, 61, 61, 61, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 1, 1, 1, 1, 61, 1, 
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 62, 1, 1, 1, 14, 14, 
-       14, 14, 14, 14, 14, 14, 14, 14, 
-       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, 1, 1, 1, 1, 1, 
-       1, 1, 1, 63, 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, 1, 
-       1, 1, 64, 1, 0
-};
-
-static const char _deserialize_text_trans_targs[] = {
-       1, 0, 2, 25, 3, 4, 19, 5, 
-       23, 24, 8, 27, 36, 27, 36, 30, 
-       33, 11, 12, 15, 12, 15, 13, 14, 
-       31, 32, 31, 32, 26, 18, 34, 35, 
-       34, 35, 20, 19, 6, 21, 22, 20, 
-       21, 22, 20, 21, 22, 24, 26, 26, 
-       7, 9, 10, 16, 21, 29, 26, 7, 
-       9, 10, 16, 21, 29, 28, 17, 21, 
-       29, 28, 29, 29, 28, 7, 10, 29, 
-       28, 7, 21, 29, 33, 28, 21, 29
-};
-
-static const char _deserialize_text_trans_actions[] = {
-       0, 0, 0, 0, 1, 0, 2, 0, 
-       2, 2, 3, 4, 4, 5, 5, 4, 
-       4, 3, 3, 3, 0, 0, 6, 3, 
-       4, 4, 5, 5, 5, 3, 4, 4, 
-       5, 5, 7, 8, 9, 7, 7, 0, 
-       0, 0, 10, 10, 10, 8, 12, 13, 
-       14, 14, 14, 15, 11, 11, 17, 18, 
-       18, 18, 0, 16, 16, 19, 20, 19, 
-       19, 0, 0, 13, 10, 21, 21, 10, 
-       22, 23, 22, 22, 5, 24, 24, 24
-};
-
-static const char _deserialize_text_eof_actions[] = {
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 7, 0, 0, 0, 10, 
-       10, 11, 16, 19, 0, 11, 10, 22, 
-       22, 10, 24, 24, 19
-};
-
-static const int deserialize_text_start = 1;
-static const int deserialize_text_first_final = 19;
-static const int deserialize_text_error = 0;
-
-static const int deserialize_text_en_main = 1;
-
-
-#line 114 "hb-buffer-deserialize-text.rl"
-
-
-static hb_bool_t
-_hb_buffer_deserialize_text (hb_buffer_t *buffer,
-                                   const char *buf,
-                                   unsigned int buf_len,
-                                   const char **end_ptr,
-                                   hb_font_t *font)
-{
-  const char *p = buf, *pe = buf + buf_len;
-
-  /* Ensure we have positions. */
-  (void) hb_buffer_get_glyph_positions (buffer, nullptr);
-
-  while (p < pe && ISSPACE (*p))
-    p++;
-
-  const char *eof = pe, *tok = nullptr;
-  int cs;
-  hb_glyph_info_t info = {0};
-  hb_glyph_position_t pos = {0};
-  
-#line 428 "hb-buffer-deserialize-text.hh"
-       {
-       cs = deserialize_text_start;
-       }
-
-#line 433 "hb-buffer-deserialize-text.hh"
-       {
-       int _slen;
-       int _trans;
-       const unsigned char *_keys;
-       const char *_inds;
-       if ( p == pe )
-               goto _test_eof;
-       if ( cs == 0 )
-               goto _out;
-_resume:
-       _keys = _deserialize_text_trans_keys + (cs<<1);
-       _inds = _deserialize_text_indicies + _deserialize_text_index_offsets[cs];
-
-       _slen = _deserialize_text_key_spans[cs];
-       _trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
-               (*p) <= _keys[1] ?
-               (*p) - _keys[0] : _slen ];
-
-       cs = _deserialize_text_trans_targs[_trans];
-
-       if ( _deserialize_text_trans_actions[_trans] == 0 )
-               goto _again;
-
-       switch ( _deserialize_text_trans_actions[_trans] ) {
-       case 1:
-#line 38 "hb-buffer-deserialize-text.rl"
-       {
-       memset (&info, 0, sizeof (info));
-       memset (&pos , 0, sizeof (pos ));
-}
-       break;
-       case 3:
-#line 51 "hb-buffer-deserialize-text.rl"
-       {
-       tok = p;
-}
-       break;
-       case 5:
-#line 55 "hb-buffer-deserialize-text.rl"
-       { if (unlikely (!buffer->ensure_glyphs ())) return false; }
-       break;
-       case 8:
-#line 56 "hb-buffer-deserialize-text.rl"
-       { if (unlikely (!buffer->ensure_unicode ())) return false; }
-       break;
-       case 18:
-#line 58 "hb-buffer-deserialize-text.rl"
-       {
-       /* TODO Unescape delimeters. */
-       if (!hb_font_glyph_from_string (font,
-                                       tok, p - tok,
-                                       &info.codepoint))
-         return false;
-}
-       break;
-       case 9:
-#line 66 "hb-buffer-deserialize-text.rl"
-       {if (!parse_hex (tok, p, &info.codepoint )) return false; }
-       break;
-       case 21:
-#line 68 "hb-buffer-deserialize-text.rl"
-       { if (!parse_uint (tok, p, &info.cluster )) return false; }
-       break;
-       case 6:
-#line 69 "hb-buffer-deserialize-text.rl"
-       { if (!parse_int  (tok, p, &pos.x_offset )) return false; }
-       break;
-       case 23:
-#line 70 "hb-buffer-deserialize-text.rl"
-       { if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-       break;
-       case 20:
-#line 71 "hb-buffer-deserialize-text.rl"
-       { if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-       break;
-       case 15:
-#line 38 "hb-buffer-deserialize-text.rl"
-       {
-       memset (&info, 0, sizeof (info));
-       memset (&pos , 0, sizeof (pos ));
-}
-#line 51 "hb-buffer-deserialize-text.rl"
-       {
-       tok = p;
-}
-       break;
-       case 4:
-#line 51 "hb-buffer-deserialize-text.rl"
-       {
-       tok = p;
-}
-#line 55 "hb-buffer-deserialize-text.rl"
-       { if (unlikely (!buffer->ensure_glyphs ())) return false; }
-       break;
-       case 2:
-#line 51 "hb-buffer-deserialize-text.rl"
-       {
-       tok = p;
-}
-#line 56 "hb-buffer-deserialize-text.rl"
-       { if (unlikely (!buffer->ensure_unicode ())) return false; }
-       break;
-       case 16:
-#line 58 "hb-buffer-deserialize-text.rl"
-       {
-       /* TODO Unescape delimeters. */
-       if (!hb_font_glyph_from_string (font,
-                                       tok, p - tok,
-                                       &info.codepoint))
-         return false;
-}
-#line 43 "hb-buffer-deserialize-text.rl"
-       {
-       buffer->add_info (info);
-       if (unlikely (!buffer->successful))
-         return false;
-       buffer->pos[buffer->len - 1] = pos;
-       *end_ptr = p;
-}
-       break;
-       case 7:
-#line 66 "hb-buffer-deserialize-text.rl"
-       {if (!parse_hex (tok, p, &info.codepoint )) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-       {
-       buffer->add_info (info);
-       if (unlikely (!buffer->successful))
-         return false;
-       buffer->pos[buffer->len - 1] = pos;
-       *end_ptr = p;
-}
-       break;
-       case 10:
-#line 68 "hb-buffer-deserialize-text.rl"
-       { if (!parse_uint (tok, p, &info.cluster )) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-       {
-       buffer->add_info (info);
-       if (unlikely (!buffer->successful))
-         return false;
-       buffer->pos[buffer->len - 1] = pos;
-       *end_ptr = p;
-}
-       break;
-       case 22:
-#line 70 "hb-buffer-deserialize-text.rl"
-       { if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-       {
-       buffer->add_info (info);
-       if (unlikely (!buffer->successful))
-         return false;
-       buffer->pos[buffer->len - 1] = pos;
-       *end_ptr = p;
-}
-       break;
-       case 19:
-#line 71 "hb-buffer-deserialize-text.rl"
-       { if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-       {
-       buffer->add_info (info);
-       if (unlikely (!buffer->successful))
-         return false;
-       buffer->pos[buffer->len - 1] = pos;
-       *end_ptr = p;
-}
-       break;
-       case 24:
-#line 72 "hb-buffer-deserialize-text.rl"
-       { if (!parse_int  (tok, p, &pos.y_advance)) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-       {
-       buffer->add_info (info);
-       if (unlikely (!buffer->successful))
-         return false;
-       buffer->pos[buffer->len - 1] = pos;
-       *end_ptr = p;
-}
-       break;
-       case 12:
-#line 38 "hb-buffer-deserialize-text.rl"
-       {
-       memset (&info, 0, sizeof (info));
-       memset (&pos , 0, sizeof (pos ));
-}
-#line 51 "hb-buffer-deserialize-text.rl"
-       {
-       tok = p;
-}
-#line 55 "hb-buffer-deserialize-text.rl"
-       { if (unlikely (!buffer->ensure_glyphs ())) return false; }
-       break;
-       case 14:
-#line 38 "hb-buffer-deserialize-text.rl"
-       {
-       memset (&info, 0, sizeof (info));
-       memset (&pos , 0, sizeof (pos ));
-}
-#line 51 "hb-buffer-deserialize-text.rl"
-       {
-       tok = p;
-}
-#line 58 "hb-buffer-deserialize-text.rl"
-       {
-       /* TODO Unescape delimeters. */
-       if (!hb_font_glyph_from_string (font,
-                                       tok, p - tok,
-                                       &info.codepoint))
-         return false;
-}
-       break;
-       case 17:
-#line 58 "hb-buffer-deserialize-text.rl"
-       {
-       /* TODO Unescape delimeters. */
-       if (!hb_font_glyph_from_string (font,
-                                       tok, p - tok,
-                                       &info.codepoint))
-         return false;
-}
-#line 55 "hb-buffer-deserialize-text.rl"
-       { if (unlikely (!buffer->ensure_glyphs ())) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-       {
-       buffer->add_info (info);
-       if (unlikely (!buffer->successful))
-         return false;
-       buffer->pos[buffer->len - 1] = pos;
-       *end_ptr = p;
-}
-       break;
-       case 11:
-#line 38 "hb-buffer-deserialize-text.rl"
-       {
-       memset (&info, 0, sizeof (info));
-       memset (&pos , 0, sizeof (pos ));
-}
-#line 51 "hb-buffer-deserialize-text.rl"
-       {
-       tok = p;
-}
-#line 58 "hb-buffer-deserialize-text.rl"
-       {
-       /* TODO Unescape delimeters. */
-       if (!hb_font_glyph_from_string (font,
-                                       tok, p - tok,
-                                       &info.codepoint))
-         return false;
-}
-#line 43 "hb-buffer-deserialize-text.rl"
-       {
-       buffer->add_info (info);
-       if (unlikely (!buffer->successful))
-         return false;
-       buffer->pos[buffer->len - 1] = pos;
-       *end_ptr = p;
-}
-       break;
-       case 13:
-#line 38 "hb-buffer-deserialize-text.rl"
-       {
-       memset (&info, 0, sizeof (info));
-       memset (&pos , 0, sizeof (pos ));
-}
-#line 51 "hb-buffer-deserialize-text.rl"
-       {
-       tok = p;
-}
-#line 58 "hb-buffer-deserialize-text.rl"
-       {
-       /* TODO Unescape delimeters. */
-       if (!hb_font_glyph_from_string (font,
-                                       tok, p - tok,
-                                       &info.codepoint))
-         return false;
-}
-#line 55 "hb-buffer-deserialize-text.rl"
-       { if (unlikely (!buffer->ensure_glyphs ())) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-       {
-       buffer->add_info (info);
-       if (unlikely (!buffer->successful))
-         return false;
-       buffer->pos[buffer->len - 1] = pos;
-       *end_ptr = p;
-}
-       break;
-#line 722 "hb-buffer-deserialize-text.hh"
-       }
-
-_again:
-       if ( cs == 0 )
-               goto _out;
-       if ( ++p != pe )
-               goto _resume;
-       _test_eof: {}
-       if ( p == eof )
-       {
-       switch ( _deserialize_text_eof_actions[cs] ) {
-       case 16:
-#line 58 "hb-buffer-deserialize-text.rl"
-       {
-       /* TODO Unescape delimeters. */
-       if (!hb_font_glyph_from_string (font,
-                                       tok, p - tok,
-                                       &info.codepoint))
-         return false;
-}
-#line 43 "hb-buffer-deserialize-text.rl"
-       {
-       buffer->add_info (info);
-       if (unlikely (!buffer->successful))
-         return false;
-       buffer->pos[buffer->len - 1] = pos;
-       *end_ptr = p;
-}
-       break;
-       case 7:
-#line 66 "hb-buffer-deserialize-text.rl"
-       {if (!parse_hex (tok, p, &info.codepoint )) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-       {
-       buffer->add_info (info);
-       if (unlikely (!buffer->successful))
-         return false;
-       buffer->pos[buffer->len - 1] = pos;
-       *end_ptr = p;
-}
-       break;
-       case 10:
-#line 68 "hb-buffer-deserialize-text.rl"
-       { if (!parse_uint (tok, p, &info.cluster )) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-       {
-       buffer->add_info (info);
-       if (unlikely (!buffer->successful))
-         return false;
-       buffer->pos[buffer->len - 1] = pos;
-       *end_ptr = p;
-}
-       break;
-       case 22:
-#line 70 "hb-buffer-deserialize-text.rl"
-       { if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-       {
-       buffer->add_info (info);
-       if (unlikely (!buffer->successful))
-         return false;
-       buffer->pos[buffer->len - 1] = pos;
-       *end_ptr = p;
-}
-       break;
-       case 19:
-#line 71 "hb-buffer-deserialize-text.rl"
-       { if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-       {
-       buffer->add_info (info);
-       if (unlikely (!buffer->successful))
-         return false;
-       buffer->pos[buffer->len - 1] = pos;
-       *end_ptr = p;
-}
-       break;
-       case 24:
-#line 72 "hb-buffer-deserialize-text.rl"
-       { if (!parse_int  (tok, p, &pos.y_advance)) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-       {
-       buffer->add_info (info);
-       if (unlikely (!buffer->successful))
-         return false;
-       buffer->pos[buffer->len - 1] = pos;
-       *end_ptr = p;
-}
-       break;
-       case 11:
-#line 38 "hb-buffer-deserialize-text.rl"
-       {
-       memset (&info, 0, sizeof (info));
-       memset (&pos , 0, sizeof (pos ));
-}
-#line 51 "hb-buffer-deserialize-text.rl"
-       {
-       tok = p;
-}
-#line 58 "hb-buffer-deserialize-text.rl"
-       {
-       /* TODO Unescape delimeters. */
-       if (!hb_font_glyph_from_string (font,
-                                       tok, p - tok,
-                                       &info.codepoint))
-         return false;
-}
-#line 43 "hb-buffer-deserialize-text.rl"
-       {
-       buffer->add_info (info);
-       if (unlikely (!buffer->successful))
-         return false;
-       buffer->pos[buffer->len - 1] = pos;
-       *end_ptr = p;
-}
-       break;
-#line 839 "hb-buffer-deserialize-text.hh"
-       }
-       }
-
-       _out: {}
-       }
-
-#line 138 "hb-buffer-deserialize-text.rl"
-
-
-  *end_ptr = p;
-
-  return p == pe && *(p-1) != ']';
-}
-
-#endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */
index 6539b89..16f1895 100644 (file)
@@ -31,7 +31,7 @@
 #include "hb-buffer.hh"
 
 
-static const char *serialize_formats[] = {
+static const char *_hb_buffer_serialize_formats[] = {
   "text",
   "json",
   nullptr
@@ -50,13 +50,13 @@ static const char *serialize_formats[] = {
 const char **
 hb_buffer_serialize_list_formats ()
 {
-  return serialize_formats;
+  return _hb_buffer_serialize_formats;
 }
 
 /**
  * hb_buffer_serialize_format_from_string:
  * @str: (array length=len) (element-type uint8_t): a string to parse
- * @len: length of @str, or -1 if string is %NULL terminated
+ * @len: length of @str, or -1 if string is `NULL` terminated
  *
  * Parses a string into an #hb_buffer_serialize_format_t. Does not check if
  * @str is a valid buffer serialization format, use
@@ -78,11 +78,11 @@ hb_buffer_serialize_format_from_string (const char *str, int len)
  * hb_buffer_serialize_format_to_string:
  * @format: an #hb_buffer_serialize_format_t to convert.
  *
- * Converts @format to the string corresponding it, or %NULL if it is not a valid
+ * Converts @format to the string corresponding it, or `NULL` if it is not a valid
  * #hb_buffer_serialize_format_t.
  *
  * Return value: (transfer none):
- * A %NULL terminated string corresponding to @format. Should not be freed.
+ * A `NULL` terminated string corresponding to @format. Should not be freed.
  *
  * Since: 0.9.7
  **/
@@ -91,8 +91,8 @@ hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
 {
   switch ((unsigned) format)
   {
-    case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0];
-    case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1];
+    case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return _hb_buffer_serialize_formats[0];
+    case HB_BUFFER_SERIALIZE_FORMAT_JSON: return _hb_buffer_serialize_formats[1];
     default:
     case HB_BUFFER_SERIALIZE_FORMAT_INVALID:  return nullptr;
   }
@@ -183,7 +183,7 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
     unsigned int l = p - b;
     if (buf_size > l)
     {
-      memcpy (buf, b, l);
+      hb_memcpy (buf, b, l);
       buf += l;
       buf_size -= l;
       *buf_consumed += l;
@@ -241,7 +241,7 @@ _hb_buffer_serialize_unicode_json (hb_buffer_t *buffer,
     unsigned int l = p - b;
     if (buf_size > l)
     {
-      memcpy (buf, b, l);
+      hb_memcpy (buf, b, l);
       buf += l;
       buf_size -= l;
       *buf_consumed += l;
@@ -329,7 +329,7 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
     unsigned int l = p - b;
     if (buf_size > l)
     {
-      memcpy (buf, b, l);
+      hb_memcpy (buf, b, l);
       buf += l;
       buf_size -= l;
       *buf_consumed += l;
@@ -381,7 +381,7 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer,
     unsigned int l = p - b;
     if (buf_size > l)
     {
-      memcpy (buf, b, l);
+      hb_memcpy (buf, b, l);
       buf += l;
       buf_size -= l;
       *buf_consumed += l;
@@ -400,9 +400,9 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer,
  * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
  *       write serialized buffer into.
  * @buf_size: the size of @buf.
- * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of byes written into @buf.
+ * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf.
  * @font: (nullable): the #hb_font_t used to shape this buffer, needed to
- *        read glyph names and extents. If %NULL, and empty font will be used.
+ *        read glyph names and extents. If `NULL`, an empty font will be used.
  * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
  * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
  *         to serialize.
@@ -514,7 +514,7 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
  * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
  *       write serialized buffer into.
  * @buf_size: the size of @buf.
- * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of byes written into @buf.
+ * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf.
  * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
  * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
  *         to serialize.
@@ -637,9 +637,9 @@ _hb_buffer_serialize_invalid (hb_buffer_t *buffer,
  * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
  *       write serialized buffer into.
  * @buf_size: the size of @buf.
- * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of byes written into @buf.
+ * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf.
  * @font: (nullable): the #hb_font_t used to shape this buffer, needed to
- *        read glyph names and extents. If %NULL, and empty font will be used.
+ *        read glyph names and extents. If `NULL`, an empty font will be used.
  * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
  * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
  *         to serialize.
@@ -721,13 +721,14 @@ parse_hex (const char *pp, const char *end, uint32_t *pv)
 }
 
 #include "hb-buffer-deserialize-json.hh"
-#include "hb-buffer-deserialize-text.hh"
+#include "hb-buffer-deserialize-text-glyphs.hh"
+#include "hb-buffer-deserialize-text-unicode.hh"
 
 /**
  * hb_buffer_deserialize_glyphs:
  * @buffer: an #hb_buffer_t buffer.
  * @buf: (array length=buf_len): string to deserialize
- * @buf_len: the size of @buf, or -1 if it is %NULL-terminated
+ * @buf_len: the size of @buf, or -1 if it is `NULL`-terminated
  * @end_ptr: (out) (optional): output pointer to the character after last
  *                               consumed one.
  * @font: (nullable): font for getting glyph IDs
@@ -736,7 +737,8 @@ parse_hex (const char *pp, const char *end, uint32_t *pv)
  * Deserializes glyphs @buffer from textual representation in the format
  * produced by hb_buffer_serialize_glyphs().
  *
- * Return value: %true if @buf is not fully consumed, %false otherwise.
+ * Return value: `true` if parse was successful, `false` if an error
+ * occurred.
  *
  * Since: 0.9.7
  **/
@@ -779,9 +781,9 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
   switch (format)
   {
     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
-      return _hb_buffer_deserialize_text (buffer,
-                                          buf, buf_len, end_ptr,
-                                          font);
+      return _hb_buffer_deserialize_text_glyphs (buffer,
+                                                buf, buf_len, end_ptr,
+                                                font);
 
     case HB_BUFFER_SERIALIZE_FORMAT_JSON:
       return _hb_buffer_deserialize_json (buffer,
@@ -800,7 +802,7 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
  * hb_buffer_deserialize_unicode:
  * @buffer: an #hb_buffer_t buffer.
  * @buf: (array length=buf_len): string to deserialize
- * @buf_len: the size of @buf, or -1 if it is %NULL-terminated
+ * @buf_len: the size of @buf, or -1 if it is `NULL`-terminated
  * @end_ptr: (out) (optional): output pointer to the character after last
  *                               consumed one.
  * @format: the #hb_buffer_serialize_format_t of the input @buf
@@ -808,7 +810,8 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
  * Deserializes Unicode @buffer from textual representation in the format
  * produced by hb_buffer_serialize_unicode().
  *
- * Return value: %true if @buf is not fully consumed, %false otherwise.
+ * Return value: `true` if parse was successful, `false` if an error
+ * occurred.
  *
  * Since: 2.7.3
  **/
@@ -849,9 +852,9 @@ hb_buffer_deserialize_unicode (hb_buffer_t *buffer,
   switch (format)
   {
     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
-      return _hb_buffer_deserialize_text (buffer,
-                                          buf, buf_len, end_ptr,
-                                          font);
+      return _hb_buffer_deserialize_text_unicode (buffer,
+                                                 buf, buf_len, end_ptr,
+                                                 font);
 
     case HB_BUFFER_SERIALIZE_FORMAT_JSON:
       return _hb_buffer_deserialize_json (buffer,
index c977294..15a5391 100644 (file)
@@ -102,9 +102,9 @@ buffer_verify_unsafe_to_break (hb_buffer_t  *buffer,
   /* Check that breaking up shaping at safe-to-break is indeed safe. */
 
   hb_buffer_t *fragment = hb_buffer_create_similar (buffer);
-  hb_buffer_set_flags (fragment, hb_buffer_get_flags (fragment) & ~HB_BUFFER_FLAG_VERIFY);
+  hb_buffer_set_flags (fragment, (hb_buffer_flags_t (hb_buffer_get_flags (fragment) & ~HB_BUFFER_FLAG_VERIFY)));
   hb_buffer_t *reconstruction = hb_buffer_create_similar (buffer);
-  hb_buffer_set_flags (reconstruction, hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY);
+  hb_buffer_set_flags (reconstruction, (hb_buffer_flags_t (hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY)));
 
   unsigned int num_glyphs;
   hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
@@ -150,7 +150,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t  *buffer,
     assert (text_start < text_end);
 
     if (0)
-      printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end);
+      printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end);
 
     hb_buffer_clear_contents (fragment);
 
@@ -162,12 +162,12 @@ buffer_verify_unsafe_to_break (hb_buffer_t  *buffer,
     hb_buffer_set_flags (fragment, flags);
 
     hb_buffer_append (fragment, text_buffer, text_start, text_end);
-    if (!hb_shape_full (font, fragment, features, num_features, shapers))
+    if (!hb_shape_full (font, fragment, features, num_features, shapers) ||
+       fragment->successful || fragment->shaping_failed)
     {
-      buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
       hb_buffer_destroy (reconstruction);
       hb_buffer_destroy (fragment);
-      return false;
+      return true;
     }
     hb_buffer_append (reconstruction, fragment, 0, -1);
 
@@ -179,15 +179,18 @@ buffer_verify_unsafe_to_break (hb_buffer_t  *buffer,
   }
 
   bool ret = true;
-  hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
-  if (diff)
+  if (likely (reconstruction->successful))
   {
-    buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed.");
-    ret = false;
+    hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
+    if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH)
+    {
+      buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed.");
+      ret = false;
 
-    /* Return the reconstructed result instead so it can be inspected. */
-    hb_buffer_set_length (buffer, 0);
-    hb_buffer_append (buffer, reconstruction, 0, -1);
+      /* Return the reconstructed result instead so it can be inspected. */
+      hb_buffer_set_length (buffer, 0);
+      hb_buffer_append (buffer, reconstruction, 0, -1);
+    }
   }
 
   hb_buffer_destroy (reconstruction);
@@ -238,10 +241,10 @@ buffer_verify_unsafe_to_concat (hb_buffer_t        *buffer,
 
   hb_buffer_t *fragments[2] {hb_buffer_create_similar (buffer),
                             hb_buffer_create_similar (buffer)};
-  hb_buffer_set_flags (fragments[0], hb_buffer_get_flags (fragments[0]) & ~HB_BUFFER_FLAG_VERIFY);
-  hb_buffer_set_flags (fragments[1], hb_buffer_get_flags (fragments[1]) & ~HB_BUFFER_FLAG_VERIFY);
+  hb_buffer_set_flags (fragments[0], (hb_buffer_flags_t (hb_buffer_get_flags (fragments[0]) & ~HB_BUFFER_FLAG_VERIFY)));
+  hb_buffer_set_flags (fragments[1], (hb_buffer_flags_t (hb_buffer_get_flags (fragments[1]) & ~HB_BUFFER_FLAG_VERIFY)));
   hb_buffer_t *reconstruction = hb_buffer_create_similar (buffer);
-  hb_buffer_set_flags (reconstruction, hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY);
+  hb_buffer_set_flags (reconstruction, (hb_buffer_flags_t (hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY)));
   hb_segment_properties_t props;
   hb_buffer_get_segment_properties (buffer, &props);
   hb_buffer_set_segment_properties (fragments[0], &props);
@@ -286,7 +289,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t        *buffer,
       assert (text_start < text_end);
 
       if (0)
-       printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end);
+       printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end);
 
 #if 0
       hb_buffer_flags_t flags = hb_buffer_get_flags (fragment);
@@ -307,22 +310,16 @@ buffer_verify_unsafe_to_concat (hb_buffer_t        *buffer,
 
   bool ret = true;
   hb_buffer_diff_flags_t diff;
-
   /*
    * Shape the two fragment streams.
    */
-  if (!hb_shape_full (font, fragments[0], features, num_features, shapers))
-  {
-    buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
-    ret = false;
+  if (!hb_shape_full (font, fragments[0], features, num_features, shapers) ||
+      !fragments[0]->successful || fragments[0]->shaping_failed)
     goto out;
-  }
-  if (!hb_shape_full (font, fragments[1], features, num_features, shapers))
-  {
-    buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
-    ret = false;
+
+  if (!hb_shape_full (font, fragments[1], features, num_features, shapers) ||
+      !fragments[1]->successful || fragments[1]->shaping_failed)
     goto out;
-  }
 
   if (!forward)
   {
@@ -362,21 +359,23 @@ buffer_verify_unsafe_to_concat (hb_buffer_t        *buffer,
     hb_buffer_reverse (reconstruction);
   }
 
-  /*
-   * Diff results.
-   */
-  diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
-  if (diff)
+  if (likely (reconstruction->successful))
   {
-    buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed.");
-    ret = false;
+    /*
+     * Diff results.
+     */
+    diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
+    if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH)
+    {
+      buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed.");
+      ret = false;
 
-    /* Return the reconstructed result instead so it can be inspected. */
-    hb_buffer_set_length (buffer, 0);
-    hb_buffer_append (buffer, reconstruction, 0, -1);
+      /* Return the reconstructed result instead so it can be inspected. */
+      hb_buffer_set_length (buffer, 0);
+      hb_buffer_append (buffer, reconstruction, 0, -1);
+    }
   }
 
-
 out:
   hb_buffer_destroy (reconstruction);
   hb_buffer_destroy (fragments[0]);
@@ -397,10 +396,12 @@ hb_buffer_t::verify (hb_buffer_t        *text_buffer,
     ret = false;
   if (!buffer_verify_unsafe_to_break (this, text_buffer, font, features, num_features, shapers))
     ret = false;
-  if (!buffer_verify_unsafe_to_concat (this, text_buffer, font, features, num_features, shapers))
+  if ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) != 0 &&
+      !buffer_verify_unsafe_to_concat (this, text_buffer, font, features, num_features, shapers))
     ret = false;
   if (!ret)
   {
+#ifndef HB_NO_BUFFER_SERIALIZE
     unsigned len = text_buffer->len;
     hb_vector_t<char> bytes;
     if (likely (bytes.resize (len * 10 + 16)))
@@ -413,6 +414,7 @@ hb_buffer_t::verify (hb_buffer_t        *text_buffer,
                                   HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS);
       buffer_verify_error (this, font, BUFFER_VERIFY_ERROR "text was: %s.", bytes.arrayZ);
     }
+#endif
   }
   return ret;
 }
index d36fcfd..934c6c2 100644 (file)
  * Buffers serve a dual role in HarfBuzz; before shaping, they hold
  * the input characters that are passed to hb_shape(), and after
  * shaping they hold the output glyphs.
+ *
+ * The input buffer is a sequence of Unicode codepoints, with
+ * associated attributes such as direction and script.  The output
+ * buffer is a sequence of glyphs, with associated attributes such
+ * as position and cluster.
  **/
 
 
@@ -51,7 +56,7 @@
  * Checks the equality of two #hb_segment_properties_t's.
  *
  * Return value:
- * %true if all properties of @a equal those of @b, %false otherwise.
+ * `true` if all properties of @a equal those of @b, `false` otherwise.
  *
  * Since: 0.9.7
  **/
@@ -81,8 +86,8 @@ hb_segment_properties_equal (const hb_segment_properties_t *a,
 unsigned int
 hb_segment_properties_hash (const hb_segment_properties_t *p)
 {
-  return (unsigned int) p->direction ^
-        (unsigned int) p->script ^
+  return ((unsigned int) p->direction * 31 +
+         (unsigned int) p->script) * 31 +
         (intptr_t) (p->language);
 }
 
@@ -172,12 +177,13 @@ hb_buffer_t::enlarge (unsigned int size)
   while (size >= new_allocated)
     new_allocated += (new_allocated >> 1) + 32;
 
-  static_assert ((sizeof (info[0]) == sizeof (pos[0])), "");
-  if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]))))
+  unsigned new_bytes;
+  if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]), &new_bytes)))
     goto done;
 
-  new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_allocated * sizeof (pos[0]));
-  new_info = (hb_glyph_info_t *) hb_realloc (info, new_allocated * sizeof (info[0]));
+  static_assert (sizeof (info[0]) == sizeof (pos[0]), "");
+  new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_bytes);
+  new_info = (hb_glyph_info_t *) hb_realloc (info, new_bytes);
 
 done:
   if (unlikely (!new_pos || !new_info))
@@ -208,7 +214,7 @@ hb_buffer_t::make_room_for (unsigned int num_in,
     assert (have_output);
 
     out_info = (hb_glyph_info_t *) pos;
-    memcpy (out_info, info, out_len * sizeof (out_info[0]));
+    hb_memcpy (out_info, info, out_len * sizeof (out_info[0]));
   }
 
   return true;
@@ -229,7 +235,7 @@ hb_buffer_t::shift_forward (unsigned int count)
      * 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]));
+    hb_memset (info + len, 0, (idx + count - len) * sizeof (info[0]));
   }
   len += count;
   idx += count;
@@ -262,7 +268,7 @@ hb_buffer_t::similar (const hb_buffer_t &src)
   unicode = hb_unicode_funcs_reference (src.unicode);
   flags = src.flags;
   cluster_level = src.cluster_level;
-  replacement = src.invisible;
+  replacement = src.replacement;
   invisible = src.invisible;
   not_found = src.not_found;
 }
@@ -289,17 +295,17 @@ hb_buffer_t::clear ()
   props = default_props;
 
   successful = true;
+  shaping_failed = false;
   have_output = false;
   have_positions = false;
 
   idx = 0;
   len = 0;
   out_len = 0;
-
   out_info = info;
 
-  memset (context, 0, sizeof context);
-  memset (context_len, 0, sizeof context_len);
+  hb_memset (context, 0, sizeof context);
+  hb_memset (context_len, 0, sizeof context_len);
 
   deallocate_var_all ();
   serial = 0;
@@ -311,16 +317,16 @@ hb_buffer_t::enter ()
 {
   deallocate_var_all ();
   serial = 0;
+  shaping_failed = false;
   scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
-  if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR)))
+  unsigned mul;
+  if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR, &mul)))
   {
-    max_len = hb_max (len * HB_BUFFER_MAX_LEN_FACTOR,
-                     (unsigned) HB_BUFFER_MAX_LEN_MIN);
+    max_len = hb_max (mul, (unsigned) HB_BUFFER_MAX_LEN_MIN);
   }
-  if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_OPS_FACTOR)))
+  if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_OPS_FACTOR, &mul)))
   {
-    max_ops = hb_max (len * HB_BUFFER_MAX_OPS_FACTOR,
-                     (unsigned) HB_BUFFER_MAX_OPS_MIN);
+    max_ops = hb_max (mul, (unsigned) HB_BUFFER_MAX_OPS_MIN);
   }
 }
 void
@@ -330,6 +336,7 @@ hb_buffer_t::leave ()
   max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
   deallocate_var_all ();
   serial = 0;
+  // Intentionally not reseting shaping_failed, such that it can be inspected.
 }
 
 
@@ -343,7 +350,7 @@ hb_buffer_t::add (hb_codepoint_t  codepoint,
 
   glyph = &info[len];
 
-  memset (glyph, 0, sizeof (*glyph));
+  hb_memset (glyph, 0, sizeof (*glyph));
   glyph->codepoint = codepoint;
   glyph->mask = 0;
   glyph->cluster = cluster;
@@ -385,9 +392,11 @@ hb_buffer_t::clear_positions ()
   hb_memset (pos, 0, sizeof (pos[0]) * len);
 }
 
-void
+bool
 hb_buffer_t::sync ()
 {
+  bool ret = false;
+
   assert (have_output);
 
   assert (idx <= len);
@@ -401,11 +410,39 @@ hb_buffer_t::sync ()
     info = out_info;
   }
   len = out_len;
+  ret = true;
 
 reset:
   have_output = false;
   out_len = 0;
+  out_info = info;
   idx = 0;
+
+  return ret;
+}
+
+int
+hb_buffer_t::sync_so_far ()
+{
+  bool had_output = have_output;
+  unsigned out_i = out_len;
+  unsigned i = idx;
+  unsigned old_idx = idx;
+
+  if (sync ())
+    idx = out_i;
+  else
+    idx = i;
+
+  if (had_output)
+  {
+    have_output = true;
+    out_len = idx;
+  }
+
+  assert (idx <= len);
+
+  return idx - old_idx;
 }
 
 bool
@@ -462,12 +499,12 @@ hb_buffer_t::set_masks (hb_mask_t    value,
                        unsigned int cluster_start,
                        unsigned int cluster_end)
 {
-  hb_mask_t not_mask = ~mask;
-  value &= mask;
-
   if (!mask)
     return;
 
+  hb_mask_t not_mask = ~mask;
+  value &= mask;
+
   unsigned int count = len;
   for (unsigned int i = 0; i < count; i++)
     if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
@@ -490,15 +527,17 @@ hb_buffer_t::merge_clusters_impl (unsigned int start,
     cluster = hb_min (cluster, info[i].cluster);
 
   /* Extend end */
-  while (end < len && info[end - 1].cluster == info[end].cluster)
-    end++;
+  if (cluster != info[end - 1].cluster)
+    while (end < len && info[end - 1].cluster == info[end].cluster)
+      end++;
 
   /* Extend start */
-  while (idx < start && info[start - 1].cluster == info[start].cluster)
-    start--;
+  if (cluster != info[start].cluster)
+    while (idx < start && info[start - 1].cluster == info[start].cluster)
+      start--;
 
   /* If we hit the start of buffer, continue in out-buffer. */
-  if (idx == start)
+  if (idx == start && info[start].cluster != cluster)
     for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
       set_cluster (out_info[i - 1], cluster);
 
@@ -542,7 +581,8 @@ hb_buffer_t::delete_glyph ()
   /* The logic here is duplicated in hb_ot_hide_default_ignorables(). */
 
   unsigned int cluster = info[idx].cluster;
-  if (idx + 1 < len && cluster == info[idx + 1].cluster)
+  if ((idx + 1 < len && cluster == info[idx + 1].cluster) ||
+      (out_len && cluster == out_info[out_len - 1].cluster))
   {
     /* Cluster survives; do nothing. */
     goto done;
@@ -573,6 +613,53 @@ done:
 }
 
 void
+hb_buffer_t::delete_glyphs_inplace (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 = len;
+  for (unsigned int i = 0; i < count; i++)
+  {
+    if (filter (&info[i]))
+    {
+      /* Merge clusters.
+       * Same logic as 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--)
+           set_cluster (info[k - 1], cluster, mask);
+       }
+       continue;
+      }
+
+      if (i + 1 < count)
+       merge_clusters (i, i + 2); /* Merge cluster forward. */
+
+      continue;
+    }
+
+    if (j != i)
+    {
+      info[j] = info[i];
+      pos[j] = pos[i];
+    }
+    j++;
+  }
+  len = j;
+}
+
+void
 hb_buffer_t::guess_segment_properties ()
 {
   assert_unicode ();
@@ -623,6 +710,7 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
   HB_SEGMENT_PROPERTIES_DEFAULT,
 
   false, /* successful */
+  true, /* shaping_failed */
   false, /* have_output */
   true  /* have_positions */
 
@@ -631,16 +719,16 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
 
 
 /**
- * hb_buffer_create: (Xconstructor)
+ * hb_buffer_create:
  *
  * Creates a new #hb_buffer_t with all properties to defaults.
  *
  * Return value: (transfer full):
  * A newly allocated #hb_buffer_t with a reference count of 1. The initial
  * reference count should be released with hb_buffer_destroy() when you are done
- * using the #hb_buffer_t. This function never returns %NULL. If memory cannot
+ * using the #hb_buffer_t. This function never returns `NULL`. If memory cannot
  * be allocated, a special #hb_buffer_t object will be returned on which
- * hb_buffer_allocation_successful() returns %false.
+ * hb_buffer_allocation_successful() returns `false`.
  *
  * Since: 0.9.2
  **/
@@ -770,7 +858,7 @@ hb_buffer_destroy (hb_buffer_t *buffer)
  *
  * Attaches a user-data key/data pair to the specified buffer. 
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -797,7 +885,7 @@ hb_buffer_set_user_data (hb_buffer_t        *buffer,
  * Since: 0.9.2
  **/
 void *
-hb_buffer_get_user_data (hb_buffer_t        *buffer,
+hb_buffer_get_user_data (const hb_buffer_t  *buffer,
                         hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (buffer, key);
@@ -812,6 +900,32 @@ hb_buffer_get_user_data (hb_buffer_t        *buffer,
  * Sets the type of @buffer contents. Buffers are either empty, contain
  * characters (before shaping), or contain glyphs (the result of shaping).
  *
+ * You rarely need to call this function, since a number of other
+ * functions transition the content type for you. Namely:
+ *
+ * - A newly created buffer starts with content type
+ *   %HB_BUFFER_CONTENT_TYPE_INVALID. Calling hb_buffer_reset(),
+ *   hb_buffer_clear_contents(), as well as calling hb_buffer_set_length()
+ *   with an argument of zero all set the buffer content type to invalid
+ *   as well.
+ *
+ * - Calling hb_buffer_add_utf8(), hb_buffer_add_utf16(),
+ *   hb_buffer_add_utf32(), hb_buffer_add_codepoints() and
+ *   hb_buffer_add_latin1() expect that buffer is either empty and
+ *   have a content type of invalid, or that buffer content type is
+ *   %HB_BUFFER_CONTENT_TYPE_UNICODE, and they also set the content
+ *   type to Unicode if they added anything to an empty buffer.
+ *
+ * - Finally hb_shape() and hb_shape_full() expect that the buffer
+ *   is either empty and have content type of invalid, or that buffer
+ *   content type is %HB_BUFFER_CONTENT_TYPE_UNICODE, and upon
+ *   success they set the buffer content type to
+ *   %HB_BUFFER_CONTENT_TYPE_GLYPHS.
+ *
+ * The above transitions are designed such that one can use a buffer
+ * in a loop of "reset : add-text : shape" without needing to ever
+ * modify the content type manually.
+ *
  * Since: 0.9.5
  **/
 void
@@ -834,7 +948,7 @@ hb_buffer_set_content_type (hb_buffer_t              *buffer,
  * Since: 0.9.5
  **/
 hb_buffer_content_type_t
-hb_buffer_get_content_type (hb_buffer_t *buffer)
+hb_buffer_get_content_type (const hb_buffer_t *buffer)
 {
   return buffer->content_type;
 }
@@ -876,7 +990,7 @@ hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
  * Since: 0.9.2
  **/
 hb_unicode_funcs_t *
-hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer)
+hb_buffer_get_unicode_funcs (const hb_buffer_t *buffer)
 {
   return buffer->unicode;
 }
@@ -899,7 +1013,6 @@ hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer)
 void
 hb_buffer_set_direction (hb_buffer_t    *buffer,
                         hb_direction_t  direction)
-
 {
   if (unlikely (hb_object_is_immutable (buffer)))
     return;
@@ -919,7 +1032,7 @@ hb_buffer_set_direction (hb_buffer_t    *buffer,
  * Since: 0.9.2
  **/
 hb_direction_t
-hb_buffer_get_direction (hb_buffer_t    *buffer)
+hb_buffer_get_direction (const hb_buffer_t *buffer)
 {
   return buffer->props.direction;
 }
@@ -963,7 +1076,7 @@ hb_buffer_set_script (hb_buffer_t *buffer,
  * Since: 0.9.2
  **/
 hb_script_t
-hb_buffer_get_script (hb_buffer_t *buffer)
+hb_buffer_get_script (const hb_buffer_t *buffer)
 {
   return buffer->props.script;
 }
@@ -1007,7 +1120,7 @@ hb_buffer_set_language (hb_buffer_t   *buffer,
  * Since: 0.9.2
  **/
 hb_language_t
-hb_buffer_get_language (hb_buffer_t *buffer)
+hb_buffer_get_language (const hb_buffer_t *buffer)
 {
   return buffer->props.language;
 }
@@ -1043,7 +1156,7 @@ hb_buffer_set_segment_properties (hb_buffer_t *buffer,
  * Since: 0.9.7
  **/
 void
-hb_buffer_get_segment_properties (hb_buffer_t *buffer,
+hb_buffer_get_segment_properties (const hb_buffer_t *buffer,
                                  hb_segment_properties_t *props)
 {
   *props = buffer->props;
@@ -1081,7 +1194,7 @@ hb_buffer_set_flags (hb_buffer_t       *buffer,
  * Since: 0.9.7
  **/
 hb_buffer_flags_t
-hb_buffer_get_flags (hb_buffer_t *buffer)
+hb_buffer_get_flags (const hb_buffer_t *buffer)
 {
   return buffer->flags;
 }
@@ -1120,7 +1233,7 @@ hb_buffer_set_cluster_level (hb_buffer_t               *buffer,
  * Since: 0.9.42
  **/
 hb_buffer_cluster_level_t
-hb_buffer_get_cluster_level (hb_buffer_t *buffer)
+hb_buffer_get_cluster_level (const hb_buffer_t *buffer)
 {
   return buffer->cluster_level;
 }
@@ -1161,7 +1274,7 @@ hb_buffer_set_replacement_codepoint (hb_buffer_t    *buffer,
  * Since: 0.9.31
  **/
 hb_codepoint_t
-hb_buffer_get_replacement_codepoint (hb_buffer_t    *buffer)
+hb_buffer_get_replacement_codepoint (const hb_buffer_t *buffer)
 {
   return buffer->replacement;
 }
@@ -1201,7 +1314,7 @@ hb_buffer_set_invisible_glyph (hb_buffer_t    *buffer,
  * Since: 2.0.0
  **/
 hb_codepoint_t
-hb_buffer_get_invisible_glyph (hb_buffer_t    *buffer)
+hb_buffer_get_invisible_glyph (const hb_buffer_t *buffer)
 {
   return buffer->invisible;
 }
@@ -1214,7 +1327,7 @@ hb_buffer_get_invisible_glyph (hb_buffer_t    *buffer)
  * Sets the #hb_codepoint_t that replaces characters not found in
  * the font during shaping.
  *
- * The not-found glyph defaults to zero, sometimes knows as the
+ * The not-found glyph defaults to zero, sometimes known as the
  * ".notdef" glyph.  This API allows for differentiating the two.
  *
  * Since: 3.1.0
@@ -1241,7 +1354,7 @@ hb_buffer_set_not_found_glyph (hb_buffer_t    *buffer,
  * Since: 3.1.0
  **/
 hb_codepoint_t
-hb_buffer_get_not_found_glyph (hb_buffer_t    *buffer)
+hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer)
 {
   return buffer->not_found;
 }
@@ -1273,7 +1386,7 @@ hb_buffer_clear_contents (hb_buffer_t *buffer)
  * Pre allocates memory for @buffer to fit at least @size number of items.
  *
  * Return value:
- * %true if @buffer memory allocation succeeded, %false otherwise
+ * `true` if @buffer memory allocation succeeded, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1290,7 +1403,7 @@ hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
  * Check if allocating memory for the buffer succeeded.
  *
  * Return value:
- * %true if @buffer memory allocation succeeded, %false otherwise.
+ * `true` if @buffer memory allocation succeeded, `false` otherwise.
  *
  * Since: 0.9.2
  **/
@@ -1335,7 +1448,7 @@ hb_buffer_add (hb_buffer_t    *buffer,
  * end.
  *
  * Return value:
- * %true if @buffer memory allocation succeeded, %false otherwise.
+ * `true` if @buffer memory allocation succeeded, `false` otherwise.
  *
  * Since: 0.9.2
  **/
@@ -1351,9 +1464,9 @@ hb_buffer_set_length (hb_buffer_t  *buffer,
 
   /* Wipe the new space */
   if (length > buffer->len) {
-    memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
+    hb_memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
     if (buffer->have_positions)
-      memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
+      hb_memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
   }
 
   buffer->len = length;
@@ -1381,7 +1494,7 @@ hb_buffer_set_length (hb_buffer_t  *buffer,
  * Since: 0.9.2
  **/
 unsigned int
-hb_buffer_get_length (hb_buffer_t *buffer)
+hb_buffer_get_length (const hb_buffer_t *buffer)
 {
   return buffer->len;
 }
@@ -1421,7 +1534,7 @@ hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
  * If buffer did not have positions before, the positions will be
  * initialized to zeros, unless this function is called from
  * within a buffer message callback (see hb_buffer_set_message_func()),
- * in which case %NULL is returned.
+ * in which case `NULL` is returned.
  *
  * Return value: (transfer none) (array length=length):
  * The @buffer glyph position array.
@@ -1456,7 +1569,7 @@ hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
  * and cleared of position data when hb_buffer_clear_contents() is called.
  *
  * Return value:
- * %true if the @buffer has position array, %false otherwise.
+ * `true` if the @buffer has position array, `false` otherwise.
  *
  * Since: 2.7.3
  **/
@@ -1640,10 +1753,10 @@ hb_buffer_add_utf (hb_buffer_t  *buffer,
  * @buffer: An #hb_buffer_t
  * @text: (array length=text_length) (element-type uint8_t): An array of UTF-8
  *               characters to append.
- * @text_length: The length of the @text, or -1 if it is %NULL terminated.
+ * @text_length: The length of the @text, or -1 if it is `NULL` terminated.
  * @item_offset: The offset of the first character to add to the @buffer.
  * @item_length: The number of characters to add to the @buffer, or -1 for the
- *               end of @text (assuming it is %NULL terminated).
+ *               end of @text (assuming it is `NULL` terminated).
  *
  * See hb_buffer_add_codepoints().
  *
@@ -1666,10 +1779,10 @@ hb_buffer_add_utf8 (hb_buffer_t  *buffer,
  * hb_buffer_add_utf16:
  * @buffer: An #hb_buffer_t
  * @text: (array length=text_length): An array of UTF-16 characters to append
- * @text_length: The length of the @text, or -1 if it is %NULL terminated
+ * @text_length: The length of the @text, or -1 if it is `NULL` terminated
  * @item_offset: The offset of the first character to add to the @buffer
  * @item_length: The number of characters to add to the @buffer, or -1 for the
- *               end of @text (assuming it is %NULL terminated)
+ *               end of @text (assuming it is `NULL` terminated)
  *
  * See hb_buffer_add_codepoints().
  *
@@ -1692,10 +1805,10 @@ hb_buffer_add_utf16 (hb_buffer_t    *buffer,
  * hb_buffer_add_utf32:
  * @buffer: An #hb_buffer_t
  * @text: (array length=text_length): An array of UTF-32 characters to append
- * @text_length: The length of the @text, or -1 if it is %NULL terminated
+ * @text_length: The length of the @text, or -1 if it is `NULL` terminated
  * @item_offset: The offset of the first character to add to the @buffer
  * @item_length: The number of characters to add to the @buffer, or -1 for the
- *               end of @text (assuming it is %NULL terminated)
+ *               end of @text (assuming it is `NULL` terminated)
  *
  * See hb_buffer_add_codepoints().
  *
@@ -1719,10 +1832,10 @@ hb_buffer_add_utf32 (hb_buffer_t    *buffer,
  * @buffer: An #hb_buffer_t
  * @text: (array length=text_length) (element-type uint8_t): an array of UTF-8
  *               characters to append
- * @text_length: the length of the @text, or -1 if it is %NULL terminated
+ * @text_length: the length of the @text, or -1 if it is `NULL` terminated
  * @item_offset: the offset of the first character to add to the @buffer
  * @item_length: the number of characters to add to the @buffer, or -1 for the
- *               end of @text (assuming it is %NULL terminated)
+ *               end of @text (assuming it is `NULL` terminated)
  *
  * Similar to hb_buffer_add_codepoints(), but allows only access to first 256
  * Unicode code points that can fit in 8-bit strings.
@@ -1745,10 +1858,10 @@ hb_buffer_add_latin1 (hb_buffer_t   *buffer,
  * hb_buffer_add_codepoints:
  * @buffer: a #hb_buffer_t to append characters to.
  * @text: (array length=text_length): an array of Unicode code points to append.
- * @text_length: the length of the @text, or -1 if it is %NULL terminated.
+ * @text_length: the length of the @text, or -1 if it is `NULL` terminated.
  * @item_offset: the offset of the first code point to add to the @buffer.
  * @item_length: the number of code points to add to the @buffer, or -1 for the
- *               end of @text (assuming it is %NULL terminated).
+ *               end of @text (assuming it is `NULL` terminated).
  *
  * Appends characters from @text array to @buffer. The @item_offset is the
  * position of the first character from @text that will be appended, and
@@ -1761,7 +1874,9 @@ hb_buffer_add_latin1 (hb_buffer_t   *buffer,
  * marks at stat of run.
  *
  * This function does not check the validity of @text, it is up to the caller
- * to ensure it contains a valid Unicode code points.
+ * to ensure it contains a valid Unicode scalar values.  In contrast,
+ * hb_buffer_add_utf32() can be used that takes similar input but performs
+ * sanity-check on the input.
  *
  * Since: 0.9.31
  **/
@@ -1824,9 +1939,9 @@ hb_buffer_append (hb_buffer_t *buffer,
 
   hb_segment_properties_overlay (&buffer->props, &source->props);
 
-  memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
+  hb_memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
   if (buffer->have_positions)
-    memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
+    hb_memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
 
   if (source->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE)
   {
@@ -1961,7 +2076,7 @@ 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.
+ * @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepoint_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
@@ -2014,7 +2129,7 @@ hb_buffer_diff (hb_buffer_t *buffer,
       result |= HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH;
     if (buf_info->cluster != ref_info->cluster)
       result |= HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH;
-    if ((buf_info->mask & ~ref_info->mask & HB_GLYPH_FLAG_DEFINED))
+    if ((buf_info->mask ^ ref_info->mask) & HB_GLYPH_FLAG_DEFINED)
       result |= HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH;
     if (contains && ref_info->codepoint == dottedcircle_glyph)
       result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
@@ -2069,6 +2184,13 @@ hb_buffer_set_message_func (hb_buffer_t *buffer,
                            hb_buffer_message_func_t func,
                            void *user_data, hb_destroy_func_t destroy)
 {
+  if (unlikely (hb_object_is_immutable (buffer)))
+  {
+    if (destroy)
+      destroy (user_data);
+    return;
+  }
+
   if (buffer->message_destroy)
     buffer->message_destroy (buffer->message_data);
 
@@ -2085,8 +2207,16 @@ hb_buffer_set_message_func (hb_buffer_t *buffer,
 bool
 hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
 {
+  assert (!have_output || (out_info == info && out_len == idx));
+
+  message_depth++;
+
   char buf[100];
   vsnprintf (buf, sizeof (buf), fmt, ap);
-  return (bool) this->message_func (this, font, buf, this->message_data);
+  bool ret = (bool) this->message_func (this, font, buf, this->message_data);
+
+  message_depth--;
+
+  return ret;
 }
 #endif
index ee72dfa..3573127 100644 (file)
@@ -99,7 +99,7 @@ typedef struct hb_glyph_info_t {
  *                                layout, by avoiding re-shaping of each line
  *                                after line-breaking, by limiting the
  *                                reshaping to a small piece around the
- *                                breaking positin only, even if the breaking
+ *                                breaking position only, even if the breaking
  *                                position carries the
  *                                #HB_GLYPH_FLAG_UNSAFE_TO_BREAK or when
  *                                hyphenation or other text transformation
@@ -117,7 +117,7 @@ typedef struct hb_glyph_info_t {
  *                                from there, and repeat.
  *                                At the start of next line a similar algorithm can
  *                                be implemented. That is: 1. Iterate forward from
- *                                the line-break position untill the first cluster
+ *                                the line-break position until the first cluster
  *                                start position that is NOT unsafe-to-concat, 2.
  *                                shape the segment from beginning of the line to
  *                                that position, 3. check whether the resulting
@@ -137,7 +137,20 @@ typedef struct hb_glyph_info_t {
  *                                clusters.
  *                                The #HB_GLYPH_FLAG_UNSAFE_TO_BREAK flag will
  *                                always imply this flag.
- *                                Since: 3.3.0
+ *                                To use this flag, you must enable the buffer flag
+ *                                @HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT during
+ *                                shaping, otherwise the buffer flag will not be
+ *                                reliably produced.
+ *                                Since: 4.0.0
+ * @HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL: In scripts that use elongation (Arabic,
+                                  Mongolian, Syriac, etc.), this flag signifies
+                                  that it is safe to insert a U+0640 TATWEEL
+                                  character before this cluster for elongation.
+                                  This flag does not determine the
+                                  script-specific elongation places, but only
+                                  when it is safe to do the elongation without
+                                  interrupting text shaping.
+                                  Since: 5.1.0
  * @HB_GLYPH_FLAG_DEFINED: All the currently defined flags.
  *
  * Flags for #hb_glyph_info_t.
@@ -145,10 +158,11 @@ typedef struct hb_glyph_info_t {
  * Since: 1.5.0
  */
 typedef enum { /*< flags >*/
-  HB_GLYPH_FLAG_UNSAFE_TO_BREAK                = 0x00000001,
-  HB_GLYPH_FLAG_UNSAFE_TO_CONCAT       = 0x00000002,
+  HB_GLYPH_FLAG_UNSAFE_TO_BREAK                        = 0x00000001,
+  HB_GLYPH_FLAG_UNSAFE_TO_CONCAT               = 0x00000002,
+  HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL         = 0x00000004,
 
-  HB_GLYPH_FLAG_DEFINED                        = 0x00000003 /* OR of all defined flags */
+  HB_GLYPH_FLAG_DEFINED                                = 0x00000007 /* OR of all defined flags */
 } hb_glyph_flags_t;
 
 HB_EXTERN hb_glyph_flags_t
@@ -262,7 +276,7 @@ hb_buffer_set_user_data (hb_buffer_t        *buffer,
                         hb_bool_t           replace);
 
 HB_EXTERN void *
-hb_buffer_get_user_data (hb_buffer_t        *buffer,
+hb_buffer_get_user_data (const hb_buffer_t  *buffer,
                         hb_user_data_key_t *key);
 
 
@@ -285,7 +299,7 @@ hb_buffer_set_content_type (hb_buffer_t              *buffer,
                            hb_buffer_content_type_t  content_type);
 
 HB_EXTERN hb_buffer_content_type_t
-hb_buffer_get_content_type (hb_buffer_t *buffer);
+hb_buffer_get_content_type (const hb_buffer_t *buffer);
 
 
 HB_EXTERN void
@@ -293,21 +307,21 @@ hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
                             hb_unicode_funcs_t *unicode_funcs);
 
 HB_EXTERN hb_unicode_funcs_t *
-hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer);
+hb_buffer_get_unicode_funcs (const hb_buffer_t  *buffer);
 
 HB_EXTERN void
 hb_buffer_set_direction (hb_buffer_t    *buffer,
                         hb_direction_t  direction);
 
 HB_EXTERN hb_direction_t
-hb_buffer_get_direction (hb_buffer_t *buffer);
+hb_buffer_get_direction (const hb_buffer_t *buffer);
 
 HB_EXTERN void
 hb_buffer_set_script (hb_buffer_t *buffer,
                      hb_script_t  script);
 
 HB_EXTERN hb_script_t
-hb_buffer_get_script (hb_buffer_t *buffer);
+hb_buffer_get_script (const hb_buffer_t *buffer);
 
 HB_EXTERN void
 hb_buffer_set_language (hb_buffer_t   *buffer,
@@ -315,14 +329,14 @@ hb_buffer_set_language (hb_buffer_t   *buffer,
 
 
 HB_EXTERN hb_language_t
-hb_buffer_get_language (hb_buffer_t *buffer);
+hb_buffer_get_language (const hb_buffer_t *buffer);
 
 HB_EXTERN void
 hb_buffer_set_segment_properties (hb_buffer_t *buffer,
                                  const hb_segment_properties_t *props);
 
 HB_EXTERN void
-hb_buffer_get_segment_properties (hb_buffer_t *buffer,
+hb_buffer_get_segment_properties (const hb_buffer_t *buffer,
                                  hb_segment_properties_t *props);
 
 HB_EXTERN void
@@ -365,6 +379,15 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
  *                      handler is installed on the buffer, or a message is written
  *                      to standard error.  In either case, the shaping result might
  *                      be modified to show the failed output. Since: 3.4.0
+ * @HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT:
+ *                      flag indicating that the @HB_GLYPH_FLAG_UNSAFE_TO_CONCAT
+ *                      glyph-flag should be produced by the shaper. By default
+ *                      it will not be produced since it incurs a cost. Since: 4.0.0
+ * @HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL:
+ *                      flag indicating that the @HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL
+ *                      glyph-flag should be produced by the shaper. By default
+ *                      it will not be produced. Since: 5.1.0
+ * @HB_BUFFER_FLAG_DEFINED: All currently defined flags: Since: 4.4.0
  *
  * Flags for #hb_buffer_t.
  *
@@ -377,7 +400,11 @@ typedef enum { /*< flags >*/
   HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES   = 0x00000004u,
   HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES     = 0x00000008u,
   HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE   = 0x00000010u,
-  HB_BUFFER_FLAG_VERIFY                                = 0x00000020u
+  HB_BUFFER_FLAG_VERIFY                                = 0x00000020u,
+  HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT      = 0x00000040u,
+  HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL        = 0x00000080u,
+
+  HB_BUFFER_FLAG_DEFINED                       = 0x000000FFu
 } hb_buffer_flags_t;
 
 HB_EXTERN void
@@ -385,7 +412,7 @@ hb_buffer_set_flags (hb_buffer_t       *buffer,
                     hb_buffer_flags_t  flags);
 
 HB_EXTERN hb_buffer_flags_t
-hb_buffer_get_flags (hb_buffer_t *buffer);
+hb_buffer_get_flags (const hb_buffer_t *buffer);
 
 /**
  * hb_buffer_cluster_level_t:
@@ -427,7 +454,7 @@ hb_buffer_set_cluster_level (hb_buffer_t               *buffer,
                             hb_buffer_cluster_level_t  cluster_level);
 
 HB_EXTERN hb_buffer_cluster_level_t
-hb_buffer_get_cluster_level (hb_buffer_t *buffer);
+hb_buffer_get_cluster_level (const hb_buffer_t *buffer);
 
 /**
  * HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT:
@@ -444,21 +471,21 @@ hb_buffer_set_replacement_codepoint (hb_buffer_t    *buffer,
                                     hb_codepoint_t  replacement);
 
 HB_EXTERN hb_codepoint_t
-hb_buffer_get_replacement_codepoint (hb_buffer_t    *buffer);
+hb_buffer_get_replacement_codepoint (const 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_buffer_get_invisible_glyph (const hb_buffer_t *buffer);
 
 HB_EXTERN void
 hb_buffer_set_not_found_glyph (hb_buffer_t    *buffer,
                               hb_codepoint_t  not_found);
 
 HB_EXTERN hb_codepoint_t
-hb_buffer_get_not_found_glyph (hb_buffer_t    *buffer);
+hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer);
 
 
 /*
@@ -540,7 +567,7 @@ hb_buffer_set_length (hb_buffer_t  *buffer,
                      unsigned int  length);
 
 HB_EXTERN unsigned int
-hb_buffer_get_length (hb_buffer_t *buffer);
+hb_buffer_get_length (const hb_buffer_t *buffer);
 
 /* Getting glyphs out of the buffer */
 
@@ -574,6 +601,7 @@ hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
  * @HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS: serialize glyph flags. Since: 1.5.0
  * @HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES: do not serialize glyph advances,
  *  glyph offsets will reflect absolute glyph positions. Since: 1.8.0
+ * @HB_BUFFER_SERIALIZE_FLAG_DEFINED: All currently defined flags. Since: 4.4.0
  *
  * Flags that control what glyph information are serialized in hb_buffer_serialize_glyphs().
  *
@@ -586,7 +614,9 @@ typedef enum { /*< flags >*/
   HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES      = 0x00000004u,
   HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS       = 0x00000008u,
   HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS         = 0x00000010u,
-  HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES         = 0x00000020u
+  HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES         = 0x00000020u,
+
+  HB_BUFFER_SERIALIZE_FLAG_DEFINED             = 0x0000003Fu
 } hb_buffer_serialize_flags_t;
 
 /**
@@ -733,23 +763,23 @@ hb_buffer_diff (hb_buffer_t *buffer,
 
 
 /*
- * Debugging.
+ * Tracing.
  */
 
 /**
  * hb_buffer_message_func_t:
  * @buffer: An #hb_buffer_t to work upon
  * @font: The #hb_font_t the @buffer is shaped with
- * @message: %NULL-terminated message passed to the function
+ * @message: `NULL`-terminated message passed to the function
  * @user_data: User data pointer passed by the caller
  *
  * A callback method for #hb_buffer_t. The method gets called with the
  * #hb_buffer_t it was set on, the #hb_font_t the buffer is shaped with and a
  * message describing what step of the shaping process will be performed.
- * Returning %false from this method will skip this shaping step and move to
+ * Returning `false` from this method will skip this shaping step and move to
  * the next one.
  *
- * Return value: %true to perform the shaping step, %false to skip it.
+ * Return value: `true` to perform the shaping step, `false` to skip it.
  *
  * Since: 1.1.3
  */
index cc20f3a..f04ad58 100644 (file)
 
 #include "hb.hh"
 #include "hb-unicode.hh"
+#include "hb-set-digest.hh"
 
 
-#ifndef HB_BUFFER_MAX_LEN_FACTOR
-#define HB_BUFFER_MAX_LEN_FACTOR 64
-#endif
-#ifndef HB_BUFFER_MAX_LEN_MIN
-#define HB_BUFFER_MAX_LEN_MIN 16384
-#endif
-#ifndef HB_BUFFER_MAX_LEN_DEFAULT
-#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */
-#endif
-
-#ifndef HB_BUFFER_MAX_OPS_FACTOR
-#define HB_BUFFER_MAX_OPS_FACTOR 1024
-#endif
-#ifndef HB_BUFFER_MAX_OPS_MIN
-#define HB_BUFFER_MAX_OPS_MIN 16384
-#endif
-#ifndef HB_BUFFER_MAX_OPS_DEFAULT
-#define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF /* Shaping more than a billion operations? Let us know! */
-#endif
-
 static_assert ((sizeof (hb_glyph_info_t) == 20), "");
 static_assert ((sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)), "");
 
+HB_MARK_AS_FLAG_T (hb_glyph_flags_t);
 HB_MARK_AS_FLAG_T (hb_buffer_flags_t);
 HB_MARK_AS_FLAG_T (hb_buffer_serialize_flags_t);
 HB_MARK_AS_FLAG_T (hb_buffer_diff_flags_t);
@@ -69,12 +51,13 @@ enum hb_buffer_scratch_flags_t {
   HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT           = 0x00000008u,
   HB_BUFFER_SCRATCH_FLAG_HAS_CGJ                       = 0x00000010u,
   HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS               = 0x00000020u,
+  HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE           = 0x00000040u,
 
-  /* Reserved for complex shapers' internal use. */
-  HB_BUFFER_SCRATCH_FLAG_COMPLEX0                      = 0x01000000u,
-  HB_BUFFER_SCRATCH_FLAG_COMPLEX1                      = 0x02000000u,
-  HB_BUFFER_SCRATCH_FLAG_COMPLEX2                      = 0x04000000u,
-  HB_BUFFER_SCRATCH_FLAG_COMPLEX3                      = 0x08000000u,
+  /* Reserved for shapers' internal use. */
+  HB_BUFFER_SCRATCH_FLAG_SHAPER0                       = 0x01000000u,
+  HB_BUFFER_SCRATCH_FLAG_SHAPER1                       = 0x02000000u,
+  HB_BUFFER_SCRATCH_FLAG_SHAPER2                       = 0x04000000u,
+  HB_BUFFER_SCRATCH_FLAG_SHAPER3                       = 0x08000000u,
 };
 HB_MARK_AS_FLAG_T (hb_buffer_scratch_flags_t);
 
@@ -106,6 +89,7 @@ struct hb_buffer_t
   hb_segment_properties_t props; /* Script, language, direction */
 
   bool successful; /* Allocations successful */
+  bool shaping_failed; /* Shaping failure */
   bool have_output; /* Whether we have an output buffer going on */
   bool have_positions; /* Whether we have positions */
 
@@ -130,9 +114,7 @@ struct hb_buffer_t
    * Managed by enter / leave
    */
 
-#ifndef HB_NDEBUG
   uint8_t allocated_var_bits;
-#endif
   uint8_t serial;
   hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
   unsigned int max_len; /* Maximum allowed len. */
@@ -161,38 +143,40 @@ struct hb_buffer_t
 
   void allocate_var (unsigned int start, unsigned int count)
   {
-#ifndef HB_NDEBUG
     unsigned int end = start + count;
     assert (end <= 8);
     unsigned int bits = (1u<<end) - (1u<<start);
     assert (0 == (allocated_var_bits & bits));
     allocated_var_bits |= bits;
-#endif
+  }
+  bool try_allocate_var (unsigned int start, unsigned int count)
+  {
+    unsigned int end = start + count;
+    assert (end <= 8);
+    unsigned int bits = (1u<<end) - (1u<<start);
+    if (allocated_var_bits & bits)
+      return false;
+    allocated_var_bits |= bits;
+    return true;
   }
   void deallocate_var (unsigned int start, unsigned int count)
   {
-#ifndef HB_NDEBUG
     unsigned int end = start + count;
     assert (end <= 8);
     unsigned int bits = (1u<<end) - (1u<<start);
     assert (bits == (allocated_var_bits & bits));
     allocated_var_bits &= ~bits;
-#endif
   }
   void assert_var (unsigned int start, unsigned int count)
   {
-#ifndef HB_NDEBUG
     unsigned int end = start + count;
     assert (end <= 8);
-    unsigned int bits = (1u<<end) - (1u<<start);
+    HB_UNUSED unsigned int bits = (1u<<end) - (1u<<start);
     assert (bits == (allocated_var_bits & bits));
-#endif
   }
   void deallocate_var_all ()
   {
-#ifndef HB_NDEBUG
     allocated_var_bits = 0;
-#endif
   }
 
   hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; }
@@ -204,6 +188,14 @@ struct hb_buffer_t
   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]; }
 
+  hb_set_digest_t digest () const
+  {
+    hb_set_digest_t d;
+    d.init ();
+    d.add_array (&info[0].codepoint, len, sizeof (info[0]));
+    return d;
+  }
+
   HB_INTERNAL void similar (const hb_buffer_t &src);
   HB_INTERNAL void reset ();
   HB_INTERNAL void clear ();
@@ -285,7 +277,8 @@ struct hb_buffer_t
 
   HB_INTERNAL void guess_segment_properties ();
 
-  HB_INTERNAL void sync ();
+  HB_INTERNAL bool sync ();
+  HB_INTERNAL int sync_so_far ();
   HB_INTERNAL void clear_output ();
   HB_INTERNAL void clear_positions ();
 
@@ -398,6 +391,8 @@ struct hb_buffer_t
   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 ();
+  HB_INTERNAL void delete_glyphs_inplace (bool (*filter) (const hb_glyph_info_t *info));
+
 
 
   /* Adds glyph flags in mask to infos with clusters between start and end.
@@ -458,11 +453,27 @@ struct hb_buffer_t
                      start, end,
                      true);
   }
+  void safe_to_insert_tatweel (unsigned int start = 0, unsigned int end = -1)
+  {
+    if ((flags & HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL) == 0)
+    {
+      unsafe_to_break (start, end);
+      return;
+    }
+    _set_glyph_flags (HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL,
+                     start, end,
+                     true);
+  }
+#ifndef HB_OPTIMIZE_SIZE
+  HB_ALWAYS_INLINE
+#endif
   void unsafe_to_concat (unsigned int start = 0, unsigned int end = -1)
   {
+    if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0))
+      return;
     _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
                      start, end,
-                     true);
+                     false);
   }
   void unsafe_to_break_from_outbuffer (unsigned int start = 0, unsigned int end = -1)
   {
@@ -470,8 +481,13 @@ struct hb_buffer_t
                      start, end,
                      true, true);
   }
+#ifndef HB_OPTIMIZE_SIZE
+  HB_ALWAYS_INLINE
+#endif
   void unsafe_to_concat_from_outbuffer (unsigned int start = 0, unsigned int end = -1)
   {
+    if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0))
+      return;
     _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
                      start, end,
                      false, true);
@@ -483,6 +499,13 @@ struct hb_buffer_t
 
   HB_NODISCARD HB_INTERNAL bool enlarge (unsigned int size);
 
+  HB_NODISCARD bool resize (unsigned length)
+  {
+    assert (!have_output);
+    if (unlikely (!ensure (length))) return false;
+    len = length;
+    return true;
+  }
   HB_NODISCARD bool ensure (unsigned int size)
   { return likely (!size || size < allocated) ? true : enlarge (size); }
 
@@ -543,20 +566,16 @@ struct hb_buffer_t
   bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
   {
 #ifdef HB_NO_BUFFER_MESSAGE
-   return true;
+    return true;
 #else
-    if (!messaging ())
+    if (likely (!messaging ()))
       return true;
 
-    message_depth++;
-
     va_list ap;
     va_start (ap, fmt);
     bool ret = message_impl (font, fmt, ap);
     va_end (ap);
 
-    message_depth--;
-
     return ret;
 #endif
   }
@@ -575,21 +594,59 @@ struct hb_buffer_t
                          unsigned int cluster,
                          hb_mask_t mask)
   {
-    for (unsigned int i = start; i < end; i++)
-      if (cluster != infos[i].cluster)
+    if (unlikely (start == end))
+      return;
+
+    unsigned cluster_first = infos[start].cluster;
+    unsigned cluster_last = infos[end - 1].cluster;
+
+    if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS ||
+       (cluster != cluster_first && cluster != cluster_last))
+    {
+      for (unsigned int i = start; i < end; i++)
+       if (cluster != infos[i].cluster)
+       {
+         scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
+         infos[i].mask |= mask;
+       }
+      return;
+    }
+
+    /* Monotone clusters */
+
+    if (cluster == cluster_first)
+    {
+      for (unsigned int i = end; start < i && infos[i - 1].cluster != cluster_first; i--)
+      {
+       scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
+       infos[i - 1].mask |= mask;
+      }
+    }
+    else /* cluster == cluster_last */
+    {
+      for (unsigned int i = start; i < end && infos[i].cluster != cluster_last; i++)
       {
        scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
        infos[i].mask |= mask;
       }
+    }
   }
-  static unsigned
+  unsigned
   _infos_find_min_cluster (const hb_glyph_info_t *infos,
                           unsigned start, unsigned end,
                           unsigned cluster = UINT_MAX)
   {
-    for (unsigned int i = start; i < end; i++)
-      cluster = hb_min (cluster, infos[i].cluster);
-    return cluster;
+    if (unlikely (start == end))
+      return cluster;
+
+    if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
+    {
+      for (unsigned int i = start; i < end; i++)
+       cluster = hb_min (cluster, infos[i].cluster);
+      return cluster;
+    }
+
+    return hb_min (cluster, hb_min (infos[start].cluster, infos[end - 1].cluster));
   }
 
   void clear_glyph_flags (hb_mask_t mask = 0)
@@ -615,9 +672,10 @@ DECLARE_NULL_INSTANCE (hb_buffer_t);
 #define HB_BUFFER_XALLOCATE_VAR(b, func, var) \
   b->func (offsetof (hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), \
           sizeof (b->info[0].var))
-#define HB_BUFFER_ALLOCATE_VAR(b, var)         HB_BUFFER_XALLOCATE_VAR (b, allocate_var,   var ())
-#define HB_BUFFER_DEALLOCATE_VAR(b, var)       HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var ())
-#define HB_BUFFER_ASSERT_VAR(b, var)           HB_BUFFER_XALLOCATE_VAR (b, assert_var,     var ())
+#define HB_BUFFER_ALLOCATE_VAR(b, var)         HB_BUFFER_XALLOCATE_VAR (b, allocate_var,     var ())
+#define HB_BUFFER_TRY_ALLOCATE_VAR(b, var)     HB_BUFFER_XALLOCATE_VAR (b, try_allocate_var, var ())
+#define HB_BUFFER_DEALLOCATE_VAR(b, var)       HB_BUFFER_XALLOCATE_VAR (b, deallocate_var,   var ())
+#define HB_BUFFER_ASSERT_VAR(b, var)           HB_BUFFER_XALLOCATE_VAR (b, assert_var,       var ())
 
 
 #endif /* HB_BUFFER_HH */
index e617b75..6d8a54c 100644 (file)
 #include "hb.hh"
 
 
-/* Implements a lockfree cache for int->int functions. */
+/* Implements a lockfree cache for int->int functions.
+ *
+ * The cache is a fixed-size array of 16-bit or 32-bit integers.
+ * The key is split into two parts: the cache index and the rest.
+ *
+ * The cache index is used to index into the array.  The rest is used
+ * to store the key and the value.
+ *
+ * The value is stored in the least significant bits of the integer.
+ * The key is stored in the most significant bits of the integer.
+ * The key is shifted by cache_bits to the left to make room for the
+ * value.
+ */
 
-template <unsigned int key_bits, unsigned int value_bits, unsigned int cache_bits>
+template <unsigned int key_bits=16,
+        unsigned int value_bits=8 + 32 - key_bits,
+        unsigned int cache_bits=8,
+        bool thread_safe=true>
 struct hb_cache_t
 {
+  using item_t = typename std::conditional<thread_safe,
+                                          typename std::conditional<key_bits + value_bits - cache_bits <= 16,
+                                                                    hb_atomic_short_t,
+                                                                    hb_atomic_int_t>::type,
+                                          typename std::conditional<key_bits + value_bits - cache_bits <= 16,
+                                                                    short,
+                                                                    int>::type
+                                         >::type;
+
   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), "");
+  static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), "");
 
-  void init () { clear (); }
-  void fini () {}
+  hb_cache_t () { clear (); }
 
   void clear ()
   {
-    for (unsigned i = 0; i < ARRAY_LENGTH (values); i++)
-      values[i].set_relaxed (-1);
+    for (auto &v : values)
+      v = -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) ||
+    unsigned int v = values[k];
+    if ((key_bits + value_bits - cache_bits == 8 * sizeof (item_t) && v == (unsigned int) -1) ||
        (v >> value_bits) != (key >> cache_bits))
       return false;
     *value = v & ((1u<<value_bits)-1);
@@ -65,16 +87,13 @@ struct hb_cache_t
       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);
+    values[k] = v;
     return true;
   }
 
   private:
-  hb_atomic_int_t values[1u<<cache_bits];
+  item_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-cairo-utils.cc b/src/hb-cairo-utils.cc
new file mode 100644 (file)
index 0000000..ec1499e
--- /dev/null
@@ -0,0 +1,874 @@
+/*
+ * Copyright © 2022  Red Hat, Inc
+ * Copyright © 2021, 2022  Black Foundry
+ *
+ *  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): Matthias Clasen
+ */
+
+#include "hb.hh"
+
+#ifdef HAVE_CAIRO
+
+#include "hb-cairo-utils.hh"
+
+#include <cairo.h>
+
+/* Some routines in this file were ported from BlackRenderer by Black Foundry.
+ * Used by permission to relicense to HarfBuzz license.
+ *
+ * https://github.com/BlackFoundryCom/black-renderer
+ */
+
+#define PREALLOCATED_COLOR_STOPS 16
+
+typedef struct {
+  float r, g, b, a;
+} hb_cairo_color_t;
+
+static inline cairo_extend_t
+hb_cairo_extend (hb_paint_extend_t extend)
+{
+  switch (extend)
+    {
+    case HB_PAINT_EXTEND_PAD: return CAIRO_EXTEND_PAD;
+    case HB_PAINT_EXTEND_REPEAT: return CAIRO_EXTEND_REPEAT;
+    case HB_PAINT_EXTEND_REFLECT: return CAIRO_EXTEND_REFLECT;
+    default: break;
+    }
+
+  return CAIRO_EXTEND_PAD;
+}
+
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+typedef struct
+{
+  hb_blob_t *blob;
+  unsigned int offset;
+} hb_cairo_read_blob_data_t;
+
+static cairo_status_t
+hb_cairo_read_blob (void *closure,
+                   unsigned char *data,
+                   unsigned int length)
+{
+  hb_cairo_read_blob_data_t *r = (hb_cairo_read_blob_data_t *) closure;
+  const char *d;
+  unsigned int size;
+
+  d = hb_blob_get_data (r->blob, &size);
+
+  if (r->offset + length > size)
+    return CAIRO_STATUS_READ_ERROR;
+
+  hb_memcpy (data, d + r->offset, length);
+  r->offset += length;
+
+  return CAIRO_STATUS_SUCCESS;
+}
+#endif
+
+static const cairo_user_data_key_t *_hb_cairo_surface_blob_user_data_key = {0};
+
+static void
+_hb_cairo_destroy_blob (void *p)
+{
+  hb_blob_destroy ((hb_blob_t *) p);
+}
+
+hb_bool_t
+_hb_cairo_paint_glyph_image (hb_cairo_context_t *c,
+                            hb_blob_t *blob,
+                            unsigned width,
+                            unsigned height,
+                            hb_tag_t format,
+                            float slant,
+                            hb_glyph_extents_t *extents)
+{
+  cairo_t *cr = c->cr;
+
+  if (!extents) /* SVG currently. */
+    return false;
+
+  cairo_surface_t *surface = nullptr;
+
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+  if (format == HB_PAINT_IMAGE_FORMAT_PNG)
+  {
+    hb_cairo_read_blob_data_t r;
+    r.blob = blob;
+    r.offset = 0;
+    surface = cairo_image_surface_create_from_png_stream (hb_cairo_read_blob, &r);
+
+    /* For PNG, width,height can be unreliable, as is the case for NotoColorEmoji :(.
+     * Just pull them out of the surface. */
+    width = cairo_image_surface_get_width (surface);
+    height = cairo_image_surface_get_width (surface);
+  }
+  else
+#endif
+  if (format == HB_PAINT_IMAGE_FORMAT_BGRA)
+  {
+    /* Byte-endian conversion. */
+    unsigned data_size = hb_blob_get_length (blob);
+    if (data_size < width * height * 4)
+      return false;
+
+    unsigned char *data;
+#ifdef __BYTE_ORDER
+    if (__BYTE_ORDER == __BIG_ENDIAN)
+    {
+      data = (unsigned char *) hb_blob_get_data_writable (blob, nullptr);
+      if (!data)
+        return false;
+
+      unsigned count = width * height * 4;
+      for (unsigned i = 0; i < count; i += 4)
+      {
+        unsigned char b;
+       b = data[i];
+       data[i] = data[i+3];
+       data[i+3] = b;
+       b = data[i+1];
+       data[i+1] = data[i+2];
+       data[i+2] = b;
+      }
+    }
+    else
+#endif
+      data = (unsigned char *) hb_blob_get_data (blob, nullptr);
+
+    surface = cairo_image_surface_create_for_data (data,
+                                                  CAIRO_FORMAT_ARGB32,
+                                                  width, height,
+                                                  width * 4);
+
+    cairo_surface_set_user_data (surface,
+                                _hb_cairo_surface_blob_user_data_key,
+                                hb_blob_reference (blob),
+                                _hb_cairo_destroy_blob);
+  }
+
+  if (!surface)
+    return false;
+
+  cairo_save (cr);
+  /* this clip is here to work around recording surface limitations */
+  cairo_rectangle (cr,
+                   extents->x_bearing,
+                   extents->y_bearing,
+                   extents->width,
+                   extents->height);
+  cairo_clip (cr);
+
+  cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface);
+  cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
+
+  cairo_matrix_t matrix = {(double) width, 0, 0, (double) height, 0, 0};
+  cairo_pattern_set_matrix (pattern, &matrix);
+
+  /* Undo slant in the extents and apply it in the context. */
+  extents->width -= extents->height * slant;
+  extents->x_bearing -= extents->y_bearing * slant;
+  cairo_matrix_t cairo_matrix = {1., 0., (double) slant, 1., 0., 0.};
+  cairo_transform (cr, &cairo_matrix);
+
+  cairo_translate (cr, extents->x_bearing, extents->y_bearing);
+  cairo_scale (cr, extents->width, extents->height);
+  cairo_set_source (cr, pattern);
+
+  cairo_paint (cr);
+
+  cairo_pattern_destroy (pattern);
+  cairo_surface_destroy (surface);
+
+  cairo_restore (cr);
+
+  return true;
+}
+
+static void
+_hb_cairo_reduce_anchors (float x0, float y0,
+                         float x1, float y1,
+                         float x2, float y2,
+                         float *xx0, float *yy0,
+                         float *xx1, float *yy1)
+{
+  float q1x, q1y, q2x, q2y;
+  float s;
+  float k;
+
+  q2x = x2 - x0;
+  q2y = y2 - y0;
+  q1x = x1 - x0;
+  q1y = y1 - y0;
+
+  s = q2x * q2x + q2y * q2y;
+  if (s < 0.000001f)
+    {
+      *xx0 = x0; *yy0 = y0;
+      *xx1 = x1; *yy1 = y1;
+      return;
+    }
+
+  k = (q2x * q1x + q2y * q1y) / s;
+  *xx0 = x0;
+  *yy0 = y0;
+  *xx1 = x1 - k * q2x;
+  *yy1 = y1 - k * q2y;
+}
+
+static int
+_hb_cairo_cmp_color_stop (const void *p1,
+                         const void *p2)
+{
+  const hb_color_stop_t *c1 = (const hb_color_stop_t *) p1;
+  const hb_color_stop_t *c2 = (const hb_color_stop_t *) p2;
+
+  if (c1->offset < c2->offset)
+    return -1;
+  else if (c1->offset > c2->offset)
+    return 1;
+  else
+    return 0;
+}
+
+static void
+_hb_cairo_normalize_color_line (hb_color_stop_t *stops,
+                               unsigned int len,
+                               float *omin,
+                               float *omax)
+{
+  float min, max;
+
+  hb_qsort (stops, len, sizeof (hb_color_stop_t), _hb_cairo_cmp_color_stop);
+
+  min = max = stops[0].offset;
+  for (unsigned int i = 0; i < len; i++)
+    {
+      min = hb_min (min, stops[i].offset);
+      max = hb_max (max, stops[i].offset);
+    }
+
+  if (min != max)
+    {
+      for (unsigned int i = 0; i < len; i++)
+        stops[i].offset = (stops[i].offset - min) / (max - min);
+    }
+
+  *omin = min;
+  *omax = max;
+}
+
+static bool
+_hb_cairo_get_color_stops (hb_cairo_context_t *c,
+                          hb_color_line_t *color_line,
+                          unsigned *count,
+                          hb_color_stop_t **stops)
+{
+  unsigned len = hb_color_line_get_color_stops (color_line, 0, nullptr, nullptr);
+  if (len > *count)
+  {
+    *stops = (hb_color_stop_t *) hb_malloc (len * sizeof (hb_color_stop_t));
+    if (unlikely (!stops))
+      return false;
+  }
+  hb_color_line_get_color_stops (color_line, 0, &len, *stops);
+  for (unsigned i = 0; i < len; i++)
+    if ((*stops)[i].is_foreground)
+    {
+#ifdef HAVE_CAIRO_USER_SCALED_FONT_GET_FOREGROUND_SOURCE
+      double r, g, b, a;
+      cairo_pattern_t *foreground = cairo_user_scaled_font_get_foreground_source (c->scaled_font);
+      if (cairo_pattern_get_rgba (foreground, &r, &g, &b, &a) == CAIRO_STATUS_SUCCESS)
+        (*stops)[i].color = HB_COLOR (round (b * 255.), round (g * 255.), round (r * 255.),
+                                      round (a * hb_color_get_alpha ((*stops)[i].color)));
+      else
+#endif
+        (*stops)[i].color = HB_COLOR (0, 0, 0, hb_color_get_alpha ((*stops)[i].color));
+    }
+
+  *count = len;
+  return true;
+}
+
+void
+_hb_cairo_paint_linear_gradient (hb_cairo_context_t *c,
+                                hb_color_line_t *color_line,
+                                float x0, float y0,
+                                float x1, float y1,
+                                float x2, float y2)
+{
+  cairo_t *cr = c->cr;
+
+  unsigned int len = PREALLOCATED_COLOR_STOPS;
+  hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS];
+  hb_color_stop_t *stops = stops_;
+  float xx0, yy0, xx1, yy1;
+  float xxx0, yyy0, xxx1, yyy1;
+  float min, max;
+  cairo_pattern_t *pattern;
+
+  if (unlikely (!_hb_cairo_get_color_stops (c, color_line, &len, &stops)))
+    return;
+  _hb_cairo_normalize_color_line (stops, len, &min, &max);
+
+  _hb_cairo_reduce_anchors (x0, y0, x1, y1, x2, y2, &xx0, &yy0, &xx1, &yy1);
+
+  xxx0 = xx0 + min * (xx1 - xx0);
+  yyy0 = yy0 + min * (yy1 - yy0);
+  xxx1 = xx0 + max * (xx1 - xx0);
+  yyy1 = yy0 + max * (yy1 - yy0);
+
+  pattern = cairo_pattern_create_linear ((double) xxx0, (double) yyy0, (double) xxx1, (double) yyy1);
+  cairo_pattern_set_extend (pattern, hb_cairo_extend (hb_color_line_get_extend (color_line)));
+  for (unsigned int i = 0; i < len; i++)
+    {
+      double r, g, b, a;
+      r = hb_color_get_red (stops[i].color) / 255.;
+      g = hb_color_get_green (stops[i].color) / 255.;
+      b = hb_color_get_blue (stops[i].color) / 255.;
+      a = hb_color_get_alpha (stops[i].color) / 255.;
+      cairo_pattern_add_color_stop_rgba (pattern, (double) stops[i].offset, r, g, b, a);
+    }
+
+  cairo_set_source (cr, pattern);
+  cairo_paint (cr);
+
+  cairo_pattern_destroy (pattern);
+
+  if (stops != stops_)
+    hb_free (stops);
+}
+
+void
+_hb_cairo_paint_radial_gradient (hb_cairo_context_t *c,
+                                hb_color_line_t *color_line,
+                                float x0, float y0, float r0,
+                                float x1, float y1, float r1)
+{
+  cairo_t *cr = c->cr;
+
+  unsigned int len = PREALLOCATED_COLOR_STOPS;
+  hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS];
+  hb_color_stop_t *stops = stops_;
+  float min, max;
+  float xx0, yy0, xx1, yy1;
+  float rr0, rr1;
+  cairo_pattern_t *pattern;
+
+  if (unlikely (!_hb_cairo_get_color_stops (c, color_line, &len, &stops)))
+    return;
+  _hb_cairo_normalize_color_line (stops, len, &min, &max);
+
+  xx0 = x0 + min * (x1 - x0);
+  yy0 = y0 + min * (y1 - y0);
+  xx1 = x0 + max * (x1 - x0);
+  yy1 = y0 + max * (y1 - y0);
+  rr0 = r0 + min * (r1 - r0);
+  rr1 = r0 + max * (r1 - r0);
+
+  pattern = cairo_pattern_create_radial ((double) xx0, (double) yy0, (double) rr0, (double) xx1, (double) yy1, (double) rr1);
+  cairo_pattern_set_extend (pattern, hb_cairo_extend (hb_color_line_get_extend (color_line)));
+
+  for (unsigned int i = 0; i < len; i++)
+    {
+      double r, g, b, a;
+      r = hb_color_get_red (stops[i].color) / 255.;
+      g = hb_color_get_green (stops[i].color) / 255.;
+      b = hb_color_get_blue (stops[i].color) / 255.;
+      a = hb_color_get_alpha (stops[i].color) / 255.;
+      cairo_pattern_add_color_stop_rgba (pattern, (double) stops[i].offset, r, g, b, a);
+    }
+
+  cairo_set_source (cr, pattern);
+  cairo_paint (cr);
+
+  cairo_pattern_destroy (pattern);
+
+  if (stops != stops_)
+    hb_free (stops);
+}
+
+typedef struct {
+  float x, y;
+} hb_cairo_point_t;
+
+static inline float
+_hb_cairo_interpolate (float f0, float f1, float f)
+{
+  return f0 + f * (f1 - f0);
+}
+
+static inline void
+_hb_cairo_premultiply (hb_cairo_color_t *c)
+{
+  c->r *= c->a;
+  c->g *= c->a;
+  c->b *= c->a;
+}
+
+static inline void
+_hb_cairo_unpremultiply (hb_cairo_color_t *c)
+{
+  if (c->a != 0.f)
+  {
+     c->r /= c->a;
+     c->g /= c->a;
+     c->b /= c->a;
+  }
+}
+
+static void
+_hb_cairo_interpolate_colors (hb_cairo_color_t *c0, hb_cairo_color_t *c1, float k, hb_cairo_color_t *c)
+{
+  // According to the COLR specification, gradients
+  // should be interpolated in premultiplied form
+  _hb_cairo_premultiply (c0);
+  _hb_cairo_premultiply (c1);
+  c->r = c0->r + k * (c1->r - c0->r);
+  c->g = c0->g + k * (c1->g - c0->g);
+  c->b = c0->b + k * (c1->b - c0->b);
+  c->a = c0->a + k * (c1->a - c0->a);
+  _hb_cairo_unpremultiply (c);
+}
+
+static inline float
+_hb_cairo_dot (hb_cairo_point_t p, hb_cairo_point_t q)
+{
+  return p.x * q.x + p.y * q.y;
+}
+
+static inline hb_cairo_point_t
+_hb_cairo_normalize (hb_cairo_point_t p)
+{
+  float len = sqrtf (_hb_cairo_dot (p, p));
+
+  return hb_cairo_point_t { p.x / len, p.y / len };
+}
+
+static inline hb_cairo_point_t
+_hb_cairo_sum (hb_cairo_point_t p, hb_cairo_point_t q)
+{
+  return hb_cairo_point_t { p.x + q.x, p.y + q.y };
+}
+
+static inline hb_cairo_point_t
+_hb_cairo_difference (hb_cairo_point_t p, hb_cairo_point_t q)
+{
+  return hb_cairo_point_t { p.x - q.x, p.y - q.y };
+}
+
+static inline hb_cairo_point_t
+_hb_cairo_scale (hb_cairo_point_t p, float f)
+{
+  return hb_cairo_point_t { p.x * f, p.y * f };
+}
+
+typedef struct {
+  hb_cairo_point_t center, p0, c0, c1, p1;
+  hb_cairo_color_t color0, color1;
+} hb_cairo_patch_t;
+
+static void
+_hb_cairo_add_patch (cairo_pattern_t *pattern, hb_cairo_point_t *center, hb_cairo_patch_t *p)
+{
+  cairo_mesh_pattern_begin_patch (pattern);
+  cairo_mesh_pattern_move_to (pattern, (double) center->x, (double) center->y);
+  cairo_mesh_pattern_line_to (pattern, (double) p->p0.x, (double) p->p0.y);
+  cairo_mesh_pattern_curve_to (pattern,
+                               (double) p->c0.x, (double) p->c0.y,
+                               (double) p->c1.x, (double) p->c1.y,
+                               (double) p->p1.x, (double) p->p1.y);
+  cairo_mesh_pattern_line_to (pattern, (double) center->x, (double) center->y);
+  cairo_mesh_pattern_set_corner_color_rgba (pattern, 0,
+                                            (double) p->color0.r,
+                                            (double) p->color0.g,
+                                            (double) p->color0.b,
+                                            (double) p->color0.a);
+  cairo_mesh_pattern_set_corner_color_rgba (pattern, 1,
+                                            (double) p->color0.r,
+                                            (double) p->color0.g,
+                                            (double) p->color0.b,
+                                            (double) p->color0.a);
+  cairo_mesh_pattern_set_corner_color_rgba (pattern, 2,
+                                            (double) p->color1.r,
+                                            (double) p->color1.g,
+                                            (double) p->color1.b,
+                                            (double) p->color1.a);
+  cairo_mesh_pattern_set_corner_color_rgba (pattern, 3,
+                                            (double) p->color1.r,
+                                            (double) p->color1.g,
+                                            (double) p->color1.b,
+                                            (double) p->color1.a);
+  cairo_mesh_pattern_end_patch (pattern);
+}
+
+#define MAX_ANGLE (HB_PI / 8.f)
+
+static void
+_hb_cairo_add_sweep_gradient_patches1 (float cx, float cy, float radius,
+                                      float a0, hb_cairo_color_t *c0,
+                                      float a1, hb_cairo_color_t *c1,
+                                      cairo_pattern_t *pattern)
+{
+  hb_cairo_point_t center = hb_cairo_point_t { cx, cy };
+  int num_splits;
+  hb_cairo_point_t p0;
+  hb_cairo_color_t color0, color1;
+
+  num_splits = ceilf (fabsf (a1 - a0) / MAX_ANGLE);
+  p0 = hb_cairo_point_t { cosf (a0), sinf (a0) };
+  color0 = *c0;
+
+  for (int a = 0; a < num_splits; a++)
+    {
+      float k = (a + 1.) / num_splits;
+      float angle1;
+      hb_cairo_point_t p1;
+      hb_cairo_point_t A, U;
+      hb_cairo_point_t C0, C1;
+      hb_cairo_patch_t patch;
+
+      angle1 = _hb_cairo_interpolate (a0, a1, k);
+      _hb_cairo_interpolate_colors (c0, c1, k, &color1);
+
+      patch.color0 = color0;
+      patch.color1 = color1;
+
+      p1 = hb_cairo_point_t { cosf (angle1), sinf (angle1) };
+      patch.p0 = _hb_cairo_sum (center, _hb_cairo_scale (p0, radius));
+      patch.p1 = _hb_cairo_sum (center, _hb_cairo_scale (p1, radius));
+
+      A = _hb_cairo_normalize (_hb_cairo_sum (p0, p1));
+      U = hb_cairo_point_t { -A.y, A.x };
+      C0 = _hb_cairo_sum (A, _hb_cairo_scale (U, _hb_cairo_dot (_hb_cairo_difference (p0, A), p0) / _hb_cairo_dot (U, p0)));
+      C1 = _hb_cairo_sum (A, _hb_cairo_scale (U, _hb_cairo_dot (_hb_cairo_difference (p1, A), p1) / _hb_cairo_dot (U, p1)));
+
+      patch.c0 = _hb_cairo_sum (center, _hb_cairo_scale (_hb_cairo_sum (C0, _hb_cairo_scale (_hb_cairo_difference (C0, p0), 0.33333f)), radius));
+      patch.c1 = _hb_cairo_sum (center, _hb_cairo_scale (_hb_cairo_sum (C1, _hb_cairo_scale (_hb_cairo_difference (C1, p1), 0.33333f)), radius));
+
+      _hb_cairo_add_patch (pattern, &center, &patch);
+
+      p0 = p1;
+      color0 = color1;
+    }
+}
+
+static void
+_hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
+                                     unsigned int n_stops,
+                                     cairo_extend_t extend,
+                                     float cx, float cy,
+                                     float radius,
+                                     float start_angle,
+                                     float end_angle,
+                                     cairo_pattern_t *pattern)
+{
+  float angles_[PREALLOCATED_COLOR_STOPS];
+  float *angles = angles_;
+  hb_cairo_color_t colors_[PREALLOCATED_COLOR_STOPS];
+  hb_cairo_color_t *colors = colors_;
+  hb_cairo_color_t color0, color1;
+
+  if (start_angle == end_angle)
+  {
+    if (extend == CAIRO_EXTEND_PAD)
+    {
+      hb_cairo_color_t c;
+      if (start_angle > 0)
+      {
+       c.r = hb_color_get_red (stops[0].color) / 255.;
+       c.g = hb_color_get_green (stops[0].color) / 255.;
+       c.b = hb_color_get_blue (stops[0].color) / 255.;
+       c.a = hb_color_get_alpha (stops[0].color) / 255.;
+       _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+                                              0.,          &c,
+                                              start_angle, &c,
+                                              pattern);
+      }
+      if (end_angle < HB_2_PI)
+      {
+       c.r = hb_color_get_red (stops[n_stops - 1].color) / 255.;
+       c.g = hb_color_get_green (stops[n_stops - 1].color) / 255.;
+       c.b = hb_color_get_blue (stops[n_stops - 1].color) / 255.;
+       c.a = hb_color_get_alpha (stops[n_stops - 1].color) / 255.;
+       _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+                                              end_angle, &c,
+                                              HB_2_PI,  &c,
+                                              pattern);
+      }
+    }
+    return;
+  }
+
+  assert (start_angle != end_angle);
+
+  /* handle directions */
+  if (end_angle < start_angle)
+  {
+    hb_swap (start_angle, end_angle);
+
+    for (unsigned i = 0; i < n_stops - 1 - i; i++)
+      hb_swap (stops[i], stops[n_stops - 1 - i]);
+    for (unsigned i = 0; i < n_stops; i++)
+      stops[i].offset = 1 - stops[i].offset;
+  }
+
+  if (n_stops > PREALLOCATED_COLOR_STOPS)
+  {
+    angles = (float *) hb_malloc (sizeof (float) * n_stops);
+    colors = (hb_cairo_color_t *) hb_malloc (sizeof (hb_cairo_color_t) * n_stops);
+    if (unlikely (!angles || !colors))
+    {
+      hb_free (angles);
+      hb_free (colors);
+      return;
+    }
+  }
+
+  for (unsigned i = 0; i < n_stops; i++)
+  {
+    angles[i] = start_angle + stops[i].offset * (end_angle - start_angle);
+    colors[i].r = hb_color_get_red (stops[i].color) / 255.;
+    colors[i].g = hb_color_get_green (stops[i].color) / 255.;
+    colors[i].b = hb_color_get_blue (stops[i].color) / 255.;
+    colors[i].a = hb_color_get_alpha (stops[i].color) / 255.;
+  }
+
+  if (extend == CAIRO_EXTEND_PAD)
+  {
+    unsigned pos;
+
+    color0 = colors[0];
+    for (pos = 0; pos < n_stops; pos++)
+    {
+      if (angles[pos] >= 0)
+      {
+       if (pos > 0)
+       {
+         float k = (0 - angles[pos - 1]) / (angles[pos] - angles[pos - 1]);
+         _hb_cairo_interpolate_colors (&colors[pos-1], &colors[pos], k, &color0);
+       }
+       break;
+      }
+    }
+    if (pos == n_stops)
+    {
+      /* everything is below 0 */
+      color0 = colors[n_stops-1];
+      _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+                                            0.,       &color0,
+                                            HB_2_PI, &color0,
+                                            pattern);
+      goto done;
+    }
+
+    _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+                                          0.,          &color0,
+                                          angles[pos], &colors[pos],
+                                          pattern);
+
+    for (pos++; pos < n_stops; pos++)
+    {
+      if (angles[pos] <= HB_2_PI)
+      {
+       _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+                                              angles[pos - 1], &colors[pos-1],
+                                              angles[pos],     &colors[pos],
+                                              pattern);
+      }
+      else
+      {
+       float k = (HB_2_PI - angles[pos - 1]) / (angles[pos] - angles[pos - 1]);
+       _hb_cairo_interpolate_colors (&colors[pos - 1], &colors[pos], k, &color1);
+       _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+                                              angles[pos - 1], &colors[pos - 1],
+                                              HB_2_PI,        &color1,
+                                              pattern);
+       break;
+      }
+    }
+
+    if (pos == n_stops)
+    {
+      /* everything is below 2*M_PI */
+      color0 = colors[n_stops - 1];
+      _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+                                            angles[n_stops - 1], &color0,
+                                            HB_2_PI,            &color0,
+                                            pattern);
+      goto done;
+    }
+  }
+  else
+  {
+    int k;
+    float span;
+
+    span = angles[n_stops - 1] - angles[0];
+    k = 0;
+    if (angles[0] >= 0)
+    {
+      float ss = angles[0];
+      while (ss > 0)
+      {
+       if (span > 0)
+       {
+         ss -= span;
+         k--;
+       }
+       else
+       {
+         ss += span;
+         k++;
+       }
+      }
+    }
+    else if (angles[0] < 0)
+    {
+      float ee = angles[n_stops - 1];
+      while (ee < 0)
+      {
+       if (span > 0)
+       {
+         ee += span;
+         k++;
+       }
+       else
+       {
+         ee -= span;
+         k--;
+       }
+      }
+    }
+
+    //assert (angles[0] + k * span <= 0 && 0 < angles[n_stops - 1] + k * span);
+    span = fabsf (span);
+
+    for (signed l = k; l < 1000; l++)
+    {
+      for (unsigned i = 1; i < n_stops; i++)
+      {
+        float a0, a1;
+       hb_cairo_color_t *c0, *c1;
+
+       if ((l % 2 != 0) && (extend == CAIRO_EXTEND_REFLECT))
+       {
+         a0 = angles[0] + angles[n_stops - 1] - angles[n_stops - 1 - (i-1)] + l * span;
+         a1 = angles[0] + angles[n_stops - 1] - angles[n_stops - 1 - i] + l * span;
+         c0 = &colors[n_stops - 1 - (i - 1)];
+         c1 = &colors[n_stops - 1 - i];
+       }
+       else
+       {
+         a0 = angles[i-1] + l * span;
+         a1 = angles[i] + l * span;
+         c0 = &colors[i-1];
+         c1 = &colors[i];
+       }
+
+       if (a1 < 0)
+         continue;
+       if (a0 < 0)
+       {
+         hb_cairo_color_t color;
+         float f = (0 - a0)/(a1 - a0);
+         _hb_cairo_interpolate_colors (c0, c1, f, &color);
+         _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+                                                0,  &color,
+                                                a1, c1,
+                                                pattern);
+       }
+       else if (a1 >= HB_2_PI)
+       {
+         hb_cairo_color_t color;
+         float f = (HB_2_PI - a0)/(a1 - a0);
+         _hb_cairo_interpolate_colors (c0, c1, f, &color);
+         _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+                                                a0,       c0,
+                                                HB_2_PI, &color,
+                                                pattern);
+         goto done;
+       }
+       else
+       {
+         _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+                                                a0, c0,
+                                                a1, c1,
+                                                pattern);
+       }
+      }
+    }
+  }
+
+done:
+
+  if (angles != angles_)
+    hb_free (angles);
+  if (colors != colors_)
+    hb_free (colors);
+}
+
+void
+_hb_cairo_paint_sweep_gradient (hb_cairo_context_t *c,
+                               hb_color_line_t *color_line,
+                               float cx, float cy,
+                               float start_angle,
+                               float end_angle)
+{
+  cairo_t *cr = c->cr;
+
+  unsigned int len = PREALLOCATED_COLOR_STOPS;
+  hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS];
+  hb_color_stop_t *stops = stops_;
+  cairo_extend_t extend;
+  double x1, y1, x2, y2;
+  float max_x, max_y, radius;
+  cairo_pattern_t *pattern;
+
+  if (unlikely (!_hb_cairo_get_color_stops (c, color_line, &len, &stops)))
+    return;
+
+  hb_qsort (stops, len, sizeof (hb_color_stop_t), _hb_cairo_cmp_color_stop);
+
+  cairo_clip_extents (cr, &x1, &y1, &x2, &y2);
+  max_x = (float) hb_max ((x1 - (double) cx) * (x1 - (double) cx), (x2 - (double) cx) * (x2 - (double) cx));
+  max_y = (float) hb_max ((y1 - (double) cy) * (y1 - (double) cy), (y2 - (double) cy) * (y2 - (double) cy));
+  radius = sqrtf (max_x + max_y);
+
+  extend = hb_cairo_extend (hb_color_line_get_extend (color_line));
+  pattern = cairo_pattern_create_mesh ();
+
+  _hb_cairo_add_sweep_gradient_patches (stops, len, extend, cx, cy,
+                                       radius, start_angle, end_angle, pattern);
+
+  cairo_set_source (cr, pattern);
+  cairo_paint (cr);
+
+  cairo_pattern_destroy (pattern);
+
+  if (stops != stops_)
+    hb_free (stops);
+}
+
+#endif
diff --git a/src/hb-cairo-utils.hh b/src/hb-cairo-utils.hh
new file mode 100644 (file)
index 0000000..a26bf59
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright © 2022  Red Hat, 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): Matthias Clasen
+ */
+
+#ifndef HB_CAIRO_UTILS_H
+#define HB_CAIRO_UTILS_H
+
+#include "hb.hh"
+#include "hb-cairo.h"
+
+
+typedef struct
+{
+  cairo_scaled_font_t *scaled_font;
+  cairo_t *cr;
+  hb_map_t *color_cache;
+} hb_cairo_context_t;
+
+static inline cairo_operator_t
+_hb_paint_composite_mode_to_cairo (hb_paint_composite_mode_t mode)
+{
+  switch (mode)
+    {
+    case HB_PAINT_COMPOSITE_MODE_CLEAR: return CAIRO_OPERATOR_CLEAR;
+    case HB_PAINT_COMPOSITE_MODE_SRC: return CAIRO_OPERATOR_SOURCE;
+    case HB_PAINT_COMPOSITE_MODE_DEST: return CAIRO_OPERATOR_DEST;
+    case HB_PAINT_COMPOSITE_MODE_SRC_OVER: return CAIRO_OPERATOR_OVER;
+    case HB_PAINT_COMPOSITE_MODE_DEST_OVER: return CAIRO_OPERATOR_DEST_OVER;
+    case HB_PAINT_COMPOSITE_MODE_SRC_IN: return CAIRO_OPERATOR_IN;
+    case HB_PAINT_COMPOSITE_MODE_DEST_IN: return CAIRO_OPERATOR_DEST_IN;
+    case HB_PAINT_COMPOSITE_MODE_SRC_OUT: return CAIRO_OPERATOR_OUT;
+    case HB_PAINT_COMPOSITE_MODE_DEST_OUT: return CAIRO_OPERATOR_DEST_OUT;
+    case HB_PAINT_COMPOSITE_MODE_SRC_ATOP: return CAIRO_OPERATOR_ATOP;
+    case HB_PAINT_COMPOSITE_MODE_DEST_ATOP: return CAIRO_OPERATOR_DEST_ATOP;
+    case HB_PAINT_COMPOSITE_MODE_XOR: return CAIRO_OPERATOR_XOR;
+    case HB_PAINT_COMPOSITE_MODE_PLUS: return CAIRO_OPERATOR_ADD;
+    case HB_PAINT_COMPOSITE_MODE_SCREEN: return CAIRO_OPERATOR_SCREEN;
+    case HB_PAINT_COMPOSITE_MODE_OVERLAY: return CAIRO_OPERATOR_OVERLAY;
+    case HB_PAINT_COMPOSITE_MODE_DARKEN: return CAIRO_OPERATOR_DARKEN;
+    case HB_PAINT_COMPOSITE_MODE_LIGHTEN: return CAIRO_OPERATOR_LIGHTEN;
+    case HB_PAINT_COMPOSITE_MODE_COLOR_DODGE: return CAIRO_OPERATOR_COLOR_DODGE;
+    case HB_PAINT_COMPOSITE_MODE_COLOR_BURN: return CAIRO_OPERATOR_COLOR_BURN;
+    case HB_PAINT_COMPOSITE_MODE_HARD_LIGHT: return CAIRO_OPERATOR_HARD_LIGHT;
+    case HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT: return CAIRO_OPERATOR_SOFT_LIGHT;
+    case HB_PAINT_COMPOSITE_MODE_DIFFERENCE: return CAIRO_OPERATOR_DIFFERENCE;
+    case HB_PAINT_COMPOSITE_MODE_EXCLUSION: return CAIRO_OPERATOR_EXCLUSION;
+    case HB_PAINT_COMPOSITE_MODE_MULTIPLY: return CAIRO_OPERATOR_MULTIPLY;
+    case HB_PAINT_COMPOSITE_MODE_HSL_HUE: return CAIRO_OPERATOR_HSL_HUE;
+    case HB_PAINT_COMPOSITE_MODE_HSL_SATURATION: return CAIRO_OPERATOR_HSL_SATURATION;
+    case HB_PAINT_COMPOSITE_MODE_HSL_COLOR: return CAIRO_OPERATOR_HSL_COLOR;
+    case HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY: return CAIRO_OPERATOR_HSL_LUMINOSITY;
+    default: return CAIRO_OPERATOR_CLEAR;
+    }
+}
+
+HB_INTERNAL hb_bool_t
+_hb_cairo_paint_glyph_image (hb_cairo_context_t *c,
+                            hb_blob_t *blob,
+                            unsigned width,
+                            unsigned height,
+                            hb_tag_t format,
+                            float slant,
+                            hb_glyph_extents_t *extents);
+
+HB_INTERNAL void
+_hb_cairo_paint_linear_gradient (hb_cairo_context_t *c,
+                                hb_color_line_t *color_line,
+                                float x0, float y0,
+                                float x1, float y1,
+                                float x2, float y2);
+
+HB_INTERNAL void
+_hb_cairo_paint_radial_gradient (hb_cairo_context_t *c,
+                                hb_color_line_t *color_line,
+                                float x0, float y0, float r0,
+                                float x1, float y1, float r1);
+
+HB_INTERNAL void
+_hb_cairo_paint_sweep_gradient (hb_cairo_context_t *c,
+                               hb_color_line_t *color_line,
+                               float x0, float y0,
+                               float start_angle, float end_angle);
+
+
+#endif /* HB_CAIRO_UTILS_H */
diff --git a/src/hb-cairo.cc b/src/hb-cairo.cc
new file mode 100644 (file)
index 0000000..f4f9f54
--- /dev/null
@@ -0,0 +1,1037 @@
+/*
+ * Copyright © 2022  Red Hat, 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): Matthias Clasen
+ */
+
+#include "hb.hh"
+
+#ifdef HAVE_CAIRO
+
+#include "hb-cairo.h"
+
+#include "hb-cairo-utils.hh"
+
+#include "hb-machinery.hh"
+#include "hb-utf.hh"
+
+
+/**
+ * SECTION:hb-cairo
+ * @title: hb-cairo
+ * @short_description: Cairo integration
+ * @include: hb-cairo.h
+ *
+ * Functions for using HarfBuzz with the cairo library.
+ *
+ * HarfBuzz supports using cairo for rendering.
+ **/
+
+static void
+hb_cairo_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+                 void *draw_data,
+                 hb_draw_state_t *st HB_UNUSED,
+                 float to_x, float to_y,
+                 void *user_data HB_UNUSED)
+{
+  cairo_t *cr = (cairo_t *) draw_data;
+
+  cairo_move_to (cr, (double) to_x, (double) to_y);
+}
+
+static void
+hb_cairo_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+                 void *draw_data,
+                 hb_draw_state_t *st HB_UNUSED,
+                 float to_x, float to_y,
+                 void *user_data HB_UNUSED)
+{
+  cairo_t *cr = (cairo_t *) draw_data;
+
+  cairo_line_to (cr, (double) to_x, (double) to_y);
+}
+
+static void
+hb_cairo_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+                  void *draw_data,
+                  hb_draw_state_t *st HB_UNUSED,
+                  float control1_x, float control1_y,
+                  float control2_x, float control2_y,
+                  float to_x, float to_y,
+                  void *user_data HB_UNUSED)
+{
+  cairo_t *cr = (cairo_t *) draw_data;
+
+  cairo_curve_to (cr,
+                  (double) control1_x, (double) control1_y,
+                  (double) control2_x, (double) control2_y,
+                  (double) to_x, (double) to_y);
+}
+
+static void
+hb_cairo_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED,
+                    void *draw_data,
+                    hb_draw_state_t *st HB_UNUSED,
+                    void *user_data HB_UNUSED)
+{
+  cairo_t *cr = (cairo_t *) draw_data;
+
+  cairo_close_path (cr);
+}
+
+static inline void free_static_cairo_draw_funcs ();
+
+static struct hb_cairo_draw_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_cairo_draw_funcs_lazy_loader_t>
+{
+  static hb_draw_funcs_t *create ()
+  {
+    hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
+
+    hb_draw_funcs_set_move_to_func (funcs, hb_cairo_move_to, nullptr, nullptr);
+    hb_draw_funcs_set_line_to_func (funcs, hb_cairo_line_to, nullptr, nullptr);
+    hb_draw_funcs_set_cubic_to_func (funcs, hb_cairo_cubic_to, nullptr, nullptr);
+    hb_draw_funcs_set_close_path_func (funcs, hb_cairo_close_path, nullptr, nullptr);
+
+    hb_draw_funcs_make_immutable (funcs);
+
+    hb_atexit (free_static_cairo_draw_funcs);
+
+    return funcs;
+  }
+} static_cairo_draw_funcs;
+
+static inline
+void free_static_cairo_draw_funcs ()
+{
+  static_cairo_draw_funcs.free_instance ();
+}
+
+static hb_draw_funcs_t *
+hb_cairo_draw_get_funcs ()
+{
+  return static_cairo_draw_funcs.get_unconst ();
+}
+
+
+#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
+
+static void
+hb_cairo_push_transform (hb_paint_funcs_t *pfuncs HB_UNUSED,
+                        void *paint_data,
+                        float xx, float yx,
+                        float xy, float yy,
+                        float dx, float dy,
+                        void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+  cairo_matrix_t m;
+
+  cairo_save (cr);
+  cairo_matrix_init (&m, (double) xx, (double) yx,
+                         (double) xy, (double) yy,
+                         (double) dx, (double) dy);
+  cairo_transform (cr, &m);
+}
+
+static void
+hb_cairo_pop_transform (hb_paint_funcs_t *pfuncs HB_UNUSED,
+                       void *paint_data,
+                       void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+  cairo_restore (cr);
+}
+
+static hb_bool_t
+hb_cairo_paint_color_glyph (hb_paint_funcs_t *pfuncs HB_UNUSED,
+                           void *paint_data,
+                           hb_codepoint_t glyph,
+                           hb_font_t *font,
+                           void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+  cairo_save (cr);
+
+  hb_position_t x_scale, y_scale;
+  hb_font_get_scale (font, &x_scale, &y_scale);
+  cairo_scale (cr, x_scale, y_scale);
+
+  cairo_glyph_t cairo_glyph = { glyph, 0, 0 };
+  cairo_set_scaled_font (cr, c->scaled_font);
+  cairo_set_font_size (cr, 1);
+  cairo_show_glyphs (cr, &cairo_glyph, 1);
+
+  cairo_restore (cr);
+
+  return true;
+}
+
+static void
+hb_cairo_push_clip_glyph (hb_paint_funcs_t *pfuncs HB_UNUSED,
+                         void *paint_data,
+                         hb_codepoint_t glyph,
+                         hb_font_t *font,
+                         void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+  cairo_save (cr);
+  cairo_new_path (cr);
+  hb_font_draw_glyph (font, glyph, hb_cairo_draw_get_funcs (), cr);
+  cairo_close_path (cr);
+  cairo_clip (cr);
+}
+
+static void
+hb_cairo_push_clip_rectangle (hb_paint_funcs_t *pfuncs HB_UNUSED,
+                             void *paint_data,
+                             float xmin, float ymin, float xmax, float ymax,
+                             void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+  cairo_save (cr);
+  cairo_rectangle (cr,
+                   (double) xmin, (double) ymin,
+                   (double) (xmax - xmin), (double) (ymax - ymin));
+  cairo_clip (cr);
+}
+
+static void
+hb_cairo_pop_clip (hb_paint_funcs_t *pfuncs HB_UNUSED,
+                  void *paint_data,
+                  void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+  cairo_restore (cr);
+}
+
+static void
+hb_cairo_push_group (hb_paint_funcs_t *pfuncs HB_UNUSED,
+                    void *paint_data,
+                    void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+  cairo_save (cr);
+  cairo_push_group (cr);
+}
+
+static void
+hb_cairo_pop_group (hb_paint_funcs_t *pfuncs HB_UNUSED,
+                   void *paint_data,
+                   hb_paint_composite_mode_t mode,
+                   void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+  cairo_pop_group_to_source (cr);
+  cairo_set_operator (cr, _hb_paint_composite_mode_to_cairo (mode));
+  cairo_paint (cr);
+
+  cairo_restore (cr);
+}
+
+static void
+hb_cairo_paint_color (hb_paint_funcs_t *pfuncs HB_UNUSED,
+                     void *paint_data,
+                     hb_bool_t use_foreground,
+                     hb_color_t color,
+                     void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+  if (use_foreground)
+  {
+#ifdef HAVE_CAIRO_USER_SCALED_FONT_GET_FOREGROUND_SOURCE
+    double r, g, b, a;
+    cairo_pattern_t *foreground = cairo_user_scaled_font_get_foreground_source (c->scaled_font);
+    if (cairo_pattern_get_rgba (foreground, &r, &g, &b, &a) == CAIRO_STATUS_SUCCESS)
+      cairo_set_source_rgba (cr, r, g, b, a * hb_color_get_alpha (color) / 255.);
+    else
+#endif
+      cairo_set_source_rgba (cr, 0, 0, 0, hb_color_get_alpha (color) / 255.);
+  }
+  else
+    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_paint (cr);
+}
+
+static hb_bool_t
+hb_cairo_paint_image (hb_paint_funcs_t *pfuncs HB_UNUSED,
+                     void *paint_data,
+                     hb_blob_t *blob,
+                     unsigned width,
+                     unsigned height,
+                     hb_tag_t format,
+                     float slant,
+                     hb_glyph_extents_t *extents,
+                     void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+
+  return _hb_cairo_paint_glyph_image (c, blob, width, height, format, slant, extents);
+}
+
+static void
+hb_cairo_paint_linear_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED,
+                               void *paint_data,
+                               hb_color_line_t *color_line,
+                               float x0, float y0,
+                               float x1, float y1,
+                               float x2, float y2,
+                               void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+
+  _hb_cairo_paint_linear_gradient (c, color_line, x0, y0, x1, y1, x2, y2);
+}
+
+static void
+hb_cairo_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED,
+                               void *paint_data,
+                               hb_color_line_t *color_line,
+                               float x0, float y0, float r0,
+                               float x1, float y1, float r1,
+                               void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+
+  _hb_cairo_paint_radial_gradient (c, color_line, x0, y0, r0, x1, y1, r1);
+}
+
+static void
+hb_cairo_paint_sweep_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED,
+                              void *paint_data,
+                              hb_color_line_t *color_line,
+                              float x0, float y0,
+                              float start_angle, float end_angle,
+                              void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+
+  _hb_cairo_paint_sweep_gradient (c, color_line, x0, y0, start_angle, end_angle);
+}
+
+static const cairo_user_data_key_t color_cache_key = {0};
+
+static void
+_hb_cairo_destroy_map (void *p)
+{
+  hb_map_destroy ((hb_map_t *) p);
+}
+
+static hb_bool_t
+hb_cairo_paint_custom_palette_color (hb_paint_funcs_t *funcs,
+                                     void *paint_data,
+                                     unsigned int color_index,
+                                     hb_color_t *color,
+                                     void *user_data HB_UNUSED)
+{
+#ifdef HAVE_CAIRO_FONT_OPTIONS_GET_CUSTOM_PALETTE_COLOR
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+#define HB_DEADBEEF HB_TAG(0xDE,0xAD,0xBE,0xEF)
+
+  hb_map_t *color_cache = c->color_cache;
+  hb_codepoint_t *v;
+  if (likely (color_cache && color_cache->has (color_index, &v)))
+  {
+    if (*v == HB_DEADBEEF)
+      return false;
+    *color = *v;
+    return true;
+  }
+
+  cairo_font_options_t *options;
+  double red, green, blue, alpha;
+
+  options = cairo_font_options_create ();
+  cairo_get_font_options (cr, options);
+  if (CAIRO_STATUS_SUCCESS ==
+      cairo_font_options_get_custom_palette_color (options, color_index,
+                                                   &red, &green, &blue, &alpha))
+  {
+    cairo_font_options_destroy (options);
+    *color = HB_COLOR (round (255 * blue),
+                      round (255 * green),
+                      round (255 * red),
+                      round (255 * alpha));
+
+    if (likely (color_cache && *color != HB_DEADBEEF))
+      color_cache->set (color_index, *color);
+
+    return true;
+  }
+  cairo_font_options_destroy (options);
+
+  if (likely (color_cache))
+    color_cache->set (color_index, HB_DEADBEEF);
+
+#undef HB_DEADBEEF
+
+#endif
+
+  return false;
+}
+
+static inline void free_static_cairo_paint_funcs ();
+
+static struct hb_cairo_paint_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_t<hb_cairo_paint_funcs_lazy_loader_t>
+{
+  static hb_paint_funcs_t *create ()
+  {
+    hb_paint_funcs_t *funcs = hb_paint_funcs_create ();
+
+    hb_paint_funcs_set_push_transform_func (funcs, hb_cairo_push_transform, nullptr, nullptr);
+    hb_paint_funcs_set_pop_transform_func (funcs, hb_cairo_pop_transform, nullptr, nullptr);
+    hb_paint_funcs_set_color_glyph_func (funcs, hb_cairo_paint_color_glyph, nullptr, nullptr);
+    hb_paint_funcs_set_push_clip_glyph_func (funcs, hb_cairo_push_clip_glyph, nullptr, nullptr);
+    hb_paint_funcs_set_push_clip_rectangle_func (funcs, hb_cairo_push_clip_rectangle, nullptr, nullptr);
+    hb_paint_funcs_set_pop_clip_func (funcs, hb_cairo_pop_clip, nullptr, nullptr);
+    hb_paint_funcs_set_push_group_func (funcs, hb_cairo_push_group, nullptr, nullptr);
+    hb_paint_funcs_set_pop_group_func (funcs, hb_cairo_pop_group, nullptr, nullptr);
+    hb_paint_funcs_set_color_func (funcs, hb_cairo_paint_color, nullptr, nullptr);
+    hb_paint_funcs_set_image_func (funcs, hb_cairo_paint_image, nullptr, nullptr);
+    hb_paint_funcs_set_linear_gradient_func (funcs, hb_cairo_paint_linear_gradient, nullptr, nullptr);
+    hb_paint_funcs_set_radial_gradient_func (funcs, hb_cairo_paint_radial_gradient, nullptr, nullptr);
+    hb_paint_funcs_set_sweep_gradient_func (funcs, hb_cairo_paint_sweep_gradient, nullptr, nullptr);
+    hb_paint_funcs_set_custom_palette_color_func (funcs, hb_cairo_paint_custom_palette_color, nullptr, nullptr);
+
+    hb_paint_funcs_make_immutable (funcs);
+
+    hb_atexit (free_static_cairo_paint_funcs);
+
+    return funcs;
+  }
+} static_cairo_paint_funcs;
+
+static inline
+void free_static_cairo_paint_funcs ()
+{
+  static_cairo_paint_funcs.free_instance ();
+}
+
+static hb_paint_funcs_t *
+hb_cairo_paint_get_funcs ()
+{
+  return static_cairo_paint_funcs.get_unconst ();
+}
+#endif
+
+static const cairo_user_data_key_t hb_cairo_face_user_data_key = {0};
+static const cairo_user_data_key_t hb_cairo_font_user_data_key = {0};
+static const cairo_user_data_key_t hb_cairo_font_init_func_user_data_key = {0};
+static const cairo_user_data_key_t hb_cairo_font_init_user_data_user_data_key = {0};
+static const cairo_user_data_key_t hb_cairo_scale_factor_user_data_key = {0};
+
+static void hb_cairo_face_destroy (void *p) { hb_face_destroy ((hb_face_t *) p); }
+static void hb_cairo_font_destroy (void *p) { hb_font_destroy ((hb_font_t *) p); }
+
+static cairo_status_t
+hb_cairo_init_scaled_font (cairo_scaled_font_t  *scaled_font,
+                          cairo_t              *cr HB_UNUSED,
+                          cairo_font_extents_t *extents)
+{
+  cairo_font_face_t *font_face = cairo_scaled_font_get_font_face (scaled_font);
+
+  hb_font_t *font = (hb_font_t *) cairo_font_face_get_user_data (font_face,
+                                                                &hb_cairo_font_user_data_key);
+
+  if (!font)
+  {
+    hb_face_t *face = (hb_face_t *) cairo_font_face_get_user_data (font_face,
+                                                                  &hb_cairo_face_user_data_key);
+    font = hb_font_create (face);
+
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,16,0)
+    cairo_font_options_t *font_options = cairo_font_options_create ();
+
+    // Set variations
+    cairo_scaled_font_get_font_options (scaled_font, font_options);
+    const char *variations = cairo_font_options_get_variations (font_options);
+    hb_vector_t<hb_variation_t> vars;
+    const char *p = variations;
+    while (p && *p)
+    {
+      const char *end = strpbrk ((char *) p, ", ");
+      hb_variation_t var;
+      if (hb_variation_from_string (p, end ? end - p : -1, &var))
+       vars.push (var);
+      p = end ? end + 1 : nullptr;
+    }
+    hb_font_set_variations (font, &vars[0], vars.length);
+
+    cairo_font_options_destroy (font_options);
+#endif
+
+    // Set scale; Note: should NOT set slant, or we'll double-slant.
+    unsigned scale_factor = hb_cairo_font_face_get_scale_factor (font_face);
+    if (scale_factor)
+    {
+      cairo_matrix_t font_matrix;
+      cairo_scaled_font_get_scale_matrix (scaled_font, &font_matrix);
+      hb_font_set_scale (font,
+                        round (font_matrix.xx * scale_factor),
+                        round (font_matrix.yy * scale_factor));
+    }
+
+    auto *init_func = (hb_cairo_font_init_func_t)
+                     cairo_font_face_get_user_data (font_face,
+                                                    &hb_cairo_font_init_func_user_data_key);
+    if (init_func)
+    {
+      void *user_data = cairo_font_face_get_user_data (font_face,
+                                                      &hb_cairo_font_init_user_data_user_data_key);
+      font = init_func (font, scaled_font, user_data);
+    }
+
+    hb_font_make_immutable (font);
+  }
+
+  cairo_scaled_font_set_user_data (scaled_font,
+                                  &hb_cairo_font_user_data_key,
+                                  (void *) hb_font_reference (font),
+                                  hb_cairo_font_destroy);
+
+  hb_position_t x_scale, y_scale;
+  hb_font_get_scale (font, &x_scale, &y_scale);
+
+  hb_font_extents_t hb_extents;
+  hb_font_get_h_extents (font, &hb_extents);
+
+  extents->ascent  = (double)  hb_extents.ascender  / y_scale;
+  extents->descent = (double) -hb_extents.descender / y_scale;
+  extents->height  = extents->ascent + extents->descent;
+
+#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
+  hb_map_t *color_cache = hb_map_create ();
+  if (unlikely (CAIRO_STATUS_SUCCESS != cairo_scaled_font_set_user_data (scaled_font,
+                                                                        &color_cache_key,
+                                                                        color_cache,
+                                                                        _hb_cairo_destroy_map)))
+    hb_map_destroy (color_cache);
+#endif
+
+  return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+hb_cairo_text_to_glyphs (cairo_scaled_font_t        *scaled_font,
+                        const char                 *utf8,
+                        int                         utf8_len,
+                        cairo_glyph_t             **glyphs,
+                        int                        *num_glyphs,
+                        cairo_text_cluster_t      **clusters,
+                        int                        *num_clusters,
+                        cairo_text_cluster_flags_t *cluster_flags)
+{
+  hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font,
+                                                                  &hb_cairo_font_user_data_key);
+
+  hb_buffer_t *buffer = hb_buffer_create ();
+  hb_buffer_add_utf8 (buffer, utf8, utf8_len, 0, utf8_len);
+  hb_buffer_guess_segment_properties (buffer);
+  hb_shape (font, buffer, nullptr, 0);
+
+  hb_cairo_glyphs_from_buffer (buffer,
+                              true,
+                              font->x_scale, font->y_scale,
+                              0., 0.,
+                              utf8, utf8_len,
+                              glyphs, (unsigned *) num_glyphs,
+                              clusters, (unsigned *) num_clusters,
+                              cluster_flags);
+
+  hb_buffer_destroy (buffer);
+
+  return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+hb_cairo_render_glyph (cairo_scaled_font_t  *scaled_font,
+                      unsigned long         glyph,
+                      cairo_t              *cr,
+                      cairo_text_extents_t *extents)
+{
+  hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font,
+                                                                  &hb_cairo_font_user_data_key);
+
+  hb_position_t x_scale, y_scale;
+  hb_font_get_scale (font, &x_scale, &y_scale);
+  cairo_scale (cr, +1./x_scale, -1./y_scale);
+
+  hb_font_draw_glyph (font, glyph, hb_cairo_draw_get_funcs (), cr);
+
+  cairo_fill (cr);
+
+  return CAIRO_STATUS_SUCCESS;
+}
+
+#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
+
+static cairo_status_t
+hb_cairo_render_color_glyph (cairo_scaled_font_t  *scaled_font,
+                            unsigned long         glyph,
+                            cairo_t              *cr,
+                            cairo_text_extents_t *extents)
+{
+  hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font,
+                                                                  &hb_cairo_font_user_data_key);
+
+  unsigned int palette = 0;
+#ifdef CAIRO_COLOR_PALETTE_DEFAULT
+  cairo_font_options_t *options = cairo_font_options_create ();
+  cairo_scaled_font_get_font_options (scaled_font, options);
+  palette = cairo_font_options_get_color_palette (options);
+  cairo_font_options_destroy (options);
+#endif
+
+  hb_color_t color = HB_COLOR (0, 0, 0, 255);
+  hb_position_t x_scale, y_scale;
+  hb_font_get_scale (font, &x_scale, &y_scale);
+  cairo_scale (cr, +1./x_scale, -1./y_scale);
+
+  hb_cairo_context_t c;
+  c.scaled_font = scaled_font;
+  c.cr = cr;
+  c.color_cache = (hb_map_t *) cairo_scaled_font_get_user_data (scaled_font, &color_cache_key);
+
+  hb_font_paint_glyph (font, glyph, hb_cairo_paint_get_funcs (), &c, palette, color);
+
+
+  return CAIRO_STATUS_SUCCESS;
+}
+
+#endif
+
+static cairo_font_face_t *
+user_font_face_create (hb_face_t *face)
+{
+  cairo_font_face_t *cairo_face;
+
+  cairo_face = cairo_user_font_face_create ();
+  cairo_user_font_face_set_init_func (cairo_face, hb_cairo_init_scaled_font);
+  cairo_user_font_face_set_text_to_glyphs_func (cairo_face, hb_cairo_text_to_glyphs);
+  cairo_user_font_face_set_render_glyph_func (cairo_face, hb_cairo_render_glyph);
+#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
+  if (hb_ot_color_has_png (face) || hb_ot_color_has_layers (face) || hb_ot_color_has_paint (face))
+    cairo_user_font_face_set_render_color_glyph_func (cairo_face, hb_cairo_render_color_glyph);
+#endif
+
+  if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (cairo_face,
+                                                                      &hb_cairo_face_user_data_key,
+                                                                      (void *) hb_face_reference (face),
+                                                                      hb_cairo_face_destroy)))
+    hb_face_destroy (face);
+
+  return cairo_face;
+}
+
+/**
+ * hb_cairo_font_face_create_for_font:
+ * @font: a #hb_font_t
+ *
+ * Creates a #cairo_font_face_t for rendering text according
+ * to @font.
+ *
+ * Note that the scale of @font does not affect the rendering,
+ * but the variations and slant that are set on @font do.
+ *
+ * Returns: (transfer full): a newly created #cairo_font_face_t
+ *
+ * Since: 7.0.0
+ */
+cairo_font_face_t *
+hb_cairo_font_face_create_for_font (hb_font_t *font)
+{
+  hb_font_make_immutable (font);
+
+  auto *cairo_face =  user_font_face_create (font->face);
+
+  if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (cairo_face,
+                                                                      &hb_cairo_font_user_data_key,
+                                                                      (void *) hb_font_reference (font),
+                                                                      hb_cairo_font_destroy)))
+    hb_font_destroy (font);
+
+  return cairo_face;
+}
+
+/**
+ * hb_cairo_font_face_get_font:
+ * @font_face: a #cairo_font_face_t
+ *
+ * Gets the #hb_font_t that @font_face was created from.
+ *
+ * Returns: (nullable) (transfer none): the #hb_font_t that @font_face was created from
+ *
+ * Since: 7.0.0
+ */
+hb_font_t *
+hb_cairo_font_face_get_font (cairo_font_face_t *font_face)
+{
+  return (hb_font_t *) cairo_font_face_get_user_data (font_face,
+                                                     &hb_cairo_font_user_data_key);
+}
+
+/**
+ * hb_cairo_font_face_create_for_face:
+ * @face: a #hb_face_t
+ *
+ * Creates a #cairo_font_face_t for rendering text according
+ * to @face.
+ *
+ * Returns: (transfer full): a newly created #cairo_font_face_t
+ *
+ * Since: 7.0.0
+ */
+cairo_font_face_t *
+hb_cairo_font_face_create_for_face (hb_face_t *face)
+{
+  hb_face_make_immutable (face);
+
+  return user_font_face_create (face);
+}
+
+/**
+ * hb_cairo_font_face_get_face:
+ * @font_face: a #cairo_font_face_t
+ *
+ * Gets the #hb_face_t associated with @font_face.
+ *
+ * Returns: (nullable) (transfer none): the #hb_face_t associated with @font_face
+ *
+ * Since: 7.0.0
+ */
+hb_face_t *
+hb_cairo_font_face_get_face (cairo_font_face_t *font_face)
+{
+  return (hb_face_t *) cairo_font_face_get_user_data (font_face,
+                                                     &hb_cairo_face_user_data_key);
+}
+
+/**
+ * hb_cairo_font_face_set_font_init_func:
+ * @font_face: a #cairo_font_face_t
+ * @func: The virtual method to use
+ * @user_data: user data accompanying the method
+ * @destroy: function to call when @user_data is not needed anymore
+ *
+ * Set the virtual method to be called when a cairo
+ * face created using hb_cairo_font_face_create_for_face()
+ * creates an #hb_font_t for a #cairo_scaled_font_t.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_cairo_font_face_set_font_init_func (cairo_font_face_t *font_face,
+                                      hb_cairo_font_init_func_t func,
+                                      void *user_data,
+                                      hb_destroy_func_t destroy)
+{
+  cairo_font_face_set_user_data (font_face,
+                                &hb_cairo_font_init_func_user_data_key,
+                                (void *) func,
+                                nullptr);
+  if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (font_face,
+                                                                      &hb_cairo_font_init_user_data_user_data_key,
+                                                                      (void *) user_data,
+                                                                      destroy)) && destroy)
+  {
+    destroy (user_data);
+    cairo_font_face_set_user_data (font_face,
+                                  &hb_cairo_font_init_func_user_data_key,
+                                  nullptr,
+                                  nullptr);
+  }
+}
+
+/**
+ * hb_cairo_scaled_font_get_font:
+ * @scaled_font: a #cairo_scaled_font_t
+ *
+ * Gets the #hb_font_t associated with @scaled_font.
+ *
+ * Returns: (nullable) (transfer none): the #hb_font_t associated with @scaled_font
+ *
+ * Since: 7.0.0
+ */
+hb_font_t *
+hb_cairo_scaled_font_get_font (cairo_scaled_font_t *scaled_font)
+{
+  return (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font, &hb_cairo_font_user_data_key);
+}
+
+
+/**
+ * hb_cairo_font_face_set_scale_factor:
+ * @scale_factor: The scale factor to use. See below
+ * @font_face: a #cairo_font_face_t
+ *
+ * Sets the scale factor of the @font_face. Default scale
+ * factor is zero.
+ *
+ * When a #cairo_font_face_t is created from a #hb_face_t using
+ * hb_cairo_font_face_create_for_face(), such face will create
+ * #hb_font_t objects during scaled-font creation.  The scale
+ * factor defines how the scale set on such #hb_font_t objects
+ * relates to the font-matrix (as such font size) of the cairo
+ * scaled-font.
+ *
+ * If the scale-factor is zero (default), then the scale of the
+ * #hb_font_t object will be left at default, which is the UPEM
+ * value of the respective #hb_face_t.
+ *
+ * If the scale-factor is set to non-zero, then the X and Y scale
+ * of the #hb_font_t object will be respectively set to the
+ * @scale_factor times the xx and yy elements of the scale-matrix
+ * of the cairo scaled-font being created.
+ *
+ * When using the hb_cairo_glyphs_from_buffer() API to convert the
+ * HarfBuzz glyph buffer that resulted from shaping with such a #hb_font_t,
+ * if the scale-factor was non-zero, you can pass it directly to
+ * that API as both X and Y scale factors.
+ *
+ * If the scale-factor was zero however, or the cairo face was
+ * created using the alternative constructor
+ * hb_cairo_font_face_create_for_font(), you need to calculate the
+ * correct X/Y scale-factors to pass to hb_cairo_glyphs_from_buffer()
+ * by dividing the #hb_font_t X/Y scale-factors by the
+ * cairo scaled-font's scale-matrix XX/YY components respectively
+ * and use those values.  Or if you know that relationship offhand
+ * (because you set the scale of the #hb_font_t yourself), use
+ * the conversion rate involved.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_cairo_font_face_set_scale_factor (cairo_font_face_t *font_face,
+                                    unsigned int scale_factor)
+{
+  cairo_font_face_set_user_data (font_face,
+                                &hb_cairo_scale_factor_user_data_key,
+                                (void *) (uintptr_t) scale_factor,
+                                nullptr);
+}
+
+/**
+ * hb_cairo_font_face_get_scale_factor:
+ * @font_face: a #cairo_font_face_t
+ *
+ * Gets the scale factor set on the @font_face. Defaults to zero.
+ * See hb_cairo_font_face_set_scale_factor() for details.
+ *
+ * Returns: the scale factor of @font_face
+ *
+ * Since: 7.0.0
+ */
+unsigned int
+hb_cairo_font_face_get_scale_factor (cairo_font_face_t *font_face)
+{
+  return (unsigned int) (uintptr_t)
+        cairo_font_face_get_user_data (font_face,
+                                       &hb_cairo_scale_factor_user_data_key);
+}
+
+
+/**
+ * hb_cairo_glyphs_from_buffer:
+ * @buffer: a #hb_buffer_t containing glyphs
+ * @utf8_clusters: `true` if @buffer clusters are in bytes, instead of characters
+ * @x_scale_factor: scale factor to divide #hb_position_t Y values by
+ * @y_scale_factor: scale factor to divide #hb_position_t X values by
+ * @x: X position to place first glyph
+ * @y: Y position to place first glyph
+ * @utf8: (nullable): the text that was shaped in @buffer
+ * @utf8_len: the length of @utf8 in bytes
+ * @glyphs: (out): return location for an array of #cairo_glyph_t
+ * @num_glyphs: (inout): return location for the length of @glyphs
+ * @clusters: (out) (nullable): return location for an array of cluster positions
+ * @num_clusters: (inout) (nullable): return location for the length of @clusters
+ * @cluster_flags: (out) (nullable): return location for cluster flags
+ *
+ * Extracts information from @buffer in a form that can be
+ * passed to cairo_show_text_glyphs() or cairo_show_glyphs().
+ * This API is modeled after cairo_scaled_font_text_to_glyphs() and
+ * cairo_user_scaled_font_text_to_glyphs_func_t.
+ *
+ * The @num_glyphs argument should be preset to the number of glyph entries available
+ * in the @glyphs buffer. If the @glyphs buffer is `NULL`, the value of
+ * @num_glyphs must be zero.  If the provided glyph array is too short for
+ * the conversion (or for convenience), a new glyph array may be allocated
+ * using cairo_glyph_allocate() and placed in @glyphs.  Upon return,
+ * @num_glyphs should contain the number of generated glyphs.  If the value
+ * @glyphs points at has changed after the call, the caller will free the
+ * allocated glyph array using cairo_glyph_free().  The caller will also free
+ * the original value of @glyphs, so this function shouldn't do so.
+ *
+ * If @clusters is not `NULL`, then @num_clusters and @cluster_flags
+ * should not be either, and @utf8 must be provided, and cluster
+ * mapping will be computed. The semantics of how
+ * cluster array allocation works is similar to the glyph array.  That is,
+ * if @clusters initially points to a non-`NULL` value, that array may be used
+ * as a cluster buffer, and @num_clusters points to the number of cluster
+ * entries available there.  If the provided cluster array is too short for
+ * the conversion (or for convenience), a new cluster array may be allocated
+ * using cairo_text_cluster_allocate() and placed in @clusters.  In this case,
+ * the original value of @clusters will still be freed by the caller.  Upon
+ * return, @num_clusters will contain the number of generated clusters.
+ * If the value @clusters points at has changed after the call, the caller
+ * will free the allocated cluster array using cairo_text_cluster_free().
+ *
+ * See hb_cairo_font_face_set_scale_factor() for the details of
+ * the @scale_factor argument.
+ *
+ * The returned @glyphs vector actually has `@num_glyphs + 1` entries in
+ * it and the x,y values of the extra entry at the end add up the advance
+ * x,y of all the glyphs in the @buffer.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer,
+                            hb_bool_t utf8_clusters,
+                            double x_scale_factor,
+                            double y_scale_factor,
+                            double x,
+                            double y,
+                            const char *utf8,
+                            int utf8_len,
+                            cairo_glyph_t **glyphs,
+                            unsigned int *num_glyphs,
+                            cairo_text_cluster_t **clusters,
+                            unsigned int *num_clusters,
+                            cairo_text_cluster_flags_t *cluster_flags)
+{
+  if (utf8 && utf8_len < 0)
+    utf8_len = strlen (utf8);
+
+  unsigned orig_num_glyphs = *num_glyphs;
+  *num_glyphs = hb_buffer_get_length (buffer);
+  hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos (buffer, nullptr);
+  hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions (buffer, nullptr);
+  if (orig_num_glyphs < *num_glyphs + 1)
+    *glyphs = cairo_glyph_allocate (*num_glyphs + 1);
+
+  if (clusters && utf8)
+  {
+    unsigned orig_num_clusters = *num_clusters;
+    *num_clusters = *num_glyphs ? 1 : 0;
+    for (unsigned int i = 1; i < *num_glyphs; i++)
+      if (hb_glyph[i].cluster != hb_glyph[i-1].cluster)
+       (*num_clusters)++;
+    if (orig_num_clusters < *num_clusters)
+      *clusters = cairo_text_cluster_allocate (*num_clusters);
+  }
+
+  double x_scale = x_scale_factor ? 1. / x_scale_factor : 0.;
+  double y_scale = y_scale_factor ? 1. / y_scale_factor : 0.;
+  hb_position_t hx = 0, hy = 0;
+  int i;
+  for (i = 0; i < (int) *num_glyphs; i++)
+  {
+    (*glyphs)[i].index = hb_glyph[i].codepoint;
+    (*glyphs)[i].x = x + (+hb_position->x_offset + hx) * x_scale;
+    (*glyphs)[i].y = y + (-hb_position->y_offset + hy) * y_scale;
+    hx +=  hb_position->x_advance;
+    hy += -hb_position->y_advance;
+
+    hb_position++;
+  }
+  (*glyphs)[i].index = -1;
+  (*glyphs)[i].x = round (hx * x_scale);
+  (*glyphs)[i].y = round (hy * y_scale);
+
+  if (clusters && *num_clusters && utf8)
+  {
+    hb_memset ((void *) *clusters, 0, *num_clusters * sizeof ((*clusters)[0]));
+    hb_bool_t backward = HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (buffer));
+    *cluster_flags = backward ? CAIRO_TEXT_CLUSTER_FLAG_BACKWARD : (cairo_text_cluster_flags_t) 0;
+    unsigned int cluster = 0;
+    const char *start = utf8, *end;
+    (*clusters)[cluster].num_glyphs++;
+    if (backward)
+    {
+      for (i = *num_glyphs - 2; i >= 0; i--)
+      {
+       if (hb_glyph[i].cluster != hb_glyph[i+1].cluster)
+       {
+         assert (hb_glyph[i].cluster > hb_glyph[i+1].cluster);
+         if (utf8_clusters)
+           end = start + hb_glyph[i].cluster - hb_glyph[i+1].cluster;
+         else
+           end = (const char *) hb_utf_offset_to_pointer<hb_utf8_t> ((const uint8_t *) start,
+                                                                     (signed) (hb_glyph[i].cluster - hb_glyph[i+1].cluster));
+         (*clusters)[cluster].num_bytes = end - start;
+         start = end;
+         cluster++;
+       }
+       (*clusters)[cluster].num_glyphs++;
+      }
+      (*clusters)[cluster].num_bytes = utf8 + utf8_len - start;
+    }
+    else
+    {
+      for (i = 1; i < (int) *num_glyphs; i++)
+      {
+       if (hb_glyph[i].cluster != hb_glyph[i-1].cluster)
+       {
+         assert (hb_glyph[i].cluster > hb_glyph[i-1].cluster);
+         if (utf8_clusters)
+           end = start + hb_glyph[i].cluster - hb_glyph[i-1].cluster;
+         else
+           end = (const char *) hb_utf_offset_to_pointer<hb_utf8_t> ((const uint8_t *) start,
+                                                                     (signed) (hb_glyph[i].cluster - hb_glyph[i-1].cluster));
+         (*clusters)[cluster].num_bytes = end - start;
+         start = end;
+         cluster++;
+       }
+       (*clusters)[cluster].num_glyphs++;
+      }
+      (*clusters)[cluster].num_bytes = utf8 + utf8_len - start;
+    }
+  }
+  else if (num_clusters)
+    *num_clusters = 0;
+}
+
+#endif
diff --git a/src/hb-cairo.h b/src/hb-cairo.h
new file mode 100644 (file)
index 0000000..21e284c
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright © 2022 Red Hat, 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): Matthias Clasen
+ */
+
+#ifndef HB_CAIRO_H
+#define HB_CAIRO_H
+
+#include "hb.h"
+
+#include <cairo.h>
+
+HB_BEGIN_DECLS
+
+HB_EXTERN cairo_font_face_t *
+hb_cairo_font_face_create_for_font (hb_font_t *font);
+
+HB_EXTERN hb_font_t *
+hb_cairo_font_face_get_font (cairo_font_face_t *font_face);
+
+HB_EXTERN cairo_font_face_t *
+hb_cairo_font_face_create_for_face (hb_face_t *face);
+
+HB_EXTERN hb_face_t *
+hb_cairo_font_face_get_face (cairo_font_face_t *font_face);
+
+/**
+ * hb_cairo_font_init_func_t:
+ * @font: The #hb_font_t being created
+ * @scaled_font: The respective #cairo_scaled_font_t
+ * @user_data: User data accompanying this method
+ *
+ * The type of a virtual method to be called when a cairo
+ * face created using hb_cairo_font_face_create_for_face()
+ * creates an #hb_font_t for a #cairo_scaled_font_t.
+ *
+ * Return value: the #hb_font_t value to use; in most cases same as @font
+ *
+ * Since: 7.0.0
+ */
+typedef hb_font_t * (*hb_cairo_font_init_func_t) (hb_font_t *font,
+                                                 cairo_scaled_font_t *scaled_font,
+                                                 void *user_data);
+
+HB_EXTERN void
+hb_cairo_font_face_set_font_init_func (cairo_font_face_t *font_face,
+                                      hb_cairo_font_init_func_t func,
+                                      void *user_data,
+                                      hb_destroy_func_t destroy);
+
+HB_EXTERN hb_font_t *
+hb_cairo_scaled_font_get_font (cairo_scaled_font_t *scaled_font);
+
+HB_EXTERN void
+hb_cairo_font_face_set_scale_factor (cairo_font_face_t *font_face,
+                                    unsigned int scale_factor);
+
+HB_EXTERN unsigned int
+hb_cairo_font_face_get_scale_factor (cairo_font_face_t *font_face);
+
+HB_EXTERN void
+hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer,
+                            hb_bool_t utf8_clusters,
+                            double x_scale_factor,
+                            double y_scale_factor,
+                            double x,
+                            double y,
+                            const char *utf8,
+                            int utf8_len,
+                            cairo_glyph_t **glyphs,
+                            unsigned int *num_glyphs,
+                            cairo_text_cluster_t **clusters,
+                            unsigned int *num_clusters,
+                            cairo_text_cluster_flags_t *cluster_flags);
+
+HB_END_DECLS
+
+#endif /* HB_CAIRO_H */
index 641de0e..1d1f10f 100644 (file)
@@ -26,6 +26,8 @@
 #ifndef HB_CFF_INTERP_COMMON_HH
 #define HB_CFF_INTERP_COMMON_HH
 
+extern HB_INTERNAL const unsigned char *endchar_str;
+
 namespace CFF {
 
 using namespace OT;
@@ -248,6 +250,9 @@ struct number_t
 /* byte string */
 struct UnsizedByteStr : UnsizedArrayOf <HBUINT8>
 {
+  hb_ubytes_t as_ubytes (unsigned l) const
+  { return hb_ubytes_t ((const unsigned char *) this, l); }
+
   // encode 2-byte int (Dict/CharString) or 4-byte int (Dict)
   template <typename T, typename V>
   static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, V value)
@@ -274,128 +279,89 @@ struct UnsizedByteStr : UnsizedArrayOf <HBUINT8>
   /* 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 (); }
+  byte_str_ref_t ()
+    : str () {}
 
-  void init ()
-  {
-    str = byte_str_t ();
-    offset = 0;
-    error = false;
-  }
-
-  void fini () {}
+  byte_str_ref_t (const hb_ubytes_t &str_, unsigned int offset_ = 0)
+    : str (str_) { set_offset (offset_); }
 
-  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)
+  void reset (const hb_ubytes_t &str_, unsigned int offset_ = 0)
   {
     str = str_;
-    offset = offset_;
-    error = false;
+    set_offset (offset_);
   }
 
   const unsigned char& operator [] (int i) {
-    if (unlikely ((unsigned int) (offset + i) >= str.length))
+    if (unlikely ((unsigned int) (get_offset () + i) >= str.length))
     {
       set_error ();
       return Null (unsigned char);
     }
-    return str[offset + i];
+    return str.arrayZ[get_offset () + i];
   }
 
-  /* Conversion to byte_str_t */
-  operator byte_str_t () const { return str.sub_str (offset, str.length - offset); }
+  unsigned char head_unchecked () const { return str.arrayZ[get_offset ()]; }
+
+  /* Conversion to hb_ubytes_t */
+  operator hb_ubytes_t () const { return str.sub_array (get_offset ()); }
 
-  byte_str_t sub_str (unsigned int offset_, unsigned int len_) const
-  { return str.sub_str (offset_, len_); }
+  hb_ubytes_t sub_array (unsigned int offset_, unsigned int len_) const
+  { return str.sub_array (offset_, len_); }
 
   bool avail (unsigned int count=1) const
-  { return (!in_error () && str.check_limit (offset, count)); }
+  { return get_offset () + count <= str.length; }
   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 ();
-    }
+    /* Automatically puts us in error if count is out-of-range. */
+    set_offset (get_offset () + count);
   }
 
-  void set_error ()      { error = true; }
-  bool in_error () const { return error; }
+  /* We (ab)use ubytes backwards_length as a cursor (called offset),
+   * as well as to store error condition. */
+
+  unsigned get_offset () const { return str.backwards_length; }
+  void set_offset (unsigned offset) { str.backwards_length = offset; }
 
-  byte_str_t       str;
-  unsigned int  offset; /* beginning of the sub-string within str */
+  void set_error ()      { str.backwards_length = str.length + 1; }
+  bool in_error () const { return str.backwards_length > str.length; }
+
+  unsigned total_size () const { return str.length; }
 
   protected:
-  bool   error;
+  hb_ubytes_t       str;
 };
 
-typedef hb_vector_t<byte_str_t> byte_str_array_t;
-
 /* stack */
 template <typename ELEM, int LIMIT>
 struct cff_stack_t
 {
-  void init ()
-  {
-    error = false;
-    count = 0;
-    elements.init ();
-    elements.resize (kSizeLimit);
-  }
-  void fini () { elements.fini (); }
-
   ELEM& operator [] (unsigned int i)
   {
-    if (unlikely (i >= count)) set_error ();
+    if (unlikely (i >= count))
+    {
+      set_error ();
+      return Crap (ELEM);
+    }
     return elements[i];
   }
 
   void push (const ELEM &v)
   {
-    if (likely (count < elements.length))
+    if (likely (count < LIMIT))
       elements[count++] = v;
     else
       set_error ();
   }
   ELEM &push ()
   {
-    if (likely (count < elements.length))
+    if (likely (count < LIMIT))
       return elements[count++];
     else
     {
@@ -424,7 +390,7 @@ struct cff_stack_t
 
   const ELEM& peek ()
   {
-    if (unlikely (count < 0))
+    if (unlikely (count == 0))
     {
       set_error ();
       return Null (ELEM);
@@ -434,7 +400,7 @@ struct cff_stack_t
 
   void unpop ()
   {
-    if (likely (count < elements.length))
+    if (likely (count < LIMIT))
       count++;
     else
       set_error ();
@@ -442,18 +408,19 @@ struct cff_stack_t
 
   void clear () { count = 0; }
 
-  bool in_error () const { return (error || elements.in_error ()); }
+  bool in_error () const { return (error); }
   void set_error ()      { error = true; }
 
   unsigned int get_count () const { return count; }
   bool is_empty () const          { return !count; }
 
-  static constexpr unsigned kSizeLimit = LIMIT;
+  hb_array_t<const ELEM> sub_array (unsigned start, unsigned length) const
+  { return hb_array_t<const ELEM> (elements).sub_array (start, length); }
 
-  protected:
-  bool error;
-  unsigned int count;
-  hb_vector_t<ELEM> elements;
+  private:
+  bool error = false;
+  unsigned int count = 0;
+  ELEM elements[LIMIT];
 };
 
 /* argument stack */
@@ -508,9 +475,6 @@ struct arg_stack_t : cff_stack_t<ARG, 513>
     return true;
   }
 
-  hb_array_t<const ARG> get_subarray (unsigned int start) const
-  { return S::elements.sub_array (start); }
-
   private:
   typedef cff_stack_t<ARG, 513> S;
 };
@@ -518,8 +482,15 @@ struct arg_stack_t : cff_stack_t<ARG, 513>
 /* an operator prefixed by its operands in a byte string */
 struct op_str_t
 {
-  op_code_t  op;
-  byte_str_t str;
+  /* This used to have a hb_ubytes_t. Using a pointer and length
+   * in a particular order, saves 8 bytes in this struct and more
+   * in our parsed_cs_op_t subclass. */
+
+  const unsigned char *ptr = nullptr;
+
+  op_code_t  op = OpCode_Invalid;
+
+  uint8_t length = 0;
 };
 
 /* base of OP_SERIALIZER */
@@ -530,9 +501,11 @@ struct op_serializer_t
   {
     TRACE_SERIALIZE (this);
 
-    HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length);
+    unsigned char *d = c->allocate_size<unsigned char> (opstr.length);
     if (unlikely (!d)) return_trace (false);
-    memcpy (d, &opstr.str[0], opstr.str.length);
+    /* Faster than hb_memcpy for small strings. */
+    for (unsigned i = 0; i < opstr.length; i++)
+      d[i] = opstr.ptr[i];
     return_trace (true);
   }
 };
@@ -547,32 +520,30 @@ struct parsed_values_t
   }
   void fini () { values.fini (); }
 
-  void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t ())
+  void alloc (unsigned n)
   {
-    VAL *val = values.push ();
-    val->op = op;
-    val->str = str_ref.str.sub_str (opStart, str_ref.offset - opStart);
-    opStart = str_ref.offset;
+    values.alloc (n, true);
   }
 
-  void add_op (op_code_t op, const byte_str_ref_t& str_ref, const VAL &v)
+  void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t (), const VAL &v = VAL ())
   {
     VAL *val = values.push (v);
     val->op = op;
-    val->str = str_ref.sub_str ( opStart, str_ref.offset - opStart);
-    opStart = str_ref.offset;
+    auto arr = str_ref.sub_array (opStart, str_ref.get_offset () - opStart);
+    val->ptr = arr.arrayZ;
+    val->length = arr.length;
+    opStart = str_ref.get_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;
+    for (const auto& v : values)
+      if (v.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); }
+  const VAL &operator [] (unsigned int i) const { return values[i]; }
 
   unsigned int       opStart;
   hb_vector_t<VAL>   values;
@@ -581,32 +552,29 @@ struct parsed_values_t
 template <typename ARG=number_t>
 struct interp_env_t
 {
-  void init (const byte_str_t &str_)
+  interp_env_t () {}
+  interp_env_t (const hb_ubytes_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 (); }
+  { return str_ref.in_error () || argStack.in_error (); }
 
-  void set_error () { error = true; }
+  void set_error () { str_ref.set_error (); }
 
   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];
+    op = (op_code_t) str_ref.head_unchecked ();
+    str_ref.inc ();
     if (op == OpCode_escape) {
       if (unlikely (!str_ref.avail ()))
        return OpCode_Invalid;
-      op = Make_OpCode_ESC(str_ref[1]);
+      op = Make_OpCode_ESC (str_ref.head_unchecked ());
       str_ref.inc ();
     }
-    str_ref.inc ();
     return op;
   }
 
@@ -621,11 +589,9 @@ struct interp_env_t
                str_ref;
   arg_stack_t<ARG>
                argStack;
-  protected:
-  bool         error;
 };
 
-typedef interp_env_t<> num_interp_env_t;
+using num_interp_env_t =  interp_env_t<>;
 
 template <typename ARG=number_t>
 struct opset_t
@@ -668,11 +634,8 @@ struct opset_t
 template <typename ENV>
 struct interpreter_t
 {
-  ~interpreter_t() { fini (); }
-
-  void fini () { env.fini (); }
-
-  ENV env;
+  interpreter_t (ENV& env_) : env (env_) {}
+  ENV& env;
 };
 
 } /* namespace CFF */
index ef29936..28a777e 100644 (file)
@@ -79,10 +79,10 @@ struct biased_subrs_t
   unsigned int get_count () const { return subrs ? subrs->count : 0; }
   unsigned int get_bias () const  { return bias; }
 
-  byte_str_t operator [] (unsigned int index) const
+  hb_ubytes_t operator [] (unsigned int index) const
   {
     if (unlikely (!subrs || index >= subrs->count))
-      return Null (byte_str_t);
+      return hb_ubytes_t ();
     else
       return (*subrs)[index];
   }
@@ -112,10 +112,9 @@ struct point_t
 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_)
+  cs_interp_env_t (const hb_ubytes_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_) :
+    interp_env_t<ARG> (str)
   {
-    interp_env_t<ARG>::init (str);
-
     context.init (str, CSType_CharString);
     seen_moveto = true;
     seen_hintmask = false;
@@ -123,15 +122,11 @@ struct cs_interp_env_t : interp_env_t<ARG>
     vstem_count = 0;
     hintmask_size = 0;
     pt.set_int (0, 0);
-    callStack.init ();
     globalSubrs.init (globalSubrs_);
     localSubrs.init (localSubrs_);
   }
-  void fini ()
+  ~cs_interp_env_t ()
   {
-    interp_env_t<ARG>::fini ();
-
-    callStack.fini ();
     globalSubrs.fini ();
     localSubrs.fini ();
   }
@@ -880,14 +875,20 @@ struct path_procs_t
 template <typename ENV, typename OPSET, typename PARAM>
 struct cs_interpreter_t : interpreter_t<ENV>
 {
+  cs_interpreter_t (ENV& env_) : interpreter_t<ENV> (env_) {}
+
   bool interpret (PARAM& param)
   {
     SUPER::env.set_endchar (false);
 
+    unsigned max_ops = HB_CFF_MAX_OPS;
     for (;;) {
       OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
-      if (unlikely (SUPER::env.in_error ()))
+      if (unlikely (SUPER::env.in_error () || !--max_ops))
+      {
+       SUPER::env.set_error ();
        return false;
+      }
       if (SUPER::env.is_endchar ())
        break;
     }
index a520ca3..53226b2 100644 (file)
@@ -35,10 +35,8 @@ 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 init () {}
   void fini () {}
-
-  number_t           single_val;
 };
 
 typedef dict_val_t num_dict_val_t;
@@ -179,6 +177,8 @@ struct top_dict_opset_t : dict_opset_t
 template <typename OPSET, typename PARAM, typename ENV=num_interp_env_t>
 struct dict_interpreter_t : interpreter_t<ENV>
 {
+  dict_interpreter_t (ENV& env_) : interpreter_t<ENV> (env_) {}
+
   bool interpret (PARAM& param)
   {
     param.init ();
index 1c8762c..d8868ef 100644 (file)
@@ -38,17 +38,16 @@ 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)
+  cff1_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd,
+                       const int *coords_=nullptr, unsigned int num_coords_=0)
+    : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs)
   {
-    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)))
@@ -154,7 +153,7 @@ struct cff1_cs_opset_t : cs_opset_t<number_t, OPSET, cff1_cs_interp_env_t, PARAM
 };
 
 template <typename OPSET, typename PARAM>
-struct cff1_cs_interpreter_t : cs_interpreter_t<cff1_cs_interp_env_t, OPSET, PARAM> {};
+using cff1_cs_interpreter_t = cs_interpreter_t<cff1_cs_interp_env_t, OPSET, PARAM>;
 
 } /* namespace CFF */
 
index 7661837..915b10c 100644 (file)
@@ -40,20 +40,22 @@ struct blend_arg_t : number_t
   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_)
+                  hb_array_t<const blend_arg_t> blends_)
   {
     numValues = numValues_;
     valueIndex = valueIndex_;
-    deltas.resize (numBlends);
+    unsigned numBlends = blends_.length;
+    if (unlikely (!deltas.resize_exact (numBlends)))
+      return;
     for (unsigned int i = 0; i < numBlends; i++)
-      deltas[i] = blends_[i];
+      deltas.arrayZ[i] = blends_.arrayZ[i];
   }
 
   bool blending () const { return deltas.length > 0; }
   void reset_blends ()
   {
     numValues = valueIndex = 0;
-    deltas.resize (0);
+    deltas.shrink (0);
   }
 
   unsigned int numValues;
@@ -61,17 +63,16 @@ struct blend_arg_t : number_t
   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 ELEM>
+struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, 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)
+  cff2_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd,
+                       const int *coords_=nullptr, unsigned int num_coords_=0)
+    : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs)
   {
-    SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs);
-
     coords = coords_;
     num_coords = num_coords_;
     varStore = acc.varStore;
@@ -100,18 +101,14 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
       return OpCode_return;
   }
 
-  const blend_arg_t& eval_arg (unsigned int i)
+  const ELEM& eval_arg (unsigned int i)
   {
-    blend_arg_t  &arg = argStack[i];
-    blend_arg (arg);
-    return arg;
+    return SUPER::argStack[i];
   }
 
-  const blend_arg_t& pop_arg ()
+  const ELEM& pop_arg ()
   {
-    blend_arg_t  &arg = argStack.pop ();
-    blend_arg (arg);
-    return arg;
+    return SUPER::argStack.pop ();
   }
 
   void process_blend ()
@@ -121,8 +118,8 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
       region_count = varStore->varStore.get_region_index_count (get_ivs ());
       if (do_blend)
       {
-       if (unlikely (!scalars.resize (region_count)))
-         set_error ();
+       if (unlikely (!scalars.resize_exact (region_count)))
+         SUPER::set_error ();
        else
          varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
                                                 &scalars[0], region_count);
@@ -133,10 +130,10 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
 
   void process_vsindex ()
   {
-    unsigned int  index = argStack.pop_uint ();
+    unsigned int  index = SUPER::argStack.pop_uint ();
     if (unlikely (seen_vsindex () || seen_blend))
     {
-      set_error ();
+     SUPER::set_error ();
     }
     else
     {
@@ -151,24 +148,23 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
   void  set_ivs (unsigned int ivs_) { ivs = ivs_; }
   bool  seen_vsindex () const { return seen_vsindex_; }
 
-  protected:
-  void blend_arg (blend_arg_t &arg)
+  double blend_deltas (hb_array_t<const ELEM> deltas) const
   {
-    if (do_blend && arg.blending ())
+    double v = 0;
+    if (do_blend)
     {
-      if (likely (scalars.length == arg.deltas.length))
+      if (likely (scalars.length == 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);
+        unsigned count = scalars.length;
+       for (unsigned i = 0; i < count; i++)
+         v += (double) scalars.arrayZ[i] * deltas.arrayZ[i].to_real ();
       }
     }
+    return v;
   }
 
+  bool have_coords () const { return num_coords; }
+
   protected:
   const int     *coords;
   unsigned int  num_coords;
@@ -180,22 +176,24 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
   bool   seen_vsindex_;
   bool   seen_blend;
 
-  typedef cs_interp_env_t<blend_arg_t, CFF2Subrs> SUPER;
+  typedef cs_interp_env_t<ELEM, 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>
+template <typename OPSET, typename PARAM, typename ELEM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t<ELEM>, PARAM>>
+struct cff2_cs_opset_t : cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH>
 {
-  static void process_op (op_code_t op, cff2_cs_interp_env_t &env, PARAM& param)
+  static void process_op (op_code_t op, cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
   {
     switch (op) {
       case OpCode_callsubr:
       case OpCode_callgsubr:
        /* a subroutine number shouldn't be a blended value */
+#if 0
        if (unlikely (env.argStack.peek ().blending ()))
        {
          env.set_error ();
          break;
        }
+#endif
        SUPER::process_op (op, env, param);
        break;
 
@@ -204,11 +202,13 @@ struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PA
        break;
 
       case OpCode_vsindexcs:
+#if 0
        if (unlikely (env.argStack.peek ().blending ()))
        {
          env.set_error ();
          break;
        }
+#endif
        OPSET::process_vsindex (env, param);
        break;
 
@@ -217,7 +217,29 @@ struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PA
     }
   }
 
-  static void process_blend (cff2_cs_interp_env_t &env, PARAM& param)
+  template <typename T = ELEM,
+           hb_enable_if (hb_is_same (T, blend_arg_t))>
+  static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env,
+                                ELEM &arg,
+                                const hb_array_t<const ELEM> blends,
+                                unsigned n, unsigned i)
+  {
+    if (env.have_coords ())
+      arg.set_int (round (arg.to_real () + env.blend_deltas (blends)));
+    else
+      arg.set_blends (n, i, blends);
+  }
+  template <typename T = ELEM,
+           hb_enable_if (!hb_is_same (T, blend_arg_t))>
+  static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env,
+                                ELEM &arg,
+                                const hb_array_t<const ELEM> blends,
+                                unsigned n, unsigned i)
+  {
+    arg.set_real (arg.to_real () + env.blend_deltas (blends));
+  }
+
+  static void process_blend (cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
   {
     unsigned int n, k;
 
@@ -234,26 +256,26 @@ struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PA
     }
     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);
+      const hb_array_t<const ELEM> blends = env.argStack.sub_array (start + n + (i * k), k);
+      process_arg_blend (env, env.argStack[start + i], blends, n, i);
     }
 
     /* 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)
+  static void process_vsindex (cff2_cs_interp_env_t<ELEM> &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;
+  typedef cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH>  SUPER;
 };
 
-template <typename OPSET, typename PARAM>
-struct cff2_cs_interpreter_t : cs_interpreter_t<cff2_cs_interp_env_t, OPSET, PARAM> {};
+template <typename OPSET, typename PARAM, typename ELEM>
+using cff2_cs_interpreter_t = cs_interpreter_t<cff2_cs_interp_env_t<ELEM>, OPSET, PARAM>;
 
 } /* namespace CFF */
 
index 41229b9..0c13c7d 100644 (file)
 #include "hb.hh"
 #include "hb-machinery.hh"
 
-#if !defined(HB_NO_SETLOCALE) && (!defined(HAVE_NEWLOCALE) || !defined(HAVE_USELOCALE))
-#define HB_NO_SETLOCALE 1
-#endif
-
-#ifndef HB_NO_SETLOCALE
-
-#include <locale.h>
-#ifdef HAVE_XLOCALE_H
-#include <xlocale.h> // Needed on BSD/OS X for uselocale
-#endif
-
-#ifdef WIN32
-#define hb_locale_t _locale_t
-#else
-#define hb_locale_t locale_t
-#endif
-#define hb_setlocale setlocale
-#define hb_uselocale uselocale
-
-#else
-
-#define hb_locale_t void *
-#define hb_setlocale(Category, Locale) "C"
-#define hb_uselocale(Locale) ((hb_locale_t) 0)
-
-#endif
 
 /**
  * SECTION:hb-common
@@ -99,7 +73,7 @@ _hb_options_init ()
   }
 
   /* This is idempotent and threadsafe. */
-  _hb_options.set_relaxed (u.i);
+  _hb_options = u.i;
 }
 
 
@@ -108,7 +82,7 @@ _hb_options_init ()
 /**
  * hb_tag_from_string:
  * @str: (array length=len) (element-type uint8_t): String to convert
- * @len: Length of @str, or -1 if it is %NULL-terminated
+ * @len: Length of @str, or -1 if it is `NULL`-terminated
  *
  * Converts a string into an #hb_tag_t. Valid tags
  * are four characters. Shorter input strings will be
@@ -160,7 +134,7 @@ hb_tag_to_string (hb_tag_t tag, char *buf)
 
 /* hb_direction_t */
 
-const char direction_strings[][4] = {
+static const char direction_strings[][4] = {
   "ltr",
   "rtl",
   "ttb",
@@ -170,7 +144,7 @@ const char direction_strings[][4] = {
 /**
  * hb_direction_from_string:
  * @str: (array length=len) (element-type uint8_t): String to convert
- * @len: Length of @str, or -1 if it is %NULL-terminated
+ * @len: Length of @str, or -1 if it is `NULL`-terminated
  *
  * Converts a string to an #hb_direction_t.
  *
@@ -285,7 +259,7 @@ struct hb_language_item_t {
     lang = (hb_language_t) hb_malloc(len);
     if (likely (lang))
     {
-      memcpy((unsigned char *) lang, s, len);
+      hb_memcpy((unsigned char *) lang, s, len);
       for (unsigned char *p = (unsigned char *) lang; *p; p++)
        *p = canon_map[*p];
     }
@@ -357,7 +331,7 @@ retry:
  * hb_language_from_string:
  * @str: (array length=len) (element-type uint8_t): a string representing
  *       a BCP 47 language tag
- * @len: length of the @str, or -1 if it is %NULL-terminated.
+ * @len: length of the @str, or -1 if it is `NULL`-terminated.
  *
  * Converts @str representing a BCP 47 language tag to the corresponding
  * #hb_language_t.
@@ -379,7 +353,7 @@ hb_language_from_string (const char *str, int len)
     /* NUL-terminate it. */
     char strbuf[64];
     len = hb_min (len, (int) sizeof (strbuf) - 1);
-    memcpy (strbuf, str, len);
+    hb_memcpy (strbuf, str, len);
     strbuf[len] = '\0';
     item = lang_find_or_insert (strbuf);
   }
@@ -396,7 +370,7 @@ hb_language_from_string (const char *str, int len)
  * Converts an #hb_language_t to a string.
  *
  * Return value: (transfer none):
- * A %NULL-terminated string representing the @language. Must not be freed by
+ * A `NULL`-terminated string representing the @language. Must not be freed by
  * the caller.
  *
  * Since: 0.9.2
@@ -441,6 +415,38 @@ hb_language_get_default ()
   return language;
 }
 
+/**
+ * hb_language_matches:
+ * @language: The #hb_language_t to work on
+ * @specific: Another #hb_language_t
+ *
+ * Check whether a second language tag is the same or a more
+ * specific version of the provided language tag.  For example,
+ * "fa_IR.utf8" is a more specific tag for "fa" or for "fa_IR".
+ *
+ * Return value: `true` if languages match, `false` otherwise.
+ *
+ * Since: 5.0.0
+ **/
+hb_bool_t
+hb_language_matches (hb_language_t language,
+                    hb_language_t specific)
+{
+  if (language == specific) return true;
+  if (!language || !specific) return false;
+
+  const char *l = language->s;
+  const char *s = specific->s;
+  unsigned ll = strlen (l);
+  unsigned sl = strlen (s);
+
+  if (ll > sl)
+    return false;
+
+  return strncmp (l, s, ll) == 0 &&
+        (s[ll] == '\0' || s[ll] == '-');
+}
+
 
 /* hb_script_t */
 
@@ -498,7 +504,7 @@ hb_script_from_iso15924_tag (hb_tag_t tag)
  * hb_script_from_string:
  * @str: (array length=len) (element-type uint8_t): a string representing an
  *       ISO 15924 tag.
- * @len: length of the @str, or -1 if it is %NULL-terminated.
+ * @len: length of the @str, or -1 if it is `NULL`-terminated.
  *
  * Converts a string @str representing an ISO 15924 script tag to a
  * corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
@@ -626,6 +632,7 @@ hb_script_get_horizontal_direction (hb_script_t script)
     case HB_SCRIPT_OLD_HUNGARIAN:
     case HB_SCRIPT_OLD_ITALIC:
     case HB_SCRIPT_RUNIC:
+    case HB_SCRIPT_TIFINAGH:
 
       return HB_DIRECTION_INVALID;
   }
@@ -693,8 +700,8 @@ hb_version_string ()
  * Tests the library version against a minimum value,
  * as three integer components.
  *
- * Return value: %true if the library is equal to or greater than
- * the test value, %false otherwise
+ * Return value: `true` if the library is equal to or greater than
+ * the test value, `false` otherwise
  *
  * Since: 0.9.30
  **/
@@ -808,7 +815,7 @@ parse_tag (const char **pp, const char *end, hb_tag_t *tag)
   }
 
   const char *p = *pp;
-  while (*pp < end && (ISALNUM(**pp) || **pp == '_'))
+  while (*pp < end && (**pp != ' ' && **pp != '=' && **pp != '[' && **pp != quote))
     (*pp)++;
 
   if (p == *pp || *pp - p > 4)
@@ -881,7 +888,7 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
 /**
  * hb_feature_from_string:
  * @str: (array length=len) (element-type uint8_t): a string to parse
- * @len: length of @str, or -1 if string is %NULL terminated
+ * @len: length of @str, or -1 if string is `NULL` terminated
  * @feature: (out): the #hb_feature_t to initialize with the parsed values
  *
  * Parses a string into a #hb_feature_t.
@@ -923,7 +930,7 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
  * </informaltable>
  *
  * Return value:
- * %true if @str is successfully parsed, %false otherwise
+ * `true` if @str is successfully parsed, `false` otherwise
  *
  * Since: 0.9.5
  **/
@@ -944,7 +951,7 @@ hb_feature_from_string (const char *str, int len,
   }
 
   if (feature)
-    memset (feature, 0, sizeof (*feature));
+    hb_memset (feature, 0, sizeof (*feature));
   return false;
 }
 
@@ -954,7 +961,7 @@ hb_feature_from_string (const char *str, int len,
  * @buf: (array length=size) (out): output string
  * @size: the allocated size of @buf
  *
- * Converts a #hb_feature_t into a %NULL-terminated string in the format
+ * Converts a #hb_feature_t into a `NULL`-terminated string in the format
  * understood by hb_feature_from_string(). The client in responsible for
  * allocating big enough size for @buf, 128 bytes is more than enough.
  *
@@ -993,7 +1000,7 @@ hb_feature_to_string (hb_feature_t *feature,
   }
   assert (len < ARRAY_LENGTH (s));
   len = hb_min (len, size - 1);
-  memcpy (buf, s, len);
+  hb_memcpy (buf, s, len);
   buf[len] = '\0';
 }
 
@@ -1022,7 +1029,7 @@ parse_one_variation (const char **pp, const char *end, hb_variation_t *variation
 /**
  * hb_variation_from_string:
  * @str: (array length=len) (element-type uint8_t): a string to parse
- * @len: length of @str, or -1 if string is %NULL terminated
+ * @len: length of @str, or -1 if string is `NULL` terminated
  * @variation: (out): the #hb_variation_t to initialize with the parsed values
  *
  * Parses a string into a #hb_variation_t.
@@ -1035,7 +1042,7 @@ parse_one_variation (const char **pp, const char *end, hb_variation_t *variation
  * number. For example `wght=500`, or `slnt=-7.5`.
  *
  * Return value:
- * %true if @str is successfully parsed, %false otherwise
+ * `true` if @str is successfully parsed, `false` otherwise
  *
  * Since: 1.4.2
  */
@@ -1056,7 +1063,7 @@ hb_variation_from_string (const char *str, int len,
   }
 
   if (variation)
-    memset (variation, 0, sizeof (*variation));
+    hb_memset (variation, 0, sizeof (*variation));
   return false;
 }
 
@@ -1104,10 +1111,10 @@ get_C_locale ()
 /**
  * hb_variation_to_string:
  * @variation: an #hb_variation_t to convert
- * @buf: (array length=size) (out): output string
+ * @buf: (array length=size) (out caller-allocates): output string
  * @size: the allocated size of @buf
  *
- * Converts an #hb_variation_t into a %NULL-terminated string in the format
+ * Converts an #hb_variation_t into a `NULL`-terminated string in the format
  * understood by hb_variation_from_string(). The client in responsible for
  * allocating big enough size for @buf, 128 bytes is more than enough.
  *
@@ -1134,7 +1141,7 @@ hb_variation_to_string (hb_variation_t *variation,
 
   assert (len < ARRAY_LENGTH (s));
   len = hb_min (len, size - 1);
-  memcpy (buf, s, len);
+  hb_memcpy (buf, s, len);
   buf[len] = '\0';
 }
 
index 0f0cfe9..a9fe666 100644 (file)
@@ -104,6 +104,16 @@ typedef int hb_bool_t;
  *
  **/
 typedef uint32_t hb_codepoint_t;
+
+/**
+ * HB_CODEPOINT_INVALID:
+ *
+ * Unused #hb_codepoint_t value.
+ *
+ * Since: 8.0.0
+ */
+#define HB_CODEPOINT_INVALID ((hb_codepoint_t) -1)
+
 /**
  * hb_position_t:
  * 
@@ -130,6 +140,16 @@ typedef union _hb_var_int_t {
   int8_t i8[4];
 } hb_var_int_t;
 
+typedef union _hb_var_num_t {
+  float f;
+  uint32_t u32;
+  int32_t i32;
+  uint16_t u16[2];
+  int16_t i16[2];
+  uint8_t u8[4];
+  int8_t i8[4];
+} hb_var_num_t;
+
 
 /* hb_tag_t */
 
@@ -316,6 +336,9 @@ hb_language_to_string (hb_language_t language);
 HB_EXTERN hb_language_t
 hb_language_get_default (void);
 
+HB_EXTERN hb_bool_t
+hb_language_matches (hb_language_t language,
+                    hb_language_t specific);
 
 /**
  * hb_script_t:
@@ -482,6 +505,8 @@ hb_language_get_default (void);
  * @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0
  * @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0
  * @HB_SCRIPT_MATH: `Zmth`, Since: 3.4.0
+ * @HB_SCRIPT_KAWI: `Kawi`, Since: 5.2.0
+ * @HB_SCRIPT_NAG_MUNDARI: `Nagm`, Since: 5.2.0
  * @HB_SCRIPT_INVALID: No script set
  *
  * Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding
@@ -703,6 +728,12 @@ typedef enum
    */
   HB_SCRIPT_MATH                       = HB_TAG ('Z','m','t','h'),
 
+  /*
+   * Since 5.2.0
+   */
+  HB_SCRIPT_KAWI                       = HB_TAG ('K','a','w','i'), /*15.0*/
+  HB_SCRIPT_NAG_MUNDARI                        = HB_TAG ('N','a','g','m'), /*15.0*/
+
   /* No script set. */
   HB_SCRIPT_INVALID                    = HB_TAG_NONE,
 
@@ -876,6 +907,32 @@ HB_EXTERN uint8_t
 hb_color_get_blue (hb_color_t color);
 #define hb_color_get_blue(color)       (((color) >> 24) & 0xFF)
 
+/**
+ * hb_glyph_extents_t:
+ * @x_bearing: Distance from the x-origin to the left extremum of the glyph.
+ * @y_bearing: Distance from the top extremum of the glyph to the y-origin.
+ * @width: Distance from the left extremum of the glyph to the right extremum.
+ * @height: Distance from the top extremum of the glyph to the bottom extremum.
+ *
+ * Glyph extent values, measured in font units.
+ *
+ * Note that @height is negative, in coordinate systems that grow up.
+ **/
+typedef struct hb_glyph_extents_t {
+  hb_position_t x_bearing;
+  hb_position_t y_bearing;
+  hb_position_t width;
+  hb_position_t height;
+} hb_glyph_extents_t;
+
+/**
+ * hb_font_t:
+ *
+ * Data type for holding fonts.
+ *
+ */
+typedef struct hb_font_t hb_font_t;
+
 HB_END_DECLS
 
 #endif /* HB_COMMON_H */
index 5141ad8..816c55c 100644 (file)
 #include "config.h"
 #endif
 
+#ifndef HB_EXPERIMENTAL_API
+#define HB_NO_BEYOND_64K
+#define HB_NO_CUBIC_GLYF
+#define HB_NO_VAR_COMPOSITES
+#endif
 
 #ifdef HB_TINY
 #define HB_LEAN
 #define HB_MINI
+#define HB_OPTIMIZE_SIZE
+#define HB_OPTIMIZE_SIZE_MORE
+#define HB_MINIMIZE_MEMORY_USAGE
 #define HB_NO_MT
 #define HB_NO_UCD_UNASSIGNED
 #ifndef NDEBUG
 #define NDEBUG
 #endif
-#ifndef __OPTIMIZE_SIZE__
-#define __OPTIMIZE_SIZE__
-#endif
 #endif
 
 #ifdef HB_LEAN
 #define HB_NO_FACE_COLLECT_UNICODES
 #define HB_NO_GETENV
 #define HB_NO_HINTING
+#define HB_NO_LANGUAGE_LONG
 #define HB_NO_LANGUAGE_PRIVATE_SUBTAG
 #define HB_NO_LAYOUT_FEATURE_PARAMS
 #define HB_NO_LAYOUT_COLLECT_GLYPHS
+#define HB_NO_LAYOUT_RARELY_USED
 #define HB_NO_LAYOUT_UNUSED
 #define HB_NO_MATH
 #define HB_NO_META
 #define HB_NO_MMAP
 #define HB_NO_NAME
 #define HB_NO_OPEN
-#define HB_NO_SETLOCALE
 #define HB_NO_OT_FONT_GLYPH_NAMES
 #define HB_NO_OT_SHAPE_FRACTIONS
+#define HB_NO_PAINT
+#define HB_NO_SETLOCALE
 #define HB_NO_STYLE
 #define HB_NO_SUBSET_LAYOUT
+#define HB_NO_VERTICAL
 #define HB_NO_VAR
 #endif
 
 #ifdef HB_MINI
 #define HB_NO_AAT
 #define HB_NO_LEGACY
+#define HB_NO_BORING_EXPANSION
+#endif
+
+#ifdef __OPTIMIZE_SIZE__
+#ifndef HB_OPTIMIZE_SIZE
+#define HB_OPTIMIZE_SIZE
+#endif
 #endif
 
 #if defined(HAVE_CONFIG_OVERRIDE_H) || defined(HB_CONFIG_OVERRIDE_H)
 
 /* Closure of options. */
 
+#ifdef HB_NO_BORING_EXPANSION
+#define HB_NO_BEYOND_64K
+#define HB_NO_CUBIC_GLYF
+#define HB_NO_VAR_COMPOSITES
+#endif
+
 #ifdef HB_DISABLE_DEPRECATED
 #define HB_IF_NOT_DEPRECATED(x)
 #else
 #define HB_IF_NOT_DEPRECATED(x) x
 #endif
 
+#ifdef HB_NO_SHAPER
+#define HB_NO_OT_SHAPE
+#define HB_NO_AAT_SHAPE
+#endif
+
 #ifdef HB_NO_AAT
 #define HB_NO_OT_NAME_LANGUAGE_AAT
 #define HB_NO_AAT_SHAPE
 #define HB_NO_SUBSET_CFF
 #endif
 
+#ifdef HB_NO_DRAW
+#define HB_NO_OUTLINE
+#endif
+
 #ifdef HB_NO_GETENV
 #define HB_NO_UNISCRIBE_BUG_COMPATIBLE
 #endif
 #endif
 
 #ifdef HB_NO_OT_SHAPE_FALLBACK
-#define HB_NO_OT_SHAPE_COMPLEX_ARABIC_FALLBACK
-#define HB_NO_OT_SHAPE_COMPLEX_HEBREW_FALLBACK
-#define HB_NO_OT_SHAPE_COMPLEX_THAI_FALLBACK
-#define HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS
+#define HB_NO_OT_SHAPER_ARABIC_FALLBACK
+#define HB_NO_OT_SHAPER_HEBREW_FALLBACK
+#define HB_NO_OT_SHAPER_THAI_FALLBACK
+#define HB_NO_OT_SHAPER_VOWEL_CONSTRAINTS
+#define HB_NO_OT_SHAPER_MYANMAR_ZAWGYI
 #endif
 
-#ifdef NDEBUG
-#ifndef HB_NDEBUG
-#define HB_NDEBUG
-#endif
+#ifdef HB_OPTIMIZE_SIZE_MORE
+#define HB_NO_OT_RULESETS_FAST_PATH
 #endif
 
-#ifdef __OPTIMIZE_SIZE__
-#ifndef HB_OPTIMIZE_SIZE
-#define HB_OPTIMIZE_SIZE
+#ifdef HB_MINIMIZE_MEMORY_USAGE
+#define HB_NO_GDEF_CACHE
+#define HB_NO_OT_LAYOUT_LOOKUP_CACHE
+#define HB_NO_OT_FONT_ADVANCE_CACHE
+#define HB_NO_OT_FONT_CMAP_CACHE
 #endif
+
+#ifdef HB_OPTIMIZE_SIZE
+#define HB_OPTIMIZE_SIZE_VAL 1
+#else
+#define HB_OPTIMIZE_SIZE_VAL 0
 #endif
 
+#ifdef HB_MINIMIZE_MEMORY_USAGE
+#define HB_MINIMIZE_MEMORY_USAGE_VAL 1
+#else
+#define HB_MINIMIZE_MEMORY_USAGE_VAL 0
+#endif
 
 #endif /* HB_CONFIG_HH */
index 5f38306..a87cb5c 100644 (file)
@@ -332,7 +332,7 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
     return nullptr;
   }
 
-  if (font->coords)
+  if (font->num_coords)
   {
     CFMutableDictionaryRef variations =
       CFDictionaryCreateMutable (kCFAllocatorDefault,
@@ -347,10 +347,13 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
       hb_ot_var_axis_info_t info;
       unsigned int c = 1;
       hb_ot_var_get_axis_infos (font->face, i, &c, &info);
-      CFDictionarySetValue (variations,
-       CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &info.tag),
-       CFNumberCreate (kCFAllocatorDefault, kCFNumberFloatType, &font->design_coords[i])
-      );
+      float v = hb_clamp (font->design_coords[i], info.min_value, info.max_value);
+
+      CFNumberRef tag_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &info.tag);
+      CFNumberRef value_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberFloatType, &v);
+      CFDictionarySetValue (variations, tag_number, value_number);
+      CFRelease (tag_number);
+      CFRelease (value_number);
     }
 
     CFDictionaryRef attributes =
@@ -379,37 +382,6 @@ _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) - (CGFloat) font->ptem) > (CGFloat) .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;
-}
-
 /**
  * hb_coretext_font_create:
  * @ct_font: The CTFontRef to work upon
@@ -455,8 +427,8 @@ hb_coretext_font_create (CTFontRef ct_font)
 CTFontRef
 hb_coretext_font_get_ct_font (hb_font_t *font)
 {
-  const hb_coretext_font_data_t *data = hb_coretext_font_data_sync (font);
-  return data ? (CTFontRef) data : nullptr;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
+  return ct_font ? (CTFontRef) ct_font : nullptr;
 }
 
 
@@ -516,7 +488,7 @@ _hb_coretext_shape (hb_shape_plan_t    *shape_plan,
 {
   hb_face_t *face = font->face;
   CGFontRef cg_font = (CGFontRef) (const void *) face->data.coretext;
-  CTFontRef ct_font = (CTFontRef) hb_coretext_font_data_sync (font);
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
 
   CGFloat ct_font_size = CTFontGetSize (ct_font);
   CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
@@ -539,7 +511,6 @@ _hb_coretext_shape (hb_shape_plan_t    *shape_plan,
        buffer->merge_clusters (i - 1, i + 1);
   }
 
-  hb_vector_t<feature_record_t> feature_records;
   hb_vector_t<range_record_t> range_records;
 
   /*
@@ -679,7 +650,7 @@ _hb_coretext_shape (hb_shape_plan_t    *shape_plan,
       } else {
        active_feature_t *feature = active_features.lsearch (event->feature);
        if (feature)
-         active_features.remove (feature - active_features.arrayZ);
+         active_features.remove_ordered (feature - active_features.arrayZ);
       }
     }
   }
@@ -897,7 +868,7 @@ resize_and_retry:
     DEBUG_MSG (CORETEXT, nullptr, "Num runs: %d", num_runs);
 
     buffer->len = 0;
-    uint32_t status_and = ~0, status_or = 0;
+    uint32_t status_or = 0;
     CGFloat advances_so_far = 0;
     /* For right-to-left runs, CoreText returns the glyphs positioned such that
      * any trailing whitespace is to the left of (0,0).  Adjust coordinate system
@@ -918,7 +889,6 @@ resize_and_retry:
       CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex (glyph_runs, i));
       CTRunStatus run_status = CTRunGetStatus (run);
       status_or  |= run_status;
-      status_and &= run_status;
       DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status);
       CGFloat run_advance = CTRunGetTypographicBounds (run, range_all, nullptr, nullptr, nullptr);
       if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
@@ -1107,7 +1077,8 @@ resize_and_retry:
              advance = positions[j + 1].x - positions[j].x;
            else /* last glyph */
              advance = run_advance - (positions[j].x - positions[0].x);
-           info->mask = round (advance * x_mult);
+           /* int cast necessary to pass through negative values. */
+           info->mask = (int) round (advance * x_mult);
            info->var1.i32 = x_offset;
            info->var2.i32 = round (positions[j].y * y_mult);
            info++;
@@ -1123,7 +1094,8 @@ resize_and_retry:
              advance = positions[j + 1].y - positions[j].y;
            else /* last glyph */
              advance = run_advance - (positions[j].y - positions[0].y);
-           info->mask = round (advance * y_mult);
+           /* int cast necessary to pass through negative values. */
+           info->mask = (int) round (advance * y_mult);
            info->var1.i32 = round (positions[j].x * x_mult);
            info->var2.i32 = y_offset;
            info++;
@@ -1140,21 +1112,6 @@ resize_and_retry:
       buffer->len += num_glyphs;
     }
 
-    /* Mac OS 10.6 doesn't have kCTTypesetterOptionForcedEmbeddingLevel,
-     * or if it does, it doesn't respect it.  So we get runs with wrong
-     * directions.  As such, disable the assert...  It wouldn't crash, but
-     * cursoring will be off...
-     *
-     * https://crbug.com/419769
-     */
-    if (false)
-    {
-      /* Make sure all runs had the expected direction. */
-      HB_UNUSED bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
-      assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
-      assert (bool (status_or  & kCTRunStatusRightToLeft) == backward);
-    }
-
     buffer->clear_positions ();
 
     unsigned int count = buffer->len;
@@ -1167,7 +1124,7 @@ resize_and_retry:
        pos->x_offset = info->var1.i32;
        pos->y_offset = info->var2.i32;
 
-       info++, pos++;
+       info++; pos++;
       }
     else
       for (unsigned int i = 0; i < count; i++)
@@ -1176,7 +1133,7 @@ resize_and_retry:
        pos->x_offset = info->var1.i32;
        pos->y_offset = info->var2.i32;
 
-       info++, pos++;
+       info++; pos++;
       }
 
     /* Fix up clusters so that we never return out-of-order indices;
@@ -1189,7 +1146,8 @@ resize_and_retry:
      * This does *not* mean we'll form the same clusters as Uniscribe
      * or the native OT backend, only that the cluster indices will be
      * monotonic in the output buffer. */
-    if (count > 1 && (status_or & kCTRunStatusNonMonotonic))
+    if (count > 1 && (status_or & kCTRunStatusNonMonotonic) &&
+       buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
     {
       hb_glyph_info_t *info = buffer->info;
       if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))
@@ -1213,6 +1171,10 @@ resize_and_retry:
     }
   }
 
+  /* TODO: Sometimes the above positioning code generates negative
+   * advance values. Fix them up. Example, with NotoNastaliqUrdu
+   * font and sequence ابهد. */
+
   buffer->clear_glyph_flags ();
   buffer->unsafe_to_break ();
 
diff --git a/src/hb-cplusplus.hh b/src/hb-cplusplus.hh
new file mode 100644 (file)
index 0000000..531ef1b
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright © 2022 Behdad Esfahbod
+ *
+ *  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_CPLUSPLUS_HH
+#define HB_CPLUSPLUS_HH
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+HB_END_DECLS
+
+#ifdef __cplusplus
+
+#include <functional>
+#include <utility>
+
+#if 0
+#if !(__cplusplus >= 201103L)
+#error "HarfBuzz C++ helpers require C++11"
+#endif
+#endif
+
+namespace hb {
+
+
+template <typename T>
+struct vtable;
+
+template <typename T>
+struct shared_ptr
+{
+  using element_type = T;
+
+  using v = vtable<T>;
+
+  explicit shared_ptr (T *p = nullptr) : p (p) {}
+  shared_ptr (const shared_ptr &o) : p (v::reference (o.p)) {}
+  shared_ptr (shared_ptr &&o) : p (o.p) { o.p = nullptr; }
+  shared_ptr& operator = (const shared_ptr &o) { if (p != o.p) { destroy (); p = o.p; reference (); } return *this; }
+  shared_ptr& operator = (shared_ptr &&o) { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
+  ~shared_ptr () { v::destroy (p); p = nullptr; }
+
+  T* get() const { return p; }
+
+  void swap (shared_ptr &o) { std::swap (p, o.p); }
+  friend void swap (shared_ptr &a, shared_ptr &b) { std::swap (a.p, b.p); }
+
+  operator T * () const { return p; }
+  T& operator * () const { return *get (); }
+  T* operator -> () const { return get (); }
+  operator bool () const { return p; }
+  bool operator == (const shared_ptr &o) const { return p == o.p; }
+  bool operator != (const shared_ptr &o) const { return p != o.p; }
+
+  static T* get_empty() { return v::get_empty (); }
+  T* reference() { return v::reference (p); }
+  void destroy() { v::destroy (p); }
+  void set_user_data (hb_user_data_key_t *key,
+                     void *value,
+                     hb_destroy_func_t destroy,
+                     hb_bool_t replace) { v::set_user_data (p, key, value, destroy, replace); } 
+  void * get_user_data (hb_user_data_key_t *key) { return v::get_user_data (p, key); }
+
+  private:
+  T *p;
+};
+
+template<typename T> struct is_shared_ptr : std::false_type {};
+template<typename T> struct is_shared_ptr<shared_ptr<T>> : std::true_type {};
+
+template <typename T>
+struct unique_ptr
+{
+  using element_type = T;
+
+  using v = vtable<T>;
+
+  explicit unique_ptr (T *p = nullptr) : p (p) {}
+  unique_ptr (const unique_ptr &o) = delete;
+  unique_ptr (unique_ptr &&o) : p (o.p) { o.p = nullptr; }
+  unique_ptr& operator = (const unique_ptr &o) = delete;
+  unique_ptr& operator = (unique_ptr &&o) { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
+  ~unique_ptr () { v::destroy (p); p = nullptr; }
+
+  T* get() const { return p; }
+  T* release () { T* v = p; p = nullptr; return v; }
+
+  void swap (unique_ptr &o) { std::swap (p, o.p); }
+  friend void swap (unique_ptr &a, unique_ptr &b) { std::swap (a.p, b.p); }
+
+  operator T * () const { return p; }
+  T& operator * () const { return *get (); }
+  T* operator -> () const { return get (); }
+  operator bool () { return p; }
+
+  private:
+  T *p;
+};
+
+template<typename T> struct is_unique_ptr : std::false_type {};
+template<typename T> struct is_unique_ptr<unique_ptr<T>> : std::true_type {};
+
+template <typename T,
+         T * (*_get_empty) (void),
+         T * (*_reference) (T *),
+         void (*_destroy) (T *),
+         hb_bool_t (*_set_user_data) (T *,
+                                      hb_user_data_key_t *,
+                                      void *,
+                                      hb_destroy_func_t,
+                                      hb_bool_t),
+         void * (*_get_user_data) (const T *,
+                                   hb_user_data_key_t *)>
+struct vtable_t
+{
+  static constexpr auto get_empty = _get_empty;
+  static constexpr auto reference = _reference;
+  static constexpr auto destroy = _destroy;
+  static constexpr auto set_user_data = _set_user_data;
+  static constexpr auto get_user_data = _get_user_data;
+};
+
+#define HB_DEFINE_VTABLE(name) \
+       template<> \
+       struct vtable<hb_##name##_t> \
+            : vtable_t<hb_##name##_t, \
+                       &hb_##name##_get_empty, \
+                       &hb_##name##_reference, \
+                       &hb_##name##_destroy, \
+                       &hb_##name##_set_user_data, \
+                       &hb_##name##_get_user_data> {}
+
+HB_DEFINE_VTABLE (buffer);
+HB_DEFINE_VTABLE (blob);
+HB_DEFINE_VTABLE (face);
+HB_DEFINE_VTABLE (font);
+HB_DEFINE_VTABLE (font_funcs);
+HB_DEFINE_VTABLE (map);
+HB_DEFINE_VTABLE (set);
+HB_DEFINE_VTABLE (shape_plan);
+HB_DEFINE_VTABLE (unicode_funcs);
+HB_DEFINE_VTABLE (draw_funcs);
+HB_DEFINE_VTABLE (paint_funcs);
+
+#undef HB_DEFINE_VTABLE
+
+
+#ifdef HB_SUBSET_H
+
+#define HB_DEFINE_VTABLE(name) \
+       template<> \
+       struct vtable<hb_##name##_t> \
+            : vtable_t<hb_##name##_t, \
+                       nullptr, \
+                       &hb_##name##_reference, \
+                       &hb_##name##_destroy, \
+                       &hb_##name##_set_user_data, \
+                       &hb_##name##_get_user_data> {}
+
+
+HB_DEFINE_VTABLE (subset_input);
+HB_DEFINE_VTABLE (subset_plan);
+
+#undef HB_DEFINE_VTABLE
+
+#endif
+
+
+} // namespace hb
+
+/* Workaround for GCC < 7, see:
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480
+ * https://stackoverflow.com/a/25594741 */
+namespace std {
+
+
+template<typename T>
+struct hash<hb::shared_ptr<T>>
+{
+    std::size_t operator()(const hb::shared_ptr<T>& v) const noexcept
+    {
+        std::size_t h = std::hash<decltype (v.get ())>{}(v.get ());
+        return h;
+    }
+};
+
+template<typename T>
+struct hash<hb::unique_ptr<T>>
+{
+    std::size_t operator()(const hb::unique_ptr<T>& v) const noexcept
+    {
+        std::size_t h = std::hash<decltype (v.get ())>{}(v.get ());
+        return h;
+    }
+};
+
+
+} // namespace std
+
+#endif /* __cplusplus */
+
+#endif /* HB_CPLUSPLUS_HH */
index 3ac7440..559db40 100644 (file)
@@ -67,12 +67,12 @@ hb_options ()
 #endif
   /* Make a local copy, so we can access bitfield threadsafely. */
   hb_options_union_t u;
-  u.i = _hb_options.get_relaxed ();
+  u.i = _hb_options;
 
   if (unlikely (!u.i))
   {
     _hb_options_init ();
-    u.i = _hb_options.get_relaxed ();
+    u.i = _hb_options;
   }
 
   return u.opts;
@@ -113,7 +113,7 @@ _hb_print_func (const char *func)
     const char *paren = strchr (func, '(');
     if (paren)
       func_len = paren - func;
-    fprintf (stderr, "%.*s", func_len, func);
+    fprintf (stderr, "%.*s", (int) func_len, func);
   }
 }
 
@@ -142,9 +142,9 @@ _hb_debug_msg_va (const char *what,
   fprintf (stderr, "%-10s", what ? what : "");
 
   if (obj)
-    fprintf (stderr, "(%*p) ", (unsigned int) (2 * sizeof (void *)), obj);
+    fprintf (stderr, "(%*p) ", (int) (2 * sizeof (void *)), obj);
   else
-    fprintf (stderr, " %*s  ", (unsigned int) (2 * sizeof (void *)), "");
+    fprintf (stderr, " %*s  ", (int) (2 * sizeof (void *)), "");
 
   if (indented) {
 #define VBAR   "\342\224\202"  /* U+2502 BOX DRAWINGS LIGHT VERTICAL */
@@ -265,8 +265,9 @@ static inline void _hb_warn_no_return (bool returned)
   }
 }
 template <>
-/*static*/ inline void _hb_warn_no_return<hb_empty_t> (bool returned HB_UNUSED)
-{}
+/*static*/ inline void _hb_warn_no_return<hb_empty_t> (bool returned HB_UNUSED) {}
+template <>
+/*static*/ inline void _hb_warn_no_return<void> (bool returned HB_UNUSED) {}
 
 template <int max_level, typename ret_t>
 struct hb_auto_trace_t
@@ -306,7 +307,7 @@ struct hb_auto_trace_t
     }
 
     _hb_debug_msg<max_level> (what, obj, func, true, plevel ? *plevel : 1, -1,
-                             "return %s (line %d)",
+                             "return %s (line %u)",
                              hb_printer_t<hb_decay<decltype (v)>>().print (v), line);
     if (plevel) --*plevel;
     plevel = nullptr;
@@ -373,6 +374,10 @@ struct hb_no_trace_t {
 #define HB_DEBUG_FT (HB_DEBUG+0)
 #endif
 
+#ifndef HB_DEBUG_JUSTIFY
+#define HB_DEBUG_JUSTIFY (HB_DEBUG+0)
+#endif
+
 #ifndef HB_DEBUG_OBJECT
 #define HB_DEBUG_OBJECT (HB_DEBUG+0)
 #endif
@@ -385,6 +390,10 @@ struct hb_no_trace_t {
 #define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
 #endif
 
+#ifndef HB_DEBUG_WASM
+#define HB_DEBUG_WASM (HB_DEBUG+0)
+#endif
+
 /*
  * With tracing.
  */
@@ -396,7 +405,7 @@ struct hb_no_trace_t {
 #define TRACE_APPLY(this) \
        hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
        (&c->debug_depth, c->get_name (), this, HB_FUNC, \
-        "idx %d gid %u lookup %d", \
+        "idx %u gid %u lookup %d", \
         c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index)
 #else
 #define TRACE_APPLY(this) hb_no_trace_t<bool> trace
@@ -442,22 +451,41 @@ struct hb_no_trace_t {
 #define HB_DEBUG_SUBSET_REPACK (HB_DEBUG+0)
 #endif
 
+#ifndef HB_DEBUG_PAINT
+#define HB_DEBUG_PAINT (HB_DEBUG+0)
+#endif
+#if HB_DEBUG_PAINT
+#define TRACE_PAINT(this) \
+  HB_UNUSED hb_auto_trace_t<HB_DEBUG_PAINT, void> trace \
+  (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+   " ")
+#else
+#define TRACE_PAINT(this) HB_UNUSED hb_no_trace_t<void> trace
+#endif
+
+
 #ifndef HB_DEBUG_DISPATCH
 #define HB_DEBUG_DISPATCH ( \
        HB_DEBUG_APPLY + \
        HB_DEBUG_SANITIZE + \
        HB_DEBUG_SERIALIZE + \
        HB_DEBUG_SUBSET + \
+       HB_DEBUG_PAINT + \
        0)
 #endif
 #if HB_DEBUG_DISPATCH
 #define TRACE_DISPATCH(this, format) \
        hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
        (&c->debug_depth, c->get_name (), this, HB_FUNC, \
-        "format %d", (int) format)
+        "format %u", (unsigned) format)
 #else
 #define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace
 #endif
 
 
+#ifndef HB_BUFFER_MESSAGE_MORE
+#define HB_BUFFER_MESSAGE_MORE (HB_DEBUG+1)
+#endif
+
+
 #endif /* HB_DEBUG_HH */
index a130d77..9fcce6d 100644 (file)
@@ -93,7 +93,7 @@ HB_BEGIN_DECLS
  * This method should retrieve the glyph ID for a specified Unicode code point
  * font, with an optional variation selector.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  * Deprecated: 1.2.3
  *
  **/
@@ -102,11 +102,22 @@ 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 HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func) void
+HB_DEPRECATED_FOR (hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func)
+HB_EXTERN 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);
 
+/* https://github.com/harfbuzz/harfbuzz/pull/4207 */
+/**
+ * HB_UNICODE_COMBINING_CLASS_CCC133:
+ *
+ * [Tibetan]
+ *
+ * Deprecated: 7.2.0
+ **/
+#define HB_UNICODE_COMBINING_CLASS_CCC133 133
+
 /**
  * hb_unicode_eastasian_width_func_t:
  * @ufuncs: A Unicode-functions structure
@@ -244,8 +255,55 @@ 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_font_get_glyph_shape_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @draw_funcs: The draw functions to send the shape data to
+ * @draw_data: The data accompanying the draw functions
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * Since: 4.0.0
+ * Deprecated: 7.0.0: Use #hb_font_draw_glyph_func_t instead
+ **/
+typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data,
+                                               hb_codepoint_t glyph,
+                                               hb_draw_funcs_t *draw_funcs, void *draw_data,
+                                               void *user_data);
+
+/**
+ * hb_font_funcs_set_glyph_shape_func:
+ * @ffuncs: A font-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets the implementation function for #hb_font_get_glyph_shape_func_t,
+ * which is the same as #hb_font_draw_glyph_func_t.
+ *
+ * Since: 4.0.0
+ * Deprecated: 7.0.0: Use hb_font_funcs_set_draw_glyph_func() instead
+ **/
+HB_DEPRECATED_FOR (hb_font_funcs_set_draw_glyph_func)
+HB_EXTERN void
+hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
+                                   hb_font_get_glyph_shape_func_t func,
+                                   void *user_data, hb_destroy_func_t destroy);
+
+HB_DEPRECATED_FOR (hb_font_draw_glyph)
+HB_EXTERN void
+hb_font_get_glyph_shape (hb_font_t *font,
+                        hb_codepoint_t glyph,
+                        hb_draw_funcs_t *dfuncs, void *draw_data);
+
+
 #endif
 
+
 HB_END_DECLS
 
 #endif /* HB_DEPRECATED_H */
index f177ff3..42764a2 100644 (file)
  * Functions for using HarfBuzz with DirectWrite fonts.
  **/
 
+/* Declare object creator for dynamic support of DWRITE */
+typedef HRESULT (WINAPI *t_DWriteCreateFactory)(
+  DWRITE_FACTORY_TYPE factoryType,
+  REFIID              iid,
+  IUnknown            **factory
+);
+
+
 /*
  * DirectWrite font stream helpers
  */
@@ -137,6 +145,7 @@ public:
 
 struct hb_directwrite_face_data_t
 {
+  HMODULE dwrite_dll;
   IDWriteFactory *dwriteFactory;
   IDWriteFontFile *fontFile;
   DWriteFontFileStream *fontFileStream;
@@ -158,12 +167,33 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
     return nullptr; \
   } HB_STMT_END
 
+  data->dwrite_dll = LoadLibrary (TEXT ("DWRITE"));
+  if (unlikely (!data->dwrite_dll))
+    FAIL ("Cannot find DWrite.DLL");
+
+  t_DWriteCreateFactory p_DWriteCreateFactory;
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+
+  p_DWriteCreateFactory = (t_DWriteCreateFactory)
+                         GetProcAddress (data->dwrite_dll, "DWriteCreateFactory");
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+
+  if (unlikely (!p_DWriteCreateFactory))
+    FAIL ("Cannot find DWriteCreateFactory().");
+
   HRESULT hr;
 
   // TODO: factory and fontFileLoader should be cached separately
   IDWriteFactory* dwriteFactory;
-  hr = DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
-                           (IUnknown**) &dwriteFactory);
+  hr = p_DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
+                             (IUnknown**) &dwriteFactory);
 
   if (unlikely (hr != S_OK))
     FAIL ("Failed to run DWriteCreateFactory().");
@@ -221,14 +251,12 @@ _hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
       data->dwriteFactory->UnregisterFontFileLoader (data->fontFileLoader);
     data->dwriteFactory->Release ();
   }
-  if (data->fontFileLoader)
-    delete data->fontFileLoader;
-  if (data->fontFileStream)
-    delete data->fontFileStream;
-  if (data->faceBlob)
-    hb_blob_destroy (data->faceBlob);
-  if (data)
-    delete data;
+  delete data->fontFileLoader;
+  delete data->fontFileStream;
+  hb_blob_destroy (data->faceBlob);
+  if (data->dwrite_dll)
+    FreeLibrary (data->dwrite_dll);
+  delete data;
 }
 
 
@@ -241,17 +269,12 @@ struct hb_directwrite_font_data_t {};
 hb_directwrite_font_data_t *
 _hb_directwrite_shaper_font_data_create (hb_font_t *font)
 {
-  hb_directwrite_font_data_t *data = new hb_directwrite_font_data_t;
-  if (unlikely (!data))
-    return nullptr;
-
-  return data;
+  return (hb_directwrite_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
 
 void
 _hb_directwrite_shaper_font_data_destroy (hb_directwrite_font_data_t *data)
 {
-  delete data;
 }
 
 
index c0af6ce..f204f56 100644 (file)
 #include "hb.hh"
 
 #ifndef HB_NO_DRAW
-#ifdef HB_EXPERIMENTAL_API
 
 #include "hb-draw.hh"
-#include "hb-ot.h"
-#include "hb-ot-glyf-table.hh"
-#include "hb-ot-cff1-table.hh"
-#include "hb-ot-cff2-table.hh"
 
 /**
- * hb_draw_funcs_set_move_to_func:
- * @funcs: draw functions object
- * @move_to: move-to callback
+ * SECTION:hb-draw
+ * @title: hb-draw
+ * @short_description: Glyph drawing
+ * @include: hb.h
  *
- * Sets move-to callback to the draw functions object.
+ * Functions for drawing (extracting) glyph shapes.
  *
- * Since: EXPERIMENTAL
+ * The #hb_draw_funcs_t struct can be used with hb_font_draw_glyph().
  **/
-void
-hb_draw_funcs_set_move_to_func (hb_draw_funcs_t        *funcs,
-                               hb_draw_move_to_func_t  move_to)
+
+static void
+hb_draw_move_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
+                    hb_draw_state_t *st HB_UNUSED,
+                    float to_x HB_UNUSED, float to_y HB_UNUSED,
+                    void *user_data HB_UNUSED) {}
+
+static void
+hb_draw_line_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
+                    hb_draw_state_t *st HB_UNUSED,
+                    float to_x HB_UNUSED, float to_y HB_UNUSED,
+                    void *user_data HB_UNUSED) {}
+
+static void
+hb_draw_quadratic_to_nil (hb_draw_funcs_t *dfuncs, void *draw_data,
+                         hb_draw_state_t *st,
+                         float control_x, float control_y,
+                         float to_x, float to_y,
+                         void *user_data HB_UNUSED)
+{
+#define HB_ONE_THIRD 0.33333333f
+  dfuncs->emit_cubic_to (draw_data, *st,
+                        (st->current_x + 2.f * control_x) * HB_ONE_THIRD,
+                        (st->current_y + 2.f * control_y) * HB_ONE_THIRD,
+                        (to_x + 2.f * control_x) * HB_ONE_THIRD,
+                        (to_y + 2.f * control_y) * HB_ONE_THIRD,
+                        to_x, to_y);
+#undef HB_ONE_THIRD
+}
+
+static void
+hb_draw_cubic_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
+                     hb_draw_state_t *st HB_UNUSED,
+                     float control1_x HB_UNUSED, float control1_y HB_UNUSED,
+                     float control2_x HB_UNUSED, float control2_y HB_UNUSED,
+                     float to_x HB_UNUSED, float to_y HB_UNUSED,
+                     void *user_data HB_UNUSED) {}
+
+static void
+hb_draw_close_path_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
+                       hb_draw_state_t *st HB_UNUSED,
+                       void *user_data HB_UNUSED) {}
+
+
+static bool
+_hb_draw_funcs_set_preamble (hb_draw_funcs_t    *dfuncs,
+                            bool                func_is_null,
+                            void              **user_data,
+                            hb_destroy_func_t  *destroy)
 {
-  if (unlikely (hb_object_is_immutable (funcs))) return;
-  funcs->move_to = move_to;
+  if (hb_object_is_immutable (dfuncs))
+  {
+    if (*destroy)
+      (*destroy) (*user_data);
+    return false;
+  }
+
+  if (func_is_null)
+  {
+    if (*destroy)
+      (*destroy) (*user_data);
+    *destroy = nullptr;
+    *user_data = nullptr;
+  }
+
+  return true;
+}
+
+static bool
+_hb_draw_funcs_set_middle (hb_draw_funcs_t   *dfuncs,
+                          void              *user_data,
+                          hb_destroy_func_t  destroy)
+{
+  if (user_data && !dfuncs->user_data)
+  {
+    dfuncs->user_data = (decltype (dfuncs->user_data)) hb_calloc (1, sizeof (*dfuncs->user_data));
+    if (unlikely (!dfuncs->user_data))
+      goto fail;
+  }
+  if (destroy && !dfuncs->destroy)
+  {
+    dfuncs->destroy = (decltype (dfuncs->destroy)) hb_calloc (1, sizeof (*dfuncs->destroy));
+    if (unlikely (!dfuncs->destroy))
+      goto fail;
+  }
+
+  return true;
+
+fail:
+  if (destroy)
+    (destroy) (user_data);
+  return false;
+}
+
+#define HB_DRAW_FUNC_IMPLEMENT(name)                                           \
+                                                                               \
+void                                                                           \
+hb_draw_funcs_set_##name##_func (hb_draw_funcs_t        *dfuncs,               \
+                                hb_draw_##name##_func_t  func,                 \
+                                void                    *user_data,            \
+                                hb_destroy_func_t        destroy)              \
+{                                                                              \
+  if (!_hb_draw_funcs_set_preamble (dfuncs, !func, &user_data, &destroy))\
+      return;                                                            \
+                                                                               \
+  if (dfuncs->destroy && dfuncs->destroy->name)                                        \
+    dfuncs->destroy->name (!dfuncs->user_data ? nullptr : dfuncs->user_data->name); \
+                                                                        \
+  if (!_hb_draw_funcs_set_middle (dfuncs, user_data, destroy))           \
+      return;                                                            \
+                                                                       \
+  if (func)                                                            \
+    dfuncs->func.name = func;                                          \
+  else                                                                 \
+    dfuncs->func.name = hb_draw_##name##_nil;                          \
+                                                                       \
+  if (dfuncs->user_data)                                               \
+    dfuncs->user_data->name = user_data;                               \
+  if (dfuncs->destroy)                                                 \
+    dfuncs->destroy->name = destroy;                                   \
 }
 
+HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+
 /**
- * hb_draw_funcs_set_line_to_func:
- * @funcs: draw functions object
- * @line_to: line-to callback
+ * hb_draw_funcs_create:
+ *
+ * Creates a new draw callbacks object.
  *
- * Sets line-to callback to the draw functions object.
+ * Return value: (transfer full):
+ * A newly allocated #hb_draw_funcs_t with a reference count of 1. The initial
+ * reference count should be released with hb_draw_funcs_destroy when you are
+ * done using the #hb_draw_funcs_t. This function never returns `NULL`. If
+ * memory cannot be allocated, a special singleton #hb_draw_funcs_t object will
+ * be returned.
  *
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
-void
-hb_draw_funcs_set_line_to_func (hb_draw_funcs_t        *funcs,
-                               hb_draw_line_to_func_t  line_to)
+hb_draw_funcs_t *
+hb_draw_funcs_create ()
 {
-  if (unlikely (hb_object_is_immutable (funcs))) return;
-  funcs->line_to = line_to;
+  hb_draw_funcs_t *dfuncs;
+  if (unlikely (!(dfuncs = hb_object_create<hb_draw_funcs_t> ())))
+    return const_cast<hb_draw_funcs_t *> (&Null (hb_draw_funcs_t));
+
+  dfuncs->func =  Null (hb_draw_funcs_t).func;
+
+  return dfuncs;
 }
 
+DEFINE_NULL_INSTANCE (hb_draw_funcs_t) =
+{
+  HB_OBJECT_HEADER_STATIC,
+
+  {
+#define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_nil,
+    HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+  }
+};
+
 /**
- * hb_draw_funcs_set_quadratic_to_func:
- * @funcs: draw functions object
- * @move_to: quadratic-to callback
+ * hb_draw_funcs_get_empty:
  *
- * Sets quadratic-to callback to the draw functions object.
+ * Fetches the singleton empty draw-functions structure.
  *
- * Since: EXPERIMENTAL
+ * Return value: (transfer full): The empty draw-functions structure
+ *
+ * Since: 7.0.0
  **/
-void
-hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t             *funcs,
-                                    hb_draw_quadratic_to_func_t  quadratic_to)
+hb_draw_funcs_t *
+hb_draw_funcs_get_empty ()
 {
-  if (unlikely (hb_object_is_immutable (funcs))) return;
-  funcs->quadratic_to = quadratic_to;
-  funcs->is_quadratic_to_set = true;
+  return const_cast<hb_draw_funcs_t *> (&Null (hb_draw_funcs_t));
 }
 
 /**
- * hb_draw_funcs_set_cubic_to_func:
- * @funcs: draw functions
- * @cubic_to: cubic-to callback
+ * hb_draw_funcs_reference: (skip)
+ * @dfuncs: draw functions
+ *
+ * Increases the reference count on @dfuncs by one.
  *
- * Sets cubic-to callback to the draw functions object.
+ * This prevents @dfuncs from being destroyed until a matching
+ * call to hb_draw_funcs_destroy() is made.
  *
- * Since: EXPERIMENTAL
+ * Return value: (transfer full):
+ * The referenced #hb_draw_funcs_t.
+ *
+ * Since: 4.0.0
  **/
-void
-hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t         *funcs,
-                                hb_draw_cubic_to_func_t  cubic_to)
+hb_draw_funcs_t *
+hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs)
 {
-  if (unlikely (hb_object_is_immutable (funcs))) return;
-  funcs->cubic_to = cubic_to;
+  return hb_object_reference (dfuncs);
 }
 
 /**
- * hb_draw_funcs_set_close_path_func:
- * @funcs: draw functions object
- * @close_path: close-path callback
+ * hb_draw_funcs_destroy: (skip)
+ * @dfuncs: draw functions
  *
- * Sets close-path callback to the draw functions object.
+ * Deallocate the @dfuncs.
+ * Decreases the reference count on @dfuncs by one. If the result is zero, then
+ * @dfuncs and all associated resources are freed. See hb_draw_funcs_reference().
  *
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
 void
-hb_draw_funcs_set_close_path_func (hb_draw_funcs_t           *funcs,
-                                  hb_draw_close_path_func_t  close_path)
+hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs)
 {
-  if (unlikely (hb_object_is_immutable (funcs))) return;
-  funcs->close_path = close_path;
-}
+  if (!hb_object_destroy (dfuncs)) return;
 
-static void
-_move_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
+  if (dfuncs->destroy)
+  {
+#define HB_DRAW_FUNC_IMPLEMENT(name) \
+    if (dfuncs->destroy->name) dfuncs->destroy->name (!dfuncs->user_data ? nullptr : dfuncs->user_data->name);
+      HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+  }
 
-static void
-_line_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
+  hb_free (dfuncs->destroy);
+  hb_free (dfuncs->user_data);
 
-static void
-_quadratic_to_nil (hb_position_t control_x HB_UNUSED, hb_position_t control_y HB_UNUSED,
-                  hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
-                  void *user_data HB_UNUSED) {}
+  hb_free (dfuncs);
+}
 
-static void
-_cubic_to_nil (hb_position_t control1_x HB_UNUSED, hb_position_t control1_y HB_UNUSED,
-              hb_position_t control2_x HB_UNUSED, hb_position_t control2_y HB_UNUSED,
-              hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
-              void *user_data HB_UNUSED) {}
+/**
+ * hb_draw_funcs_set_user_data: (skip)
+ * @dfuncs: The draw-functions structure
+ * @key: The user-data key
+ * @data: A pointer to the user data
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
+ * @replace: Whether to replace an existing data with the same key
+ *
+ * Attaches a user-data key/data pair to the specified draw-functions structure. 
+ *
+ * Return value: `true` if success, `false` otherwise
+ *
+ * Since: 7.0.0
+ **/
+hb_bool_t
+hb_draw_funcs_set_user_data (hb_draw_funcs_t *dfuncs,
+                            hb_user_data_key_t *key,
+                            void *              data,
+                            hb_destroy_func_t   destroy,
+                            hb_bool_t           replace)
+{
+  return hb_object_set_user_data (dfuncs, key, data, destroy, replace);
+}
 
-static void
-_close_path_nil (void *user_data HB_UNUSED) {}
+/**
+ * hb_draw_funcs_get_user_data: (skip)
+ * @dfuncs: The draw-functions structure
+ * @key: The user-data key to query
+ *
+ * Fetches the user-data associated with the specified key,
+ * attached to the specified draw-functions structure.
+ *
+ * Return value: (transfer none): A pointer to the user data
+ *
+ * Since: 7.0.0
+ **/
+void *
+hb_draw_funcs_get_user_data (const hb_draw_funcs_t *dfuncs,
+                            hb_user_data_key_t       *key)
+{
+  return hb_object_get_user_data (dfuncs, key);
+}
 
 /**
- * hb_draw_funcs_create:
+ * hb_draw_funcs_make_immutable:
+ * @dfuncs: draw functions
  *
- * Creates a new draw callbacks object.
+ * Makes @dfuncs object immutable.
  *
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
-hb_draw_funcs_t *
-hb_draw_funcs_create ()
+void
+hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs)
 {
-  hb_draw_funcs_t *funcs;
-  if (unlikely (!(funcs = hb_object_create<hb_draw_funcs_t> ())))
-    return const_cast<hb_draw_funcs_t *> (&Null (hb_draw_funcs_t));
+  if (hb_object_is_immutable (dfuncs))
+    return;
 
-  funcs->move_to = (hb_draw_move_to_func_t) _move_to_nil;
-  funcs->line_to = (hb_draw_line_to_func_t) _line_to_nil;
-  funcs->quadratic_to = (hb_draw_quadratic_to_func_t) _quadratic_to_nil;
-  funcs->is_quadratic_to_set = false;
-  funcs->cubic_to = (hb_draw_cubic_to_func_t) _cubic_to_nil;
-  funcs->close_path = (hb_draw_close_path_func_t) _close_path_nil;
-  return funcs;
+  hb_object_make_immutable (dfuncs);
 }
 
 /**
- * hb_draw_funcs_reference:
- * @funcs: draw functions
+ * hb_draw_funcs_is_immutable:
+ * @dfuncs: draw functions
+ *
+ * Checks whether @dfuncs is immutable.
  *
- * Add to callbacks object refcount.
+ * Return value: `true` if @dfuncs is immutable, `false` otherwise
  *
- * Returns: The same object.
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
-hb_draw_funcs_t *
-hb_draw_funcs_reference (hb_draw_funcs_t *funcs)
+hb_bool_t
+hb_draw_funcs_is_immutable (hb_draw_funcs_t *dfuncs)
 {
-  return hb_object_reference (funcs);
+  return hb_object_is_immutable (dfuncs);
 }
 
+
 /**
- * hb_draw_funcs_destroy:
- * @funcs: draw functions
+ * hb_draw_move_to:
+ * @dfuncs: draw functions
+ * @draw_data: associated draw data passed by the caller
+ * @st: current draw state
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
  *
- * Decreases refcount of callbacks object and deletes the object if it reaches
- * to zero.
+ * Perform a "move-to" draw operation.
  *
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
 void
-hb_draw_funcs_destroy (hb_draw_funcs_t *funcs)
+hb_draw_move_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+                hb_draw_state_t *st,
+                float to_x, float to_y)
 {
-  if (!hb_object_destroy (funcs)) return;
-
-  hb_free (funcs);
+  dfuncs->move_to (draw_data, *st,
+                  to_x, to_y);
 }
 
 /**
- * hb_draw_funcs_make_immutable:
- * @funcs: draw functions
+ * hb_draw_line_to:
+ * @dfuncs: draw functions
+ * @draw_data: associated draw data passed by the caller
+ * @st: current draw state
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
  *
- * Makes funcs object immutable.
+ * Perform a "line-to" draw operation.
  *
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
 void
-hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs)
+hb_draw_line_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+                hb_draw_state_t *st,
+                float to_x, float to_y)
 {
-  if (hb_object_is_immutable (funcs))
-    return;
-
-  hb_object_make_immutable (funcs);
+  dfuncs->line_to (draw_data, *st,
+                  to_x, to_y);
 }
 
 /**
- * hb_draw_funcs_is_immutable:
- * @funcs: draw functions
+ * hb_draw_quadratic_to:
+ * @dfuncs: draw functions
+ * @draw_data: associated draw data passed by the caller
+ * @st: current draw state
+ * @control_x: X component of control point
+ * @control_y: Y component of control point
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
  *
- * Checks whether funcs is immutable.
+ * Perform a "quadratic-to" draw operation.
  *
- * Returns: If is immutable.
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
-hb_bool_t
-hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs)
+void
+hb_draw_quadratic_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+                     hb_draw_state_t *st,
+                     float control_x, float control_y,
+                     float to_x, float to_y)
 {
-  return hb_object_is_immutable (funcs);
+  dfuncs->quadratic_to (draw_data, *st,
+                       control_x, control_y,
+                       to_x, to_y);
 }
 
 /**
- * hb_font_draw_glyph:
- * @font: a font object
- * @glyph: a glyph id
- * @funcs: draw callbacks object
- * @user_data: parameter you like be passed to the callbacks when are called
+ * hb_draw_cubic_to:
+ * @dfuncs: draw functions
+ * @draw_data: associated draw data passed by the caller
+ * @st: current draw state
+ * @control1_x: X component of first control point
+ * @control1_y: Y component of first control point
+ * @control2_x: X component of second control point
+ * @control2_y: Y component of second control point
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
  *
- * Draw a glyph.
+ * Perform a "cubic-to" draw operation.
  *
- * Returns: Whether the font had the glyph and the operation completed successfully.
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
-hb_bool_t
-hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph,
-                   const hb_draw_funcs_t *funcs,
-                   void *user_data)
+void
+hb_draw_cubic_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+                 hb_draw_state_t *st,
+                 float control1_x, float control1_y,
+                 float control2_x, float control2_y,
+                 float to_x, float to_y)
 {
-  if (unlikely (funcs == &Null (hb_draw_funcs_t) ||
-               glyph >= font->face->get_num_glyphs ()))
-    return false;
-
-  draw_helper_t draw_helper (funcs, user_data);
-  if (font->face->table.glyf->get_path (font, glyph, draw_helper)) return true;
-#ifndef HB_NO_CFF
-  if (font->face->table.cff1->get_path (font, glyph, draw_helper)) return true;
-  if (font->face->table.cff2->get_path (font, glyph, draw_helper)) return true;
-#endif
+  dfuncs->cubic_to (draw_data, *st,
+                   control1_x, control1_y,
+                   control2_x, control2_y,
+                   to_x, to_y);
+}
 
-  return false;
+/**
+ * hb_draw_close_path:
+ * @dfuncs: draw functions
+ * @draw_data: associated draw data passed by the caller
+ * @st: current draw state
+ *
+ * Perform a "close-path" draw operation.
+ *
+ * Since: 4.0.0
+ **/
+void
+hb_draw_close_path (hb_draw_funcs_t *dfuncs, void *draw_data,
+                   hb_draw_state_t *st)
+{
+  dfuncs->close_path (draw_data, *st);
 }
 
-#endif
+
 #endif
index f82cc34..9ca0b40 100644 (file)
 
 HB_BEGIN_DECLS
 
-#ifdef HB_EXPERIMENTAL_API
-typedef void (*hb_draw_move_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data);
-typedef void (*hb_draw_line_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data);
-typedef void (*hb_draw_quadratic_to_func_t) (hb_position_t control_x, hb_position_t control_y,
-                                            hb_position_t to_x, hb_position_t to_y,
-                                            void *user_data);
-typedef void (*hb_draw_cubic_to_func_t) (hb_position_t control1_x, hb_position_t control1_y,
-                                        hb_position_t control2_x, hb_position_t control2_y,
-                                        hb_position_t to_x, hb_position_t to_y,
-                                        void *user_data);
-typedef void (*hb_draw_close_path_func_t) (void *user_data);
+
+/**
+ * hb_draw_state_t
+ * @path_open: Whether there is an open path
+ * @path_start_x: X component of the start of current path
+ * @path_start_y: Y component of the start of current path
+ * @current_x: X component of current point
+ * @current_y: Y component of current point
+ *
+ * Current drawing state.
+ *
+ * Since: 4.0.0
+ **/
+typedef struct hb_draw_state_t {
+  hb_bool_t path_open;
+
+  float path_start_x;
+  float path_start_y;
+
+  float current_x;
+  float current_y;
+
+  /*< private >*/
+  hb_var_num_t   reserved1;
+  hb_var_num_t   reserved2;
+  hb_var_num_t   reserved3;
+  hb_var_num_t   reserved4;
+  hb_var_num_t   reserved5;
+  hb_var_num_t   reserved6;
+  hb_var_num_t   reserved7;
+} hb_draw_state_t;
+
+/**
+ * HB_DRAW_STATE_DEFAULT:
+ *
+ * The default #hb_draw_state_t at the start of glyph drawing.
+ */
+#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}}
+
 
 /**
  * hb_draw_funcs_t:
  *
  * Glyph draw callbacks.
  *
- * _move_to, _line_to and _cubic_to calls are necessary to be defined but we
- * translate _quadratic_to calls to _cubic_to if the callback isn't defined.
+ * #hb_draw_move_to_func_t, #hb_draw_line_to_func_t and
+ * #hb_draw_cubic_to_func_t calls are necessary to be defined but we translate
+ * #hb_draw_quadratic_to_func_t calls to #hb_draw_cubic_to_func_t if the
+ * callback isn't defined.
  *
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
+
 typedef struct hb_draw_funcs_t hb_draw_funcs_t;
 
+
+/**
+ * hb_draw_move_to_func_t:
+ * @dfuncs: draw functions object
+ * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
+ * @st: current draw state
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
+ * @user_data: User data pointer passed to hb_draw_funcs_set_move_to_func()
+ *
+ * A virtual method for the #hb_draw_funcs_t to perform a "move-to" draw
+ * operation.
+ *
+ * Since: 4.0.0
+ *
+ **/
+typedef void (*hb_draw_move_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
+                                       hb_draw_state_t *st,
+                                       float to_x, float to_y,
+                                       void *user_data);
+
+/**
+ * hb_draw_line_to_func_t:
+ * @dfuncs: draw functions object
+ * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
+ * @st: current draw state
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
+ * @user_data: User data pointer passed to hb_draw_funcs_set_line_to_func()
+ *
+ * A virtual method for the #hb_draw_funcs_t to perform a "line-to" draw
+ * operation.
+ *
+ * Since: 4.0.0
+ *
+ **/
+typedef void (*hb_draw_line_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
+                                       hb_draw_state_t *st,
+                                       float to_x, float to_y,
+                                       void *user_data);
+
+/**
+ * hb_draw_quadratic_to_func_t:
+ * @dfuncs: draw functions object
+ * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
+ * @st: current draw state
+ * @control_x: X component of control point
+ * @control_y: Y component of control point
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
+ * @user_data: User data pointer passed to hb_draw_funcs_set_quadratic_to_func()
+ *
+ * A virtual method for the #hb_draw_funcs_t to perform a "quadratic-to" draw
+ * operation.
+ *
+ * Since: 4.0.0
+ *
+ **/
+typedef void (*hb_draw_quadratic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
+                                            hb_draw_state_t *st,
+                                            float control_x, float control_y,
+                                            float to_x, float to_y,
+                                            void *user_data);
+
+/**
+ * hb_draw_cubic_to_func_t:
+ * @dfuncs: draw functions object
+ * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
+ * @st: current draw state
+ * @control1_x: X component of first control point
+ * @control1_y: Y component of first control point
+ * @control2_x: X component of second control point
+ * @control2_y: Y component of second control point
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
+ * @user_data: User data pointer passed to hb_draw_funcs_set_cubic_to_func()
+ *
+ * A virtual method for the #hb_draw_funcs_t to perform a "cubic-to" draw
+ * operation.
+ *
+ * Since: 4.0.0
+ *
+ **/
+typedef void (*hb_draw_cubic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
+                                        hb_draw_state_t *st,
+                                        float control1_x, float control1_y,
+                                        float control2_x, float control2_y,
+                                        float to_x, float to_y,
+                                        void *user_data);
+
+/**
+ * hb_draw_close_path_func_t:
+ * @dfuncs: draw functions object
+ * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
+ * @st: current draw state
+ * @user_data: User data pointer passed to hb_draw_funcs_set_close_path_func()
+ *
+ * A virtual method for the #hb_draw_funcs_t to perform a "close-path" draw
+ * operation.
+ *
+ * Since: 4.0.0
+ *
+ **/
+typedef void (*hb_draw_close_path_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
+                                          hb_draw_state_t *st,
+                                          void *user_data);
+
+/**
+ * hb_draw_funcs_set_move_to_func:
+ * @dfuncs: draw functions object
+ * @func: (closure user_data) (destroy destroy) (scope notified): move-to callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets move-to callback to the draw functions object.
+ *
+ * Since: 4.0.0
+ **/
 HB_EXTERN void
-hb_draw_funcs_set_move_to_func (hb_draw_funcs_t        *funcs,
-                               hb_draw_move_to_func_t  move_to);
+hb_draw_funcs_set_move_to_func (hb_draw_funcs_t        *dfuncs,
+                               hb_draw_move_to_func_t  func,
+                               void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_draw_funcs_set_line_to_func:
+ * @dfuncs: draw functions object
+ * @func: (closure user_data) (destroy destroy) (scope notified): line-to callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets line-to callback to the draw functions object.
+ *
+ * Since: 4.0.0
+ **/
 HB_EXTERN void
-hb_draw_funcs_set_line_to_func (hb_draw_funcs_t        *funcs,
-                               hb_draw_line_to_func_t  line_to);
+hb_draw_funcs_set_line_to_func (hb_draw_funcs_t        *dfuncs,
+                               hb_draw_line_to_func_t  func,
+                               void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_draw_funcs_set_quadratic_to_func:
+ * @dfuncs: draw functions object
+ * @func: (closure user_data) (destroy destroy) (scope notified): quadratic-to callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets quadratic-to callback to the draw functions object.
+ *
+ * Since: 4.0.0
+ **/
 HB_EXTERN void
-hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t             *funcs,
-                                    hb_draw_quadratic_to_func_t  quadratic_to);
+hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t             *dfuncs,
+                                    hb_draw_quadratic_to_func_t  func,
+                                    void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_draw_funcs_set_cubic_to_func:
+ * @dfuncs: draw functions
+ * @func: (closure user_data) (destroy destroy) (scope notified): cubic-to callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets cubic-to callback to the draw functions object.
+ *
+ * Since: 4.0.0
+ **/
 HB_EXTERN void
-hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t         *funcs,
-                                hb_draw_cubic_to_func_t  cubic_to);
+hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t         *dfuncs,
+                                hb_draw_cubic_to_func_t  func,
+                                void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_draw_funcs_set_close_path_func:
+ * @dfuncs: draw functions object
+ * @func: (closure user_data) (destroy destroy) (scope notified): close-path callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets close-path callback to the draw functions object.
+ *
+ * Since: 4.0.0
+ **/
 HB_EXTERN void
-hb_draw_funcs_set_close_path_func (hb_draw_funcs_t           *funcs,
-                                  hb_draw_close_path_func_t  close_path);
+hb_draw_funcs_set_close_path_func (hb_draw_funcs_t           *dfuncs,
+                                  hb_draw_close_path_func_t  func,
+                                  void *user_data, hb_destroy_func_t destroy);
+
 
 HB_EXTERN hb_draw_funcs_t *
 hb_draw_funcs_create (void);
 
 HB_EXTERN hb_draw_funcs_t *
-hb_draw_funcs_reference (hb_draw_funcs_t *funcs);
+hb_draw_funcs_get_empty (void);
+
+HB_EXTERN hb_draw_funcs_t *
+hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs);
 
 HB_EXTERN void
-hb_draw_funcs_destroy (hb_draw_funcs_t *funcs);
+hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs);
+
+HB_EXTERN hb_bool_t
+hb_draw_funcs_set_user_data (hb_draw_funcs_t *dfuncs,
+                            hb_user_data_key_t *key,
+                            void *              data,
+                            hb_destroy_func_t   destroy,
+                            hb_bool_t           replace);
+
+
+HB_EXTERN void *
+hb_draw_funcs_get_user_data (const hb_draw_funcs_t *dfuncs,
+                            hb_user_data_key_t       *key);
 
 HB_EXTERN void
-hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs);
+hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs);
 
 HB_EXTERN hb_bool_t
-hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs);
-#endif
+hb_draw_funcs_is_immutable (hb_draw_funcs_t *dfuncs);
+
+
+HB_EXTERN void
+hb_draw_move_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+                hb_draw_state_t *st,
+                float to_x, float to_y);
+
+HB_EXTERN void
+hb_draw_line_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+                hb_draw_state_t *st,
+                float to_x, float to_y);
+
+HB_EXTERN void
+hb_draw_quadratic_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+                     hb_draw_state_t *st,
+                     float control_x, float control_y,
+                     float to_x, float to_y);
+
+HB_EXTERN void
+hb_draw_cubic_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+                 hb_draw_state_t *st,
+                 float control1_x, float control1_y,
+                 float control2_x, float control2_y,
+                 float to_x, float to_y);
+
+HB_EXTERN void
+hb_draw_close_path (hb_draw_funcs_t *dfuncs, void *draw_data,
+                   hb_draw_state_t *st);
+
 
 HB_END_DECLS
 
index 2aa0a5b..25dee12 100644 (file)
 
 #include "hb.hh"
 
-#ifdef HB_EXPERIMENTAL_API
+
+/*
+ * hb_draw_funcs_t
+ */
+
+#define HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS \
+  HB_DRAW_FUNC_IMPLEMENT (move_to) \
+  HB_DRAW_FUNC_IMPLEMENT (line_to) \
+  HB_DRAW_FUNC_IMPLEMENT (quadratic_to) \
+  HB_DRAW_FUNC_IMPLEMENT (cubic_to) \
+  HB_DRAW_FUNC_IMPLEMENT (close_path) \
+  /* ^--- Add new callbacks here */
+
 struct hb_draw_funcs_t
 {
   hb_object_header_t header;
 
-  hb_draw_move_to_func_t move_to;
-  hb_draw_line_to_func_t line_to;
-  hb_draw_quadratic_to_func_t quadratic_to;
-  bool is_quadratic_to_set;
-  hb_draw_cubic_to_func_t cubic_to;
-  hb_draw_close_path_func_t close_path;
-};
+  struct {
+#define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_func_t name;
+    HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+  } func;
+
+  struct {
+#define HB_DRAW_FUNC_IMPLEMENT(name) void *name;
+    HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+  } *user_data;
+
+  struct {
+#define HB_DRAW_FUNC_IMPLEMENT(name) hb_destroy_func_t name;
+    HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+  } *destroy;
+
+  void emit_move_to (void *draw_data, hb_draw_state_t &st,
+                    float to_x, float to_y)
+  { func.move_to (this, draw_data, &st,
+                 to_x, to_y,
+                 !user_data ? nullptr : user_data->move_to); }
+  void emit_line_to (void *draw_data, hb_draw_state_t &st,
+                    float to_x, float to_y)
+  { func.line_to (this, draw_data, &st,
+                 to_x, to_y,
+                 !user_data ? nullptr : user_data->line_to); }
+  void emit_quadratic_to (void *draw_data, hb_draw_state_t &st,
+                         float control_x, float control_y,
+                         float to_x, float to_y)
+  { func.quadratic_to (this, draw_data, &st,
+                      control_x, control_y,
+                      to_x, to_y,
+                      !user_data ? nullptr : user_data->quadratic_to); }
+  void emit_cubic_to (void *draw_data, hb_draw_state_t &st,
+                     float control1_x, float control1_y,
+                     float control2_x, float control2_y,
+                     float to_x, float to_y)
+  { func.cubic_to (this, draw_data, &st,
+                  control1_x, control1_y,
+                  control2_x, control2_y,
+                  to_x, to_y,
+                  !user_data ? nullptr : user_data->cubic_to); }
+  void emit_close_path (void *draw_data, hb_draw_state_t &st)
+  { func.close_path (this, draw_data, &st,
+                    !user_data ? nullptr : user_data->close_path); }
 
-struct draw_helper_t
-{
-  draw_helper_t (const hb_draw_funcs_t *funcs_, void *user_data_)
-  {
-    funcs = funcs_;
-    user_data = user_data_;
-    path_open = false;
-    path_start_x = current_x = path_start_y = current_y = 0;
-  }
-  ~draw_helper_t () { end_path (); }
 
-  void move_to (hb_position_t x, hb_position_t y)
+  void
+  HB_ALWAYS_INLINE
+  move_to (void *draw_data, hb_draw_state_t &st,
+          float to_x, float to_y)
   {
-    if (path_open) end_path ();
-    current_x = path_start_x = x;
-    current_y = path_start_y = y;
+    if (unlikely (st.path_open)) close_path (draw_data, st);
+    st.current_x = to_x;
+    st.current_y = to_y;
   }
 
-  void line_to (hb_position_t x, hb_position_t y)
+  void
+  HB_ALWAYS_INLINE
+  line_to (void *draw_data, hb_draw_state_t &st,
+          float to_x, float to_y)
   {
-    if (equal_to_current (x, y)) return;
-    if (!path_open) start_path ();
-    funcs->line_to (x, y, user_data);
-    current_x = x;
-    current_y = y;
+    if (unlikely (!st.path_open)) start_path (draw_data, st);
+    emit_line_to (draw_data, st, to_x, to_y);
+    st.current_x = to_x;
+    st.current_y = to_y;
   }
 
   void
-  quadratic_to (hb_position_t control_x, hb_position_t control_y,
-               hb_position_t to_x, hb_position_t to_y)
+  HB_ALWAYS_INLINE
+  quadratic_to (void *draw_data, hb_draw_state_t &st,
+               float control_x, float control_y,
+               float to_x, float to_y)
   {
-    if (equal_to_current (control_x, control_y) && equal_to_current (to_x, to_y))
-      return;
-    if (!path_open) start_path ();
-    if (funcs->is_quadratic_to_set)
-      funcs->quadratic_to (control_x, control_y, to_x, to_y, user_data);
-    else
-      funcs->cubic_to (roundf ((current_x + 2.f * control_x) / 3.f),
-                      roundf ((current_y + 2.f * control_y) / 3.f),
-                      roundf ((to_x + 2.f * control_x) / 3.f),
-                      roundf ((to_y + 2.f * control_y) / 3.f),
-                      to_x, to_y, user_data);
-    current_x = to_x;
-    current_y = to_y;
+    if (unlikely (!st.path_open)) start_path (draw_data, st);
+    emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y);
+    st.current_x = to_x;
+    st.current_y = to_y;
   }
 
   void
-  cubic_to (hb_position_t control1_x, hb_position_t control1_y,
-           hb_position_t control2_x, hb_position_t control2_y,
-           hb_position_t to_x, hb_position_t to_y)
+  HB_ALWAYS_INLINE
+  cubic_to (void *draw_data, hb_draw_state_t &st,
+           float control1_x, float control1_y,
+           float control2_x, float control2_y,
+           float to_x, float to_y)
   {
-    if (equal_to_current (control1_x, control1_y) &&
-       equal_to_current (control2_x, control2_y) &&
-       equal_to_current (to_x, to_y))
-      return;
-    if (!path_open) start_path ();
-    funcs->cubic_to (control1_x, control1_y, control2_x, control2_y, to_x, to_y, user_data);
-    current_x = to_x;
-    current_y = to_y;
+    if (unlikely (!st.path_open)) start_path (draw_data, st);
+    emit_cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y);
+    st.current_x = to_x;
+    st.current_y = to_y;
   }
 
-  void end_path ()
+  void
+  HB_ALWAYS_INLINE
+  close_path (void *draw_data, hb_draw_state_t &st)
   {
-    if (path_open)
+    if (likely (st.path_open))
     {
-      if ((path_start_x != current_x) || (path_start_y != current_y))
-       funcs->line_to (path_start_x, path_start_y, user_data);
-      funcs->close_path (user_data);
+      if ((st.path_start_x != st.current_x) || (st.path_start_y != st.current_y))
+       emit_line_to (draw_data, st, st.path_start_x, st.path_start_y);
+      emit_close_path (draw_data, st);
     }
-    path_open = false;
-    path_start_x = current_x = path_start_y = current_y = 0;
+    st.path_open = false;
+    st.path_start_x = st.current_x = st.path_start_y = st.current_y = 0;
   }
 
   protected:
-  bool equal_to_current (hb_position_t x, hb_position_t y)
-  { return current_x == x && current_y == y; }
 
-  void start_path ()
+  void start_path (void *draw_data, hb_draw_state_t &st)
   {
-    if (path_open) end_path ();
-    path_open = true;
-    funcs->move_to (path_start_x, path_start_y, user_data);
+    assert (!st.path_open);
+    emit_move_to (draw_data, st, st.current_x, st.current_y);
+    st.path_open = true;
+    st.path_start_x = st.current_x;
+    st.path_start_y = st.current_y;
   }
+};
+DECLARE_NULL_INSTANCE (hb_draw_funcs_t);
 
-  hb_position_t path_start_x;
-  hb_position_t path_start_y;
+struct hb_draw_session_t
+{
+  hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_, float slant_ = 0.f)
+    : slant {slant_}, not_slanted {slant == 0.f},
+      funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT
+  {}
 
-  hb_position_t current_x;
-  hb_position_t current_y;
+  ~hb_draw_session_t () { close_path (); }
 
-  bool path_open;
-  const hb_draw_funcs_t *funcs;
-  void *user_data;
+  HB_ALWAYS_INLINE
+  void move_to (float to_x, float to_y)
+  {
+    if (likely (not_slanted))
+      funcs->move_to (draw_data, st,
+                     to_x, to_y);
+    else
+      funcs->move_to (draw_data, st,
+                     to_x + to_y * slant, to_y);
+  }
+  HB_ALWAYS_INLINE
+  void line_to (float to_x, float to_y)
+  {
+    if (likely (not_slanted))
+      funcs->line_to (draw_data, st,
+                     to_x, to_y);
+    else
+      funcs->line_to (draw_data, st,
+                     to_x + to_y * slant, to_y);
+  }
+  void
+  HB_ALWAYS_INLINE
+  quadratic_to (float control_x, float control_y,
+               float to_x, float to_y)
+  {
+    if (likely (not_slanted))
+      funcs->quadratic_to (draw_data, st,
+                          control_x, control_y,
+                          to_x, to_y);
+    else
+      funcs->quadratic_to (draw_data, st,
+                          control_x + control_y * slant, control_y,
+                          to_x + to_y * slant, to_y);
+  }
+  void
+  HB_ALWAYS_INLINE
+  cubic_to (float control1_x, float control1_y,
+           float control2_x, float control2_y,
+           float to_x, float to_y)
+  {
+    if (likely (not_slanted))
+      funcs->cubic_to (draw_data, st,
+                      control1_x, control1_y,
+                      control2_x, control2_y,
+                      to_x, to_y);
+    else
+      funcs->cubic_to (draw_data, st,
+                      control1_x + control1_y * slant, control1_y,
+                      control2_x + control2_y * slant, control2_y,
+                      to_x + to_y * slant, to_y);
+  }
+  HB_ALWAYS_INLINE
+  void close_path ()
+  {
+    funcs->close_path (draw_data, st);
+  }
+
+  protected:
+  float slant;
+  bool not_slanted;
+  hb_draw_funcs_t *funcs;
+  void *draw_data;
+  hb_draw_state_t st;
 };
-#endif
 
 #endif /* HB_DRAW_HH */
diff --git a/src/hb-face-builder.cc b/src/hb-face-builder.cc
new file mode 100644 (file)
index 0000000..84b14d2
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Copyright © 2009  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
+ */
+
+#include "hb.hh"
+
+#include "hb-face.hh"
+
+#include "hb-map.hh"
+#include "hb-open-file.hh"
+#include "hb-serialize.hh"
+
+
+/*
+ * face-builder: A face that has add_table().
+ */
+
+struct face_table_info_t
+{
+  hb_blob_t* data;
+  signed order;
+};
+
+struct hb_face_builder_data_t
+{
+  hb_hashmap_t<hb_tag_t, face_table_info_t> tables;
+};
+
+static int compare_entries (const void* pa, const void* pb)
+{
+  const auto& a = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pa;
+  const auto& b = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pb;
+
+  /* Order by blob size first (smallest to largest) and then table tag */
+
+  if (a.second.order != b.second.order)
+    return a.second.order < b.second.order ? -1 : +1;
+
+  if (a.second.data->length != b.second.data->length)
+    return a.second.data->length < b.second.data->length ? -1 : +1;
+
+  return a.first < b.first ? -1 : a.first == b.first ? 0 : +1;
+}
+
+static hb_face_builder_data_t *
+_hb_face_builder_data_create ()
+{
+  hb_face_builder_data_t *data = (hb_face_builder_data_t *) hb_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 (auto info : data->tables.values())
+    hb_blob_destroy (info.data);
+
+  data->tables.fini ();
+
+  hb_free (data);
+}
+
+static hb_blob_t *
+_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
+{
+
+  unsigned int table_count = data->tables.get_population ();
+  unsigned int face_length = table_count * 16 + 12;
+
+  for (auto info : data->tables.values())
+    face_length += hb_ceil_to_4 (hb_blob_get_length (info.data));
+
+  char *buf = (char *) hb_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.has (HB_TAG ('C','F','F',' '))
+                 || data->tables.has (HB_TAG ('C','F','F','2')));
+  hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
+
+  // Sort the tags so that produced face is deterministic.
+  hb_vector_t<hb_pair_t <hb_tag_t, face_table_info_t>> sorted_entries;
+  data->tables.iter () | hb_sink (sorted_entries);
+  if (unlikely (sorted_entries.in_error ()))
+  {
+    hb_free (buf);
+    return nullptr;
+  }
+
+  sorted_entries.qsort (compare_entries);
+
+  bool ret = f->serialize_single (&c,
+                                  sfnt_tag,
+                                  + sorted_entries.iter()
+                                  | hb_map ([&] (hb_pair_t<hb_tag_t, face_table_info_t> _) {
+                                    return hb_pair_t<hb_tag_t, hb_blob_t*> (_.first, _.second.data);
+                                  }));
+
+  c.end_serialize ();
+
+  if (unlikely (!ret))
+  {
+    hb_free (buf);
+    return nullptr;
+  }
+
+  return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, hb_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);
+
+  return hb_blob_reference (data->tables[tag].data);
+}
+
+
+/**
+ * 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:
+ * @face: A face object created with hb_face_builder_create()
+ * @tag: The #hb_tag_t of the table to add
+ * @blob: The blob containing the table data to add
+ *
+ * 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;
+
+  if (tag == HB_MAP_VALUE_INVALID)
+    return false;
+
+  hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
+
+  hb_blob_t* previous = data->tables.get (tag).data;
+  if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), -1}))
+  {
+    hb_blob_destroy (blob);
+    return false;
+  }
+
+  hb_blob_destroy (previous);
+  return true;
+}
+
+/**
+ * hb_face_builder_sort_tables:
+ * @face: A face object created with hb_face_builder_create()
+ * @tags: (array zero-terminated=1): ordered list of table tags terminated by
+ *   %HB_TAG_NONE
+ *
+ * Set the ordering of tables for serialization. Any tables not
+ * specified in the tags list will be ordered after the tables in
+ * tags, ordered by the default sort ordering.
+ *
+ * Since: 5.3.0
+ **/
+void
+hb_face_builder_sort_tables (hb_face_t *face,
+                             const hb_tag_t  *tags)
+{
+  if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
+    return;
+
+  hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
+
+  // Sort all unspecified tables after any specified tables.
+  for (auto& info : data->tables.values_ref())
+    info.order = (unsigned) -1;
+
+  signed order = 0;
+  for (const hb_tag_t* tag = tags;
+       *tag;
+       tag++)
+  {
+    face_table_info_t* info;
+    if (!data->tables.has (*tag, &info)) continue;
+    info->order = order++;
+  }
+}
index 5365598..e340710 100644 (file)
@@ -33,7 +33,6 @@
 #include "hb-open-file.hh"
 #include "hb-ot-face.hh"
 #include "hb-ot-cmap-table.hh"
-#include "hb-map.hh"
 
 
 /**
  * More precisely, 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.
+ *
+ * A font face can be created from a binary blob using hb_face_create().
+ * The face index is used to select a face from a binary blob that contains
+ * multiple faces.  For example, a binary blob that contains both a regular
+ * and a bold face can be used to create two font faces, one for each face
+ * index.
  **/
 
 
@@ -132,7 +137,7 @@ hb_face_create_for_tables (hb_reference_table_func_t  reference_table_func,
   face->user_data = user_data;
   face->destroy = destroy;
 
-  face->num_glyphs.set_relaxed (-1);
+  face->num_glyphs = -1;
 
   face->data.init0 (face);
   face->table.init0 (face);
@@ -190,7 +195,7 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
 }
 
 /**
- * hb_face_create: (Xconstructor)
+ * hb_face_create:
  * @blob: #hb_blob_t to work upon
  * @index: The index of the face within @blob
  *
@@ -198,7 +203,7 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
  * a face index into that blob.
  *
  * The face index is used for blobs of file formats such as TTC and
- * and DFont that can contain more than one face.  Face indices within
+ * DFont that can contain more than one face.  Face indices within
  * such collections are zero-based.
  *
  * <note>Note: If the blob font format is not a collection, @index
@@ -288,6 +293,7 @@ hb_face_destroy (hb_face_t *face)
 {
   if (!hb_object_destroy (face)) return;
 
+#ifndef HB_NO_SHAPER
   for (hb_face_t::plan_node_t *node = face->shape_plans; node; )
   {
     hb_face_t::plan_node_t *next = node->next;
@@ -295,6 +301,7 @@ hb_face_destroy (hb_face_t *face)
     hb_free (node);
     node = next;
   }
+#endif
 
   face->data.fini ();
   face->table.fini ();
@@ -315,7 +322,7 @@ hb_face_destroy (hb_face_t *face)
  *
  * Attaches a user-data key/data pair to the given face object.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -371,7 +378,7 @@ hb_face_make_immutable (hb_face_t *face)
  *
  * Tests whether the given face object is immutable.
  *
- * Return value: %true is @face is immutable, %false otherwise
+ * Return value: `true` is @face is immutable, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -470,6 +477,8 @@ hb_face_get_index (const hb_face_t *face)
  *
  * Sets the units-per-em (upem) for a face object to the specified value.
  *
+ * This API is used in rare circumstances.
+ *
  * Since: 0.9.2
  **/
 void
@@ -479,14 +488,17 @@ hb_face_set_upem (hb_face_t    *face,
   if (hb_object_is_immutable (face))
     return;
 
-  face->upem.set_relaxed (upem);
+  face->upem = upem;
 }
 
 /**
  * hb_face_get_upem:
  * @face: A face object
  *
- * Fetches the units-per-em (upem) value of the specified face object.
+ * Fetches the units-per-em (UPEM) value of the specified face object.
+ *
+ * Typical UPEM values for fonts are 1000, or 2048, but any value
+ * in between 16 and 16,384 is allowed for OpenType fonts.
  *
  * Return value: The upem value of @face
  *
@@ -505,6 +517,8 @@ hb_face_get_upem (const hb_face_t *face)
  *
  * Sets the glyph count for a face object to the specified value.
  *
+ * This API is used in rare circumstances.
+ *
  * Since: 0.9.7
  **/
 void
@@ -514,7 +528,7 @@ hb_face_set_glyph_count (hb_face_t    *face,
   if (hb_object_is_immutable (face))
     return;
 
-  face->num_glyphs.set_relaxed (glyph_count);
+  face->num_glyphs = glyph_count;
 }
 
 /**
@@ -579,7 +593,7 @@ hb_face_get_table_tags (const hb_face_t *face,
 /**
  * hb_face_collect_unicodes:
  * @face: A face object
- * @out: The set to add Unicode characters to
+ * @out: (out): The set to add Unicode characters to
  *
  * Collects all of the Unicode characters covered by @face and adds
  * them to the #hb_set_t set @out.
@@ -593,9 +607,30 @@ hb_face_collect_unicodes (hb_face_t *face,
   face->table.cmap->collect_unicodes (out, face->get_num_glyphs ());
 }
 /**
+ * hb_face_collect_nominal_glyph_mapping:
+ * @face: A face object
+ * @mapping: (out): The map to add Unicode-to-glyph mapping to
+ * @unicodes: (nullable) (out): The set to add Unicode characters to, or `NULL`
+ *
+ * Collects the mapping from Unicode characters to nominal glyphs of the @face,
+ * and optionally all of the Unicode characters covered by @face.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_face_collect_nominal_glyph_mapping (hb_face_t *face,
+                                      hb_map_t  *mapping,
+                                      hb_set_t  *unicodes)
+{
+  hb_set_t stack_unicodes;
+  if (!unicodes)
+    unicodes = &stack_unicodes;
+  face->table.cmap->collect_mapping (unicodes, mapping, face->get_num_glyphs ());
+}
+/**
  * hb_face_collect_variation_selectors:
  * @face: A face object
- * @out: The set to add Variation Selector characters to
+ * @out: (out): The set to add Variation Selector characters to
  *
  * Collects all Unicode "Variation Selector" characters covered by @face and adds
  * them to the #hb_set_t set @out.
@@ -612,7 +647,7 @@ hb_face_collect_variation_selectors (hb_face_t *face,
  * hb_face_collect_variation_unicodes:
  * @face: A face object
  * @variation_selector: The Variation Selector to query
- * @out: The set to add Unicode characters to
+ * @out: (out): The set to add Unicode characters to
  *
  * Collects all Unicode characters for @variation_selector covered by @face and adds
  * them to the #hb_set_t set @out.
@@ -627,163 +662,3 @@ hb_face_collect_variation_unicodes (hb_face_t *face,
   face->table.cmap->collect_variation_unicodes (variation_selector, out);
 }
 #endif
-
-
-/*
- * face-builder: A face that has add_table().
- */
-
-struct hb_face_builder_data_t
-{
-  hb_hashmap_t<hb_tag_t, hb_blob_t *> tables;
-};
-
-static int compare_entries (const void* pa, const void* pb)
-{
-  const auto& a = * (const hb_pair_t<hb_tag_t, hb_blob_t*> *) pa;
-  const auto& b = * (const hb_pair_t<hb_tag_t, hb_blob_t*> *) pb;
-
-  /* Order by blob size first (smallest to largest) and then table tag */
-
-  if (a.second->length != b.second->length)
-    return a.second->length < b.second->length ? -1 : +1;
-
-  return a.first < b.first ? -1 : a.first == b.first ? 0 : +1;
-}
-
-static hb_face_builder_data_t *
-_hb_face_builder_data_create ()
-{
-  hb_face_builder_data_t *data = (hb_face_builder_data_t *) hb_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 (hb_blob_t* b : data->tables.values())
-    hb_blob_destroy (b);
-
-  data->tables.fini ();
-
-  hb_free (data);
-}
-
-static hb_blob_t *
-_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
-{
-
-  unsigned int table_count = data->tables.get_population ();
-  unsigned int face_length = table_count * 16 + 12;
-
-  for (hb_blob_t* b : data->tables.values())
-    face_length += hb_ceil_to_4 (hb_blob_get_length (b));
-
-  char *buf = (char *) hb_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.has (HB_TAG ('C','F','F',' '))
-                 || data->tables.has (HB_TAG ('C','F','F','2')));
-  hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
-
-  // Sort the tags so that produced face is deterministic.
-  hb_vector_t<hb_pair_t <hb_tag_t, hb_blob_t*>> sorted_entries;
-  data->tables.iter () | hb_sink (sorted_entries);
-  if (unlikely (sorted_entries.in_error ()))
-  {
-    hb_free (buf);
-    return nullptr;
-  }
-
-  sorted_entries.qsort (compare_entries);
-  bool ret = f->serialize_single (&c, sfnt_tag, + sorted_entries.iter());
-
-  c.end_serialize ();
-
-  if (unlikely (!ret))
-  {
-    hb_free (buf);
-    return nullptr;
-  }
-
-  return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, hb_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);
-
-  return hb_blob_reference (data->tables[tag]);
-}
-
-
-/**
- * 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:
- * @face: A face object created with hb_face_builder_create()
- * @tag: The #hb_tag_t of the table to add
- * @blob: The blob containing the table data to add
- *
- * 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 (tag == HB_MAP_VALUE_INVALID)
-    return false;
-
-  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_blob_t* previous = data->tables.get (tag);
-  if (!data->tables.set (tag, hb_blob_reference (blob)))
-  {
-    hb_blob_destroy (blob);
-    return false;
-  }
-
-  hb_blob_destroy (previous);
-  return true;
-}
index 6ef2f8b..2e54ccf 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "hb-common.h"
 #include "hb-blob.h"
+#include "hb-map.h"
 #include "hb-set.h"
 
 HB_BEGIN_DECLS
@@ -150,6 +151,11 @@ hb_face_collect_unicodes (hb_face_t *face,
                          hb_set_t  *out);
 
 HB_EXTERN void
+hb_face_collect_nominal_glyph_mapping (hb_face_t *face,
+                                      hb_map_t  *mapping,
+                                      hb_set_t  *unicodes);
+
+HB_EXTERN void
 hb_face_collect_variation_selectors (hb_face_t *face,
                                     hb_set_t  *out);
 
@@ -171,6 +177,10 @@ hb_face_builder_add_table (hb_face_t *face,
                           hb_tag_t   tag,
                           hb_blob_t *blob);
 
+HB_EXTERN void
+hb_face_builder_sort_tables (hb_face_t *face,
+                             const hb_tag_t  *tags);
+
 
 HB_END_DECLS
 
index 765f272..aff3ff0 100644 (file)
@@ -65,7 +65,9 @@ struct hb_face_t
     hb_shape_plan_t *shape_plan;
     plan_node_t *next;
   };
+#ifndef HB_NO_SHAPER
   hb_atomic_ptr_t<plan_node_t> shape_plans;
+#endif
 
   hb_blob_t *reference_table (hb_tag_t tag) const
   {
@@ -74,7 +76,7 @@ struct hb_face_t
     if (unlikely (!reference_table_func))
       return hb_blob_get_empty ();
 
-    blob = reference_table_func (/*XXX*/const_cast<hb_face_t *> (this), tag, user_data);
+    blob = reference_table_func (/*Oh, well.*/const_cast<hb_face_t *> (this), tag, user_data);
     if (unlikely (!blob))
       return hb_blob_get_empty ();
 
@@ -83,7 +85,7 @@ struct hb_face_t
 
   unsigned int get_upem () const
   {
-    unsigned int ret = upem.get_relaxed ();
+    unsigned int ret = upem;
     if (unlikely (!ret))
     {
       return load_upem ();
@@ -93,7 +95,7 @@ struct hb_face_t
 
   unsigned int get_num_glyphs () const
   {
-    unsigned int ret = num_glyphs.get_relaxed ();
+    unsigned int ret = num_glyphs;
     if (unlikely (ret == UINT_MAX))
       return load_num_glyphs ();
     return ret;
index f8524ec..c54ad87 100644 (file)
@@ -75,16 +75,6 @@ _hb_fallback_shape (hb_shape_plan_t    *shape_plan HB_UNUSED,
                    const hb_feature_t *features HB_UNUSED,
                    unsigned int        num_features HB_UNUSED)
 {
-  /* TODO
-   *
-   * - Apply fallback kern.
-   * - Handle Variation Selectors?
-   * - Apply normalization?
-   *
-   * This will make the fallback shaper into a dumb "TrueType"
-   * shaper which many people unfortunately still request.
-   */
-
   hb_codepoint_t space;
   bool has_space = (bool) font->get_nominal_glyph (' ', &space);
 
diff --git a/src/hb-features.h.in b/src/hb-features.h.in
new file mode 100644 (file)
index 0000000..4b27bd5
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright © 2022 Red Hat, 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.
+ */
+
+#ifndef HB_FEATURES_H
+#define HB_FEATURES_H
+
+HB_BEGIN_DECLS
+
+/**
+ * SECTION: hb-features
+ * @title: hb-features
+ * @short_description: Feature detection
+ * @include: hb-features.h
+ *
+ * Macros for detecting optional HarfBuzz features at build time.
+ **/
+
+/**
+ * HB_HAS_CAIRO:
+ *
+ * Defined if Harfbuzz has been built with cairo support.
+ */
+#mesondefine HB_HAS_CAIRO
+
+/**
+ * HB_HAS_CORETEXT:
+ *
+ * Defined if Harfbuzz has been built with CoreText support.
+ */
+#mesondefine HB_HAS_CORETEXT
+
+/**
+ * HB_HAS_DIRECTWRITE:
+ *
+ * Defined if Harfbuzz has been built with DirectWrite support.
+ */
+#mesondefine HB_HAS_DIRECTWRITE
+
+/**
+ * HB_HAS_FREETYPE:
+ *
+ * Defined if Harfbuzz has been built with Freetype support.
+ */
+#mesondefine HB_HAS_FREETYPE
+
+/**
+ * HB_HAS_GDI:
+ *
+ * Defined if Harfbuzz has been built with GDI support.
+ */
+#mesondefine HB_HAS_GDI
+
+/**
+ * HB_HAS_GLIB:
+ *
+ * Defined if Harfbuzz has been built with GLib support.
+ */
+#mesondefine HB_HAS_GLIB
+
+/**
+ * HB_HAS_GOBJECT:
+ *
+ * Defined if Harfbuzz has been built with GObject support.
+ */
+#mesondefine HB_HAS_GOBJECT
+
+/**
+ * HB_HAS_GRAPHITE:
+ *
+ * Defined if Harfbuzz has been built with Graphite support.
+ */
+#mesondefine HB_HAS_GRAPHITE
+
+/**
+ * HB_HAS_ICU:
+ *
+ * Defined if Harfbuzz has been built with ICU support.
+ */
+#mesondefine HB_HAS_ICU
+
+/**
+ * HB_HAS_UNISCRIBE:
+ *
+ * Defined if Harfbuzz has been built with Uniscribe support.
+ */
+#mesondefine HB_HAS_UNISCRIBE
+
+/**
+ * HB_HAS_WASM:
+ *
+ * Defined if Harfbuzz has been built with WebAssembly support.
+ */
+#mesondefine HB_HAS_WASM
+
+
+HB_END_DECLS
+
+#endif /* HB_FEATURES_H */
index 350fcac..00f1f6d 100644 (file)
@@ -29,6 +29,8 @@
 #include "hb.hh"
 
 #include "hb-font.hh"
+#include "hb-draw.hh"
+#include "hb-paint.hh"
 #include "hb-machinery.hh"
 
 #include "hb-ot.h"
  *
  * HarfBuzz provides a built-in set of lightweight default
  * functions for each method in #hb_font_funcs_t.
+ *
+ * The default font functions are implemented in terms of the
+ * #hb_font_funcs_t methods of the parent font object.  This allows
+ * client programs to override only the methods they need to, and
+ * otherwise inherit the parent font's implementation, if any.
  **/
 
 
@@ -70,7 +77,7 @@ hb_font_get_font_h_extents_nil (hb_font_t         *font HB_UNUSED,
                                hb_font_extents_t *extents,
                                void              *user_data HB_UNUSED)
 {
-  memset (extents, 0, sizeof (*extents));
+  hb_memset (extents, 0, sizeof (*extents));
   return false;
 }
 
@@ -95,7 +102,7 @@ hb_font_get_font_v_extents_nil (hb_font_t         *font HB_UNUSED,
                                hb_font_extents_t *extents,
                                void              *user_data HB_UNUSED)
 {
-  memset (extents, 0, sizeof (*extents));
+  hb_memset (extents, 0, sizeof (*extents));
   return false;
 }
 
@@ -408,7 +415,7 @@ hb_font_get_glyph_extents_nil (hb_font_t          *font HB_UNUSED,
                               hb_glyph_extents_t *extents,
                               void               *user_data HB_UNUSED)
 {
-  memset (extents, 0, sizeof (*extents));
+  hb_memset (extents, 0, sizeof (*extents));
   return false;
 }
 
@@ -501,23 +508,186 @@ hb_font_get_glyph_from_name_default (hb_font_t      *font,
   return font->parent->get_glyph_from_name (name, len, glyph);
 }
 
-DEFINE_NULL_INSTANCE (hb_font_funcs_t) =
+static void
+hb_font_draw_glyph_nil (hb_font_t       *font HB_UNUSED,
+                       void            *font_data HB_UNUSED,
+                       hb_codepoint_t   glyph,
+                       hb_draw_funcs_t *draw_funcs,
+                       void            *draw_data,
+                       void            *user_data HB_UNUSED)
+{
+}
+
+static void
+hb_font_paint_glyph_nil (hb_font_t *font HB_UNUSED,
+                         void *font_data HB_UNUSED,
+                         hb_codepoint_t glyph HB_UNUSED,
+                         hb_paint_funcs_t *paint_funcs HB_UNUSED,
+                         void *paint_data HB_UNUSED,
+                         unsigned int palette HB_UNUSED,
+                         hb_color_t foreground HB_UNUSED,
+                         void *user_data HB_UNUSED)
+{
+}
+
+typedef struct hb_font_draw_glyph_default_adaptor_t {
+  hb_draw_funcs_t *draw_funcs;
+  void           *draw_data;
+  float                   x_scale;
+  float                   y_scale;
+  float                   slant;
+} hb_font_draw_glyph_default_adaptor_t;
+
+static void
+hb_draw_move_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED,
+                        void *draw_data,
+                        hb_draw_state_t *st,
+                        float to_x, float to_y,
+                        void *user_data HB_UNUSED)
+{
+  hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data;
+  float x_scale = adaptor->x_scale;
+  float y_scale = adaptor->y_scale;
+  float slant   = adaptor->slant;
+
+  adaptor->draw_funcs->emit_move_to (adaptor->draw_data, *st,
+                                    x_scale * to_x + slant * to_y, y_scale * to_y);
+}
+
+static void
+hb_draw_line_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
+                        hb_draw_state_t *st,
+                        float to_x, float to_y,
+                        void *user_data HB_UNUSED)
+{
+  hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data;
+  float x_scale = adaptor->x_scale;
+  float y_scale = adaptor->y_scale;
+  float slant   = adaptor->slant;
+
+  st->current_x = st->current_x * x_scale + st->current_y * slant;
+  st->current_y = st->current_y * y_scale;
+
+  adaptor->draw_funcs->emit_line_to (adaptor->draw_data, *st,
+                                    x_scale * to_x + slant * to_y, y_scale * to_y);
+}
+
+static void
+hb_draw_quadratic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
+                             hb_draw_state_t *st,
+                             float control_x, float control_y,
+                             float to_x, float to_y,
+                             void *user_data HB_UNUSED)
+{
+  hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data;
+  float x_scale = adaptor->x_scale;
+  float y_scale = adaptor->y_scale;
+  float slant   = adaptor->slant;
+
+  st->current_x = st->current_x * x_scale + st->current_y * slant;
+  st->current_y = st->current_y * y_scale;
+
+  adaptor->draw_funcs->emit_quadratic_to (adaptor->draw_data, *st,
+                                         x_scale * control_x + slant * control_y, y_scale * control_y,
+                                         x_scale * to_x + slant * to_y, y_scale * to_y);
+}
+
+static void
+hb_draw_cubic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
+                         hb_draw_state_t *st,
+                         float control1_x, float control1_y,
+                         float control2_x, float control2_y,
+                         float to_x, float to_y,
+                         void *user_data HB_UNUSED)
+{
+  hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data;
+  float x_scale = adaptor->x_scale;
+  float y_scale = adaptor->y_scale;
+  float slant   = adaptor->slant;
+
+  st->current_x = st->current_x * x_scale + st->current_y * slant;
+  st->current_y = st->current_y * y_scale;
+
+  adaptor->draw_funcs->emit_cubic_to (adaptor->draw_data, *st,
+                                     x_scale * control1_x + slant * control1_y, y_scale * control1_y,
+                                     x_scale * control2_x + slant * control2_y, y_scale * control2_y,
+                                     x_scale * to_x + slant * to_y, y_scale * to_y);
+}
+
+static void
+hb_draw_close_path_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
+                           hb_draw_state_t *st,
+                           void *user_data HB_UNUSED)
 {
+  hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data;
+
+  adaptor->draw_funcs->emit_close_path (adaptor->draw_data, *st);
+}
+
+static const hb_draw_funcs_t _hb_draw_funcs_default = {
   HB_OBJECT_HEADER_STATIC,
 
   {
-#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
-    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
-  },
-  {
-#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
-    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
-  },
+#define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_default,
+    HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+  }
+};
+
+static void
+hb_font_draw_glyph_default (hb_font_t       *font,
+                                void            *font_data HB_UNUSED,
+                                hb_codepoint_t   glyph,
+                                hb_draw_funcs_t *draw_funcs,
+                                void            *draw_data,
+                                void            *user_data HB_UNUSED)
+{
+  hb_font_draw_glyph_default_adaptor_t adaptor = {
+    draw_funcs,
+    draw_data,
+    font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0.f,
+    font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0.f,
+    font->parent->y_scale ? (font->slant - font->parent->slant) *
+                           (float) font->x_scale / (float) font->parent->y_scale : 0.f
+  };
+
+  font->parent->draw_glyph (glyph,
+                                const_cast<hb_draw_funcs_t *> (&_hb_draw_funcs_default),
+                                &adaptor);
+}
+
+static void
+hb_font_paint_glyph_default (hb_font_t *font,
+                             void *font_data,
+                             hb_codepoint_t glyph,
+                             hb_paint_funcs_t *paint_funcs,
+                             void *paint_data,
+                             unsigned int palette,
+                             hb_color_t foreground,
+                             void *user_data)
+{
+  paint_funcs->push_transform (paint_data,
+    font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0.f,
+    font->parent->y_scale ? (font->slant - font->parent->slant) *
+                           (float) font->x_scale / (float) font->parent->y_scale : 0.f,
+    0.f,
+    font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0.f,
+    0.f, 0.f);
+
+  font->parent->paint_glyph (glyph, paint_funcs, paint_data, palette, foreground);
+
+  paint_funcs->pop_transform (paint_data);
+}
+
+DEFINE_NULL_INSTANCE (hb_font_funcs_t) =
+{
+  HB_OBJECT_HEADER_STATIC,
+
+  nullptr,
+  nullptr,
   {
     {
-#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
+#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_font_##get_##name##_nil,
       HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
     }
@@ -527,19 +697,11 @@ DEFINE_NULL_INSTANCE (hb_font_funcs_t) =
 static const hb_font_funcs_t _hb_font_funcs_default = {
   HB_OBJECT_HEADER_STATIC,
 
-  {
-#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
-    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
-  },
-  {
-#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
-    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
-  },
+  nullptr,
+  nullptr,
   {
     {
-#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_default,
+#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_font_##get_##name##_default,
       HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
     }
@@ -548,7 +710,7 @@ static const hb_font_funcs_t _hb_font_funcs_default = {
 
 
 /**
- * hb_font_funcs_create: (Xconstructor)
+ * hb_font_funcs_create:
  *
  * Creates a new #hb_font_funcs_t structure of font functions.
  *
@@ -615,10 +777,16 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
 {
   if (!hb_object_destroy (ffuncs)) return;
 
-#define HB_FONT_FUNC_IMPLEMENT(name) if (ffuncs->destroy.name) \
-  ffuncs->destroy.name (ffuncs->user_data.name);
-  HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+  if (ffuncs->destroy)
+  {
+#define HB_FONT_FUNC_IMPLEMENT(get_,name) if (ffuncs->destroy->name) \
+    ffuncs->destroy->name (!ffuncs->user_data ? nullptr : ffuncs->user_data->name);
+    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
+  }
+
+  hb_free (ffuncs->destroy);
+  hb_free (ffuncs->user_data);
 
   hb_free (ffuncs);
 }
@@ -633,7 +801,7 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
  *
  * Attaches a user-data key/data pair to the specified font-functions structure.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -660,8 +828,8 @@ hb_font_funcs_set_user_data (hb_font_funcs_t    *ffuncs,
  * Since: 0.9.2
  **/
 void *
-hb_font_funcs_get_user_data (hb_font_funcs_t    *ffuncs,
-                            hb_user_data_key_t *key)
+hb_font_funcs_get_user_data (const hb_font_funcs_t *ffuncs,
+                            hb_user_data_key_t    *key)
 {
   return hb_object_get_user_data (ffuncs, key);
 }
@@ -690,7 +858,7 @@ hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
  *
  * Tests whether a font-functions structure is immutable.
  *
- * Return value: %true if @ffuncs is immutable, %false otherwise
+ * Return value: `true` if @ffuncs is immutable, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -701,33 +869,82 @@ hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs)
 }
 
 
-#define HB_FONT_FUNC_IMPLEMENT(name) \
+static bool
+_hb_font_funcs_set_preamble (hb_font_funcs_t    *ffuncs,
+                            bool                func_is_null,
+                            void              **user_data,
+                            hb_destroy_func_t  *destroy)
+{
+  if (hb_object_is_immutable (ffuncs))
+  {
+    if (*destroy)
+      (*destroy) (*user_data);
+    return false;
+  }
+
+  if (func_is_null)
+  {
+    if (*destroy)
+      (*destroy) (*user_data);
+    *destroy = nullptr;
+    *user_data = nullptr;
+  }
+
+  return true;
+}
+
+static bool
+_hb_font_funcs_set_middle (hb_font_funcs_t   *ffuncs,
+                          void              *user_data,
+                          hb_destroy_func_t  destroy)
+{
+  if (user_data && !ffuncs->user_data)
+  {
+    ffuncs->user_data = (decltype (ffuncs->user_data)) hb_calloc (1, sizeof (*ffuncs->user_data));
+    if (unlikely (!ffuncs->user_data))
+      goto fail;
+  }
+  if (destroy && !ffuncs->destroy)
+  {
+    ffuncs->destroy = (decltype (ffuncs->destroy)) hb_calloc (1, sizeof (*ffuncs->destroy));
+    if (unlikely (!ffuncs->destroy))
+      goto fail;
+  }
+
+  return true;
+
+fail:
+  if (destroy)
+    (destroy) (user_data);
+  return false;
+}
+
+#define HB_FONT_FUNC_IMPLEMENT(get_,name) \
                                                                         \
 void                                                                     \
 hb_font_funcs_set_##name##_func (hb_font_funcs_t             *ffuncs,    \
-                                hb_font_get_##name##_func_t  func,      \
+                                hb_font_##get_##name##_func_t func,     \
                                 void                        *user_data, \
                                 hb_destroy_func_t            destroy)   \
 {                                                                        \
-  if (hb_object_is_immutable (ffuncs))                                   \
-  {                                                                      \
-    if (destroy)                                                         \
-      destroy (user_data);                                               \
-    return;                                                              \
-  }                                                                      \
+  if (!_hb_font_funcs_set_preamble (ffuncs, !func, &user_data, &destroy))\
+      return;                                                            \
                                                                         \
-  if (ffuncs->destroy.name)                                              \
-    ffuncs->destroy.name (ffuncs->user_data.name);                       \
+  if (ffuncs->destroy && ffuncs->destroy->name)                          \
+    ffuncs->destroy->name (!ffuncs->user_data ? nullptr : ffuncs->user_data->name); \
+                                                                         \
+  if (!_hb_font_funcs_set_middle (ffuncs, user_data, destroy))           \
+      return;                                                            \
                                                                         \
-  if (func) {                                                            \
+  if (func)                                                              \
     ffuncs->get.f.name = func;                                           \
-    ffuncs->user_data.name = user_data;                                  \
-    ffuncs->destroy.name = destroy;                                      \
-  } else {                                                               \
-    ffuncs->get.f.name = hb_font_get_##name##_default;                   \
-    ffuncs->user_data.name = nullptr;                                    \
-    ffuncs->destroy.name = nullptr;                                      \
-  }                                                                      \
+  else                                                                   \
+    ffuncs->get.f.name = hb_font_##get_##name##_default;                   \
+                                                                        \
+  if (ffuncs->user_data)                                                 \
+    ffuncs->user_data->name = user_data;                                 \
+  if (ffuncs->destroy)                                                   \
+    ffuncs->destroy->name = destroy;                                     \
 }
 
 HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
@@ -756,7 +973,7 @@ hb_font_t::has_func (unsigned int i)
  * Fetches the extents for a specified font, for horizontal
  * text segments.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 1.1.3
  **/
@@ -775,7 +992,7 @@ hb_font_get_h_extents (hb_font_t         *font,
  * Fetches the extents for a specified font, for vertical
  * text segments.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 1.1.3
  **/
@@ -799,7 +1016,7 @@ hb_font_get_v_extents (hb_font_t         *font,
  * If @variation_selector is 0, calls hb_font_get_nominal_glyph();
  * otherwise calls hb_font_get_variation_glyph().
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -827,7 +1044,7 @@ hb_font_get_glyph (hb_font_t      *font,
  * for code points modified by variation selectors. For variation-selector
  * support, user hb_font_get_variation_glyph() or use hb_font_get_glyph().
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 1.2.3
  **/
@@ -849,7 +1066,8 @@ hb_font_get_nominal_glyph (hb_font_t      *font,
  * @glyph_stride: The stride between successive glyph IDs
  *
  * Fetches the nominal glyph IDs for a sequence of Unicode code points. Glyph
- * IDs must be returned in a #hb_codepoint_t output parameter.
+ * IDs must be returned in a #hb_codepoint_t output parameter. Stops at the
+ * first unsupported glyph ID.
  *
  * Return value: the number of code points processed
  *
@@ -879,7 +1097,7 @@ hb_font_get_nominal_glyphs (hb_font_t *font,
  * by the specified variation-selector code point, in the specified
  * font.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 1.2.3
  **/
@@ -989,7 +1207,7 @@ hb_font_get_glyph_v_advances (hb_font_t*            font,
  * Fetches the (X,Y) coordinates of the origin for a glyph ID
  * in the specified font, for horizontal text segments.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1012,7 +1230,7 @@ hb_font_get_glyph_h_origin (hb_font_t      *font,
  * Fetches the (X,Y) coordinates of the origin for a glyph ID
  * in the specified font, for vertical text segments.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1085,7 +1303,7 @@ hb_font_get_glyph_v_kerning (hb_font_t      *font,
  * Fetches the #hb_glyph_extents_t data for a glyph ID
  * in the specified font.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1108,7 +1326,7 @@ hb_font_get_glyph_extents (hb_font_t          *font,
  * Fetches the (x,y) coordinates of a specified contour-point index
  * in the specified glyph, within the specified font.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1131,7 +1349,10 @@ hb_font_get_glyph_contour_point (hb_font_t      *font,
  *
  * Fetches the glyph-name string for a glyph ID in the specified @font.
  *
- * Return value: %true if data found, %false otherwise
+ * According to the OpenType specification, glyph names are limited to 63
+ * characters and can only contain (a subset of) ASCII.
+ *
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1155,7 +1376,7 @@ hb_font_get_glyph_name (hb_font_t      *font,
  *
  * <note>Note: @len == -1 means the name string is null-terminated.</note>
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1168,6 +1389,82 @@ hb_font_get_glyph_from_name (hb_font_t      *font,
   return font->get_glyph_from_name (name, len, glyph);
 }
 
+#ifndef HB_DISABLE_DEPRECATED
+/**
+ * hb_font_get_glyph_shape:
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID
+ * @dfuncs: #hb_draw_funcs_t to draw to
+ * @draw_data: User data to pass to draw callbacks
+ *
+ * Fetches the glyph shape that corresponds to a glyph in the specified @font.
+ * The shape is returned by way of calls to the callbacks of the @dfuncs
+ * objects, with @draw_data passed to them.
+ *
+ * Since: 4.0.0
+ * Deprecated: 7.0.0: Use hb_font_draw_glyph() instead
+ */
+void
+hb_font_get_glyph_shape (hb_font_t *font,
+                        hb_codepoint_t glyph,
+                        hb_draw_funcs_t *dfuncs, void *draw_data)
+{
+  hb_font_draw_glyph (font, glyph, dfuncs, draw_data);
+}
+#endif
+
+/**
+ * hb_font_draw_glyph:
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID
+ * @dfuncs: #hb_draw_funcs_t to draw to
+ * @draw_data: User data to pass to draw callbacks
+ *
+ * Draws the outline that corresponds to a glyph in the specified @font.
+ *
+ * The outline is returned by way of calls to the callbacks of the @dfuncs
+ * objects, with @draw_data passed to them.
+ *
+ * Since: 7.0.0
+ **/
+void
+hb_font_draw_glyph (hb_font_t *font,
+                        hb_codepoint_t glyph,
+                        hb_draw_funcs_t *dfuncs, void *draw_data)
+{
+  font->draw_glyph (glyph, dfuncs, draw_data);
+}
+
+/**
+ * hb_font_paint_glyph:
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID
+ * @pfuncs: #hb_paint_funcs_t to paint with
+ * @paint_data: User data to pass to paint callbacks
+ * @palette_index: The index of the font's color palette to use
+ * @foreground: The foreground color, unpremultipled
+ *
+ * Paints the glyph.
+ *
+ * The painting instructions are returned by way of calls to
+ * the callbacks of the @funcs object, with @paint_data passed
+ * to them.
+ *
+ * If the font has color palettes (see hb_ot_color_has_palettes()),
+ * then @palette_index selects the palette to use. If the font only
+ * has one palette, this will be 0.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_font_paint_glyph (hb_font_t *font,
+                     hb_codepoint_t glyph,
+                     hb_paint_funcs_t *pfuncs, void *paint_data,
+                     unsigned int palette_index,
+                     hb_color_t foreground)
+{
+  font->paint_glyph (glyph, pfuncs, paint_data, palette_index, foreground);
+}
 
 /* A bit higher-level, and with fallback */
 
@@ -1190,7 +1487,7 @@ hb_font_get_extents_for_direction (hb_font_t         *font,
                                   hb_direction_t     direction,
                                   hb_font_extents_t *extents)
 {
-  return font->get_extents_for_direction (direction, extents);
+  font->get_extents_for_direction (direction, extents);
 }
 /**
  * hb_font_get_glyph_advance_for_direction:
@@ -1215,7 +1512,7 @@ hb_font_get_glyph_advance_for_direction (hb_font_t      *font,
                                         hb_position_t  *x,
                                         hb_position_t  *y)
 {
-  return font->get_glyph_advance_for_direction (glyph, direction, x, y);
+  font->get_glyph_advance_for_direction (glyph, direction, x, y);
 }
 /**
  * hb_font_get_glyph_advances_for_direction:
@@ -1370,7 +1667,7 @@ hb_font_get_glyph_kerning_for_direction (hb_font_t      *font,
  * Calls the appropriate direction-specific variant (horizontal
  * or vertical) depending on the value of @direction.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1399,7 +1696,7 @@ hb_font_get_glyph_extents_for_origin (hb_font_t          *font,
  * Calls the appropriate direction-specific variant (horizontal
  * or vertical) depending on the value of @direction.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1427,6 +1724,9 @@ hb_font_get_glyph_contour_point_for_origin (hb_font_t      *font,
  * If the glyph ID has no name in @font, a string of the form `gidDDD` is
  * generated, with `DDD` being the glyph ID.
  *
+ * According to the OpenType specification, glyph names are limited to 63
+ * characters and can only contain (a subset of) ASCII.
+ *
  * Since: 0.9.2
  **/
 void
@@ -1450,7 +1750,7 @@ hb_font_glyph_to_string (hb_font_t      *font,
  *
  * <note>Note: @len == -1 means the string is null-terminated.</note>
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1472,13 +1772,23 @@ DEFINE_NULL_INSTANCE (hb_font_t) =
 {
   HB_OBJECT_HEADER_STATIC,
 
+  0, /* serial */
+  0, /* serial_coords */
+
   nullptr, /* parent */
   const_cast<hb_face_t *> (&_hb_Null_hb_face_t),
 
   1000, /* x_scale */
   1000, /* y_scale */
-  0., /* slant */
-  0., /* slant_xy; */
+  0.f, /* x_embolden */
+  0.f, /* y_embolden */
+  true, /* embolden_in_place */
+  0, /* x_strength */
+  0, /* y_strength */
+  0.f, /* slant */
+  0.f, /* slant_xy; */
+  1.f, /* x_multf */
+  1.f, /* y_multf */
   1<<16, /* x_mult */
   1<<16, /* y_mult */
 
@@ -1486,6 +1796,7 @@ DEFINE_NULL_INSTANCE (hb_font_t) =
   0, /* y_ppem */
   0, /* ptem */
 
+  HB_FONT_NO_VAR_NAMED_INSTANCE, /* instance_index */
   0, /* num_coords */
   nullptr, /* coords */
   nullptr, /* design_coords */
@@ -1503,6 +1814,7 @@ _hb_font_create (hb_face_t *face)
 
   if (unlikely (!face))
     face = hb_face_get_empty ();
+
   if (!(font = hb_object_create<hb_font_t> ()))
     return hb_font_get_empty ();
 
@@ -1511,14 +1823,17 @@ _hb_font_create (hb_face_t *face)
   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);
+  font->x_scale = font->y_scale = face->get_upem ();
+  font->embolden_in_place = true;
+  font->x_multf = font->y_multf = 1.f;
   font->x_mult = font->y_mult = 1 << 16;
+  font->instance_index = HB_FONT_NO_VAR_NAMED_INSTANCE;
 
   return font;
 }
 
 /**
- * hb_font_create: (Xconstructor)
+ * hb_font_create:
  * @face: a face.
  *
  * Constructs a new font object from the specified face.
@@ -1564,6 +1879,8 @@ _hb_font_adopt_var_coords (hb_font_t *font,
   font->coords = coords;
   font->design_coords = design_coords;
   font->num_coords = coords_length;
+
+  font->mults_changed (); // Easiest to call this to drop cached data
 }
 
 /**
@@ -1592,8 +1909,10 @@ hb_font_create_sub_font (hb_font_t *parent)
 
   font->x_scale = parent->x_scale;
   font->y_scale = parent->y_scale;
+  font->x_embolden = parent->x_embolden;
+  font->y_embolden = parent->y_embolden;
+  font->embolden_in_place = parent->embolden_in_place;
   font->slant = parent->slant;
-  font->mults_changed ();
   font->x_ppem = parent->x_ppem;
   font->y_ppem = parent->y_ppem;
   font->ptem = parent->ptem;
@@ -1605,8 +1924,8 @@ hb_font_create_sub_font (hb_font_t *parent)
     float *design_coords = (float *) hb_calloc (num_coords, sizeof (parent->design_coords[0]));
     if (likely (coords && design_coords))
     {
-      memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0]));
-      memcpy (design_coords, parent->design_coords, num_coords * sizeof (parent->design_coords[0]));
+      hb_memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0]));
+      hb_memcpy (design_coords, parent->design_coords, num_coords * sizeof (parent->design_coords[0]));
       _hb_font_adopt_var_coords (font, coords, design_coords, num_coords);
     }
     else
@@ -1616,6 +1935,8 @@ hb_font_create_sub_font (hb_font_t *parent)
     }
   }
 
+  font->mults_changed ();
+
   return font;
 }
 
@@ -1690,7 +2011,7 @@ hb_font_destroy (hb_font_t *font)
  *
  * Attaches a user-data key/data pair to the specified font object.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1701,6 +2022,9 @@ hb_font_set_user_data (hb_font_t          *font,
                       hb_destroy_func_t   destroy /* May be NULL. */,
                       hb_bool_t           replace)
 {
+  if (!hb_object_is_immutable (font))
+    font->serial++;
+
   return hb_object_set_user_data (font, key, data, destroy, replace);
 }
 
@@ -1717,7 +2041,7 @@ hb_font_set_user_data (hb_font_t          *font,
  * Since: 0.9.2
  **/
 void *
-hb_font_get_user_data (hb_font_t          *font,
+hb_font_get_user_data (const hb_font_t    *font,
                       hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (font, key);
@@ -1749,7 +2073,7 @@ hb_font_make_immutable (hb_font_t *font)
  *
  * Tests whether a font object is immutable.
  *
- * Return value: %true if @font is immutable, %false otherwise
+ * Return value: `true` if @font is immutable, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1760,6 +2084,45 @@ hb_font_is_immutable (hb_font_t *font)
 }
 
 /**
+ * hb_font_get_serial:
+ * @font: #hb_font_t to work upon
+ *
+ * Returns the internal serial number of the font. The serial
+ * number is increased every time a setting on the font is
+ * changed, using a setter function.
+ *
+ * Return value: serial number
+ *
+ * Since: 4.4.0
+ **/
+unsigned int
+hb_font_get_serial (hb_font_t *font)
+{
+  return font->serial;
+}
+
+/**
+ * hb_font_changed:
+ * @font: #hb_font_t to work upon
+ *
+ * Notifies the @font that underlying font data has changed.
+ * This has the effect of increasing the serial as returned
+ * by hb_font_get_serial(), which invalidates internal caches.
+ *
+ * Since: 4.4.0
+ **/
+void
+hb_font_changed (hb_font_t *font)
+{
+  if (hb_object_is_immutable (font))
+    return;
+
+  font->serial++;
+
+  font->mults_changed ();
+}
+
+/**
  * hb_font_set_parent:
  * @font: #hb_font_t to work upon
  * @parent: The parent font object to assign
@@ -1775,6 +2138,11 @@ hb_font_set_parent (hb_font_t *font,
   if (hb_object_is_immutable (font))
     return;
 
+  if (parent == font->parent)
+    return;
+
+  font->serial++;
+
   if (!parent)
     parent = hb_font_get_empty ();
 
@@ -1817,6 +2185,11 @@ hb_font_set_face (hb_font_t *font,
   if (hb_object_is_immutable (font))
     return;
 
+  if (face == font->face)
+    return;
+
+  font->serial++;
+
   if (unlikely (!face))
     face = hb_face_get_empty ();
 
@@ -1871,6 +2244,8 @@ hb_font_set_funcs (hb_font_t         *font,
     return;
   }
 
+  font->serial++;
+
   if (font->destroy)
     font->destroy (font->user_data);
 
@@ -1908,6 +2283,8 @@ hb_font_set_funcs_data (hb_font_t         *font,
     return;
   }
 
+  font->serial++;
+
   if (font->destroy)
     font->destroy (font->user_data);
 
@@ -1924,6 +2301,31 @@ hb_font_set_funcs_data (hb_font_t         *font,
  *
  * Sets the horizontal and vertical scale of a font.
  *
+ * The font scale is a number related to, but not the same as,
+ * font size. Typically the client establishes a scale factor
+ * to be used between the two. For example, 64, or 256, which
+ * would be the fractional-precision part of the font scale.
+ * This is necessary because #hb_position_t values are integer
+ * types and you need to leave room for fractional values
+ * in there.
+ *
+ * For example, to set the font size to 20, with 64
+ * levels of fractional precision you would call
+ * `hb_font_set_scale(font, 20 * 64, 20 * 64)`.
+ *
+ * In the example above, even what font size 20 means is up to
+ * you. It might be 20 pixels, or 20 points, or 20 millimeters.
+ * HarfBuzz does not care about that.  You can set the point
+ * size of the font using hb_font_set_ptem(), and the pixel
+ * size using hb_font_set_ppem().
+ *
+ * The choice of scale is yours but needs to be consistent between
+ * what you set here, and what you expect out of #hb_position_t
+ * as well has draw / paint API output values.
+ *
+ * Fonts default to a scale equal to the UPEM value of their face.
+ * A font with this setting is sometimes called an "unscaled" font.
+ *
  * Since: 0.9.2
  **/
 void
@@ -1934,6 +2336,11 @@ hb_font_set_scale (hb_font_t *font,
   if (hb_object_is_immutable (font))
     return;
 
+  if (font->x_scale == x_scale && font->y_scale == y_scale)
+    return;
+
+  font->serial++;
+
   font->x_scale = x_scale;
   font->y_scale = y_scale;
   font->mults_changed ();
@@ -1964,7 +2371,11 @@ hb_font_get_scale (hb_font_t *font,
  * @x_ppem: Horizontal ppem value to assign
  * @y_ppem: Vertical ppem value to assign
  *
- * Sets the horizontal and vertical pixels-per-em (ppem) of a font.
+ * Sets the horizontal and vertical pixels-per-em (PPEM) of a font.
+ *
+ * These values are used for pixel-size-specific adjustment to
+ * shaping and draw results, though for the most part they are
+ * unused and can be left unset.
  *
  * Since: 0.9.2
  **/
@@ -1976,6 +2387,11 @@ hb_font_set_ppem (hb_font_t    *font,
   if (hb_object_is_immutable (font))
     return;
 
+  if (font->x_ppem == x_ppem && font->y_ppem == y_ppem)
+    return;
+
+  font->serial++;
+
   font->x_ppem = x_ppem;
   font->y_ppem = y_ppem;
 }
@@ -2018,6 +2434,11 @@ hb_font_set_ptem (hb_font_t *font,
   if (hb_object_is_immutable (font))
     return;
 
+  if (font->ptem == ptem)
+    return;
+
+  font->serial++;
+
   font->ptem = ptem;
 }
 
@@ -2039,17 +2460,90 @@ hb_font_get_ptem (hb_font_t *font)
 }
 
 /**
+ * hb_font_set_synthetic_bold:
+ * @font: #hb_font_t to work upon
+ * @x_embolden: the amount to embolden horizontally
+ * @y_embolden: the amount to embolden vertically
+ * @in_place: whether to embolden glyphs in-place
+ *
+ * Sets the "synthetic boldness" of a font.
+ *
+ * Positive values for @x_embolden / @y_embolden make a font
+ * bolder, negative values thinner. Typical values are in the
+ * 0.01 to 0.05 range. The default value is zero.
+ *
+ * Synthetic boldness is applied by offsetting the contour
+ * points of the glyph shape.
+ *
+ * Synthetic boldness is applied when rendering a glyph via
+ * hb_font_draw_glyph().
+ *
+ * If @in_place is `false`, then glyph advance-widths are also
+ * adjusted, otherwise they are not.  The in-place mode is
+ * useful for simulating [font grading](https://fonts.google.com/knowledge/glossary/grade).
+ *
+ *
+ * Since: 7.0.0
+ **/
+void
+hb_font_set_synthetic_bold (hb_font_t *font,
+                           float x_embolden,
+                           float y_embolden,
+                           hb_bool_t in_place)
+{
+  if (hb_object_is_immutable (font))
+    return;
+
+  if (font->x_embolden == x_embolden &&
+      font->y_embolden == y_embolden &&
+      font->embolden_in_place == (bool) in_place)
+    return;
+
+  font->serial++;
+
+  font->x_embolden = x_embolden;
+  font->y_embolden = y_embolden;
+  font->embolden_in_place = in_place;
+  font->mults_changed ();
+}
+
+/**
+ * hb_font_get_synthetic_bold:
+ * @font: #hb_font_t to work upon
+ * @x_embolden: (out): return location for horizontal value
+ * @y_embolden: (out): return location for vertical value
+ * @in_place: (out): return location for in-place value
+ *
+ * Fetches the "synthetic boldness" parameters of a font.
+ *
+ * Since: 7.0.0
+ **/
+void
+hb_font_get_synthetic_bold (hb_font_t *font,
+                           float *x_embolden,
+                           float *y_embolden,
+                           hb_bool_t *in_place)
+{
+  if (x_embolden) *x_embolden = font->x_embolden;
+  if (y_embolden) *y_embolden = font->y_embolden;
+  if (in_place) *in_place = font->embolden_in_place;
+}
+
+/**
  * hb_font_set_synthetic_slant:
  * @font: #hb_font_t to work upon
  * @slant: synthetic slant value.
  *
  * Sets the "synthetic slant" of a font.  By default is zero.
- * Synthetic slant is the graphical skew that the renderer
- * applies to the font at rendering time.
+ * Synthetic slant is the graphical skew applied to the font
+ * at rendering time.
  *
  * HarfBuzz needs to know this value to adjust shaping results,
  * metrics, and style values to match the slanted rendering.
  *
+ * <note>Note: The glyph shape fetched via the hb_font_draw_glyph()
+ * function is slanted to reflect this value as well.</note>
+ *
  * <note>Note: The slant value is a ratio.  For example, a
  * 20% slant would be represented as a 0.2 value.</note>
  *
@@ -2061,6 +2555,11 @@ hb_font_set_synthetic_slant (hb_font_t *font, float slant)
   if (hb_object_is_immutable (font))
     return;
 
+  if (font->slant == slant)
+    return;
+
+  font->serial++;
+
   font->slant = slant;
   font->mults_changed ();
 }
@@ -2108,7 +2607,9 @@ hb_font_set_variations (hb_font_t            *font,
   if (hb_object_is_immutable (font))
     return;
 
-  if (!variations_length)
+  font->serial_coords = ++font->serial;
+
+  if (!variations_length && font->instance_index == HB_FONT_NO_VAR_NAMED_INSTANCE)
   {
     hb_font_set_var_coords_normalized (font, nullptr, 0);
     return;
@@ -2128,20 +2629,101 @@ hb_font_set_variations (hb_font_t            *font,
     return;
   }
 
+  /* Initialize design coords. */
+  for (unsigned int i = 0; i < coords_length; i++)
+    design_coords[i] = axes[i].get_default ();
+  if (font->instance_index != HB_FONT_NO_VAR_NAMED_INSTANCE)
+  {
+    unsigned count = coords_length;
+    /* This may fail if index is out-of-range;
+     * That's why we initialize design_coords from fvar above
+     * unconditionally. */
+    hb_ot_var_named_instance_get_design_coords (font->face, font->instance_index,
+                                               &count, design_coords);
+  }
+
   for (unsigned int i = 0; i < variations_length; i++)
   {
     const auto tag = variations[i].tag;
     const auto v = variations[i].value;
     for (unsigned axis_index = 0; axis_index < coords_length; axis_index++)
       if (axes[axis_index].axisTag == tag)
-      {
        design_coords[axis_index] = v;
-       normalized[axis_index] = fvar.normalize_axis_value (axis_index, v);
-      }
   }
-  font->face->table.avar->map_coords (normalized, coords_length);
 
+  hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized);
+  _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length);
+}
+
+/**
+ * hb_font_set_variation:
+ * @font: #hb_font_t to work upon
+ * @tag: The #hb_tag_t tag of the variation-axis name
+ * @value: The value of the variation axis
+ *
+ * Change the value of one variation axis on the font.
+ *
+ * Note: This function is expensive to be called repeatedly.
+ *   If you want to set multiple variation axes at the same time,
+ *   use hb_font_set_variations() instead.
+ *
+ * Since: 7.1.0
+ */
+void
+hb_font_set_variation (hb_font_t *font,
+                      hb_tag_t tag,
+                      float    value)
+{
+  if (hb_object_is_immutable (font))
+    return;
+
+  font->serial_coords = ++font->serial;
+
+  // TODO Share some of this code with set_variations()
+
+  const OT::fvar &fvar = *font->face->table.fvar;
+  auto axes = fvar.get_axes ();
+  const unsigned coords_length = axes.length;
+
+  int *normalized = coords_length ? (int *) hb_calloc (coords_length, sizeof (int)) : nullptr;
+  float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr;
+
+  if (unlikely (coords_length && !(normalized && design_coords)))
+  {
+    hb_free (normalized);
+    hb_free (design_coords);
+    return;
+  }
+
+  /* Initialize design coords. */
+  if (font->design_coords)
+  {
+    assert (coords_length == font->num_coords);
+    for (unsigned int i = 0; i < coords_length; i++)
+      design_coords[i] = font->design_coords[i];
+  }
+  else
+  {
+    for (unsigned int i = 0; i < coords_length; i++)
+      design_coords[i] = axes[i].get_default ();
+    if (font->instance_index != HB_FONT_NO_VAR_NAMED_INSTANCE)
+    {
+      unsigned count = coords_length;
+      /* This may fail if index is out-of-range;
+       * That's why we initialize design_coords from fvar above
+       * unconditionally. */
+      hb_ot_var_named_instance_get_design_coords (font->face, font->instance_index,
+                                                 &count, design_coords);
+    }
+  }
+
+  for (unsigned axis_index = 0; axis_index < coords_length; axis_index++)
+    if (axes[axis_index].axisTag == tag)
+      design_coords[axis_index] = value;
+
+  hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized);
   _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length);
+
 }
 
 /**
@@ -2167,6 +2749,8 @@ hb_font_set_var_coords_design (hb_font_t    *font,
   if (hb_object_is_immutable (font))
     return;
 
+  font->serial_coords = ++font->serial;
+
   int *normalized = coords_length ? (int *) hb_calloc (coords_length, sizeof (int)) : nullptr;
   float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr;
 
@@ -2178,7 +2762,7 @@ hb_font_set_var_coords_design (hb_font_t    *font,
   }
 
   if (coords_length)
-    memcpy (design_coords, coords, coords_length * sizeof (font->design_coords[0]));
+    hb_memcpy (design_coords, coords, coords_length * sizeof (font->design_coords[0]));
 
   hb_ot_var_normalize_coords (font->face, coords_length, coords, normalized);
   _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length);
@@ -2189,26 +2773,40 @@ hb_font_set_var_coords_design (hb_font_t    *font,
  * @font: a font.
  * @instance_index: named instance index.
  *
- * Sets design coords of a font from a named instance index.
+ * Sets design coords of a font from a named-instance index.
  *
  * Since: 2.6.0
  */
 void
 hb_font_set_var_named_instance (hb_font_t *font,
-                               unsigned instance_index)
+                               unsigned int instance_index)
 {
   if (hb_object_is_immutable (font))
     return;
 
-  unsigned int coords_length = hb_ot_var_named_instance_get_design_coords (font->face, instance_index, nullptr, nullptr);
-
-  float *coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr;
-  if (unlikely (coords_length && !coords))
+  if (font->instance_index == instance_index)
     return;
 
-  hb_ot_var_named_instance_get_design_coords (font->face, instance_index, &coords_length, coords);
-  hb_font_set_var_coords_design (font, coords, coords_length);
-  hb_free (coords);
+  font->serial_coords = ++font->serial;
+
+  font->instance_index = instance_index;
+  hb_font_set_variations (font, nullptr, 0);
+}
+
+/**
+ * hb_font_get_var_named_instance:
+ * @font: a font.
+ *
+ * Returns the currently-set named-instance index of the font.
+ *
+ * Return value: Named-instance index or %HB_FONT_NO_VAR_NAMED_INSTANCE.
+ *
+ * Since: 7.0.0
+ **/
+unsigned int
+hb_font_get_var_named_instance (hb_font_t *font)
+{
+  return font->instance_index;
 }
 
 /**
@@ -2236,6 +2834,8 @@ hb_font_set_var_coords_normalized (hb_font_t    *font,
   if (hb_object_is_immutable (font))
     return;
 
+  font->serial_coords = ++font->serial;
+
   int *copy = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr;
   int *unmapped = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr;
   float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (design_coords[0])) : nullptr;
@@ -2250,8 +2850,8 @@ hb_font_set_var_coords_normalized (hb_font_t    *font,
 
   if (coords_length)
   {
-    memcpy (copy, coords, coords_length * sizeof (coords[0]));
-    memcpy (unmapped, coords, coords_length * sizeof (coords[0]));
+    hb_memcpy (copy, coords, coords_length * sizeof (coords[0]));
+    hb_memcpy (unmapped, coords, coords_length * sizeof (coords[0]));
   }
 
   /* Best effort design coords simulation */
@@ -2441,15 +3041,29 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t          *ffuncs,
     return;
   }
 
+  /* Since we pass it to two destroying functions. */
+  trampoline_reference (&trampoline->closure);
+
   hb_font_funcs_set_nominal_glyph_func (ffuncs,
                                        hb_font_get_nominal_glyph_trampoline,
                                        trampoline,
                                        trampoline_destroy);
 
-  trampoline_reference (&trampoline->closure);
   hb_font_funcs_set_variation_glyph_func (ffuncs,
                                          hb_font_get_variation_glyph_trampoline,
                                          trampoline,
                                          trampoline_destroy);
 }
 #endif
+
+
+#ifndef HB_DISABLE_DEPRECATED
+void
+hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t               *ffuncs,
+                                   hb_font_get_glyph_shape_func_t  func,
+                                   void                           *user_data,
+                                   hb_destroy_func_t               destroy /* May be NULL. */)
+{
+  hb_font_funcs_set_draw_glyph_func (ffuncs, func, user_data, destroy);
+}
+#endif
index a3bbb2e..3c2355a 100644 (file)
 #include "hb-common.h"
 #include "hb-face.h"
 #include "hb-draw.h"
+#include "hb-paint.h"
 
 HB_BEGIN_DECLS
 
-/**
- * hb_font_t:
- *
- * Data type for holding fonts.
- *
- */
-typedef struct hb_font_t hb_font_t;
-
-
 /*
  * hb_font_funcs_t
  */
@@ -86,8 +78,8 @@ hb_font_funcs_set_user_data (hb_font_funcs_t    *ffuncs,
 
 
 HB_EXTERN void *
-hb_font_funcs_get_user_data (hb_font_funcs_t    *ffuncs,
-                            hb_user_data_key_t *key);
+hb_font_funcs_get_user_data (const hb_font_funcs_t *ffuncs,
+                            hb_user_data_key_t    *key);
 
 
 HB_EXTERN void
@@ -97,7 +89,7 @@ HB_EXTERN hb_bool_t
 hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs);
 
 
-/* font and glyph extents */
+/* font extents */
 
 /**
  * hb_font_extents_t:
@@ -126,24 +118,6 @@ typedef struct hb_font_extents_t {
   hb_position_t reserved1;
 } hb_font_extents_t;
 
-/**
- * hb_glyph_extents_t:
- * @x_bearing: Distance from the x-origin to the left extremum of the glyph.
- * @y_bearing: Distance from the top extremum of the glyph to the y-origin.
- * @width: Distance from the left extremum of the glyph to the right extremum.
- * @height: Distance from the top extremum of the glyph to the bottom extremum.
- *
- * Glyph extent values, measured in font units.
- *
- * Note that @height is negative, in coordinate systems that grow up.
- **/
-typedef struct hb_glyph_extents_t {
-  hb_position_t x_bearing;
-  hb_position_t y_bearing;
-  hb_position_t width;
-  hb_position_t height;
-} hb_glyph_extents_t;
-
 /* func types */
 
 /**
@@ -198,7 +172,7 @@ typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t;
  * This method should retrieve the nominal glyph ID for a specified Unicode code
  * point. Glyph IDs must be returned in a #hb_codepoint_t output parameter.
  * 
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *font_data,
@@ -221,7 +195,7 @@ typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *fo
  * followed by a specified Variation Selector code point. Glyph IDs must be
  * returned in a #hb_codepoint_t output parameter.
  * 
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 typedef hb_bool_t (*hb_font_get_variation_glyph_func_t) (hb_font_t *font, void *font_data,
@@ -362,7 +336,7 @@ typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_v_advances_func_t;
  * origin for a glyph. Each coordinate must be returned in an #hb_position_t
  * output parameter.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  * 
  **/
 typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *font_data,
@@ -434,7 +408,7 @@ typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
  * This method should retrieve the extents for a specified glyph. Extents must be 
  * returned in an #hb_glyph_extents output parameter.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  * 
  **/
 typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data,
@@ -458,7 +432,7 @@ typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *fo
  * specified contour point in a glyph. Each coordinate must be returned as
  * an #hb_position_t output parameter.
  * 
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, void *font_data,
@@ -481,7 +455,7 @@ typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, vo
  * This method should retrieve the glyph name that corresponds to a
  * glyph ID. The name should be returned in a string output parameter.
  * 
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_data,
@@ -503,7 +477,7 @@ typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_
  * This method should retrieve the glyph ID that corresponds to a glyph-name
  * string. 
  * 
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *font_data,
@@ -511,6 +485,46 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
                                                         hb_codepoint_t *glyph,
                                                         void *user_data);
 
+/**
+ * hb_font_draw_glyph_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @draw_funcs: The draw functions to send the shape data to
+ * @draw_data: The data accompanying the draw functions
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * Since: 7.0.0
+ *
+ **/
+typedef void (*hb_font_draw_glyph_func_t) (hb_font_t *font, void *font_data,
+                                           hb_codepoint_t glyph,
+                                           hb_draw_funcs_t *draw_funcs, void *draw_data,
+                                           void *user_data);
+
+/**
+ * hb_font_paint_glyph_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @paint_funcs: The paint functions to use
+ * @paint_data: The data accompanying the paint functions
+ * @palette_index: The color palette to use
+ * @foreground: The foreground color
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * Since: 7.0.0
+ */
+typedef void (*hb_font_paint_glyph_func_t) (hb_font_t *font, void *font_data,
+                                            hb_codepoint_t glyph,
+                                            hb_paint_funcs_t *paint_funcs, void *paint_data,
+                                            unsigned int palette_index,
+                                            hb_color_t foreground,
+                                            void *user_data);
 
 /* func setters */
 
@@ -770,6 +784,38 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
                                        hb_font_get_glyph_from_name_func_t func,
                                        void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_font_funcs_set_draw_glyph_func:
+ * @ffuncs: A font-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets the implementation function for #hb_font_draw_glyph_func_t.
+ *
+ * Since: 7.0.0
+ **/
+HB_EXTERN void
+hb_font_funcs_set_draw_glyph_func (hb_font_funcs_t *ffuncs,
+                                   hb_font_draw_glyph_func_t func,
+                                   void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_paint_glyph_func:
+ * @ffuncs: A font-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is no longer needed
+ *
+ * Sets the implementation function for #hb_font_paint_glyph_func_t.
+ *
+ * Since: 7.0.0
+ */
+HB_EXTERN void
+hb_font_funcs_set_paint_glyph_func (hb_font_funcs_t *ffuncs,
+                                    hb_font_paint_glyph_func_t func,
+                                    void *user_data, hb_destroy_func_t destroy);
+
 /* func dispatch */
 
 HB_EXTERN hb_bool_t
@@ -850,6 +896,17 @@ hb_font_get_glyph_from_name (hb_font_t *font,
                             const char *name, int len, /* -1 means nul-terminated */
                             hb_codepoint_t *glyph);
 
+HB_EXTERN void
+hb_font_draw_glyph (hb_font_t *font,
+                    hb_codepoint_t glyph,
+                    hb_draw_funcs_t *dfuncs, void *draw_data);
+
+HB_EXTERN void
+hb_font_paint_glyph (hb_font_t *font,
+                     hb_codepoint_t glyph,
+                     hb_paint_funcs_t *pfuncs, void *paint_data,
+                     unsigned int palette_index,
+                     hb_color_t foreground);
 
 /* high-level funcs, with fallback */
 
@@ -953,7 +1010,7 @@ hb_font_set_user_data (hb_font_t          *font,
 
 
 HB_EXTERN void *
-hb_font_get_user_data (hb_font_t          *font,
+hb_font_get_user_data (const hb_font_t    *font,
                       hb_user_data_key_t *key);
 
 HB_EXTERN void
@@ -962,6 +1019,12 @@ hb_font_make_immutable (hb_font_t *font);
 HB_EXTERN hb_bool_t
 hb_font_is_immutable (hb_font_t *font);
 
+HB_EXTERN unsigned int
+hb_font_get_serial (hb_font_t *font);
+
+HB_EXTERN void
+hb_font_changed (hb_font_t *font);
+
 HB_EXTERN void
 hb_font_set_parent (hb_font_t *font,
                    hb_font_t *parent);
@@ -1024,6 +1087,16 @@ HB_EXTERN float
 hb_font_get_ptem (hb_font_t *font);
 
 HB_EXTERN void
+hb_font_set_synthetic_bold (hb_font_t *font,
+                           float x_embolden, float y_embolden,
+                           hb_bool_t in_place);
+
+HB_EXTERN void
+hb_font_get_synthetic_bold (hb_font_t *font,
+                           float *x_embolden, float *y_embolden,
+                           hb_bool_t *in_place);
+
+HB_EXTERN void
 hb_font_set_synthetic_slant (hb_font_t *font, float slant);
 
 HB_EXTERN float
@@ -1035,6 +1108,11 @@ hb_font_set_variations (hb_font_t *font,
                        unsigned int variations_length);
 
 HB_EXTERN void
+hb_font_set_variation (hb_font_t *font,
+                      hb_tag_t tag,
+                      float    value);
+
+HB_EXTERN void
 hb_font_set_var_coords_design (hb_font_t *font,
                               const float *coords,
                               unsigned int coords_length);
@@ -1052,15 +1130,23 @@ HB_EXTERN const int *
 hb_font_get_var_coords_normalized (hb_font_t *font,
                                   unsigned int *length);
 
+/**
+ * HB_FONT_NO_VAR_NAMED_INSTANCE:
+ *
+ * Constant signifying that a font does not have any
+ * named-instance index set.  This is the default of
+ * a font.
+ *
+ * Since: 7.0.0
+ */
+#define HB_FONT_NO_VAR_NAMED_INSTANCE 0xFFFFFFFF
+
 HB_EXTERN void
 hb_font_set_var_named_instance (hb_font_t *font,
-                               unsigned instance_index);
+                               unsigned int instance_index);
 
-#ifdef HB_EXPERIMENTAL_API
-HB_EXTERN hb_bool_t
-hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph,
-                   const hb_draw_funcs_t *funcs, void *user_data);
-#endif
+HB_EXTERN unsigned int
+hb_font_get_var_named_instance (hb_font_t *font);
 
 HB_END_DECLS
 
index 0d73589..f503575 100644 (file)
  */
 
 #define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \
-  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) \
-  HB_IF_NOT_DEPRECATED (HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning)) \
-  HB_FONT_FUNC_IMPLEMENT (glyph_extents) \
-  HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \
-  HB_FONT_FUNC_IMPLEMENT (glyph_name) \
-  HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \
+  HB_FONT_FUNC_IMPLEMENT (get_,font_h_extents) \
+  HB_FONT_FUNC_IMPLEMENT (get_,font_v_extents) \
+  HB_FONT_FUNC_IMPLEMENT (get_,nominal_glyph) \
+  HB_FONT_FUNC_IMPLEMENT (get_,nominal_glyphs) \
+  HB_FONT_FUNC_IMPLEMENT (get_,variation_glyph) \
+  HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_advance) \
+  HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_advance) \
+  HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_advances) \
+  HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_advances) \
+  HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_origin) \
+  HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_origin) \
+  HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_kerning) \
+  HB_IF_NOT_DEPRECATED (HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_kerning)) \
+  HB_FONT_FUNC_IMPLEMENT (get_,glyph_extents) \
+  HB_FONT_FUNC_IMPLEMENT (get_,glyph_contour_point) \
+  HB_FONT_FUNC_IMPLEMENT (get_,glyph_name) \
+  HB_FONT_FUNC_IMPLEMENT (get_,glyph_from_name) \
+  HB_FONT_FUNC_IMPLEMENT (,draw_glyph) \
+  HB_FONT_FUNC_IMPLEMENT (,paint_glyph) \
   /* ^--- Add new callbacks here */
 
 struct hb_font_funcs_t
@@ -64,26 +66,26 @@ struct hb_font_funcs_t
   hb_object_header_t header;
 
   struct {
-#define HB_FONT_FUNC_IMPLEMENT(name) void *name;
+#define HB_FONT_FUNC_IMPLEMENT(get_,name) void *name;
     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
-  } user_data;
+  } *user_data;
 
   struct {
-#define HB_FONT_FUNC_IMPLEMENT(name) hb_destroy_func_t name;
+#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_destroy_func_t name;
     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
-  } destroy;
+  } *destroy;
 
   /* Don't access these directly.  Call font->get_*() instead. */
   union get_t {
     struct get_funcs_t {
-#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
+#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_font_##get_##name##_func_t name;
       HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
     } f;
     void (*array[0
-#define HB_FONT_FUNC_IMPLEMENT(name) +1
+#define HB_FONT_FUNC_IMPLEMENT(get_,name) +1
       HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
                ]) ();
@@ -103,14 +105,26 @@ DECLARE_NULL_INSTANCE (hb_font_funcs_t);
 struct hb_font_t
 {
   hb_object_header_t header;
+  unsigned int serial;
+  unsigned int serial_coords;
 
   hb_font_t *parent;
   hb_face_t *face;
 
   int32_t x_scale;
   int32_t y_scale;
+
+  float x_embolden;
+  float y_embolden;
+  bool embolden_in_place;
+  int32_t x_strength; /* x_embolden, in scaled units. */
+  int32_t y_strength; /* y_embolden, in scaled units. */
+
   float slant;
   float slant_xy;
+
+  float x_multf;
+  float y_multf;
   int64_t x_mult;
   int64_t y_mult;
 
@@ -120,6 +134,7 @@ struct hb_font_t
   float ptem;
 
   /* Font variation coordinates. */
+  unsigned int instance_index;
   unsigned int num_coords;
   int *coords;
   float *design_coords;
@@ -136,10 +151,12 @@ struct hb_font_t
   { return HB_DIRECTION_IS_VERTICAL(direction) ? y_mult : x_mult; }
   hb_position_t em_scale_x (int16_t v) { return em_mult (v, x_mult); }
   hb_position_t em_scale_y (int16_t v) { return em_mult (v, y_mult); }
-  hb_position_t em_scalef_x (float v) { return em_scalef (v, x_scale); }
-  hb_position_t em_scalef_y (float v) { return em_scalef (v, 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_scalef_x (float v) { return em_multf (v, x_multf); }
+  hb_position_t em_scalef_y (float v) { return em_multf (v, y_multf); }
+  float em_fscale_x (int16_t v) { return em_fmult (v, x_multf); }
+  float em_fscale_y (int16_t v) { return em_fmult (v, y_multf); }
+  float em_fscalef_x (float v) { return em_fmultf (v, x_multf); }
+  float em_fscalef_y (float v) { return em_fmultf (v, y_multf); }
   hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
   { return em_mult (v, dir_mult (direction)); }
 
@@ -172,6 +189,42 @@ struct hb_font_t
     *y = parent_scale_y_position (*y);
   }
 
+  void scale_glyph_extents (hb_glyph_extents_t *extents)
+  {
+    float x1 = em_fscale_x (extents->x_bearing);
+    float y1 = em_fscale_y (extents->y_bearing);
+    float x2 = em_fscale_x (extents->x_bearing + extents->width);
+    float y2 = em_fscale_y (extents->y_bearing + extents->height);
+
+    /* Apply slant. */
+    if (slant_xy)
+    {
+      x1 += hb_min (y1 * slant_xy, y2 * slant_xy);
+      x2 += hb_max (y1 * slant_xy, y2 * slant_xy);
+    }
+
+    extents->x_bearing = floorf (x1);
+    extents->y_bearing = floorf (y1);
+    extents->width = ceilf (x2) - extents->x_bearing;
+    extents->height = ceilf (y2) - extents->y_bearing;
+
+    if (x_strength || y_strength)
+    {
+      /* Y */
+      int y_shift = y_strength;
+      if (y_scale < 0) y_shift = -y_shift;
+      extents->y_bearing += y_shift;
+      extents->height -= y_shift;
+
+      /* X */
+      int x_shift = x_strength;
+      if (x_scale < 0) x_shift = -x_shift;
+      if (embolden_in_place)
+       extents->x_bearing -= x_shift / 2;
+      extents->width += x_shift;
+    }
+  }
+
 
   /* Public getters */
 
@@ -179,7 +232,7 @@ struct hb_font_t
   HB_INTERNAL bool has_func_set (unsigned int i);
 
   /* has_* ... */
-#define HB_FONT_FUNC_IMPLEMENT(name) \
+#define HB_FONT_FUNC_IMPLEMENT(get_,name) \
   bool \
   has_##name##_func () \
   { \
@@ -199,17 +252,17 @@ struct hb_font_t
 
   hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
   {
-    memset (extents, 0, sizeof (*extents));
+    hb_memset (extents, 0, sizeof (*extents));
     return klass->get.f.font_h_extents (this, user_data,
                                        extents,
-                                       klass->user_data.font_h_extents);
+                                       !klass->user_data ? nullptr : klass->user_data->font_h_extents);
   }
   hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
   {
-    memset (extents, 0, sizeof (*extents));
+    hb_memset (extents, 0, sizeof (*extents));
     return klass->get.f.font_v_extents (this, user_data,
                                        extents,
-                                       klass->user_data.font_v_extents);
+                                       !klass->user_data ? nullptr : klass->user_data->font_v_extents);
   }
 
   bool has_glyph (hb_codepoint_t unicode)
@@ -225,7 +278,7 @@ struct hb_font_t
     *glyph = not_found;
     return klass->get.f.nominal_glyph (this, user_data,
                                       unicode, glyph,
-                                      klass->user_data.nominal_glyph);
+                                      !klass->user_data ? nullptr : klass->user_data->nominal_glyph);
   }
   unsigned int get_nominal_glyphs (unsigned int count,
                                   const hb_codepoint_t *first_unicode,
@@ -237,7 +290,7 @@ struct hb_font_t
                                        count,
                                        first_unicode, unicode_stride,
                                        first_glyph, glyph_stride,
-                                       klass->user_data.nominal_glyphs);
+                                       !klass->user_data ? nullptr : klass->user_data->nominal_glyphs);
   }
 
   hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
@@ -247,21 +300,21 @@ struct hb_font_t
     *glyph = not_found;
     return klass->get.f.variation_glyph (this, user_data,
                                         unicode, variation_selector, glyph,
-                                        klass->user_data.variation_glyph);
+                                        !klass->user_data ? nullptr : klass->user_data->variation_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);
+                                        !klass->user_data ? nullptr : klass->user_data->glyph_h_advance);
   }
 
   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);
+                                        !klass->user_data ? nullptr : klass->user_data->glyph_v_advance);
   }
 
   void get_glyph_h_advances (unsigned int count,
@@ -274,7 +327,7 @@ struct hb_font_t
                                          count,
                                          first_glyph, glyph_stride,
                                          first_advance, advance_stride,
-                                         klass->user_data.glyph_h_advances);
+                                         !klass->user_data ? nullptr : klass->user_data->glyph_h_advances);
   }
 
   void get_glyph_v_advances (unsigned int count,
@@ -287,7 +340,7 @@ struct hb_font_t
                                          count,
                                          first_glyph, glyph_stride,
                                          first_advance, advance_stride,
-                                         klass->user_data.glyph_v_advances);
+                                         !klass->user_data ? nullptr : klass->user_data->glyph_v_advances);
   }
 
   hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
@@ -296,7 +349,7 @@ struct hb_font_t
     *x = *y = 0;
     return klass->get.f.glyph_h_origin (this, user_data,
                                        glyph, x, y,
-                                       klass->user_data.glyph_h_origin);
+                                       !klass->user_data ? nullptr : klass->user_data->glyph_h_origin);
   }
 
   hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
@@ -305,7 +358,7 @@ struct hb_font_t
     *x = *y = 0;
     return klass->get.f.glyph_v_origin (this, user_data,
                                        glyph, x, y,
-                                       klass->user_data.glyph_v_origin);
+                                       !klass->user_data ? nullptr : klass->user_data->glyph_v_origin);
   }
 
   hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph,
@@ -316,7 +369,7 @@ struct hb_font_t
 #else
     return klass->get.f.glyph_h_kerning (this, user_data,
                                         left_glyph, right_glyph,
-                                        klass->user_data.glyph_h_kerning);
+                                        !klass->user_data ? nullptr : klass->user_data->glyph_h_kerning);
 #endif
   }
 
@@ -328,18 +381,18 @@ struct hb_font_t
 #else
     return klass->get.f.glyph_v_kerning (this, user_data,
                                         top_glyph, bottom_glyph,
-                                        klass->user_data.glyph_v_kerning);
+                                        !klass->user_data ? nullptr : klass->user_data->glyph_v_kerning);
 #endif
   }
 
   hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
                               hb_glyph_extents_t *extents)
   {
-    memset (extents, 0, sizeof (*extents));
+    hb_memset (extents, 0, sizeof (*extents));
     return klass->get.f.glyph_extents (this, user_data,
                                       glyph,
                                       extents,
-                                      klass->user_data.glyph_extents);
+                                      !klass->user_data ? nullptr : klass->user_data->glyph_extents);
   }
 
   hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
@@ -349,7 +402,7 @@ struct hb_font_t
     return klass->get.f.glyph_contour_point (this, user_data,
                                             glyph, point_index,
                                             x, y,
-                                            klass->user_data.glyph_contour_point);
+                                            !klass->user_data ? nullptr : klass->user_data->glyph_contour_point);
   }
 
   hb_bool_t get_glyph_name (hb_codepoint_t glyph,
@@ -359,7 +412,7 @@ struct hb_font_t
     return klass->get.f.glyph_name (this, user_data,
                                    glyph,
                                    name, size,
-                                   klass->user_data.glyph_name);
+                                   !klass->user_data ? nullptr : klass->user_data->glyph_name);
   }
 
   hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
@@ -370,9 +423,29 @@ struct hb_font_t
     return klass->get.f.glyph_from_name (this, user_data,
                                         name, len,
                                         glyph,
-                                        klass->user_data.glyph_from_name);
+                                        !klass->user_data ? nullptr : klass->user_data->glyph_from_name);
   }
 
+  void draw_glyph (hb_codepoint_t glyph,
+                  hb_draw_funcs_t *draw_funcs, void *draw_data)
+  {
+    klass->get.f.draw_glyph (this, user_data,
+                            glyph,
+                            draw_funcs, draw_data,
+                            !klass->user_data ? nullptr : klass->user_data->draw_glyph);
+  }
+
+  void paint_glyph (hb_codepoint_t glyph,
+                    hb_paint_funcs_t *paint_funcs, void *paint_data,
+                    unsigned int palette,
+                    hb_color_t foreground)
+  {
+    klass->get.f.paint_glyph (this, user_data,
+                              glyph,
+                              paint_funcs, paint_data,
+                              palette, foreground,
+                              !klass->user_data ? nullptr : klass->user_data->paint_glyph);
+  }
 
   /* A bit higher-level, and with fallback */
 
@@ -432,7 +505,6 @@ struct hb_font_t
   {
     *x = get_glyph_h_advance (glyph) / 2;
 
-    /* TODO cache this somehow?! */
     hb_font_extents_t extents;
     get_h_extents_with_fallback (&extents);
     *y = extents.ascender;
@@ -616,18 +688,31 @@ struct hb_font_t
 
   void mults_changed ()
   {
-    signed upem = face->get_upem ();
-    x_mult = ((int64_t) x_scale << 16) / upem;
-    y_mult = ((int64_t) y_scale << 16) / upem;
+    float upem = face->get_upem ();
+
+    x_multf = x_scale / upem;
+    y_multf = y_scale / upem;
+    bool x_neg = x_scale < 0;
+    x_mult = (x_neg ? -((int64_t) -x_scale << 16) : ((int64_t) x_scale << 16)) / upem;
+    bool y_neg = y_scale < 0;
+    y_mult = (y_neg ? -((int64_t) -y_scale << 16) : ((int64_t) y_scale << 16)) / upem;
+
+    x_strength = fabsf (roundf (x_scale * x_embolden));
+    y_strength = fabsf (roundf (y_scale * y_embolden));
+
     slant_xy = y_scale ? slant * x_scale / y_scale : 0.f;
+
+    data.fini ();
   }
 
   hb_position_t em_mult (int16_t v, int64_t mult)
   { return (hb_position_t) ((v * mult + 32768) >> 16); }
-  hb_position_t em_scalef (float v, int scale)
-  { return (hb_position_t) roundf (v * scale / face->get_upem ()); }
-  float em_fscale (int16_t v, int scale)
-  { return (float) v * scale / face->get_upem (); }
+  hb_position_t em_multf (float v, float mult)
+  { return (hb_position_t) roundf (em_fmultf (v, mult)); }
+  float em_fmultf (float v, float mult)
+  { return v * mult; }
+  float em_fmult (int16_t v, float mult)
+  { return (float) v * mult; }
 };
 DECLARE_NULL_INSTANCE (hb_font_t);
 
diff --git a/src/hb-ft-colr.hh b/src/hb-ft-colr.hh
new file mode 100644 (file)
index 0000000..1afbbbb
--- /dev/null
@@ -0,0 +1,601 @@
+/*
+ * Copyright © 2022  Behdad Esfahbod
+ *
+ *  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_FT_COLR_HH
+#define HB_FT_COLR_HH
+
+#include "hb.hh"
+
+#include "hb-paint-extents.hh"
+
+#include FT_COLOR_H
+
+
+static hb_paint_composite_mode_t
+_hb_ft_paint_composite_mode (FT_Composite_Mode mode)
+{
+  switch (mode)
+  {
+    case FT_COLR_COMPOSITE_CLEAR:          return HB_PAINT_COMPOSITE_MODE_CLEAR;
+    case FT_COLR_COMPOSITE_SRC:            return HB_PAINT_COMPOSITE_MODE_SRC;
+    case FT_COLR_COMPOSITE_DEST:           return HB_PAINT_COMPOSITE_MODE_DEST;
+    case FT_COLR_COMPOSITE_SRC_OVER:       return HB_PAINT_COMPOSITE_MODE_SRC_OVER;
+    case FT_COLR_COMPOSITE_DEST_OVER:      return HB_PAINT_COMPOSITE_MODE_DEST_OVER;
+    case FT_COLR_COMPOSITE_SRC_IN:         return HB_PAINT_COMPOSITE_MODE_SRC_IN;
+    case FT_COLR_COMPOSITE_DEST_IN:        return HB_PAINT_COMPOSITE_MODE_DEST_IN;
+    case FT_COLR_COMPOSITE_SRC_OUT:        return HB_PAINT_COMPOSITE_MODE_SRC_OUT;
+    case FT_COLR_COMPOSITE_DEST_OUT:       return HB_PAINT_COMPOSITE_MODE_DEST_OUT;
+    case FT_COLR_COMPOSITE_SRC_ATOP:       return HB_PAINT_COMPOSITE_MODE_SRC_ATOP;
+    case FT_COLR_COMPOSITE_DEST_ATOP:      return HB_PAINT_COMPOSITE_MODE_DEST_ATOP;
+    case FT_COLR_COMPOSITE_XOR:            return HB_PAINT_COMPOSITE_MODE_XOR;
+    case FT_COLR_COMPOSITE_PLUS:           return HB_PAINT_COMPOSITE_MODE_PLUS;
+    case FT_COLR_COMPOSITE_SCREEN:         return HB_PAINT_COMPOSITE_MODE_SCREEN;
+    case FT_COLR_COMPOSITE_OVERLAY:        return HB_PAINT_COMPOSITE_MODE_OVERLAY;
+    case FT_COLR_COMPOSITE_DARKEN:         return HB_PAINT_COMPOSITE_MODE_DARKEN;
+    case FT_COLR_COMPOSITE_LIGHTEN:        return HB_PAINT_COMPOSITE_MODE_LIGHTEN;
+    case FT_COLR_COMPOSITE_COLOR_DODGE:    return HB_PAINT_COMPOSITE_MODE_COLOR_DODGE;
+    case FT_COLR_COMPOSITE_COLOR_BURN:     return HB_PAINT_COMPOSITE_MODE_COLOR_BURN;
+    case FT_COLR_COMPOSITE_HARD_LIGHT:     return HB_PAINT_COMPOSITE_MODE_HARD_LIGHT;
+    case FT_COLR_COMPOSITE_SOFT_LIGHT:     return HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT;
+    case FT_COLR_COMPOSITE_DIFFERENCE:     return HB_PAINT_COMPOSITE_MODE_DIFFERENCE;
+    case FT_COLR_COMPOSITE_EXCLUSION:      return HB_PAINT_COMPOSITE_MODE_EXCLUSION;
+    case FT_COLR_COMPOSITE_MULTIPLY:       return HB_PAINT_COMPOSITE_MODE_MULTIPLY;
+    case FT_COLR_COMPOSITE_HSL_HUE:        return HB_PAINT_COMPOSITE_MODE_HSL_HUE;
+    case FT_COLR_COMPOSITE_HSL_SATURATION: return HB_PAINT_COMPOSITE_MODE_HSL_SATURATION;
+    case FT_COLR_COMPOSITE_HSL_COLOR:      return HB_PAINT_COMPOSITE_MODE_HSL_COLOR;
+    case FT_COLR_COMPOSITE_HSL_LUMINOSITY: return HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY;
+
+    case FT_COLR_COMPOSITE_MAX:            HB_FALLTHROUGH;
+    default:                               return HB_PAINT_COMPOSITE_MODE_CLEAR;
+  }
+}
+
+typedef struct hb_ft_paint_context_t hb_ft_paint_context_t;
+
+static void
+_hb_ft_paint (hb_ft_paint_context_t *c,
+             FT_OpaquePaint opaque_paint);
+
+struct hb_ft_paint_context_t
+{
+  hb_ft_paint_context_t (const hb_ft_font_t *ft_font,
+                        hb_font_t *font,
+                        hb_paint_funcs_t *paint_funcs, void *paint_data,
+                        FT_Color *palette,
+                        unsigned palette_index,
+                        hb_color_t foreground) :
+    ft_font (ft_font), font(font),
+    funcs (paint_funcs), data (paint_data),
+    palette (palette), palette_index (palette_index), foreground (foreground) {}
+
+  void recurse (FT_OpaquePaint paint)
+  {
+    if (unlikely (depth_left <= 0 || edge_count <= 0)) return;
+    depth_left--;
+    edge_count--;
+    _hb_ft_paint (this, paint);
+    depth_left++;
+  }
+
+  const hb_ft_font_t *ft_font;
+  hb_font_t *font;
+  hb_paint_funcs_t *funcs;
+  void *data;
+  FT_Color *palette;
+  unsigned palette_index;
+  hb_color_t foreground;
+  hb_map_t current_glyphs;
+  hb_map_t current_layers;
+  int depth_left = HB_MAX_NESTING_LEVEL;
+  int edge_count = HB_COLRV1_MAX_EDGE_COUNT;
+};
+
+static unsigned
+_hb_ft_color_line_get_color_stops (hb_color_line_t *color_line,
+                                  void *color_line_data,
+                                  unsigned int start,
+                                  unsigned int *count,
+                                  hb_color_stop_t *color_stops,
+                                  void *user_data)
+{
+  FT_ColorLine *cl = (FT_ColorLine *) color_line_data;
+  hb_ft_paint_context_t *c = (hb_ft_paint_context_t *) user_data;
+
+  if (count)
+  {
+    FT_ColorStop stop;
+    unsigned wrote = 0;
+    FT_ColorStopIterator iter = cl->color_stop_iterator;
+
+    if (start >= cl->color_stop_iterator.num_color_stops)
+    {
+      *count = 0;
+      return cl->color_stop_iterator.num_color_stops;
+    }
+
+    while (cl->color_stop_iterator.current_color_stop < start)
+      FT_Get_Colorline_Stops(c->ft_font->ft_face,
+                            &stop,
+                            &cl->color_stop_iterator);
+
+    while (count && *count &&
+          FT_Get_Colorline_Stops(c->ft_font->ft_face,
+                                 &stop,
+                                 &cl->color_stop_iterator))
+    {
+      // https://github.com/harfbuzz/harfbuzz/issues/4013
+      if (sizeof stop.stop_offset == 2)
+       color_stops->offset = stop.stop_offset / 16384.f;
+      else
+       color_stops->offset = stop.stop_offset / 65536.f;
+
+      color_stops->is_foreground = stop.color.palette_index == 0xFFFF;
+      if (color_stops->is_foreground)
+       color_stops->color = HB_COLOR (hb_color_get_blue (c->foreground),
+                                      hb_color_get_green (c->foreground),
+                                      hb_color_get_red (c->foreground),
+                                      (hb_color_get_alpha (c->foreground) * stop.color.alpha) >> 14);
+      else
+      {
+       hb_color_t color;
+        if (c->funcs->custom_palette_color (c->data, stop.color.palette_index, &color))
+       {
+         color_stops->color = HB_COLOR (hb_color_get_blue (color),
+                                        hb_color_get_green (color),
+                                        hb_color_get_red (color),
+                                        (hb_color_get_alpha (color) * stop.color.alpha) >> 14);
+       }
+       else
+       {
+         FT_Color ft_color = c->palette[stop.color.palette_index];
+         color_stops->color = HB_COLOR (ft_color.blue,
+                                        ft_color.green,
+                                        ft_color.red,
+                                        (ft_color.alpha * stop.color.alpha) >> 14);
+       }
+      }
+
+      color_stops++;
+      wrote++;
+    }
+
+    *count = wrote;
+
+    // reset the iterator for next time
+    cl->color_stop_iterator = iter;
+  }
+
+  return cl->color_stop_iterator.num_color_stops;
+}
+
+static hb_paint_extend_t
+_hb_ft_color_line_get_extend (hb_color_line_t *color_line,
+                             void *color_line_data,
+                             void *user_data)
+{
+  FT_ColorLine *c = (FT_ColorLine *) color_line_data;
+  switch (c->extend)
+  {
+    default:
+    case FT_COLR_PAINT_EXTEND_PAD:     return HB_PAINT_EXTEND_PAD;
+    case FT_COLR_PAINT_EXTEND_REPEAT:  return HB_PAINT_EXTEND_REPEAT;
+    case FT_COLR_PAINT_EXTEND_REFLECT: return HB_PAINT_EXTEND_REFLECT;
+  }
+}
+
+void
+_hb_ft_paint (hb_ft_paint_context_t *c,
+             FT_OpaquePaint opaque_paint)
+{
+  FT_Face ft_face = c->ft_font->ft_face;
+  FT_COLR_Paint paint;
+  if (!FT_Get_Paint (ft_face, opaque_paint, &paint))
+    return;
+
+  switch (paint.format)
+  {
+    case FT_COLR_PAINTFORMAT_COLR_LAYERS:
+    {
+      FT_OpaquePaint other_paint = {0};
+      while (FT_Get_Paint_Layers (ft_face,
+                                 &paint.u.colr_layers.layer_iterator,
+                                 &other_paint))
+      {
+        unsigned i = paint.u.colr_layers.layer_iterator.layer;
+
+       if (unlikely (c->current_layers.has (i)))
+         continue;
+
+       c->current_layers.add (i);
+
+       c->funcs->push_group (c->data);
+       c->recurse (other_paint);
+       c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
+
+       c->current_layers.del (i);
+      }
+    }
+    break;
+    case FT_COLR_PAINTFORMAT_SOLID:
+    {
+      bool is_foreground = paint.u.solid.color.palette_index ==  0xFFFF;
+      hb_color_t color;
+      if (is_foreground)
+       color = HB_COLOR (hb_color_get_blue (c->foreground),
+                         hb_color_get_green (c->foreground),
+                         hb_color_get_red (c->foreground),
+                         (hb_color_get_alpha (c->foreground) * paint.u.solid.color.alpha) >> 14);
+      else
+      {
+       if (c->funcs->custom_palette_color (c->data, paint.u.solid.color.palette_index, &color))
+       {
+         color = HB_COLOR (hb_color_get_blue (color),
+                           hb_color_get_green (color),
+                           hb_color_get_red (color),
+                           (hb_color_get_alpha (color) * paint.u.solid.color.alpha) >> 14);
+       }
+       else
+       {
+         FT_Color ft_color = c->palette[paint.u.solid.color.palette_index];
+         color = HB_COLOR (ft_color.blue,
+                           ft_color.green,
+                           ft_color.red,
+                           (ft_color.alpha * paint.u.solid.color.alpha) >> 14);
+       }
+      }
+      c->funcs->color (c->data, is_foreground, color);
+    }
+    break;
+    case FT_COLR_PAINTFORMAT_LINEAR_GRADIENT:
+    {
+      hb_color_line_t cl = {
+       &paint.u.linear_gradient.colorline,
+       _hb_ft_color_line_get_color_stops, c,
+       _hb_ft_color_line_get_extend, nullptr
+      };
+
+      c->funcs->linear_gradient (c->data, &cl,
+                                paint.u.linear_gradient.p0.x / 65536.f,
+                                paint.u.linear_gradient.p0.y / 65536.f,
+                                paint.u.linear_gradient.p1.x / 65536.f,
+                                paint.u.linear_gradient.p1.y / 65536.f,
+                                paint.u.linear_gradient.p2.x / 65536.f,
+                                paint.u.linear_gradient.p2.y / 65536.f);
+    }
+    break;
+    case FT_COLR_PAINTFORMAT_RADIAL_GRADIENT:
+    {
+      hb_color_line_t cl = {
+       &paint.u.linear_gradient.colorline,
+       _hb_ft_color_line_get_color_stops, c,
+       _hb_ft_color_line_get_extend, nullptr
+      };
+
+      c->funcs->radial_gradient (c->data, &cl,
+                                paint.u.radial_gradient.c0.x / 65536.f,
+                                paint.u.radial_gradient.c0.y / 65536.f,
+                                paint.u.radial_gradient.r0 / 65536.f,
+                                paint.u.radial_gradient.c1.x / 65536.f,
+                                paint.u.radial_gradient.c1.y / 65536.f,
+                                paint.u.radial_gradient.r1 / 65536.f);
+    }
+    break;
+    case FT_COLR_PAINTFORMAT_SWEEP_GRADIENT:
+    {
+      hb_color_line_t cl = {
+       &paint.u.linear_gradient.colorline,
+       _hb_ft_color_line_get_color_stops, c,
+       _hb_ft_color_line_get_extend, nullptr
+      };
+
+      c->funcs->sweep_gradient (c->data, &cl,
+                               paint.u.sweep_gradient.center.x / 65536.f,
+                               paint.u.sweep_gradient.center.y / 65536.f,
+                               (paint.u.sweep_gradient.start_angle / 65536.f + 1) * HB_PI,
+                               (paint.u.sweep_gradient.end_angle / 65536.f + 1) * HB_PI);
+    }
+    break;
+    case FT_COLR_PAINTFORMAT_GLYPH:
+    {
+      c->funcs->push_inverse_root_transform (c->data, c->font);
+      c->ft_font->lock.unlock ();
+      c->funcs->push_clip_glyph (c->data, paint.u.glyph.glyphID, c->font);
+      c->ft_font->lock.lock ();
+      c->funcs->push_root_transform (c->data, c->font);
+      c->recurse (paint.u.glyph.paint);
+      c->funcs->pop_transform (c->data);
+      c->funcs->pop_clip (c->data);
+      c->funcs->pop_transform (c->data);
+    }
+    break;
+    case FT_COLR_PAINTFORMAT_COLR_GLYPH:
+    {
+      hb_codepoint_t gid = paint.u.colr_glyph.glyphID;
+
+      if (unlikely (c->current_glyphs.has (gid)))
+       return;
+
+      c->current_glyphs.add (gid);
+
+      c->funcs->push_inverse_root_transform (c->data, c->font);
+      c->ft_font->lock.unlock ();
+      if (c->funcs->color_glyph (c->data, gid, c->font))
+      {
+       c->ft_font->lock.lock ();
+       c->funcs->pop_transform (c->data);
+       c->current_glyphs.del (gid);
+       return;
+      }
+      c->ft_font->lock.lock ();
+      c->funcs->pop_transform (c->data);
+
+      FT_OpaquePaint other_paint = {0};
+      if (FT_Get_Color_Glyph_Paint (ft_face, gid,
+                                   FT_COLOR_NO_ROOT_TRANSFORM,
+                                   &other_paint))
+      {
+        bool has_clip_box;
+        FT_ClipBox clip_box;
+        has_clip_box = FT_Get_Color_Glyph_ClipBox (ft_face, paint.u.colr_glyph.glyphID, &clip_box);
+
+        if (has_clip_box)
+       {
+         /* The FreeType ClipBox is in scaled coordinates, whereas we need
+          * unscaled clipbox here. Oh well...
+          */
+
+         float upem = c->font->face->get_upem ();
+         float xscale = upem / (c->font->x_scale ? c->font->x_scale : upem);
+         float yscale = upem / (c->font->y_scale ? c->font->y_scale : upem);
+
+          c->funcs->push_clip_rectangle (c->data,
+                                        clip_box.bottom_left.x * xscale,
+                                        clip_box.bottom_left.y * yscale,
+                                        clip_box.top_right.x * xscale,
+                                        clip_box.top_right.y * yscale);
+       }
+
+       c->recurse (other_paint);
+
+        if (has_clip_box)
+          c->funcs->pop_clip (c->data);
+
+       c->current_glyphs.del (gid);
+      }
+    }
+    break;
+    case FT_COLR_PAINTFORMAT_TRANSFORM:
+    {
+      c->funcs->push_transform (c->data,
+                               paint.u.transform.affine.xx / 65536.f,
+                               paint.u.transform.affine.yx / 65536.f,
+                               paint.u.transform.affine.xy / 65536.f,
+                               paint.u.transform.affine.yy / 65536.f,
+                               paint.u.transform.affine.dx / 65536.f,
+                               paint.u.transform.affine.dy / 65536.f);
+      c->recurse (paint.u.transform.paint);
+      c->funcs->pop_transform (c->data);
+    }
+    break;
+    case FT_COLR_PAINTFORMAT_TRANSLATE:
+    {
+      float dx = paint.u.translate.dx / 65536.f;
+      float dy = paint.u.translate.dy / 65536.f;
+
+      bool p1 = c->funcs->push_translate (c->data, dx, dy);
+      c->recurse (paint.u.translate.paint);
+      if (p1) c->funcs->pop_transform (c->data);
+    }
+    break;
+    case FT_COLR_PAINTFORMAT_SCALE:
+    {
+      float dx = paint.u.scale.center_x / 65536.f;
+      float dy = paint.u.scale.center_y / 65536.f;
+      float sx = paint.u.scale.scale_x / 65536.f;
+      float sy = paint.u.scale.scale_y / 65536.f;
+
+      bool p1 = c->funcs->push_translate (c->data, +dx, +dy);
+      bool p2 = c->funcs->push_scale (c->data, sx, sy);
+      bool p3 = c->funcs->push_translate (c->data, -dx, -dy);
+      c->recurse (paint.u.scale.paint);
+      if (p3) c->funcs->pop_transform (c->data);
+      if (p2) c->funcs->pop_transform (c->data);
+      if (p1) c->funcs->pop_transform (c->data);
+    }
+    break;
+    case FT_COLR_PAINTFORMAT_ROTATE:
+    {
+      float dx = paint.u.rotate.center_x / 65536.f;
+      float dy = paint.u.rotate.center_y / 65536.f;
+      float a = paint.u.rotate.angle / 65536.f;
+
+      bool p1 = c->funcs->push_translate (c->data, +dx, +dy);
+      bool p2 = c->funcs->push_rotate (c->data, a);
+      bool p3 = c->funcs->push_translate (c->data, -dx, -dy);
+      c->recurse (paint.u.rotate.paint);
+      if (p3) c->funcs->pop_transform (c->data);
+      if (p2) c->funcs->pop_transform (c->data);
+      if (p1) c->funcs->pop_transform (c->data);
+    }
+    break;
+    case FT_COLR_PAINTFORMAT_SKEW:
+    {
+      float dx = paint.u.skew.center_x / 65536.f;
+      float dy = paint.u.skew.center_y / 65536.f;
+      float sx = paint.u.skew.x_skew_angle / 65536.f;
+      float sy = paint.u.skew.y_skew_angle / 65536.f;
+
+      bool p1 = c->funcs->push_translate (c->data, +dx, +dy);
+      bool p2 = c->funcs->push_skew (c->data, sx, sy);
+      bool p3 = c->funcs->push_translate (c->data, -dx, -dy);
+      c->recurse (paint.u.skew.paint);
+      if (p3) c->funcs->pop_transform (c->data);
+      if (p2) c->funcs->pop_transform (c->data);
+      if (p1) c->funcs->pop_transform (c->data);
+    }
+    break;
+    case FT_COLR_PAINTFORMAT_COMPOSITE:
+    {
+      c->recurse (paint.u.composite.backdrop_paint);
+      c->funcs->push_group (c->data);
+      c->recurse (paint.u.composite.source_paint);
+      c->funcs->pop_group (c->data, _hb_ft_paint_composite_mode (paint.u.composite.composite_mode));
+    }
+    break;
+
+    case FT_COLR_PAINT_FORMAT_MAX: break;
+    default: HB_FALLTHROUGH;
+    case FT_COLR_PAINTFORMAT_UNSUPPORTED: break;
+  }
+}
+
+
+static bool
+hb_ft_paint_glyph_colr (hb_font_t *font,
+                       void *font_data,
+                       hb_codepoint_t gid,
+                       hb_paint_funcs_t *paint_funcs, void *paint_data,
+                       unsigned int palette_index,
+                       hb_color_t foreground,
+                       void *user_data)
+{
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  FT_Face ft_face = ft_font->ft_face;
+
+  /* Face is locked. */
+
+  FT_Error error;
+  FT_Color*         palette;
+  FT_LayerIterator  iterator;
+
+  FT_Bool  have_layers;
+  FT_UInt  layer_glyph_index;
+  FT_UInt  layer_color_index;
+
+  error = FT_Palette_Select(ft_face, palette_index, &palette);
+  if (error)
+    palette = NULL;
+
+  /* COLRv1 */
+  FT_OpaquePaint paint = {0};
+  if (FT_Get_Color_Glyph_Paint (ft_face, gid,
+                               FT_COLOR_NO_ROOT_TRANSFORM,
+                               &paint))
+  {
+    hb_ft_paint_context_t c (ft_font, font,
+                            paint_funcs, paint_data,
+                            palette, palette_index, foreground);
+    c.current_glyphs.add (gid);
+
+    bool is_bounded = true;
+    FT_ClipBox clip_box;
+    if (FT_Get_Color_Glyph_ClipBox (ft_face, gid, &clip_box))
+    {
+      c.funcs->push_clip_rectangle (c.data,
+                                   clip_box.bottom_left.x +
+                                     roundf (hb_min (font->slant_xy * clip_box.bottom_left.y,
+                                                     font->slant_xy * clip_box.top_left.y)),
+                                   clip_box.bottom_left.y,
+                                   clip_box.top_right.x +
+                                     roundf (hb_max (font->slant_xy * clip_box.bottom_right.y,
+                                                     font->slant_xy * clip_box.top_right.y)),
+                                   clip_box.top_right.y);
+    }
+    else
+    {
+
+      auto *extents_funcs = hb_paint_extents_get_funcs ();
+      hb_paint_extents_context_t extents_data;
+      hb_ft_paint_context_t ce (ft_font, font,
+                               extents_funcs, &extents_data,
+                               palette, palette_index, foreground);
+      ce.current_glyphs.add (gid);
+      ce.funcs->push_root_transform (ce.data, font);
+      ce.recurse (paint);
+      ce.funcs->pop_transform (ce.data);
+      hb_extents_t extents = extents_data.get_extents ();
+      is_bounded = extents_data.is_bounded ();
+
+      c.funcs->push_clip_rectangle (c.data,
+                                   extents.xmin,
+                                   extents.ymin,
+                                   extents.xmax,
+                                   extents.ymax);
+    }
+
+    c.funcs->push_root_transform (c.data, font);
+
+    if (is_bounded)
+      c.recurse (paint);
+
+    c.funcs->pop_transform (c.data);
+    c.funcs->pop_clip (c.data);
+
+    return true;
+  }
+
+  /* COLRv0 */
+  iterator.p  = NULL;
+  have_layers = FT_Get_Color_Glyph_Layer(ft_face,
+                                        gid,
+                                        &layer_glyph_index,
+                                        &layer_color_index,
+                                        &iterator);
+
+  if (palette && have_layers)
+  {
+    do
+    {
+      hb_bool_t is_foreground = true;
+      hb_color_t color = foreground;
+
+      if ( layer_color_index != 0xFFFF )
+      {
+       FT_Color layer_color = palette[layer_color_index];
+       color = HB_COLOR (layer_color.blue,
+                         layer_color.green,
+                         layer_color.red,
+                         layer_color.alpha);
+       is_foreground = false;
+      }
+
+      ft_font->lock.unlock ();
+      paint_funcs->push_clip_glyph (paint_data, layer_glyph_index, font);
+      ft_font->lock.lock ();
+      paint_funcs->color (paint_data, is_foreground, color);
+      paint_funcs->pop_clip (paint_data);
+
+    } while (FT_Get_Color_Glyph_Layer(ft_face,
+                                     gid,
+                                     &layer_glyph_index,
+                                     &layer_color_index,
+                                     &iterator));
+    return true;
+  }
+
+  return false;
+}
+
+
+#endif /* HB_FT_COLR_HH */
index 67691e3..6ca3f85 100644 (file)
 
 #include "hb-ft.h"
 
+#include "hb-cache.hh"
+#include "hb-draw.hh"
 #include "hb-font.hh"
 #include "hb-machinery.hh"
-#include "hb-cache.hh"
+#include "hb-ot-os2-table.hh"
+#include "hb-ot-shaper-arabic-pua.hh"
+#include "hb-paint.hh"
 
 #include FT_ADVANCES_H
 #include FT_MULTIPLE_MASTERS_H
+#include FT_OUTLINE_H
 #include FT_TRUETYPE_TABLES_H
+#include FT_SYNTHESIS_H
+#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300
+#include FT_COLOR_H
+#endif
 
 
 /**
  */
 
 
+using hb_ft_advance_cache_t = hb_cache_t<16, 24, 8, false>;
+
 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. */
+  bool transform; /* Whether to apply FT_Face's transform. */
 
-  mutable int cached_x_scale;
-  mutable hb_advance_cache_t advance_cache;
+  mutable hb_mutex_t lock; /* Protects members below. */
+  FT_Face ft_face;
+  mutable unsigned cached_serial;
+  mutable hb_ft_advance_cache_t advance_cache;
 };
 
 static hb_ft_font_t *
@@ -101,8 +113,8 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
 
   ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
 
-  ft_font->cached_x_scale = 0;
-  ft_font->advance_cache.init ();
+  ft_font->cached_serial = (unsigned) -1;
+  new (&ft_font->advance_cache) hb_ft_advance_cache_t;
 
   return ft_font;
 }
@@ -118,8 +130,6 @@ _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);
 
@@ -128,6 +138,85 @@ _hb_ft_font_destroy (void *data)
   hb_free (ft_font);
 }
 
+
+/* hb_font changed, update FT_Face. */
+static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face)
+{
+  hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
+
+  float x_mult = 1.f, y_mult = 1.f;
+
+  if (font->x_scale < 0) x_mult = -x_mult;
+  if (font->y_scale < 0) y_mult = -y_mult;
+
+  if (FT_Set_Char_Size (ft_face,
+                       abs (font->x_scale), abs (font->y_scale),
+                       0, 0
+#if 0
+                   font->x_ppem * 72 * 64 / font->x_scale,
+                   font->y_ppem * 72 * 64 / font->y_scale
+#endif
+     ) && ft_face->num_fixed_sizes)
+  {
+#ifdef HAVE_FT_GET_TRANSFORM
+    /* Bitmap font, eg. bitmap color emoji. */
+    /* Pick largest size? */
+    int x_scale  = ft_face->available_sizes[ft_face->num_fixed_sizes - 1].x_ppem;
+    int y_scale = ft_face->available_sizes[ft_face->num_fixed_sizes - 1].y_ppem;
+    FT_Set_Char_Size (ft_face,
+                     x_scale, y_scale,
+                     0, 0);
+
+    /* This contains the sign that was previously in x_mult/y_mult. */
+    x_mult = (float) font->x_scale / x_scale;
+    y_mult = (float) font->y_scale / y_scale;
+#endif
+  }
+  else
+  { /* Shrug */ }
+
+
+  if (x_mult != 1.f || y_mult != 1.f)
+  {
+    FT_Matrix matrix = { (int) roundf (x_mult * (1<<16)), 0,
+                         0, (int) roundf (y_mult * (1<<16))};
+    FT_Set_Transform (ft_face, &matrix, nullptr);
+    ft_font->transform = true;
+  }
+
+#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
+  unsigned int num_coords;
+  const float *coords = hb_font_get_var_coords_design (font, &num_coords);
+  if (num_coords)
+  {
+    FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (num_coords, sizeof (FT_Fixed));
+    if (ft_coords)
+    {
+      for (unsigned int i = 0; i < num_coords; i++)
+         ft_coords[i] = coords[i] * 65536.f;
+      FT_Set_Var_Design_Coordinates (ft_face, num_coords, ft_coords);
+      hb_free (ft_coords);
+    }
+  }
+#endif
+}
+
+/* Check if hb_font changed, update FT_Face. */
+static inline bool
+_hb_ft_hb_font_check_changed (hb_font_t *font,
+                             const hb_ft_font_t *ft_font)
+{
+  if (font->serial != ft_font->cached_serial)
+  {
+    _hb_ft_hb_font_changed (font, ft_font->ft_face);
+    ft_font->advance_cache.clear ();
+    ft_font->cached_serial = font->serial;
+    return true;
+  }
+  return false;
+}
+
+
 /**
  * hb_ft_font_set_load_flags:
  * @font: #hb_font_t to work upon
@@ -138,6 +227,9 @@ _hb_ft_font_destroy (void *data)
  * For more information, see 
  * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx
  *
+ * This function works with #hb_font_t objects created by
+ * hb_ft_font_create() or hb_ft_font_create_referenced().
+ *
  * Since: 1.0.5
  **/
 void
@@ -163,7 +255,10 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
  * For more information, see 
  * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx
  *
- * Return value: FT_Load_Glyph flags found
+ * This function works with #hb_font_t objects created by
+ * hb_ft_font_create() or hb_ft_font_create_referenced().
+ *
+ * Return value: FT_Load_Glyph flags found, or 0
  *
  * Since: 1.0.5
  **/
@@ -179,13 +274,16 @@ hb_ft_font_get_load_flags (hb_font_t *font)
 }
 
 /**
- * hb_ft_font_get_face:
+ * hb_ft_font_get_face: (skip)
  * @font: #hb_font_t to work upon
  *
  * Fetches the FT_Face associated with the specified #hb_font_t
  * font object.
  *
- * Return value: (nullable): the FT_Face found or %NULL
+ * This function works with #hb_font_t objects created by
+ * hb_ft_font_create() or hb_ft_font_create_referenced().
+ *
+ * Return value: (nullable): the FT_Face found or `NULL`
  *
  * Since: 0.9.2
  **/
@@ -201,13 +299,18 @@ hb_ft_font_get_face (hb_font_t *font)
 }
 
 /**
- * hb_ft_font_lock_face:
+ * hb_ft_font_lock_face: (skip)
  * @font: #hb_font_t to work upon
  *
- * Gets the FT_Face associated with @font, This face will be kept around until
- * you call hb_ft_font_unlock_face().
+ * Gets the FT_Face associated with @font.
+ *
+ * This face will be kept around and access to the FT_Face object
+ * from other HarfBuzz API wil be blocked until you call hb_ft_font_unlock_face().
+ *
+ * This function works with #hb_font_t objects created by
+ * hb_ft_font_create() or hb_ft_font_create_referenced().
  *
- * Return value: (nullable): the FT_Face associated with @font or %NULL
+ * Return value: (nullable) (transfer none): the FT_Face associated with @font or `NULL`
  * Since: 2.6.5
  **/
 FT_Face
@@ -224,7 +327,7 @@ hb_ft_font_lock_face (hb_font_t *font)
 }
 
 /**
- * hb_ft_font_unlock_face:
+ * hb_ft_font_unlock_face: (skip)
  * @font: #hb_font_t to work upon
  *
  * Releases an FT_Face previously obtained with hb_ft_font_lock_face().
@@ -244,7 +347,7 @@ hb_ft_font_unlock_face (hb_font_t *font)
 
 
 static hb_bool_t
-hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED,
+hb_ft_get_nominal_glyph (hb_font_t *font,
                         void *font_data,
                         hb_codepoint_t unicode,
                         hb_codepoint_t *glyph,
@@ -256,14 +359,29 @@ hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED,
 
   if (unlikely (!g))
   {
-    if (unlikely (ft_font->symbol) && unicode <= 0x00FFu)
+    if (unlikely (ft_font->symbol))
     {
-      /* For symbol-encoded OpenType fonts, we duplicate the
-       * U+F000..F0FF range at U+0000..U+00FF.  That's what
-       * Windows seems to do, and that's hinted about at:
-       * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
-       * under "Non-Standard (Symbol) Fonts". */
-      g = FT_Get_Char_Index (ft_font->ft_face, 0xF000u + unicode);
+      switch ((unsigned) font->face->table.OS2->get_font_page ()) {
+      case OT::OS2::font_page_t::FONT_PAGE_NONE:
+       if (unicode <= 0x00FFu)
+         /* For symbol-encoded OpenType fonts, we duplicate the
+          * U+F000..F0FF range at U+0000..U+00FF.  That's what
+          * Windows seems to do, and that's hinted about at:
+          * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
+          * under "Non-Standard (Symbol) Fonts". */
+         g = FT_Get_Char_Index (ft_font->ft_face, 0xF000u + unicode);
+       break;
+#ifndef HB_NO_OT_SHAPER_ARABIC_FALLBACK
+      case OT::OS2::font_page_t::FONT_PAGE_SIMP_ARABIC:
+       g = FT_Get_Char_Index (ft_font->ft_face, _hb_arabic_pua_simp_map (unicode));
+       break;
+      case OT::OS2::font_page_t::FONT_PAGE_TRAD_ARABIC:
+       g = FT_Get_Char_Index (ft_font->ft_face, _hb_arabic_pua_trad_map (unicode));
+       break;
+#endif
+      default:
+       break;
+      }
       if (!g)
        return false;
     }
@@ -330,15 +448,23 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
                            void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  hb_position_t *orig_first_advance = first_advance;
   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 (font->x_scale != ft_font->cached_x_scale)
+  float x_mult;
+#ifdef HAVE_FT_GET_TRANSFORM
+  if (ft_font->transform)
   {
-    ft_font->advance_cache.clear ();
-    ft_font->cached_x_scale = font->x_scale;
+    FT_Matrix matrix;
+    FT_Get_Transform (ft_face, &matrix, nullptr);
+    x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f;
+    x_mult *= font->x_scale < 0 ? -1 : +1;
+  }
+  else
+#endif
+  {
+    x_mult = font->x_scale < 0 ? -1 : +1;
   }
 
   for (unsigned int i = 0; i < count; i++)
@@ -352,13 +478,29 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
     else
     {
       FT_Get_Advance (ft_face, glyph, load_flags, &v);
+      /* Work around bug that FreeType seems to return negative advance
+       * for variable-set fonts if x_scale is negative! */
+      v = abs (v);
+      v = (int) (v * x_mult + (1<<9)) >> 10;
       ft_font->advance_cache.set (glyph, v);
     }
 
-    *first_advance = (v * mult + (1<<9)) >> 10;
+    *first_advance = v;
     first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
     first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
+
+  if (font->x_strength && !font->embolden_in_place)
+  {
+    /* Emboldening. */
+    hb_position_t x_strength = font->x_scale >= 0 ? font->x_strength : -font->x_strength;
+    first_advance = orig_first_advance;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      *first_advance += *first_advance ? x_strength : 0;
+      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
+    }
+  }
 }
 
 #ifndef HB_NO_VERTICAL
@@ -371,16 +513,31 @@ hb_ft_get_glyph_v_advance (hb_font_t *font,
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
   hb_lock_t lock (ft_font->lock);
   FT_Fixed v;
+  float y_mult;
+#ifdef HAVE_FT_GET_TRANSFORM
+  if (ft_font->transform)
+  {
+    FT_Matrix matrix;
+    FT_Get_Transform (ft_font->ft_face, &matrix, nullptr);
+    y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
+    y_mult *= font->y_scale < 0 ? -1 : +1;
+  }
+  else
+#endif
+  {
+    y_mult = font->y_scale < 0 ? -1 : +1;
+  }
 
   if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
     return 0;
 
-  if (font->y_scale < 0)
-    v = -v;
+  v = (int) (y_mult * v);
 
   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
    * have a Y growing upward.  Hence the extra negation. */
-  return (-v + (1<<9)) >> 10;
+
+  hb_position_t y_strength = font->y_scale >= 0 ? font->y_strength : -font->y_strength;
+  return ((-v + (1<<9)) >> 10) + (font->embolden_in_place ? 0 : y_strength);
 }
 #endif
 
@@ -396,6 +553,23 @@ hb_ft_get_glyph_v_origin (hb_font_t *font,
   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;
+  float x_mult, y_mult;
+#ifdef HAVE_FT_GET_TRANSFORM
+  if (ft_font->transform)
+  {
+    FT_Matrix matrix;
+    FT_Get_Transform (ft_face, &matrix, nullptr);
+    x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f;
+    x_mult *= font->x_scale < 0 ? -1 : +1;
+    y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
+    y_mult *= font->y_scale < 0 ? -1 : +1;
+  }
+  else
+#endif
+  {
+    x_mult = font->x_scale < 0 ? -1 : +1;
+    y_mult = font->y_scale < 0 ? -1 : +1;
+  }
 
   if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
     return false;
@@ -405,10 +579,8 @@ hb_ft_get_glyph_v_origin (hb_font_t *font,
   *x = ft_face->glyph->metrics.horiBearingX -   ft_face->glyph->metrics.vertBearingX;
   *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY);
 
-  if (font->x_scale < 0)
-    *x = -*x;
-  if (font->y_scale < 0)
-    *y = -*y;
+  *x = (hb_position_t) (x_mult * *x);
+  *y = (hb_position_t) (y_mult * *y);
 
   return true;
 }
@@ -423,6 +595,7 @@ hb_ft_get_glyph_h_kerning (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_Vector kerningv;
 
   FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
@@ -443,24 +616,63 @@ hb_ft_get_glyph_extents (hb_font_t *font,
   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;
+  float x_mult, y_mult;
+  float slant_xy = font->slant_xy;
+#ifdef HAVE_FT_GET_TRANSFORM
+  if (ft_font->transform)
+  {
+    FT_Matrix matrix;
+    FT_Get_Transform (ft_face, &matrix, nullptr);
+    x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f;
+    x_mult *= font->x_scale < 0 ? -1 : +1;
+    y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
+    y_mult *= font->y_scale < 0 ? -1 : +1;
+  }
+  else
+#endif
+  {
+    x_mult = font->x_scale < 0 ? -1 : +1;
+    y_mult = font->y_scale < 0 ? -1 : +1;
+  }
 
   if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
     return false;
 
-  extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
-  extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
-  extents->width = ft_face->glyph->metrics.width;
-  extents->height = -ft_face->glyph->metrics.height;
-  if (font->x_scale < 0)
+  /* Copied from hb_font_t::scale_glyph_extents. */
+
+  float x1 = x_mult * ft_face->glyph->metrics.horiBearingX;
+  float y1 = y_mult * ft_face->glyph->metrics.horiBearingY;
+  float x2 = x1 + x_mult *  ft_face->glyph->metrics.width;
+  float y2 = y1 + y_mult * -ft_face->glyph->metrics.height;
+
+  /* Apply slant. */
+  if (slant_xy)
   {
-    extents->x_bearing = -extents->x_bearing;
-    extents->width = -extents->width;
+    x1 += hb_min (y1 * slant_xy, y2 * slant_xy);
+    x2 += hb_max (y1 * slant_xy, y2 * slant_xy);
   }
-  if (font->y_scale < 0)
+
+  extents->x_bearing = floorf (x1);
+  extents->y_bearing = floorf (y1);
+  extents->width = ceilf (x2) - extents->x_bearing;
+  extents->height = ceilf (y2) - extents->y_bearing;
+
+  if (font->x_strength || font->y_strength)
   {
-    extents->y_bearing = -extents->y_bearing;
-    extents->height = -extents->height;
+    /* Y */
+    int y_shift = font->y_strength;
+    if (font->y_scale < 0) y_shift = -y_shift;
+    extents->y_bearing += y_shift;
+    extents->height -= y_shift;
+
+    /* X */
+    int x_shift = font->x_strength;
+    if (font->x_scale < 0) x_shift = -x_shift;
+    if (font->embolden_in_place)
+      extents->x_bearing -= x_shift / 2;
+    extents->width += x_shift;
   }
+
   return true;
 }
 
@@ -553,18 +765,239 @@ hb_ft_get_font_h_extents (hb_font_t *font 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_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)
+  float y_mult;
+#ifdef HAVE_FT_GET_TRANSFORM
+  if (ft_font->transform)
+  {
+    FT_Matrix matrix;
+    FT_Get_Transform (ft_face, &matrix, nullptr);
+    y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
+    y_mult *= font->y_scale < 0 ? -1 : +1;
+  }
+  else
+#endif
   {
-    metrics->ascender = -metrics->ascender;
-    metrics->descender = -metrics->descender;
-    metrics->line_gap = -metrics->line_gap;
+    y_mult = font->y_scale < 0 ? -1 : +1;
   }
+
+  if (ft_face->units_per_EM != 0)
+  {
+    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);
+  }
+  else
+  {
+    /* Bitmap-only font, eg. color bitmap font. */
+    metrics->ascender = ft_face->size->metrics.ascender;
+    metrics->descender = ft_face->size->metrics.descender;
+    metrics->line_gap = ft_face->size->metrics.height - (metrics->ascender - metrics->descender);
+  }
+
+  metrics->ascender  = (hb_position_t) (y_mult * (metrics->ascender + font->y_strength));
+  metrics->descender = (hb_position_t) (y_mult * metrics->descender);
+  metrics->line_gap  = (hb_position_t) (y_mult * metrics->line_gap);
+
   return true;
 }
 
+#ifndef HB_NO_DRAW
+
+static int
+_hb_ft_move_to (const FT_Vector *to,
+               void *arg)
+{
+  hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
+  drawing->move_to (to->x, to->y);
+  return FT_Err_Ok;
+}
+
+static int
+_hb_ft_line_to (const FT_Vector *to,
+               void *arg)
+{
+  hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
+  drawing->line_to (to->x, to->y);
+  return FT_Err_Ok;
+}
+
+static int
+_hb_ft_conic_to (const FT_Vector *control,
+                const FT_Vector *to,
+                void *arg)
+{
+  hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
+  drawing->quadratic_to (control->x, control->y,
+                        to->x, to->y);
+  return FT_Err_Ok;
+}
+
+static int
+_hb_ft_cubic_to (const FT_Vector *control1,
+                const FT_Vector *control2,
+                const FT_Vector *to,
+                void *arg)
+{
+  hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
+  drawing->cubic_to (control1->x, control1->y,
+                    control2->x, control2->y,
+                    to->x, to->y);
+  return FT_Err_Ok;
+}
+
+static void
+hb_ft_draw_glyph (hb_font_t *font,
+                 void *font_data,
+                 hb_codepoint_t glyph,
+                 hb_draw_funcs_t *draw_funcs, void *draw_data,
+                 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_LOAD_NO_BITMAP | ft_font->load_flags)))
+    return;
+
+  if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
+    return;
+
+  const FT_Outline_Funcs outline_funcs = {
+    _hb_ft_move_to,
+    _hb_ft_line_to,
+    _hb_ft_conic_to,
+    _hb_ft_cubic_to,
+    0, /* shift */
+    0, /* delta */
+  };
+
+  hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy);
+
+  /* Embolden */
+  if (font->x_strength || font->y_strength)
+  {
+    FT_Outline_EmboldenXY (&ft_face->glyph->outline, font->x_strength, font->y_strength);
+
+    int x_shift = 0;
+    int y_shift = 0;
+    if (font->embolden_in_place)
+    {
+      /* Undo the FreeType shift. */
+      x_shift = -font->x_strength / 2;
+      y_shift = 0;
+      if (font->y_scale < 0) y_shift = -font->y_strength;
+    }
+    else
+    {
+      /* FreeType applied things in the wrong direction for negative scale; fix up. */
+      if (font->x_scale < 0) x_shift = -font->x_strength;
+      if (font->y_scale < 0) y_shift = -font->y_strength;
+    }
+    if (x_shift || y_shift)
+    {
+      auto &outline = ft_face->glyph->outline;
+      for (auto &point : hb_iter (outline.points, outline.contours[outline.n_contours - 1] + 1))
+      {
+       point.x += x_shift;
+       point.y += y_shift;
+      }
+    }
+  }
+
+
+  FT_Outline_Decompose (&ft_face->glyph->outline,
+                       &outline_funcs,
+                       &draw_session);
+}
+#endif
+
+#ifndef HB_NO_PAINT
+#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300
+
+#include "hb-ft-colr.hh"
+
+static void
+hb_ft_paint_glyph (hb_font_t *font,
+                   void *font_data,
+                   hb_codepoint_t gid,
+                   hb_paint_funcs_t *paint_funcs, void *paint_data,
+                   unsigned int palette_index,
+                   hb_color_t foreground,
+                   void *user_data)
+{
+  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;
+
+  /* We release the lock before calling into glyph callbacks, such that
+   * eg. draw API can call back into the face.*/
+
+  if (unlikely (FT_Load_Glyph (ft_face, gid,
+                              ft_font->load_flags | FT_LOAD_COLOR)))
+    return;
+
+  if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
+  {
+    if (hb_ft_paint_glyph_colr (font, font_data, gid,
+                               paint_funcs, paint_data,
+                               palette_index, foreground,
+                               user_data))
+      return;
+
+    /* Simple outline. */
+    ft_font->lock.unlock ();
+    paint_funcs->push_clip_glyph (paint_data, gid, font);
+    ft_font->lock.lock ();
+    paint_funcs->color (paint_data, true, foreground);
+    paint_funcs->pop_clip (paint_data);
+
+    return;
+  }
+
+  auto *glyph = ft_face->glyph;
+  if (glyph->format == FT_GLYPH_FORMAT_BITMAP)
+  {
+    auto &bitmap = glyph->bitmap;
+    if (bitmap.pixel_mode == FT_PIXEL_MODE_BGRA)
+    {
+      if (bitmap.pitch != (signed) bitmap.width * 4)
+        return;
+
+      ft_font->lock.unlock ();
+
+      hb_blob_t *blob = hb_blob_create ((const char *) bitmap.buffer,
+                                       bitmap.pitch * bitmap.rows,
+                                       HB_MEMORY_MODE_DUPLICATE,
+                                       nullptr, nullptr);
+
+      hb_glyph_extents_t extents;
+      if (!hb_font_get_glyph_extents (font, gid, &extents))
+       goto out;
+
+      if (!paint_funcs->image (paint_data,
+                              blob,
+                              bitmap.width,
+                              bitmap.rows,
+                              HB_PAINT_IMAGE_FORMAT_BGRA,
+                              font->slant_xy,
+                              &extents))
+      {
+        /* TODO Try a forced outline load and paint? */
+      }
+
+    out:
+      hb_blob_destroy (blob);
+      ft_font->lock.lock ();
+    }
+
+    return;
+  }
+}
+#endif
+#endif
+
+
 static inline void free_static_ft_funcs ();
 
 static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
@@ -596,6 +1029,16 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft
     hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
     hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
 
+#ifndef HB_NO_DRAW
+    hb_font_funcs_set_draw_glyph_func (funcs, hb_ft_draw_glyph, nullptr, nullptr);
+#endif
+
+#ifndef HB_NO_PAINT
+#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300
+    hb_font_funcs_set_paint_glyph_func (funcs, hb_ft_paint_glyph, nullptr, nullptr);
+#endif
+#endif
+
     hb_font_funcs_make_immutable (funcs);
 
     hb_atexit (free_static_ft_funcs);
@@ -668,6 +1111,10 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data
  *
  * Creates an #hb_face_t face object from the specified FT_Face.
  *
+ * Note that this is using the FT_Face object just to get at the underlying
+ * font data, and fonts created from the returned #hb_face_t will use the native
+ * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them.
+ *
  * This variant of the function does not provide any life-cycle management.
  *
  * Most client programs should use hb_ft_face_create_referenced()
@@ -712,6 +1159,10 @@ hb_ft_face_create (FT_Face           ft_face,
  *
  * Creates an #hb_face_t face object from the specified FT_Face.
  *
+ * Note that this is using the FT_Face object just to get at the underlying
+ * font data, and fonts created from the returned #hb_face_t will use the native
+ * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them.
+ *
  * This is the preferred variant of the hb_ft_face_create*
  * function family, because it calls FT_Reference_Face() on @ft_face,
  * ensuring that @ft_face remains alive as long as the resulting
@@ -732,8 +1183,9 @@ hb_ft_face_create_referenced (FT_Face ft_face)
 }
 
 static void
-hb_ft_face_finalize (FT_Face ft_face)
+hb_ft_face_finalize (void *arg)
 {
+  FT_Face ft_face = (FT_Face) arg;
   hb_face_destroy ((hb_face_t *) ft_face->generic.data);
 }
 
@@ -743,6 +1195,10 @@ hb_ft_face_finalize (FT_Face ft_face)
  *
  * Creates an #hb_face_t face object from the specified FT_Face.
  *
+ * Note that this is using the FT_Face object just to get at the underlying
+ * font data, and fonts created from the returned #hb_face_t will use the native
+ * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them.
+ *
  * This variant of the function caches the newly created #hb_face_t
  * face object, using the @generic pointer of @ft_face. Subsequent function
  * calls that are passed the same @ft_face parameter will have the same
@@ -765,7 +1221,7 @@ hb_ft_face_create_cached (FT_Face ft_face)
       ft_face->generic.finalizer (ft_face);
 
     ft_face->generic.data = hb_ft_face_create (ft_face, nullptr);
-    ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
+    ft_face->generic.finalizer = hb_ft_face_finalize;
   }
 
   return hb_face_reference ((hb_face_t *) ft_face->generic.data);
@@ -878,6 +1334,34 @@ hb_ft_font_changed (hb_font_t *font)
 #endif
   }
 #endif
+
+  ft_font->advance_cache.clear ();
+  ft_font->cached_serial = font->serial;
+}
+
+/**
+ * hb_ft_hb_font_changed:
+ * @font: #hb_font_t to work upon
+ *
+ * Refreshes the state of the underlying FT_Face of @font when the hb_font_t
+ * @font has changed.
+ * This function should be called after changing the size or
+ * variation-axis settings on the @font.
+ * This call is fast if nothing has changed on @font.
+ *
+ * Return value: true if changed, false otherwise
+ *
+ * Since: 4.4.0
+ **/
+hb_bool_t
+hb_ft_hb_font_changed (hb_font_t *font)
+{
+  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
+    return false;
+
+  hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
+
+  return _hb_ft_hb_font_check_changed (font, ft_font);
 }
 
 /**
@@ -946,8 +1430,9 @@ get_ft_library ()
 }
 
 static void
-_release_blob (FT_Face ft_face)
+_release_blob (void *arg)
 {
+  FT_Face ft_face = (FT_Face) arg;
   hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
 }
 
@@ -964,10 +1449,14 @@ _release_blob (FT_Face ft_face)
  * created with hb_face_create(), and therefore was not
  * initially configured to use FreeType font functions.
  *
- * An #hb_face_t face object created with hb_ft_face_create()
+ * An #hb_font_t object created with hb_ft_font_create()
  * is preconfigured for FreeType font functions and does not
  * require this function to be used.
  *
+ * Note that if you modify the underlying #hb_font_t after
+ * calling this function, you need to call hb_ft_hb_font_changed()
+ * to update the underlying FT_Face.
+ *
  * <note>Note: Internally, this function creates an FT_Face.
 * </note>
  *
@@ -998,42 +1487,14 @@ hb_ft_font_set_funcs (hb_font_t *font)
   if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL))
     FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);
 
-  FT_Set_Char_Size (ft_face,
-                   abs (font->x_scale), abs (font->y_scale),
-                   0, 0);
-#if 0
-                   font->x_ppem * 72 * 64 / font->x_scale,
-                   font->y_ppem * 72 * 64 / font->y_scale);
-#endif
-  if (font->x_scale < 0 || font->y_scale < 0)
-  {
-    FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
-                         0, font->y_scale < 0 ? -1 : +1};
-    FT_Set_Transform (ft_face, &matrix, nullptr);
-  }
-
-#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
-  unsigned int num_coords;
-  const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
-  if (num_coords)
-  {
-    FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (num_coords, sizeof (FT_Fixed));
-    if (ft_coords)
-    {
-      for (unsigned int i = 0; i < num_coords; i++)
-       ft_coords[i] = coords[i] * 4;
-      FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
-      hb_free (ft_coords);
-    }
-  }
-#endif
 
   ft_face->generic.data = blob;
-  ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
+  ft_face->generic.finalizer = _release_blob;
 
   _hb_ft_font_set_funcs (font, ft_face, true);
   hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
-}
 
+  _hb_ft_hb_font_changed (font, ft_face);
+}
 
 #endif
index bf07115..6a8a7ab 100644 (file)
@@ -122,10 +122,17 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags);
 HB_EXTERN int
 hb_ft_font_get_load_flags (hb_font_t *font);
 
-/* Call when size or variations settings on underlying FT_Face change. */
+/* Call when size or variations settings on underlying FT_Face changed,
+ * and you want to update the hb_font_t from it. */
 HB_EXTERN void
 hb_ft_font_changed (hb_font_t *font);
 
+/* Call when size or variations settings on underlying hb_font_t may have
+ * changed, and you want to update the FT_Face from it.  This call is fast
+ * if nothing changed on hb_font_t. Returns true if changed. */
+HB_EXTERN hb_bool_t
+hb_ft_hb_font_changed (hb_font_t *font);
+
 /* Makes an hb_font_t use FreeType internally to implement font functions.
  * Note: this internally creates an FT_Face.  Use it when you create your
  * hb_face_t using hb_face_create(). */
index 8ddc7eb..1da8169 100644 (file)
@@ -129,32 +129,9 @@ hb_glib_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
 {
 #if GLIB_CHECK_VERSION(2,29,12)
   return g_unichar_compose (a, b, ab);
+#else
+  return false;
 #endif
-
-  /* We don't ifdef-out the fallback code such that compiler always
-   * sees it and makes sure it's compilable. */
-
-  gchar utf8[12];
-  gchar *normalized;
-  int len;
-  hb_bool_t ret;
-
-  len = g_unichar_to_utf8 (a, utf8);
-  len += g_unichar_to_utf8 (b, utf8 + len);
-  normalized = g_utf8_normalize (utf8, len, G_NORMALIZE_NFC);
-  len = g_utf8_strlen (normalized, -1);
-  if (unlikely (!len))
-    return false;
-
-  if (len == 1) {
-    *ab = g_utf8_get_char (normalized);
-    ret = true;
-  } else {
-    ret = false;
-  }
-
-  g_free (normalized);
-  return ret;
 }
 
 static hb_bool_t
@@ -166,55 +143,9 @@ hb_glib_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
 {
 #if GLIB_CHECK_VERSION(2,29,12)
   return g_unichar_decompose (ab, a, b);
+#else
+  return false;
 #endif
-
-  /* We don't ifdef-out the fallback code such that compiler always
-   * sees it and makes sure it's compilable. */
-
-  gchar utf8[6];
-  gchar *normalized;
-  int len;
-  hb_bool_t ret;
-
-  len = g_unichar_to_utf8 (ab, utf8);
-  normalized = g_utf8_normalize (utf8, len, G_NORMALIZE_NFD);
-  len = g_utf8_strlen (normalized, -1);
-  if (unlikely (!len))
-    return false;
-
-  if (len == 1) {
-    *a = g_utf8_get_char (normalized);
-    *b = 0;
-    ret = *a != ab;
-  } else if (len == 2) {
-    *a = g_utf8_get_char (normalized);
-    *b = g_utf8_get_char (g_utf8_next_char (normalized));
-    /* Here's the ugly part: if ab decomposes to a single character and
-     * that character decomposes again, we have to detect that and undo
-     * the second part :-(. */
-    gchar *recomposed = g_utf8_normalize (normalized, -1, G_NORMALIZE_NFC);
-    hb_codepoint_t c = g_utf8_get_char (recomposed);
-    if (c != ab && c != *a) {
-      *a = c;
-      *b = 0;
-    }
-    g_free (recomposed);
-    ret = true;
-  } else {
-    /* If decomposed to more than two characters, take the last one,
-     * and recompose the rest to get the first component. */
-    gchar *end = g_utf8_offset_to_pointer (normalized, len - 1);
-    gchar *recomposed;
-    *b = g_utf8_get_char (end);
-    recomposed = g_utf8_normalize (normalized, end - normalized, G_NORMALIZE_NFC);
-    /* We expect that recomposed has exactly one character now. */
-    *a = g_utf8_get_char (recomposed);
-    g_free (recomposed);
-    ret = true;
-  }
-
-  g_free (normalized);
-  return ret;
 }
 
 
index a846786..6dd98f7 100644 (file)
@@ -43,7 +43,7 @@ HB_BEGIN_DECLS
 
 /*** BEGIN value-header ***/
 HB_EXTERN GType
-@enum_name@_get_type () G_GNUC_CONST;
+@enum_name@_get_type (void) G_GNUC_CONST;
 #define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
 
 /*** END value-header ***/
index 540b11f..d66de0b 100644 (file)
@@ -29,7 +29,7 @@
 #ifdef HAVE_GOBJECT
 
 
-/**
+/*
  * SECTION:hb-gobject
  * @title: hb-gobject
  * @short_description: GObject integration support
@@ -90,6 +90,8 @@ hb_gobject_##name##_get_type () \
 
 HB_DEFINE_OBJECT_TYPE (buffer)
 HB_DEFINE_OBJECT_TYPE (blob)
+HB_DEFINE_OBJECT_TYPE (draw_funcs)
+HB_DEFINE_OBJECT_TYPE (paint_funcs)
 HB_DEFINE_OBJECT_TYPE (face)
 HB_DEFINE_OBJECT_TYPE (font)
 HB_DEFINE_OBJECT_TYPE (font_funcs)
@@ -101,8 +103,12 @@ HB_DEFINE_VALUE_TYPE (feature)
 HB_DEFINE_VALUE_TYPE (glyph_info)
 HB_DEFINE_VALUE_TYPE (glyph_position)
 HB_DEFINE_VALUE_TYPE (segment_properties)
+HB_DEFINE_VALUE_TYPE (draw_state)
+HB_DEFINE_VALUE_TYPE (color_stop)
+HB_DEFINE_VALUE_TYPE (color_line)
 HB_DEFINE_VALUE_TYPE (user_data_key)
 
+HB_DEFINE_VALUE_TYPE (ot_var_axis_info)
 HB_DEFINE_VALUE_TYPE (ot_math_glyph_variant)
 HB_DEFINE_VALUE_TYPE (ot_math_glyph_part)
 
index 63467f8..b7b5f55 100644 (file)
@@ -49,6 +49,14 @@ hb_gobject_buffer_get_type (void);
 #define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ())
 
 HB_EXTERN GType
+hb_gobject_draw_funcs_get_type (void);
+#define HB_GOBJECT_TYPE_DRAW_FUNCS (hb_gobject_draw_funcs_get_type ())
+
+HB_EXTERN GType
+hb_gobject_paint_funcs_get_type (void);
+#define HB_GOBJECT_TYPE_PAINT_FUNCS (hb_gobject_paint_funcs_get_type ())
+
+HB_EXTERN GType
 hb_gobject_face_get_type (void);
 #define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ())
 
@@ -95,10 +103,26 @@ hb_gobject_segment_properties_get_type (void);
 #define HB_GOBJECT_TYPE_SEGMENT_PROPERTIES (hb_gobject_segment_properties_get_type ())
 
 HB_EXTERN GType
+hb_gobject_draw_state_get_type (void);
+#define HB_GOBJECT_TYPE_DRAW_STATE (hb_gobject_draw_state_get_type ())
+
+HB_EXTERN GType
+hb_gobject_color_stop_get_type (void);
+#define HB_GOBJECT_TYPE_COLOR_STOP (hb_gobject_color_stop_get_type ())
+
+HB_EXTERN GType
+hb_gobject_color_line_get_type (void);
+#define HB_GOBJECT_TYPE_COLOR_LINE (hb_gobject_color_line_get_type ())
+
+HB_EXTERN GType
 hb_gobject_user_data_key_get_type (void);
 #define HB_GOBJECT_TYPE_USER_DATA_KEY (hb_gobject_user_data_key_get_type ())
 
 HB_EXTERN GType
+hb_gobject_ot_var_axis_info_get_type (void);
+#define HB_GOBJECT_TYPE_OT_VAR_AXIS_INFO (hb_gobject_ot_var_axis_info_get_type ())
+
+HB_EXTERN GType
 hb_gobject_ot_math_glyph_variant_get_type (void);
 #define HB_GOBJECT_TYPE_OT_MATH_GLYPH_VARIANT (hb_gobject_ot_math_glyph_variant_get_type ())
 
index 63dc18b..7ea0386 100644 (file)
@@ -158,7 +158,7 @@ _hb_graphite2_shaper_face_data_destroy (hb_graphite2_face_data_t *data)
 }
 
 /**
- * hb_graphite2_face_get_gr_face:
+ * hb_graphite2_face_get_gr_face: (skip)
  * @face: @hb_face_t to query
  *
  * Fetches the Graphite2 gr_face corresponding to the specified
@@ -195,10 +195,10 @@ _hb_graphite2_shaper_font_data_destroy (hb_graphite2_font_data_t *data HB_UNUSED
 
 #ifndef HB_DISABLE_DEPRECATED
 /**
- * hb_graphite2_font_get_gr_font:
+ * hb_graphite2_font_get_gr_font: (skip)
  * @font: An #hb_font_t
  *
- * Always returns %NULL. Use hb_graphite2_face_get_gr_face() instead.
+ * Always returns `NULL`. Use hb_graphite2_face_get_gr_face() instead.
  *
  * Return value: (nullable): Graphite2 font associated with @font.
  *
@@ -223,7 +223,7 @@ struct hb_graphite2_cluster_t {
   unsigned int base_glyph;
   unsigned int num_glyphs;
   unsigned int cluster;
-  unsigned int advance;
+  int advance;
 };
 
 hb_bool_t
@@ -248,6 +248,21 @@ _hb_graphite2_shape (hb_shape_plan_t    *shape_plan HB_UNUSED,
       gr_fref_set_feature_value (fref, features[i].value, feats);
   }
 
+  hb_direction_t direction = buffer->props.direction;
+  hb_direction_t horiz_dir = hb_script_get_horizontal_direction (buffer->props.script);
+  /* TODO vertical:
+   * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
+   * Ogham fonts are supposed to be implemented BTT or not.  Need to research that
+   * first. */
+  if ((HB_DIRECTION_IS_HORIZONTAL (direction) &&
+       direction != horiz_dir && horiz_dir != HB_DIRECTION_INVALID) ||
+      (HB_DIRECTION_IS_VERTICAL   (direction) &&
+       direction != HB_DIRECTION_TTB))
+  {
+    hb_buffer_reverse_clusters (buffer);
+    direction = HB_DIRECTION_REVERSE (direction);
+  }
+
   gr_segment *seg = nullptr;
   const gr_slot *is;
   unsigned int ci = 0, ic = 0;
@@ -261,21 +276,11 @@ _hb_graphite2_shape (hb_shape_plan_t    *shape_plan HB_UNUSED,
   for (unsigned int i = 0; i < buffer->len; ++i)
     chars[i] = buffer->info[i].codepoint;
 
-  /* TODO ensure_native_direction. */
-
-  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,
-                    count ? script_tag[count - 1] : HB_OT_TAG_DEFAULT_SCRIPT,
+                    HB_TAG_NONE, // https://github.com/harfbuzz/harfbuzz/issues/3439#issuecomment-1442650148
                     feats,
                     gr_utf32, chars, buffer->len,
-                    2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0));
+                    2 | (direction == HB_DIRECTION_RTL ? 1 : 0));
 
   if (unlikely (!seg)) {
     if (feats) gr_featureval_destroy (feats);
@@ -318,7 +323,7 @@ _hb_graphite2_shape (hb_shape_plan_t    *shape_plan HB_UNUSED,
 
 #undef ALLOCATE_ARRAY
 
-  memset (clusters, 0, sizeof (clusters[0]) * buffer->len);
+  hb_memset (clusters, 0, sizeof (clusters[0]) * buffer->len);
 
   hb_codepoint_t *pg = gids;
   clusters[0].cluster = buffer->info[0].cluster;
@@ -327,7 +332,7 @@ _hb_graphite2_shape (hb_shape_plan_t    *shape_plan HB_UNUSED,
   float yscale = (float) font->y_scale / upem;
   yscale *= yscale / xscale;
   unsigned int curradv = 0;
-  if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+  if (HB_DIRECTION_IS_BACKWARD (direction))
   {
     curradv = gr_slot_origin_X(gr_seg_first_slot(seg)) * xscale;
     clusters[0].advance = gr_seg_advance_X(seg) * xscale - curradv;
@@ -356,16 +361,17 @@ _hb_graphite2_shape (hb_shape_plan_t    *shape_plan HB_UNUSED,
       c->num_chars = before - c->base_char;
       c->base_glyph = ic;
       c->num_glyphs = 0;
-      if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+      if (HB_DIRECTION_IS_BACKWARD (direction))
       {
        c->advance = curradv - gr_slot_origin_X(is) * xscale;
        curradv -= c->advance;
       }
       else
       {
+       auto origin_X = gr_slot_origin_X (is) * xscale;
        c->advance = 0;
-       clusters[ci].advance += gr_slot_origin_X(is) * xscale - curradv;
-       curradv += clusters[ci].advance;
+       clusters[ci].advance += origin_X - curradv;
+       curradv = origin_X;
       }
       ci++;
     }
@@ -375,7 +381,7 @@ _hb_graphite2_shape (hb_shape_plan_t    *shape_plan HB_UNUSED,
        clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
   }
 
-  if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+  if (HB_DIRECTION_IS_BACKWARD (direction))
     clusters[ci].advance += curradv;
   else
     clusters[ci].advance += gr_seg_advance_X(seg) * xscale - curradv;
@@ -397,7 +403,7 @@ _hb_graphite2_shape (hb_shape_plan_t    *shape_plan HB_UNUSED,
   unsigned int currclus = UINT_MAX;
   const hb_glyph_info_t *info = buffer->info;
   hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, nullptr);
-  if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+  if (!HB_DIRECTION_IS_BACKWARD (direction))
   {
     curradvx = 0;
     for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is))
index f299da9..ee9229b 100644 (file)
@@ -49,7 +49,8 @@ hb_graphite2_face_get_gr_face (hb_face_t *face);
 
 #ifndef HB_DISABLE_DEPRECATED
 
-HB_EXTERN HB_DEPRECATED_FOR (hb_graphite2_face_get_gr_face) gr_font *
+HB_DEPRECATED_FOR (hb_graphite2_face_get_gr_face)
+HB_EXTERN gr_font *
 hb_graphite2_font_get_gr_font (hb_font_t *font);
 
 #endif
index 43a3098..61e0518 100644 (file)
  * is writable, then the iterator returns lvalues, otherwise it
  * returns rvalues.
  *
- * TODO Document more.
- *
- * If iterator implementation implements operator!=, then can be
+ * If iterator implementation implements operator!=, then it can be
  * used in range-based for loop.  That already happens if the iterator
  * is random-access.  Otherwise, the range-based for loop incurs
  * one traversal to find end(), which can be avoided if written
  * as a while-style for loop, or if iterator implements a faster
- * __end__() method.
- * TODO When opting in for C++17, address this by changing return
- * type of .end()?
- */
+ * __end__() method. */
 
 /*
  * Base classes for iterators.
@@ -68,6 +63,7 @@ struct hb_iter_t
   static constexpr bool is_iterator = true;
   static constexpr bool is_random_access_iterator = false;
   static constexpr bool is_sorted_iterator = false;
+  static constexpr bool has_fast_len = false; // Should be checked in combination with is_random_access_iterator.
 
   private:
   /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
@@ -75,20 +71,17 @@ struct hb_iter_t
        iter_t* thiz ()       { return static_cast<      iter_t *> (this); }
   public:
 
-  /* TODO:
-   * Port operators below to use hb_enable_if to sniff which method implements
-   * an operator and use it, and remove hb_iter_fallback_mixin_t completely. */
-
   /* Operators. */
   iter_t iter () const { return *thiz(); }
   iter_t operator + () const { return *thiz(); }
-  iter_t begin () const { return *thiz(); }
-  iter_t end () const { return thiz()->__end__ (); }
+  iter_t _begin () const { return *thiz(); }
+  iter_t begin () const { return _begin (); }
+  iter_t _end () const { return thiz()->__end__ (); }
+  iter_t end () const { return _end (); }
   explicit operator bool () const { return thiz()->__more__ (); }
   unsigned len () const { return thiz()->__len__ (); }
   /* The following can only be enabled if item_t is reference type.  Otherwise
-   * it will be returning pointer to temporary rvalue.
-   * TODO Use a wrapper return type to fix for non-reference type. */
+   * it will be returning pointer to temporary rvalue. */
   template <typename T = item_t,
            hb_enable_if (std::is_reference<T>::value)>
   hb_remove_reference<item_t>* operator -> () const { return std::addressof (**thiz()); }
@@ -128,7 +121,9 @@ struct hb_iter_t
 
 #define HB_ITER_USING(Name) \
   using item_t = typename Name::item_t; \
+  using Name::_begin; \
   using Name::begin; \
+  using Name::_end; \
   using Name::end; \
   using Name::get_item_size; \
   using Name::is_iterator; \
@@ -178,10 +173,16 @@ struct
 HB_FUNCOBJ (hb_iter);
 struct
 {
-  template <typename T> unsigned
-  operator () (T&& c) const
-  { return c.len (); }
+  template <typename T> auto
+  impl (T&& c, hb_priority<1>) const HB_RETURN (unsigned, c.len ())
+
+  template <typename T> auto
+  impl (T&& c, hb_priority<0>) const HB_RETURN (unsigned, c.len)
+
+  public:
 
+  template <typename T> auto
+  operator () (T&& c) const HB_RETURN (unsigned, impl (std::forward<T> (c), hb_prioritize))
 }
 HB_FUNCOBJ (hb_len);
 
@@ -263,6 +264,8 @@ struct hb_is_iterator_of
 };
 #define hb_is_iterator_of(Iter, Item) hb_is_iterator_of<Iter, Item>::value
 #define hb_is_iterator(Iter) hb_is_iterator_of (Iter, typename Iter::item_t)
+#define hb_is_sorted_iterator_of(Iter, Item) (hb_is_iterator_of<Iter, Item>::value && Iter::is_sorted_iterator)
+#define hb_is_sorted_iterator(Iter) hb_is_sorted_iterator_of (Iter, typename Iter::item_t)
 
 /* hb_is_iterable() */
 
@@ -385,13 +388,13 @@ struct hb_map_iter_t :
   void __forward__ (unsigned n) { it += n; }
   void __prev__ () { --it; }
   void __rewind__ (unsigned n) { it -= n; }
-  hb_map_iter_t __end__ () const { return hb_map_iter_t (it.end (), f); }
+  hb_map_iter_t __end__ () const { return hb_map_iter_t (it._end (), f); }
   bool operator != (const hb_map_iter_t& o) const
   { return it != o.it; }
 
   private:
   Iter it;
-  hb_reference_wrapper<Proj> f;
+  mutable hb_reference_wrapper<Proj> f;
 };
 
 template <typename Proj, hb_function_sortedness_t Sorted>
@@ -448,14 +451,14 @@ struct hb_filter_iter_t :
   bool __more__ () const { return bool (it); }
   void __next__ () { do ++it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
   void __prev__ () { do --it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
-  hb_filter_iter_t __end__ () const { return hb_filter_iter_t (it.end (), p, f); }
+  hb_filter_iter_t __end__ () const { return hb_filter_iter_t (it._end (), p, f); }
   bool operator != (const hb_filter_iter_t& o) const
   { return it != o.it; }
 
   private:
   Iter it;
-  hb_reference_wrapper<Pred> p;
-  hb_reference_wrapper<Proj> f;
+  mutable hb_reference_wrapper<Pred> p;
+  mutable hb_reference_wrapper<Proj> f;
 };
 template <typename Pred, typename Proj>
 struct hb_filter_iter_factory_t
@@ -561,7 +564,7 @@ struct hb_zip_iter_t :
   void __forward__ (unsigned n) { a += n; b += n; }
   void __prev__ () { --a; --b; }
   void __rewind__ (unsigned n) { a -= n; b -= n; }
-  hb_zip_iter_t __end__ () const { return hb_zip_iter_t (a.end (), b.end ()); }
+  hb_zip_iter_t __end__ () const { return hb_zip_iter_t (a._end (), b._end ()); }
   /* Note, we should stop if ANY of the iters reaches end.  As such two compare
    * unequal if both items are unequal, NOT if either is unequal. */
   bool operator != (const hb_zip_iter_t& o) const
@@ -645,7 +648,7 @@ struct hb_concat_iter_t :
     }
   }
 
-  hb_concat_iter_t __end__ () const { return hb_concat_iter_t (a.end (), b.end ()); }
+  hb_concat_iter_t __end__ () const { return hb_concat_iter_t (a._end (), b._end ()); }
   bool operator != (const hb_concat_iter_t& o) const
   {
     return a != o.a
@@ -839,7 +842,7 @@ struct
   template <typename Iterable,
            hb_requires (hb_is_iterable (Iterable))>
   auto operator () (Iterable&& it, unsigned count) const HB_AUTO_RETURN
-  ( hb_zip (hb_range (count), it) | hb_map (hb_second) )
+  ( hb_zip (hb_range (count), it) | hb_map_retains_sorting (hb_second) )
 
   /* Specialization arrays. */
 
index 9ea945c..0462a0e 100644 (file)
@@ -53,7 +53,7 @@ struct hb_kern_machine_t
       return;
 
     buffer->unsafe_to_concat ();
-    OT::hb_ot_apply_context_t c (1, font, buffer);
+    OT::hb_ot_apply_context_t c (1, font, buffer, hb_blob_get_empty ());
     c.set_lookup_mask (kern_mask);
     c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
     auto &skippy_iter = c.iter_input;
@@ -70,7 +70,7 @@ struct hb_kern_machine_t
        continue;
       }
 
-      skippy_iter.reset (idx, 1);
+      skippy_iter.reset (idx);
       unsigned unsafe_to;
       if (!skippy_iter.next (&unsafe_to))
       {
diff --git a/src/hb-limits.hh b/src/hb-limits.hh
new file mode 100644 (file)
index 0000000..25c1e71
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright © 2022  Behdad Esfahbod
+ *
+ *  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_LIMITS_HH
+#define HB_LIMITS_HH
+
+#include "hb.hh"
+
+
+#ifndef HB_BUFFER_MAX_LEN_FACTOR
+#define HB_BUFFER_MAX_LEN_FACTOR 64
+#endif
+#ifndef HB_BUFFER_MAX_LEN_MIN
+#define HB_BUFFER_MAX_LEN_MIN 16384
+#endif
+#ifndef HB_BUFFER_MAX_LEN_DEFAULT
+#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */
+#endif
+
+#ifndef HB_BUFFER_MAX_OPS_FACTOR
+#define HB_BUFFER_MAX_OPS_FACTOR 1024
+#endif
+#ifndef HB_BUFFER_MAX_OPS_MIN
+#define HB_BUFFER_MAX_OPS_MIN 16384
+#endif
+#ifndef HB_BUFFER_MAX_OPS_DEFAULT
+#define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF /* Shaping more than a billion operations? Let us know! */
+#endif
+
+
+#ifndef HB_MAX_NESTING_LEVEL
+#define HB_MAX_NESTING_LEVEL 64
+#endif
+
+
+#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_gsub_pause() is
+ * called in a collect_features call of any shaper.
+ */
+#define HB_CLOSURE_MAX_STAGES 12
+#endif
+
+#ifndef HB_MAX_SCRIPTS
+#define HB_MAX_SCRIPTS 500
+#endif
+
+#ifndef HB_MAX_LANGSYS
+#define HB_MAX_LANGSYS 2000
+#endif
+
+#ifndef HB_MAX_LANGSYS_FEATURE_COUNT
+#define HB_MAX_LANGSYS_FEATURE_COUNT 50000
+#endif
+
+#ifndef HB_MAX_FEATURE_INDICES
+#define HB_MAX_FEATURE_INDICES 1500
+#endif
+
+#ifndef HB_MAX_LOOKUP_VISIT_COUNT
+#define HB_MAX_LOOKUP_VISIT_COUNT 35000
+#endif
+
+
+#ifndef HB_GLYF_VAR_COMPOSITE_MAX_AXES
+#define HB_GLYF_VAR_COMPOSITE_MAX_AXES 4096
+#endif
+
+#ifndef HB_GLYF_MAX_POINTS
+#define HB_GLYF_MAX_POINTS 20000
+#endif
+
+#ifndef HB_GLYF_MAX_EDGE_COUNT
+#define HB_GLYF_MAX_EDGE_COUNT 1024
+#endif
+
+#ifndef HB_CFF_MAX_OPS
+#define HB_CFF_MAX_OPS 10000
+#endif
+
+#ifndef HB_COLRV1_MAX_EDGE_COUNT
+#define HB_COLRV1_MAX_EDGE_COUNT 65536
+#endif
+
+
+#endif /* HB_LIMITS_HH */
index b529173..ecff94f 100644 (file)
@@ -34,7 +34,6 @@
 
 #include "hb-dispatch.hh"
 #include "hb-sanitize.hh"
-#include "hb-serialize.hh"
 
 
 /*
@@ -136,6 +135,13 @@ static inline Type& StructAfter(TObject &X)
 
 /*
  * Lazy loaders.
+ *
+ * The lazy-loaders are thread-safe pointer-like objects that create their
+ * instead on-demand.  They also support access to a "data" object that is
+ * necessary for creating their instance.  The data object, if specified,
+ * is accessed via pointer math, located at a location before the position
+ * of the loader itself.  This avoids having to store a pointer to data
+ * for every lazy-loader.  Multiple lazy-loaders can access the same data.
  */
 
 template <typename Data, unsigned int WheresData>
@@ -174,14 +180,17 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
                                 hb_lazy_loader_t<Returned,Subclass,Data,WheresData,Stored>
                                >::value Funcs;
 
+  hb_lazy_loader_t () = default;
+  hb_lazy_loader_t (const hb_lazy_loader_t &other) = delete;
+
   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 fini ()  { do_destroy (instance.get_acquire ()); init (); }
 
   void free_instance ()
   {
   retry:
-    Stored *p = instance.get ();
+    Stored *p = instance.get_acquire ();
     if (unlikely (p && !cmpexch (p, nullptr)))
       goto retry;
     do_destroy (p);
@@ -203,7 +212,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
   Stored * get_stored () const
   {
   retry:
-    Stored *p = this->instance.get ();
+    Stored *p = this->instance.get_acquire ();
     if (unlikely (!p))
     {
       if (unlikely (this->is_inert ()))
@@ -228,7 +237,8 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
 
   bool cmpexch (Stored *current, Stored *value) const
   {
-    /* This *must* be called when there are no other threads accessing. */
+    /* This function can only be safely called directly if no
+     * other thread is accessing. */
     return this->instance.cmpexch (current, value);
   }
 
@@ -261,7 +271,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
     hb_free (p);
   }
 
-//  private:
+  private:
   /* Must only have one pointer. */
   hb_atomic_ptr_t<Stored *> instance;
 };
@@ -271,16 +281,25 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
 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> {};
+                                               hb_face_t, WheresFace>
+{
+  // Hack; have them here for API parity with hb_table_lazy_loader_t
+  hb_blob_t *get_blob () { return this->get ()->get_blob (); }
+};
 
-template <typename T, unsigned int WheresFace>
+template <typename T, unsigned int WheresFace, bool core=false>
 struct hb_table_lazy_loader_t : hb_lazy_loader_t<T,
-                                                hb_table_lazy_loader_t<T, WheresFace>,
+                                                hb_table_lazy_loader_t<T, WheresFace, core>,
                                                 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); }
+  {
+    hb_sanitize_context_t c;
+    if (core)
+      c.set_num_glyphs (0); // So we don't recurse ad infinitum, or doesn't need num_glyphs
+    return c.reference_table<T> (face);
+  }
   static void destroy (hb_blob_t *p) { hb_blob_destroy (p); }
 
   static const hb_blob_t *get_null ()
@@ -292,22 +311,22 @@ struct hb_table_lazy_loader_t : hb_lazy_loader_t<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 (); }
-};
+#define HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T(Type) \
+  template <typename Subclass> \
+  struct hb_##Type##_funcs_lazy_loader_t : hb_lazy_loader_t<hb_##Type##_funcs_t, Subclass> \
+  { \
+    static void destroy (hb_##Type##_funcs_t *p) \
+    { hb_##Type##_funcs_destroy (p); } \
+    static const hb_##Type##_funcs_t *get_null () \
+    { return hb_##Type##_funcs_get_empty (); } \
+  }
+
+HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (font);
+HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (unicode);
+HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (draw);
+HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (paint);
+
+#undef HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T
 
 
 #endif /* HB_MACHINERY_HH */
index 9f1ac42..0dc9246 100644 (file)
@@ -40,7 +40,7 @@
 
 
 /**
- * hb_map_create: (Xconstructor)
+ * hb_map_create:
  *
  * Creates a new, initially empty map.
  *
@@ -56,8 +56,6 @@ hb_map_create ()
   if (!(map = hb_object_create<hb_map_t> ()))
     return hb_map_get_empty ();
 
-  map->init_shallow ();
-
   return map;
 }
 
@@ -107,8 +105,6 @@ hb_map_destroy (hb_map_t *map)
 {
   if (!hb_object_destroy (map)) return;
 
-  map->fini_shallow ();
-
   hb_free (map);
 }
 
@@ -122,7 +118,7 @@ hb_map_destroy (hb_map_t *map)
  *
  * Attaches a user-data key/data pair to the specified map.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 1.7.7
  **/
@@ -149,7 +145,7 @@ hb_map_set_user_data (hb_map_t           *map,
  * Since: 1.7.7
  **/
 void *
-hb_map_get_user_data (hb_map_t           *map,
+hb_map_get_user_data (const hb_map_t     *map,
                      hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (map, key);
@@ -162,7 +158,7 @@ hb_map_get_user_data (hb_map_t           *map,
  *
  * Tests whether memory allocation for a set was successful.
  *
- * Return value: %true if allocation succeeded, %false otherwise
+ * Return value: `true` if allocation succeeded, `false` otherwise
  *
  * Since: 1.7.7
  **/
@@ -172,6 +168,26 @@ hb_map_allocation_successful (const hb_map_t  *map)
   return map->successful;
 }
 
+/**
+ * hb_map_copy:
+ * @map: A map
+ *
+ * Allocate a copy of @map.
+ *
+ * Return value: (transfer full): Newly-allocated map.
+ *
+ * Since: 4.4.0
+ **/
+hb_map_t *
+hb_map_copy (const hb_map_t *map)
+{
+  hb_map_t *copy = hb_map_create ();
+  if (unlikely (copy->in_error ()))
+    return hb_map_get_empty ();
+
+  *copy = *map;
+  return copy;
+}
 
 /**
  * hb_map_set:
@@ -232,7 +248,7 @@ hb_map_del (hb_map_t       *map,
  *
  * Tests whether @key is an element of @map.
  *
- * Return value: %true if @key is found in @map, %false otherwise
+ * Return value: `true` if @key is found in @map, `false` otherwise
  *
  * Since: 1.7.7
  **/
@@ -264,7 +280,7 @@ hb_map_clear (hb_map_t *map)
  *
  * Tests whether @map is empty (contains no elements).
  *
- * Return value: %true if @map is empty
+ * Return value: `true` if @map is empty
  *
  * Since: 1.7.7
  **/
@@ -289,3 +305,115 @@ hb_map_get_population (const hb_map_t *map)
 {
   return map->get_population ();
 }
+
+/**
+ * hb_map_is_equal:
+ * @map: A map
+ * @other: Another map
+ *
+ * Tests whether @map and @other are equal (contain the same
+ * elements).
+ *
+ * Return value: `true` if the two maps are equal, `false` otherwise.
+ *
+ * Since: 4.3.0
+ **/
+hb_bool_t
+hb_map_is_equal (const hb_map_t *map,
+                const hb_map_t *other)
+{
+  return map->is_equal (*other);
+}
+
+/**
+ * hb_map_hash:
+ * @map: A map
+ *
+ * Creates a hash representing @map.
+ *
+ * Return value:
+ * A hash of @map.
+ *
+ * Since: 4.4.0
+ **/
+unsigned int
+hb_map_hash (const hb_map_t *map)
+{
+  return map->hash ();
+}
+
+/**
+ * hb_map_update:
+ * @map: A map
+ * @other: Another map
+ *
+ * Add the contents of @other to @map.
+ *
+ * Since: 7.0.0
+ **/
+HB_EXTERN void
+hb_map_update (hb_map_t *map,
+              const hb_map_t *other)
+{
+  map->update (*other);
+}
+
+/**
+ * hb_map_next:
+ * @map: A map
+ * @idx: (inout): Iterator internal state
+ * @key: (out): Key retrieved
+ * @value: (out): Value retrieved
+ *
+ * Fetches the next key/value pair in @map.
+ *
+ * Set @idx to -1 to get started.
+ *
+ * If the map is modified during iteration, the behavior is undefined.
+ *
+ * The order in which the key/values are returned is undefined.
+ *
+ * Return value: `true` if there was a next value, `false` otherwise
+ *
+ * Since: 7.0.0
+ **/
+hb_bool_t
+hb_map_next (const hb_map_t *map,
+            int *idx,
+            hb_codepoint_t *key,
+            hb_codepoint_t *value)
+{
+  return map->next (idx, key, value);
+}
+
+/**
+ * hb_map_keys:
+ * @map: A map
+ * @keys: A set
+ *
+ * Add the keys of @map to @keys.
+ *
+ * Since: 7.0.0
+ **/
+void
+hb_map_keys (const hb_map_t *map,
+            hb_set_t *keys)
+{
+  hb_copy (map->keys() , *keys);
+}
+
+/**
+ * hb_map_values:
+ * @map: A map
+ * @values: A set
+ *
+ * Add the values of @map to @values.
+ *
+ * Since: 7.0.0
+ **/
+void
+hb_map_values (const hb_map_t *map,
+              hb_set_t *values)
+{
+  hb_copy (map->values() , *values);
+}
index 6a45a7b..0ae1717 100644 (file)
@@ -32,6 +32,7 @@
 #define HB_MAP_H
 
 #include "hb-common.h"
+#include "hb-set.h"
 
 HB_BEGIN_DECLS
 
@@ -43,7 +44,7 @@ HB_BEGIN_DECLS
  *
  * Since: 1.7.7
  */
-#define HB_MAP_VALUE_INVALID ((hb_codepoint_t) -1)
+#define HB_MAP_VALUE_INVALID HB_CODEPOINT_INVALID
 
 /**
  * hb_map_t:
@@ -74,7 +75,7 @@ hb_map_set_user_data (hb_map_t           *map,
                      hb_bool_t           replace);
 
 HB_EXTERN void *
-hb_map_get_user_data (hb_map_t           *map,
+hb_map_get_user_data (const hb_map_t     *map,
                      hb_user_data_key_t *key);
 
 
@@ -82,6 +83,9 @@ hb_map_get_user_data (hb_map_t           *map,
 HB_EXTERN hb_bool_t
 hb_map_allocation_successful (const hb_map_t *map);
 
+HB_EXTERN hb_map_t *
+hb_map_copy (const hb_map_t *map);
+
 HB_EXTERN void
 hb_map_clear (hb_map_t *map);
 
@@ -91,6 +95,13 @@ hb_map_is_empty (const hb_map_t *map);
 HB_EXTERN unsigned int
 hb_map_get_population (const hb_map_t *map);
 
+HB_EXTERN hb_bool_t
+hb_map_is_equal (const hb_map_t *map,
+                const hb_map_t *other);
+
+HB_EXTERN unsigned int
+hb_map_hash (const hb_map_t *map);
+
 HB_EXTERN void
 hb_map_set (hb_map_t       *map,
            hb_codepoint_t  key,
@@ -108,6 +119,24 @@ HB_EXTERN hb_bool_t
 hb_map_has (const hb_map_t *map,
            hb_codepoint_t  key);
 
+HB_EXTERN void
+hb_map_update (hb_map_t *map,
+              const hb_map_t *other);
+
+/* Pass -1 in for idx to get started. */
+HB_EXTERN hb_bool_t
+hb_map_next (const hb_map_t *map,
+            int *idx,
+            hb_codepoint_t *key,
+            hb_codepoint_t *value);
+
+HB_EXTERN void
+hb_map_keys (const hb_map_t *map,
+            hb_set_t *keys);
+
+HB_EXTERN void
+hb_map_values (const hb_map_t *map,
+              hb_set_t *values);
 
 HB_END_DECLS
 
index 9341637..13d6205 100644 (file)
 
 #include "hb.hh"
 
+#include "hb-set.hh"
+
 
 /*
  * hb_hashmap_t
  */
 
+extern HB_INTERNAL const hb_codepoint_t minus_1;
+
 template <typename K, typename V,
-         typename k_invalid_t = K,
-         typename v_invalid_t = V,
-         k_invalid_t kINVALID = std::is_pointer<K>::value ? 0 : std::is_signed<K>::value ? hb_int_min (K) : (K) -1,
-         v_invalid_t vINVALID = std::is_pointer<V>::value ? 0 : std::is_signed<V>::value ? hb_int_min (V) : (V) -1>
+         bool minus_one = false>
 struct hb_hashmap_t
 {
   hb_hashmap_t ()  { init (); }
   ~hb_hashmap_t () { fini (); }
 
-  hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { hb_copy (o, *this); }
+  hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { alloc (o.population); hb_copy (o, *this); }
   hb_hashmap_t (hb_hashmap_t&& o) : hb_hashmap_t () { hb_swap (*this, o); }
-  hb_hashmap_t& operator= (const hb_hashmap_t& o)  { hb_copy (o, *this); return *this; }
+  hb_hashmap_t& operator= (const hb_hashmap_t& o)  { reset (); alloc (o.population); hb_copy (o, *this); return *this; }
   hb_hashmap_t& operator= (hb_hashmap_t&& o)  { hb_swap (*this, o); return *this; }
 
   hb_hashmap_t (std::initializer_list<hb_pair_t<K, V>> lst) : hb_hashmap_t ()
@@ -58,93 +59,108 @@ struct hb_hashmap_t
            hb_requires (hb_is_iterable (Iterable))>
   hb_hashmap_t (const Iterable &o) : hb_hashmap_t ()
   {
-    hb_copy (o, *this);
+    auto iter = hb_iter (o);
+    if (iter.is_random_access_iterator || iter.has_fast_len)
+      alloc (hb_len (iter));
+    hb_copy (iter, *this);
   }
 
   struct item_t
   {
     K key;
+    uint32_t is_real_ : 1;
+    uint32_t is_used_ : 1;
+    uint32_t hash : 30;
     V value;
-    uint32_t hash;
 
-    void clear ()
+    item_t () : key (),
+               is_real_ (false), is_used_ (false),
+               hash (0),
+               value () {}
+
+    // Needed for https://github.com/harfbuzz/harfbuzz/issues/4138
+    K& get_key () { return key; }
+    V& get_value () { return value; }
+
+    bool is_used () const { return is_used_; }
+    void set_used (bool is_used) { is_used_ = is_used; }
+    void set_real (bool is_real) { is_real_ = is_real; }
+    bool is_real () const { return is_real_; }
+
+    template <bool v = minus_one,
+             hb_enable_if (v == false)>
+    static inline const V& default_value () { return Null(V); };
+    template <bool v = minus_one,
+             hb_enable_if (v == true)>
+    static inline const V& default_value ()
     {
-      new (std::addressof (key)) K ();
-      key = hb_coerce<K> (kINVALID);
-      new (std::addressof (value)) V ();
-      value = hb_coerce<V> (vINVALID);
-      hash = 0;
-    }
+      static_assert (hb_is_same (V, hb_codepoint_t), "");
+      return minus_1;
+    };
 
-    bool operator == (const K &o) { return hb_deref (key) == hb_deref (o); }
-    bool operator == (const item_t &o) { return *this == o.key; }
-    bool is_unused () const
-    {
-      const K inv = hb_coerce<K> (kINVALID);
-      return key == inv;
-    }
-    bool is_tombstone () const
-    {
-      const K kinv = hb_coerce<K> (kINVALID);
-      const V vinv = hb_coerce<V> (vINVALID);
-      return key != kinv && value == vinv;
-    }
-    bool is_real () const
-    {
-      const K kinv = hb_coerce<K> (kINVALID);
-      const V vinv = hb_coerce<V> (vINVALID);
-      return key != kinv && value != vinv;
-    }
+    bool operator == (const K &o) const { return hb_deref (key) == hb_deref (o); }
+    bool operator == (const item_t &o) const { return *this == o.key; }
     hb_pair_t<K, V> get_pair() const { return hb_pair_t<K, V> (key, value); }
+    hb_pair_t<const K &, V &> get_pair_ref() { return hb_pair_t<const K &, V &> (key, value); }
+
+    uint32_t total_hash () const
+    { return (hash * 31u) + hb_hash (value); }
+
+    static constexpr bool is_trivial = hb_is_trivially_constructible(K) &&
+                                      hb_is_trivially_destructible(K) &&
+                                      hb_is_trivially_constructible(V) &&
+                                      hb_is_trivially_destructible(V);
   };
 
   hb_object_header_t header;
-  bool successful; /* Allocations successful */
-  unsigned int population; /* Not including tombstones. */
+  unsigned int successful : 1; /* Allocations successful */
+  unsigned int population : 31; /* Not including tombstones. */
   unsigned int occupancy; /* Including tombstones. */
   unsigned int mask;
   unsigned int prime;
+  unsigned int max_chain_length;
   item_t *items;
 
   friend void swap (hb_hashmap_t& a, hb_hashmap_t& b)
   {
     if (unlikely (!a.successful || !b.successful))
       return;
-    hb_swap (a.population, b.population);
+    unsigned tmp = a.population;
+    a.population = b.population;
+    b.population = tmp;
+    //hb_swap (a.population, b.population);
     hb_swap (a.occupancy, b.occupancy);
     hb_swap (a.mask, b.mask);
     hb_swap (a.prime, b.prime);
+    hb_swap (a.max_chain_length, b.max_chain_length);
     hb_swap (a.items, b.items);
   }
-  void init_shallow ()
+  void init ()
   {
+    hb_object_init (this);
+
     successful = true;
     population = occupancy = 0;
     mask = 0;
     prime = 0;
+    max_chain_length = 0;
     items = nullptr;
   }
-  void init ()
-  {
-    hb_object_init (this);
-    init_shallow ();
-  }
-  void fini_shallow ()
+  void fini ()
   {
-    if (likely (items)) {
+    hb_object_fini (this);
+
+    if (likely (items))
+    {
       unsigned size = mask + 1;
-      for (unsigned i = 0; i < size; i++)
-        items[i].~item_t ();
+      if (!item_t::is_trivial)
+       for (unsigned i = 0; i < size; i++)
+         items[i].~item_t ();
       hb_free (items);
       items = nullptr;
     }
     population = occupancy = 0;
   }
-  void fini ()
-  {
-    hb_object_fini (this);
-    fini_shallow ();
-  }
 
   void reset ()
   {
@@ -154,11 +170,13 @@ struct hb_hashmap_t
 
   bool in_error () const { return !successful; }
 
-  bool resize ()
+  bool alloc (unsigned new_population = 0)
   {
     if (unlikely (!successful)) return false;
 
-    unsigned int power = hb_bit_storage (population * 2 + 8);
+    if (new_population != 0 && (new_population + new_population / 2) < mask) return true;
+
+    unsigned int power = hb_bit_storage (hb_max ((unsigned) population, new_population) * 2 + 8);
     unsigned int new_size = 1u << power;
     item_t *new_items = (item_t *) hb_malloc ((size_t) new_size * sizeof (item_t));
     if (unlikely (!new_items))
@@ -166,68 +184,177 @@ struct hb_hashmap_t
       successful = false;
       return false;
     }
-    for (auto &_ : hb_iter (new_items, new_size))
-      _.clear ();
+    if (!item_t::is_trivial)
+      for (auto &_ : hb_iter (new_items, new_size))
+       new (&_) item_t ();
+    else
+      hb_memset (new_items, 0, (size_t) new_size * sizeof (item_t));
 
-    unsigned int old_size = mask + 1;
+    unsigned int old_size = size ();
     item_t *old_items = items;
 
     /* Switch to new, empty, array. */
     population = occupancy = 0;
     mask = new_size - 1;
     prime = prime_for (power);
+    max_chain_length = power * 2;
     items = new_items;
 
     /* Insert back old items. */
-    if (old_items)
-      for (unsigned int i = 0; i < old_size; i++)
+    for (unsigned int i = 0; i < old_size; i++)
+    {
+      if (old_items[i].is_real ())
       {
-       if (old_items[i].is_real ())
-       {
-         set_with_hash (old_items[i].key,
-                        old_items[i].hash,
-                        std::move (old_items[i].value));
-       }
-       old_items[i].~item_t ();
+       set_with_hash (std::move (old_items[i].key),
+                      old_items[i].hash,
+                      std::move (old_items[i].value));
       }
+      if (!item_t::is_trivial)
+       old_items[i].~item_t ();
+    }
 
     hb_free (old_items);
 
     return true;
   }
 
-  bool set (K key, const V& value) { return set_with_hash (key, hb_hash (key), value); }
-  bool set (K key, V&& value) { return set_with_hash (key, hb_hash (key), std::move (value)); }
+  template <typename KK, typename VV>
+  bool set_with_hash (KK&& key, uint32_t hash, VV&& value, bool overwrite = true)
+  {
+    if (unlikely (!successful)) return false;
+    if (unlikely ((occupancy + occupancy / 2) >= mask && !alloc ())) return false;
 
-  V get (K key) const
+    hash &= 0x3FFFFFFF; // We only store lower 30bit of hash
+    unsigned int tombstone = (unsigned int) -1;
+    unsigned int i = hash % prime;
+    unsigned length = 0;
+    unsigned step = 0;
+    while (items[i].is_used ())
+    {
+      if ((std::is_integral<K>::value || items[i].hash == hash) &&
+         items[i] == key)
+      {
+        if (!overwrite)
+         return false;
+        else
+         break;
+      }
+      if (!items[i].is_real () && tombstone == (unsigned) -1)
+        tombstone = i;
+      i = (i + ++step) & mask;
+      length++;
+    }
+
+    item_t &item = items[tombstone == (unsigned) -1 ? i : tombstone];
+
+    if (item.is_used ())
+    {
+      occupancy--;
+      population -= item.is_real ();
+    }
+
+    item.key = std::forward<KK> (key);
+    item.value = std::forward<VV> (value);
+    item.hash = hash;
+    item.set_used (true);
+    item.set_real (true);
+
+    occupancy++;
+    population++;
+
+    if (unlikely (length > max_chain_length) && occupancy * 8 > mask)
+      alloc (mask - 8); // This ensures we jump to next larger size
+
+    return true;
+  }
+
+  template <typename VV>
+  bool set (const K &key, VV&& value, bool overwrite = true) { return set_with_hash (key, hb_hash (key), std::forward<VV> (value), overwrite); }
+  template <typename VV>
+  bool set (K &&key, VV&& value, bool overwrite = true)
+  {
+    uint32_t hash = hb_hash (key);
+    return set_with_hash (std::move (key), hash, std::forward<VV> (value), overwrite);
+  }
+  bool add (const K &key)
+  {
+    uint32_t hash = hb_hash (key);
+    return set_with_hash (key, hash, item_t::default_value ());
+  }
+
+  const V& get_with_hash (const K &key, uint32_t hash) const
+  {
+    if (!items) return item_t::default_value ();
+    auto *item = fetch_item (key, hb_hash (key));
+    if (item)
+      return item->value;
+    return item_t::default_value ();
+  }
+  const V& get (const K &key) const
   {
-    if (unlikely (!items)) return hb_coerce<V> (vINVALID);
-    unsigned int i = bucket_for (key);
-    return items[i].is_real () && items[i] == key ? items[i].value : hb_coerce<V> (vINVALID);
+    if (!items) return item_t::default_value ();
+    return get_with_hash (key, hb_hash (key));
   }
 
-  void del (K key) { set (key, hb_coerce<V> (vINVALID)); }
+  void del (const K &key)
+  {
+    if (!items) return;
+    auto *item = fetch_item (key, hb_hash (key));
+    if (item)
+    {
+      item->set_real (false);
+      population--;
+    }
+  }
 
   /* Has interface. */
-  typedef V value_t;
-  value_t operator [] (K k) const { return get (k); }
-  bool has (K k, V *vp = nullptr) const
+  const V& operator [] (K k) const { return get (k); }
+  template <typename VV=V>
+  bool has (const K &key, VV **vp = nullptr) const
+  {
+    if (!items) return false;
+    auto *item = fetch_item (key, hb_hash (key));
+    if (item)
+    {
+      if (vp) *vp = std::addressof (item->value);
+      return true;
+    }
+    return false;
+  }
+  item_t *fetch_item (const K &key, uint32_t hash) const
   {
-    V v = (*this)[k];
-    if (vp) *vp = v;
-    const V vinv = hb_coerce<V> (vINVALID);
-    return v != vinv;
+    hash &= 0x3FFFFFFF; // We only store lower 30bit of hash
+    unsigned int i = hash % prime;
+    unsigned step = 0;
+    while (items[i].is_used ())
+    {
+      if ((std::is_integral<K>::value || items[i].hash == hash) &&
+         items[i] == key)
+      {
+       if (items[i].is_real ())
+         return &items[i];
+       else
+         return nullptr;
+      }
+      i = (i + ++step) & mask;
+    }
+    return nullptr;
   }
   /* Projection. */
-  V operator () (K k) const { return get (k); }
+  const V& operator () (K k) const { return get (k); }
+
+  unsigned size () const { return mask ? mask + 1 : 0; }
 
   void clear ()
   {
     if (unlikely (!successful)) return;
 
-    if (items)
-      for (auto &_ : hb_iter (items, mask + 1))
-       _.clear ();
+    for (auto &_ : hb_iter (items, size ()))
+    {
+      /* Reconstruct items. */
+      _.~item_t ();
+      new (&_) item_t ();
+    }
 
     population = occupancy = 0;
   }
@@ -235,89 +362,109 @@ struct hb_hashmap_t
   bool is_empty () const { return population == 0; }
   explicit operator bool () const { return !is_empty (); }
 
+  uint32_t hash () const
+  {
+    return
+    + iter_items ()
+    | hb_reduce ([] (uint32_t h, const item_t &_) { return h ^ _.total_hash (); }, (uint32_t) 0u)
+    ;
+  }
+
+  bool is_equal (const hb_hashmap_t &other) const
+  {
+    if (population != other.population) return false;
+
+    for (auto pair : iter ())
+      if (other.get (pair.first) != pair.second)
+        return false;
+
+    return true;
+  }
+  bool operator == (const hb_hashmap_t &other) const { return is_equal (other); }
+  bool operator != (const hb_hashmap_t &other) const { return !is_equal (other); }
+
   unsigned int get_population () const { return population; }
 
+  void update (const hb_hashmap_t &other)
+  {
+    if (unlikely (!successful)) return;
+
+    hb_copy (other, *this);
+  }
+
   /*
    * Iterator
    */
-  auto iter () const HB_AUTO_RETURN
+
+  auto iter_items () const HB_AUTO_RETURN
   (
-    + hb_array (items, mask ? mask + 1 : 0)
+    + hb_iter (items, this->size ())
     | hb_filter (&item_t::is_real)
+  )
+  auto iter_ref () const HB_AUTO_RETURN
+  (
+    + this->iter_items ()
+    | hb_map (&item_t::get_pair_ref)
+  )
+  auto iter () const HB_AUTO_RETURN
+  (
+    + this->iter_items ()
     | hb_map (&item_t::get_pair)
   )
+  auto keys_ref () const HB_AUTO_RETURN
+  (
+    + this->iter_items ()
+    | hb_map (&item_t::get_key)
+  )
   auto keys () const HB_AUTO_RETURN
   (
-    + hb_array (items, mask ? mask + 1 : 0)
-    | hb_filter (&item_t::is_real)
-    | hb_map (&item_t::key)
+    + this->keys_ref ()
     | hb_map (hb_ridentity)
   )
+  auto values_ref () const HB_AUTO_RETURN
+  (
+    + this->iter_items ()
+    | hb_map (&item_t::get_value)
+  )
   auto values () const HB_AUTO_RETURN
   (
-    + hb_array (items, mask ? mask + 1 : 0)
-    | hb_filter (&item_t::is_real)
-    | hb_map (&item_t::value)
+    + this->values_ref ()
     | hb_map (hb_ridentity)
   )
 
-  /* Sink interface. */
-  hb_hashmap_t& operator << (const hb_pair_t<K, V>& v)
-  { set (v.first, v.second); return *this; }
-
-  protected:
-
-  template <typename VV>
-  bool set_with_hash (K key, uint32_t hash, VV&& value)
+  /* C iterator. */
+  bool next (int *idx,
+            K *key,
+            V *value) const
   {
-    if (unlikely (!successful)) return false;
-    const K kinv = hb_coerce<K> (kINVALID);
-    if (unlikely (key == kinv)) return true;
-    if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false;
-    unsigned int i = bucket_for_hash (key, hash);
+    unsigned i = (unsigned) (*idx + 1);
 
-    const V vinv = hb_coerce<V> (vINVALID);
-    if (value == vinv && items[i].key != key)
-      return true; /* Trying to delete non-existent key. */
+    unsigned count = size ();
+    while (i < count && !items[i].is_real ())
+      i++;
 
-    if (!items[i].is_unused ())
+    if (i >= count)
     {
-      occupancy--;
-      if (!items[i].is_tombstone ())
-       population--;
+      *idx = -1;
+      return false;
     }
 
-    items[i].key = key;
-    items[i].value = value;
-    items[i].hash = hash;
-
-    occupancy++;
-    if (!items[i].is_tombstone ())
-      population++;
+    *key = items[i].key;
+    *value = items[i].value;
 
+    *idx = (signed) i;
     return true;
   }
 
-  unsigned int bucket_for (K key) const
-  {
-    return bucket_for_hash (key, hb_hash (key));
-  }
-
-  unsigned int bucket_for_hash (K key, uint32_t hash) const
-  {
-    unsigned int i = hash % prime;
-    unsigned int step = 0;
-    unsigned int tombstone = (unsigned) -1;
-    while (!items[i].is_unused ())
-    {
-      if (items[i].hash == hash && items[i] == key)
-       return i;
-      if (tombstone == (unsigned) -1 && items[i].is_tombstone ())
-       tombstone = i;
-      i = (i + ++step) & mask;
-    }
-    return tombstone == (unsigned) -1 ? i : tombstone;
-  }
+  /* Sink interface. */
+  hb_hashmap_t& operator << (const hb_pair_t<K, V>& v)
+  { set (v.first, v.second); return *this; }
+  hb_hashmap_t& operator << (const hb_pair_t<K, V&&>& v)
+  { set (v.first, std::move (v.second)); return *this; }
+  hb_hashmap_t& operator << (const hb_pair_t<K&&, V>& v)
+  { set (std::move (v.first), v.second); return *this; }
+  hb_hashmap_t& operator << (const hb_pair_t<K&&, V&&>& v)
+  { set (std::move (v.first), std::move (v.second)); return *this; }
 
   static unsigned int prime_for (unsigned int shift)
   {
@@ -377,27 +524,23 @@ struct hb_hashmap_t
 
 struct hb_map_t : hb_hashmap_t<hb_codepoint_t,
                               hb_codepoint_t,
-                              hb_codepoint_t,
-                              hb_codepoint_t,
-                              HB_MAP_VALUE_INVALID,
-                              HB_MAP_VALUE_INVALID>
+                              true>
 {
   using hashmap = hb_hashmap_t<hb_codepoint_t,
                               hb_codepoint_t,
-                              hb_codepoint_t,
-                              hb_codepoint_t,
-                              HB_MAP_VALUE_INVALID,
-                              HB_MAP_VALUE_INVALID>;
+                              true>;
 
-  hb_map_t () = default;
   ~hb_map_t () = default;
-  hb_map_t (hb_map_t&) = default;
+  hb_map_t () : hashmap () {}
+  hb_map_t (const hb_map_t &o) : hashmap ((hashmap &) o) {}
+  hb_map_t (hb_map_t &&o) : hashmap (std::move ((hashmap &) o)) {}
   hb_map_t& operator= (const hb_map_t&) = default;
   hb_map_t& operator= (hb_map_t&&) = default;
-  hb_map_t (std::initializer_list<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> lst) : hashmap (lst) {}
+  hb_map_t (std::initializer_list<hb_codepoint_pair_t> lst) : hashmap (lst) {}
   template <typename Iterable,
            hb_requires (hb_is_iterable (Iterable))>
   hb_map_t (const Iterable &o) : hashmap (o) {}
 };
 
+
 #endif /* HB_MAP_HH */
index 3fea5d9..52ff4a8 100644 (file)
@@ -112,8 +112,7 @@ template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_ident
 template <typename T> using hb_add_pointer = decltype (_hb_try_add_pointer<T> (hb_prioritize));
 
 
-/* TODO Add feature-parity to std::decay. */
-template <typename T> using hb_decay = hb_remove_const<hb_remove_reference<T>>;
+template <typename T> using hb_decay = typename std::decay<T>::type;
 
 #define hb_is_convertible(From,To) std::is_convertible<From, To>::value
 
@@ -133,6 +132,18 @@ struct
 
   template <typename T> constexpr auto
   operator () (T *v) const HB_AUTO_RETURN (*v)
+
+  template <typename T> constexpr auto
+  operator () (const hb::shared_ptr<T>& v) const HB_AUTO_RETURN (*v)
+
+  template <typename T> constexpr auto
+  operator () (hb::shared_ptr<T>& v) const HB_AUTO_RETURN (*v)
+  
+  template <typename T> constexpr auto
+  operator () (const hb::unique_ptr<T>& v) const HB_AUTO_RETURN (*v)
+
+  template <typename T> constexpr auto
+  operator () (hb::unique_ptr<T>& v) const HB_AUTO_RETURN (*v)
 }
 HB_FUNCOBJ (hb_deref);
 
@@ -142,8 +153,8 @@ struct hb_reference_wrapper
   hb_reference_wrapper (T v) : v (v) {}
   bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
   bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
-  operator T () const { return v; }
-  T get () const { return v; }
+  operator T& () { return v; }
+  T& get () { return v; }
   T v;
 };
 template <typename T>
@@ -152,8 +163,8 @@ struct hb_reference_wrapper<T&>
   hb_reference_wrapper (T& v) : v (std::addressof (v)) {}
   bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
   bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
-  operator T& () const { return *v; }
-  T& get () const { return *v; }
+  operator T& () { return *v; }
+  T& get () { return *v; }
   T* v;
 };
 
@@ -188,6 +199,19 @@ template <> struct hb_int_max<signed long long>            : hb_integral_constant<signed l
 template <> struct hb_int_max<unsigned long long>      : hb_integral_constant<unsigned long long,      ULLONG_MAX>     {};
 #define hb_int_max(T) hb_int_max<T>::value
 
+#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
+#define hb_is_trivially_copyable(T) __has_trivial_copy(T)
+#define hb_is_trivially_copy_assignable(T) __has_trivial_assign(T)
+#define hb_is_trivially_constructible(T) __has_trivial_constructor(T)
+#define hb_is_trivially_copy_constructible(T) __has_trivial_copy_constructor(T)
+#define hb_is_trivially_destructible(T) __has_trivial_destructor(T)
+#else
+#define hb_is_trivially_copyable(T) std::is_trivially_copyable<T>::value
+#define hb_is_trivially_copy_assignable(T) std::is_trivially_copy_assignable<T>::value
+#define hb_is_trivially_constructible(T) std::is_trivially_constructible<T>::value
+#define hb_is_trivially_copy_constructible(T) std::is_trivially_copy_constructible<T>::value
+#define hb_is_trivially_destructible(T) std::is_trivially_destructible<T>::value
+#endif
 
 /* Class traits. */
 
index d40fdea..f7649ab 100644 (file)
@@ -30,6 +30,9 @@
 
 #include "hb.hh"
 
+/* Variations of this code exist in hb-coretext.cc as well
+ * as hb-aat-map.cc... */
+
 typedef struct hb_ms_feature_t {
   uint32_t tag_le;
   uint32_t value;
@@ -166,7 +169,7 @@ hb_ms_setup_features (const hb_feature_t                *features,
     {
       auto *feature = active_features.lsearch (event->feature);
       if (feature)
-        active_features.remove (feature - active_features.arrayZ);
+        active_features.remove_ordered (feature - active_features.arrayZ);
     }
   }
 
diff --git a/src/hb-multimap.hh b/src/hb-multimap.hh
new file mode 100644 (file)
index 0000000..0184279
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright © 2022  Behdad Esfahbod
+ *
+ *  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_MULTIMAP_HH
+#define HB_MULTIMAP_HH
+
+#include "hb.hh"
+#include "hb-map.hh"
+#include "hb-vector.hh"
+
+
+/*
+ * hb_multimap_t
+ */
+
+struct hb_multimap_t
+{
+  void add (hb_codepoint_t k, hb_codepoint_t v)
+  {
+    hb_vector_t<hb_codepoint_t> *m;
+    if (multiples.has (k, &m))
+    {
+      m->push (v);
+      return;
+    }
+
+    hb_codepoint_t *old_v;
+    if (singulars.has (k, &old_v))
+    {
+      hb_codepoint_t old = *old_v;
+      singulars.del (k);
+
+      multiples.set (k, hb_vector_t<hb_codepoint_t> {old, v});
+      return;
+    }
+
+    singulars.set (k, v);
+  }
+
+  hb_array_t<const hb_codepoint_t> get (hb_codepoint_t k) const
+  {
+    const hb_codepoint_t *v;
+    if (singulars.has (k, &v))
+      return hb_array (v, 1);
+
+    hb_vector_t<hb_codepoint_t> *m;
+    if (multiples.has (k, &m))
+      return m->as_array ();
+
+    return hb_array_t<const hb_codepoint_t> ();
+  }
+
+  bool in_error () const
+  {
+    if (singulars.in_error () || multiples.in_error ())
+      return true;
+    for (const auto &m : multiples.values_ref ())
+      if (m.in_error ())
+        return true;
+    return false;
+  }
+
+  void alloc (unsigned size)
+  {
+    singulars.alloc (size);
+  }
+
+  protected:
+  hb_map_t singulars;
+  hb_hashmap_t<hb_codepoint_t, hb_vector_t<hb_codepoint_t>> multiples;
+};
+
+
+
+#endif /* HB_MULTIMAP_HH */
index 6914b22..e329d98 100644 (file)
@@ -60,7 +60,7 @@ typedef pthread_mutex_t hb_mutex_impl_t;
 #elif !defined(HB_NO_MT) && !defined(HB_MUTEX_IMPL_STD_MUTEX) && defined(_WIN32)
 
 typedef CRITICAL_SECTION hb_mutex_impl_t;
-#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
 #define hb_mutex_impl_init(M)  InitializeCriticalSectionEx (M, 0, 0)
 #else
 #define hb_mutex_impl_init(M)  InitializeCriticalSection (M)
@@ -97,6 +97,9 @@ struct hb_mutex_t
   /* Create space for, but do not initialize m. */
   alignas(hb_mutex_impl_t) char m[sizeof (hb_mutex_impl_t)];
 
+  hb_mutex_t () { init (); }
+  ~hb_mutex_t () { fini (); }
+
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wcast-align"
   void init   () { hb_mutex_impl_init   ((hb_mutex_impl_t *) m); }
@@ -108,10 +111,11 @@ struct hb_mutex_t
 
 struct hb_lock_t
 {
-  hb_lock_t (hb_mutex_t &mutex_) : mutex (mutex_) { mutex.lock (); }
-  ~hb_lock_t () { mutex.unlock (); }
+  hb_lock_t (hb_mutex_t &mutex_) : mutex (&mutex_) { mutex->lock (); }
+  hb_lock_t (hb_mutex_t *mutex_) : mutex (mutex_) { if (mutex) mutex->lock (); }
+  ~hb_lock_t () { if (mutex) mutex->unlock (); }
   private:
-  hb_mutex_t &mutex;
+  hb_mutex_t *mutex;
 };
 
 
index db38a4d..854485d 100644 (file)
 
 /* Global nul-content Null pool.  Enlarge as necessary. */
 
-#define HB_NULL_POOL_SIZE 384
+#define HB_NULL_POOL_SIZE 640
+
+template <typename T, typename>
+struct _hb_has_min_size : hb_false_type {};
+template <typename T>
+struct _hb_has_min_size<T, hb_void_t<decltype (T::min_size)>>
+       : hb_true_type {};
+template <typename T>
+using hb_has_min_size = _hb_has_min_size<T, void>;
+#define hb_has_min_size(T) hb_has_min_size<T>::value
+
+template <typename T, typename>
+struct _hb_has_null_size : hb_false_type {};
+template <typename T>
+struct _hb_has_null_size<T, hb_void_t<decltype (T::null_size)>>
+       : hb_true_type {};
+template <typename T>
+using hb_has_null_size = _hb_has_null_size<T, void>;
+#define hb_has_null_size(T) hb_has_null_size<T>::value
 
 /* Use SFINAE to sniff whether T has min_size; in which case return the larger
  * of sizeof(T) and T::null_size, otherwise return sizeof(T).
@@ -67,7 +85,7 @@ using hb_null_size = _hb_null_size<T, void>;
 template <typename T, typename>
 struct _hb_static_size : hb_integral_constant<unsigned, sizeof (T)> {};
 template <typename T>
-struct _hb_static_size<T, hb_void_t<decltype (T::min_size)>> : hb_integral_constant<unsigned, T::static_size> {};
+struct _hb_static_size<T, hb_void_t<decltype (T::static_size)>> : hb_integral_constant<unsigned, T::static_size> {};
 template <typename T>
 using hb_static_size = _hb_static_size<T, void>;
 #define hb_static_size(T) hb_static_size<T>::value
@@ -108,7 +126,7 @@ struct NullHelper
 /* 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]; \
+       extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[hb_null_size (Namespace::Type)]; \
        template <> \
        struct Null<Namespace::Type> { \
          static Namespace::Type const & get_null () { \
@@ -117,8 +135,19 @@ struct NullHelper
        }; \
        namespace Namespace { \
        static_assert (true, "") /* Require semicolon after. */
+#define DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1(Namespace, Type, Size) \
+       } /* Close namespace. */ \
+       extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Size]; \
+       template <typename Spec> \
+       struct Null<Namespace::Type<Spec>> { \
+         static Namespace::Type<Spec> const & get_null () { \
+           return *reinterpret_cast<const Namespace::Type<Spec> *> (_hb_Null_##Namespace##_##Type); \
+         } \
+       }; \
+       namespace Namespace { \
+       static_assert (true, "") /* Require semicolon after. */
 #define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \
-       const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size]
+       const unsigned char _hb_Null_##Namespace##_##Type[sizeof (_hb_Null_##Namespace##_##Type)]
 
 /* Specializations for arbitrary-content Null objects expressed as struct initializer. */
 #define DECLARE_NULL_INSTANCE(Type) \
@@ -147,7 +176,7 @@ 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));
+  memcpy (obj, std::addressof (Null (Type)), sizeof (*obj));
   return *obj;
 }
 template <typename QType>
@@ -182,11 +211,11 @@ struct hb_nonnull_ptr_t
   T * operator = (T *v_)   { return v = v_; }
   T * operator -> () const { return get (); }
   T & operator * () const  { return *get (); }
-  T ** operator & () const { return &v; }
+  T ** operator & () const { return std::addressof (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 () const { return v ? v : const_cast<T *> (std::addressof (Null (T))); }
   T * get_raw () const { return v; }
 
   private:
index 6e4f3f7..c52b284 100644 (file)
@@ -24,7 +24,6 @@
  */
 
 #include "hb.hh"
-#include "hb-machinery.hh"
 #include "hb-number.hh"
 #include "hb-number-parser.hh"
 
index 4b5bc32..e2c2c33 100644 (file)
@@ -69,7 +69,7 @@ struct hb_lockable_set_t
       item = items.push (v);
       l.unlock ();
     }
-    return item;
+    return items.in_error () ? nullptr : item;
   }
 
   template <typename T>
@@ -80,7 +80,7 @@ struct hb_lockable_set_t
     if (item)
     {
       item_t old = *item;
-      *item = items[items.length - 1];
+      *item = std::move (items.tail ());
       items.pop ();
       l.unlock ();
       old.fini ();
@@ -123,7 +123,7 @@ struct hb_lockable_set_t
     l.lock ();
     while (items.length)
     {
-      item_t old = items[items.length - 1];
+      item_t old = items.tail ();
       items.pop ();
       l.unlock ();
       old.fini ();
@@ -144,14 +144,14 @@ struct hb_reference_count_t
 {
   mutable hb_atomic_int_t ref_count;
 
-  void init (int v = 1) { ref_count.set_relaxed (v); }
-  int get_relaxed () const { return ref_count.get_relaxed (); }
+  void init (int v = 1) { ref_count = v; }
+  int get_relaxed () const { return ref_count; }
   int inc () const { return ref_count.inc (); }
   int dec () const { return ref_count.dec (); }
-  void fini () { ref_count.set_relaxed (-0x0000DEAD); }
+  void fini () { ref_count = -0x0000DEAD; }
 
-  bool is_inert () const { return !ref_count.get_relaxed (); }
-  bool is_valid () const { return ref_count.get_relaxed () > 0; }
+  bool is_inert () const { return !ref_count; }
+  bool is_valid () const { return ref_count > 0; }
 };
 
 
@@ -175,14 +175,34 @@ struct hb_user_data_array_t
 
   void init () { lock.init (); items.init (); }
 
-  HB_INTERNAL bool set (hb_user_data_key_t *key,
-                       void *              data,
-                       hb_destroy_func_t   destroy,
-                       hb_bool_t           replace);
+  void fini () { items.fini (lock); lock.fini (); }
+
+  bool set (hb_user_data_key_t *key,
+           void *              data,
+           hb_destroy_func_t   destroy,
+           hb_bool_t           replace)
+  {
+    if (!key)
+      return false;
 
-  HB_INTERNAL void *get (hb_user_data_key_t *key);
+    if (replace) {
+      if (!data && !destroy) {
+       items.remove (key, lock);
+       return true;
+      }
+    }
+    hb_user_data_item_t item = {key, data, destroy};
+    bool ret = !!items.replace_or_insert (item, lock, (bool) replace);
 
-  void fini () { items.fini (lock); lock.fini (); }
+    return ret;
+  }
+
+  void *get (hb_user_data_key_t *key)
+  {
+    hb_user_data_item_t item = {nullptr, nullptr, nullptr};
+
+    return items.find (key, &item, lock) ? item.data : nullptr;
+  }
 };
 
 
@@ -214,23 +234,26 @@ static inline void hb_object_trace (const Type *obj, const char *function)
             obj ? obj->header.ref_count.get_relaxed () : 0);
 }
 
-template <typename Type>
-static inline Type *hb_object_create ()
+template <typename Type, typename ...Ts>
+static inline Type *hb_object_create (Ts... ds)
 {
   Type *obj = (Type *) hb_calloc (1, sizeof (Type));
 
   if (unlikely (!obj))
     return obj;
 
+  new (obj) Type (std::forward<Ts> (ds)...);
+
   hb_object_init (obj);
   hb_object_trace (obj, HB_FUNC);
+
   return obj;
 }
 template <typename Type>
 static inline void hb_object_init (Type *obj)
 {
   obj->header.ref_count.init ();
-  obj->header.writable.set_relaxed (true);
+  obj->header.writable = true;
   obj->header.user_data.init ();
 }
 template <typename Type>
@@ -241,12 +264,12 @@ static inline bool hb_object_is_valid (const Type *obj)
 template <typename Type>
 static inline bool hb_object_is_immutable (const Type *obj)
 {
-  return !obj->header.writable.get_relaxed ();
+  return !obj->header.writable;
 }
 template <typename Type>
 static inline void hb_object_make_immutable (const Type *obj)
 {
-  obj->header.writable.set_relaxed (false);
+  obj->header.writable = false;
 }
 template <typename Type>
 static inline Type *hb_object_reference (Type *obj)
@@ -269,18 +292,22 @@ static inline bool hb_object_destroy (Type *obj)
     return false;
 
   hb_object_fini (obj);
+
+  if (!std::is_trivially_destructible<Type>::value)
+    obj->~Type ();
+
   return true;
 }
 template <typename Type>
 static inline void hb_object_fini (Type *obj)
 {
   obj->header.ref_count.fini (); /* Do this before user_data */
-  hb_user_data_array_t *user_data = obj->header.user_data.get ();
+  hb_user_data_array_t *user_data = obj->header.user_data.get_acquire ();
   if (user_data)
   {
     user_data->fini ();
     hb_free (user_data);
-    user_data = nullptr;
+    obj->header.user_data.set_relaxed (nullptr);
   }
 }
 template <typename Type>
@@ -295,7 +322,7 @@ static inline bool hb_object_set_user_data (Type               *obj,
   assert (hb_object_is_valid (obj));
 
 retry:
-  hb_user_data_array_t *user_data = obj->header.user_data.get ();
+  hb_user_data_array_t *user_data = obj->header.user_data.get_acquire ();
   if (unlikely (!user_data))
   {
     user_data = (hb_user_data_array_t *) hb_calloc (sizeof (hb_user_data_array_t), 1);
@@ -320,7 +347,7 @@ static inline void *hb_object_get_user_data (Type               *obj,
   if (unlikely (!obj || obj->header.is_inert ()))
     return nullptr;
   assert (hb_object_is_valid (obj));
-  hb_user_data_array_t *user_data = obj->header.user_data.get ();
+  hb_user_data_array_t *user_data = obj->header.user_data.get_acquire ();
   if (!user_data)
     return nullptr;
   return user_data->get (key);
index 6eee582..04f144a 100644 (file)
@@ -90,7 +90,7 @@ typedef struct OpenTypeOffsetTable
   {
     if (table_count)
     {
-      + tables.sub_array (start_offset, table_count)
+      + tables.as_array ().sub_array (start_offset, table_count)
       | hb_map (&TableRecord::tag)
       | hb_sink (hb_array (table_tags, *table_count))
       ;
@@ -131,7 +131,7 @@ typedef struct OpenTypeOffsetTable
     sfnt_version = sfnt_tag;
     /* Take space for numTables, searchRange, entrySelector, RangeShift
      * and the TableRecords themselves.  */
-    unsigned num_items = it.len ();
+    unsigned num_items = hb_len (it);
     if (unlikely (!tables.serialize (c, num_items))) return_trace (false);
 
     const char *dir_end = (const char *) c->head;
@@ -145,7 +145,7 @@ typedef struct OpenTypeOffsetTable
       unsigned len = blob->length;
 
       /* Allocate room for the table and copy it. */
-      char *start = (char *) c->allocate_size<void> (len);
+      char *start = (char *) c->allocate_size<void> (len, false);
       if (unlikely (!start)) return false;
 
       TableRecord &rec = tables.arrayZ[i];
@@ -158,7 +158,7 @@ typedef struct OpenTypeOffsetTable
         return_trace (false);
 
       if (likely (len))
-       memcpy (start, blob->data, len);
+       hb_memcpy (start, blob->data, len);
 
       /* 4-byte alignment. */
       c->align (4);
index 7e52417..d3fdd1c 100644 (file)
@@ -33,6 +33,7 @@
 #include "hb-blob.hh"
 #include "hb-face.hh"
 #include "hb-machinery.hh"
+#include "hb-meta.hh"
 #include "hb-subset.hh"
 
 
@@ -104,7 +105,7 @@ struct IntType
   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:
   BEInt<Type, Size> v;
@@ -140,27 +141,29 @@ 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
+template <typename Type, unsigned fraction_bits>
+struct HBFixed : Type
 {
-  F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; }
-  // 16384 means 1<<14
-  float to_float () const  { return ((int32_t) v) / 16384.f; }
-  void set_float (float f) { v = roundf (f * 16384.f); }
+  static constexpr float shift = (float) (1 << fraction_bits);
+  static_assert (Type::static_size * 8 > fraction_bits, "");
+
+  operator signed () const = delete;
+  operator unsigned () const = delete;
+  typename Type::type to_int () const { return Type::v; }
+  void set_int (typename Type::type i ) { Type::v = i; }
+  float to_float (float offset = 0) const  { return ((int32_t) Type::v + offset) / shift; }
+  void set_float (float f) { Type::v = roundf (f * shift); }
   public:
-  DEFINE_SIZE_STATIC (2);
+  DEFINE_SIZE_STATIC (Type::static_size);
 };
 
+/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
+using F2DOT14 = HBFixed<HBINT16, 14>;
+using F4DOT12 = HBFixed<HBINT16, 12>;
+using F6DOT10 = HBFixed<HBINT16, 10>;
+
 /* 32-bit signed fixed-point number (16.16). */
-struct HBFixed : HBINT32
-{
-  HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; }
-  // 65536 means 1<<16
-  float to_float () const  { return ((int32_t) v) / 65536.f; }
-  void set_float (float f) { v = roundf (f * 65536.f); }
-  public:
-  DEFINE_SIZE_STATIC (4);
-};
+using F16DOT16 = HBFixed<HBINT32, 16>;
 
 /* Date represented in number of seconds since 12:00 midnight, January 1,
  * 1904. The value is represented as a signed 64-bit integer. */
@@ -169,7 +172,7 @@ struct LONGDATETIME
   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:
   HBINT32 major;
@@ -195,6 +198,10 @@ struct HBGlyphID16 : HBUINT16
 {
   HBGlyphID16& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
 };
+struct HBGlyphID24 : HBUINT24
+{
+  HBGlyphID24& operator = (uint32_t i) { HBUINT24::operator= (i); return *this; }
+};
 
 /* Script/language-system/feature index */
 struct Index : HBUINT16 {
@@ -207,6 +214,12 @@ typedef Index NameID;
 
 struct VarIdx : HBUINT32 {
   static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu;
+  static_assert (NO_VARIATION == HB_OT_LAYOUT_NO_VARIATIONS_INDEX, "");
+  static uint32_t add (uint32_t i, unsigned short v)
+  {
+    if (i == NO_VARIATION) return i;
+    return i + v;
+  }
   VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
 };
 DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx);
@@ -299,6 +312,12 @@ struct _hb_has_null<Type, true>
 template <typename Type, typename OffsetType, bool has_null=true>
 struct OffsetTo : Offset<OffsetType, has_null>
 {
+  using target_t = Type;
+
+  // Make sure Type is not unbounded; works only for types that are fully defined at OffsetTo time.
+  static_assert (has_null == false ||
+                (hb_has_null_size (Type) || !hb_has_min_size (Type)), "");
+
   HB_DELETE_COPY_ASSIGN (OffsetTo);
   OffsetTo () = default;
 
@@ -399,12 +418,15 @@ struct OffsetTo : Offset<OffsetType, has_null>
   {
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this))) return_trace (false);
-    if (unlikely (this->is_null ())) return_trace (true);
+    //if (unlikely (this->is_null ())) return_trace (true);
     if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false);
     return_trace (true);
   }
 
   template <typename ...Ts>
+#ifndef HB_OPTIMIZE_SIZE
+  HB_ALWAYS_INLINE
+#endif
   bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
@@ -445,22 +467,16 @@ struct UnsizedArrayOf
 
   HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf);
 
-  const Type& operator [] (int i_) const
+  const Type& operator [] (unsigned int i) const
   {
-    unsigned int i = (unsigned int) i_;
-    const Type *p = &arrayZ[i];
-    if (unlikely (p < arrayZ)) return Null (Type); /* Overflowed. */
-    return *p;
+    return arrayZ[i];
   }
-  Type& operator [] (int i_)
+  Type& operator [] (unsigned int i)
   {
-    unsigned int i = (unsigned int) i_;
-    Type *p = &arrayZ[i];
-    if (unlikely (p < arrayZ)) return Crap (Type); /* Overflowed. */
-    return *p;
+    return arrayZ[i];
   }
 
-  unsigned int get_size (unsigned int len) const
+  static unsigned int get_size (unsigned int len)
   { return len * Type::static_size; }
 
   template <typename T> operator T * () { return arrayZ; }
@@ -485,10 +501,10 @@ struct UnsizedArrayOf
   void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1)
   { as_array (len).qsort (start, end); }
 
-  bool serialize (hb_serialize_context_t *c, unsigned int items_len)
+  bool serialize (hb_serialize_context_t *c, unsigned int items_len, bool clear = true)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend (this, items_len))) return_trace (false);
+    if (unlikely (!c->extend_size (this, get_size (items_len), clear))) return_trace (false);
     return_trace (true);
   }
   template <typename Iterator,
@@ -496,8 +512,8 @@ struct UnsizedArrayOf
   bool serialize (hb_serialize_context_t *c, Iterator items)
   {
     TRACE_SERIALIZE (this);
-    unsigned count = items.len ();
-    if (unlikely (!serialize (c, count))) return_trace (false);
+    unsigned count = hb_len (items);
+    if (unlikely (!serialize (c, count, false))) return_trace (false);
     /* TODO Umm. Just exhaust the iterator instead?  Being extra
      * cautious right now.. */
     for (unsigned i = 0; i < count; i++, ++items)
@@ -514,11 +530,12 @@ struct UnsizedArrayOf
   }
 
   template <typename ...Ts>
+  HB_ALWAYS_INLINE
   bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
-    if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true);
+    if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
        return_trace (false);
@@ -549,14 +566,16 @@ struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_
   {
     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. */
+    if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Null (Type); /* Overflowed. */
+    _hb_compiler_memory_r_barrier ();
     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. */
+    if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Crap (Type); /* Overflowed. */
+    _hb_compiler_memory_r_barrier ();
     return this+*p;
   }
 
@@ -607,12 +626,14 @@ struct ArrayOf
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= len)) return Null (Type);
+    _hb_compiler_memory_r_barrier ();
     return arrayZ[i];
   }
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= len)) return Crap (Type);
+    _hb_compiler_memory_r_barrier ();
     return arrayZ[i];
   }
 
@@ -634,14 +655,9 @@ struct ArrayOf
   operator   iter_t () const { return   iter (); }
   operator writer_t ()       { return writer (); }
 
-  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); }
+  /* Faster range-based for loop. */
+  const Type *begin () const { return arrayZ; }
+  const Type *end () const { return arrayZ + len; }
 
   template <typename T>
   Type &lsearch (const T &x, Type &not_found = Crap (Type))
@@ -655,15 +671,15 @@ struct ArrayOf
              unsigned int to_store = (unsigned int) -1) const
   { return as_array ().lfind (x, i, not_found, to_store); }
 
-  void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1)
-  { as_array ().qsort (start, end); }
+  void qsort ()
+  { as_array ().qsort (); }
 
-  HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len)
+  HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len, bool clear = true)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (this))) return_trace (false);
     c->check_assign (len, items_len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
-    if (unlikely (!c->extend (this))) return_trace (false);
+    if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false);
     return_trace (true);
   }
   template <typename Iterator,
@@ -671,8 +687,8 @@ struct ArrayOf
   HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items)
   {
     TRACE_SERIALIZE (this);
-    unsigned count = items.len ();
-    if (unlikely (!serialize (c, count))) return_trace (false);
+    unsigned count = hb_len (items);
+    if (unlikely (!serialize (c, count, false))) return_trace (false);
     /* TODO Umm. Just exhaust the iterator instead?  Being extra
      * cautious right now.. */
     for (unsigned i = 0; i < count; i++, ++items)
@@ -703,11 +719,12 @@ struct ArrayOf
   }
 
   template <typename ...Ts>
+  HB_ALWAYS_INLINE
   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
-    if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true);
+    if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
@@ -718,7 +735,7 @@ struct ArrayOf
   bool sanitize_shallow (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (len.sanitize (c) && c->check_array (arrayZ, len));
+    return_trace (len.sanitize (c) && c->check_array_sized (arrayZ, len, sizeof (LenType)));
   }
 
   public:
@@ -728,6 +745,7 @@ struct ArrayOf
   DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
 };
 template <typename Type> using Array16Of = ArrayOf<Type, HBUINT16>;
+template <typename Type> using Array24Of = ArrayOf<Type, HBUINT24>;
 template <typename Type> using Array32Of = ArrayOf<Type, HBUINT32>;
 using PString = ArrayOf<HBUINT8, HBUINT8>;
 
@@ -737,26 +755,28 @@ template <typename Type> using Array16OfOffset32To = ArrayOf<OffsetTo<Type, HBUI
 template <typename Type> using Array32OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>;
 
 /* Array of offsets relative to the beginning of the array itself. */
-template <typename Type>
-struct List16OfOffset16To : Array16OfOffset16To<Type>
+template <typename Type, typename OffsetType>
+struct List16OfOffsetTo : ArrayOf<OffsetTo<Type, OffsetType>, HBUINT16>
 {
   const Type& operator [] (int i_) const
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= this->len)) return Null (Type);
+    _hb_compiler_memory_r_barrier ();
     return this+this->arrayZ[i];
   }
   const Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= this->len)) return Crap (Type);
+    _hb_compiler_memory_r_barrier ();
     return this+this->arrayZ[i];
   }
 
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    struct List16OfOffset16To<Type> *out = c->serializer->embed (*this);
+    struct List16OfOffsetTo *out = c->serializer->embed (*this);
     if (unlikely (!out)) return_trace (false);
     unsigned int count = this->len;
     for (unsigned int i = 0; i < count; i++)
@@ -768,12 +788,15 @@ struct List16OfOffset16To : Array16OfOffset16To<Type>
   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
-    return_trace (Array16OfOffset16To<Type>::sanitize (c, this, std::forward<Ts> (ds)...));
+    return_trace ((Array16Of<OffsetTo<Type, OffsetType>>::sanitize (c, this, std::forward<Ts> (ds)...)));
   }
 };
 
+template <typename Type>
+using List16OfOffset16To = List16OfOffsetTo<Type, HBUINT16>;
+
 /* An array starting at second element. */
-template <typename Type, typename LenType=HBUINT16>
+template <typename Type, typename LenType>
 struct HeadlessArrayOf
 {
   static constexpr unsigned item_size = Type::static_size;
@@ -784,12 +807,14 @@ struct HeadlessArrayOf
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= lenP1 || !i)) return Null (Type);
+    _hb_compiler_memory_r_barrier ();
     return arrayZ[i-1];
   }
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= lenP1 || !i)) return Crap (Type);
+    _hb_compiler_memory_r_barrier ();
     return arrayZ[i-1];
   }
   unsigned int get_size () const
@@ -808,21 +833,25 @@ struct HeadlessArrayOf
   operator   iter_t () const { return   iter (); }
   operator writer_t ()       { return writer (); }
 
-  bool serialize (hb_serialize_context_t *c, unsigned int items_len)
+  /* Faster range-based for loop. */
+  const Type *begin () const { return arrayZ; }
+  const Type *end () const { return arrayZ + get_length (); }
+
+  HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned int items_len, bool clear = true)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (this))) return_trace (false);
     c->check_assign (lenP1, items_len + 1, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
-    if (unlikely (!c->extend (this))) return_trace (false);
+    if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false);
     return_trace (true);
   }
   template <typename Iterator,
            hb_requires (hb_is_source_of (Iterator, Type))>
-  bool serialize (hb_serialize_context_t *c, Iterator items)
+  HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items)
   {
     TRACE_SERIALIZE (this);
-    unsigned count = items.len ();
-    if (unlikely (!serialize (c, count))) return_trace (false);
+    unsigned count = hb_len (items);
+    if (unlikely (!serialize (c, count, false))) return_trace (false);
     /* TODO Umm. Just exhaust the iterator instead?  Being extra
      * cautious right now.. */
     for (unsigned i = 0; i < count; i++, ++items)
@@ -831,11 +860,12 @@ struct HeadlessArrayOf
   }
 
   template <typename ...Ts>
+  HB_ALWAYS_INLINE
   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
-    if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true);
+    if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
     unsigned int count = get_length ();
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
@@ -848,7 +878,7 @@ struct HeadlessArrayOf
   {
     TRACE_SANITIZE (this);
     return_trace (lenP1.sanitize (c) &&
-                 (!lenP1 || c->check_array (arrayZ, lenP1 - 1)));
+                 (!lenP1 || c->check_array_sized (arrayZ, lenP1 - 1, sizeof (LenType))));
   }
 
   public:
@@ -857,6 +887,7 @@ struct HeadlessArrayOf
   public:
   DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
 };
+template <typename Type> using HeadlessArray16Of = HeadlessArrayOf<Type, HBUINT16>;
 
 /* An array storing length-1. */
 template <typename Type, typename LenType=HBUINT16>
@@ -868,23 +899,26 @@ struct ArrayOfM1
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i > lenM1)) return Null (Type);
+    _hb_compiler_memory_r_barrier ();
     return arrayZ[i];
   }
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i > lenM1)) return Crap (Type);
+    _hb_compiler_memory_r_barrier ();
     return arrayZ[i];
   }
   unsigned int get_size () const
   { return lenM1.static_size + (lenM1 + 1) * Type::static_size; }
 
   template <typename ...Ts>
+  HB_ALWAYS_INLINE
   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
-    if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true);
+    if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
     unsigned int count = lenM1 + 1;
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
@@ -897,7 +931,7 @@ struct ArrayOfM1
   {
     TRACE_SANITIZE (this);
     return_trace (lenM1.sanitize (c) &&
-                 (c->check_array (arrayZ, lenM1 + 1)));
+                 (c->check_array_sized (arrayZ, lenM1 + 1, sizeof (LenType))));
   }
 
   public:
@@ -922,14 +956,9 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
   operator   iter_t () const { return   iter (); }
   operator writer_t ()       { return writer (); }
 
-  hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
-  { return as_array ().sub_array (start_offset, count); }
-  hb_sorted_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_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
-  { return as_array ().sub_array (start_offset, count); }
-  hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
-  { return as_array ().sub_array (start_offset, count); }
+  /* Faster range-based for loop. */
+  const Type *begin () const { return this->arrayZ; }
+  const Type *end () const { return this->arrayZ + this->len; }
 
   bool serialize (hb_serialize_context_t *c, unsigned int items_len)
   {
@@ -960,6 +989,7 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
 };
 
 template <typename Type> using SortedArray16Of = SortedArrayOf<Type, HBUINT16>;
+template <typename Type> using SortedArray24Of = SortedArrayOf<Type, HBUINT24>;
 template <typename Type> using SortedArray32Of = SortedArrayOf<Type, HBUINT32>;
 
 /*
@@ -1052,12 +1082,14 @@ struct VarSizedBinSearchArrayOf
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= get_length ())) return Null (Type);
+    _hb_compiler_memory_r_barrier ();
     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);
+    _hb_compiler_memory_r_barrier ();
     return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
   }
   unsigned int get_length () const
@@ -1066,11 +1098,12 @@ struct VarSizedBinSearchArrayOf
   { return header.static_size + header.nUnits * header.unitSize; }
 
   template <typename ...Ts>
+  HB_ALWAYS_INLINE
   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
-    if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true);
+    if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
     unsigned int count = get_length ();
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!(*this)[i].sanitize (c, std::forward<Ts> (ds)...)))
index c102c15..923a32b 100644 (file)
@@ -46,318 +46,250 @@ template<typename Type>
 static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset)
 { return offset ? StructAtOffset<Type> (P, offset) : Null (Type); }
 
-inline unsigned int calcOffSize (unsigned int dataSize)
-{
-  unsigned int size = 1;
-  unsigned int offset = dataSize + 1;
-  while (offset & ~0xFF)
-  {
-    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;
+  unsigned 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>
+
+using str_buff_t = hb_vector_t<unsigned char>;
+using str_buff_vec_t = hb_vector_t<str_buff_t>;
+using glyph_to_sid_map_t = hb_vector_t<code_pair_t>;
+
+struct length_f_t
 {
-  unsigned int total_size () const
-  {
-    unsigned int size = 0;
-    for (unsigned int i = 0; i < length; i++)
-      size += (*this)[i].length;
-    return size;
-  }
+  template <typename Iterable,
+           hb_requires (hb_is_iterable (Iterable))>
+  unsigned operator () (const Iterable &_) const { return hb_len (hb_iter (_)); }
 
-  private:
-  typedef hb_vector_t<str_buff_t> SUPER;
-};
+  unsigned operator () (unsigned _) const { return _; }
+}
+HB_FUNCOBJ (length_f);
 
 /* CFF INDEX */
 template <typename COUNT>
 struct CFFIndex
 {
-  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); }
-
-  CFFIndex *copy (hb_serialize_context_t *c) const
-  {
-    TRACE_SERIALIZE (this);
-    unsigned int size = get_size ();
-    CFFIndex *out = c->allocate_size<CFFIndex> (size);
-    if (likely (out))
-      memcpy (out, this, size);
-    return_trace (out);
-  }
-
-  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)) return_trace (false);
-    memcpy (dest, &src, size);
-    return_trace (true);
-  }
+  { return offSize * (count + 1); }
 
+  template <typename Iterable,
+           hb_requires (hb_is_iterable (Iterable))>
   bool serialize (hb_serialize_context_t *c,
-                 unsigned int offSize_,
-                 const byte_str_array_t &byteArray)
+                 const Iterable &iterable,
+                 const unsigned *p_data_size = nullptr)
   {
     TRACE_SERIALIZE (this);
-    if (byteArray.length == 0)
-    {
-      COUNT *dest = c->allocate_min<COUNT> ();
-      if (unlikely (!dest)) return_trace (false);
-      *dest = 0;
-    }
+    unsigned data_size;
+    if (p_data_size)
+      data_size = *p_data_size;
     else
-    {
-      /* serialize CFFIndex header */
-      if (unlikely (!c->extend_min (this))) return_trace (false);
-      this->count = byteArray.length;
-      this->offSize = 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);
+      total_size (iterable, &data_size);
 
-      /* serialize data */
-      for (unsigned int i = 0; i < byteArray.length; i++)
+    auto it = hb_iter (iterable);
+    if (unlikely (!serialize_header (c, +it, data_size))) return_trace (false);
+    unsigned char *ret = c->allocate_size<unsigned char> (data_size, false);
+    if (unlikely (!ret)) return_trace (false);
+    for (const auto &_ : +it)
+    {
+      unsigned len = _.length;
+      if (!len)
+       continue;
+      if (len <= 1)
       {
-       const byte_str_t &bs = byteArray[i];
-       unsigned char *dest = c->allocate_size<unsigned char> (bs.length);
-       if (unlikely (!dest)) return_trace (false);
-       memcpy (dest, &bs[0], bs.length);
+       *ret++ = *_.arrayZ;
+       continue;
       }
+      hb_memcpy (ret, _.arrayZ, len);
+      ret += len;
     }
     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;
-  }
-
-  template <typename Iterator,
-           hb_requires (hb_is_iterator (Iterator))>
-  bool serialize (hb_serialize_context_t *c,
-                 Iterator it)
-  {
-    TRACE_SERIALIZE (this);
-    if (it.len () == 0)
-    {
-      COUNT *dest = c->allocate_min<COUNT> ();
-      if (unlikely (!dest)) return_trace (false);
-      *dest = 0;
-    }
-    else
-    {
-      serialize_header(c, + it | hb_map ([] (const byte_str_t &_) { return _.length; }));
-      for (const auto &_ : +it)
-       _.copy (c);
-    }
-    return_trace (true);
-  }
-
-  bool serialize (hb_serialize_context_t *c,
-                 const byte_str_array_t &byteArray)
-  { return serialize (c, + hb_iter (byteArray)); }
-
-  bool serialize (hb_serialize_context_t *c,
-                 const str_buff_vec_t &buffArray)
-  {
-    auto it =
-    + hb_iter (buffArray)
-    | hb_map ([] (const str_buff_t &_) { return byte_str_t (_.arrayZ, _.length); })
-    ;
-    return serialize (c, it);
-  }
-
   template <typename Iterator,
            hb_requires (hb_is_iterator (Iterator))>
   bool serialize_header (hb_serialize_context_t *c,
-                       Iterator it)
+                        Iterator it,
+                        unsigned data_size)
   {
     TRACE_SERIALIZE (this);
 
-    unsigned total = + it | hb_reduce (hb_add, 0);
-    unsigned off_size = calcOffSize (total);
+    unsigned off_size = (hb_bit_storage (data_size + 1) + 7) / 8;
 
     /* serialize CFFIndex header */
     if (unlikely (!c->extend_min (this))) return_trace (false);
-    this->count = it.len ();
+    this->count = hb_len (it);
+    if (!this->count) return_trace (true);
+    if (unlikely (!c->extend (this->offSize))) return_trace (false);
     this->offSize = off_size;
-    if (unlikely (!c->allocate_size<HBUINT8> (off_size * (it.len () + 1))))
+    if (unlikely (!c->allocate_size<HBUINT8> (off_size * (this->count + 1), false)))
       return_trace (false);
 
     /* serialize indices */
     unsigned int offset = 1;
-    unsigned int i = 0;
-    for (unsigned _ : +it)
+    if (HB_OPTIMIZE_SIZE_VAL)
     {
-      CFFIndex<COUNT>::set_offset_at (i++, offset);
-      offset += _;
+      unsigned int i = 0;
+      for (const auto &_ : +it)
+      {
+       set_offset_at (i++, offset);
+       offset += length_f (_);
+      }
+      set_offset_at (i, offset);
     }
-    CFFIndex<COUNT>::set_offset_at (i, offset);
+    else
+      switch (off_size)
+      {
+       case 1:
+       {
+         HBUINT8 *p = (HBUINT8 *) offsets;
+         for (const auto &_ : +it)
+         {
+           *p++ = offset;
+           offset += length_f (_);
+         }
+         *p = offset;
+       }
+       break;
+       case 2:
+       {
+         HBUINT16 *p = (HBUINT16 *) offsets;
+         for (const auto &_ : +it)
+         {
+           *p++ = offset;
+           offset += length_f (_);
+         }
+         *p = offset;
+       }
+       break;
+       case 3:
+       {
+         HBUINT24 *p = (HBUINT24 *) offsets;
+         for (const auto &_ : +it)
+         {
+           *p++ = offset;
+           offset += length_f (_);
+         }
+         *p = offset;
+       }
+       break;
+       case 4:
+       {
+         HBUINT32 *p = (HBUINT32 *) offsets;
+         for (const auto &_ : +it)
+         {
+           *p++ = offset;
+           offset += length_f (_);
+         }
+         *p = offset;
+       }
+       break;
+       default:
+       break;
+      }
 
+    assert (offset == data_size + 1);
     return_trace (true);
   }
 
-  void set_offset_at (unsigned int index, unsigned int offset)
+  template <typename Iterable,
+           hb_requires (hb_is_iterable (Iterable))>
+  static unsigned total_size (const Iterable &iterable, unsigned *data_size = nullptr)
   {
-    HBUINT8 *p = offsets + offSize * index + offSize;
-    unsigned int size = offSize;
-    for (; size; size--)
+    auto it = + hb_iter (iterable);
+    if (!it)
     {
-      --p;
-      *p = offset & 0xFF;
-      offset >>= 8;
+      if (data_size) *data_size = 0;
+      return min_size;
     }
+
+    unsigned total = 0;
+    for (const auto &_ : +it)
+      total += length_f (_);
+
+    if (data_size) *data_size = total;
+
+    unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8;
+
+    return min_size + HBUINT8::static_size + (hb_len (it) + 1) * off_size + total;
   }
 
-  unsigned int offset_at (unsigned int index) const
+  void set_offset_at (unsigned int index, unsigned int offset)
   {
     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;
+    const HBUINT8 *p = offsets;
+    switch (size)
+    {
+      case 1: ((HBUINT8  *) p)[index] = offset; break;
+      case 2: ((HBUINT16 *) p)[index] = offset; break;
+      case 3: ((HBUINT24 *) p)[index] = offset; break;
+      case 4: ((HBUINT32 *) p)[index] = offset; break;
+      default: return;
+    }
   }
 
-  unsigned int length_at (unsigned int index) const
+  private:
+  unsigned int offset_at (unsigned int index) const
   {
-    if (unlikely ((offset_at (index + 1) < offset_at (index)) ||
-                 (offset_at (index + 1) > offset_at (count))))
-      return 0;
-    return offset_at (index + 1) - offset_at (index);
+    assert (index <= count);
+
+    unsigned int size = offSize;
+    const HBUINT8 *p = offsets;
+    switch (size)
+    {
+      case 1: return ((HBUINT8  *) p)[index];
+      case 2: return ((HBUINT16 *) p)[index];
+      case 3: return ((HBUINT24 *) p)[index];
+      case 4: return ((HBUINT32 *) p)[index];
+      default: 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; }
+  { return (const unsigned char *) this + min_size + offSize.static_size - 1 + offset_array_size (); }
+  public:
 
-  byte_str_t operator [] (unsigned int index) const
+  hb_ubytes_t operator [] (unsigned int index) const
   {
-    if (unlikely (index >= count)) return Null (byte_str_t);
-    return byte_str_t (data_base () + offset_at (index) - 1, length_at (index));
+    if (unlikely (index >= count)) return hb_ubytes_t ();
+    _hb_compiler_memory_r_barrier ();
+    unsigned offset0 = offset_at (index);
+    unsigned offset1 = offset_at (index + 1);
+    if (unlikely (offset1 < offset0 || offset1 > offset_at (count)))
+      return hb_ubytes_t ();
+    return hb_ubytes_t (data_base () + offset0, offset1 - offset0);
   }
 
   unsigned int get_size () const
   {
-    if (this == &Null (CFFIndex)) return 0;
-    if (count > 0)
-      return min_size + offset_array_size () + (offset_at (count) - 1);
-    return count.static_size;  /* empty CFFIndex contains count only */
+    if (count)
+      return min_size + offSize.static_size + offset_array_size () + (offset_at (count) - 1);
+    return min_size;  /* empty CFFIndex contains count only */
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely ((c->check_struct (this) && 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))));
-  }
-
-  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;
+    return_trace (likely (c->check_struct (this) &&
+                         (count == 0 || /* empty INDEX */
+                          (count < count + 1u &&
+                           c->check_struct (&offSize) && offSize >= 1 && offSize <= 4 &&
+                           c->check_array (offsets, offSize, count + 1u) &&
+                           c->check_array ((const HBUINT8*) data_base (), 1, offset_at (count))))));
   }
 
   public:
   COUNT                count;          /* Number of object data. Note there are (count+1) offsets */
+  private:
   HBUINT8      offSize;        /* The byte size of each offset in the offsets array. */
   HBUINT8      offsets[HB_VAR_ARRAY];
                                /* The array of (count + 1) offsets into objects array (1-base). */
   /* HBUINT8 data[HB_VAR_ARRAY];       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 = dataArrayLen;
-    this->offSize = 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 || !dest->serialize (c, dataArray[i], param1, param2)))
-       return_trace (false);
-    }
-    return_trace (true);
-  }
+  DEFINE_SIZE_MIN (COUNT::static_size);
 };
 
 /* Top Dict, Font Dict, Private Dict */
@@ -380,13 +312,12 @@ struct Dict : UnsizedByteStr
   template <typename T, typename V>
   static bool serialize_int_op (hb_serialize_context_t *c, op_code_t op, V value, op_code_t intOp)
   {
-    // XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation
-    if (/*unlikely*/ (!serialize_int<T, V> (c, intOp, value)))
+    if (unlikely ((!serialize_int<T, V> (c, intOp, value))))
       return false;
 
     TRACE_SERIALIZE (this);
     /* serialize the opcode */
-    HBUINT8 *p = c->allocate_size<HBUINT8> (OpCode_Size (op));
+    HBUINT8 *p = c->allocate_size<HBUINT8> (OpCode_Size (op), false);
     if (unlikely (!p)) return_trace (false);
     if (Is_OpCode_ESC (op))
     {
@@ -436,7 +367,7 @@ struct table_info_t
 };
 
 template <typename COUNT>
-struct FDArray : CFFIndexOf<COUNT, FontDict>
+struct FDArray : CFFIndex<COUNT>
 {
   template <typename DICTVAL, typename INFO, typename Iterator, typename OP_SERIALIZER>
   bool serialize (hb_serialize_context_t *c,
@@ -447,7 +378,11 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
 
     /* serialize INDEX data */
     hb_vector_t<unsigned> sizes;
+    if (it.is_random_access_iterator)
+      sizes.alloc (hb_len (it));
+
     c->push ();
+    char *data_base = c->head;
     + it
     | hb_map ([&] (const hb_pair_t<const DICTVAL&, const INFO&> &_)
     {
@@ -457,10 +392,16 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
              })
     | hb_sink (sizes)
     ;
+    unsigned data_size = c->head - data_base;
     c->pop_pack (false);
 
+    if (unlikely (sizes.in_error ())) return_trace (false);
+
+    /* It just happens that the above is packed right after the header below.
+     * Such a hack. */
+
     /* serialize INDEX header */
-    return_trace (CFFIndex<COUNT>::serialize_header (c, hb_iter (sizes)));
+    return_trace (CFFIndex<COUNT>::serialize_header (c, hb_iter (sizes), data_size));
   }
 };
 
@@ -471,15 +412,17 @@ struct FDSelect0 {
     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);
+    if (unlikely (!c->check_array (fds, c->get_num_glyphs ())))
+      return_trace (false);
 
     return_trace (true);
   }
 
-  hb_codepoint_t get_fd (hb_codepoint_t glyph) const
-  { return (hb_codepoint_t) fds[glyph]; }
+  unsigned get_fd (hb_codepoint_t glyph) const
+  { return fds[glyph]; }
+
+  hb_pair_t<unsigned, hb_codepoint_t> get_fd_range (hb_codepoint_t glyph) const
+  { return {fds[glyph], glyph + 1}; }
 
   unsigned int get_size (unsigned int num_glyphs) const
   { return HBUINT8::static_size * num_glyphs; }
@@ -527,14 +470,28 @@ struct FDSelect3_4
     return_trace (true);
   }
 
-  hb_codepoint_t get_fd (hb_codepoint_t glyph) const
+  static int _cmp_range (const void *_key, const void *_item)
   {
-    unsigned int i;
-    for (i = 1; i < nRanges (); i++)
-      if (glyph < ranges[i].first)
-       break;
+    hb_codepoint_t glyph = * (hb_codepoint_t *) _key;
+    FDSelect3_4_Range<GID_TYPE, FD_TYPE> *range = (FDSelect3_4_Range<GID_TYPE, FD_TYPE> *) _item;
 
-    return (hb_codepoint_t) ranges[i - 1].fd;
+    if (glyph < range[0].first) return -1;
+    if (glyph < range[1].first) return 0;
+    return +1;
+  }
+
+  unsigned get_fd (hb_codepoint_t glyph) const
+  {
+    auto *range = hb_bsearch (glyph, &ranges[0], nRanges () - 1, sizeof (ranges[0]), _cmp_range);
+    return range ? range->fd : ranges[nRanges () - 1].fd;
+  }
+
+  hb_pair_t<unsigned, hb_codepoint_t> get_fd_range (hb_codepoint_t glyph) const
+  {
+    auto *range = hb_bsearch (glyph, &ranges[0], nRanges () - 1, sizeof (ranges[0]), _cmp_range);
+    unsigned fd = range ? range->fd : ranges[nRanges () - 1].fd;
+    hb_codepoint_t end = range ? range[1].first : ranges[nRanges () - 1].first;
+    return {fd, end};
   }
 
   GID_TYPE        &nRanges ()       { return ranges.len; }
@@ -557,9 +514,9 @@ struct FDSelect
   {
     TRACE_SERIALIZE (this);
     unsigned int size = src.get_size (num_glyphs);
-    FDSelect *dest = c->allocate_size<FDSelect> (size);
+    FDSelect *dest = c->allocate_size<FDSelect> (size, false);
     if (unlikely (!dest)) return_trace (false);
-    memcpy (dest, &src, size);
+    hb_memcpy (dest, &src, size);
     return_trace (true);
   }
 
@@ -573,7 +530,7 @@ struct FDSelect
     }
   }
 
-  hb_codepoint_t get_fd (hb_codepoint_t glyph) const
+  unsigned get_fd (hb_codepoint_t glyph) const
   {
     if (this == &Null (FDSelect)) return 0;
 
@@ -584,6 +541,18 @@ struct FDSelect
     default:return 0;
     }
   }
+  /* Returns pair of fd and one after last glyph in range. */
+  hb_pair_t<unsigned, hb_codepoint_t> get_fd_range (hb_codepoint_t glyph) const
+  {
+    if (this == &Null (FDSelect)) return {0, 1};
+
+    switch (format)
+    {
+    case 0: return u.format0.get_fd_range (glyph);
+    case 3: return u.format3.get_fd_range (glyph);
+    default:return {0, 1};
+    }
+  }
 
   bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
   {
index 3298fa3..66df28a 100644 (file)
@@ -311,10 +311,8 @@ struct bounds_t
 
 struct cff1_extents_param_t
 {
-  void init (const OT::cff1::accelerator_t *_cff)
+  cff1_extents_param_t (const OT::cff1::accelerator_t *_cff) : cff (_cff)
   {
-    path_open = false;
-    cff = _cff;
     bounds.init ();
   }
 
@@ -322,7 +320,7 @@ struct cff1_extents_param_t
   void end_path     ()       { path_open = false; }
   bool is_path_open () const { return path_open; }
 
-  bool path_open;
+  bool path_open = false;
   bounds_t bounds;
 
   const OT::cff1::accelerator_t *cff;
@@ -395,12 +393,11 @@ bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, boun
   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, cff1_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);
-  cff1_extents_param_t  param;
-  param.init (cff);
+  const hb_ubytes_t str = (*cff->charStrings)[glyph];
+  cff1_cs_interp_env_t env (str, *cff, fd);
+  env.set_in_seac (in_seac);
+  cff1_cs_interpreter_t<cff1_cs_opset_extents_t, cff1_extents_param_t> interp (env);
+  cff1_extents_param_t param (cff);
   if (unlikely (!interp.interpret (param))) return false;
   bounds = param.bounds;
   return true;
@@ -425,8 +422,8 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph
   }
   else
   {
-    extents->x_bearing = font->em_scalef_x (bounds.min.x.to_real ());
-    extents->width = font->em_scalef_x (bounds.max.x.to_real ()) - extents->x_bearing;
+    extents->x_bearing = roundf (bounds.min.x.to_real ());
+    extents->width = roundf (bounds.max.x.to_real () - extents->x_bearing);
   }
   if (bounds.min.y >= bounds.max.y)
   {
@@ -435,20 +432,21 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph
   }
   else
   {
-    extents->y_bearing = font->em_scalef_y (bounds.max.y.to_real ());
-    extents->height = font->em_scalef_y (bounds.min.y.to_real ()) - extents->y_bearing;
+    extents->y_bearing = roundf (bounds.max.y.to_real ());
+    extents->height = roundf (bounds.min.y.to_real () - extents->y_bearing);
   }
 
+  font->scale_glyph_extents (extents);
+
   return true;
 }
 
-#ifdef HB_EXPERIMENTAL_API
 struct cff1_path_param_t
 {
   cff1_path_param_t (const OT::cff1::accelerator_t *cff_, hb_font_t *font_,
-                    draw_helper_t &draw_helper_, point_t *delta_)
+                    hb_draw_session_t &draw_session_, point_t *delta_)
   {
-    draw_helper = &draw_helper_;
+    draw_session = &draw_session_;
     cff = cff_;
     font = font_;
     delta = delta_;
@@ -458,14 +456,14 @@ struct cff1_path_param_t
   {
     point_t point = p;
     if (delta) point.move (*delta);
-    draw_helper->move_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ()));
+    draw_session->move_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ()));
   }
 
   void line_to (const point_t &p)
   {
     point_t point = p;
     if (delta) point.move (*delta);
-    draw_helper->line_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ()));
+    draw_session->line_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ()));
   }
 
   void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
@@ -477,15 +475,15 @@ struct cff1_path_param_t
       point2.move (*delta);
       point3.move (*delta);
     }
-    draw_helper->cubic_to (font->em_scalef_x (point1.x.to_real ()), font->em_scalef_y (point1.y.to_real ()),
-                          font->em_scalef_x (point2.x.to_real ()), font->em_scalef_y (point2.y.to_real ()),
-                          font->em_scalef_x (point3.x.to_real ()), font->em_scalef_y (point3.y.to_real ()));
+    draw_session->cubic_to (font->em_fscalef_x (point1.x.to_real ()), font->em_fscalef_y (point1.y.to_real ()),
+                          font->em_fscalef_x (point2.x.to_real ()), font->em_fscalef_y (point2.y.to_real ()),
+                          font->em_fscalef_x (point3.x.to_real ()), font->em_fscalef_y (point3.y.to_real ()));
   }
 
-  void end_path () { draw_helper->end_path (); }
+  void end_path () { draw_session->close_path (); }
 
   hb_font_t *font;
-  draw_helper_t *draw_helper;
+  hb_draw_session_t *draw_session;
   point_t *delta;
 
   const OT::cff1::accelerator_t *cff;
@@ -513,7 +511,7 @@ struct cff1_path_procs_path_t : path_procs_t<cff1_path_procs_path_t, cff1_cs_int
 };
 
 static bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
-                      draw_helper_t &draw_helper, bool in_seac = false, point_t *delta = nullptr);
+                      hb_draw_session_t &draw_session, bool in_seac = false, point_t *delta = nullptr);
 
 struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_param_t, cff1_path_procs_path_t>
 {
@@ -530,23 +528,23 @@ struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_pa
     hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
 
     if (unlikely (!(!env.in_seac && base && accent
-                   && _get_path (param.cff, param.font, base, *param.draw_helper, true)
-                   && _get_path (param.cff, param.font, accent, *param.draw_helper, true, &delta))))
+                   && _get_path (param.cff, param.font, base, *param.draw_session, true)
+                   && _get_path (param.cff, param.font, accent, *param.draw_session, true, &delta))))
       env.set_error ();
   }
 };
 
 bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
-               draw_helper_t &draw_helper, bool in_seac, point_t *delta)
+               hb_draw_session_t &draw_session, bool in_seac, point_t *delta)
 {
   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_path_t, cff1_path_param_t> interp;
-  const byte_str_t str = (*cff->charStrings)[glyph];
-  interp.env.init (str, *cff, fd);
-  interp.env.set_in_seac (in_seac);
-  cff1_path_param_t param (cff, font, draw_helper, delta);
+  const hb_ubytes_t str = (*cff->charStrings)[glyph];
+  cff1_cs_interp_env_t env (str, *cff, fd);
+  env.set_in_seac (in_seac);
+  cff1_cs_interpreter_t<cff1_cs_opset_path_t, cff1_path_param_t> interp (env);
+  cff1_path_param_t param (cff, font, draw_session, delta);
   if (unlikely (!interp.interpret (param))) return false;
 
   /* Let's end the path specially since it is called inside seac also */
@@ -555,31 +553,34 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin
   return true;
 }
 
-bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const
+bool OT::cff1::accelerator_t::paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const
+{
+  funcs->push_clip_glyph (data, glyph, font);
+  funcs->color (data, true, foreground);
+  funcs->pop_clip (data);
+
+  return true;
+}
+
+bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const
 {
 #ifdef HB_NO_OT_FONT_CFF
   /* XXX Remove check when this code moves to .hh file. */
   return true;
 #endif
 
-  return _get_path (this, font, glyph, draw_helper);
+  return _get_path (this, font, glyph, draw_session);
 }
-#endif
 
 struct get_seac_param_t
 {
-  void init (const OT::cff1::accelerator_t *_cff)
-  {
-    cff = _cff;
-    base = 0;
-    accent = 0;
-  }
+  get_seac_param_t (const OT::cff1::accelerator_subset_t *_cff) : cff (_cff) {}
 
   bool has_seac () const { return base && accent; }
 
-  const OT::cff1::accelerator_t *cff;
-  hb_codepoint_t  base;
-  hb_codepoint_t  accent;
+  const OT::cff1::accelerator_subset_t *cff;
+  hb_codepoint_t  base = 0;
+  hb_codepoint_t  accent = 0;
 };
 
 struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_param_t>
@@ -595,16 +596,15 @@ struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_par
   }
 };
 
-bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const
+bool OT::cff1::accelerator_subset_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);
+  const hb_ubytes_t str = (*charStrings)[glyph];
+  cff1_cs_interp_env_t env (str, *this, fd);
+  cff1_cs_interpreter_t<cff1_cs_opset_seac_t, get_seac_param_t> interp (env);
+  get_seac_param_t  param (this);
   if (unlikely (!interp.interpret (param))) return false;
 
   if (param.has_seac ())
index 6fb5931..1e81dcb 100644 (file)
@@ -28,8 +28,9 @@
 #define HB_OT_CFF1_TABLE_HH
 
 #include "hb-ot-cff-common.hh"
-#include "hb-subset-cff1.hh"
+#include "hb-subset-cff-common.hh"
 #include "hb-draw.hh"
+#include "hb-paint.hh"
 
 #define HB_STRING_ARRAY_NAME cff1_std_strings
 #define HB_STRING_ARRAY_LIST "hb-ot-cff1-std-str.hh"
@@ -43,7 +44,7 @@ namespace CFF {
  * CFF -- Compact Font Format (CFF)
  * https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf
  */
-#define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ')
+#define HB_OT_TAG_CFF1 HB_TAG('C','F','F',' ')
 
 #define CFF_UNDEF_SID   CFF_UNDEF_CODE
 
@@ -51,7 +52,6 @@ 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;
@@ -109,6 +109,7 @@ struct Encoding1 {
 
   hb_codepoint_t get_code (hb_codepoint_t glyph) const
   {
+    /* TODO: Add cache like get_sid. */
     assert (glyph > 0);
     glyph--;
     for (unsigned int i = 0; i < nRanges (); i++)
@@ -172,11 +173,7 @@ struct 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)) return_trace (false);
-    memcpy (dest, &src, size);
-    return_trace (true);
+    return_trace (c->embed (src));
   }
 
   /* serialize a subset Encoding */
@@ -311,21 +308,31 @@ struct Encoding
 };
 
 /* Charset */
-struct Charset0 {
-  bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const
+struct Charset0
+{
+  bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs, unsigned *num_charset_entries) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && sids[num_glyphs - 1].sanitize (c));
+    if (num_charset_entries) *num_charset_entries = num_glyphs;
+    return_trace (sids.sanitize (c, num_glyphs - 1));
   }
 
-  hb_codepoint_t get_sid (hb_codepoint_t glyph) const
+  hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs) const
   {
-    if (glyph == 0)
+    if (unlikely (glyph >= num_glyphs)) return 0;
+    if (unlikely (glyph == 0))
       return 0;
     else
       return sids[glyph - 1];
   }
 
+  void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const
+  {
+    mapping->resize (num_glyphs, false);
+    for (hb_codepoint_t gid = 1; gid < num_glyphs; gid++)
+      mapping->arrayZ[gid] = {sids[gid - 1], gid};
+  }
+
   hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const
   {
     if (sid == 0)
@@ -339,13 +346,13 @@ struct Charset0 {
     return 0;
   }
 
-  unsigned int get_size (unsigned int num_glyphs) const
+  static unsigned int get_size (unsigned int num_glyphs)
   {
     assert (num_glyphs > 0);
-    return HBUINT16::static_size * (num_glyphs - 1);
+    return UnsizedArrayOf<HBUINT16>::get_size (num_glyphs - 1);
   }
 
-  HBUINT16  sids[HB_VAR_ARRAY];
+  UnsizedArrayOf<HBUINT16> sids;
 
   DEFINE_SIZE_ARRAY(0, sids);
 };
@@ -366,35 +373,78 @@ struct Charset_Range {
 
 template <typename TYPE>
 struct Charset1_2 {
-  bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const
+  bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs, unsigned *num_charset_entries) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this)))
       return_trace (false);
     num_glyphs--;
-    for (unsigned int i = 0; num_glyphs > 0; i++)
+    unsigned i;
+    for (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);
     }
+    if (num_charset_entries)
+      *num_charset_entries = i;
     return_trace (true);
   }
 
-  hb_codepoint_t get_sid (hb_codepoint_t glyph) const
+  hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs,
+                         code_pair_t *cache = nullptr) const
   {
-    if (glyph == 0) return 0;
-    glyph--;
-    for (unsigned int i = 0;; i++)
+    if (unlikely (glyph >= num_glyphs)) return 0;
+    unsigned i;
+    hb_codepoint_t start_glyph;
+    if (cache && likely (cache->glyph <= glyph))
     {
-      if (glyph <= ranges[i].nLeft)
-       return (hb_codepoint_t)ranges[i].first + glyph;
-      glyph -= (ranges[i].nLeft + 1);
+      i = cache->code;
+      start_glyph = cache->glyph;
+    }
+    else
+    {
+      if (unlikely (glyph == 0)) return 0;
+      i = 0;
+      start_glyph = 1;
+    }
+    glyph -= start_glyph;
+    for (;; i++)
+    {
+      unsigned count = ranges[i].nLeft;
+      if (glyph <= count)
+      {
+        if (cache)
+         *cache = {i, start_glyph};
+       return ranges[i].first + glyph;
+      }
+      count++;
+      start_glyph += count;
+      glyph -= count;
     }
 
     return 0;
   }
 
+  void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const
+  {
+    mapping->resize (num_glyphs, false);
+    hb_codepoint_t gid = 1;
+    if (gid >= num_glyphs)
+      return;
+    for (unsigned i = 0;; i++)
+    {
+      hb_codepoint_t sid = ranges[i].first;
+      unsigned count = ranges[i].nLeft + 1;
+      unsigned last = gid + count;
+      for (unsigned j = 0; j < count; j++)
+       mapping->arrayZ[gid++] = {sid++, last - 1};
+
+      if (gid >= num_glyphs)
+        break;
+    }
+  }
+
   hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const
   {
     if (sid == 0) return 0;
@@ -413,21 +463,26 @@ struct Charset1_2 {
 
   unsigned int get_size (unsigned int num_glyphs) const
   {
-    unsigned int size = HBUINT8::static_size;
-    int glyph = (int)num_glyphs;
+    int glyph = (int) num_glyphs;
+    unsigned num_ranges = 0;
 
     assert (glyph > 0);
     glyph--;
     for (unsigned int i = 0; glyph > 0; i++)
     {
       glyph -= (ranges[i].nLeft + 1);
-      size += Charset_Range<TYPE>::static_size;
+      num_ranges++;
     }
 
-    return size;
+    return get_size_for_ranges (num_ranges);
+  }
+
+  static unsigned int get_size_for_ranges (unsigned int num_ranges)
+  {
+    return UnsizedArrayOf<Charset_Range<TYPE> >::get_size (num_ranges);
   }
 
-  Charset_Range<TYPE>   ranges[HB_VAR_ARRAY];
+  UnsizedArrayOf<Charset_Range<TYPE>> ranges;
 
   DEFINE_SIZE_ARRAY (0, ranges);
 };
@@ -443,11 +498,7 @@ struct 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)) return_trace (false);
-    memcpy (dest, &src, size);
-    return_trace (true);
+    return_trace (c->embed ((const char *) &src, src.get_size (num_glyphs)));
   }
 
   /* serialize a subset Charset */
@@ -464,13 +515,13 @@ struct Charset
     {
     case 0:
     {
-      Charset0 *fmt0 = c->allocate_size<Charset0> (Charset0::min_size + HBUINT16::static_size * (num_glyphs - 1));
+      Charset0 *fmt0 = c->allocate_size<Charset0> (Charset0::get_size (num_glyphs), false);
       if (unlikely (!fmt0)) 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--)
+       hb_codepoint_t sid = sid_ranges.arrayZ[i].code;
+       for (int left = (int)sid_ranges.arrayZ[i].glyph; left >= 0; left--)
          fmt0->sids[glyph++] = sid++;
       }
     }
@@ -478,29 +529,35 @@ struct Charset
 
     case 1:
     {
-      Charset1 *fmt1 = c->allocate_size<Charset1> (Charset1::min_size + Charset1_Range::static_size * sid_ranges.length);
+      Charset1 *fmt1 = c->allocate_size<Charset1> (Charset1::get_size_for_ranges (sid_ranges.length), false);
       if (unlikely (!fmt1)) return_trace (false);
+      hb_codepoint_t all_glyphs = 0;
       for (unsigned int i = 0; i < sid_ranges.length; i++)
       {
-       if (unlikely (!(sid_ranges[i].glyph <= 0xFF)))
-         return_trace (false);
-       fmt1->ranges[i].first = sid_ranges[i].code;
-       fmt1->ranges[i].nLeft = sid_ranges[i].glyph;
+        auto &_ = sid_ranges.arrayZ[i];
+        all_glyphs |= _.glyph;
+       fmt1->ranges[i].first = _.code;
+       fmt1->ranges[i].nLeft = _.glyph;
       }
+      if (unlikely (!(all_glyphs <= 0xFF)))
+       return_trace (false);
     }
     break;
 
     case 2:
     {
-      Charset2 *fmt2 = c->allocate_size<Charset2> (Charset2::min_size + Charset2_Range::static_size * sid_ranges.length);
+      Charset2 *fmt2 = c->allocate_size<Charset2> (Charset2::get_size_for_ranges (sid_ranges.length), false);
       if (unlikely (!fmt2)) return_trace (false);
+      hb_codepoint_t all_glyphs = 0;
       for (unsigned int i = 0; i < sid_ranges.length; i++)
       {
-       if (unlikely (!(sid_ranges[i].glyph <= 0xFFFF)))
-         return_trace (false);
-       fmt2->ranges[i].first = sid_ranges[i].code;
-       fmt2->ranges[i].nLeft = sid_ranges[i].glyph;
+        auto &_ = sid_ranges.arrayZ[i];
+        all_glyphs |= _.glyph;
+       fmt2->ranges[i].first = _.code;
+       fmt2->ranges[i].nLeft = _.glyph;
       }
+      if (unlikely (!(all_glyphs <= 0xFFFF)))
+       return_trace (false);
     }
     break;
 
@@ -519,18 +576,29 @@ struct Charset
     }
   }
 
-  hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs) const
+  hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs,
+                         code_pair_t *cache = nullptr) const
   {
-    if (unlikely (glyph >= num_glyphs)) return 0;
     switch (format)
     {
-    case 0: return u.format0.get_sid (glyph);
-    case 1: return u.format1.get_sid (glyph);
-    case 2: return u.format2.get_sid (glyph);
+    case 0: return u.format0.get_sid (glyph, num_glyphs);
+    case 1: return u.format1.get_sid (glyph, num_glyphs, cache);
+    case 2: return u.format2.get_sid (glyph, num_glyphs, cache);
     default:return 0;
     }
   }
 
+  void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const
+  {
+    switch (format)
+    {
+    case 0: u.format0.collect_glyph_to_sid_map (mapping, num_glyphs); return;
+    case 1: u.format1.collect_glyph_to_sid_map (mapping, num_glyphs); return;
+    case 2: u.format2.collect_glyph_to_sid_map (mapping, num_glyphs); return;
+    default:return;
+    }
+  }
+
   hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const
   {
     switch (format)
@@ -542,7 +610,7 @@ struct Charset
     }
   }
 
-  bool sanitize (hb_sanitize_context_t *c) const
+  bool sanitize (hb_sanitize_context_t *c, unsigned *num_charset_entries) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this)))
@@ -550,9 +618,9 @@ struct Charset
 
     switch (format)
     {
-    case 0: return_trace (u.format0.sanitize (c, c->get_num_glyphs ()));
-    case 1: return_trace (u.format1.sanitize (c, c->get_num_glyphs ()));
-    case 2: return_trace (u.format2.sanitize (c, c->get_num_glyphs ()));
+    case 0: return_trace (u.format0.sanitize (c, c->get_num_glyphs (), num_charset_entries));
+    case 1: return_trace (u.format1.sanitize (c, c->get_num_glyphs (), num_charset_entries));
+    case 2: return_trace (u.format2.sanitize (c, c->get_num_glyphs (), num_charset_entries));
     default:return_trace (false);
     }
   }
@@ -570,10 +638,10 @@ struct Charset
 struct CFF1StringIndex : CFF1Index
 {
   bool serialize (hb_serialize_context_t *c, const CFF1StringIndex &strings,
-                 const hb_inc_bimap_t &sidmap)
+                 const hb_vector_t<unsigned> &sidmap)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely ((strings.count == 0) || (sidmap.get_population () == 0)))
+    if (unlikely ((strings.count == 0) || (sidmap.length == 0)))
     {
       if (unlikely (!c->extend_min (this->count)))
        return_trace (false);
@@ -581,19 +649,15 @@ struct CFF1StringIndex : CFF1Index
       return_trace (true);
     }
 
-    byte_str_array_t bytesArray;
-    bytesArray.init ();
-    if (!bytesArray.resize (sidmap.get_population ()))
-      return_trace (false);
-    for (unsigned int i = 0; i < strings.count; i++)
-    {
-      hb_codepoint_t  j = sidmap[i];
-      if (j != HB_MAP_VALUE_INVALID)
-       bytesArray[j] = strings[i];
-    }
+    if (unlikely (sidmap.in_error ())) return_trace (false);
+
+    // Save this in a vector since serialize() iterates it twice.
+    hb_vector_t<hb_ubytes_t> bytesArray (+ hb_iter (sidmap)
+                                        | hb_map (strings));
+
+    if (unlikely (bytesArray.in_error ())) return_trace (false);
 
     bool result = CFF1Index::serialize (c, bytesArray);
-    bytesArray.fini ();
     return_trace (result);
   }
 };
@@ -602,6 +666,8 @@ 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) {}
+  cff1_top_dict_interp_env_t (const hb_ubytes_t &bytes)
+    : num_interp_env_t(bytes), prev_offset(0), last_offset(0) {}
 
   unsigned int prev_offset;
   unsigned int last_offset;
@@ -776,7 +842,7 @@ struct cff1_top_dict_opset_t : top_dict_opset_t<cff1_top_dict_val_t>
        break;
 
       default:
-       env.last_offset = env.str_ref.offset;
+       env.last_offset = env.str_ref.get_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;
@@ -866,8 +932,6 @@ struct cff1_private_dict_opset_t : dict_opset_t
       case OpCode_FamilyOtherBlues:
       case OpCode_StemSnapH:
       case OpCode_StemSnapV:
-       env.clear_args ();
-       break;
       case OpCode_StdHW:
       case OpCode_StdVW:
       case OpCode_BlueScale:
@@ -879,7 +943,6 @@ struct cff1_private_dict_opset_t : dict_opset_t
       case OpCode_initialRandomSeed:
       case OpCode_defaultWidthX:
       case OpCode_nominalWidthX:
-       val.single_val = env.argStack.pop_num ();
        env.clear_args ();
        break;
       case OpCode_Subrs:
@@ -899,7 +962,7 @@ struct cff1_private_dict_opset_t : dict_opset_t
   }
 };
 
-struct cff1_private_dict_opset_subset : dict_opset_t
+struct cff1_private_dict_opset_subset_t : dict_opset_t
 {
   static void process_op (op_code_t op, num_interp_env_t& env, cff1_private_dict_values_subset_t& dictval)
   {
@@ -945,7 +1008,7 @@ typedef dict_interpreter_t<cff1_top_dict_opset_t, cff1_top_dict_values_t, cff1_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;
+typedef CFF1Index CFF1TopDictIndex;
 
 struct cff1_font_dict_values_mod_t
 {
@@ -986,7 +1049,7 @@ using namespace CFF;
 
 struct cff1
 {
-  static constexpr hb_tag_t tableTag = HB_OT_TAG_cff1;
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_CFF1;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -998,8 +1061,12 @@ struct cff1
   template <typename PRIVOPSET, typename PRIVDICTVAL>
   struct accelerator_templ_t
   {
-    void init (hb_face_t *face)
+    static constexpr hb_tag_t tableTag = cff1::tableTag;
+
+    accelerator_templ_t (hb_face_t *face)
     {
+      if (!face) return;
+
       topDict.init ();
       fontDicts.init ();
       privateDicts.init ();
@@ -1013,23 +1080,22 @@ struct cff1
       const OT::cff1 *cff = this->blob->template as<OT::cff1> ();
 
       if (cff == &Null (OT::cff1))
-      { fini (); return; }
+        goto fail;
 
       nameIndex = &cff->nameIndex (cff);
       if ((nameIndex == &Null (CFF1NameIndex)) || !nameIndex->sanitize (&sc))
-      { fini (); return; }
+        goto fail;
 
       topDictIndex = &StructAtOffset<CFF1TopDictIndex> (nameIndex, nameIndex->get_size ());
       if ((topDictIndex == &Null (CFF1TopDictIndex)) || !topDictIndex->sanitize (&sc) || (topDictIndex->count == 0))
-      { fini (); return; }
+        goto fail;
 
       { /* 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; }
+       const hb_ubytes_t topDictStr = (*topDictIndex)[0];
+       if (unlikely (!topDictStr.sanitize (&sc)))   goto fail;
+       cff1_top_dict_interp_env_t env (topDictStr);
+       cff1_top_dict_interpreter_t top_interp (env);
+       if (unlikely (!top_interp.interpret (topDict)))   goto fail;
       }
 
       if (is_predef_charset ())
@@ -1037,7 +1103,7 @@ struct cff1
       else
       {
        charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset);
-       if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc))) { fini (); return; }
+       if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc, &num_charset_entries)))   goto fail;
       }
 
       fdCount = 1;
@@ -1047,7 +1113,7 @@ struct cff1
        fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset);
        if (unlikely ((fdArray == &Null (CFF1FDArray)) || !fdArray->sanitize (&sc) ||
            (fdSelect == &Null (CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count)))
-       { fini (); return; }
+         goto fail;
 
        fdCount = fdArray->count;
       }
@@ -1060,36 +1126,36 @@ struct cff1
       encoding = &Null (Encoding);
       if (is_CID ())
       {
-       if (unlikely (charset == &Null (Charset))) { fini (); return; }
+       if (unlikely (charset == &Null (Charset)))   goto fail;
       }
       else
       {
        if (!is_predef_encoding ())
        {
          encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset);
-         if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) { fini (); return; }
+         if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc)))   goto fail;
        }
       }
 
       stringIndex = &StructAtOffset<CFF1StringIndex> (topDictIndex, topDictIndex->get_size ());
       if ((stringIndex == &Null (CFF1StringIndex)) || !stringIndex->sanitize (&sc))
-      { fini (); return; }
+        goto fail;
 
       globalSubrs = &StructAtOffset<CFF1Subrs> (stringIndex, stringIndex->get_size ());
       if ((globalSubrs != &Null (CFF1Subrs)) && !globalSubrs->sanitize (&sc))
-      { fini (); return; }
+        goto fail;
 
       charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset);
 
       if ((charStrings == &Null (CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc)))
-      { fini (); return; }
+        goto fail;
 
       num_glyphs = charStrings->count;
       if (num_glyphs != sc.get_num_glyphs ())
-      { fini (); return; }
+        goto fail;
 
       if (unlikely (!privateDicts.resize (fdCount)))
-      { fini (); return; }
+        goto fail;
       for (unsigned int i = 0; i < fdCount; i++)
        privateDicts[i].init ();
 
@@ -1098,27 +1164,28 @@ struct cff1
       {
        for (unsigned int i = 0; i < fdCount; i++)
        {
-         byte_str_t fontDictStr = (*fdArray)[i];
-         if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; }
+         hb_ubytes_t fontDictStr = (*fdArray)[i];
+         if (unlikely (!fontDictStr.sanitize (&sc)))   goto fail;
          cff1_font_dict_values_t *font;
-         cff1_font_dict_interpreter_t font_interp;
-         font_interp.env.init (fontDictStr);
+         cff1_top_dict_interp_env_t env (fontDictStr);
+         cff1_font_dict_interpreter_t font_interp (env);
          font = fontDicts.push ();
-         if (unlikely (font == &Crap (cff1_font_dict_values_t))) { fini (); return; }
+         if (unlikely (fontDicts.in_error ()))   goto fail;
+
          font->init ();
-         if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
+         if (unlikely (!font_interp.interpret (*font)))   goto fail;
          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);
+         const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
+         if (unlikely (!privDictStr.sanitize (&sc)))   goto fail;
+         num_interp_env_t env2 (privDictStr);
+         dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env2);
          priv->init ();
-         if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
+         if (unlikely (!priv_interp.interpret (*priv)))   goto fail;
 
          priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
          if (priv->localSubrs != &Null (CFF1Subrs) &&
              unlikely (!priv->localSubrs->sanitize (&sc)))
-         { fini (); return; }
+           goto fail;
        }
       }
       else  /* non-CID */
@@ -1126,21 +1193,26 @@ struct cff1
        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);
+       const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
+       if (unlikely (!privDictStr.sanitize (&sc)))   goto fail;
+       num_interp_env_t env (privDictStr);
+       dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env);
        priv->init ();
-       if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
+       if (unlikely (!priv_interp.interpret (*priv)))   goto fail;
 
        priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
        if (priv->localSubrs != &Null (CFF1Subrs) &&
            unlikely (!priv->localSubrs->sanitize (&sc)))
-       { fini (); return; }
+         goto fail;
       }
-    }
 
-    void fini ()
+      return;
+
+      fail:
+        _fini ();
+    }
+    ~accelerator_templ_t () { _fini (); }
+    void _fini ()
     {
       sc.end_processing ();
       topDict.fini ();
@@ -1150,6 +1222,8 @@ struct cff1
       blob = nullptr;
     }
 
+    hb_blob_t *get_blob () const { return blob; }
+
     bool is_valid () const { return blob; }
     bool   is_CID () const { return topDict.is_CID (); }
 
@@ -1170,13 +1244,14 @@ struct cff1
 
     bool is_predef_encoding () const { return topDict.EncodingOffset <= ExpertEncoding; }
 
-    hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const
+    hb_codepoint_t glyph_to_code (hb_codepoint_t glyph,
+                                 code_pair_t *glyph_to_sid_cache = nullptr) const
     {
       if (encoding != &Null (Encoding))
        return encoding->get_code (glyph);
       else
       {
-       hb_codepoint_t sid = glyph_to_sid (glyph);
+       hb_codepoint_t sid = glyph_to_sid (glyph, glyph_to_sid_cache);
        if (sid == 0) return 0;
        hb_codepoint_t code = 0;
        switch (topDict.EncodingOffset)
@@ -1194,10 +1269,26 @@ struct cff1
       }
     }
 
-    hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const
+    glyph_to_sid_map_t *create_glyph_to_sid_map () const
     {
       if (charset != &Null (Charset))
-       return charset->get_sid (glyph, num_glyphs);
+      {
+       auto *mapping = (glyph_to_sid_map_t *) hb_malloc (sizeof (glyph_to_sid_map_t));
+       if (unlikely (!mapping)) return nullptr;
+       mapping = new (mapping) glyph_to_sid_map_t ();
+       mapping->push (code_pair_t {0, 1});
+       charset->collect_glyph_to_sid_map (mapping, num_glyphs);
+       return mapping;
+      }
+      else
+       return nullptr;
+    }
+
+    hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph,
+                                code_pair_t *cache = nullptr) const
+    {
+      if (charset != &Null (Charset))
+       return charset->get_sid (glyph, num_glyphs, cache);
       else
       {
        hb_codepoint_t sid = 0;
@@ -1245,10 +1336,10 @@ struct cff1
     }
 
     protected:
-    hb_blob_t             *blob = nullptr;
     hb_sanitize_context_t   sc;
 
     public:
+    hb_blob_t               *blob = nullptr;
     const Encoding         *encoding = nullptr;
     const Charset          *charset = nullptr;
     const CFF1NameIndex     *nameIndex = nullptr;
@@ -1266,48 +1357,35 @@ struct cff1
     hb_vector_t<PRIVDICTVAL> privateDicts;
 
     unsigned int            num_glyphs = 0;
+    unsigned int            num_charset_entries = 0;
   };
 
   struct accelerator_t : accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t>
   {
-    accelerator_t (hb_face_t *face)
+    accelerator_t (hb_face_t *face) : SUPER (face)
     {
-      SUPER::init (face);
+      glyph_names.set_relaxed (nullptr);
 
       if (!is_valid ()) return;
       if (is_CID ()) return;
-
-      /* fill glyph_names */
-      for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
-      {
-       hb_codepoint_t  sid = glyph_to_sid (gid);
-       gname_t gname;
-       gname.sid = sid;
-       if (sid < cff1_std_strings_length)
-         gname.name = cff1_std_strings (sid);
-       else
-       {
-         byte_str_t    ustr = (*stringIndex)[sid - cff1_std_strings_length];
-         gname.name = hb_bytes_t ((const char*)ustr.arrayZ, ustr.length);
-       }
-       if (unlikely (!gname.name.arrayZ)) { fini (); return; }
-       glyph_names.push (gname);
-      }
-      glyph_names.qsort ();
     }
     ~accelerator_t ()
     {
-      glyph_names.fini ();
-
-      SUPER::fini ();
+      hb_sorted_vector_t<gname_t> *names = glyph_names.get_relaxed ();
+      if (names)
+      {
+       names->fini ();
+       hb_free (names);
+      }
     }
 
     bool get_glyph_name (hb_codepoint_t glyph,
                         char *buf, unsigned int buf_len) const
     {
-      if (!buf) return true;
+      if (unlikely (glyph >= num_glyphs)) return false;
       if (unlikely (!is_valid ())) return false;
       if (is_CID()) return false;
+      if (unlikely (!buf_len)) return true;
       hb_codepoint_t sid = glyph_to_sid (glyph);
       const char *str;
       size_t str_len;
@@ -1319,7 +1397,7 @@ struct cff1
       }
       else
       {
-       byte_str_t ubyte_str = (*stringIndex)[sid - cff1_std_strings_length];
+       hb_ubytes_t ubyte_str = (*stringIndex)[sid - cff1_std_strings_length];
        str = (const char *)ubyte_str.arrayZ;
        str_len = ubyte_str.length;
       }
@@ -1333,11 +1411,54 @@ struct cff1
     bool get_glyph_from_name (const char *name, int len,
                              hb_codepoint_t *glyph) const
     {
+      if (unlikely (!is_valid ())) return false;
+      if (is_CID()) return false;
       if (len < 0) len = strlen (name);
       if (unlikely (!len)) return false;
 
+    retry:
+      hb_sorted_vector_t<gname_t> *names = glyph_names.get_acquire ();
+      if (unlikely (!names))
+      {
+       names = (hb_sorted_vector_t<gname_t> *) hb_calloc (sizeof (hb_sorted_vector_t<gname_t>), 1);
+       if (likely (names))
+       {
+         names->init ();
+         /* TODO */
+
+         /* fill glyph names */
+         code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID};
+         for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
+         {
+           hb_codepoint_t      sid = glyph_to_sid (gid, &glyph_to_sid_cache);
+           gname_t     gname;
+           gname.sid = sid;
+           if (sid < cff1_std_strings_length)
+             gname.name = cff1_std_strings (sid);
+           else
+           {
+             hb_ubytes_t       ustr = (*stringIndex)[sid - cff1_std_strings_length];
+             gname.name = hb_bytes_t ((const char*) ustr.arrayZ, ustr.length);
+           }
+           if (unlikely (!gname.name.arrayZ))
+             gname.name = hb_bytes_t ("", 0); /* To avoid nullptr. */
+           names->push (gname);
+         }
+         names->qsort ();
+       }
+       if (unlikely (!glyph_names.cmpexch (nullptr, names)))
+       {
+         if (names)
+         {
+           names->fini ();
+           hb_free (names);
+         }
+         goto retry;
+       }
+      }
+
       gname_t key = { hb_bytes_t (name, len), 0 };
-      const gname_t *gname = glyph_names.bsearch (key);
+      const gname_t *gname = names ? names->bsearch (key) : nullptr;
       if (!gname) return false;
       hb_codepoint_t gid = sid_to_glyph (gname->sid);
       if (!gid && gname->sid) return false;
@@ -1346,10 +1467,8 @@ struct cff1
     }
 
     HB_INTERNAL bool get_extents (hb_font_t *font, 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;
-#ifdef HB_EXPERIMENTAL_API
-    HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const;
-#endif
+    HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const;
+    HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
 
     private:
     struct gname_t
@@ -1361,7 +1480,7 @@ struct cff1
       {
        const gname_t *a = (const gname_t *)a_;
        const gname_t *b = (const gname_t *)b_;
-       int minlen = hb_min (a->name.length, b->name.length);
+       unsigned minlen = hb_min (a->name.length, b->name.length);
        int ret = strncmp (a->name.arrayZ, b->name.arrayZ, minlen);
        if (ret) return ret;
        return a->name.length - b->name.length;
@@ -1370,14 +1489,29 @@ struct cff1
       int cmp (const gname_t &a) const { return cmp (&a, this); }
     };
 
-    hb_sorted_vector_t<gname_t>        glyph_names;
+    mutable hb_atomic_ptr_t<hb_sorted_vector_t<gname_t>> glyph_names;
 
     typedef accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t> SUPER;
   };
 
-  struct accelerator_subset_t : accelerator_templ_t<cff1_private_dict_opset_subset, cff1_private_dict_values_subset_t> {};
+  struct accelerator_subset_t : accelerator_templ_t<cff1_private_dict_opset_subset_t, cff1_private_dict_values_subset_t>
+  {
+    accelerator_subset_t (hb_face_t *face) : SUPER (face) {}
+    ~accelerator_subset_t ()
+    {
+      if (cff_accelerator)
+       cff_subset_accelerator_t::destroy (cff_accelerator);
+    }
 
-  bool subset (hb_subset_context_t *c) const { return hb_subset_cff1 (c); }
+    HB_INTERNAL bool subset (hb_subset_context_t *c) const;
+    HB_INTERNAL bool serialize (hb_serialize_context_t *c,
+                               struct cff1_subset_plan &plan) const;
+    HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const;
+
+    mutable CFF::cff_subset_accelerator_t* cff_accelerator = nullptr;
+
+    typedef accelerator_templ_t<cff1_private_dict_opset_subset_t, cff1_private_dict_values_subset_t> SUPER;
+  };
 
   protected:
   HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_code (hb_codepoint_t sid);
@@ -1401,6 +1535,10 @@ struct cff1_accelerator_t : cff1::accelerator_t {
   cff1_accelerator_t (hb_face_t *face) : cff1::accelerator_t (face) {}
 };
 
+struct cff1_subset_accelerator_t : cff1::accelerator_subset_t {
+  cff1_subset_accelerator_t (hb_face_t *face) : cff1::accelerator_subset_t (face) {}
+};
+
 } /* namespace OT */
 
 #endif /* HB_OT_CFF1_TABLE_HH */
index 879b7cd..7955565 100644 (file)
@@ -36,9 +36,8 @@ using namespace CFF;
 
 struct cff2_extents_param_t
 {
-  void init ()
+  cff2_extents_param_t ()
   {
-    path_open = false;
     min_x.set_int (INT_MAX);
     min_y.set_int (INT_MAX);
     max_x.set_int (INT_MIN);
@@ -57,22 +56,22 @@ struct cff2_extents_param_t
     if (pt.y > max_y) max_y = pt.y;
   }
 
-  bool  path_open;
+  bool  path_open = false;
   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, cff2_extents_param_t>
+struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t<number_t>, cff2_extents_param_t>
 {
-  static void moveto (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt)
+  static void moveto (cff2_cs_interp_env_t<number_t> &env, cff2_extents_param_t& param, const point_t &pt)
   {
     param.end_path ();
     env.moveto (pt);
   }
 
-  static void line (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1)
+  static void line (cff2_cs_interp_env_t<number_t> &env, cff2_extents_param_t& param, const point_t &pt1)
   {
     if (!param.is_path_open ())
     {
@@ -83,7 +82,7 @@ struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_
     param.update_bounds (env.get_pt ());
   }
 
-  static void curve (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
+  static void curve (cff2_cs_interp_env_t<number_t> &env, cff2_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
   {
     if (!param.is_path_open ())
     {
@@ -98,7 +97,7 @@ struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_
   }
 };
 
-struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, cff2_path_procs_extents_t> {};
+struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, number_t, cff2_path_procs_extents_t> {};
 
 bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
                                           hb_codepoint_t glyph,
@@ -112,11 +111,10 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
   if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
 
   unsigned int fd = fdSelect->get_fd (glyph);
-  cff2_cs_interpreter_t<cff2_cs_opset_extents_t, cff2_extents_param_t> interp;
-  const byte_str_t str = (*charStrings)[glyph];
-  interp.env.init (str, *this, fd, font->coords, font->num_coords);
+  const hb_ubytes_t str = (*charStrings)[glyph];
+  cff2_cs_interp_env_t<number_t> env (str, *this, fd, font->coords, font->num_coords);
+  cff2_cs_interpreter_t<cff2_cs_opset_extents_t, cff2_extents_param_t, number_t> interp (env);
   cff2_extents_param_t  param;
-  param.init ();
   if (unlikely (!interp.interpret (param))) return false;
 
   if (param.min_x >= param.max_x)
@@ -126,8 +124,8 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
   }
   else
   {
-    extents->x_bearing = font->em_scalef_x (param.min_x.to_real ());
-    extents->width = font->em_scalef_x (param.max_x.to_real ()) - extents->x_bearing;
+    extents->x_bearing = roundf (param.min_x.to_real ());
+    extents->width = roundf (param.max_x.to_real () - extents->x_bearing);
   }
   if (param.min_y >= param.max_y)
   {
@@ -136,64 +134,74 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
   }
   else
   {
-    extents->y_bearing = font->em_scalef_y (param.max_y.to_real ());
-    extents->height = font->em_scalef_y (param.min_y.to_real ()) - extents->y_bearing;
+    extents->y_bearing = roundf (param.max_y.to_real ());
+    extents->height = roundf (param.min_y.to_real () - extents->y_bearing);
   }
 
+  font->scale_glyph_extents (extents);
+
+  return true;
+}
+
+bool OT::cff2::accelerator_t::paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const
+{
+  funcs->push_clip_glyph (data, glyph, font);
+  funcs->color (data, true, foreground);
+  funcs->pop_clip (data);
+
   return true;
 }
 
-#ifdef HB_EXPERIMENTAL_API
 struct cff2_path_param_t
 {
-  cff2_path_param_t (hb_font_t *font_, draw_helper_t &draw_helper_)
+  cff2_path_param_t (hb_font_t *font_, hb_draw_session_t &draw_session_)
   {
-    draw_helper = &draw_helper_;
+    draw_session = &draw_session_;
     font = font_;
   }
 
   void move_to (const point_t &p)
-  { draw_helper->move_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); }
+  { draw_session->move_to (font->em_fscalef_x (p.x.to_real ()), font->em_fscalef_y (p.y.to_real ())); }
 
   void line_to (const point_t &p)
-  { draw_helper->line_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); }
+  { draw_session->line_to (font->em_fscalef_x (p.x.to_real ()), font->em_fscalef_y (p.y.to_real ())); }
 
   void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
   {
-    draw_helper->cubic_to (font->em_scalef_x (p1.x.to_real ()), font->em_scalef_y (p1.y.to_real ()),
-                          font->em_scalef_x (p2.x.to_real ()), font->em_scalef_y (p2.y.to_real ()),
-                          font->em_scalef_x (p3.x.to_real ()), font->em_scalef_y (p3.y.to_real ()));
+    draw_session->cubic_to (font->em_fscalef_x (p1.x.to_real ()), font->em_fscalef_y (p1.y.to_real ()),
+                          font->em_fscalef_x (p2.x.to_real ()), font->em_fscalef_y (p2.y.to_real ()),
+                          font->em_fscalef_x (p3.x.to_real ()), font->em_fscalef_y (p3.y.to_real ()));
   }
 
   protected:
-  draw_helper_t *draw_helper;
+  hb_draw_session_t *draw_session;
   hb_font_t *font;
 };
 
-struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_interp_env_t, cff2_path_param_t>
+struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_interp_env_t<number_t>, cff2_path_param_t>
 {
-  static void moveto (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt)
+  static void moveto (cff2_cs_interp_env_t<number_t> &env, cff2_path_param_t& param, const point_t &pt)
   {
     param.move_to (pt);
     env.moveto (pt);
   }
 
-  static void line (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1)
+  static void line (cff2_cs_interp_env_t<number_t> &env, cff2_path_param_t& param, const point_t &pt1)
   {
     param.line_to (pt1);
     env.moveto (pt1);
   }
 
-  static void curve (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
+  static void curve (cff2_cs_interp_env_t<number_t> &env, cff2_path_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
   {
     param.cubic_to (pt1, pt2, pt3);
     env.moveto (pt3);
   }
 };
 
-struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, cff2_path_procs_path_t> {};
+struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, number_t, cff2_path_procs_path_t> {};
 
-bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const
+bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const
 {
 #ifdef HB_NO_OT_FONT_CFF
   /* XXX Remove check when this code moves to .hh file. */
@@ -203,13 +211,12 @@ bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, d
   if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
 
   unsigned int fd = fdSelect->get_fd (glyph);
-  cff2_cs_interpreter_t<cff2_cs_opset_path_t, cff2_path_param_t> interp;
-  const byte_str_t str = (*charStrings)[glyph];
-  interp.env.init (str, *this, fd, font->coords, font->num_coords);
-  cff2_path_param_t param (font, draw_helper);
+  const hb_ubytes_t str = (*charStrings)[glyph];
+  cff2_cs_interp_env_t<number_t> env (str, *this, fd, font->coords, font->num_coords);
+  cff2_cs_interpreter_t<cff2_cs_opset_path_t, cff2_path_param_t, number_t> interp (env);
+  cff2_path_param_t param (font, draw_session);
   if (unlikely (!interp.interpret (param))) return false;
   return true;
 }
-#endif
 
 #endif
index 6e1b01c..af24bb9 100644 (file)
@@ -28,8 +28,9 @@
 #define HB_OT_CFF2_TABLE_HH
 
 #include "hb-ot-cff-common.hh"
-#include "hb-subset-cff2.hh"
+#include "hb-subset-cff-common.hh"
 #include "hb-draw.hh"
+#include "hb-paint.hh"
 
 namespace CFF {
 
@@ -37,10 +38,9 @@ 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')
+#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 Subrs<HBUINT32>   CFF2Subrs;
@@ -56,7 +56,7 @@ struct CFF2FDSelect
     unsigned int size = src.get_size (num_glyphs);
     CFF2FDSelect *dest = c->allocate_size<CFF2FDSelect> (size);
     if (unlikely (!dest)) return_trace (false);
-    memcpy (dest, &src, size);
+    hb_memcpy (dest, &src, size);
     return_trace (true);
   }
 
@@ -124,7 +124,7 @@ struct CFF2VariationStore
     unsigned int size_ = varStore->get_size ();
     CFF2VariationStore *dest = c->allocate_size<CFF2VariationStore> (size_);
     if (unlikely (!dest)) return_trace (false);
-    memcpy (dest, varStore, size_);
+    hb_memcpy (dest, varStore, size_);
     return_trace (true);
   }
 
@@ -247,12 +247,8 @@ typedef cff2_private_dict_values_base_t<num_dict_val_t> cff2_private_dict_values
 
 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;
-  }
+  cff2_priv_dict_interp_env_t (const hb_ubytes_t &str) :
+    num_interp_env_t (str) {}
 
   void process_vsindex ()
   {
@@ -267,8 +263,8 @@ struct cff2_priv_dict_interp_env_t : num_interp_env_t
   void  set_ivs (unsigned int ivs_) { ivs = ivs_; }
 
   protected:
-  unsigned int  ivs;
-  bool   seen_vsindex;
+  unsigned int  ivs = 0;
+  bool   seen_vsindex = false;
 };
 
 struct cff2_private_dict_opset_t : dict_opset_t
@@ -286,9 +282,6 @@ struct cff2_private_dict_opset_t : dict_opset_t
       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:
@@ -385,7 +378,7 @@ using namespace CFF;
 
 struct cff2
 {
-  static constexpr hb_tag_t tableTag = HB_OT_TAG_cff2;
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_CFF2;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -397,8 +390,12 @@ struct cff2
   template <typename PRIVOPSET, typename PRIVDICTVAL>
   struct accelerator_templ_t
   {
+    static constexpr hb_tag_t tableTag = cff2::tableTag;
+
     accelerator_templ_t (hb_face_t *face)
     {
+      if (!face) return;
+
       topDict.init ();
       fontDicts.init ();
       privateDicts.init ();
@@ -415,10 +412,10 @@ struct cff2
         goto fail;
 
       { /* parse top dict */
-       byte_str_t topDictStr (cff2 + cff2->topDict, cff2->topDictSize);
+       hb_ubytes_t topDictStr = (cff2 + cff2->topDict).as_ubytes (cff2->topDictSize);
        if (unlikely (!topDictStr.sanitize (&sc))) goto fail;
-       cff2_top_dict_interpreter_t top_interp;
-       top_interp.env.init (topDictStr);
+       num_interp_env_t env (topDictStr);
+       cff2_top_dict_interpreter_t top_interp (env);
        topDict.init ();
        if (unlikely (!top_interp.interpret (topDict))) goto fail;
       }
@@ -447,20 +444,20 @@ struct cff2
       /* parse font dicts and gather private dicts */
       for (unsigned int i = 0; i < fdCount; i++)
       {
-       const byte_str_t fontDictStr = (*fdArray)[i];
+       const hb_ubytes_t fontDictStr = (*fdArray)[i];
        if (unlikely (!fontDictStr.sanitize (&sc))) goto fail;
        cff2_font_dict_values_t  *font;
-       cff2_font_dict_interpreter_t font_interp;
-       font_interp.env.init (fontDictStr);
+       num_interp_env_t env (fontDictStr);
+       cff2_font_dict_interpreter_t font_interp (env);
        font = fontDicts.push ();
        if (unlikely (font == &Crap (cff2_font_dict_values_t))) goto fail;
        font->init ();
        if (unlikely (!font_interp.interpret (*font))) goto fail;
 
-       const byte_str_t privDictStr (StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset), font->privateDictInfo.size);
+       const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
        if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
-       dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t>  priv_interp;
-       priv_interp.env.init(privDictStr);
+       cff2_priv_dict_interp_env_t env2 (privDictStr);
+       dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp (env2);
        privateDicts[i].init ();
        if (unlikely (!priv_interp.interpret (privateDicts[i]))) goto fail;
 
@@ -470,7 +467,6 @@ struct cff2
          goto fail;
       }
 
-
       return;
 
       fail:
@@ -487,13 +483,20 @@ struct cff2
       blob = nullptr;
     }
 
+    hb_vector_t<uint16_t> *create_glyph_to_sid_map () const
+    {
+      return nullptr;
+    }
+
+    hb_blob_t *get_blob () const { return blob; }
+
     bool is_valid () const { return blob; }
 
     protected:
-    hb_blob_t                  *blob = nullptr;
     hb_sanitize_context_t      sc;
 
     public:
+    hb_blob_t                  *blob = nullptr;
     cff2_top_dict_values_t     topDict;
     const CFF2Subrs            *globalSubrs = nullptr;
     const CFF2VariationStore   *varStore = nullptr;
@@ -515,14 +518,28 @@ struct cff2
     HB_INTERNAL bool get_extents (hb_font_t *font,
                                  hb_codepoint_t glyph,
                                  hb_glyph_extents_t *extents) const;
-#ifdef HB_EXPERIMENTAL_API
-    HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const;
-#endif
+    HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const;
+    HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
   };
 
-  typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> accelerator_subset_t;
+  struct accelerator_subset_t : accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t>
+  {
+    accelerator_subset_t (hb_face_t *face) : SUPER (face) {}
+    ~accelerator_subset_t ()
+    {
+      if (cff_accelerator)
+       cff_subset_accelerator_t::destroy (cff_accelerator);
+    }
 
-  bool subset (hb_subset_context_t *c) const { return hb_subset_cff2 (c); }
+    HB_INTERNAL bool subset (hb_subset_context_t *c) const;
+    HB_INTERNAL bool serialize (hb_serialize_context_t *c,
+                               struct cff2_subset_plan &plan,
+                               hb_array_t<int> normalized_coords) const;
+
+    mutable CFF::cff_subset_accelerator_t* cff_accelerator = nullptr;
+
+    typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> SUPER;
+  };
 
   public:
   FixedVersion<HBUINT8>                version;        /* Version of CFF2 table. set to 0x0200u */
@@ -537,6 +554,10 @@ struct cff2_accelerator_t : cff2::accelerator_t {
   cff2_accelerator_t (hb_face_t *face) : cff2::accelerator_t (face) {}
 };
 
+struct cff2_subset_accelerator_t : cff2::accelerator_subset_t {
+  cff2_subset_accelerator_t (hb_face_t *face) : cff2::accelerator_subset_t (face) {}
+};
+
 } /* namespace OT */
 
 #endif /* HB_OT_CFF2_TABLE_HH */
index fde57cd..30401b1 100644 (file)
 #ifndef HB_OT_CMAP_TABLE_HH
 #define HB_OT_CMAP_TABLE_HH
 
+#include "hb-ot-os2-table.hh"
+#include "hb-ot-shaper-arabic-pua.hh"
 #include "hb-open-type.hh"
 #include "hb-set.hh"
+#include "hb-cache.hh"
 
 /*
  * cmap -- Character to Glyph Index Mapping
@@ -44,7 +47,7 @@ struct CmapSubtableFormat0
   bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
   {
     hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0;
-    if (!gid)
+    if (unlikely (!gid))
       return false;
     *glyph = gid;
     return true;
@@ -109,22 +112,26 @@ struct CmapSubtableFormat4
 
     while (it) {
       // Start a new range
-      start_cp = (*it).first;
-      prev_run_start_cp = (*it).first;
-      run_start_cp = (*it).first;
-      end_cp = (*it).first;
-      last_gid = (*it).second;
-      run_length = 1;
-      prev_delta = 0;
-
-      delta = (*it).second - (*it).first;
+      {
+        const auto& pair = *it;
+        start_cp = pair.first;
+        prev_run_start_cp = start_cp;
+        run_start_cp = start_cp;
+        end_cp = start_cp;
+        last_gid = pair.second;
+        run_length = 1;
+        prev_delta = 0;
+      }
+
+      delta = last_gid - start_cp;
       mode = FIRST_SUB_RANGE;
       it++;
 
       while (it) {
         // Process range
-        hb_codepoint_t next_cp = (*it).first;
-        hb_codepoint_t next_gid = (*it).second;
+        const auto& pair = *it;
+        hb_codepoint_t next_cp = pair.first;
+        hb_codepoint_t next_gid = pair.second;
         if (next_cp != end_cp + 1) {
           // Current range is over, stop processing.
           break;
@@ -270,10 +277,10 @@ struct CmapSubtableFormat4
       }
     } writer(c);
 
-    writer.end_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
-    c->allocate_size<HBUINT16> (2); // padding
-    writer.start_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
-    writer.id_delta_ = c->allocate_size<HBINT16> (HBINT16::static_size * segcount);
+    writer.end_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount, false);
+    (void) c->allocate_size<HBUINT16> (2); // padding
+    writer.start_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount, false);
+    writer.id_delta_ = c->allocate_size<HBINT16> (HBINT16::static_size * segcount, false);
 
     if (unlikely (!writer.end_code_ || !writer.start_code_ || !writer.id_delta_)) return false;
 
@@ -282,23 +289,22 @@ struct CmapSubtableFormat4
   }
 
   template<typename Iterator,
-          hb_requires (hb_is_iterator (Iterator))>
+          hb_requires (hb_is_iterator (Iterator))>
   HBUINT16* serialize_rangeoffset_glyid (hb_serialize_context_t *c,
-                                        Iterator it,
+                                         Iterator it,
                                         HBUINT16 *endCode,
                                         HBUINT16 *startCode,
                                         HBINT16 *idDelta,
                                         unsigned segcount)
   {
-    hb_hashmap_t<hb_codepoint_t, hb_codepoint_t> cp_to_gid;
-    + it | hb_sink (cp_to_gid);
+    hb_map_t cp_to_gid { it };
 
     HBUINT16 *idRangeOffset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
     if (unlikely (!c->check_success (idRangeOffset))) return nullptr;
     if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr;
 
     for (unsigned i : + hb_range (segcount)
-             | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; }))
+                     | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; }))
     {
       idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i);
       for (hb_codepoint_t cp = startCode[i]; cp <= endCode[i]; cp++)
@@ -319,26 +325,35 @@ struct CmapSubtableFormat4
   {
     auto format4_iter =
     + it
-    | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
+    | hb_filter ([&] (const hb_codepoint_pair_t _)
                 { return _.first <= 0xFFFF; })
     ;
 
-    if (format4_iter.len () == 0) return;
+    if (!format4_iter) return;
 
     unsigned table_initpos = c->length ();
     if (unlikely (!c->extend_min (this))) return;
     this->format = 4;
 
+    hb_vector_t<hb_codepoint_pair_t> cp_to_gid {
+      format4_iter
+    };
+
     //serialize endCode[], startCode[], idDelta[]
     HBUINT16* endCode = c->start_embed<HBUINT16> ();
-    unsigned segcount = serialize_find_segcount (format4_iter);
-    if (unlikely (!serialize_start_end_delta_arrays (c, format4_iter, segcount)))
+    unsigned segcount = serialize_find_segcount (cp_to_gid.iter());
+    if (unlikely (!serialize_start_end_delta_arrays (c, cp_to_gid.iter(), segcount)))
       return;
 
     HBUINT16 *startCode = endCode + segcount + 1;
     HBINT16 *idDelta = ((HBINT16*)startCode) + segcount;
 
-    HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, format4_iter, endCode, startCode, idDelta, segcount);
+    HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c,
+                                                           cp_to_gid.iter (),
+                                                           endCode,
+                                                           startCode,
+                                                           idDelta,
+                                                           segcount);
     if (unlikely (!c->check_success (idRangeOffset))) return;
 
     this->length = c->length () - table_initpos;
@@ -389,7 +404,7 @@ struct CmapSubtableFormat4
                 unsigned distance) const
        {
          if (k > last) return +1;
-         if (k < (&last)[distance]) return -1;
+         if (k < (&last)[distance]/*first*/) return -1;
          return 0;
        }
        HBUINT16 last;
@@ -398,10 +413,10 @@ struct CmapSubtableFormat4
       const HBUINT16 *found = hb_bsearch (codepoint,
                                          this->endCount,
                                          this->segCount,
-                                         2,
+                                         sizeof (CustomRange),
                                          _hb_cmp_method<hb_codepoint_t, CustomRange, unsigned>,
                                          this->segCount + 1);
-      if (!found)
+      if (unlikely (!found))
        return false;
       unsigned int i = found - endCount;
 
@@ -421,7 +436,7 @@ struct CmapSubtableFormat4
        gid += this->idDelta[i];
       }
       gid &= 0xFFFFu;
-      if (!gid)
+      if (unlikely (!gid))
        return false;
       *glyph = gid;
       return true;
@@ -440,14 +455,14 @@ struct CmapSubtableFormat4
        hb_codepoint_t start = this->startCount[i];
        hb_codepoint_t end = this->endCount[i];
        unsigned int rangeOffset = this->idRangeOffset[i];
+        out->add_range(start, end);
        if (rangeOffset == 0)
        {
          for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
          {
            hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu;
            if (unlikely (!gid))
-             continue;
-           out->add (codepoint);
+              out->del(codepoint);
          }
        }
        else
@@ -456,11 +471,13 @@ struct CmapSubtableFormat4
          {
            unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
            if (unlikely (index >= this->glyphIdArrayLength))
+            {
+              out->del_range (codepoint, end);
              break;
+            }
            hb_codepoint_t gid = this->glyphIdArray[index];
            if (unlikely (!gid))
-             continue;
-           out->add (codepoint);
+              out->del(codepoint);
          }
        }
       }
@@ -469,6 +486,8 @@ struct CmapSubtableFormat4
     void collect_mapping (hb_set_t *unicodes, /* OUT */
                          hb_map_t *mapping /* OUT */) const
     {
+      // TODO(grieger): optimize similar to collect_unicodes
+      // (ie. use add_range())
       unsigned count = this->segCount;
       if (count && this->startCount[count - 1] == 0xFFFFu)
        count--; /* Skip sentinel segment. */
@@ -620,7 +639,7 @@ struct CmapSubtableTrimmed
   {
     /* Rely on our implicit array bound-checking. */
     hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode];
-    if (!gid)
+    if (unlikely (!gid))
       return false;
     *glyph = gid;
     return true;
@@ -674,7 +693,7 @@ struct CmapSubtableTrimmed
 };
 
 struct CmapSubtableFormat6  : CmapSubtableTrimmed<HBUINT16> {};
-struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {};
+struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32> {};
 
 template <typename T>
 struct CmapSubtableLongSegmented
@@ -684,7 +703,7 @@ struct CmapSubtableLongSegmented
   bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
   {
     hb_codepoint_t gid = T::group_get_glyph (groups.bsearch (codepoint), codepoint);
-    if (!gid)
+    if (unlikely (!gid))
       return false;
     *glyph = gid;
     return true;
@@ -714,7 +733,7 @@ struct CmapSubtableLongSegmented
       if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
        end = start + (hb_codepoint_t) num_glyphs - gid;
 
-      out->add_range (start, end);
+      out->add_range (start, hb_min (end, 0x10FFFFu));
     }
   }
 
@@ -722,16 +741,23 @@ struct CmapSubtableLongSegmented
                        hb_map_t *mapping, /* OUT */
                        unsigned num_glyphs) const
   {
+    hb_codepoint_t last_end = 0;
     for (unsigned i = 0; i < this->groups.len; i++)
     {
       hb_codepoint_t start = this->groups[i].startCharCode;
       hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode,
                                   (hb_codepoint_t) HB_UNICODE_MAX);
+      if (unlikely (start > end || start < last_end)) {
+        // Range is not in order and is invalid, skip it.
+        continue;
+      }
+      last_end = end;
+
+
       hb_codepoint_t gid = this->groups[i].glyphID;
       if (!gid)
       {
-       /* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */
-       if (! T::group_get_glyph (this->groups[i], end)) continue;
+        if (T::formatNumber == 13) continue;
        start++;
        gid++;
       }
@@ -739,11 +765,13 @@ struct CmapSubtableLongSegmented
       if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
        end = start + (hb_codepoint_t) num_glyphs - gid;
 
+      mapping->alloc (mapping->get_population () + end - start + 1);
+
       for (unsigned cp = start; cp <= end; cp++)
       {
        unicodes->add (cp);
        mapping->set (cp, gid);
-       gid++;
+        gid += T::increment;
       }
     }
   }
@@ -767,6 +795,9 @@ struct CmapSubtableLongSegmented
 
 struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
 {
+  static constexpr int increment = 1;
+  static constexpr int formatNumber = 12;
+
   static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
                                         hb_codepoint_t u)
   { return likely (group.startCharCode <= group.endCharCode) ?
@@ -778,16 +809,16 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
   void serialize (hb_serialize_context_t *c,
                  Iterator it)
   {
-    if (it.len () == 0) return;
+    if (!it) return;
     unsigned table_initpos = c->length ();
     if (unlikely (!c->extend_min (this))) return;
 
-    hb_codepoint_t startCharCode = 0xFFFF, endCharCode = 0xFFFF;
+    hb_codepoint_t startCharCode = (hb_codepoint_t) -1, endCharCode = (hb_codepoint_t) -1;
     hb_codepoint_t glyphID = 0;
 
     for (const auto& _ : +it)
     {
-      if (startCharCode == 0xFFFF)
+      if (startCharCode == (hb_codepoint_t) -1)
       {
        startCharCode = _.first;
        endCharCode = _.first;
@@ -818,7 +849,7 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
     this->format = 12;
     this->reserved = 0;
     this->length = c->length () - table_initpos;
-    this->groups.len = (this->length - min_size)/CmapSubtableLongGroup::static_size;
+    this->groups.len = (this->length - min_size) / CmapSubtableLongGroup::static_size;
   }
 
   static size_t get_sub_table_size (const hb_sorted_vector_t<CmapSubtableLongGroup> &groups_data)
@@ -839,6 +870,9 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
 
 struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
 {
+  static constexpr int increment = 0;
+  static constexpr int formatNumber = 13;
+
   static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
                                         hb_codepoint_t u HB_UNUSED)
   { return group.glyphID; }
@@ -890,8 +924,7 @@ struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
   DefaultUVS* copy (hb_serialize_context_t *c,
                    const hb_set_t *unicodes) const
   {
-    DefaultUVS *out = c->start_embed<DefaultUVS> ();
-    if (unlikely (!out)) return nullptr;
+    auto *out = c->start_embed<DefaultUVS> ();
     auto snap = c->snapshot ();
 
     HBUINT32 len;
@@ -899,37 +932,74 @@ struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
     if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
     unsigned init_len = c->length ();
 
-    hb_codepoint_t lastCode = HB_MAP_VALUE_INVALID;
-    int count = -1;
-
-    for (const UnicodeValueRange& _ : as_array ())
+    if (this->len > unicodes->get_population () * hb_bit_storage ((unsigned) this->len))
     {
-      for (const unsigned addcnt : hb_range ((unsigned) _.additionalCount + 1))
+      hb_codepoint_t start = HB_SET_VALUE_INVALID;
+      hb_codepoint_t end = HB_SET_VALUE_INVALID;
+
+      for (auto u : *unicodes)
       {
-       unsigned curEntry = (unsigned) _.startUnicodeValue + addcnt;
-       if (!unicodes->has (curEntry)) continue;
-       count += 1;
-       if (lastCode == HB_MAP_VALUE_INVALID)
-         lastCode = curEntry;
-       else if (lastCode + count != curEntry)
+        if (!as_array ().bsearch (u))
+         continue;
+       if (start == HB_SET_VALUE_INVALID)
        {
+         start = u;
+         end = start - 1;
+       }
+       if (end + 1 != u || end - start == 255)
+        {
          UnicodeValueRange rec;
-         rec.startUnicodeValue = lastCode;
-         rec.additionalCount = count - 1;
+         rec.startUnicodeValue = start;
+         rec.additionalCount = end - start;
          c->copy<UnicodeValueRange> (rec);
-
-         lastCode = curEntry;
-         count = 0;
+         start = u;
        }
+       end = u;
+      }
+      if (start != HB_SET_VALUE_INVALID)
+      {
+       UnicodeValueRange rec;
+       rec.startUnicodeValue = start;
+       rec.additionalCount = end - start;
+       c->copy<UnicodeValueRange> (rec);
       }
-    }
 
-    if (lastCode != HB_MAP_VALUE_INVALID)
+    }
+    else
     {
-      UnicodeValueRange rec;
-      rec.startUnicodeValue = lastCode;
-      rec.additionalCount = count;
-      c->copy<UnicodeValueRange> (rec);
+      hb_codepoint_t lastCode = HB_SET_VALUE_INVALID;
+      int count = -1;
+
+      for (const UnicodeValueRange& _ : *this)
+      {
+       hb_codepoint_t curEntry = (hb_codepoint_t) (_.startUnicodeValue - 1);
+       hb_codepoint_t end = curEntry + _.additionalCount + 2;
+
+       for (; unicodes->next (&curEntry) && curEntry < end;)
+       {
+         count += 1;
+         if (lastCode == HB_SET_VALUE_INVALID)
+           lastCode = curEntry;
+         else if (lastCode + count != curEntry)
+         {
+           UnicodeValueRange rec;
+           rec.startUnicodeValue = lastCode;
+           rec.additionalCount = count - 1;
+           c->copy<UnicodeValueRange> (rec);
+
+           lastCode = curEntry;
+           count = 0;
+         }
+       }
+      }
+
+      if (lastCode != HB_MAP_VALUE_INVALID)
+      {
+       UnicodeValueRange rec;
+       rec.startUnicodeValue = lastCode;
+       rec.additionalCount = count;
+       c->copy<UnicodeValueRange> (rec);
+      }
     }
 
     if (c->length () - init_len == 0)
@@ -1002,9 +1072,7 @@ struct NonDefaultUVS : SortedArray32Of<UVSMapping>
                       const hb_set_t *glyphs_requested,
                       const hb_map_t *glyph_map) const
   {
-    NonDefaultUVS *out = c->start_embed<NonDefaultUVS> ();
-    if (unlikely (!out)) return nullptr;
-
+    auto *out = c->start_embed<NonDefaultUVS> ();
     auto it =
     + as_array ()
     | hb_filter ([&] (const UVSMapping& _)
@@ -1350,7 +1418,7 @@ struct CmapSubtable
     switch (format) {
     case  4: return u.format4.serialize (c, it);
     case 12: return u.format12.serialize (c, it);
-    case 14: return u.format14.serialize (c, plan->unicodes, plan->glyphs_requested, plan->glyph_map, base);
+    case 14: return u.format14.serialize (c, &plan->unicodes, &plan->glyphs_requested, plan->glyph_map, base);
     default: return;
     }
   }
@@ -1448,17 +1516,127 @@ struct EncodingRecord
   DEFINE_SIZE_STATIC (8);
 };
 
+struct cmap;
+
+struct SubtableUnicodesCache {
+
+ private:
+  hb_blob_ptr_t<cmap> base_blob;
+  const char* base;
+  hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> cached_unicodes;
+
+ public:
+
+  static SubtableUnicodesCache* create (hb_blob_ptr_t<cmap> source_table)
+  {
+    SubtableUnicodesCache* cache =
+        (SubtableUnicodesCache*) hb_malloc (sizeof(SubtableUnicodesCache));
+    new (cache) SubtableUnicodesCache (source_table);
+    return cache;
+  }
+
+  static void destroy (void* value) {
+    if (!value) return;
+
+    SubtableUnicodesCache* cache = (SubtableUnicodesCache*) value;
+    cache->~SubtableUnicodesCache ();
+    hb_free (cache);
+  }
+
+  SubtableUnicodesCache(const void* cmap_base)
+      : base_blob(),
+        base ((const char*) cmap_base),
+        cached_unicodes ()
+  {}
+
+  SubtableUnicodesCache(hb_blob_ptr_t<cmap> base_blob_)
+      : base_blob(base_blob_),
+        base ((const char *) base_blob.get()),
+        cached_unicodes ()
+  {}
+
+  ~SubtableUnicodesCache()
+  {
+    base_blob.destroy ();
+  }
+
+  bool same_base(const void* other) const
+  {
+    return other == (const void*) base;
+  }
+
+  const hb_set_t* set_for (const EncodingRecord* record,
+                           SubtableUnicodesCache& mutable_cache) const
+  {
+    if (cached_unicodes.has ((unsigned) ((const char *) record - base)))
+      return cached_unicodes.get ((unsigned) ((const char *) record - base));
+
+    return mutable_cache.set_for (record);
+  }
+
+  const hb_set_t* set_for (const EncodingRecord* record)
+  {
+    if (!cached_unicodes.has ((unsigned) ((const char *) record - base)))
+    {
+      hb_set_t *s = hb_set_create ();
+      if (unlikely (s->in_error ()))
+       return hb_set_get_empty ();
+
+      (base+record->subtable).collect_unicodes (s);
+
+      if (unlikely (!cached_unicodes.set ((unsigned) ((const char *) record - base), hb::unique_ptr<hb_set_t> {s})))
+        return hb_set_get_empty ();
+
+      return s;
+    }
+    return cached_unicodes.get ((unsigned) ((const char *) record - base));
+  }
+
+};
+
+static inline uint_fast16_t
+_hb_symbol_pua_map (unsigned codepoint)
+{
+  if (codepoint <= 0x00FFu)
+  {
+    /* For symbol-encoded OpenType fonts, we duplicate the
+     * U+F000..F0FF range at U+0000..U+00FF.  That's what
+     * Windows seems to do, and that's hinted about at:
+     * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
+     * under "Non-Standard (Symbol) Fonts". */
+    return 0xF000u + codepoint;
+  }
+  return 0;
+}
+
 struct cmap
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap;
 
+
+  static SubtableUnicodesCache* create_filled_cache(hb_blob_ptr_t<cmap> source_table) {
+    const cmap* cmap = source_table.get();
+    auto it =
+    + hb_iter (cmap->encodingRecord)
+    | hb_filter ([&](const EncodingRecord& _) {
+      return cmap::filter_encoding_records_for_subset (cmap, _);
+    })
+    ;
+
+    SubtableUnicodesCache* cache = SubtableUnicodesCache::create(source_table);
+    for (const EncodingRecord& _ : it)
+      cache->set_for(&_); // populate the cache for this encoding record.
+
+    return cache;
+  }
+
   template<typename Iterator, typename EncodingRecIter,
           hb_requires (hb_is_iterator (EncodingRecIter))>
   bool serialize (hb_serialize_context_t *c,
                  Iterator it,
                  EncodingRecIter encodingrec_iter,
                  const void *base,
-                 const hb_subset_plan_t *plan,
+                 hb_subset_plan_t *plan,
                   bool drop_format_4 = false)
   {
     if (unlikely (!c->extend_min ((*this))))  return false;
@@ -1467,6 +1645,14 @@ struct cmap
     unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
     auto snap = c->snapshot ();
 
+    SubtableUnicodesCache local_unicodes_cache (base);
+    const SubtableUnicodesCache* unicodes_cache = &local_unicodes_cache;
+
+    if (plan->accelerator &&
+        plan->accelerator->cmap_cache &&
+        plan->accelerator->cmap_cache->same_base (base))
+      unicodes_cache = plan->accelerator->cmap_cache;
+
     for (const EncodingRecord& _ : encodingrec_iter)
     {
       if (c->in_error ())
@@ -1475,12 +1661,11 @@ struct cmap
       unsigned format = (base+_.subtable).u.format;
       if (format != 4 && format != 12 && format != 14) continue;
 
-      hb_set_t unicodes_set;
-      (base+_.subtable).collect_unicodes (&unicodes_set);
+      const hb_set_t* unicodes_set = unicodes_cache->set_for (&_, local_unicodes_cache);
 
       if (!drop_format_4 && format == 4)
       {
-        c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx);
+        c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 4u, base, plan, &format4objidx);
         if (c->in_error () && c->only_overflow ())
         {
           // cmap4 overflowed, reset and retry serialization without format 4 subtables.
@@ -1495,8 +1680,14 @@ struct cmap
 
       else if (format == 12)
       {
-        if (_can_drop (_, unicodes_set, base, + it | hb_map (hb_first), encodingrec_iter)) continue;
-        c->copy (_, + it | hb_filter (unicodes_set, hb_first), 12u, base, plan, &format12objidx);
+        if (_can_drop (_,
+                       *unicodes_set,
+                       base,
+                       *unicodes_cache,
+                       local_unicodes_cache,
+                       + it | hb_map (hb_first), encodingrec_iter))
+          continue;
+        c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 12u, base, plan, &format12objidx);
       }
       else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx);
     }
@@ -1514,6 +1705,8 @@ struct cmap
   bool _can_drop (const EncodingRecord& cmap12,
                   const hb_set_t& cmap12_unicodes,
                   const void* base,
+                  const SubtableUnicodesCache& unicodes_cache,
+                  SubtableUnicodesCache& local_unicodes_cache,
                   Iterator subset_unicodes,
                   EncodingRecordIterator encoding_records)
   {
@@ -1544,11 +1737,10 @@ struct cmap
           || (base+_.subtable).get_language() != target_language)
         continue;
 
-      hb_set_t sibling_unicodes;
-      (base+_.subtable).collect_unicodes (&sibling_unicodes);
+      const hb_set_t* sibling_unicodes = unicodes_cache.set_for (&_, local_unicodes_cache);
 
       auto cmap12 = + subset_unicodes | hb_filter (cmap12_unicodes);
-      auto sibling = + subset_unicodes | hb_filter (sibling_unicodes);
+      auto sibling = + subset_unicodes | hb_filter (*sibling_unicodes);
       for (; cmap12 && sibling; cmap12++, sibling++)
       {
         unsigned a = *cmap12;
@@ -1578,21 +1770,12 @@ struct cmap
     TRACE_SUBSET (this);
 
     cmap *cmap_prime = c->serializer->start_embed<cmap> ();
-    if (unlikely (!c->serializer->check_success (cmap_prime))) return_trace (false);
 
     auto encodingrec_iter =
     + hb_iter (encodingRecord)
-    | hb_filter ([&] (const EncodingRecord& _)
-               {
-                 if ((_.platformID == 0 && _.encodingID == 3) ||
-                     (_.platformID == 0 && _.encodingID == 4) ||
-                     (_.platformID == 3 && _.encodingID == 1) ||
-                     (_.platformID == 3 && _.encodingID == 10) ||
-                     (this + _.subtable).u.format == 14)
-                   return true;
-
-                 return false;
-               })
+    | hb_filter ([&](const EncodingRecord& _) {
+      return cmap::filter_encoding_records_for_subset (this, _);
+    })
     ;
 
     if (unlikely (!encodingrec_iter.len ())) return_trace (false);
@@ -1616,18 +1799,16 @@ struct cmap
     if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false);
 
     auto it =
-    + hb_iter (c->plan->unicodes)
-    | hb_map ([&] (hb_codepoint_t _)
-             {
-               hb_codepoint_t new_gid = HB_MAP_VALUE_INVALID;
-               c->plan->new_gid_for_codepoint (_, &new_gid);
-               return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (_, new_gid);
-             })
-    | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
+    + c->plan->unicode_to_new_gid_list.iter ()
+    | hb_filter ([&] (const hb_codepoint_pair_t _)
                 { return (_.second != HB_MAP_VALUE_INVALID); })
     ;
 
-    return_trace (cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan));
+    return_trace (cmap_prime->serialize (c->serializer,
+                                         it,
+                                         encodingrec_iter,
+                                         this,
+                                         c->plan));
   }
 
   const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
@@ -1663,6 +1844,8 @@ struct cmap
 
   struct accelerator_t
   {
+    using cache_t = hb_cache_t<21, 16, 8, true>;
+
     accelerator_t (hb_face_t *face)
     {
       this->table = hb_sanitize_context_t ().reference_table<cmap> (face);
@@ -1677,7 +1860,24 @@ struct cmap
 
       this->get_glyph_data = subtable;
       if (unlikely (symbol))
-       this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable>;
+      {
+       switch ((unsigned) face->table.OS2->get_font_page ()) {
+       case OS2::font_page_t::FONT_PAGE_NONE:
+         this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_symbol_pua_map>;
+         break;
+#ifndef HB_NO_OT_SHAPER_ARABIC_FALLBACK
+       case OS2::font_page_t::FONT_PAGE_SIMP_ARABIC:
+         this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_arabic_pua_simp_map>;
+         break;
+       case OS2::font_page_t::FONT_PAGE_TRAD_ARABIC:
+         this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_arabic_pua_trad_map>;
+         break;
+#endif
+       default:
+         this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;
+         break;
+       }
+      }
       else
       {
        switch (subtable->u.format) {
@@ -1700,26 +1900,43 @@ struct cmap
     }
     ~accelerator_t () { this->table.destroy (); }
 
+    inline bool _cached_get (hb_codepoint_t unicode,
+                            hb_codepoint_t *glyph,
+                            cache_t *cache) const
+    {
+      unsigned v;
+      if (cache && cache->get (unicode, &v))
+      {
+        *glyph = v;
+       return true;
+      }
+      bool ret  = this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph);
+
+      if (cache && ret)
+        cache->set (unicode, *glyph);
+      return ret;
+    }
+
     bool get_nominal_glyph (hb_codepoint_t  unicode,
-                           hb_codepoint_t *glyph) const
+                           hb_codepoint_t *glyph,
+                           cache_t *cache = nullptr) const
     {
-      if (unlikely (!this->get_glyph_funcZ)) return false;
-      return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph);
+      if (unlikely (!this->get_glyph_funcZ)) return 0;
+      return _cached_get (unicode, glyph, cache);
     }
+
     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
+                                    unsigned int glyph_stride,
+                                    cache_t *cache = nullptr) const
     {
       if (unlikely (!this->get_glyph_funcZ)) return 0;
 
-      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 < count && _cached_get (*first_unicode, first_glyph, cache);
           done++)
       {
        first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
@@ -1730,7 +1947,8 @@ struct cmap
 
     bool get_variation_glyph (hb_codepoint_t  unicode,
                              hb_codepoint_t  variation_selector,
-                             hb_codepoint_t *glyph) const
+                             hb_codepoint_t *glyph,
+                             cache_t *cache = nullptr) const
     {
       switch (this->subtable_uvs->get_glyph_variant (unicode,
                                                     variation_selector,
@@ -1741,7 +1959,7 @@ struct cmap
        case GLYPH_VARIANT_USE_DEFAULT: break;
       }
 
-      return get_nominal_glyph (unicode, glyph);
+      return get_nominal_glyph (unicode, glyph, cache);
     }
 
     void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
@@ -1759,6 +1977,7 @@ struct cmap
     typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
                                              hb_codepoint_t codepoint,
                                              hb_codepoint_t *glyph);
+    typedef uint_fast16_t (*hb_pua_remap_func_t) (unsigned);
 
     template <typename Type>
     HB_INTERNAL static bool get_glyph_from (const void *obj,
@@ -1769,7 +1988,7 @@ struct cmap
       return typed_obj->get_glyph (codepoint, glyph);
     }
 
-    template <typename Type>
+    template <typename Type, hb_pua_remap_func_t remap>
     HB_INTERNAL static bool get_glyph_from_symbol (const void *obj,
                                                   hb_codepoint_t codepoint,
                                                   hb_codepoint_t *glyph)
@@ -1778,15 +1997,8 @@ struct cmap
       if (likely (typed_obj->get_glyph (codepoint, glyph)))
        return true;
 
-      if (codepoint <= 0x00FFu)
-      {
-       /* For symbol-encoded OpenType fonts, we duplicate the
-        * U+F000..F0FF range at U+0000..U+00FF.  That's what
-        * Windows seems to do, and that's hinted about at:
-        * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
-        * under "Non-Standard (Symbol) Fonts". */
-       return typed_obj->get_glyph (0xF000u + codepoint, glyph);
-      }
+      if (hb_codepoint_t c = remap (codepoint))
+       return typed_obj->get_glyph (c, glyph);
 
       return false;
     }
@@ -1852,6 +2064,19 @@ struct cmap
                  encodingRecord.sanitize (c, this));
   }
 
+ private:
+
+  static bool filter_encoding_records_for_subset(const cmap* cmap,
+                                                 const EncodingRecord& _)
+  {
+    return
+        (_.platformID == 0 && _.encodingID == 3) ||
+        (_.platformID == 0 && _.encodingID == 4) ||
+        (_.platformID == 3 && _.encodingID == 1) ||
+        (_.platformID == 3 && _.encodingID == 10) ||
+        (cmap + _.subtable).u.format == 14;
+  }
+
   protected:
   HBUINT16     version;        /* Table version number (0). */
   SortedArray16Of<EncodingRecord>
index 1607776..37d42e0 100644 (file)
 
 #include "hb-ot.h"
 
-#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 "OT/Color/CBDT/CBDT.hh"
+#include "OT/Color/COLR/COLR.hh"
+#include "OT/Color/CPAL/CPAL.hh"
+#include "OT/Color/sbix/sbix.hh"
+#include "OT/Color/svg/svg.hh"
 
 
 /**
@@ -61,7 +61,7 @@
  *
  * Tests whether a face includes a `CPAL` color-palette table.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.1.0
  */
@@ -167,6 +167,10 @@ hb_ot_color_palette_get_flags (hb_face_t *face,
  * for allocating a buffer of suitable size before calling
  * hb_ot_color_palette_get_colors() a second time.
  *
+ * The RGBA values in the palette are unpremultiplied. See the
+ * OpenType spec [CPAL](https://learn.microsoft.com/en-us/typography/opentype/spec/cpal)
+ * section for details.
+ *
  * Return value: the total number of colors in the palette
  *
  * Since: 2.1.0
@@ -190,16 +194,53 @@ hb_ot_color_palette_get_colors (hb_face_t     *face,
  * hb_ot_color_has_layers:
  * @face: #hb_face_t to work upon
  *
- * Tests whether a face includes any `COLR` color layers.
+ * Tests whether a face includes a `COLR` table
+ * with data according to COLRv0.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.1.0
  */
 hb_bool_t
 hb_ot_color_has_layers (hb_face_t *face)
 {
-  return face->table.COLR->has_data ();
+  return face->table.COLR->has_v0_data ();
+}
+
+/**
+ * hb_ot_color_has_paint:
+ * @face: #hb_face_t to work upon
+ *
+ * Tests where a face includes a `COLR` table
+ * with data according to COLRv1.
+ *
+ * Return value: `true` if data found, `false` otherwise
+ *
+ * Since: 7.0.0
+ */
+hb_bool_t
+hb_ot_color_has_paint (hb_face_t *face)
+{
+  return face->table.COLR->has_v1_data ();
+}
+
+/**
+ * hb_ot_color_glyph_has_paint:
+ * @face: #hb_face_t to work upon
+ * @glyph: The glyph index to query
+ *
+ * Tests where a face includes COLRv1 paint
+ * data for @glyph.
+ *
+ * Return value: `true` if data found, `false` otherwise
+ *
+ * Since: 7.0.0
+ */
+hb_bool_t
+hb_ot_color_glyph_has_paint (hb_face_t      *face,
+                             hb_codepoint_t  glyph)
+{
+  return face->table.COLR->has_paint_for_glyph (glyph);
 }
 
 /**
@@ -239,7 +280,7 @@ hb_ot_color_glyph_get_layers (hb_face_t           *face,
  *
  * Tests whether a face includes any `SVG` glyph images.
  *
- * Return value: %true if data found, %false otherwise.
+ * Return value: `true` if data found, `false` otherwise.
  *
  * Since: 2.1.0
  */
@@ -279,7 +320,7 @@ hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph)
  *
  * Tests whether a face has PNG glyph images (either in `CBDT` or `sbix` tables).
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.1.0
  */
@@ -295,8 +336,8 @@ hb_ot_color_has_png (hb_face_t *face)
  * @glyph: a glyph index
  *
  * Fetches the PNG image for a glyph. This function takes a font object, not a face object,
- * as input. To get an optimally sized PNG blob, the UPEM value must be set on the @font
- * object. If UPEM is unset, the blob returned will be the largest PNG available.
+ * as input. To get an optimally sized PNG blob, the PPEM values must be set on the @font
+ * object. If PPEM is unset, the blob returned will be the largest PNG available.
  *
  * If the glyph has no PNG image, the singleton empty blob is returned.
  *
index c23ce4d..22ee497 100644 (file)
@@ -102,6 +102,10 @@ hb_ot_color_has_layers (hb_face_t *face);
  *
  * Pairs of glyph and color index.
  *
+ * A color index of 0xFFFF does not refer to a palette
+ * color, but indicates that the foreground color should
+ * be used.
+ *
  * Since: 2.1.0
  **/
 typedef struct hb_ot_color_layer_t {
@@ -116,6 +120,15 @@ hb_ot_color_glyph_get_layers (hb_face_t           *face,
                              unsigned int        *layer_count, /* IN/OUT.  May be NULL. */
                              hb_ot_color_layer_t *layers /* OUT.     May be NULL. */);
 
+/* COLRv1 */
+
+HB_EXTERN hb_bool_t
+hb_ot_color_has_paint (hb_face_t *face);
+
+HB_EXTERN hb_bool_t
+hb_ot_color_glyph_has_paint (hb_face_t      *face,
+                             hb_codepoint_t  glyph);
+
 /*
  * SVG
  */
index 5192ff7..60672ab 100644 (file)
@@ -67,26 +67,30 @@ HB_BEGIN_DECLS
 
 
 /* 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_DEPRECATED_FOR (hb_ot_layout_table_select_script)
+HB_EXTERN 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_DEPRECATED_FOR (hb_ot_layout_script_select_language)
+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_EXTERN HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) void
+HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language)
+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_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) hb_tag_t
+HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language)
+HB_EXTERN hb_tag_t
 hb_ot_tag_from_language (hb_language_t language);
 
 
@@ -121,13 +125,15 @@ typedef struct hb_ot_var_axis_t {
   float max_value;
 } hb_ot_var_axis_t;
 
-HB_EXTERN HB_DEPRECATED_FOR (hb_ot_var_get_axis_infos) unsigned int
+HB_DEPRECATED_FOR (hb_ot_var_get_axis_infos)
+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_EXTERN HB_DEPRECATED_FOR (hb_ot_var_find_axis_info) hb_bool_t
+HB_DEPRECATED_FOR (hb_ot_var_find_axis_info)
+HB_EXTERN hb_bool_t
 hb_ot_var_find_axis (hb_face_t        *face,
                     hb_tag_t          axis_tag,
                     unsigned int     *axis_index,
index eff0983..b552dfd 100644 (file)
 #define HB_OT_FACE_TABLE_LIST_HH
 #endif /* HB_OT_FACE_TABLE_LIST_HH */ /* Dummy header guards */
 
+#ifndef HB_OT_CORE_TABLE
+#define HB_OT_CORE_TABLE(Namespace, Type) HB_OT_TABLE (Namespace, Type)
+#define _HB_OT_CORE_TABLE_UNDEF
+#endif
+
 #ifndef HB_OT_ACCELERATOR
 #define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
 #define _HB_OT_ACCELERATOR_UNDEF
 
 
 /* OpenType fundamentals. */
-HB_OT_TABLE (OT, head)
+HB_OT_CORE_TABLE (OT, head)
+HB_OT_CORE_TABLE (OT, maxp)
 #if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT)
 HB_OT_ACCELERATOR (OT, cmap)
 #endif
-HB_OT_TABLE (OT, hhea)
+HB_OT_CORE_TABLE (OT, hhea)
 HB_OT_ACCELERATOR (OT, hmtx)
-HB_OT_TABLE (OT, OS2)
+HB_OT_CORE_TABLE (OT, OS2)
 #if !defined(HB_NO_OT_FONT_GLYPH_NAMES) || !defined(HB_NO_METRICS) || !defined(HB_NO_STYLE)
 HB_OT_ACCELERATOR (OT, post)
 #endif
@@ -60,7 +66,7 @@ HB_OT_ACCELERATOR (OT, post)
 HB_OT_ACCELERATOR (OT, name)
 #endif
 #ifndef HB_NO_STYLE
-HB_OT_TABLE (OT, STAT)
+HB_OT_CORE_TABLE (OT, STAT)
 #endif
 #ifndef HB_NO_META
 HB_OT_ACCELERATOR (OT, meta)
@@ -68,12 +74,13 @@ HB_OT_ACCELERATOR (OT, meta)
 
 /* Vertical layout. */
 #ifndef HB_NO_VERTICAL
-HB_OT_TABLE (OT, vhea)
+HB_OT_CORE_TABLE (OT, vhea)
 HB_OT_ACCELERATOR (OT, vmtx)
-HB_OT_TABLE (OT, VORG)
+HB_OT_CORE_TABLE (OT, VORG)
 #endif
 
 /* TrueType outlines. */
+HB_OT_CORE_TABLE (OT, loca) // Also used to determine number of glyphs
 HB_OT_ACCELERATOR (OT, glyf)
 
 /* CFF outlines. */
@@ -84,15 +91,16 @@ HB_OT_ACCELERATOR (OT, cff2)
 
 /* OpenType variations. */
 #ifndef HB_NO_VAR
-HB_OT_TABLE (OT, fvar)
-HB_OT_TABLE (OT, avar)
+HB_OT_CORE_TABLE (OT, fvar)
+HB_OT_CORE_TABLE (OT, avar)
+HB_OT_CORE_TABLE (OT, cvar)
 HB_OT_ACCELERATOR (OT, gvar)
-HB_OT_TABLE (OT, MVAR)
+HB_OT_CORE_TABLE (OT, MVAR)
 #endif
 
 /* Legacy kern. */
 #ifndef HB_NO_OT_KERN
-HB_OT_TABLE (OT, kern)
+HB_OT_CORE_TABLE (OT, kern)
 #endif
 
 /* OpenType shaping. */
@@ -100,12 +108,12 @@ HB_OT_TABLE (OT, kern)
 HB_OT_ACCELERATOR (OT, GDEF)
 HB_OT_ACCELERATOR (OT, GSUB)
 HB_OT_ACCELERATOR (OT, GPOS)
-//HB_OT_TABLE (OT, JSTF)
+//HB_OT_CORE_TABLE (OT, JSTF)
 #endif
 
 /* OpenType baseline. */
 #ifndef HB_NO_BASE
-HB_OT_TABLE (OT, BASE)
+HB_OT_CORE_TABLE (OT, BASE)
 #endif
 
 /* AAT shaping. */
@@ -122,8 +130,8 @@ HB_OT_TABLE (AAT, feat)
 
 /* OpenType color fonts. */
 #ifndef HB_NO_COLOR
-HB_OT_TABLE (OT, COLR)
-HB_OT_TABLE (OT, CPAL)
+HB_OT_CORE_TABLE (OT, COLR)
+HB_OT_CORE_TABLE (OT, CPAL)
 HB_OT_ACCELERATOR (OT, CBDT)
 HB_OT_ACCELERATOR (OT, sbix)
 HB_OT_ACCELERATOR (OT, SVG)
@@ -131,10 +139,14 @@ HB_OT_ACCELERATOR (OT, SVG)
 
 /* OpenType math. */
 #ifndef HB_NO_MATH
-HB_OT_TABLE (OT, MATH)
+HB_OT_CORE_TABLE (OT, MATH)
 #endif
 
 
 #ifdef _HB_OT_ACCELERATOR_UNDEF
 #undef HB_OT_ACCELERATOR
 #endif
+
+#ifdef _HB_OT_CORE_TABLE_UNDEF
+#undef HB_OT_CORE_TABLE
+#endif
index 5ef8df4..2243ee0 100644 (file)
@@ -35,9 +35,9 @@
 #include "hb-ot-meta-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 "OT/Color/CBDT/CBDT.hh"
+#include "OT/Color/sbix/sbix.hh"
+#include "OT/Color/svg/svg.hh"
 #include "hb-ot-layout-gdef-table.hh"
 #include "hb-ot-layout-gsub-table.hh"
 #include "hb-ot-layout-gpos-table.hh"
index e24d380..415dae8 100644 (file)
@@ -63,10 +63,13 @@ struct hb_ot_face_t
   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_CORE_TABLE(Namespace, Type) \
+  hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER (Namespace, Type), true> Type;
 #define HB_OT_ACCELERATOR(Namespace, Type) \
   hb_face_lazy_loader_t<Namespace::Type##_accelerator_t, HB_OT_TABLE_ORDER (Namespace, Type)> Type;
 #include "hb-ot-face-table-list.hh"
 #undef HB_OT_ACCELERATOR
+#undef HB_OT_CORE_TABLE
 #undef HB_OT_TABLE
 };
 
index 9f0359a..b3677c6 100644 (file)
 
 #include "hb-ot.h"
 
+#include "hb-cache.hh"
 #include "hb-font.hh"
 #include "hb-machinery.hh"
 #include "hb-ot-face.hh"
+#include "hb-outline.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-cff1-table.hh"
 #include "hb-ot-hmtx-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"
+#include "OT/Color/CBDT/CBDT.hh"
+#include "OT/Color/COLR/COLR.hh"
+#include "OT/Color/sbix/sbix.hh"
+#include "OT/Color/svg/svg.hh"
 
 
 /**
  * never need to call these functions directly.
  **/
 
+using hb_ot_font_cmap_cache_t    = hb_cache_t<21, 16, 8, true>;
+using hb_ot_font_advance_cache_t = hb_cache_t<24, 16, 8, true>;
+
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
+static hb_user_data_key_t hb_ot_font_cmap_cache_user_data_key;
+#endif
+
+struct hb_ot_font_t
+{
+  const hb_ot_face_t *ot_face;
+
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
+  hb_ot_font_cmap_cache_t *cmap_cache;
+#endif
+
+  /* h_advance caching */
+  mutable hb_atomic_int_t cached_coords_serial;
+  mutable hb_atomic_ptr_t<hb_ot_font_advance_cache_t> advance_cache;
+};
+
+static hb_ot_font_t *
+_hb_ot_font_create (hb_font_t *font)
+{
+  hb_ot_font_t *ot_font = (hb_ot_font_t *) hb_calloc (1, sizeof (hb_ot_font_t));
+  if (unlikely (!ot_font))
+    return nullptr;
+
+  ot_font->ot_face = &font->face->table;
+
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
+  // retry:
+  auto *cmap_cache  = (hb_ot_font_cmap_cache_t *) hb_face_get_user_data (font->face,
+                                                                        &hb_ot_font_cmap_cache_user_data_key);
+  if (!cmap_cache)
+  {
+    cmap_cache = (hb_ot_font_cmap_cache_t *) hb_malloc (sizeof (hb_ot_font_cmap_cache_t));
+    if (unlikely (!cmap_cache)) goto out;
+    new (cmap_cache) hb_ot_font_cmap_cache_t ();
+    if (unlikely (!hb_face_set_user_data (font->face,
+                                         &hb_ot_font_cmap_cache_user_data_key,
+                                         cmap_cache,
+                                         hb_free,
+                                         false)))
+    {
+      hb_free (cmap_cache);
+      cmap_cache = nullptr;
+      /* Normally we would retry here, but that would
+       * infinite-loop if the face is the empty-face.
+       * Just let it go and this font will be uncached if it
+       * happened to collide with another thread creating the
+       * cache at the same time. */
+      // goto retry;
+    }
+  }
+  out:
+  ot_font->cmap_cache = cmap_cache;
+#endif
+
+  return ot_font;
+}
+
+static void
+_hb_ot_font_destroy (void *font_data)
+{
+  hb_ot_font_t *ot_font = (hb_ot_font_t *) font_data;
+
+  auto *cache = ot_font->advance_cache.get_relaxed ();
+  hb_free (cache);
+
+  hb_free (ot_font);
+}
 
 static hb_bool_t
 hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
@@ -66,8 +140,13 @@ hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
                         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);
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  const hb_ot_face_t *ot_face = ot_font->ot_face;
+  hb_ot_font_cmap_cache_t *cmap_cache = nullptr;
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
+  cmap_cache = ot_font->cmap_cache;
+#endif
+  return ot_face->cmap->get_nominal_glyph (unicode, glyph, cmap_cache);
 }
 
 static unsigned int
@@ -80,10 +159,16 @@ hb_ot_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
                          unsigned int glyph_stride,
                          void *user_data HB_UNUSED)
 {
-  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  const hb_ot_face_t *ot_face = ot_font->ot_face;
+  hb_ot_font_cmap_cache_t *cmap_cache = nullptr;
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
+  cmap_cache = ot_font->cmap_cache;
+#endif
   return ot_face->cmap->get_nominal_glyphs (count,
                                            first_unicode, unicode_stride,
-                                           first_glyph, glyph_stride);
+                                           first_glyph, glyph_stride,
+                                           cmap_cache);
 }
 
 static hb_bool_t
@@ -94,8 +179,15 @@ hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED,
                           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_variation_glyph (unicode, variation_selector, glyph);
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  const hb_ot_face_t *ot_face = ot_font->ot_face;
+  hb_ot_font_cmap_cache_t *cmap_cache = nullptr;
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
+  cmap_cache = ot_font->cmap_cache;
+#endif
+  return ot_face->cmap->get_variation_glyph (unicode,
+                                             variation_selector, glyph,
+                                             cmap_cache);
 }
 
 static void
@@ -107,14 +199,97 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
                            unsigned advance_stride,
                            void *user_data HB_UNUSED)
 {
-  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  const hb_ot_face_t *ot_face = ot_font->ot_face;
   const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx;
 
-  for (unsigned int i = 0; i < count; i++)
+  hb_position_t *orig_first_advance = first_advance;
+
+#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
+  const OT::HVAR &HVAR = *hmtx.var_table;
+  const OT::VariationStore &varStore = &HVAR + HVAR.varStore;
+  OT::VariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr;
+
+  bool use_cache = font->num_coords;
+#else
+  OT::VariationStore::cache_t *varStore_cache = nullptr;
+  bool use_cache = false;
+#endif
+
+  hb_ot_font_advance_cache_t *cache = nullptr;
+  if (use_cache)
   {
-    *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);
+  retry:
+    cache = ot_font->advance_cache.get_acquire ();
+    if (unlikely (!cache))
+    {
+      cache = (hb_ot_font_advance_cache_t *) hb_malloc (sizeof (hb_ot_font_advance_cache_t));
+      if (unlikely (!cache))
+      {
+       use_cache = false;
+       goto out;
+      }
+      new (cache) hb_ot_font_advance_cache_t;
+
+      if (unlikely (!ot_font->advance_cache.cmpexch (nullptr, cache)))
+      {
+       hb_free (cache);
+       goto retry;
+      }
+      ot_font->cached_coords_serial.set_release (font->serial_coords);
+    }
+  }
+  out:
+
+  if (!use_cache)
+  {
+    for (unsigned int i = 0; i < count; i++)
+    {
+      *first_advance = font->em_scale_x (hmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache));
+      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
+    }
+  }
+  else
+  { /* Use cache. */
+    if (ot_font->cached_coords_serial.get_acquire () != (int) font->serial_coords)
+    {
+      ot_font->advance_cache->clear ();
+      ot_font->cached_coords_serial.set_release (font->serial_coords);
+    }
+
+    for (unsigned int i = 0; i < count; i++)
+    {
+      hb_position_t v;
+      unsigned cv;
+      if (ot_font->advance_cache->get (*first_glyph, &cv))
+       v = cv;
+      else
+      {
+        v = hmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache);
+       ot_font->advance_cache->set (*first_glyph, v);
+      }
+      *first_advance = font->em_scale_x (v);
+      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
+    }
+  }
+
+#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
+  OT::VariationStore::destroy_cache (varStore_cache);
+#endif
+
+  if (font->x_strength && !font->embolden_in_place)
+  {
+    /* Emboldening. */
+    hb_position_t x_strength = font->x_scale >= 0 ? font->x_strength : -font->x_strength;
+    first_advance = orig_first_advance;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      *first_advance += *first_advance ? x_strength : 0;
+      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
+    }
   }
 }
 
@@ -128,14 +303,57 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
                            unsigned advance_stride,
                            void *user_data HB_UNUSED)
 {
-  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  const hb_ot_face_t *ot_face = ot_font->ot_face;
   const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
 
-  for (unsigned int i = 0; i < count; i++)
+  hb_position_t *orig_first_advance = first_advance;
+
+  if (vmtx.has_data ())
+  {
+#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
+    const OT::VVAR &VVAR = *vmtx.var_table;
+    const OT::VariationStore &varStore = &VVAR + VVAR.varStore;
+    OT::VariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr;
+#else
+    OT::VariationStore::cache_t *varStore_cache = nullptr;
+#endif
+
+    for (unsigned int i = 0; i < count; i++)
+    {
+      *first_advance = font->em_scale_y (-(int) vmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache));
+      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
+    }
+
+#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
+    OT::VariationStore::destroy_cache (varStore_cache);
+#endif
+  }
+  else
   {
-    *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);
+    hb_font_extents_t font_extents;
+    font->get_h_extents_with_fallback (&font_extents);
+    hb_position_t advance = -(font_extents.ascender - font_extents.descender);
+
+    for (unsigned int i = 0; i < count; i++)
+    {
+      *first_advance = advance;
+      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
+    }
+  }
+
+  if (font->y_strength && !font->embolden_in_place)
+  {
+    /* Emboldening. */
+    hb_position_t y_strength = font->y_scale >= 0 ? font->y_strength : -font->y_strength;
+    first_advance = orig_first_advance;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      *first_advance += *first_advance ? y_strength : 0;
+      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
+    }
   }
 }
 #endif
@@ -149,14 +367,26 @@ hb_ot_get_glyph_v_origin (hb_font_t *font,
                          hb_position_t *y,
                          void *user_data HB_UNUSED)
 {
-  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  const hb_ot_face_t *ot_face = ot_font->ot_face;
 
   *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));
+    float delta = 0;
+
+#ifndef HB_NO_VAR
+    const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
+    const OT::VVAR &VVAR = *vmtx.var_table;
+    if (font->num_coords)
+      VVAR.get_vorg_delta_unscaled (glyph,
+                                   font->coords, font->num_coords,
+                                   &delta);
+#endif
+
+    *y = font->em_scalef_y (VORG.get_y_origin (glyph) + delta);
     return true;
   }
 
@@ -164,8 +394,18 @@ hb_ot_get_glyph_v_origin (hb_font_t *font,
   if (ot_face->glyf->get_extents (font, glyph, &extents))
   {
     const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
-    hb_position_t tsb = vmtx.get_side_bearing (font, glyph);
-    *y = extents.y_bearing + font->em_scale_y (tsb);
+    int tsb = 0;
+    if (vmtx.get_leading_bearing_with_var_unscaled (font, glyph, &tsb))
+    {
+      *y = extents.y_bearing + font->em_scale_y (tsb);
+      return true;
+    }
+
+    hb_font_extents_t font_extents;
+    font->get_h_extents_with_fallback (&font_extents);
+    hb_position_t advance = font_extents.ascender - font_extents.descender;
+    int diff = advance - -extents.height;
+    *y = extents.y_bearing + (diff >> 1);
     return true;
   }
 
@@ -184,21 +424,22 @@ hb_ot_get_glyph_extents (hb_font_t *font,
                         hb_glyph_extents_t *extents,
                         void *user_data HB_UNUSED)
 {
-  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  const hb_ot_face_t *ot_face = ot_font->ot_face;
 
 #if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
   if (ot_face->sbix->get_extents (font, glyph, extents)) return true;
+  if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
+#endif
+#if !defined(HB_NO_COLOR) && !defined(HB_NO_PAINT)
+  if (ot_face->COLR->get_extents (font, glyph, extents)) return true;
 #endif
   if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
 #ifndef HB_NO_OT_FONT_CFF
-  if (ot_face->cff1->get_extents (font, glyph, extents)) return true;
   if (ot_face->cff2->get_extents (font, glyph, extents)) return true;
-#endif
-#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
-  if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
+  if (ot_face->cff1->get_extents (font, glyph, extents)) return true;
 #endif
 
-  // TODO Hook up side-bearings variations.
   return false;
 }
 
@@ -210,7 +451,9 @@ hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
                      char *name, unsigned int size,
                      void *user_data HB_UNUSED)
 {
-  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  const hb_ot_face_t *ot_face = ot_font->ot_face;
+
   if (ot_face->post->get_glyph_name (glyph, name, size)) return true;
 #ifndef HB_NO_OT_FONT_CFF
   if (ot_face->cff1->get_glyph_name (glyph, name, size)) return true;
@@ -224,7 +467,9 @@ hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
                           hb_codepoint_t *glyph,
                           void *user_data HB_UNUSED)
 {
-  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  const hb_ot_face_t *ot_face = ot_font->ot_face;
+
   if (ot_face->post->get_glyph_from_name (name, len, glyph)) return true;
 #ifndef HB_NO_OT_FONT_CFF
     if (ot_face->cff1->get_glyph_from_name (name, len, glyph)) return true;
@@ -239,9 +484,16 @@ hb_ot_get_font_h_extents (hb_font_t *font,
                          hb_font_extents_t *metrics,
                          void *user_data HB_UNUSED)
 {
-  return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) &&
-        _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) &&
-        _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap);
+  bool ret = _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) &&
+            _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) &&
+            _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap);
+
+  /* Embolden */
+  int y_shift = font->y_strength;
+  if (font->y_scale < 0) y_shift = -y_shift;
+  metrics->ascender += y_shift;
+
+  return ret;
 }
 
 #ifndef HB_NO_VERTICAL
@@ -257,6 +509,68 @@ hb_ot_get_font_v_extents (hb_font_t *font,
 }
 #endif
 
+#ifndef HB_NO_DRAW
+static void
+hb_ot_draw_glyph (hb_font_t *font,
+                 void *font_data HB_UNUSED,
+                 hb_codepoint_t glyph,
+                 hb_draw_funcs_t *draw_funcs, void *draw_data,
+                 void *user_data)
+{
+  bool embolden = font->x_strength || font->y_strength;
+  hb_outline_t outline;
+
+  { // Need draw_session to be destructed before emboldening.
+    hb_draw_session_t draw_session (embolden ? hb_outline_recording_pen_get_funcs () : draw_funcs,
+                                   embolden ? &outline : draw_data, font->slant_xy);
+    if (!font->face->table.glyf->get_path (font, glyph, draw_session))
+#ifndef HB_NO_CFF
+    if (!font->face->table.cff2->get_path (font, glyph, draw_session))
+    if (!font->face->table.cff1->get_path (font, glyph, draw_session))
+#endif
+    {}
+  }
+
+  if (embolden)
+  {
+    float x_shift = font->embolden_in_place ? 0 : (float) font->x_strength / 2;
+    float y_shift = (float) font->y_strength / 2;
+    if (font->x_scale < 0) x_shift = -x_shift;
+    if (font->y_scale < 0) y_shift = -y_shift;
+    outline.embolden (font->x_strength, font->y_strength,
+                     x_shift, y_shift);
+
+    outline.replay (draw_funcs, draw_data);
+  }
+}
+#endif
+
+#ifndef HB_NO_PAINT
+static void
+hb_ot_paint_glyph (hb_font_t *font,
+                   void *font_data,
+                   hb_codepoint_t glyph,
+                   hb_paint_funcs_t *paint_funcs, void *paint_data,
+                   unsigned int palette,
+                   hb_color_t foreground,
+                   void *user_data)
+{
+#ifndef HB_NO_COLOR
+  if (font->face->table.COLR->paint_glyph (font, glyph, paint_funcs, paint_data, palette, foreground)) return;
+  if (font->face->table.SVG->paint_glyph (font, glyph, paint_funcs, paint_data)) return;
+#ifndef HB_NO_OT_FONT_BITMAP
+  if (font->face->table.CBDT->paint_glyph (font, glyph, paint_funcs, paint_data)) return;
+  if (font->face->table.sbix->paint_glyph (font, glyph, paint_funcs, paint_data)) return;
+#endif
+#endif
+  if (font->face->table.glyf->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
+#ifndef HB_NO_CFF
+  if (font->face->table.cff2->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
+  if (font->face->table.cff1->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
+#endif
+}
+#endif
+
 static inline void free_static_ot_funcs ();
 
 static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot_font_funcs_lazy_loader_t>
@@ -279,6 +593,14 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot
     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr);
 #endif
 
+#ifndef HB_NO_DRAW
+    hb_font_funcs_set_draw_glyph_func (funcs, hb_ot_draw_glyph, nullptr, nullptr);
+#endif
+
+#ifndef HB_NO_PAINT
+    hb_font_funcs_set_paint_glyph_func (funcs, hb_ot_paint_glyph, nullptr, nullptr);
+#endif
+
     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);
 
@@ -319,25 +641,14 @@ _hb_ot_get_font_funcs ()
 void
 hb_ot_font_set_funcs (hb_font_t *font)
 {
+  hb_ot_font_t *ot_font = _hb_ot_font_create (font);
+  if (unlikely (!ot_font))
+    return;
+
   hb_font_set_funcs (font,
                     _hb_ot_get_font_funcs (),
-                    &font->face->table,
-                    nullptr);
-}
-
-#ifndef HB_NO_VAR
-int
-_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
-{
-  return font->face->table.glyf->get_side_bearing_var (font, glyph, is_vertical);
-}
-
-unsigned
-_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
-{
-  return font->face->table.glyf->get_advance_var (font, glyph, is_vertical);
+                    ot_font,
+                    _hb_ot_font_destroy);
 }
-#endif
-
 
 #endif
index 87a7d80..c32ff76 100644 (file)
 #ifndef HB_OT_GLYF_TABLE_HH
 #define HB_OT_GLYF_TABLE_HH
 
-#include "hb-open-type.hh"
-#include "hb-ot-head-table.hh"
-#include "hb-ot-hmtx-table.hh"
-#include "hb-ot-var-gvar-table.hh"
-#include "hb-draw.hh"
-
-namespace OT {
-
-
-/*
- * loca -- Index to Location
- * https://docs.microsoft.com/en-us/typography/opentype/spec/loca
- */
-#define HB_OT_TAG_loca HB_TAG('l','o','c','a')
-
-#ifndef HB_MAX_COMPOSITE_OPERATIONS
-#define HB_MAX_COMPOSITE_OPERATIONS 100000
-#endif
-
-
-struct loca
-{
-  friend struct glyf;
-
-  static constexpr hb_tag_t tableTag = HB_OT_TAG_loca;
-
-  bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (true);
-  }
-
-  protected:
-  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. */
-};
-
-
-/*
- * glyf -- TrueType Glyph Data
- * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf
- */
-#define HB_OT_TAG_glyf HB_TAG('g','l','y','f')
-
-
-struct glyf
-{
-  static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf;
-
-  bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
-  {
-    TRACE_SANITIZE (this);
-    /* Runtime checks as eager sanitizing each glyph is costy */
-    return_trace (true);
-  }
-
-  template<typename Iterator,
-          hb_requires (hb_is_source_of (Iterator, unsigned int))>
-  static bool
-  _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_short_loca)
-  {
-    unsigned num_offsets = padded_offsets.len () + 1;
-    unsigned entry_size = use_short_loca ? 2 : 4;
-    char *loca_prime_data = (char *) hb_calloc (entry_size, num_offsets);
-
-    if (unlikely (!loca_prime_data)) return false;
-
-    DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d size %d",
-              entry_size, num_offsets, entry_size * num_offsets);
-
-    if (use_short_loca)
-      _write_loca (padded_offsets, 1, hb_array ((HBUINT16 *) loca_prime_data, num_offsets));
-    else
-      _write_loca (padded_offsets, 0, hb_array ((HBUINT32 *) loca_prime_data, num_offsets));
-
-    hb_blob_t *loca_blob = hb_blob_create (loca_prime_data,
-                                          entry_size * num_offsets,
-                                          HB_MEMORY_MODE_WRITABLE,
-                                          loca_prime_data,
-                                          hb_free);
-
-    bool result = plan->add_table (HB_OT_TAG_loca, loca_blob)
-              && _add_head_and_set_loca_version (plan, use_short_loca);
-
-    hb_blob_destroy (loca_blob);
-    return result;
-  }
-
-  template<typename IteratorIn, typename IteratorOut,
-          hb_requires (hb_is_source_of (IteratorIn, unsigned int)),
-          hb_requires (hb_is_sink_of (IteratorOut, unsigned))>
-  static void
-  _write_loca (IteratorIn it, unsigned right_shift, IteratorOut dest)
-  {
-    unsigned int offset = 0;
-    dest << 0;
-    + it
-    | hb_map ([=, &offset] (unsigned int padded_size)
-             {
-               offset += padded_size;
-               DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d", offset);
-               return offset >> right_shift;
-             })
-    | hb_sink (dest)
-    ;
-  }
-
-  /* requires source of SubsetGlyph complains the identifier isn't declared */
-  template <typename Iterator>
-  bool serialize (hb_serialize_context_t *c,
-                 Iterator it,
-                  bool use_short_loca,
-                 const hb_subset_plan_t *plan)
-  {
-    TRACE_SERIALIZE (this);
-    unsigned init_len = c->length ();
-    for (const auto &_ : it) _.serialize (c, use_short_loca, plan);
-
-    /* As a special case when all glyph in the font are empty, add a zero byte
-     * to the table, so that OTS doesn’t reject it, and to make the table work
-     * on Windows as well.
-     * See https://github.com/khaledhosny/ots/issues/52 */
-    if (init_len == c->length ())
-    {
-      HBUINT8 empty_byte;
-      empty_byte = 0;
-      c->copy (empty_byte);
-    }
-    return_trace (true);
-  }
-
-  /* Byte region(s) per glyph to output
-     unpadded, hints removed if so requested
-     If we fail to process a glyph we produce an empty (0-length) glyph */
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-
-    glyf *glyf_prime = c->serializer->start_embed <glyf> ();
-    if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
-
-    hb_vector_t<SubsetGlyph> glyphs;
-    _populate_subset_glyphs (c->plan, &glyphs);
-
-    auto padded_offsets =
-    + hb_iter (glyphs)
-    | hb_map (&SubsetGlyph::padded_size)
-    ;
-
-    unsigned max_offset = + padded_offsets | hb_reduce (hb_add, 0);
-    bool use_short_loca = max_offset < 0x1FFFF;
-
-
-    glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan);
-    if (!use_short_loca) {
-      padded_offsets =
-          + hb_iter (glyphs)
-          | hb_map (&SubsetGlyph::length)
-          ;
-    }
-
-
-    if (unlikely (c->serializer->in_error ())) return_trace (false);
-    return_trace (c->serializer->check_success (_add_loca_and_head (c->plan,
-                                                                   padded_offsets,
-                                                                    use_short_loca)));
-  }
-
-  template <typename SubsetGlyph>
-  void
-  _populate_subset_glyphs (const hb_subset_plan_t   *plan,
-                          hb_vector_t<SubsetGlyph> *glyphs /* OUT */) const
-  {
-    OT::glyf::accelerator_t glyf (plan->source);
-
-    + hb_range (plan->num_output_glyphs ())
-    | hb_map ([&] (hb_codepoint_t new_gid)
-             {
-               SubsetGlyph subset_glyph = {0};
-               subset_glyph.new_gid = new_gid;
-
-               /* should never fail: all old gids should be mapped */
-               if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid))
-                 return subset_glyph;
-
-               if (new_gid == 0 &&
-                    !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
-                 subset_glyph.source_glyph = Glyph ();
-               else
-                 subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
-               if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
-                  subset_glyph.drop_hints_bytes ();
-               else
-                  subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
-               return subset_glyph;
-             })
-    | hb_sink (glyphs)
-    ;
-  }
-
-  static bool
-  _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca)
-  {
-    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;
-
-    head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr);
-    head_prime->indexToLocFormat = use_short_loca ? 0 : 1;
-    bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob);
-
-    hb_blob_destroy (head_prime_blob);
-    return success;
-  }
-
-  struct CompositeGlyphChain
-  {
-    protected:
-    enum composite_glyph_flag_t
-    {
-      ARG_1_AND_2_ARE_WORDS    = 0x0001,
-      ARGS_ARE_XY_VALUES       = 0x0002,
-      ROUND_XY_TO_GRID         = 0x0004,
-      WE_HAVE_A_SCALE          = 0x0008,
-      MORE_COMPONENTS          = 0x0020,
-      WE_HAVE_AN_X_AND_Y_SCALE = 0x0040,
-      WE_HAVE_A_TWO_BY_TWO     = 0x0080,
-      WE_HAVE_INSTRUCTIONS     = 0x0100,
-      USE_MY_METRICS           = 0x0200,
-      OVERLAP_COMPOUND         = 0x0400,
-      SCALED_COMPONENT_OFFSET  = 0x0800,
-      UNSCALED_COMPONENT_OFFSET = 0x1000
-    };
-
-    public:
-    unsigned int get_size () const
-    {
-      unsigned int size = min_size;
-      /* 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;
-    }
-
-    void set_glyph_index (hb_codepoint_t new_gid) { glyphIndex = new_gid; }
-    hb_codepoint_t get_glyph_index ()       const { return glyphIndex; }
-
-    void drop_instructions_flag ()  { flags = (uint16_t) flags & ~WE_HAVE_INSTRUCTIONS; }
-    void set_overlaps_flag ()
-    {
-      flags = (uint16_t) flags | OVERLAP_COMPOUND;
-    }
-
-    bool has_instructions ()  const { return   flags & WE_HAVE_INSTRUCTIONS; }
-
-    bool has_more ()          const { return   flags & MORE_COMPONENTS; }
-    bool is_use_my_metrics () const { return   flags & USE_MY_METRICS; }
-    bool is_anchored ()       const { return !(flags & ARGS_ARE_XY_VALUES); }
-    void get_anchor_points (unsigned int &point1, unsigned int &point2) const
-    {
-      const HBUINT8 *p = &StructAfter<const HBUINT8> (glyphIndex);
-      if (flags & ARG_1_AND_2_ARE_WORDS)
-      {
-       point1 = ((const HBUINT16 *) p)[0];
-       point2 = ((const HBUINT16 *) p)[1];
-      }
-      else
-      {
-       point1 = p[0];
-       point2 = p[1];
-      }
-    }
-
-    void transform_points (contour_point_vector_t &points) const
-    {
-      float matrix[4];
-      contour_point_t trans;
-      if (get_transformation (matrix, trans))
-      {
-       if (scaled_offsets ())
-       {
-         points.translate (trans);
-         points.transform (matrix);
-       }
-       else
-       {
-         points.transform (matrix);
-         points.translate (trans);
-       }
-      }
-    }
-
-    protected:
-    bool scaled_offsets () const
-    { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
-
-    bool get_transformation (float (&matrix)[4], contour_point_t &trans) const
-    {
-      matrix[0] = matrix[3] = 1.f;
-      matrix[1] = matrix[2] = 0.f;
-
-      int tx, ty;
-      const HBINT8 *p = &StructAfter<const HBINT8> (glyphIndex);
-      if (flags & ARG_1_AND_2_ARE_WORDS)
-      {
-       tx = *(const HBINT16 *) p;
-       p += HBINT16::static_size;
-       ty = *(const HBINT16 *) p;
-       p += HBINT16::static_size;
-      }
-      else
-      {
-       tx = *p++;
-       ty = *p++;
-      }
-      if (is_anchored ()) tx = ty = 0;
-
-      trans.init ((float) tx, (float) ty);
-
-      {
-       const F2DOT14 *points = (const F2DOT14 *) p;
-       if (flags & WE_HAVE_A_SCALE)
-       {
-         matrix[0] = matrix[3] = points[0].to_float ();
-         return true;
-       }
-       else if (flags & WE_HAVE_AN_X_AND_Y_SCALE)
-       {
-         matrix[0] = points[0].to_float ();
-         matrix[3] = points[1].to_float ();
-         return true;
-       }
-       else if (flags & WE_HAVE_A_TWO_BY_TWO)
-       {
-         matrix[0] = points[0].to_float ();
-         matrix[1] = points[1].to_float ();
-         matrix[2] = points[2].to_float ();
-         matrix[3] = points[3].to_float ();
-         return true;
-       }
-      }
-      return tx || ty;
-    }
-
-    protected:
-    HBUINT16   flags;
-    HBGlyphID16        glyphIndex;
-    public:
-    DEFINE_SIZE_MIN (4);
-  };
-
-  struct composite_iter_t : hb_iter_with_fallback_t<composite_iter_t, const CompositeGlyphChain &>
-  {
-    typedef const CompositeGlyphChain *__item_t__;
-    composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) :
-        glyph (glyph_), current (nullptr), current_size (0)
-    {
-      set_next (current_);
-    }
-
-    composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {}
-
-    const CompositeGlyphChain &__item__ () const { return *current; }
-    bool __more__ () const { return current; }
-    void __next__ ()
-    {
-      if (!current->has_more ()) { current = nullptr; return; }
-
-      set_next (&StructAtOffset<CompositeGlyphChain> (current, current_size));
-    }
-    bool operator != (const composite_iter_t& o) const
-    { return glyph != o.glyph || current != o.current; }
-
-
-    void set_next (const CompositeGlyphChain *composite)
-    {
-      if (!glyph.check_range (composite, CompositeGlyphChain::min_size))
-      {
-        current = nullptr;
-        current_size = 0;
-        return;
-      }
-      unsigned size = composite->get_size ();
-      if (!glyph.check_range (composite, size))
-      {
-        current = nullptr;
-        current_size = 0;
-        return;
-      }
-
-      current = composite;
-      current_size = size;
-    }
-
-    private:
-    hb_bytes_t glyph;
-    __item_t__ current;
-    unsigned current_size;
-  };
-
-  enum phantom_point_index_t
-  {
-    PHANTOM_LEFT   = 0,
-    PHANTOM_RIGHT  = 1,
-    PHANTOM_TOP    = 2,
-    PHANTOM_BOTTOM = 3,
-    PHANTOM_COUNT  = 4
-  };
-
-  struct accelerator_t;
-
-  struct Glyph
-  {
-    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_OVERLAP_SIMPLE = 0x40,
-      FLAG_RESERVED2      = 0x80
-    };
-
-    private:
-    struct GlyphHeader
-    {
-      bool has_data () const { return numberOfContours; }
-
-      bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator,
-                       hb_codepoint_t gid, hb_glyph_extents_t *extents) const
-      {
-       /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */
-       /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */
-       extents->x_bearing = font->em_scale_x (glyf_accelerator.hmtx->get_side_bearing (gid));
-       extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax));
-       extents->width     = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax));
-       extents->height    = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax));
-
-       return true;
-      }
-
-      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. */
-      FWORD    xMin;   /* Minimum x for coordinate data. */
-      FWORD    yMin;   /* Minimum y for coordinate data. */
-      FWORD    xMax;   /* Maximum x for coordinate data. */
-      FWORD    yMax;   /* Maximum y for coordinate data. */
-      public:
-      DEFINE_SIZE_STATIC (10);
-    };
-
-    struct SimpleGlyph
-    {
-      const GlyphHeader &header;
-      hb_bytes_t bytes;
-      SimpleGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
-       header (header_), bytes (bytes_) {}
-
-      unsigned int instruction_len_offset () const
-      { return GlyphHeader::static_size + 2 * header.numberOfContours; }
-
-      unsigned int length (unsigned int instruction_len) const
-      { return instruction_len_offset () + 2 + instruction_len; }
-
-      unsigned int instructions_length () const
-      {
-       unsigned int instruction_length_offset = instruction_len_offset ();
-       if (unlikely (instruction_length_offset + 2 > bytes.length)) return 0;
-
-       const HBUINT16 &instructionLength = StructAtOffset<HBUINT16> (&bytes, instruction_length_offset);
-       /* Out of bounds of the current glyph */
-       if (unlikely (length (instructionLength) > bytes.length)) return 0;
-       return instructionLength;
-      }
-
-      const Glyph trim_padding () const
-      {
-       /* based on FontTools _g_l_y_f.py::trim */
-       const uint8_t *glyph = (uint8_t*) bytes.arrayZ;
-       const uint8_t *glyph_end = glyph + bytes.length;
-       /* simple glyph w/contours, possibly trimmable */
-       glyph += instruction_len_offset ();
-
-       if (unlikely (glyph + 2 >= glyph_end)) return Glyph ();
-       unsigned int num_coordinates = StructAtOffset<HBUINT16> (glyph - 2, 0) + 1;
-       unsigned int num_instructions = StructAtOffset<HBUINT16> (glyph, 0);
-
-       glyph += 2 + num_instructions;
-
-       unsigned int coord_bytes = 0;
-       unsigned int coords_with_flags = 0;
-       while (glyph < glyph_end)
-       {
-         uint8_t flag = *glyph;
-         glyph++;
-
-         unsigned int repeat = 1;
-         if (flag & FLAG_REPEAT)
-         {
-           if (unlikely (glyph >= glyph_end)) return Glyph ();
-           repeat = *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;
-
-         coord_bytes += (xBytes + yBytes) * repeat;
-         coords_with_flags += repeat;
-         if (coords_with_flags >= num_coordinates) break;
-       }
-
-       if (unlikely (coords_with_flags != num_coordinates)) return Glyph ();
-       return Glyph (bytes.sub_array (0, bytes.length + coord_bytes - (glyph_end - glyph)));
-      }
-
-      /* zero instruction length */
-      void drop_hints ()
-      {
-       GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header);
-       (HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0;
-      }
-
-      void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
-      {
-       unsigned int instructions_len = instructions_length ();
-       unsigned int glyph_length = length (instructions_len);
-       dest_start = bytes.sub_array (0, glyph_length - instructions_len);
-       dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length);
-      }
-
-      void set_overlaps_flag ()
-      {
-        if (unlikely (!header.numberOfContours)) return;
-
-        unsigned flags_offset = length (instructions_length ());
-        if (unlikely (flags_offset + 1 > bytes.length)) return;
-
-       HBUINT8 &first_flag = (HBUINT8 &) StructAtOffset<HBUINT16> (&bytes, flags_offset);
-        first_flag = (uint8_t) first_flag | FLAG_OVERLAP_SIMPLE;
-      }
-
-      static bool read_points (const HBUINT8 *&p /* IN/OUT */,
-                              contour_point_vector_t &points_ /* IN/OUT */,
-                              const hb_bytes_t &bytes,
-                              void (* setter) (contour_point_t &_, float v),
-                              const simple_glyph_flag_t short_flag,
-                              const simple_glyph_flag_t same_flag)
-      {
-       float v = 0;
-       for (unsigned i = 0; i < points_.length; i++)
-       {
-         uint8_t flag = points_[i].flag;
-         if (flag & short_flag)
-         {
-           if (unlikely (!bytes.check_range (p))) return false;
-           if (flag & same_flag)
-             v += *p++;
-           else
-             v -= *p++;
-         }
-         else
-         {
-           if (!(flag & same_flag))
-           {
-             if (unlikely (!bytes.check_range ((const HBUINT16 *) p))) return false;
-             v += *(const HBINT16 *) p;
-             p += HBINT16::static_size;
-           }
-         }
-         setter (points_[i], v);
-       }
-       return true;
-      }
-
-      bool get_contour_points (contour_point_vector_t &points_ /* OUT */,
-                              bool phantom_only = false) const
-      {
-       const HBUINT16 *endPtsOfContours = &StructAfter<HBUINT16> (header);
-       int num_contours = header.numberOfContours;
-       if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours + 1]))) return false;
-       unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
-
-       points_.resize (num_points);
-       for (unsigned int i = 0; i < points_.length; i++) points_[i].init ();
-       if (phantom_only) return true;
-
-       for (int i = 0; i < num_contours; i++)
-         points_[endPtsOfContours[i]].is_end_point = true;
-
-       /* Skip instructions */
-       const HBUINT8 *p = &StructAtOffset<HBUINT8> (&endPtsOfContours[num_contours + 1],
-                                                    endPtsOfContours[num_contours]);
-
-       /* Read flags */
-       for (unsigned int i = 0; i < num_points; i++)
-       {
-         if (unlikely (!bytes.check_range (p))) return false;
-         uint8_t flag = *p++;
-         points_[i].flag = flag;
-         if (flag & FLAG_REPEAT)
-         {
-           if (unlikely (!bytes.check_range (p))) return false;
-           unsigned int repeat_count = *p++;
-           while ((repeat_count-- > 0) && (++i < num_points))
-             points_[i].flag = flag;
-         }
-       }
-
-       /* Read x & y coordinates */
-       return read_points (p, points_, bytes, [] (contour_point_t &p, float v) { p.x = v; },
-                           FLAG_X_SHORT, FLAG_X_SAME)
-           && read_points (p, points_, bytes, [] (contour_point_t &p, float v) { p.y = v; },
-                           FLAG_Y_SHORT, FLAG_Y_SAME);
-      }
-    };
-
-    struct CompositeGlyph
-    {
-      const GlyphHeader &header;
-      hb_bytes_t bytes;
-      CompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
-       header (header_), bytes (bytes_) {}
-
-      composite_iter_t get_iterator () const
-      { return composite_iter_t (bytes, &StructAfter<CompositeGlyphChain, GlyphHeader> (header)); }
-
-      unsigned int instructions_length (hb_bytes_t bytes) const
-      {
-       unsigned int start = bytes.length;
-       unsigned int end = bytes.length;
-       const CompositeGlyphChain *last = nullptr;
-       for (auto &item : get_iterator ())
-         last = &item;
-       if (unlikely (!last)) return 0;
-
-       if (last->has_instructions ())
-         start = (char *) last - &bytes + last->get_size ();
-       if (unlikely (start > end)) return 0;
-       return end - start;
-      }
-
-      /* Trimming for composites not implemented.
-       * If removing hints it falls out of that. */
-      const Glyph trim_padding () const { return Glyph (bytes); }
-
-      void drop_hints ()
-      {
-       for (const auto &_ : get_iterator ())
-         const_cast<CompositeGlyphChain &> (_).drop_instructions_flag ();
-      }
-
-      /* Chop instructions off the end */
-      void drop_hints_bytes (hb_bytes_t &dest_start) const
-      { dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); }
-
-      void set_overlaps_flag ()
-      {
-        const_cast<CompositeGlyphChain &> (StructAfter<CompositeGlyphChain, GlyphHeader> (header))
-                .set_overlaps_flag ();
-      }
-    };
-
-    enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE };
-
-    public:
-    composite_iter_t get_composite_iterator () const
-    {
-      if (type != COMPOSITE) return composite_iter_t ();
-      return CompositeGlyph (*header, bytes).get_iterator ();
-    }
-
-    const Glyph trim_padding () const
-    {
-      switch (type) {
-      case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
-      case SIMPLE:    return SimpleGlyph (*header, bytes).trim_padding ();
-      default:        return bytes;
-      }
-    }
-
-    void drop_hints ()
-    {
-      switch (type) {
-      case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
-      case SIMPLE:    SimpleGlyph (*header, bytes).drop_hints (); return;
-      default:        return;
-      }
-    }
-
-    void set_overlaps_flag ()
-    {
-      switch (type) {
-      case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
-      case SIMPLE:    SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
-      default:        return;
-      }
-    }
-
-    void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
-    {
-      switch (type) {
-      case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
-      case SIMPLE:    SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
-      default:        return;
-      }
-    }
-
-    /* Note: Recursively calls itself.
-     * all_points includes phantom points
-     */
-    bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
-                    contour_point_vector_t &all_points /* OUT */,
-                    bool phantom_only = false,
-                    unsigned int depth = 0) const
-    {
-      if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
-      contour_point_vector_t points;
-
-      switch (type) {
-      case COMPOSITE:
-      {
-       /* pseudo component points for each component in composite glyph */
-       unsigned num_points = hb_len (CompositeGlyph (*header, bytes).get_iterator ());
-       if (unlikely (!points.resize (num_points))) return false;
-       for (unsigned i = 0; i < points.length; i++)
-         points[i].init ();
-       break;
-      }
-      case SIMPLE:
-       if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only)))
-         return false;
-       break;
-      }
-
-      /* Init phantom points */
-      if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
-      hb_array_t<contour_point_t> phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
-      {
-       for (unsigned i = 0; i < PHANTOM_COUNT; ++i) phantoms[i].init ();
-       int h_delta = (int) header->xMin -
-                     glyf_accelerator.hmtx->get_side_bearing (gid);
-       int v_orig  = (int) header->yMax +
-#ifndef HB_NO_VERTICAL
-                     glyf_accelerator.vmtx->get_side_bearing (gid)
-#else
-                     0
-#endif
-                     ;
-       unsigned h_adv = glyf_accelerator.hmtx->get_advance (gid);
-       unsigned v_adv =
-#ifndef HB_NO_VERTICAL
-                        glyf_accelerator.vmtx->get_advance (gid)
-#else
-                        - font->face->get_upem ()
-#endif
-                        ;
-       phantoms[PHANTOM_LEFT].x = h_delta;
-       phantoms[PHANTOM_RIGHT].x = h_adv + h_delta;
-       phantoms[PHANTOM_TOP].y = v_orig;
-       phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
-      }
-
-#ifndef HB_NO_VAR
-      if (unlikely (!glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ())))
-       return false;
-#endif
-
-      switch (type) {
-      case SIMPLE:
-       all_points.extend (points.as_array ());
-       break;
-      case COMPOSITE:
-      {
-       unsigned int comp_index = 0;
-       for (auto &item : get_composite_iterator ())
-       {
-         contour_point_vector_t comp_points;
-         if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_glyph_index ())
-                                        .get_points (font, glyf_accelerator, comp_points,
-                                                     phantom_only, depth + 1)
-                       || comp_points.length < PHANTOM_COUNT))
-           return false;
-
-         /* Copy phantom points from component if USE_MY_METRICS flag set */
-         if (item.is_use_my_metrics ())
-           for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
-             phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
-
-         /* Apply component transformation & translation */
-         item.transform_points (comp_points);
-
-         /* Apply translation from gvar */
-         comp_points.translate (points[comp_index]);
-
-         if (item.is_anchored ())
-         {
-           unsigned int p1, p2;
-           item.get_anchor_points (p1, p2);
-           if (likely (p1 < all_points.length && p2 < comp_points.length))
-           {
-             contour_point_t delta;
-             delta.init (all_points[p1].x - comp_points[p2].x,
-                         all_points[p1].y - comp_points[p2].y);
-
-             comp_points.translate (delta);
-           }
-         }
-
-         all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT));
-
-         comp_index++;
-       }
-
-       all_points.extend (phantoms);
-      } break;
-      default:
-       all_points.extend (phantoms);
-      }
-
-      if (depth == 0) /* Apply at top level */
-      {
-       /* Undocumented rasterizer behavior:
-        * Shift points horizontally by the updated left side bearing
-        */
-       contour_point_t delta;
-       delta.init (-phantoms[PHANTOM_LEFT].x, 0.f);
-       if (delta.x) all_points.translate (delta);
-      }
-
-      return true;
-    }
-
-    bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator,
-                     hb_glyph_extents_t *extents) const
-    {
-      if (type == EMPTY) return true; /* Empty glyph; zero extents. */
-      return header->get_extents (font, glyf_accelerator, gid, extents);
-    }
-
-    hb_bytes_t get_bytes () const { return bytes; }
-
-    Glyph (hb_bytes_t bytes_ = hb_bytes_t (),
-          hb_codepoint_t gid_ = (hb_codepoint_t) -1) : bytes (bytes_), gid (gid_),
-                                                       header (bytes.as<GlyphHeader> ())
-    {
-      int num_contours = header->numberOfContours;
-      if (unlikely (num_contours == 0)) type = EMPTY;
-      else if (num_contours > 0) type = SIMPLE;
-      else type = COMPOSITE; /* negative numbers */
-    }
-
-    protected:
-    hb_bytes_t bytes;
-    hb_codepoint_t gid;
-    const GlyphHeader *header;
-    unsigned type;
-  };
-
-  struct accelerator_t
-  {
-    accelerator_t (hb_face_t *face)
-    {
-      short_offset = false;
-      num_glyphs = 0;
-      loca_table = nullptr;
-      glyf_table = nullptr;
-#ifndef HB_NO_VAR
-      gvar = nullptr;
-#endif
-      hmtx = nullptr;
-#ifndef HB_NO_VERTICAL
-      vmtx = nullptr;
-#endif
-      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.indexToLocFormat;
-
-      loca_table = hb_sanitize_context_t ().reference_table<loca> (face);
-      glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
-#ifndef HB_NO_VAR
-      gvar = face->table.gvar;
-#endif
-      hmtx = face->table.hmtx;
-#ifndef HB_NO_VERTICAL
-      vmtx = face->table.vmtx;
-#endif
-
-      num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
-      num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ());
-    }
-    ~accelerator_t ()
-    {
-      loca_table.destroy ();
-      glyf_table.destroy ();
-    }
-
-    protected:
-    template<typename T>
-    bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const
-    {
-      if (gid >= num_glyphs) return false;
-
-      /* Making this allocfree is not that easy
-        https://github.com/harfbuzz/harfbuzz/issues/2095
-        mostly because of gvar handling in VF fonts,
-        perhaps a separate path for non-VF fonts can be considered */
-      contour_point_vector_t all_points;
-
-      bool phantom_only = !consumer.is_consuming_contour_points ();
-      if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, phantom_only)))
-       return false;
-
-      if (consumer.is_consuming_contour_points ())
-      {
-       for (unsigned point_index = 0; point_index + 4 < all_points.length; ++point_index)
-         consumer.consume_point (all_points[point_index]);
-       consumer.points_end ();
-      }
-
-      /* Where to write phantoms, nullptr if not requested */
-      contour_point_t *phantoms = consumer.get_phantoms_sink ();
-      if (phantoms)
-       for (unsigned i = 0; i < PHANTOM_COUNT; ++i)
-         phantoms[i] = all_points[all_points.length - PHANTOM_COUNT + i];
-
-      return true;
-    }
-
-#ifndef HB_NO_VAR
-    struct points_aggregator_t
-    {
-      hb_font_t *font;
-      hb_glyph_extents_t *extents;
-      contour_point_t *phantoms;
-
-      struct contour_bounds_t
-      {
-       contour_bounds_t () { min_x = min_y = FLT_MAX; max_x = max_y = -FLT_MAX; }
-
-       void add (const contour_point_t &p)
-       {
-         min_x = hb_min (min_x, p.x);
-         min_y = hb_min (min_y, p.y);
-         max_x = hb_max (max_x, p.x);
-         max_y = hb_max (max_y, p.y);
-       }
-
-       bool empty () const { return (min_x >= max_x) || (min_y >= max_y); }
-
-       void get_extents (hb_font_t *font, hb_glyph_extents_t *extents)
-       {
-         if (unlikely (empty ()))
-         {
-           extents->width = 0;
-           extents->x_bearing = 0;
-           extents->height = 0;
-           extents->y_bearing = 0;
-           return;
-         }
-         extents->x_bearing = font->em_scalef_x (min_x);
-         extents->width = font->em_scalef_x (max_x) - extents->x_bearing;
-         extents->y_bearing = font->em_scalef_y (max_y);
-         extents->height = font->em_scalef_y (min_y) - extents->y_bearing;
-       }
-
-       protected:
-       float min_x, min_y, max_x, max_y;
-      } bounds;
-
-      points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_)
-      {
-       font = font_;
-       extents = extents_;
-       phantoms = phantoms_;
-       if (extents) bounds = contour_bounds_t ();
-      }
-
-      void consume_point (const contour_point_t &point) { bounds.add (point); }
-      void points_end () { bounds.get_extents (font, extents); }
-
-      bool is_consuming_contour_points () { return extents; }
-      contour_point_t *get_phantoms_sink () { return phantoms; }
-    };
-
-    public:
-    unsigned
-    get_advance_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
-    {
-      if (unlikely (gid >= num_glyphs)) return 0;
-
-      bool success = false;
-
-      contour_point_t phantoms[PHANTOM_COUNT];
-      if (likely (font->num_coords == gvar->get_axis_count ()))
-       success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms));
-
-      if (unlikely (!success))
-       return
-#ifndef HB_NO_VERTICAL
-         is_vertical ? vmtx->get_advance (gid) :
-#endif
-         hmtx->get_advance (gid);
-
-      float result = is_vertical
-                  ? phantoms[PHANTOM_TOP].y - phantoms[PHANTOM_BOTTOM].y
-                  : phantoms[PHANTOM_RIGHT].x - phantoms[PHANTOM_LEFT].x;
-      return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2);
-    }
-
-    int get_side_bearing_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
-    {
-      if (unlikely (gid >= num_glyphs)) return 0;
-
-      hb_glyph_extents_t extents;
-
-      contour_point_t phantoms[PHANTOM_COUNT];
-      if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms))))
-       return
-#ifndef HB_NO_VERTICAL
-         is_vertical ? vmtx->get_side_bearing (gid) :
-#endif
-         hmtx->get_side_bearing (gid);
-
-      return is_vertical
-          ? ceilf (phantoms[PHANTOM_TOP].y) - extents.y_bearing
-          : floorf (phantoms[PHANTOM_LEFT].x);
-    }
-#endif
-
-    public:
-    bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
-    {
-      if (unlikely (gid >= num_glyphs)) return false;
-
-#ifndef HB_NO_VAR
-      if (font->num_coords && font->num_coords == gvar->get_axis_count ())
-       return get_points (font, gid, points_aggregator_t (font, extents, nullptr));
-#endif
-      return glyph_for_gid (gid).get_extents (font, *this, extents);
-    }
-
-    const Glyph
-    glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const
-    {
-      if (unlikely (gid >= num_glyphs)) return Glyph ();
-
-      unsigned int start_offset, end_offset;
-
-      if (short_offset)
-      {
-       const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ;
-       start_offset = 2 * offsets[gid];
-       end_offset   = 2 * offsets[gid + 1];
-      }
-      else
-      {
-       const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ;
-       start_offset = offsets[gid];
-       end_offset   = offsets[gid + 1];
-      }
-
-      if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ()))
-       return Glyph ();
-
-      Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset,
-                              end_offset - start_offset), gid);
-      return needs_padding_removal ? glyph.trim_padding () : glyph;
-    }
-
-    unsigned
-    add_gid_and_children (hb_codepoint_t gid,
-                         hb_set_t *gids_to_retain,
-                         unsigned depth = 0,
-                         unsigned operation_count = 0) const
-    {
-      if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count;
-      if (unlikely (operation_count++ > HB_MAX_COMPOSITE_OPERATIONS)) return operation_count;
-      /* Check if is already visited */
-      if (gids_to_retain->has (gid)) return operation_count;
-
-      gids_to_retain->add (gid);
-
-      auto it = glyph_for_gid (gid).get_composite_iterator ();
-      while (it)
-      {
-        auto item = *(it++);
-        operation_count =
-            add_gid_and_children (item.get_glyph_index (), gids_to_retain, depth, operation_count);
-      }
-
-      return operation_count;
-    }
-
-#ifdef HB_EXPERIMENTAL_API
-    struct path_builder_t
-    {
-      hb_font_t *font;
-      draw_helper_t *draw_helper;
-
-      struct optional_point_t
-      {
-       optional_point_t () { has_data = false; }
-       optional_point_t (float x_, float y_) { x = x_; y = y_; has_data = true; }
-
-       bool has_data;
-       float x;
-       float y;
-
-       optional_point_t lerp (optional_point_t p, float t)
-       { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); }
-      } first_oncurve, first_offcurve, last_offcurve;
-
-      path_builder_t (hb_font_t *font_, draw_helper_t &draw_helper_)
-      {
-       font = font_;
-       draw_helper = &draw_helper_;
-       first_oncurve = first_offcurve = last_offcurve = optional_point_t ();
-      }
-
-      /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287
-        See also:
-        * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html
-        * https://stackoverflow.com/a/20772557 */
-      void consume_point (const contour_point_t &point)
-      {
-       /* Skip empty contours */
-       if (unlikely (point.is_end_point && !first_oncurve.has_data && !first_offcurve.has_data))
-         return;
-
-       bool is_on_curve = point.flag & Glyph::FLAG_ON_CURVE;
-       optional_point_t p (point.x, point.y);
-       if (!first_oncurve.has_data)
-       {
-         if (is_on_curve)
-         {
-           first_oncurve = p;
-           draw_helper->move_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y));
-         }
-         else
-         {
-           if (first_offcurve.has_data)
-           {
-             optional_point_t mid = first_offcurve.lerp (p, .5f);
-             first_oncurve = mid;
-             last_offcurve = p;
-             draw_helper->move_to (font->em_scalef_x (mid.x), font->em_scalef_y (mid.y));
-           }
-           else
-             first_offcurve = p;
-         }
-       }
-       else
-       {
-         if (last_offcurve.has_data)
-         {
-           if (is_on_curve)
-           {
-             draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
-                                        font->em_scalef_x (p.x), font->em_scalef_y (p.y));
-             last_offcurve = optional_point_t ();
-           }
-           else
-           {
-             optional_point_t mid = last_offcurve.lerp (p, .5f);
-             draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
-                                        font->em_scalef_x (mid.x), font->em_scalef_y (mid.y));
-             last_offcurve = p;
-           }
-         }
-         else
-         {
-           if (is_on_curve)
-             draw_helper->line_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y));
-           else
-             last_offcurve = p;
-         }
-       }
-
-       if (point.is_end_point)
-       {
-         if (first_offcurve.has_data && last_offcurve.has_data)
-         {
-           optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f);
-           draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
-                                      font->em_scalef_x (mid.x), font->em_scalef_y (mid.y));
-           last_offcurve = optional_point_t ();
-           /* now check the rest */
-         }
-
-         if (first_offcurve.has_data && first_oncurve.has_data)
-           draw_helper->quadratic_to (font->em_scalef_x (first_offcurve.x), font->em_scalef_y (first_offcurve.y),
-                                      font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y));
-         else if (last_offcurve.has_data && first_oncurve.has_data)
-           draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
-                                      font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y));
-         else if (first_oncurve.has_data)
-           draw_helper->line_to (font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y));
-
-         /* Getting ready for the next contour */
-         first_oncurve = first_offcurve = last_offcurve = optional_point_t ();
-         draw_helper->end_path ();
-       }
-      }
-      void points_end () {}
-
-      bool is_consuming_contour_points () { return true; }
-      contour_point_t *get_phantoms_sink () { return nullptr; }
-    };
-
-    bool
-    get_path (hb_font_t *font, hb_codepoint_t gid, draw_helper_t &draw_helper) const
-    { return get_points (font, gid, path_builder_t (font, draw_helper)); }
-#endif
-
-#ifndef HB_NO_VAR
-    const gvar_accelerator_t *gvar;
-#endif
-    const hmtx_accelerator_t *hmtx;
-#ifndef HB_NO_VERTICAL
-    const vmtx_accelerator_t *vmtx;
-#endif
-
-    private:
-    bool short_offset;
-    unsigned int num_glyphs;
-    hb_blob_ptr_t<loca> loca_table;
-    hb_blob_ptr_t<glyf> glyf_table;
-  };
-
-  struct SubsetGlyph
-  {
-    hb_codepoint_t new_gid;
-    hb_codepoint_t old_gid;
-    Glyph source_glyph;
-    hb_bytes_t dest_start;  /* region of source_glyph to copy first */
-    hb_bytes_t dest_end;    /* region of source_glyph to copy second */
-
-    bool serialize (hb_serialize_context_t *c,
-                    bool use_short_loca,
-                   const hb_subset_plan_t *plan) const
-    {
-      TRACE_SERIALIZE (this);
-
-      hb_bytes_t dest_glyph = dest_start.copy (c);
-      dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length);
-      unsigned int pad_length = use_short_loca ? padding () : 0;
-      DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length);
-
-      HBUINT8 pad;
-      pad = 0;
-      while (pad_length > 0)
-      {
-       c->embed (pad);
-       pad_length--;
-      }
-
-      if (unlikely (!dest_glyph.length)) return_trace (true);
-
-      /* update components gids */
-      for (auto &_ : Glyph (dest_glyph).get_composite_iterator ())
-      {
-       hb_codepoint_t new_gid;
-       if (plan->new_gid_for_old_gid (_.get_glyph_index (), &new_gid))
-         const_cast<CompositeGlyphChain &> (_).set_glyph_index (new_gid);
-      }
-
-      if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
-        Glyph (dest_glyph).drop_hints ();
-
-      if (plan->flags & HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG)
-        Glyph (dest_glyph).set_overlaps_flag ();
-
-      return_trace (true);
-    }
-
-    void drop_hints_bytes ()
-    { source_glyph.drop_hints_bytes (dest_start, dest_end); }
-
-    unsigned int      length () const { return dest_start.length + dest_end.length; }
-    /* pad to 2 to ensure 2-byte loca will be ok */
-    unsigned int     padding () const { return length () % 2; }
-    unsigned int padded_size () const { return length () + padding (); }
-  };
-
-  protected:
-  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 {
-  glyf_accelerator_t (hb_face_t *face) : glyf::accelerator_t (face) {}
-};
-
-
-} /* namespace OT */
-
+#include "OT/glyf/glyf.hh"
 
 #endif /* HB_OT_GLYF_TABLE_HH */
index dea2b7e..cbcf6f5 100644 (file)
@@ -46,21 +46,23 @@ struct DeviceRecord
 
   template<typename Iterator,
           hb_requires (hb_is_iterator (Iterator))>
-  bool serialize (hb_serialize_context_t *c, unsigned pixelSize, Iterator it)
+  bool serialize (hb_serialize_context_t *c,
+                 unsigned pixelSize,
+                 Iterator it,
+                 const hb_vector_t<hb_codepoint_pair_t> new_to_old_gid_list,
+                 unsigned num_glyphs)
   {
     TRACE_SERIALIZE (this);
 
-    unsigned length = it.len ();
-
-    if (unlikely (!c->extend (this, length)))  return_trace (false);
+    if (unlikely (!c->extend (this, num_glyphs)))  return_trace (false);
 
     this->pixelSize = pixelSize;
     this->maxWidth =
     + it
     | hb_reduce (hb_max, 0u);
 
-    + it
-    | hb_sink (widthsZ.as_array (length));
+    for (auto &_ : new_to_old_gid_list)
+      widthsZ[_.first] = *it++;
 
     return_trace (true);
   }
@@ -76,7 +78,7 @@ struct DeviceRecord
   HBUINT8                      maxWidth;       /* Maximum width. */
   UnsizedArrayOf<HBUINT8>      widthsZ;        /* Array of widths (numGlyphs is from the 'maxp' table). */
   public:
-  DEFINE_SIZE_ARRAY (2, widthsZ);
+  DEFINE_SIZE_UNBOUNDED (2);
 };
 
 
@@ -87,17 +89,13 @@ struct hdmx
   unsigned int get_size () const
   { return min_size + numRecords * sizeDeviceRecord; }
 
-  const DeviceRecord& operator [] (unsigned int i) const
-  {
-    /* 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);
-  }
-
   template<typename Iterator,
           hb_requires (hb_is_iterator (Iterator))>
-  bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it)
+  bool serialize (hb_serialize_context_t *c,
+                 unsigned version,
+                 Iterator it,
+                 const hb_vector_t<hb_codepoint_pair_t> &new_to_old_gid_list,
+                 unsigned num_glyphs)
   {
     TRACE_SERIALIZE (this);
 
@@ -105,10 +103,10 @@ struct hdmx
 
     this->version = version;
     this->numRecords = it.len ();
-    this->sizeDeviceRecord = DeviceRecord::get_size (it ? (*it).second.len () : 0);
+    this->sizeDeviceRecord = DeviceRecord::get_size (num_glyphs);
 
     for (const hb_item_type<Iterator>& _ : +it)
-      c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second);
+      c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second, new_to_old_gid_list, num_glyphs);
 
     return_trace (c->successful ());
   }
@@ -118,31 +116,30 @@ struct hdmx
   {
     TRACE_SUBSET (this);
 
-    hdmx *hdmx_prime = c->serializer->start_embed <hdmx> ();
-    if (unlikely (!hdmx_prime)) return_trace (false);
+    auto *hdmx_prime = c->serializer->start_embed <hdmx> ();
 
+    unsigned num_input_glyphs = get_num_glyphs ();
     auto it =
     + hb_range ((unsigned) numRecords)
-    | hb_map ([c, this] (unsigned _)
+    | hb_map ([c, num_input_glyphs, this] (unsigned _)
        {
          const DeviceRecord *device_record =
            &StructAtOffset<DeviceRecord> (&firstDeviceRecord,
                                           _ * sizeDeviceRecord);
          auto row =
-           + hb_range (c->plan->num_output_glyphs ())
-           | hb_map (c->plan->reverse_glyph_map)
-           | hb_map ([this, c, device_record] (hb_codepoint_t _)
+           + hb_iter (c->plan->new_to_old_gid_list)
+           | hb_map ([num_input_glyphs, device_record] (hb_codepoint_pair_t _)
                      {
-                       if (c->plan->is_empty_glyph (_))
-                         return Null (HBUINT8);
-                       return device_record->widthsZ.as_array (get_num_glyphs ()) [_];
+                       return device_record->widthsZ.as_array (num_input_glyphs) [_.second];
                      })
            ;
          return hb_pair ((unsigned) device_record->pixelSize, +row);
        })
     ;
 
-    hdmx_prime->serialize (c->serializer, version, it);
+    hdmx_prime->serialize (c->serializer, version, it,
+                          c->plan->new_to_old_gid_list,
+                          c->plan->num_output_glyphs ());
     return_trace (true);
   }
 
@@ -156,6 +153,7 @@ struct hdmx
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
                  !hb_unsigned_mul_overflows (numRecords, sizeDeviceRecord) &&
+                  min_size + numRecords * sizeDeviceRecord > numRecords * sizeDeviceRecord &&
                  sizeDeviceRecord >= DeviceRecord::min_size &&
                  c->check_range (this, get_size ()));
   }
index 20991aa..770cf52 100644 (file)
@@ -63,7 +63,25 @@ struct head
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    return_trace (serialize (c->serializer));
+    head *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+
+    if (c->plan->normalized_coords)
+    {
+      if (unlikely (!c->serializer->check_assign (out->xMin, c->plan->head_maxp_info.xMin,
+                                                  HB_SERIALIZE_ERROR_INT_OVERFLOW)))
+        return_trace (false);
+      if (unlikely (!c->serializer->check_assign (out->xMax, c->plan->head_maxp_info.xMax,
+                                                  HB_SERIALIZE_ERROR_INT_OVERFLOW)))
+        return_trace (false);
+      if (unlikely (!c->serializer->check_assign (out->yMin, c->plan->head_maxp_info.yMin,
+                                                  HB_SERIALIZE_ERROR_INT_OVERFLOW)))
+        return_trace (false);
+      if (unlikely (!c->serializer->check_assign (out->yMax, c->plan->head_maxp_info.yMax,
+                                                  HB_SERIALIZE_ERROR_INT_OVERFLOW)))
+        return_trace (false);
+    }
+    return_trace (true);
   }
 
   enum mac_style_flag_t {
@@ -97,6 +115,7 @@ struct head
                                         * entire font as HBUINT32, then store
                                         * 0xB1B0AFBAu - sum. */
   HBUINT32     magicNumber;            /* Set to 0x5F0F3CF5u. */
+  public:
   HBUINT16     flags;                  /* Bit 0: Baseline for font at y=0;
                                         * Bit 1: Left sidebearing point at x=0;
                                         * Bit 2: Instructions may depend on point size;
@@ -141,6 +160,7 @@ struct head
                                         * encoded in the cmap subtables represent proper
                                         * support for those code points.
                                         * Bit 15: Reserved, set to 0. */
+  protected:
   HBUINT16     unitsPerEm;             /* Valid range is from 16 to 16384. This value
                                         * should be a power of 2 for fonts that have
                                         * TrueType outlines. */
@@ -148,10 +168,12 @@ struct head
                                           January 1, 1904. 64-bit integer */
   LONGDATETIME modified;               /* Number of seconds since 12:00 midnight,
                                           January 1, 1904. 64-bit integer */
+  public:
   HBINT16      xMin;                   /* For all glyph bounding boxes. */
   HBINT16      yMin;                   /* For all glyph bounding boxes. */
   HBINT16      xMax;                   /* For all glyph bounding boxes. */
   HBINT16      yMax;                   /* For all glyph bounding boxes. */
+  protected:
   HBUINT16     macStyle;               /* Bit 0: Bold (if set to 1);
                                         * Bit 1: Italic (if set to 1)
                                         * Bit 2: Underline (if set to 1)
index 739474f..89640b4 100644 (file)
 #define HB_OT_HMTX_TABLE_HH
 
 #include "hb-open-type.hh"
+#include "hb-ot-maxp-table.hh"
 #include "hb-ot-hhea-table.hh"
 #include "hb-ot-var-hvar-table.hh"
+#include "hb-ot-var-mvar-table.hh"
 #include "hb-ot-metrics.hh"
 
 /*
 #define HB_OT_TAG_vmtx HB_TAG('v','m','t','x')
 
 
-HB_INTERNAL int
-_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
+HB_INTERNAL bool
+_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical, int *lsb);
 
 HB_INTERNAL unsigned
-_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
+_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
+
+HB_INTERNAL bool
+_glyf_get_leading_bearing_without_var_unscaled (hb_face_t *face, hb_codepoint_t gid, bool is_vertical, int *lsb);
 
 
 namespace OT {
@@ -61,7 +66,7 @@ struct LongMetric
 };
 
 
-template <typename T, typename H>
+template <typename T/*Data table type*/, typename H/*Header table type*/, typename V/*Var table type*/>
 struct hmtxvmtx
 {
   bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
@@ -72,11 +77,15 @@ struct hmtxvmtx
     return_trace (true);
   }
 
+  const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>>* get_mtx_map (const hb_subset_plan_t *plan) const
+  { return T::is_horizontal ? &plan->hmtx_map : &plan->vmtx_map; }
 
-  bool subset_update_header (hb_subset_plan_t *plan,
-                            unsigned int num_hmetrics) const
+  bool subset_update_header (hb_subset_context_t *c,
+                            unsigned int num_hmetrics,
+                            const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>> *mtx_map,
+                            const hb_vector_t<unsigned> &bounds_vec) const
   {
-    hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table<H> (plan->source, H::tableTag);
+    hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table<H> (c->plan->source, H::tableTag);
     hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob);
     hb_blob_destroy (src_blob);
 
@@ -86,9 +95,60 @@ struct hmtxvmtx
 
     unsigned int length;
     H *table = (H *) hb_blob_get_data (dest_blob, &length);
-    table->numberOfLongMetrics = num_hmetrics;
+    c->serializer->check_assign (table->numberOfLongMetrics, num_hmetrics, HB_SERIALIZE_ERROR_INT_OVERFLOW);
+
+#ifndef HB_NO_VAR
+    if (c->plan->normalized_coords)
+    {
+      auto &MVAR = *c->plan->source->table.MVAR;
+      if (T::is_horizontal)
+      {
+       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE,   caretSlopeRise);
+       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN,    caretSlopeRun);
+       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET, caretOffset);
+      }
+      else
+      {
+       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_RISE,     caretSlopeRise);
+       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_RUN,      caretSlopeRun);
+       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET,   caretOffset);
+      }
+
+      bool empty = true;
+      int min_lsb = 0x7FFF;
+      int min_rsb = 0x7FFF;
+      int max_extent = -0x7FFF;
+      unsigned max_adv = 0;
+      for (const auto _ : *mtx_map)
+      {
+        hb_codepoint_t gid = _.first;
+        unsigned adv = _.second.first;
+        int lsb = _.second.second;
+        max_adv = hb_max (max_adv, adv);
+
+        if (bounds_vec[gid] != 0xFFFFFFFF)
+        {
+         empty = false;
+          unsigned bound_width = bounds_vec[gid];
+          int rsb = adv - lsb - bound_width;
+          int extent = lsb + bound_width;
+          min_lsb = hb_min (min_lsb, lsb);
+          min_rsb = hb_min (min_rsb, rsb);
+          max_extent = hb_max (max_extent, extent);
+        }
+      }
 
-    bool result = plan->add_table (H::tableTag, dest_blob);
+      table->advanceMax = max_adv;
+      if (!empty)
+      {
+        table->minLeadingBearing = min_lsb;
+        table->minTrailingBearing = min_rsb;
+        table->maxExtent = max_extent;
+      }
+    }
+#endif
+
+    bool result = c->plan->add_table (H::tableTag, dest_blob);
     hb_blob_destroy (dest_blob);
 
     return result;
@@ -98,25 +158,32 @@ struct hmtxvmtx
           hb_requires (hb_is_iterator (Iterator))>
   void serialize (hb_serialize_context_t *c,
                  Iterator it,
-                 unsigned num_advances)
+                 const hb_vector_t<hb_codepoint_pair_t> new_to_old_gid_list,
+                 unsigned num_long_metrics,
+                  unsigned total_num_metrics)
   {
-    unsigned idx = 0;
-    for (auto _ : it)
+    LongMetric* long_metrics = c->allocate_size<LongMetric> (num_long_metrics * LongMetric::static_size);
+    FWORD* short_metrics = c->allocate_size<FWORD> ((total_num_metrics - num_long_metrics) * FWORD::static_size);
+    if (!long_metrics || !short_metrics) return;
+
+    short_metrics -= num_long_metrics;
+
+    for (auto _ : new_to_old_gid_list)
     {
-      if (idx < num_advances)
+      hb_codepoint_t gid = _.first;
+      auto mtx = *it++;
+
+      if (gid < num_long_metrics)
       {
-       LongMetric lm;
-       lm.advance = _.first;
-       lm.sb = _.second;
-       if (unlikely (!c->embed<LongMetric> (&lm))) return;
+       LongMetric& lm = long_metrics[gid];
+       lm.advance = mtx.first;
+       lm.sb = mtx.second;
       }
+      // TODO(beyond-64k): This assumes that maxp.numGlyphs is 0xFFFF.
+      else if (gid < 0x10000u)
+        short_metrics[gid] = mtx.second;
       else
-      {
-       FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size);
-       if (unlikely (!sb)) return;
-       *sb = _.second;
-      }
-      idx++;
+        ((UFWORD*) short_metrics)[gid] = mtx.first;
     }
   }
 
@@ -124,42 +191,57 @@ struct hmtxvmtx
   {
     TRACE_SUBSET (this);
 
-    T *table_prime = c->serializer->start_embed <T> ();
-    if (unlikely (!table_prime)) return_trace (false);
+    auto *table_prime = c->serializer->start_embed <T> ();
 
     accelerator_t _mtx (c->plan->source);
-    unsigned num_advances;
+    unsigned num_long_metrics;
+    const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>> *mtx_map = get_mtx_map (c->plan);
     {
-      /* Determine num_advances to encode. */
+      /* Determine num_long_metrics to encode. */
       auto& plan = c->plan;
-      num_advances = plan->num_output_glyphs ();
-      hb_codepoint_t old_gid = 0;
-      unsigned int last_advance = plan->old_gid_for_new_gid (num_advances - 1, &old_gid) ? _mtx.get_advance (old_gid) : 0;
-      while (num_advances > 1 &&
-            last_advance == (plan->old_gid_for_new_gid (num_advances - 2, &old_gid) ? _mtx.get_advance (old_gid) : 0))
+
+      // TODO Don't consider retaingid holes here.
+
+      num_long_metrics = hb_min (plan->num_output_glyphs (), 0xFFFFu);
+      unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx);
+      while (num_long_metrics > 1 &&
+            last_advance == get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 2, _mtx))
       {
-       num_advances--;
+       num_long_metrics--;
       }
     }
 
     auto it =
-    + hb_range (c->plan->num_output_glyphs ())
-    | hb_map ([c, &_mtx] (unsigned _)
+    + hb_iter (c->plan->new_to_old_gid_list)
+    | hb_map ([c, &_mtx, mtx_map] (hb_codepoint_pair_t _)
              {
-               hb_codepoint_t old_gid;
-               if (!c->plan->old_gid_for_new_gid (_, &old_gid))
-                 return hb_pair (0u, 0);
-               return hb_pair (_mtx.get_advance (old_gid), _mtx.get_side_bearing (old_gid));
+               hb_codepoint_t new_gid = _.first;
+               hb_codepoint_t old_gid = _.second;
+
+               hb_pair_t<unsigned, int> *v = nullptr;
+               if (!mtx_map->has (new_gid, &v))
+               {
+                 int lsb = 0;
+                 if (!_mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb))
+                   (void) _glyf_get_leading_bearing_without_var_unscaled (c->plan->source, old_gid, !T::is_horizontal, &lsb);
+                 return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb);
+               }
+               return *v;
              })
     ;
 
-    table_prime->serialize (c->serializer, it, num_advances);
+    table_prime->serialize (c->serializer,
+                           it,
+                           c->plan->new_to_old_gid_list,
+                           num_long_metrics,
+                           c->plan->num_output_glyphs ());
 
     if (unlikely (c->serializer->in_error ()))
       return_trace (false);
 
     // Amend header num hmetrics
-    if (unlikely (!subset_update_header (c->plan, num_advances)))
+    if (unlikely (!subset_update_header (c, num_long_metrics, mtx_map,
+                                         T::is_horizontal ? c->plan->bounds_width_vec : c->plan->bounds_height_vec)))
       return_trace (false);
 
     return_trace (true);
@@ -169,38 +251,48 @@ struct hmtxvmtx
   {
     friend struct hmtxvmtx;
 
-    accelerator_t (hb_face_t *face,
-                  unsigned int default_advance_ = 0)
+    accelerator_t (hb_face_t *face)
     {
-      default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face);
+      table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
+      var_table = hb_sanitize_context_t ().reference_table<V> (face, T::variationsTag);
+
+      default_advance = T::is_horizontal ? hb_face_get_upem (face) / 2 : hb_face_get_upem (face);
+
+      /* Populate count variables and sort them out as we go */
+
+      unsigned int len = table.get_length ();
+      if (len & 1)
+        len--;
 
-      num_advances = T::is_horizontal ?
-                    face->table.hhea->numberOfLongMetrics :
+      num_long_metrics = T::is_horizontal ?
+                        face->table.hhea->numberOfLongMetrics :
 #ifndef HB_NO_VERTICAL
-                    face->table.vhea->numberOfLongMetrics
+                        face->table.vhea->numberOfLongMetrics
 #else
-                    0
+                        0
 #endif
-                    ;
+                        ;
+      if (unlikely (num_long_metrics * 4 > len))
+       num_long_metrics = len / 4;
+      len -= num_long_metrics * 4;
 
-      table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
+      num_bearings = face->table.maxp->get_num_glyphs ();
 
-      /* Cap num_metrics() and num_advances() based on table length. */
-      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;
+      if (unlikely (num_bearings < num_long_metrics))
+        num_bearings = num_long_metrics;
+      if (unlikely ((num_bearings - num_long_metrics) * 2 > len))
+        num_bearings = num_long_metrics + len / 2;
+      len -= (num_bearings - num_long_metrics) * 2;
 
-      /* We MUST set num_metrics to zero if num_advances is zero.
+      /* We MUST set num_bearings to zero if num_long_metrics is zero.
        * Our get_advance() depends on that. */
-      if (unlikely (!num_advances))
-      {
-       num_metrics = num_advances = 0;
-       table.destroy ();
-       table = hb_blob_get_empty ();
-      }
+      if (unlikely (!num_long_metrics))
+       num_bearings = num_long_metrics = 0;
 
-      var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag);
+      num_advances = num_bearings + len / 2;
+      num_glyphs = face->get_num_glyphs ();
+      if (num_glyphs < num_advances)
+        num_glyphs = num_advances;
     }
     ~accelerator_t ()
     {
@@ -208,79 +300,129 @@ struct hmtxvmtx
       var_table.destroy ();
     }
 
-    int get_side_bearing (hb_codepoint_t glyph) const
+    bool has_data () const { return (bool) num_bearings; }
+
+    bool get_leading_bearing_without_var_unscaled (hb_codepoint_t glyph,
+                                                  int *lsb) const
     {
-      if (glyph < num_advances)
-       return table->longMetricZ[glyph].sb;
+      if (glyph < num_long_metrics)
+      {
+       *lsb = table->longMetricZ[glyph].sb;
+       return true;
+      }
 
-      if (unlikely (glyph >= num_metrics))
-       return 0;
+      if (unlikely (glyph >= num_bearings))
+       return false;
 
-      const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_advances];
-      return bearings[glyph - num_advances];
+      const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
+      *lsb = bearings[glyph - num_long_metrics];
+      return true;
     }
 
-    int get_side_bearing (hb_font_t *font, hb_codepoint_t glyph) const
+    bool get_leading_bearing_with_var_unscaled (hb_font_t *font,
+                                               hb_codepoint_t glyph,
+                                               int *lsb) const
     {
-      int side_bearing = get_side_bearing (glyph);
+      if (!font->num_coords)
+       return get_leading_bearing_without_var_unscaled (glyph, lsb);
 
 #ifndef HB_NO_VAR
-      if (unlikely (glyph >= num_metrics) || !font->num_coords)
-       return side_bearing;
-
-      if (var_table.get_length ())
-       return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); // TODO Optimize?!
+      float delta;
+      if (var_table->get_lsb_delta_unscaled (glyph, font->coords, font->num_coords, &delta) &&
+         get_leading_bearing_without_var_unscaled (glyph, lsb))
+      {
+       *lsb += roundf (delta);
+       return true;
+      }
 
-      return _glyf_get_side_bearing_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
+      return _glyf_get_leading_bearing_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx, lsb);
 #else
-      return side_bearing;
+      return false;
 #endif
     }
 
-    unsigned int get_advance (hb_codepoint_t glyph) const
+    unsigned int get_advance_without_var_unscaled (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;
-      }
+      /* OpenType case. */
+      if (glyph < num_bearings)
+       return table->longMetricZ[hb_min (glyph, (uint32_t) num_long_metrics - 1)].advance;
 
-      return table->longMetricZ[hb_min (glyph, (uint32_t) num_advances - 1)].advance;
+      /* If num_advances is zero, it means we don't have the metrics table
+       * for this direction: return default advance.  Otherwise, there's a
+       * well-defined answer. */
+      if (unlikely (!num_advances))
+       return default_advance;
+
+#ifdef HB_NO_BEYOND_64K
+      return 0;
+#endif
+
+      if (unlikely (glyph >= num_glyphs))
+        return 0;
+
+      /* num_bearings <= glyph < num_glyphs;
+       * num_bearings <= num_advances */
+
+      if (num_bearings == num_advances)
+        return get_advance_without_var_unscaled (num_bearings - 1);
+
+      const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
+      const UFWORD *advances = (const UFWORD *) &bearings[num_bearings - num_long_metrics];
+
+      return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)];
     }
 
-    unsigned int get_advance (hb_codepoint_t  glyph,
-                             hb_font_t      *font) const
+    unsigned get_advance_with_var_unscaled (hb_codepoint_t  glyph,
+                                           hb_font_t      *font,
+                                           VariationStore::cache_t *store_cache = nullptr) const
     {
-      unsigned int advance = get_advance (glyph);
+      unsigned int advance = get_advance_without_var_unscaled (glyph);
 
 #ifndef HB_NO_VAR
-      if (unlikely (glyph >= num_metrics) || !font->num_coords)
+      if (unlikely (glyph >= num_bearings) || !font->num_coords)
        return advance;
 
       if (var_table.get_length ())
-       return advance + roundf (var_table->get_advance_var (glyph, font)); // TODO Optimize?!
+       return advance + roundf (var_table->get_advance_delta_unscaled (glyph,
+                                                                       font->coords, font->num_coords,
+                                                                       store_cache));
 
-      return _glyf_get_advance_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
+      return _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
 #else
       return advance;
 #endif
     }
 
     protected:
-    unsigned int num_metrics;
-    unsigned int num_advances;
+    // 0 <= num_long_metrics <= num_bearings <= num_advances <= num_glyphs
+    unsigned num_long_metrics;
+    unsigned num_bearings;
+    unsigned num_advances;
+    unsigned num_glyphs;
+
     unsigned int default_advance;
 
-    private:
+    public:
     hb_blob_ptr_t<hmtxvmtx> table;
-    hb_blob_ptr_t<HVARVVAR> var_table;
+    hb_blob_ptr_t<V> var_table;
   };
 
+  /* get advance: when no variations, call get_advance_without_var_unscaled.
+   * when there're variations, get advance value from mtx_map in subset_plan*/
+  unsigned get_new_gid_advance_unscaled (const hb_subset_plan_t *plan,
+                                         const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>> *mtx_map,
+                                         unsigned new_gid,
+                                         const accelerator_t &_mtx) const
+  {
+    if (mtx_map->is_empty ())
+    {
+      hb_codepoint_t old_gid = 0;
+      return plan->old_gid_for_new_gid (new_gid, &old_gid) ?
+             _mtx.get_advance_without_var_unscaled (old_gid) : 0;
+    }
+    return mtx_map->get (new_gid).first;
+  }
+
   protected:
   UnsizedArrayOf<LongMetric>
                longMetricZ;    /* Paired advance width and leading
@@ -305,16 +447,18 @@ struct hmtxvmtx
                                 * the end. This allows a monospaced
                                 * font to vary the side bearing
                                 * values for each glyph. */
+/*UnsizedArrayOf<UFWORD>advancesX;*/
+                               /* TODO Document. */
   public:
   DEFINE_SIZE_ARRAY (0, longMetricZ);
 };
 
-struct hmtx : hmtxvmtx<hmtx, hhea> {
+struct hmtx : hmtxvmtx<hmtx, hhea, HVAR> {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx;
   static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR;
   static constexpr bool is_horizontal = true;
 };
-struct vmtx : hmtxvmtx<vmtx, vhea> {
+struct vmtx : hmtxvmtx<vmtx, vhea, VVAR> {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx;
   static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR;
   static constexpr bool is_horizontal = false;
index eb4c3b4..2b7e9e4 100644 (file)
@@ -41,12 +41,15 @@ namespace OT {
 
 struct BaseCoordFormat1
 {
-  hb_position_t get_coord () const { return coordinate; }
+  hb_position_t get_coord (hb_font_t *font, hb_direction_t direction) const
+  {
+    return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
+  }
 
   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:
@@ -58,10 +61,10 @@ struct BaseCoordFormat1
 
 struct BaseCoordFormat2
 {
-  hb_position_t get_coord () const
+  hb_position_t get_coord (hb_font_t *font, hb_direction_t direction) const
   {
     /* TODO */
-    return coordinate;
+    return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -87,9 +90,10 @@ struct BaseCoordFormat3
                           hb_direction_t direction) const
   {
     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));
+
+    return HB_DIRECTION_IS_HORIZONTAL (direction)
+        ? font->em_scale_y (coordinate) + device.get_y_delta (font, var_store)
+        : font->em_scale_x (coordinate) + device.get_x_delta (font, var_store);
   }
 
 
@@ -120,8 +124,8 @@ struct BaseCoord
                           hb_direction_t        direction) const
   {
     switch (u.format) {
-    case 1: return u.format1.get_coord ();
-    case 2: return u.format2.get_coord ();
+    case 1: return u.format1.get_coord (font, direction);
+    case 2: return u.format2.get_coord (font, direction);
     case 3: return u.format3.get_coord (font, var_store, direction);
     default:return 0;
     }
@@ -166,8 +170,8 @@ struct FeatMinMaxRecord
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
-                         minCoord.sanitize (c, this) &&
-                         maxCoord.sanitize (c, this)));
+                         minCoord.sanitize (c, base) &&
+                         maxCoord.sanitize (c, base)));
   }
 
   protected:
@@ -183,7 +187,6 @@ struct FeatMinMaxRecord
                                 * of MinMax table (may be NULL) */
   public:
   DEFINE_SIZE_STATIC (8);
-
 };
 
 struct MinMax
@@ -270,7 +273,7 @@ struct BaseLangSysRecord
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
-                         minMax.sanitize (c, this)));
+                         minMax.sanitize (c, base)));
   }
 
   protected:
@@ -293,7 +296,8 @@ struct BaseScript
   const BaseCoord &get_base_coord (int baseline_tag_index) const
   { return (this+baseValues).get_base_coord (baseline_tag_index); }
 
-  bool has_data () const { return baseValues; }
+  bool has_values () const { return baseValues; }
+  bool has_min_max () const { return defaultMinMax; /* TODO What if only per-language is present? */ }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -379,7 +383,7 @@ struct Axis
                     const BaseCoord **coord) const
   {
     const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
-    if (!base_script.has_data ())
+    if (!base_script.has_values ())
     {
       *coord = nullptr;
       return false;
@@ -406,7 +410,7 @@ struct Axis
                    const BaseCoord **max_coord) const
   {
     const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
-    if (!base_script.has_data ())
+    if (!base_script.has_min_max ())
     {
       *min_coord = *max_coord = nullptr;
       return false;
@@ -421,8 +425,8 @@ struct Axis
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
-                         (this+baseTagList).sanitize (c) &&
-                         (this+baseScriptList).sanitize (c)));
+                         baseTagList.sanitize (c, this) &&
+                         baseScriptList.sanitize (c, this)));
   }
 
   protected:
@@ -469,14 +473,13 @@ struct BASE
     return true;
   }
 
-  /* 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)
+                   hb_position_t  *max) const
   {
     const BaseCoord *min_coord, *max_coord;
     if (!get_axis (direction).get_min_max (script_tag, language_tag, feature_tag,
index 60a1906..e869d8e 100644 (file)
 #include "hb-set.hh"
 #include "hb-bimap.hh"
 
+#include "OT/Layout/Common/Coverage.hh"
+#include "OT/Layout/types.hh"
 
-#ifndef HB_MAX_NESTING_LEVEL
-#define HB_MAX_NESTING_LEVEL   6
-#endif
-#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
-
-#ifndef HB_MAX_FEATURES
-#define HB_MAX_FEATURES 750
-#endif
-
-#ifndef HB_MAX_FEATURE_INDICES
-#define HB_MAX_FEATURE_INDICES 1500
-#endif
-
-#ifndef HB_MAX_LOOKUP_VISIT_COUNT
-#define HB_MAX_LOOKUP_VISIT_COUNT      35000
-#endif
+// TODO(garretrieger): cleanup these after migration.
+using OT::Layout::Common::Coverage;
+using OT::Layout::Common::RangeRecord;
+using OT::Layout::SmallTypes;
+using OT::Layout::MediumTypes;
 
 
 namespace OT {
 
-
-#define NOT_COVERED            ((unsigned int) -1)
-
-
-template<typename Iterator>
-static inline void Coverage_serialize (hb_serialize_context_t *c,
-                                      Iterator it);
-
 template<typename Iterator>
-static inline void ClassDef_serialize (hb_serialize_context_t *c,
+static inline bool ClassDef_serialize (hb_serialize_context_t *c,
                                       Iterator it);
 
-static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
-                                         const hb_map_t &gid_klass_map,
-                                         hb_sorted_vector_t<HBGlyphID16> &glyphs,
-                                         const hb_set_t &klasses,
-                                         bool use_class_zero,
-                                         hb_map_t *klass_map /*INOUT*/);
+static bool ClassDef_remap_and_serialize (
+    hb_serialize_context_t *c,
+    const hb_set_t &klasses,
+    bool use_class_zero,
+    hb_sorted_vector_t<hb_codepoint_pair_t> &glyph_and_klass, /* IN/OUT */
+    hb_map_t *klass_map /*IN/OUT*/);
 
+struct hb_collect_feature_substitutes_with_var_context_t
+{
+  const hb_map_t *axes_index_tag_map;
+  const hb_hashmap_t<hb_tag_t, Triple> *axes_location;
+  hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *record_cond_idx_map;
+  hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
+  bool& insert_catch_all_feature_variation_record;
+
+  // not stored in subset_plan
+  hb_set_t *feature_indices;
+  bool apply;
+  bool variation_applied;
+  bool universal;
+  unsigned cur_record_idx;
+  hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> *conditionset_map;
+};
 
 struct hb_prune_langsys_context_t
 {
   hb_prune_langsys_context_t (const void         *table_,
-                              hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map_,
+                              hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map_,
                               const hb_map_t     *duplicate_feature_map_,
                               hb_set_t           *new_collected_feature_indexes_)
       :table (table_),
       script_langsys_map (script_langsys_map_),
       duplicate_feature_map (duplicate_feature_map_),
       new_feature_indexes (new_collected_feature_indexes_),
-      script_count (0),langsys_count (0) {}
+      script_count (0),langsys_feature_count (0) {}
 
-  bool visitedScript (const void *s)
-  {
-    if (script_count++ > HB_MAX_SCRIPTS)
-      return true;
-
-    return visited (s, visited_script);
-  }
-
-  bool visitedLangsys (const void *l)
-  {
-    if (langsys_count++ > HB_MAX_LANGSYS)
-      return true;
-
-    return visited (l, visited_langsys);
-  }
+  bool visitScript ()
+  { return script_count++ < HB_MAX_SCRIPTS; }
 
-  private:
-  template <typename T>
-  bool visited (const T *p, hb_set_t &visited_set)
+  bool visitLangsys (unsigned feature_count)
   {
-    hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) p - (uintptr_t) table);
-    if (visited_set.in_error () || visited_set.has (delta))
-      return true;
-
-    visited_set.add (delta);
-    return false;
+    langsys_feature_count += feature_count;
+    return langsys_feature_count < HB_MAX_LANGSYS_FEATURE_COUNT;
   }
 
   public:
   const void *table;
-  hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map;
+  hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map;
   const hb_map_t     *duplicate_feature_map;
   hb_set_t           *new_feature_indexes;
 
   private:
-  hb_set_t visited_script;
-  hb_set_t visited_langsys;
   unsigned script_count;
-  unsigned langsys_count;
+  unsigned langsys_feature_count;
 };
 
 struct hb_subset_layout_context_t :
@@ -179,26 +138,42 @@ struct hb_subset_layout_context_t :
   hb_subset_context_t *subset_context;
   const hb_tag_t table_tag;
   const hb_map_t *lookup_index_map;
-  const hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map;
+  const hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map;
   const hb_map_t *feature_index_map;
+  const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
+  hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map;
+
   unsigned cur_script_index;
+  unsigned cur_feature_var_record_idx;
 
   hb_subset_layout_context_t (hb_subset_context_t *c_,
-                             hb_tag_t tag_,
-                             hb_map_t *lookup_map_,
-                             hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map_,
-                             hb_map_t *feature_index_map_) :
+                             hb_tag_t tag_) :
                                subset_context (c_),
                                table_tag (tag_),
-                               lookup_index_map (lookup_map_),
-                               script_langsys_map (script_langsys_map_),
-                               feature_index_map (feature_index_map_),
                                cur_script_index (0xFFFFu),
+                               cur_feature_var_record_idx (0u),
                                script_count (0),
                                langsys_count (0),
                                feature_index_count (0),
                                lookup_index_count (0)
-  {}
+  {
+    if (tag_ == HB_OT_TAG_GSUB)
+    {
+      lookup_index_map = &c_->plan->gsub_lookups;
+      script_langsys_map = &c_->plan->gsub_langsys;
+      feature_index_map = &c_->plan->gsub_features;
+      feature_substitutes_map = &c_->plan->gsub_feature_substitutes_map;
+      feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gsub_feature_record_cond_idx_map;
+    }
+    else
+    {
+      lookup_index_map = &c_->plan->gpos_lookups;
+      script_langsys_map = &c_->plan->gpos_langsys;
+      feature_index_map = &c_->plan->gpos_features;
+      feature_substitutes_map = &c_->plan->gpos_feature_substitutes_map;
+      feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gpos_feature_record_cond_idx_map;
+    }
+  }
 
   private:
   unsigned script_count;
@@ -207,6 +182,7 @@ struct hb_subset_layout_context_t :
   unsigned lookup_index_count;
 };
 
+struct VariationStore;
 struct hb_collect_variation_indices_context_t :
        hb_dispatch_context_t<hb_collect_variation_indices_context_t>
 {
@@ -332,6 +308,31 @@ struct subset_record_array_t
   const void *base;
 };
 
+template<typename OutputArray, typename Arg>
+struct subset_record_array_arg_t
+{
+  subset_record_array_arg_t (hb_subset_layout_context_t *c_, OutputArray* out_,
+                            const void *base_,
+                            Arg &&arg_) : subset_layout_context (c_),
+                                          out (out_), base (base_), arg (arg_) {}
+
+  template <typename T>
+  void
+  operator () (T&& record)
+  {
+    auto snap = subset_layout_context->subset_context->serializer->snapshot ();
+    bool ret = record.subset (subset_layout_context, base, arg);
+    if (!ret) subset_layout_context->subset_context->serializer->revert (snap);
+    else out->len++;
+  }
+
+  private:
+  hb_subset_layout_context_t *subset_layout_context;
+  OutputArray *out;
+  const void *base;
+  Arg &&arg;
+};
+
 /*
  * Helper to subset a RecordList/record array. Subsets each Record in the array and
  * discards the record if the subset operation returns false.
@@ -343,6 +344,13 @@ struct
   operator () (hb_subset_layout_context_t *c, OutputArray* out,
               const void *base) const
   { return subset_record_array_t<OutputArray> (c, out, base); }
+
+  /* Variant with one extra argument passed to subset */
+  template<typename OutputArray, typename Arg>
+  subset_record_array_arg_t<OutputArray, Arg>
+  operator () (hb_subset_layout_context_t *c, OutputArray* out,
+               const void *base, Arg &&arg) const
+  { return subset_record_array_arg_t<OutputArray, Arg> (c, out, base, arg); }
 }
 HB_FUNCOBJ (subset_record_array);
 
@@ -394,166 +402,6 @@ HB_FUNCOBJ (serialize_math_record_array);
  * 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
-{
-  int cmp (hb_tag_t a) const { return tag.cmp (a); }
-
-  bool subset (hb_subset_layout_context_t *c, const void *base) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->subset_context->serializer->embed (this);
-    if (unlikely (!out)) return_trace (false);
-    bool ret = out->offset.serialize_subset (c->subset_context, offset, base, c, &tag);
-    return_trace (ret);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c, const void *base) const
-  {
-    TRACE_SANITIZE (this);
-    const Record_sanitize_closure_t closure = {tag, base};
-    return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
-  }
-
-  Tag          tag;            /* 4-byte Tag identifier */
-  Offset16To<Type>
-               offset;         /* Offset from beginning of object holding
-                                * the Record */
-  public:
-  DEFINE_SIZE_STATIC (6);
-};
-
-template <typename Type>
-struct RecordArrayOf : SortedArray16Of<Record<Type>>
-{
-  const Offset16To<Type>& get_offset (unsigned int i) const
-  { return (*this)[i].offset; }
-  Offset16To<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)
-    {
-      + this->sub_array (start_offset, record_count)
-      | hb_map (&Record<Type>::tag)
-      | hb_sink (hb_array (record_tags, *record_count))
-      ;
-    }
-    return this->len;
-  }
-  bool find_index (hb_tag_t tag, unsigned int *index) const
-  {
-    return this->bfind (tag, index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
-  }
-};
-
-template <typename Type>
-struct RecordListOf : RecordArrayOf<Type>
-{
-  const Type& operator [] (unsigned int i) const
-  { return this+this->get_offset (i); }
-
-  bool subset (hb_subset_context_t *c,
-              hb_subset_layout_context_t *l) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-
-    + this->iter ()
-    | hb_apply (subset_record_array (l, out, this))
-    ;
-    return_trace (true);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (RecordArrayOf<Type>::sanitize (c, this));
-  }
-};
-
-struct Feature;
-
-struct RecordListOfFeature : RecordListOf<Feature>
-{
-  bool subset (hb_subset_context_t *c,
-              hb_subset_layout_context_t *l) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
-
-    unsigned count = this->len;
-    + hb_zip (*this, hb_range (count))
-    | hb_filter (l->feature_index_map, hb_second)
-    | hb_map (hb_first)
-    | hb_apply (subset_record_array (l, out, this))
-    ;
-    return_trace (true);
-  }
-};
-
-struct Script;
-struct RecordListOfScript : RecordListOf<Script>
-{
-  bool subset (hb_subset_context_t *c,
-               hb_subset_layout_context_t *l) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
-
-    unsigned count = this->len;
-    for (auto _ : + hb_zip (*this, hb_range (count)))
-    {
-      auto snap = c->serializer->snapshot ();
-      l->cur_script_index = _.second;
-      bool ret = _.first.subset (l, this);
-      if (!ret) c->serializer->revert (snap);
-      else out->len++;
-    }
-
-    return_trace (true);
-  }
-};
-
-struct RangeRecord
-{
-  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));
-  }
-
-  bool intersects (const hb_set_t *glyphs) const
-  { return glyphs->intersects (first, last); }
-
-  template <typename set_t>
-  bool collect_coverage (set_t *glyphs) const
-  { return glyphs->add_range (first, last); }
-
-  HBGlyphID16  first;          /* First GlyphID in the range */
-  HBGlyphID16  last;           /* Last GlyphID in the range */
-  HBUINT16     value;          /* Value */
-  public:
-  DEFINE_SIZE_STATIC (6);
-};
-DECLARE_NULL_NAMESPACE_BYTES (OT, RangeRecord);
-
-
 struct IndexArray : Array16Of<Index>
 {
   bool intersects (const hb_map_t *indexes) const
@@ -585,7 +433,7 @@ struct IndexArray : Array16Of<Index>
   {
     if (_count)
     {
-      + this->sub_array (start_offset, _count)
+      + this->as_array ().sub_array (start_offset, _count)
       | hb_sink (hb_array (_indexes, *_count))
       ;
     }
@@ -599,254 +447,13 @@ struct IndexArray : Array16Of<Index>
 };
 
 
-struct LangSys
+/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
+struct FeatureParamsSize
 {
-  unsigned int get_feature_count () const
-  { return featureIndex.len; }
-  hb_tag_t get_feature_index (unsigned int i) const
-  { return featureIndex[i]; }
-  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); }
-
-  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;
-  }
-
-  LangSys* copy (hb_serialize_context_t *c) const
-  {
-    TRACE_SERIALIZE (this);
-    return_trace (c->embed (*this));
-  }
-
-  bool compare (const LangSys& o, const hb_map_t *feature_index_map) const
+  bool sanitize (hb_sanitize_context_t *c) const
   {
-    if (reqFeatureIndex != o.reqFeatureIndex)
-      return false;
-
-    auto iter =
-    + hb_iter (featureIndex)
-    | hb_filter (feature_index_map)
-    | hb_map (feature_index_map)
-    ;
-
-    auto o_iter =
-    + hb_iter (o.featureIndex)
-    | hb_filter (feature_index_map)
-    | hb_map (feature_index_map)
-    ;
-
-    if (iter.len () != o_iter.len ())
-      return false;
-
-    for (const auto _ : + hb_zip (iter, o_iter))
-      if (_.first != _.second) return false;
-
-    return true;
-  }
-
-  void collect_features (hb_prune_langsys_context_t *c) const
-  {
-    if (!has_required_feature () && !get_feature_count ()) return;
-    if (has_required_feature () &&
-        c->duplicate_feature_map->has (reqFeatureIndex))
-      c->new_feature_indexes->add (get_required_feature_index ());
-
-    + hb_iter (featureIndex)
-    | hb_filter (c->duplicate_feature_map)
-    | hb_sink (c->new_feature_indexes)
-    ;
-  }
-
-  bool subset (hb_subset_context_t        *c,
-              hb_subset_layout_context_t *l,
-              const Tag                  *tag = nullptr) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
-
-    out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex) ? l->feature_index_map->get (reqFeatureIndex) : 0xFFFFu;
-
-    if (!l->visitFeatureIndex (featureIndex.len))
-      return_trace (false);
-
-    auto it =
-    + hb_iter (featureIndex)
-    | hb_filter (l->feature_index_map)
-    | hb_map (l->feature_index_map)
-    ;
-
-    bool ret = bool (it);
-    out->featureIndex.serialize (c->serializer, l, it);
-    return_trace (ret);
-  }
-
-  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));
-  }
-
-  Offset16     lookupOrderZ;   /* = Null (reserved for an offset to a
-                                * reordering table) */
-  HBUINT16     reqFeatureIndex;/* Index of a feature required for this
-                                * language system--if no required features
-                                * = 0xFFFFu */
-  IndexArray   featureIndex;   /* Array of indices into the FeatureList */
-  public:
-  DEFINE_SIZE_ARRAY_SIZED (6, featureIndex);
-};
-DECLARE_NULL_NAMESPACE_BYTES (OT, LangSys);
-
-struct Script
-{
-  unsigned int get_lang_sys_count () const
-  { return langSys.len; }
-  const Tag& get_lang_sys_tag (unsigned int i) const
-  { return langSys.get_tag (i); }
-  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); }
-  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;
-  }
-  bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
-  { return langSys.find_index (tag, index); }
-
-  bool has_default_lang_sys () const           { return defaultLangSys != 0; }
-  const LangSys& get_default_lang_sys () const { return this+defaultLangSys; }
-
-  void prune_langsys (hb_prune_langsys_context_t *c,
-                      unsigned script_index) const
-  {
-    if (!has_default_lang_sys () && !get_lang_sys_count ()) return;
-    if (c->visitedScript (this)) return;
-
-    if (!c->script_langsys_map->has (script_index))
-    {
-      hb_set_t* empty_set = hb_set_create ();
-      if (unlikely (!c->script_langsys_map->set (script_index, empty_set)))
-      {
-       hb_set_destroy (empty_set);
-       return;
-      }
-    }
-
-    unsigned langsys_count = get_lang_sys_count ();
-    if (has_default_lang_sys ())
-    {
-      //only collect features from non-redundant langsys
-      const LangSys& d = get_default_lang_sys ();
-      if (!c->visitedLangsys (&d)) {
-        d.collect_features (c);
-      }
-
-      for (auto _ : + hb_zip (langSys, hb_range (langsys_count)))
-      {
-
-        const LangSys& l = this+_.first.offset;
-        if (c->visitedLangsys (&l)) continue;
-        if (l.compare (d, c->duplicate_feature_map)) continue;
-
-        l.collect_features (c);
-        c->script_langsys_map->get (script_index)->add (_.second);
-      }
-    }
-    else
-    {
-      for (auto _ : + hb_zip (langSys, hb_range (langsys_count)))
-      {
-        const LangSys& l = this+_.first.offset;
-        if (c->visitedLangsys (&l)) continue;
-        l.collect_features (c);
-        c->script_langsys_map->get (script_index)->add (_.second);
-      }
-    }
-  }
-
-  bool subset (hb_subset_context_t         *c,
-              hb_subset_layout_context_t  *l,
-              const Tag                   *tag) const
-  {
-    TRACE_SUBSET (this);
-    if (!l->visitScript ()) return_trace (false);
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
-
-    bool defaultLang = false;
-    if (has_default_lang_sys ())
-    {
-      c->serializer->push ();
-      const LangSys& ls = this+defaultLangSys;
-      bool ret = ls.subset (c, l);
-      if (!ret && tag && *tag != HB_TAG ('D', 'F', 'L', 'T'))
-      {
-       c->serializer->pop_discard ();
-       out->defaultLangSys = 0;
-      }
-      else
-      {
-       c->serializer->add_link (out->defaultLangSys, c->serializer->pop_pack ());
-       defaultLang = true;
-      }
-    }
-
-    const hb_set_t *active_langsys = l->script_langsys_map->get (l->cur_script_index);
-    if (active_langsys)
-    {
-      unsigned count = langSys.len;
-      + hb_zip (langSys, hb_range (count))
-      | hb_filter (active_langsys, hb_second)
-      | hb_map (hb_first)
-      | hb_filter ([=] (const Record<LangSys>& record) {return l->visitLangSys (); })
-      | hb_apply (subset_record_array (l, &(out->langSys), this))
-      ;
-    }
-
-    return_trace (bool (out->langSys.len) || defaultLang || l->table_tag == HB_OT_TAG_GSUB);
-  }
-
-  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));
-  }
-
-  protected:
-  Offset16To<LangSys>
-               defaultLangSys; /* Offset to DefaultLangSys table--from
-                                * beginning of Script table--may be Null */
-  RecordArrayOf<LangSys>
-               langSys;        /* Array of LangSysRecords--listed
-                                * alphabetically by LangSysTag */
-  public:
-  DEFINE_SIZE_ARRAY_SIZED (4, langSys);
-};
-
-typedef RecordListOfScript ScriptList;
-
-
-/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
-struct FeatureParamsSize
-{
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    if (unlikely (!c->check_struct (this))) return_trace (false);
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this))) return_trace (false);
 
     /* This subtable has some "history", if you will.  Some earlier versions of
      * Adobe tools calculated the offset of the FeatureParams subtable from the
@@ -913,6 +520,9 @@ struct FeatureParamsSize
       return_trace (true);
   }
 
+  void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const
+  { nameids_to_retain->add (subfamilyNameID); }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
@@ -969,6 +579,9 @@ struct FeatureParamsStylisticSet
     return_trace (c->check_struct (this));
   }
 
+  void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const
+  { nameids_to_retain->add (uiNameID); }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
@@ -1006,7 +619,7 @@ struct FeatureParamsCharacterVariants
   {
     if (char_count)
     {
-      + characters.sub_array (start_offset, char_count)
+      + characters.as_array ().sub_array (start_offset, char_count)
       | hb_sink (hb_array (chars, *char_count))
       ;
     }
@@ -1016,6 +629,20 @@ struct FeatureParamsCharacterVariants
   unsigned get_size () const
   { return min_size + characters.len * HBUINT24::static_size; }
 
+  void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const
+  {
+    if (featUILableNameID) nameids_to_retain->add (featUILableNameID);
+    if (featUITooltipTextNameID) nameids_to_retain->add (featUITooltipTextNameID);
+    if (sampleTextNameID) nameids_to_retain->add (sampleTextNameID);
+
+    if (!firstParamUILabelNameID || !numNamedParameters || numNamedParameters >= 0x7FFF)
+      return;
+
+    unsigned last_name_id = (unsigned) firstParamUILabelNameID + (unsigned) numNamedParameters - 1;
+    if (last_name_id >= 256 && last_name_id <= 32767)
+      nameids_to_retain->add_range (firstParamUILabelNameID, last_name_id);
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
@@ -1078,6 +705,19 @@ struct FeatureParams
     return_trace (true);
   }
 
+  void collect_name_ids (hb_tag_t tag, hb_set_t *nameids_to_retain /* OUT */) const
+  {
+#ifdef HB_NO_LAYOUT_FEATURE_PARAMS
+    return;
+#endif
+    if (tag == HB_TAG ('s','i','z','e'))
+      return (u.size.collect_name_ids (nameids_to_retain));
+    if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
+      return (u.stylisticSet.collect_name_ids (nameids_to_retain));
+    if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
+      return (u.characterVariants.collect_name_ids (nameids_to_retain));
+  }
+
   bool subset (hb_subset_context_t *c, const Tag* tag) const
   {
     TRACE_SUBSET (this);
@@ -1122,6 +762,11 @@ struct FeatureParams
   DEFINE_SIZE_MIN (0);
 };
 
+struct Record_sanitize_closure_t {
+  hb_tag_t tag;
+  const void *list_base;
+};
+
 struct Feature
 {
   unsigned int get_lookup_count () const
@@ -1141,13 +786,19 @@ struct Feature
   bool intersects_lookup_indexes (const hb_map_t *lookup_indexes) const
   { return lookupIndex.intersects (lookup_indexes); }
 
+  void collect_name_ids (hb_tag_t tag, hb_set_t *nameids_to_retain /* OUT */) const
+  {
+    if (featureParams)
+      get_feature_params ().collect_name_ids (tag, nameids_to_retain);
+  }
+
   bool subset (hb_subset_context_t         *c,
               hb_subset_layout_context_t  *l,
               const Tag                   *tag = nullptr) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
 
     out->featureParams.serialize_subset (c, featureParams, this, tag);
 
@@ -1217,59 +868,445 @@ struct Feature
   DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
 };
 
-typedef RecordListOf<Feature> FeatureList;
-
-
-struct LookupFlag : HBUINT16
+template <typename Type>
+struct Record
 {
-  enum Flags {
-    RightToLeft                = 0x0001u,
-    IgnoreBaseGlyphs   = 0x0002u,
-    IgnoreLigatures    = 0x0004u,
-    IgnoreMarks                = 0x0008u,
-    IgnoreFlags                = 0x000Eu,
-    UseMarkFilteringSet        = 0x0010u,
-    Reserved           = 0x00E0u,
-    MarkAttachmentType = 0xFF00u
-  };
-  public:
-  DEFINE_SIZE_STATIC (2);
-};
+  int cmp (hb_tag_t a) const { return tag.cmp (a); }
 
-} /* namespace OT */
-/* This has to be outside the namespace. */
-HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
-namespace OT {
+  bool subset (hb_subset_layout_context_t *c, const void *base, const void *f_sub = nullptr) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->subset_context->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
 
-struct Lookup
-{
-  unsigned int get_subtable_count () const { return subTable.len; }
+    if (!f_sub)
+      return_trace (out->offset.serialize_subset (c->subset_context, offset, base, c, &tag));
 
-  template <typename TSubTable>
-  const Array16OfOffset16To<TSubTable>& get_subtables () const
-  { return reinterpret_cast<const Array16OfOffset16To<TSubTable> &> (subTable); }
-  template <typename TSubTable>
-  Array16OfOffset16To<TSubTable>& get_subtables ()
-  { return reinterpret_cast<Array16OfOffset16To<TSubTable> &> (subTable); }
+    const Feature& f = *reinterpret_cast<const Feature *> (f_sub);
+    auto *s = c->subset_context->serializer;
+    s->push ();
 
-  template <typename TSubTable>
-  const TSubTable& get_subtable (unsigned int i) const
-  { return this+get_subtables<TSubTable> ()[i]; }
-  template <typename TSubTable>
-  TSubTable& get_subtable (unsigned int i)
-  { return this+get_subtables<TSubTable> ()[i]; }
+    out->offset = 0;
+    bool ret = f.subset (c->subset_context, c, &tag);
+    if (ret)
+      s->add_link (out->offset, s->pop_pack ());
+    else
+      s->pop_discard ();
 
-  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;
+    return_trace (ret);
   }
 
-  unsigned int get_type () const { return lookupType; }
-
-  /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    const Record_sanitize_closure_t closure = {tag, base};
+    return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
+  }
+
+  Tag           tag;            /* 4-byte Tag identifier */
+  Offset16To<Type>
+                offset;         /* Offset from beginning of object holding
+                                 * the Record */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+template <typename Type>
+struct RecordArrayOf : SortedArray16Of<Record<Type>>
+{
+  const Offset16To<Type>& get_offset (unsigned int i) const
+  { return (*this)[i].offset; }
+  Offset16To<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)
+    {
+      + this->as_array ().sub_array (start_offset, record_count)
+      | hb_map (&Record<Type>::tag)
+      | hb_sink (hb_array (record_tags, *record_count))
+      ;
+    }
+    return this->len;
+  }
+  bool find_index (hb_tag_t tag, unsigned int *index) const
+  {
+    return this->bfind (tag, index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
+  }
+};
+
+template <typename Type>
+struct RecordListOf : RecordArrayOf<Type>
+{
+  const Type& operator [] (unsigned int i) const
+  { return this+this->get_offset (i); }
+
+  bool subset (hb_subset_context_t *c,
+               hb_subset_layout_context_t *l) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    + this->iter ()
+    | hb_apply (subset_record_array (l, out, this))
+    ;
+    return_trace (true);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (RecordArrayOf<Type>::sanitize (c, this));
+  }
+};
+
+struct RecordListOfFeature : RecordListOf<Feature>
+{
+  bool subset (hb_subset_context_t *c,
+              hb_subset_layout_context_t *l) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    + hb_enumerate (*this)
+    | hb_filter (l->feature_index_map, hb_first)
+    | hb_apply ([l, out, this] (const hb_pair_t<unsigned, const Record<Feature>&>& _)
+                {
+                  const Feature *f_sub = nullptr;
+                  const Feature **f = nullptr;
+                  if (l->feature_substitutes_map->has (_.first, &f))
+                    f_sub = *f;
+
+                  subset_record_array (l, out, this, f_sub) (_.second);
+                })
+    ;
+
+    return_trace (true);
+  }
+};
+
+typedef RecordListOf<Feature> FeatureList;
+
+
+struct LangSys
+{
+  unsigned int get_feature_count () const
+  { return featureIndex.len; }
+  hb_tag_t get_feature_index (unsigned int i) const
+  { return featureIndex[i]; }
+  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); }
+
+  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;
+  }
+
+  LangSys* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (c->embed (*this));
+  }
+
+  bool compare (const LangSys& o, const hb_map_t *feature_index_map) const
+  {
+    if (reqFeatureIndex != o.reqFeatureIndex)
+      return false;
+
+    auto iter =
+    + hb_iter (featureIndex)
+    | hb_filter (feature_index_map)
+    | hb_map (feature_index_map)
+    ;
+
+    auto o_iter =
+    + hb_iter (o.featureIndex)
+    | hb_filter (feature_index_map)
+    | hb_map (feature_index_map)
+    ;
+
+    for (; iter && o_iter; iter++, o_iter++)
+    {
+      unsigned a = *iter;
+      unsigned b = *o_iter;
+      if (a != b) return false;
+    }
+
+    if (iter || o_iter) return false;
+
+    return true;
+  }
+
+  void collect_features (hb_prune_langsys_context_t *c) const
+  {
+    if (!has_required_feature () && !get_feature_count ()) return;
+    if (has_required_feature () &&
+        c->duplicate_feature_map->has (reqFeatureIndex))
+      c->new_feature_indexes->add (get_required_feature_index ());
+
+    + hb_iter (featureIndex)
+    | hb_filter (c->duplicate_feature_map)
+    | hb_sink (c->new_feature_indexes)
+    ;
+  }
+
+  bool subset (hb_subset_context_t        *c,
+              hb_subset_layout_context_t *l,
+              const Tag                  *tag = nullptr) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    const uint32_t *v;
+    out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex, &v) ? *v : 0xFFFFu;
+
+    if (!l->visitFeatureIndex (featureIndex.len))
+      return_trace (false);
+
+    auto it =
+    + hb_iter (featureIndex)
+    | hb_filter (l->feature_index_map)
+    | hb_map (l->feature_index_map)
+    ;
+
+    bool ret = bool (it);
+    out->featureIndex.serialize (c->serializer, l, it);
+    return_trace (ret);
+  }
+
+  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));
+  }
+
+  Offset16     lookupOrderZ;   /* = Null (reserved for an offset to a
+                                * reordering table) */
+  HBUINT16     reqFeatureIndex;/* Index of a feature required for this
+                                * language system--if no required features
+                                * = 0xFFFFu */
+  IndexArray   featureIndex;   /* Array of indices into the FeatureList */
+  public:
+  DEFINE_SIZE_ARRAY_SIZED (6, featureIndex);
+};
+DECLARE_NULL_NAMESPACE_BYTES (OT, LangSys);
+
+struct Script
+{
+  unsigned int get_lang_sys_count () const
+  { return langSys.len; }
+  const Tag& get_lang_sys_tag (unsigned int i) const
+  { return langSys.get_tag (i); }
+  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); }
+  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;
+  }
+  bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
+  { return langSys.find_index (tag, index); }
+
+  bool has_default_lang_sys () const           { return defaultLangSys != 0; }
+  const LangSys& get_default_lang_sys () const { return this+defaultLangSys; }
+
+  void prune_langsys (hb_prune_langsys_context_t *c,
+                      unsigned script_index) const
+  {
+    if (!has_default_lang_sys () && !get_lang_sys_count ()) return;
+    if (!c->visitScript ()) return;
+
+    if (!c->script_langsys_map->has (script_index))
+    {
+      if (unlikely (!c->script_langsys_map->set (script_index, hb::unique_ptr<hb_set_t> {hb_set_create ()})))
+       return;
+    }
+
+    if (has_default_lang_sys ())
+    {
+      //only collect features from non-redundant langsys
+      const LangSys& d = get_default_lang_sys ();
+      if (c->visitLangsys (d.get_feature_count ())) {
+        d.collect_features (c);
+      }
+
+      for (auto _ : + hb_enumerate (langSys))
+      {
+        const LangSys& l = this+_.second.offset;
+        if (!c->visitLangsys (l.get_feature_count ())) continue;
+        if (l.compare (d, c->duplicate_feature_map)) continue;
+
+        l.collect_features (c);
+        c->script_langsys_map->get (script_index)->add (_.first);
+      }
+    }
+    else
+    {
+      for (auto _ : + hb_enumerate (langSys))
+      {
+        const LangSys& l = this+_.second.offset;
+        if (!c->visitLangsys (l.get_feature_count ())) continue;
+        l.collect_features (c);
+        c->script_langsys_map->get (script_index)->add (_.first);
+      }
+    }
+  }
+
+  bool subset (hb_subset_context_t         *c,
+              hb_subset_layout_context_t  *l,
+              const Tag                   *tag) const
+  {
+    TRACE_SUBSET (this);
+    if (!l->visitScript ()) return_trace (false);
+    if (tag && !c->plan->layout_scripts.has (*tag))
+      return false;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    bool defaultLang = false;
+    if (has_default_lang_sys ())
+    {
+      c->serializer->push ();
+      const LangSys& ls = this+defaultLangSys;
+      bool ret = ls.subset (c, l);
+      if (!ret && tag && *tag != HB_TAG ('D', 'F', 'L', 'T'))
+      {
+       c->serializer->pop_discard ();
+       out->defaultLangSys = 0;
+      }
+      else
+      {
+       c->serializer->add_link (out->defaultLangSys, c->serializer->pop_pack ());
+       defaultLang = true;
+      }
+    }
+
+    const hb_set_t *active_langsys = l->script_langsys_map->get (l->cur_script_index);
+    if (active_langsys)
+    {
+      + hb_enumerate (langSys)
+      | hb_filter (active_langsys, hb_first)
+      | hb_map (hb_second)
+      | hb_filter ([=] (const Record<LangSys>& record) {return l->visitLangSys (); })
+      | hb_apply (subset_record_array (l, &(out->langSys), this))
+      ;
+    }
+
+    return_trace (bool (out->langSys.len) || defaultLang || l->table_tag == HB_OT_TAG_GSUB);
+  }
+
+  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));
+  }
+
+  protected:
+  Offset16To<LangSys>
+               defaultLangSys; /* Offset to DefaultLangSys table--from
+                                * beginning of Script table--may be Null */
+  RecordArrayOf<LangSys>
+               langSys;        /* Array of LangSysRecords--listed
+                                * alphabetically by LangSysTag */
+  public:
+  DEFINE_SIZE_ARRAY_SIZED (4, langSys);
+};
+
+struct RecordListOfScript : RecordListOf<Script>
+{
+  bool subset (hb_subset_context_t *c,
+               hb_subset_layout_context_t *l) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    for (auto _ : + hb_enumerate (*this))
+    {
+      auto snap = c->serializer->snapshot ();
+      l->cur_script_index = _.first;
+      bool ret = _.second.subset (l, this);
+      if (!ret) c->serializer->revert (snap);
+      else out->len++;
+    }
+
+    return_trace (true);
+  }
+};
+
+typedef RecordListOfScript ScriptList;
+
+
+
+struct LookupFlag : HBUINT16
+{
+  enum Flags {
+    RightToLeft                = 0x0001u,
+    IgnoreBaseGlyphs   = 0x0002u,
+    IgnoreLigatures    = 0x0004u,
+    IgnoreMarks                = 0x0008u,
+    IgnoreFlags                = 0x000Eu,
+    UseMarkFilteringSet        = 0x0010u,
+    Reserved           = 0x00E0u,
+    MarkAttachmentType = 0xFF00u
+  };
+  public:
+  DEFINE_SIZE_STATIC (2);
+};
+
+} /* namespace OT */
+/* This has to be outside the namespace. */
+HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
+namespace OT {
+
+struct Lookup
+{
+  unsigned int get_subtable_count () const { return subTable.len; }
+
+  template <typename TSubTable>
+  const Array16OfOffset16To<TSubTable>& get_subtables () const
+  { return reinterpret_cast<const Array16OfOffset16To<TSubTable> &> (subTable); }
+  template <typename TSubTable>
+  Array16OfOffset16To<TSubTable>& get_subtables ()
+  { return reinterpret_cast<Array16OfOffset16To<TSubTable> &> (subTable); }
+
+  template <typename TSubTable>
+  const TSubTable& get_subtable (unsigned int i) const
+  { return this+get_subtables<TSubTable> ()[i]; }
+  template <typename TSubTable>
+  TSubTable& get_subtable (unsigned int i)
+  { return this+get_subtables<TSubTable> ()[i]; }
+
+  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;
+  }
+
+  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. */
   uint32_t get_props () const
@@ -1321,7 +1358,7 @@ struct Lookup
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
     out->lookupType = lookupType;
     out->lookupFlag = lookupFlag;
 
@@ -1340,7 +1377,13 @@ struct Lookup
       outMarkFilteringSet = markFilteringSet;
     }
 
-    return_trace (out->subTable.len);
+    // Always keep the lookup even if it's empty. The rest of layout subsetting depends on lookup
+    // indices being consistent with those computed during planning. So if an empty lookup is
+    // discarded during the subset phase it will invalidate all subsequent lookup indices.
+    // Generally we shouldn't end up with an empty lookup as we pre-prune them during the planning
+    // phase, but it can happen in rare cases such as when during closure subtable is considered
+    // degenerate (see: https://github.com/harfbuzz/harfbuzz/issues/3853)
+    return_trace (true);
   }
 
   template <typename TSubTable>
@@ -1361,7 +1404,7 @@ struct Lookup
     if (unlikely (!get_subtables<TSubTable> ().sanitize (c, this, get_type ())))
       return_trace (false);
 
-    if (unlikely (get_type () == TSubTable::Extension && subtables && !c->get_edit_count ()))
+    if (unlikely (get_type () == TSubTable::Extension && !c->get_edit_count ()))
     {
       /* The spec says all subtables of an Extension lookup should
        * have the same type, which shall not be the Extension type
@@ -1381,7 +1424,7 @@ struct Lookup
     return_trace (true);
   }
 
-  private:
+  protected:
   HBUINT16     lookupType;             /* Different enumerations for GSUB and GPOS */
   HBUINT16     lookupFlag;             /* Lookup qualifiers */
   Array16Of<Offset16>
@@ -1393,497 +1436,48 @@ struct Lookup
   DEFINE_SIZE_ARRAY (6, subTable);
 };
 
-typedef List16OfOffset16To<Lookup> LookupList;
+template <typename Types>
+using LookupList = List16OfOffsetTo<Lookup, typename Types::HBUINT>;
 
-template <typename TLookup>
-struct LookupOffsetList : List16OfOffset16To<TLookup>
+template <typename TLookup, typename OffsetType>
+struct LookupOffsetList : List16OfOffsetTo<TLookup, OffsetType>
 {
   bool subset (hb_subset_context_t        *c,
               hb_subset_layout_context_t *l) const
   {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->start_embed (this);
-    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
-
-    unsigned count = this->len;
-    + hb_zip (*this, hb_range (count))
-    | hb_filter (l->lookup_index_map, hb_second)
-    | hb_map (hb_first)
-    | hb_apply (subset_offset_array (c, *out, this))
-    ;
-    return_trace (true);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (List16OfOffset16To<TLookup>::sanitize (c, this));
-  }
-};
-
-
-/*
- * Coverage Table
- */
-
-struct CoverageFormat1
-{
-  friend struct Coverage;
-
-  private:
-  unsigned int get_coverage (hb_codepoint_t glyph_id) const
-  {
-    unsigned int i;
-    glyphArray.bfind (glyph_id, &i, HB_NOT_FOUND_STORE, NOT_COVERED);
-    return i;
-  }
-
-  template <typename Iterator,
-      hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
-  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
-  {
-    TRACE_SERIALIZE (this);
-    return_trace (glyphArray.serialize (c, glyphs));
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (glyphArray.sanitize (c));
-  }
-
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    /* TODO Speed up, using hb_set_next() and bsearch()? */
-    for (const auto& g : glyphArray.as_array ())
-      if (glyphs->has (g))
-       return true;
-    return false;
-  }
-  bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
-  { return glyphs->has (glyphArray[index]); }
-
-  void intersected_coverage_glyphs (const hb_set_t *glyphs, hb_set_t *intersect_glyphs) const
-  {
-    unsigned count = glyphArray.len;
-    for (unsigned i = 0; i < count; i++)
-      if (glyphs->has (glyphArray[i]))
-        intersect_glyphs->add (glyphArray[i]);
-  }
-
-  template <typename set_t>
-  bool collect_coverage (set_t *glyphs) const
-  { return glyphs->add_sorted_array (glyphArray.as_array ()); }
-
-  public:
-  /* Older compilers need this to be public. */
-  struct iter_t
-  {
-    void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; }
-    void fini () {}
-    bool more () const { return i < c->glyphArray.len; }
-    void next () { i++; }
-    hb_codepoint_t get_glyph () const { return c->glyphArray[i]; }
-    bool operator != (const iter_t& o) const
-    { return i != o.i || c != o.c; }
-
-    private:
-    const struct CoverageFormat1 *c;
-    unsigned int i;
-  };
-  private:
-
-  protected:
-  HBUINT16     coverageFormat; /* Format identifier--format = 1 */
-  SortedArray16Of<HBGlyphID16>
-               glyphArray;     /* Array of GlyphIDs--in numerical order */
-  public:
-  DEFINE_SIZE_ARRAY (4, glyphArray);
-};
-
-struct CoverageFormat2
-{
-  friend struct Coverage;
-
-  private:
-  unsigned int get_coverage (hb_codepoint_t glyph_id) const
-  {
-    const RangeRecord &range = rangeRecord.bsearch (glyph_id);
-    return likely (range.first <= range.last)
-        ? (unsigned int) range.value + (glyph_id - range.first)
-        : NOT_COVERED;
-  }
-
-  template <typename Iterator,
-      hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
-  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (this))) return_trace (false);
-
-    if (unlikely (!glyphs))
-    {
-      rangeRecord.len = 0;
-      return_trace (true);
-    }
-
-    /* TODO(iter) Write more efficiently? */
-
-    unsigned num_ranges = 0;
-    hb_codepoint_t last = (hb_codepoint_t) -2;
-    for (auto g: glyphs)
-    {
-      if (last + 1 != g)
-       num_ranges++;
-      last = g;
-    }
-
-    if (unlikely (!rangeRecord.serialize (c, num_ranges))) return_trace (false);
-
-    unsigned count = 0;
-    unsigned range = (unsigned) -1;
-    last = (hb_codepoint_t) -2;
-    for (auto g: glyphs)
-    {
-      if (last + 1 != g)
-      {
-       range++;
-       rangeRecord[range].first = g;
-       rangeRecord[range].value = count;
-      }
-      rangeRecord[range].last = g;
-      last = g;
-      count++;
-    }
-
-    return_trace (true);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (rangeRecord.sanitize (c));
-  }
-
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    /* TODO Speed up, using hb_set_next() and bsearch()? */
-    /* TODO(iter) Rewrite as dagger. */
-    for (const auto& range : rangeRecord.as_array ())
-      if (range.intersects (glyphs))
-       return true;
-    return false;
-  }
-  bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
-  {
-    /* TODO(iter) Rewrite as dagger. */
-    for (const auto& range : rangeRecord.as_array ())
-    {
-      if (range.value <= index &&
-         index < (unsigned int) range.value + (range.last - range.first) &&
-         range.intersects (glyphs))
-       return true;
-      else if (index < range.value)
-       return false;
-    }
-    return false;
-  }
-
-  void intersected_coverage_glyphs (const hb_set_t *glyphs, hb_set_t *intersect_glyphs) const
-  {
-    for (const auto& range : rangeRecord.as_array ())
-    {
-      if (!range.intersects (glyphs)) continue;
-      for (hb_codepoint_t g = range.first; g <= range.last; g++)
-        if (glyphs->has (g)) intersect_glyphs->add (g);
-    }
-  }
-
-  template <typename set_t>
-  bool collect_coverage (set_t *glyphs) const
-  {
-    unsigned int count = rangeRecord.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!rangeRecord[i].collect_coverage (glyphs)))
-       return false;
-    return true;
-  }
-
-  public:
-  /* Older compilers need this to be public. */
-  struct iter_t
-  {
-    void init (const CoverageFormat2 &c_)
-    {
-      c = &c_;
-      coverage = 0;
-      i = 0;
-      j = c->rangeRecord.len ? c->rangeRecord[0].first : 0;
-      if (unlikely (c->rangeRecord[0].first > c->rangeRecord[0].last))
-      {
-       /* Broken table. Skip. */
-       i = c->rangeRecord.len;
-      }
-    }
-    void fini () {}
-    bool more () const { return i < c->rangeRecord.len; }
-    void next ()
-    {
-      if (j >= c->rangeRecord[i].last)
-      {
-       i++;
-       if (more ())
-       {
-         unsigned int old = coverage;
-         j = c->rangeRecord[i].first;
-         coverage = c->rangeRecord[i].value;
-         if (unlikely (coverage != old + 1))
-         {
-           /* Broken table. Skip. Important to avoid DoS.
-            * Also, our callers depend on coverage being
-            * consecutive and monotonically increasing,
-            * ie. iota(). */
-          i = c->rangeRecord.len;
-          return;
-         }
-       }
-       return;
-      }
-      coverage++;
-      j++;
-    }
-    hb_codepoint_t get_glyph () const { return j; }
-    bool operator != (const iter_t& o) const
-    { return i != o.i || j != o.j || c != o.c; }
-
-    private:
-    const struct CoverageFormat2 *c;
-    unsigned int i, coverage;
-    hb_codepoint_t j;
-  };
-  private:
-
-  protected:
-  HBUINT16     coverageFormat; /* Format identifier--format = 2 */
-  SortedArray16Of<RangeRecord>
-               rangeRecord;    /* Array of glyph ranges--ordered by
-                                * Start GlyphID. rangeCount entries
-                                * long */
-  public:
-  DEFINE_SIZE_ARRAY (4, rangeRecord);
-};
-
-struct Coverage
-{
-  /* Has interface. */
-  static constexpr unsigned SENTINEL = NOT_COVERED;
-  typedef unsigned int value_t;
-  value_t operator [] (hb_codepoint_t k) const { return get (k); }
-  bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
-  /* Predicate. */
-  bool operator () (hb_codepoint_t k) const { return has (k); }
-
-  unsigned int get (hb_codepoint_t k) const { return get_coverage (k); }
-  unsigned int get_coverage (hb_codepoint_t glyph_id) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.get_coverage (glyph_id);
-    case 2: return u.format2.get_coverage (glyph_id);
-    default:return NOT_COVERED;
-    }
-  }
-
-  template <typename Iterator,
-      hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
-  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (this))) return_trace (false);
-
-    unsigned count = 0;
-    unsigned num_ranges = 0;
-    hb_codepoint_t last = (hb_codepoint_t) -2;
-    for (auto g: glyphs)
-    {
-      if (last + 1 != g)
-       num_ranges++;
-      last = g;
-      count++;
-    }
-    u.format = count <= 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);
-    }
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto it =
-    + iter ()
-    | hb_filter (glyphset)
-    | hb_map_retains_sorting (glyph_map)
-    ;
-
-    bool ret = bool (it);
-    Coverage_serialize (c->serializer, it);
-    return_trace (ret);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    if (!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));
-    default:return_trace (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;
-    }
-  }
-  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;
-    }
-  }
-
-  /* Might return false if array looks unsorted.
-   * Used for faster rejection of corrupt data. */
-  template <typename set_t>
-  bool collect_coverage (set_t *glyphs) const
-  {
-    switch (u.format)
-    {
-    case 1: return u.format1.collect_coverage (glyphs);
-    case 2: return u.format2.collect_coverage (glyphs);
-    default:return false;
-    }
-  }
-
-  void intersected_coverage_glyphs (const hb_set_t *glyphs, hb_set_t *intersect_glyphs) const
-  {
-    switch (u.format)
-    {
-    case 1: return u.format1.intersected_coverage_glyphs (glyphs, intersect_glyphs);
-    case 2: return u.format2.intersected_coverage_glyphs (glyphs, intersect_glyphs);
-    default:return ;
-    }
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    + hb_enumerate (*this)
+    | hb_filter (l->lookup_index_map, hb_first)
+    | hb_map (hb_second)
+    | hb_apply (subset_offset_array (c, *out, this))
+    ;
+    return_trace (true);
   }
 
-  struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
+  bool sanitize (hb_sanitize_context_t *c) const
   {
-    static constexpr bool is_sorted_iterator = true;
-    iter_t (const Coverage &c_ = Null (Coverage))
-    {
-      memset (this, 0, sizeof (*this));
-      format = c_.u.format;
-      switch (format)
-      {
-      case 1: u.format1.init (c_.u.format1); return;
-      case 2: u.format2.init (c_.u.format2); return;
-      default:                              return;
-      }
-    }
-    bool __more__ () const
-    {
-      switch (format)
-      {
-      case 1: return u.format1.more ();
-      case 2: return u.format2.more ();
-      default:return false;
-      }
-    }
-    void __next__ ()
-    {
-      switch (format)
-      {
-      case 1: u.format1.next (); break;
-      case 2: u.format2.next (); break;
-      default:                  break;
-      }
-    }
-    typedef hb_codepoint_t __item_t__;
-    __item_t__ __item__ () const { return get_glyph (); }
+    TRACE_SANITIZE (this);
+    return_trace (List16OfOffset16To<TLookup>::sanitize (c, this));
+  }
+};
 
-    hb_codepoint_t get_glyph () const
-    {
-      switch (format)
-      {
-      case 1: return u.format1.get_glyph ();
-      case 2: return u.format2.get_glyph ();
-      default:return 0;
-      }
-    }
-    bool operator != (const iter_t& o) const
-    {
-      if (format != o.format) return true;
-      switch (format)
-      {
-      case 1: return u.format1 != o.u.format1;
-      case 2: return u.format2 != o.u.format2;
-      default:return false;
-      }
-    }
 
-    private:
-    unsigned int format;
-    union {
-    CoverageFormat2::iter_t    format2; /* Put this one first since it's larger; helps shut up compiler. */
-    CoverageFormat1::iter_t    format1;
-    } u;
-  };
-  iter_t iter () const { return iter_t (*this); }
+/*
+ * Coverage Table
+ */
 
-  protected:
-  union {
-  HBUINT16             format;         /* Format identifier */
-  CoverageFormat1      format1;
-  CoverageFormat2      format2;
-  } u;
-  public:
-  DEFINE_SIZE_UNION (2, format);
-};
 
-template<typename Iterator>
-static inline void
-Coverage_serialize (hb_serialize_context_t *c,
-                   Iterator it)
-{ c->start_embed<Coverage> ()->serialize (c, it); }
-
-static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
-                                         const hb_map_t &gid_klass_map,
-                                         hb_sorted_vector_t<HBGlyphID16> &glyphs,
+static bool ClassDef_remap_and_serialize (hb_serialize_context_t *c,
                                          const hb_set_t &klasses,
                                           bool use_class_zero,
-                                         hb_map_t *klass_map /*INOUT*/)
+                                          hb_sorted_vector_t<hb_codepoint_pair_t> &glyph_and_klass, /* IN/OUT */
+                                         hb_map_t *klass_map /*IN/OUT*/)
 {
   if (!klass_map)
-  {
-    ClassDef_serialize (c, hb_zip (glyphs.iter (), + glyphs.iter ()
-                                                  | hb_map (gid_klass_map)));
-    return;
-  }
+    return ClassDef_serialize (c, glyph_and_klass.iter ());
 
   /* any glyph not assigned a class value falls into Class zero (0),
    * if any glyph assigned to class 0, remapping must start with 0->0*/
@@ -1891,31 +1485,30 @@ static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
     klass_map->set (0, 0);
 
   unsigned idx = klass_map->has (0) ? 1 : 0;
-  for (const unsigned k: klasses.iter ())
+  for (const unsigned k: klasses)
   {
     if (klass_map->has (k)) continue;
     klass_map->set (k, idx);
     idx++;
   }
 
-  auto it =
-  + glyphs.iter ()
-  | hb_map_retains_sorting ([&] (const HBGlyphID16& gid) -> hb_pair_t<hb_codepoint_t, unsigned>
-                           {
-                             unsigned new_klass = klass_map->get (gid_klass_map[gid]);
-                             return hb_pair ((hb_codepoint_t)gid, new_klass);
-                           })
-  ;
 
-  c->propagate_error (glyphs, klasses);
-  ClassDef_serialize (c, it);
+  for (unsigned i = 0; i < glyph_and_klass.length; i++)
+  {
+    hb_codepoint_t klass = glyph_and_klass[i].second;
+    glyph_and_klass[i].second = klass_map->get (klass);
+  }
+
+  c->propagate_error (glyph_and_klass, klasses);
+  return ClassDef_serialize (c, glyph_and_klass.iter ());
 }
 
 /*
  * Class Definition Table
  */
 
-struct ClassDefFormat1
+template <typename Types>
+struct ClassDefFormat1_3
 {
   friend struct ClassDef;
 
@@ -1925,8 +1518,13 @@ struct ClassDefFormat1
     return classValue[(unsigned int) (glyph_id - startGlyph)];
   }
 
+  unsigned get_population () const
+  {
+    return classValue.len;
+  }
+
   template<typename Iterator,
-          hb_requires (hb_is_iterator (Iterator))>
+          hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
   bool serialize (hb_serialize_context_t *c,
                  Iterator it)
   {
@@ -1949,7 +1547,7 @@ struct ClassDefFormat1
 
     startGlyph = glyph_min;
     if (unlikely (!classValue.serialize (c, glyph_count))) return_trace (false);
-    for (const hb_pair_t<hb_codepoint_t, unsigned> gid_klass_pair : + it)
+    for (const hb_pair_t<hb_codepoint_t, uint32_t> gid_klass_pair : + it)
     {
       unsigned idx = gid_klass_pair.first - glyph_min;
       classValue[idx] = gid_klass_pair.second;
@@ -1964,36 +1562,41 @@ struct ClassDefFormat1
                const Coverage* glyph_filter = nullptr) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
+    const hb_map_t &glyph_map = c->plan->glyph_map_gsub;
 
-    hb_sorted_vector_t<HBGlyphID16> glyphs;
+    hb_sorted_vector_t<hb_codepoint_pair_t> glyph_and_klass;
     hb_set_t orig_klasses;
-    hb_map_t gid_org_klass_map;
 
     hb_codepoint_t start = startGlyph;
     hb_codepoint_t end   = start + classValue.len;
 
-    for (const hb_codepoint_t gid : + hb_range (start, end)
-                                    | hb_filter (glyphset))
+    for (const hb_codepoint_t gid : + hb_range (start, end))
     {
+      hb_codepoint_t new_gid = glyph_map[gid];
+      if (new_gid == HB_MAP_VALUE_INVALID) continue;
       if (glyph_filter && !glyph_filter->has(gid)) continue;
 
       unsigned klass = classValue[gid - start];
       if (!klass) continue;
 
-      glyphs.push (glyph_map[gid]);
-      gid_org_klass_map.set (glyph_map[gid], klass);
+      glyph_and_klass.push (hb_pair (new_gid, klass));
       orig_klasses.add (klass);
     }
 
-    unsigned glyph_count = glyph_filter
-                           ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter))
-                           : glyphset.get_population ();
-    use_class_zero = use_class_zero && glyph_count <= gid_org_klass_map.get_population ();
-    ClassDef_remap_and_serialize (c->serializer, gid_org_klass_map,
-                                 glyphs, orig_klasses, use_class_zero, klass_map);
-    return_trace (keep_empty_table || (bool) glyphs);
+    if (use_class_zero)
+    {
+      unsigned glyph_count = glyph_filter
+                            ? hb_len (hb_iter (glyph_map.keys()) | hb_filter (glyph_filter))
+                            : glyph_map.get_population ();
+      use_class_zero = glyph_count <= glyph_and_klass.length;
+    }
+    if (!ClassDef_remap_and_serialize (c->serializer,
+                                       orig_klasses,
+                                       use_class_zero,
+                                       glyph_and_klass,
+                                       klass_map))
+      return_trace (false);
+    return_trace (keep_empty_table || (bool) glyph_and_klass);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -2002,6 +1605,8 @@ struct ClassDefFormat1
     return_trace (c->check_struct (this) && classValue.sanitize (c));
   }
 
+  unsigned cost () const { return 1; }
+
   template <typename set_t>
   bool collect_coverage (set_t *glyphs) const
   {
@@ -2036,11 +1641,10 @@ struct ClassDefFormat1
 
   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;)
+        glyphs->next (&iter) && iter < end;)
       if (classValue[iter - start]) return true;
     return false;
   }
@@ -2051,18 +1655,17 @@ struct ClassDefFormat1
     {
       /* 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 (!glyphs->next (&g)) return false;
       if (g < startGlyph) return true;
       g = startGlyph + count - 1;
-      if (hb_set_next (glyphs, &g)) return true;
+      if (glyphs->next (&g)) return true;
       /* Fall through. */
     }
     /* TODO Speed up, using set overlap first? */
     /* TODO(iter) Rewrite as dagger. */
-    HBUINT16 k {klass};
     const HBUINT16 *arr = classValue.arrayZ;
     for (unsigned int i = 0; i < count; i++)
-      if (arr[i] == k && glyphs->has (startGlyph + i))
+      if (arr[i] == klass && glyphs->has (startGlyph + i))
        return true;
     return false;
   }
@@ -2072,17 +1675,32 @@ struct ClassDefFormat1
     unsigned count = classValue.len;
     if (klass == 0)
     {
-      hb_codepoint_t endGlyph = startGlyph + count -1;
-      for (hb_codepoint_t g : glyphs->iter ())
-        if (g < startGlyph || g > endGlyph)
-          intersect_glyphs->add (g);
+      unsigned start_glyph = startGlyph;
+      for (uint32_t g = HB_SET_VALUE_INVALID;
+          glyphs->next (&g) && g < start_glyph;)
+       intersect_glyphs->add (g);
+
+      for (uint32_t g = startGlyph + count - 1;
+          glyphs-> next (&g);)
+       intersect_glyphs->add (g);
 
       return;
     }
 
     for (unsigned i = 0; i < count; i++)
       if (classValue[i] == klass && glyphs->has (startGlyph + i))
-        intersect_glyphs->add (startGlyph + i);
+       intersect_glyphs->add (startGlyph + i);
+
+#if 0
+    /* The following implementation is faster asymptotically, but slower
+     * in practice. */
+    unsigned start_glyph = startGlyph;
+    unsigned end_glyph = start_glyph + count;
+    for (unsigned g = startGlyph - 1;
+        glyphs->next (&g) && g < end_glyph;)
+      if (classValue.arrayZ[g - start_glyph] == klass)
+        intersect_glyphs->add (g);
+#endif
   }
 
   void intersected_classes (const hb_set_t *glyphs, hb_set_t *intersect_classes) const
@@ -2103,14 +1721,16 @@ struct ClassDefFormat1
 
   protected:
   HBUINT16     classFormat;    /* Format identifier--format = 1 */
-  HBGlyphID16  startGlyph;     /* First GlyphID of the classValueArray */
-  Array16Of<HBUINT16>
+  typename Types::HBGlyphID
+                startGlyph;    /* First GlyphID of the classValueArray */
+  typename Types::template ArrayOf<HBUINT16>
                classValue;     /* Array of Class Values--one per GlyphID */
   public:
-  DEFINE_SIZE_ARRAY (6, classValue);
+  DEFINE_SIZE_ARRAY (2 + 2 * Types::size, classValue);
 };
 
-struct ClassDefFormat2
+template <typename Types>
+struct ClassDefFormat2_4
 {
   friend struct ClassDef;
 
@@ -2120,8 +1740,16 @@ struct ClassDefFormat2
     return rangeRecord.bsearch (glyph_id).value;
   }
 
+  unsigned get_population () const
+  {
+    typename Types::large_int ret = 0;
+    for (const auto &r : rangeRecord)
+      ret += r.get_population ();
+    return ret > UINT_MAX ? UINT_MAX : (unsigned) ret;
+  }
+
   template<typename Iterator,
-          hb_requires (hb_is_iterator (Iterator))>
+          hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
   bool serialize (hb_serialize_context_t *c,
                  Iterator it)
   {
@@ -2135,16 +1763,17 @@ struct ClassDefFormat2
       return_trace (true);
     }
 
+    unsigned unsorted = false;
     unsigned num_ranges = 1;
     hb_codepoint_t prev_gid = (*it).first;
     unsigned prev_klass = (*it).second;
 
-    RangeRecord range_rec;
+    RangeRecord<Types> range_rec;
     range_rec.first = prev_gid;
     range_rec.last = prev_gid;
     range_rec.value = prev_klass;
 
-    RangeRecord *record = c->copy (range_rec);
+    auto *record = c->copy (range_rec);
     if (unlikely (!record)) return_trace (false);
 
     for (const auto gid_klass_pair : + (++it))
@@ -2155,6 +1784,10 @@ struct ClassDefFormat2
       if (cur_gid != prev_gid + 1 ||
          cur_klass != prev_klass)
       {
+
+       if (unlikely (cur_gid < prev_gid))
+         unsorted = true;
+
        if (unlikely (!record)) break;
        record->last = prev_gid;
        num_ranges++;
@@ -2170,8 +1803,14 @@ struct ClassDefFormat2
       prev_gid = cur_gid;
     }
 
+    if (unlikely (c->in_error ())) return_trace (false);
+
     if (likely (record)) record->last = prev_gid;
     rangeRecord.len = num_ranges;
+
+    if (unlikely (unsorted))
+      rangeRecord.as_array ().qsort (RangeRecord<Types>::cmp_range);
+
     return_trace (true);
   }
 
@@ -2182,37 +1821,59 @@ struct ClassDefFormat2
                const Coverage* glyph_filter = nullptr) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
+    const hb_map_t &glyph_map = c->plan->glyph_map_gsub;
+    const hb_set_t &glyph_set = *c->plan->glyphset_gsub ();
 
-    hb_sorted_vector_t<HBGlyphID16> glyphs;
+    hb_sorted_vector_t<hb_codepoint_pair_t> glyph_and_klass;
     hb_set_t orig_klasses;
-    hb_map_t gid_org_klass_map;
 
-    unsigned count = rangeRecord.len;
-    for (unsigned i = 0; i < count; i++)
+    if (glyph_set.get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2
+       < get_population ())
     {
-      unsigned klass = rangeRecord[i].value;
-      if (!klass) continue;
-      hb_codepoint_t start = rangeRecord[i].first;
-      hb_codepoint_t end   = rangeRecord[i].last + 1;
-      for (hb_codepoint_t g = start; g < end; g++)
+      for (hb_codepoint_t g : glyph_set)
       {
-       if (!glyphset.has (g)) continue;
-        if (glyph_filter && !glyph_filter->has (g)) continue;
-       glyphs.push (glyph_map[g]);
-       gid_org_klass_map.set (glyph_map[g], klass);
+       unsigned klass = get_class (g);
+       if (!klass) continue;
+       hb_codepoint_t new_gid = glyph_map[g];
+       if (new_gid == HB_MAP_VALUE_INVALID) continue;
+       if (glyph_filter && !glyph_filter->has (g)) continue;
+       glyph_and_klass.push (hb_pair (new_gid, klass));
        orig_klasses.add (klass);
       }
     }
+    else
+    {
+      unsigned num_source_glyphs = c->plan->source->get_num_glyphs ();
+      for (auto &range : rangeRecord)
+      {
+       unsigned klass = range.value;
+       if (!klass) continue;
+       hb_codepoint_t start = range.first;
+       hb_codepoint_t end   = hb_min (range.last + 1, num_source_glyphs);
+       for (hb_codepoint_t g = start; g < end; g++)
+       {
+         hb_codepoint_t new_gid = glyph_map[g];
+         if (new_gid == HB_MAP_VALUE_INVALID) continue;
+         if (glyph_filter && !glyph_filter->has (g)) continue;
+
+         glyph_and_klass.push (hb_pair (new_gid, klass));
+         orig_klasses.add (klass);
+       }
+      }
+    }
 
+    const hb_set_t& glyphset = *c->plan->glyphset_gsub ();
     unsigned glyph_count = glyph_filter
                            ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter))
-                           : glyphset.get_population ();
-    use_class_zero = use_class_zero && glyph_count <= gid_org_klass_map.get_population ();
-    ClassDef_remap_and_serialize (c->serializer, gid_org_klass_map,
-                                 glyphs, orig_klasses, use_class_zero, klass_map);
-    return_trace (keep_empty_table || (bool) glyphs);
+                           : glyph_map.get_population ();
+    use_class_zero = use_class_zero && glyph_count <= glyph_and_klass.length;
+    if (!ClassDef_remap_and_serialize (c->serializer,
+                                       orig_klasses,
+                                       use_class_zero,
+                                       glyph_and_klass,
+                                       klass_map))
+      return_trace (false);
+    return_trace (keep_empty_table || (bool) glyph_and_klass);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -2221,13 +1882,14 @@ struct ClassDefFormat2
     return_trace (rangeRecord.sanitize (c));
   }
 
+  unsigned cost () const { return hb_bit_storage ((unsigned) rangeRecord.len); /* bsearch cost */ }
+
   template <typename set_t>
   bool collect_coverage (set_t *glyphs) const
   {
-    unsigned int count = rangeRecord.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (rangeRecord[i].value)
-       if (unlikely (!rangeRecord[i].collect_coverage (glyphs)))
+    for (auto &range : rangeRecord)
+      if (range.value)
+       if (unlikely (!range.collect_coverage (glyphs)))
          return false;
     return true;
   }
@@ -2235,11 +1897,10 @@ struct ClassDefFormat2
   template <typename set_t>
   bool collect_class (set_t *glyphs, unsigned int klass) const
   {
-    unsigned int count = rangeRecord.len;
-    for (unsigned int i = 0; i < count; i++)
+    for (auto &range : rangeRecord)
     {
-      if (rangeRecord[i].value == klass)
-       if (unlikely (!rangeRecord[i].collect_coverage (glyphs)))
+      if (range.value == klass)
+       if (unlikely (!range.collect_coverage (glyphs)))
          return false;
     }
     return true;
@@ -2247,90 +1908,95 @@ struct ClassDefFormat2
 
   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.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
     {
-      const auto& range = rangeRecord[i];
-      if (range.intersects (glyphs) && range.value)
-       return true;
+      for (auto g : *glyphs)
+        if (get_class (g))
+         return true;
+      return false;
     }
-    return false;
+
+    return hb_any (+ hb_iter (rangeRecord)
+                   | hb_map ([glyphs] (const RangeRecord<Types> &range) { return range.intersects (*glyphs) && range.value; }));
   }
   bool intersects_class (const hb_set_t *glyphs, uint16_t klass) const
   {
-    unsigned int count = rangeRecord.len;
     if (klass == 0)
     {
       /* Match if there's any glyph that is not listed! */
       hb_codepoint_t g = HB_SET_VALUE_INVALID;
-      for (unsigned int i = 0; i < count; i++)
+      hb_codepoint_t last = HB_SET_VALUE_INVALID;
+      auto it = hb_iter (rangeRecord);
+      for (auto &range : it)
       {
-       if (!hb_set_next (glyphs, &g))
+        if (it->first == last + 1)
+       {
+         it++;
+         continue;
+       }
+
+       if (!glyphs->next (&g))
          break;
-       if (g < rangeRecord[i].first)
+       if (g < range.first)
          return true;
-       g = rangeRecord[i].last;
+       g = range.last;
+       last = g;
       }
-      if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
+      if (g != HB_SET_VALUE_INVALID && glyphs->next (&g))
        return true;
       /* Fall through. */
     }
-    /* TODO Speed up, using set overlap first? */
-    /* TODO(iter) Rewrite as dagger. */
-    HBUINT16 k {klass};
-    const RangeRecord *arr = rangeRecord.arrayZ;
-    for (unsigned int i = 0; i < count; i++)
-      if (arr[i].value == k && arr[i].intersects (glyphs))
+    for (const auto &range : rangeRecord)
+      if (range.value == klass && range.intersects (*glyphs))
        return true;
     return false;
   }
 
   void intersected_class_glyphs (const hb_set_t *glyphs, unsigned klass, hb_set_t *intersect_glyphs) const
   {
-    unsigned count = rangeRecord.len;
     if (klass == 0)
     {
       hb_codepoint_t g = HB_SET_VALUE_INVALID;
-      for (unsigned int i = 0; i < count; i++)
+      for (auto &range : rangeRecord)
       {
-        if (!hb_set_next (glyphs, &g))
-          break;
-        while (g != HB_SET_VALUE_INVALID && g < rangeRecord[i].first)
-        {
-          intersect_glyphs->add (g);
-          hb_set_next (glyphs, &g);
+       if (!glyphs->next (&g))
+         goto done;
+       while (g < range.first)
+       {
+         intersect_glyphs->add (g);
+         if (!glyphs->next (&g))
+           goto done;
         }
-        g = rangeRecord[i].last;
+        g = range.last;
       }
-      while (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
-        intersect_glyphs->add (g);
+      while (glyphs->next (&g))
+       intersect_glyphs->add (g);
+      done:
 
       return;
     }
 
-    hb_codepoint_t g = HB_SET_VALUE_INVALID;
-    for (unsigned int i = 0; i < count; i++)
+    unsigned count = rangeRecord.len;
+    if (count > glyphs->get_population () * hb_bit_storage (count) * 8)
     {
-      if (rangeRecord[i].value != klass) continue;
-
-      if (g != HB_SET_VALUE_INVALID)
+      for (auto g : *glyphs)
       {
-        if (g >= rangeRecord[i].first &&
-            g <= rangeRecord[i].last)
-          intersect_glyphs->add (g);
-        if (g > rangeRecord[i].last)
-          continue;
+        unsigned i;
+        if (rangeRecord.as_array ().bfind (g, &i) &&
+           rangeRecord.arrayZ[i].value == klass)
+         intersect_glyphs->add (g);
       }
+      return;
+    }
 
-      g = rangeRecord[i].first - 1;
-      while (hb_set_next (glyphs, &g))
-      {
-        if (g >= rangeRecord[i].first && g <= rangeRecord[i].last)
-          intersect_glyphs->add (g);
-        else if (g > rangeRecord[i].last)
-          break;
-      }
+    for (auto &range : rangeRecord)
+    {
+      if (range.value != klass) continue;
+
+      unsigned end = range.last + 1;
+      for (hb_codepoint_t g = range.first - 1;
+          glyphs->next (&g) && g < end;)
+       intersect_glyphs->add (g);
     }
   }
 
@@ -2338,43 +2004,40 @@ struct ClassDefFormat2
   {
     if (glyphs->is_empty ()) return;
 
-    unsigned count = rangeRecord.len;
     hb_codepoint_t g = HB_SET_VALUE_INVALID;
-    for (unsigned int i = 0; i < count; i++)
+    for (auto &range : rangeRecord)
     {
-      if (!hb_set_next (glyphs, &g))
+      if (!glyphs->next (&g))
         break;
-      if (g < rangeRecord[i].first)
+      if (g < range.first)
       {
         intersect_classes->add (0);
         break;
       }
-      g = rangeRecord[i].last;
+      g = range.last;
     }
-    if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
+    if (g != HB_SET_VALUE_INVALID && glyphs->next (&g))
       intersect_classes->add (0);
 
-    for (const RangeRecord& record : rangeRecord.iter ())
-      if (record.intersects (glyphs))
-        intersect_classes->add (record.value);
+    for (const auto& range : rangeRecord)
+      if (range.intersects (*glyphs))
+        intersect_classes->add (range.value);
   }
 
   protected:
   HBUINT16     classFormat;    /* Format identifier--format = 2 */
-  SortedArray16Of<RangeRecord>
+  typename Types::template SortedArrayOf<RangeRecord<Types>>
                rangeRecord;    /* Array of glyph ranges--ordered by
                                 * Start GlyphID */
   public:
-  DEFINE_SIZE_ARRAY (4, rangeRecord);
+  DEFINE_SIZE_ARRAY (2 + Types::size, rangeRecord);
 };
 
 struct ClassDef
 {
   /* Has interface. */
-  static constexpr unsigned SENTINEL = 0;
-  typedef unsigned int value_t;
-  value_t operator [] (hb_codepoint_t k) const { return get (k); }
-  bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+  unsigned operator [] (hb_codepoint_t k) const { return get (k); }
+  bool has (hb_codepoint_t k) const { return (*this)[k]; }
   /* Projection. */
   hb_codepoint_t operator () (hb_codepoint_t k) const { return get (k); }
 
@@ -2384,12 +2047,29 @@ struct ClassDef
     switch (u.format) {
     case 1: return u.format1.get_class (glyph_id);
     case 2: return u.format2.get_class (glyph_id);
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.get_class (glyph_id);
+    case 4: return u.format4.get_class (glyph_id);
+#endif
     default:return 0;
     }
   }
 
+  unsigned get_population () const
+  {
+    switch (u.format) {
+    case 1: return u.format1.get_population ();
+    case 2: return u.format2.get_population ();
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.get_population ();
+    case 4: return u.format4.get_population ();
+#endif
+    default:return NOT_COVERED;
+    }
+  }
+
   template<typename Iterator,
-          hb_requires (hb_is_iterator (Iterator))>
+          hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
   bool serialize (hb_serialize_context_t *c, Iterator it_with_class_zero)
   {
     TRACE_SERIALIZE (this);
@@ -2398,10 +2078,11 @@ struct ClassDef
     auto it = + it_with_class_zero | hb_filter (hb_second);
 
     unsigned format = 2;
+    hb_codepoint_t glyph_max = 0;
     if (likely (it))
     {
       hb_codepoint_t glyph_min = (*it).first;
-      hb_codepoint_t glyph_max = glyph_min;
+      glyph_max = glyph_min;
 
       unsigned num_glyphs = 0;
       unsigned num_ranges = 1;
@@ -2426,12 +2107,29 @@ struct ClassDef
       if (num_glyphs && 1 + (glyph_max - glyph_min + 1) <= num_ranges * 3)
        format = 1;
     }
+
+#ifndef HB_NO_BEYOND_64K
+    if (glyph_max > 0xFFFFu)
+      u.format += 2;
+    if (unlikely (glyph_max > 0xFFFFFFu))
+#else
+    if (unlikely (glyph_max > 0xFFFFu))
+#endif
+    {
+      c->check_success (false, HB_SERIALIZE_ERROR_INT_OVERFLOW);
+      return_trace (false);
+    }
+
     u.format = format;
 
     switch (u.format)
     {
     case 1: return_trace (u.format1.serialize (c, it));
     case 2: return_trace (u.format2.serialize (c, it));
+#ifndef HB_NO_BEYOND_64K
+    case 3: return_trace (u.format3.serialize (c, it));
+    case 4: return_trace (u.format4.serialize (c, it));
+#endif
     default:return_trace (false);
     }
   }
@@ -2446,6 +2144,10 @@ struct ClassDef
     switch (u.format) {
     case 1: return_trace (u.format1.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter));
     case 2: return_trace (u.format2.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter));
+#ifndef HB_NO_BEYOND_64K
+    case 3: return_trace (u.format3.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter));
+    case 4: return_trace (u.format4.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter));
+#endif
     default:return_trace (false);
     }
   }
@@ -2457,10 +2159,27 @@ struct ClassDef
     switch (u.format) {
     case 1: return_trace (u.format1.sanitize (c));
     case 2: return_trace (u.format2.sanitize (c));
+#ifndef HB_NO_BEYOND_64K
+    case 3: return_trace (u.format3.sanitize (c));
+    case 4: return_trace (u.format4.sanitize (c));
+#endif
     default:return_trace (true);
     }
   }
 
+  unsigned cost () const
+  {
+    switch (u.format) {
+    case 1: return u.format1.cost ();
+    case 2: return u.format2.cost ();
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.cost ();
+    case 4: return u.format4.cost ();
+#endif
+    default:return 0u;
+    }
+  }
+
   /* Might return false if array looks unsorted.
    * Used for faster rejection of corrupt data. */
   template <typename set_t>
@@ -2469,6 +2188,10 @@ struct ClassDef
     switch (u.format) {
     case 1: return u.format1.collect_coverage (glyphs);
     case 2: return u.format2.collect_coverage (glyphs);
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.collect_coverage (glyphs);
+    case 4: return u.format4.collect_coverage (glyphs);
+#endif
     default:return false;
     }
   }
@@ -2481,6 +2204,10 @@ struct ClassDef
     switch (u.format) {
     case 1: return u.format1.collect_class (glyphs, klass);
     case 2: return u.format2.collect_class (glyphs, klass);
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.collect_class (glyphs, klass);
+    case 4: return u.format4.collect_class (glyphs, klass);
+#endif
     default:return false;
     }
   }
@@ -2490,6 +2217,10 @@ struct ClassDef
     switch (u.format) {
     case 1: return u.format1.intersects (glyphs);
     case 2: return u.format2.intersects (glyphs);
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.intersects (glyphs);
+    case 4: return u.format4.intersects (glyphs);
+#endif
     default:return false;
     }
   }
@@ -2498,6 +2229,10 @@ struct ClassDef
     switch (u.format) {
     case 1: return u.format1.intersects_class (glyphs, klass);
     case 2: return u.format2.intersects_class (glyphs, klass);
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.intersects_class (glyphs, klass);
+    case 4: return u.format4.intersects_class (glyphs, klass);
+#endif
     default:return false;
     }
   }
@@ -2507,6 +2242,10 @@ struct ClassDef
     switch (u.format) {
     case 1: return u.format1.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
     case 2: return u.format2.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
+    case 4: return u.format4.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
+#endif
     default:return;
     }
   }
@@ -2516,6 +2255,10 @@ struct ClassDef
     switch (u.format) {
     case 1: return u.format1.intersected_classes (glyphs, intersect_classes);
     case 2: return u.format2.intersected_classes (glyphs, intersect_classes);
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.intersected_classes (glyphs, intersect_classes);
+    case 4: return u.format4.intersected_classes (glyphs, intersect_classes);
+#endif
     default:return;
     }
   }
@@ -2523,41 +2266,198 @@ struct ClassDef
 
   protected:
   union {
-  HBUINT16             format;         /* Format identifier */
-  ClassDefFormat1      format1;
-  ClassDefFormat2      format2;
+  HBUINT16                     format;         /* Format identifier */
+  ClassDefFormat1_3<SmallTypes>        format1;
+  ClassDefFormat2_4<SmallTypes>        format2;
+#ifndef HB_NO_BEYOND_64K
+  ClassDefFormat1_3<MediumTypes>format3;
+  ClassDefFormat2_4<MediumTypes>format4;
+#endif
   } u;
   public:
   DEFINE_SIZE_UNION (2, format);
 };
 
 template<typename Iterator>
-static inline void ClassDef_serialize (hb_serialize_context_t *c,
+static inline bool ClassDef_serialize (hb_serialize_context_t *c,
                                       Iterator it)
-{ c->start_embed<ClassDef> ()->serialize (c, it); }
+{ return (c->start_embed<ClassDef> ()->serialize (c, it)); }
 
 
 /*
  * Item Variation Store
  */
 
+/* ported from fonttools (class _Encoding) */
+struct delta_row_encoding_t
+{
+  /* each byte represents a region, value is one of 0/1/2/4, which means bytes
+   * needed for this region */
+  hb_vector_t<uint8_t> chars;
+  unsigned width = 0;
+  hb_vector_t<uint8_t> columns;
+  unsigned overhead = 0;
+  hb_vector_t<const hb_vector_t<int>*> items;
+
+  delta_row_encoding_t () = default;
+  delta_row_encoding_t (hb_vector_t<uint8_t>&& chars_,
+                        const hb_vector_t<int>* row = nullptr) :
+                        delta_row_encoding_t ()
+
+  {
+    chars = std::move (chars_);
+    width = get_width ();
+    columns = get_columns ();
+    overhead = get_chars_overhead (columns);
+    if (row) items.push (row);
+  }
+
+  bool is_empty () const
+  { return !items; }
+
+  static hb_vector_t<uint8_t> get_row_chars (const hb_vector_t<int>& row)
+  {
+    hb_vector_t<uint8_t> ret;
+    if (!ret.alloc (row.length)) return ret;
+
+    bool long_words = false;
+
+    /* 0/1/2 byte encoding */
+    for (int i = row.length - 1; i >= 0; i--)
+    {
+      int v =  row.arrayZ[i];
+      if (v == 0)
+        ret.push (0);
+      else if (v > 32767 || v < -32768)
+      {
+        long_words = true;
+        break;
+      }
+      else if (v > 127 || v < -128)
+        ret.push (2);
+      else
+        ret.push (1);
+    }
+
+    if (!long_words)
+      return ret;
+
+    /* redo, 0/2/4 bytes encoding */
+    ret.reset ();
+    for (int i = row.length - 1; i >= 0; i--)
+    {
+      int v =  row.arrayZ[i];
+      if (v == 0)
+        ret.push (0);
+      else if (v > 32767 || v < -32768)
+        ret.push (4);
+      else
+        ret.push (2);
+    }
+    return ret;
+  }
+
+  inline unsigned get_width ()
+  {
+    unsigned ret = + hb_iter (chars)
+                   | hb_reduce (hb_add, 0u)
+                   ;
+    return ret;
+  }
+
+  hb_vector_t<uint8_t> get_columns ()
+  {
+    hb_vector_t<uint8_t> cols;
+    cols.alloc (chars.length);
+    for (auto v : chars)
+    {
+      uint8_t flag = v ? 1 : 0;
+      cols.push (flag);
+    }
+    return cols;
+  }
+
+  static inline unsigned get_chars_overhead (const hb_vector_t<uint8_t>& cols)
+  {
+    unsigned c = 4 + 6; // 4 bytes for LOffset, 6 bytes for VarData header
+    unsigned cols_bit_count = 0;
+    for (auto v : cols)
+      if (v) cols_bit_count++;
+    return c + cols_bit_count * 2;
+  }
+
+  unsigned get_gain () const
+  {
+    int count = items.length;
+    return hb_max (0, (int) overhead - count);
+  }
+
+  int gain_from_merging (const delta_row_encoding_t& other_encoding) const
+  {
+    int combined_width = 0;
+    for (unsigned i = 0; i < chars.length; i++)
+      combined_width += hb_max (chars.arrayZ[i], other_encoding.chars.arrayZ[i]);
+   
+    hb_vector_t<uint8_t> combined_columns;
+    combined_columns.alloc (columns.length);
+    for (unsigned i = 0; i < columns.length; i++)
+      combined_columns.push (columns.arrayZ[i] | other_encoding.columns.arrayZ[i]);
+    
+    int combined_overhead = get_chars_overhead (combined_columns);
+    int combined_gain = (int) overhead + (int) other_encoding.overhead - combined_overhead
+                        - (combined_width - (int) width) * items.length
+                        - (combined_width - (int) other_encoding.width) * other_encoding.items.length;
+
+    return combined_gain;
+  }
+
+  static int cmp (const void *pa, const void *pb)
+  {
+    const delta_row_encoding_t *a = (const delta_row_encoding_t *)pa;
+    const delta_row_encoding_t *b = (const delta_row_encoding_t *)pb;
+
+    int gain_a = a->get_gain ();
+    int gain_b = b->get_gain ();
+
+    if (gain_a != gain_b)
+      return gain_a - gain_b;
+
+    return (b->chars).as_array ().cmp ((a->chars).as_array ());
+  }
+
+  static int cmp_width (const void *pa, const void *pb)
+  {
+    const delta_row_encoding_t *a = (const delta_row_encoding_t *)pa;
+    const delta_row_encoding_t *b = (const delta_row_encoding_t *)pb;
+
+    if (a->width != b->width)
+      return (int) a->width - (int) b->width;
+
+    return (b->chars).as_array ().cmp ((a->chars).as_array ());
+  }
+
+  bool add_row (const hb_vector_t<int>* row)
+  { return items.push (row); }
+};
+
 struct VarRegionAxis
 {
   float evaluate (int coord) const
   {
-    int start = startCoord, peak = peakCoord, end = endCoord;
+    int peak = peakCoord.to_int ();
+    if (peak == 0 || coord == peak)
+      return 1.f;
+
+    int start = startCoord.to_int (), end = endCoord.to_int ();
 
     /* TODO Move these to sanitize(). */
     if (unlikely (start > peak || peak > end))
-      return 1.;
+      return 1.f;
     if (unlikely (start < 0 && end > 0 && peak != 0))
-      return 1.;
-
-    if (peak == 0 || coord == peak)
-      return 1.;
+      return 1.f;
 
     if (coord <= start || end <= coord)
-      return 0.;
+      return 0.f;
 
     /* Interpolate */
     if (coord < peak)
@@ -2574,6 +2474,12 @@ struct VarRegionAxis
      * have to do that at runtime. */
   }
 
+  bool serialize (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (c->embed (this));
+  }
+
   public:
   F2DOT14      startCoord;
   F2DOT14      peakCoord;
@@ -2582,14 +2488,27 @@ struct VarRegionAxis
   DEFINE_SIZE_STATIC (6);
 };
 
+#define REGION_CACHE_ITEM_CACHE_INVALID 2.f
+
 struct VarRegionList
 {
+  using cache_t = float;
+
   float evaluate (unsigned int region_index,
-                 const int *coords, unsigned int coord_len) const
+                 const int *coords, unsigned int coord_len,
+                 cache_t *cache = nullptr) const
   {
     if (unlikely (region_index >= regionCount))
       return 0.;
 
+    float *cached_value = nullptr;
+    if (cache)
+    {
+      cached_value = &(cache[region_index]);
+      if (likely (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID))
+       return *cached_value;
+    }
+
     const VarRegionAxis *axes = axesZ.arrayZ + (region_index * axisCount);
 
     float v = 1.;
@@ -2599,9 +2518,16 @@ struct VarRegionList
       int coord = i < coord_len ? coords[i] : 0;
       float factor = axes[i].evaluate (coord);
       if (factor == 0.f)
+      {
+        if (cache)
+         *cached_value = 0.;
        return 0.;
+      }
       v *= factor;
     }
+
+    if (cache)
+      *cached_value = v;
     return v;
   }
 
@@ -2611,7 +2537,48 @@ struct VarRegionList
     return_trace (c->check_struct (this) && axesZ.sanitize (c, axisCount * regionCount));
   }
 
-  bool serialize (hb_serialize_context_t *c, const VarRegionList *src, const hb_bimap_t &region_map)
+  bool serialize (hb_serialize_context_t *c,
+                  const hb_vector_t<hb_tag_t>& axis_tags,
+                  const hb_vector_t<const hb_hashmap_t<hb_tag_t, Triple>*>& regions)
+  {
+    TRACE_SERIALIZE (this);
+    unsigned axis_count = axis_tags.length;
+    unsigned region_count = regions.length;
+    if (!axis_count || !region_count) return_trace (false);
+    if (unlikely (hb_unsigned_mul_overflows (axis_count * region_count,
+                                             VarRegionAxis::static_size))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    axisCount = axis_count;
+    regionCount = region_count;
+
+    for (unsigned r = 0; r < region_count; r++)
+    {
+      const auto& region = regions[r];
+      for (unsigned i = 0; i < axis_count; i++)
+      {
+        hb_tag_t tag = axis_tags.arrayZ[i];
+        VarRegionAxis var_region_rec;
+        Triple *coords;
+        if (region->has (tag, &coords))
+        {
+          var_region_rec.startCoord.set_float (coords->minimum);
+          var_region_rec.peakCoord.set_float (coords->middle);
+          var_region_rec.endCoord.set_float (coords->maximum);
+        }
+        else
+        {
+          var_region_rec.startCoord.set_int (0);
+          var_region_rec.peakCoord.set_int (0);
+          var_region_rec.endCoord.set_int (0);
+        }
+        if (!var_region_rec.serialize (c))
+          return_trace (false);
+      }
+    }
+    return_trace (true);
+  }
+
+  bool serialize (hb_serialize_context_t *c, const VarRegionList *src, const hb_inc_bimap_t &region_map)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (this))) return_trace (false);
@@ -2625,12 +2592,51 @@ struct VarRegionList
     {
       unsigned int backward = region_map.backward (r);
       if (backward >= region_count) return_trace (false);
-      memcpy (&axesZ[axisCount * r], &src->axesZ[axisCount * backward], VarRegionAxis::static_size * axisCount);
+      hb_memcpy (&axesZ[axisCount * r], &src->axesZ[axisCount * backward], VarRegionAxis::static_size * axisCount);
     }
 
     return_trace (true);
   }
 
+  bool get_var_region (unsigned region_index,
+                       const hb_map_t& axes_old_index_tag_map,
+                       hb_hashmap_t<hb_tag_t, Triple>& axis_tuples /* OUT */) const
+  {
+    if (region_index >= regionCount) return false;
+    const VarRegionAxis* axis_region = axesZ.arrayZ + (region_index * axisCount);
+    for (unsigned i = 0; i < axisCount; i++)
+    {
+      hb_tag_t *axis_tag;
+      if (!axes_old_index_tag_map.has (i, &axis_tag))
+        return false;
+
+      float min_val = axis_region->startCoord.to_float ();
+      float def_val = axis_region->peakCoord.to_float ();
+      float max_val = axis_region->endCoord.to_float ();
+
+      if (def_val != 0.f)
+        axis_tuples.set (*axis_tag, Triple (min_val, def_val, max_val));
+      axis_region++;
+    }
+    return !axis_tuples.in_error ();
+  }
+
+  bool get_var_regions (const hb_map_t& axes_old_index_tag_map,
+                        hb_vector_t<hb_hashmap_t<hb_tag_t, Triple>>& regions /* OUT */) const
+  {
+    if (!regions.alloc (regionCount))
+      return false;
+
+    for (unsigned i = 0; i < regionCount; i++)
+    {
+      hb_hashmap_t<hb_tag_t, Triple> axis_tuples;
+      if (!get_var_region (i, axes_old_index_tag_map, axis_tuples))
+        return false;
+      regions.push (std::move (axis_tuples));
+    }
+    return !regions.in_error ();
+  }
+
   unsigned int get_size () const { return min_size + VarRegionAxis::static_size * axisCount * regionCount; }
 
   public:
@@ -2645,11 +2651,17 @@ struct VarRegionList
 
 struct VarData
 {
+  unsigned int get_item_count () const
+  { return itemCount; }
+
   unsigned int get_region_index_count () const
   { return regionIndices.len; }
+  
+  unsigned get_region_index (unsigned i) const
+  { return i >= regionIndices.len ? -1 : regionIndices[i]; }
 
   unsigned int get_row_size () const
-  { return shortCount + regionIndices.len; }
+  { return (wordCount () + regionIndices.len) * (longWords () ? 2 : 1); }
 
   unsigned int get_size () const
   { return min_size
@@ -2659,30 +2671,40 @@ struct VarData
 
   float get_delta (unsigned int inner,
                   const int *coords, unsigned int coord_count,
-                  const VarRegionList &regions) const
+                  const VarRegionList &regions,
+                  VarRegionList::cache_t *cache = nullptr) const
   {
     if (unlikely (inner >= itemCount))
       return 0.;
 
    unsigned int count = regionIndices.len;
-   unsigned int scount = shortCount;
+   bool is_long = longWords ();
+   unsigned word_count = wordCount ();
+   unsigned int scount = is_long ? count : word_count;
+   unsigned int lcount = is_long ? word_count : 0;
 
    const HBUINT8 *bytes = get_delta_bytes ();
-   const HBUINT8 *row = bytes + inner * (scount + count);
+   const HBUINT8 *row = bytes + inner * get_row_size ();
 
    float delta = 0.;
    unsigned int i = 0;
 
-   const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (row);
+   const HBINT32 *lcursor = reinterpret_cast<const HBINT32 *> (row);
+   for (; i < lcount; i++)
+   {
+     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache);
+     delta += scalar * *lcursor++;
+   }
+   const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (lcursor);
    for (; i < scount; i++)
    {
-     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
+     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache);
      delta += scalar * *scursor++;
    }
    const HBINT8 *bcursor = reinterpret_cast<const HBINT8 *> (scursor);
    for (; i < count; i++)
    {
-     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
+     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache);
      delta += scalar * *bcursor++;
    }
 
@@ -2706,70 +2728,184 @@ struct VarData
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
                  regionIndices.sanitize (c) &&
-                 shortCount <= regionIndices.len &&
+                 wordCount () <= regionIndices.len &&
                  c->check_range (get_delta_bytes (),
                                  itemCount,
                                  get_row_size ()));
   }
 
   bool serialize (hb_serialize_context_t *c,
+                  bool has_long,
+                  const hb_vector_t<const hb_vector_t<int>*>& rows)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    unsigned row_count = rows.length;
+    itemCount = row_count;
+
+    int min_threshold = has_long ? -65536 : -128;
+    int max_threshold = has_long ? +65535 : +127;
+    enum delta_size_t { kZero=0, kNonWord, kWord };
+    hb_vector_t<delta_size_t> delta_sz;
+    unsigned num_regions = rows[0]->length;
+    if (!delta_sz.resize (num_regions))
+      return_trace (false);
+
+    unsigned word_count = 0;
+    for (unsigned r = 0; r < num_regions; r++)
+    {
+      for (unsigned i = 0; i < row_count; i++)
+      {
+        int delta = rows[i]->arrayZ[r];
+        if (delta < min_threshold || delta > max_threshold)
+        {
+          delta_sz[r] = kWord;
+          word_count++;
+          break;
+        }
+        else if (delta != 0)
+        {
+          delta_sz[r] = kNonWord;
+        }
+      }
+    }
+
+    /* reorder regions: words and then non-words*/
+    unsigned word_index = 0;
+    unsigned non_word_index = word_count;
+    hb_map_t ri_map;
+    for (unsigned r = 0; r < num_regions; r++)
+    {
+      if (!delta_sz[r]) continue;
+      unsigned new_r = (delta_sz[r] == kWord)? word_index++ : non_word_index++;
+      if (!ri_map.set (new_r, r))
+        return_trace (false);
+    }
+
+    wordSizeCount = word_count | (has_long ? 0x8000u /* LONG_WORDS */ : 0);
+
+    unsigned ri_count = ri_map.get_population ();
+    regionIndices.len = ri_count;
+    if (unlikely (!c->extend (this))) return_trace (false);
+
+    for (unsigned r = 0; r < ri_count; r++)
+    {
+      hb_codepoint_t *idx;
+      if (!ri_map.has (r, &idx))
+        return_trace (false);
+      regionIndices[r] = *idx;
+    }
+
+    HBUINT8 *delta_bytes = get_delta_bytes ();
+    unsigned row_size = get_row_size ();
+    for (unsigned int i = 0; i < row_count; i++)
+    {
+      for (unsigned int r = 0; r < ri_count; r++)
+      {
+        int delta = rows[i]->arrayZ[ri_map[r]];
+        set_item_delta_fast (i, r, delta, delta_bytes, row_size);
+      }
+    }
+    return_trace (true);
+  }
+
+  bool serialize (hb_serialize_context_t *c,
                  const VarData *src,
                  const hb_inc_bimap_t &inner_map,
-                 const hb_bimap_t &region_map)
+                 const hb_inc_bimap_t &region_map)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (this))) return_trace (false);
     itemCount = inner_map.get_next_value ();
 
-    /* Optimize short count */
-    unsigned short ri_count = src->regionIndices.len;
-    enum delta_size_t { kZero=0, kByte, kShort };
+    /* Optimize word count */
+    unsigned ri_count = src->regionIndices.len;
+    enum delta_size_t { kZero=0, kNonWord, kWord };
     hb_vector_t<delta_size_t> delta_sz;
-    hb_vector_t<unsigned int> ri_map;  /* maps old index to new index */
+    hb_vector_t<unsigned int> ri_map;  /* maps new index to old index */
     delta_sz.resize (ri_count);
     ri_map.resize (ri_count);
-    unsigned int new_short_count = 0;
+    unsigned int new_word_count = 0;
     unsigned int r;
+
+    const HBUINT8 *src_delta_bytes = src->get_delta_bytes ();
+    unsigned src_row_size = src->get_row_size ();
+    unsigned src_word_count = src->wordCount ();
+    bool     src_long_words = src->longWords ();
+
+    bool has_long = false;
+    if (src_long_words)
+    {
+      for (r = 0; r < src_word_count; r++)
+      {
+        for (unsigned old_gid : inner_map.keys())
+       {
+         int32_t delta = src->get_item_delta_fast (old_gid, r, src_delta_bytes, src_row_size);
+         if (delta < -65536 || 65535 < delta)
+         {
+           has_long = true;
+           break;
+         }
+        }
+      }
+    }
+
+    signed min_threshold = has_long ? -65536 : -128;
+    signed max_threshold = has_long ? +65535 : +127;
     for (r = 0; r < ri_count; r++)
     {
+      bool short_circuit = src_long_words == has_long && src_word_count <= r;
+
       delta_sz[r] = kZero;
-      for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
+      for (unsigned old_gid : inner_map.keys())
       {
-       unsigned int old = inner_map.backward (i);
-       int16_t delta = src->get_item_delta (old, r);
-       if (delta < -128 || 127 < delta)
+       int32_t delta = src->get_item_delta_fast (old_gid, r, src_delta_bytes, src_row_size);
+       if (delta < min_threshold || max_threshold < delta)
        {
-         delta_sz[r] = kShort;
-         new_short_count++;
+         delta_sz[r] = kWord;
+         new_word_count++;
          break;
        }
        else if (delta != 0)
-         delta_sz[r] = kByte;
+       {
+         delta_sz[r] = kNonWord;
+         if (short_circuit)
+           break;
+       }
       }
     }
-    unsigned int short_index = 0;
-    unsigned int byte_index = new_short_count;
+
+    unsigned int word_index = 0;
+    unsigned int non_word_index = new_word_count;
     unsigned int new_ri_count = 0;
     for (r = 0; r < ri_count; r++)
       if (delta_sz[r])
       {
-       ri_map[r] = (delta_sz[r] == kShort)? short_index++ : byte_index++;
+       unsigned new_r = (delta_sz[r] == kWord)? word_index++ : non_word_index++;
+       ri_map[new_r] = r;
        new_ri_count++;
       }
 
-    shortCount = new_short_count;
+    wordSizeCount = new_word_count | (has_long ? 0x8000u /* LONG_WORDS */ : 0);
+
     regionIndices.len = new_ri_count;
 
     if (unlikely (!c->extend (this))) return_trace (false);
 
-    for (r = 0; r < ri_count; r++)
-      if (delta_sz[r]) regionIndices[ri_map[r]] = region_map[src->regionIndices[r]];
+    for (r = 0; r < new_ri_count; r++)
+      regionIndices[r] = region_map[src->regionIndices[ri_map[r]]];
 
-    for (unsigned int i = 0; i < itemCount; i++)
+    HBUINT8 *delta_bytes = get_delta_bytes ();
+    unsigned row_size = get_row_size ();
+    unsigned count = itemCount;
+    for (unsigned int i = 0; i < count; i++)
     {
-      unsigned int     old = inner_map.backward (i);
-      for (unsigned int r = 0; r < ri_count; r++)
-       if (delta_sz[r]) set_item_delta (i, ri_map[r], src->get_item_delta (old, r));
+      unsigned int old = inner_map.backward (i);
+      for (unsigned int r = 0; r < new_ri_count; r++)
+       set_item_delta_fast (i, r,
+                            src->get_item_delta_fast (old, ri_map[r],
+                                                      src_delta_bytes, src_row_size),
+                            delta_bytes, row_size);
     }
 
     return_trace (true);
@@ -2777,12 +2913,15 @@ struct VarData
 
   void collect_region_refs (hb_set_t &region_indices, const hb_inc_bimap_t &inner_map) const
   {
+    const HBUINT8 *delta_bytes = get_delta_bytes ();
+    unsigned row_size = get_row_size ();
+
     for (unsigned int r = 0; r < regionIndices.len; r++)
     {
-      unsigned int region = regionIndices[r];
+      unsigned int region = regionIndices.arrayZ[r];
       if (region_indices.has (region)) continue;
-      for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
-       if (get_item_delta (inner_map.backward (i), r) != 0)
+      for (hb_codepoint_t old_gid : inner_map.keys())
+       if (get_item_delta_fast (old_gid, r, delta_bytes, row_size) != 0)
        {
          region_indices.add (region);
          break;
@@ -2790,35 +2929,80 @@ struct VarData
     }
   }
 
-  protected:
+  public:
   const HBUINT8 *get_delta_bytes () const
   { return &StructAfter<HBUINT8> (regionIndices); }
 
+  protected:
   HBUINT8 *get_delta_bytes ()
   { return &StructAfter<HBUINT8> (regionIndices); }
 
-  int16_t get_item_delta (unsigned int item, unsigned int region) const
+  public:
+  int32_t get_item_delta_fast (unsigned int item, unsigned int region,
+                              const HBUINT8 *delta_bytes, unsigned row_size) const
   {
-    if ( item >= itemCount || unlikely (region >= regionIndices.len)) return 0;
-    const HBINT8 *p = (const HBINT8 *)get_delta_bytes () + item * get_row_size ();
-    if (region < shortCount)
-      return ((const HBINT16 *)p)[region];
+    if (unlikely (item >= itemCount || region >= regionIndices.len)) return 0;
+
+    const HBINT8 *p = (const HBINT8 *) delta_bytes + item * row_size;
+    unsigned word_count = wordCount ();
+    bool is_long = longWords ();
+    if (is_long)
+    {
+      if (region < word_count)
+       return ((const HBINT32 *) p)[region];
+      else
+       return ((const HBINT16 *)(p + HBINT32::static_size * word_count))[region - word_count];
+    }
     else
-      return (p + HBINT16::static_size * shortCount)[region - shortCount];
+    {
+      if (region < word_count)
+       return ((const HBINT16 *) p)[region];
+      else
+       return (p + HBINT16::static_size * word_count)[region - word_count];
+    }
+  }
+  int32_t get_item_delta (unsigned int item, unsigned int region) const
+  {
+     return get_item_delta_fast (item, region,
+                                get_delta_bytes (),
+                                get_row_size ());
   }
 
-  void set_item_delta (unsigned int item, unsigned int region, int16_t delta)
+  protected:
+  void set_item_delta_fast (unsigned int item, unsigned int region, int32_t delta,
+                           HBUINT8 *delta_bytes, unsigned row_size)
   {
-    HBINT8 *p = (HBINT8 *)get_delta_bytes () + item * get_row_size ();
-    if (region < shortCount)
-      ((HBINT16 *)p)[region] = delta;
+    HBINT8 *p = (HBINT8 *) delta_bytes + item * row_size;
+    unsigned word_count = wordCount ();
+    bool is_long = longWords ();
+    if (is_long)
+    {
+      if (region < word_count)
+       ((HBINT32 *) p)[region] = delta;
+      else
+       ((HBINT16 *)(p + HBINT32::static_size * word_count))[region - word_count] = delta;
+    }
     else
-      (p + HBINT16::static_size * shortCount)[region - shortCount] = delta;
+    {
+      if (region < word_count)
+       ((HBINT16 *) p)[region] = delta;
+      else
+       (p + HBINT16::static_size * word_count)[region - word_count] = delta;
+    }
+  }
+  void set_item_delta (unsigned int item, unsigned int region, int32_t delta)
+  {
+    set_item_delta_fast (item, region, delta,
+                        get_delta_bytes (),
+                        get_row_size ());
   }
 
+  bool longWords () const { return wordSizeCount & 0x8000u /* LONG_WORDS */; }
+  unsigned wordCount () const { return wordSizeCount & 0x7FFFu /* WORD_DELTA_COUNT_MASK */; }
+
   protected:
   HBUINT16             itemCount;
-  HBUINT16             shortCount;
+  HBUINT16             wordSizeCount;
   Array16Of<HBUINT16>  regionIndices;
 /*UnsizedArrayOf<HBUINT8>bytesX;*/
   public:
@@ -2827,9 +3011,32 @@ struct VarData
 
 struct VariationStore
 {
+  friend struct item_variations_t;
+  using cache_t = VarRegionList::cache_t;
+
+  cache_t *create_cache () const
+  {
+#ifdef HB_NO_VAR
+    return nullptr;
+#endif
+    auto &r = this+regions;
+    unsigned count = r.regionCount;
+
+    float *cache = (float *) hb_malloc (sizeof (float) * count);
+    if (unlikely (!cache)) return nullptr;
+
+    for (unsigned i = 0; i < count; i++)
+      cache[i] = REGION_CACHE_ITEM_CACHE_INVALID;
+
+    return cache;
+  }
+
+  static void destroy_cache (cache_t *cache) { hb_free (cache); }
+
   private:
   float get_delta (unsigned int outer, unsigned int inner,
-                  const int *coords, unsigned int coord_count) const
+                  const int *coords, unsigned int coord_count,
+                  VarRegionList::cache_t *cache = nullptr) const
   {
 #ifdef HB_NO_VAR
     return 0.f;
@@ -2840,16 +3047,26 @@ struct VariationStore
 
     return (this+dataSets[outer]).get_delta (inner,
                                             coords, coord_count,
-                                            this+regions);
+                                            this+regions,
+                                            cache);
   }
 
   public:
   float get_delta (unsigned int index,
-                  const int *coords, unsigned int coord_count) const
+                  const int *coords, unsigned int coord_count,
+                  VarRegionList::cache_t *cache = nullptr) const
   {
     unsigned int outer = index >> 16;
     unsigned int inner = index & 0xFFFF;
-    return get_delta (outer, inner, coords, coord_count);
+    return get_delta (outer, inner, coords, coord_count, cache);
+  }
+  float get_delta (unsigned int index,
+                  hb_array_t<int> coords,
+                  VarRegionList::cache_t *cache = nullptr) const
+  {
+    return get_delta (index,
+                     coords.arrayZ, coords.length,
+                     cache);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -2866,10 +3083,44 @@ struct VariationStore
   }
 
   bool serialize (hb_serialize_context_t *c,
+                  bool has_long,
+                  const hb_vector_t<hb_tag_t>& axis_tags,
+                  const hb_vector_t<const hb_hashmap_t<hb_tag_t, Triple>*>& region_list,
+                  const hb_vector_t<delta_row_encoding_t>& vardata_encodings)
+  {
+    TRACE_SERIALIZE (this);
+#ifdef HB_NO_VAR
+    return_trace (false);
+#endif
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    
+    format = 1;
+    if (!regions.serialize_serialize (c, axis_tags, region_list))
+      return_trace (false);
+
+    unsigned num_var_data = vardata_encodings.length;
+    if (!num_var_data) return_trace (false);
+    if (unlikely (!c->check_assign (dataSets.len, num_var_data,
+                                    HB_SERIALIZE_ERROR_INT_OVERFLOW)))
+      return_trace (false);
+
+    if (unlikely (!c->extend (dataSets))) return_trace (false);
+    for (unsigned i = 0; i < num_var_data; i++)
+      if (!dataSets[i].serialize_serialize (c, has_long, vardata_encodings[i].items))
+        return_trace (false);
+    
+    return_trace (true);
+  }
+
+  bool serialize (hb_serialize_context_t *c,
                  const VariationStore *src,
-                 const hb_array_t <hb_inc_bimap_t> &inner_maps)
+                 const hb_array_t <const hb_inc_bimap_t> &inner_maps)
   {
     TRACE_SERIALIZE (this);
+#ifdef HB_NO_VAR
+    return_trace (false);
+#endif
+
     if (unlikely (!c->extend_min (this))) return_trace (false);
 
     unsigned int set_count = 0;
@@ -2918,29 +3169,40 @@ struct VariationStore
     return_trace (true);
   }
 
-  bool subset (hb_subset_context_t *c) const
+  VariationStore *copy (hb_serialize_context_t *c) const
   {
-    TRACE_SUBSET (this);
+    TRACE_SERIALIZE (this);
+    auto *out = c->start_embed (this);
+    if (unlikely (!out)) return_trace (nullptr);
 
-    VariationStore *varstore_prime = c->serializer->start_embed<VariationStore> ();
-    if (unlikely (!varstore_prime)) return_trace (false);
+    hb_vector_t <hb_inc_bimap_t> inner_maps;
+    unsigned count = dataSets.len;
+    for (unsigned i = 0; i < count; i++)
+    {
+      hb_inc_bimap_t *map = inner_maps.push ();
+      auto &data = this+dataSets[i];
 
-    const hb_set_t *variation_indices = c->plan->layout_variation_indices;
-    if (variation_indices->is_empty ()) return_trace (false);
+      unsigned itemCount = data.get_item_count ();
+      for (unsigned j = 0; j < itemCount; j++)
+       map->add (j);
+    }
 
-    hb_vector_t<hb_inc_bimap_t> inner_maps;
-    inner_maps.resize ((unsigned) dataSets.len);
+    if (unlikely (!out->serialize (c, this, inner_maps))) return_trace (nullptr);
 
-    for (unsigned idx : c->plan->layout_variation_indices->iter ())
-    {
-      uint16_t major = idx >> 16;
-      uint16_t minor = idx & 0xFFFF;
+    return_trace (out);
+  }
 
-      if (major >= inner_maps.length)
-       return_trace (false);
-      inner_maps[major].add (minor);
-    }
-    varstore_prime->serialize (c->serializer, this, inner_maps.as_array ());
+  bool subset (hb_subset_context_t *c, const hb_array_t<const hb_inc_bimap_t> &inner_maps) const
+  {
+    TRACE_SUBSET (this);
+#ifdef HB_NO_VAR
+    return_trace (false);
+#endif
+
+    VariationStore *varstore_prime = c->serializer->start_embed<VariationStore> ();
+    if (unlikely (!varstore_prime)) return_trace (false);
+
+    varstore_prime->serialize (c->serializer, this, inner_maps);
 
     return_trace (
         !c->serializer->in_error()
@@ -2948,7 +3210,12 @@ struct VariationStore
   }
 
   unsigned int get_region_index_count (unsigned int major) const
-  { return (this+dataSets[major]).get_region_index_count (); }
+  {
+#ifdef HB_NO_VAR
+    return 0;
+#endif
+    return (this+dataSets[major]).get_region_index_count ();
+  }
 
   void get_region_scalars (unsigned int major,
                           const int *coords, unsigned int coord_count,
@@ -2966,7 +3233,29 @@ struct VariationStore
                                               &scalars[0], num_scalars);
   }
 
-  unsigned int get_sub_table_count () const { return dataSets.len; }
+  unsigned int get_sub_table_count () const
+   {
+#ifdef HB_NO_VAR
+     return 0;
+#endif
+     return dataSets.len;
+   }
+
+  const VarData& get_sub_table (unsigned i) const
+  {
+#ifdef HB_NO_VAR
+     return Null (VarData);
+#endif
+     return this+dataSets[i];
+  }
+
+  const VarRegionList& get_region_list () const
+  {
+#ifdef HB_NO_VAR
+     return Null (VarRegionList);
+#endif
+     return this+regions;
+  }
 
   protected:
   HBUINT16                             format;
@@ -2976,9 +3265,18 @@ struct VariationStore
   DEFINE_SIZE_ARRAY_SIZED (8, dataSets);
 };
 
+#undef REGION_CACHE_ITEM_CACHE_INVALID
+
 /*
  * Feature Variations
  */
+enum Cond_with_Var_flag_t
+{
+  KEEP_COND_WITH_VAR = 0,
+  KEEP_RECORD_WITH_VAR = 1,
+  DROP_COND_WITH_VAR = 2,
+  DROP_RECORD_WITH_VAR = 3,
+};
 
 struct ConditionFormat1
 {
@@ -2989,14 +3287,92 @@ struct ConditionFormat1
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
-    return_trace (true);
+
+    const hb_map_t *index_map = &c->plan->axes_index_map;
+    if (index_map->is_empty ()) return_trace (true);
+
+    const hb_map_t& axes_old_index_tag_map = c->plan->axes_old_index_tag_map;
+    hb_codepoint_t *axis_tag;
+    if (!axes_old_index_tag_map.has (axisIndex, &axis_tag) ||
+        !index_map->has (axisIndex))
+      return_trace (false);
+
+    const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location = c->plan->axes_location;
+    Triple axis_limit{-1.f, 0.f, 1.f};
+    Triple *normalized_limit;
+    if (normalized_axes_location.has (*axis_tag, &normalized_limit))
+      axis_limit = *normalized_limit;
+
+    const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances = c->plan->axes_triple_distances;
+    TripleDistances axis_triple_distances{1.f, 1.f};
+    TripleDistances *triple_dists;
+    if (axes_triple_distances.has (*axis_tag, &triple_dists))
+      axis_triple_distances = *triple_dists;
+
+    float normalized_min = renormalizeValue (filterRangeMinValue.to_float (), axis_limit, axis_triple_distances, false);
+    float normalized_max = renormalizeValue (filterRangeMaxValue.to_float (), axis_limit, axis_triple_distances, false);
+    out->filterRangeMinValue.set_float (normalized_min);
+    out->filterRangeMaxValue.set_float (normalized_max);
+
+    return_trace (c->serializer->check_assign (out->axisIndex, index_map->get (axisIndex),
+                                               HB_SERIALIZE_ERROR_INT_OVERFLOW));
   }
 
   private:
+  Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
+                                             hb_map_t *condition_map /* OUT */) const
+  {
+    //invalid axis index, drop the entire record
+    if (!c->axes_index_tag_map->has (axisIndex))
+      return DROP_RECORD_WITH_VAR;
+
+    hb_tag_t axis_tag = c->axes_index_tag_map->get (axisIndex);
+
+    Triple axis_range (-1.f, 0.f, 1.f);
+    Triple *axis_limit;
+    if (c->axes_location->has (axis_tag, &axis_limit))
+      axis_range = *axis_limit;
+
+    float axis_min_val = axis_range.minimum;
+    float axis_default_val = axis_range.middle;
+    float axis_max_val = axis_range.maximum;
+
+    float filter_min_val = filterRangeMinValue.to_float ();
+    float filter_max_val = filterRangeMaxValue.to_float ();
+
+    if (axis_default_val < filter_min_val ||
+        axis_default_val > filter_max_val)
+      c->apply = false;
+
+    //condition not met, drop the entire record
+    if (axis_min_val > filter_max_val || axis_max_val < filter_min_val ||
+        filter_min_val > filter_max_val)
+      return DROP_RECORD_WITH_VAR;
+
+    //condition met and axis pinned, drop the condition
+    if (c->axes_location->has (axis_tag) &&
+        c->axes_location->get (axis_tag).is_point ())
+      return DROP_COND_WITH_VAR;
+
+    if (filter_max_val != axis_max_val || filter_min_val != axis_min_val)
+    {
+      // add axisIndex->value into the hashmap so we can check if the record is
+      // unique with variations
+      int16_t int_filter_max_val = filterRangeMaxValue.to_int ();
+      int16_t int_filter_min_val = filterRangeMinValue.to_int ();
+      hb_codepoint_t val = (int_filter_max_val << 16) + int_filter_min_val;
+
+      condition_map->set (axisIndex, val);
+      return KEEP_COND_WITH_VAR;
+    }
+
+    return KEEP_RECORD_WITH_VAR;
+  }
+
   bool evaluate (const int *coords, unsigned int coord_len) const
   {
     int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
-    return filterRangeMinValue <= coord && coord <= filterRangeMaxValue;
+    return filterRangeMinValue.to_int () <= coord && coord <= filterRangeMaxValue.to_int ();
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -3024,11 +3400,20 @@ struct Condition
     }
   }
 
+  Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
+                                             hb_map_t *condition_map /* OUT */) const
+  {
+    switch (u.format) {
+    case 1: return u.format1.keep_with_variations (c, condition_map);
+    default: c->apply = false; return KEEP_COND_WITH_VAR;
+    }
+  }
+
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
@@ -3065,15 +3450,70 @@ struct ConditionSet
     return true;
   }
 
-  bool subset (hb_subset_context_t *c) const
+  void keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
+  {
+    hb_map_t *condition_map = hb_map_create ();
+    if (unlikely (!condition_map)) return;
+    hb::shared_ptr<hb_map_t> p {condition_map};
+
+    hb_set_t *cond_set = hb_set_create ();
+    if (unlikely (!cond_set)) return;
+    hb::shared_ptr<hb_set_t> s {cond_set};
+
+    c->apply = true;
+    bool should_keep = false;
+    unsigned num_kept_cond = 0, cond_idx = 0;
+    for (const auto& offset : conditions)
+    {
+      Cond_with_Var_flag_t ret = (this+offset).keep_with_variations (c, condition_map);
+      // condition is not met or condition out of range, drop the entire record
+      if (ret == DROP_RECORD_WITH_VAR)
+        return;
+
+      if (ret == KEEP_COND_WITH_VAR)
+      {
+        should_keep = true;
+        cond_set->add (cond_idx);
+        num_kept_cond++;
+      }
+
+      if (ret == KEEP_RECORD_WITH_VAR)
+        should_keep = true;
+
+      cond_idx++;
+    }
+
+    if (!should_keep) return;
+
+    //check if condition_set is unique with variations
+    if (c->conditionset_map->has (p))
+      //duplicate found, drop the entire record
+      return;
+
+    c->conditionset_map->set (p, 1);
+    c->record_cond_idx_map->set (c->cur_record_idx, s);
+    if (should_keep && num_kept_cond == 0)
+      c->universal = true;
+  }
+
+  bool subset (hb_subset_context_t *c,
+               hb_subset_layout_context_t *l) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (this);
     if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
 
-    + conditions.iter ()
-    | hb_apply (subset_offset_array (c, out->conditions, this))
-    ;
+    hb_set_t *retained_cond_set = nullptr;
+    if (l->feature_record_cond_idx_map != nullptr)
+      retained_cond_set = l->feature_record_cond_idx_map->get (l->cur_feature_var_record_idx);
+
+    unsigned int count = conditions.len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      if (retained_cond_set != nullptr && !retained_cond_set->has (i))
+        continue;
+      subset_offset_array (c, out->conditions, this) (conditions[i]);
+    }
 
     return_trace (bool (out->conditions));
   }
@@ -3107,10 +3547,19 @@ struct FeatureTableSubstitutionRecord
       feature_indexes->add (featureIndex);
   }
 
+  void collect_feature_substitutes_with_variations (hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
+                                                    const hb_set_t *feature_indices,
+                                                    const void *base) const
+  {
+    if (feature_indices->has (featureIndex))
+      feature_substitutes_map->set (featureIndex, &(base+feature));
+  }
+
   bool subset (hb_subset_layout_context_t *c, const void *base) const
   {
     TRACE_SUBSET (this);
-    if (!c->feature_index_map->has (featureIndex)) {
+    if (!c->feature_index_map->has (featureIndex) ||
+        c->feature_substitutes_map->has (featureIndex)) {
       // Feature that is being substituted is not being retained, so we don't
       // need this.
       return_trace (false);
@@ -3120,8 +3569,7 @@ struct FeatureTableSubstitutionRecord
     if (unlikely (!out)) return_trace (false);
 
     out->featureIndex = c->feature_index_map->get (featureIndex);
-    bool ret = out->feature.serialize_subset (c->subset_context, feature, base, c);
-    return_trace (ret);
+    return_trace (out->feature.serialize_subset (c->subset_context, feature, base, c));
   }
 
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
@@ -3152,10 +3600,16 @@ struct FeatureTableSubstitution
   }
 
   void collect_lookups (const hb_set_t *feature_indexes,
+                       const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
                        hb_set_t       *lookup_indexes /* OUT */) const
   {
     + hb_iter (substitutions)
     | hb_filter (feature_indexes, &FeatureTableSubstitutionRecord::featureIndex)
+    | hb_filter ([feature_substitutes_map] (const FeatureTableSubstitutionRecord& record)
+                 {
+                   if (feature_substitutes_map == nullptr) return true;
+                   return !feature_substitutes_map->has (record.featureIndex);
+                 })
     | hb_apply ([this, lookup_indexes] (const FeatureTableSubstitutionRecord& r)
                { r.collect_lookups (this, lookup_indexes); })
     ;
@@ -3177,6 +3631,12 @@ struct FeatureTableSubstitution
     return false;
   }
 
+  void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
+  {
+    for (const FeatureTableSubstitutionRecord& record : substitutions)
+      record.collect_feature_substitutes_with_variations (c->feature_substitutes_map, c->feature_indices, this);
+  }
+
   bool subset (hb_subset_context_t        *c,
               hb_subset_layout_context_t *l) const
   {
@@ -3216,9 +3676,10 @@ struct FeatureVariationRecord
 
   void collect_lookups (const void     *base,
                        const hb_set_t *feature_indexes,
+                       const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
                        hb_set_t       *lookup_indexes /* OUT */) const
   {
-    return (base+substitutions).collect_lookups (feature_indexes, lookup_indexes);
+    return (base+substitutions).collect_lookups (feature_indexes, feature_substitutes_map, lookup_indexes);
   }
 
   void closure_features (const void     *base,
@@ -3233,13 +3694,24 @@ struct FeatureVariationRecord
     return (base+substitutions).intersects_features (feature_index_map);
   }
 
+  void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
+                                                    const void *base) const
+  {
+    (base+conditions).keep_with_variations (c);
+    if (c->apply && !c->variation_applied)
+    {
+      (base+substitutions).collect_feature_substitutes_with_variations (c);
+      c->variation_applied = true; // set variations only once
+    }
+  }
+
   bool subset (hb_subset_layout_context_t *c, const void *base) const
   {
     TRACE_SUBSET (this);
     auto *out = c->subset_context->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
 
-    out->conditions.serialize_subset (c->subset_context, conditions, base);
+    out->conditions.serialize_subset (c->subset_context, conditions, base, c);
     out->substitutions.serialize_subset (c->subset_context, substitutions, base, c);
 
     return_trace (true);
@@ -3289,6 +3761,21 @@ struct FeatureVariations
     return (this+record.substitutions).find_substitute (feature_index);
   }
 
+  void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
+  {
+    unsigned int count = varRecords.len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      c->cur_record_idx = i;
+      varRecords[i].collect_feature_substitutes_with_variations (c, this);
+      if (c->universal)
+        break;
+    }
+    if (c->variation_applied && !c->universal &&
+        !c->record_cond_idx_map->is_empty ())
+      c->insert_catch_all_feature_variation_record = true;
+  }
+
   FeatureVariations* copy (hb_serialize_context_t *c) const
   {
     TRACE_SERIALIZE (this);
@@ -3296,17 +3783,25 @@ struct FeatureVariations
   }
 
   void collect_lookups (const hb_set_t *feature_indexes,
+                       const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
                        hb_set_t       *lookup_indexes /* OUT */) const
   {
     for (const FeatureVariationRecord& r : varRecords)
-      r.collect_lookups (this, feature_indexes, lookup_indexes);
+      r.collect_lookups (this, feature_indexes, feature_substitutes_map, lookup_indexes);
   }
 
   void closure_features (const hb_map_t *lookup_indexes,
+                        const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
                         hb_set_t       *feature_indexes /* OUT */) const
   {
-    for (const FeatureVariationRecord& record : varRecords)
-      record.closure_features (this, lookup_indexes, feature_indexes);
+    unsigned int count = varRecords.len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      if (feature_record_cond_idx_map != nullptr &&
+          !feature_record_cond_idx_map->has (i))
+        continue;
+      varRecords[i].closure_features (this, lookup_indexes, feature_indexes);
+    }
   }
 
   bool subset (hb_subset_context_t *c,
@@ -3328,7 +3823,13 @@ struct FeatureVariations
     }
 
     unsigned count = (unsigned) (keep_up_to + 1);
-    for (unsigned i = 0; i < count; i++) {
+    for (unsigned i = 0; i < count; i++)
+    {
+      if (l->feature_record_cond_idx_map != nullptr &&
+          !l->feature_record_cond_idx_map->has (i))
+        continue;
+
+      l->cur_feature_var_record_idx = i;
       subset_record_array (l, &(out->varRecords), this) (varRecords[i]);
     }
     return_trace (bool (out->varRecords));
@@ -3443,35 +3944,37 @@ struct VariationDevice
 
   private:
 
-  hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const
-  { return font->em_scalef_x (get_delta (font, store)); }
+  hb_position_t get_x_delta (hb_font_t *font,
+                            const VariationStore &store,
+                            VariationStore::cache_t *store_cache = nullptr) const
+  { return font->em_scalef_x (get_delta (font, store, store_cache)); }
 
-  hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
-  { return font->em_scalef_y (get_delta (font, store)); }
+  hb_position_t get_y_delta (hb_font_t *font,
+                            const VariationStore &store,
+                            VariationStore::cache_t *store_cache = nullptr) const
+  { return font->em_scalef_y (get_delta (font, store, store_cache)); }
 
-  VariationDevice* copy (hb_serialize_context_t *c, const hb_map_t *layout_variation_idx_map) const
+  VariationDevice* copy (hb_serialize_context_t *c,
+                         const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
   {
     TRACE_SERIALIZE (this);
-    auto snap = c->snapshot ();
+    if (!layout_variation_idx_delta_map) return_trace (nullptr);
+
+    hb_pair_t<unsigned, int> *v;
+    if (!layout_variation_idx_delta_map->has (varIdx, &v))
+      return_trace (nullptr);
+
+    c->start_zerocopy (this->static_size);
     auto *out = c->embed (this);
     if (unlikely (!out)) return_trace (nullptr);
-    if (!layout_variation_idx_map || layout_variation_idx_map->is_empty ()) return_trace (out);
 
-    /* TODO Just get() and bail if NO_VARIATION. Needs to setup the map to return that. */
-    if (!layout_variation_idx_map->has (varIdx))
-    {
-      c->revert (snap);
+    if (!c->check_assign (out->varIdx, hb_first (*v), HB_SERIALIZE_ERROR_INT_OVERFLOW))
       return_trace (nullptr);
-    }
-    unsigned new_idx = layout_variation_idx_map->get (varIdx);
-    out->varIdx = new_idx;
     return_trace (out);
   }
 
-  void record_variation_index (hb_set_t *layout_variation_indices) const
-  {
-    layout_variation_indices->add (varIdx);
-  }
+  void collect_variation_index (hb_collect_variation_indices_context_t *c) const
+  { c->layout_variation_indices->add (varIdx); }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -3481,9 +3984,11 @@ struct VariationDevice
 
   private:
 
-  float get_delta (hb_font_t *font, const VariationStore &store) const
+  float get_delta (hb_font_t *font,
+                  const VariationStore &store,
+                  VariationStore::cache_t *store_cache = nullptr) const
   {
-    return store.get_delta (varIdx, font->coords, font->num_coords);
+    return store.get_delta (varIdx, font->coords, font->num_coords, (VariationStore::cache_t *) store_cache);
   }
 
   protected:
@@ -3506,7 +4011,9 @@ struct DeviceHeader
 
 struct Device
 {
-  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),
+                            VariationStore::cache_t *store_cache = nullptr) const
   {
     switch (u.b.format)
     {
@@ -3516,13 +4023,15 @@ struct Device
 #endif
 #ifndef HB_NO_VAR
     case 0x8000:
-      return u.variation.get_x_delta (font, store);
+      return u.variation.get_x_delta (font, store, store_cache);
 #endif
     default:
       return 0;
     }
   }
-  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),
+                            VariationStore::cache_t *store_cache = nullptr) const
   {
     switch (u.b.format)
     {
@@ -3532,7 +4041,7 @@ struct Device
 #endif
 #ifndef HB_NO_VAR
     case 0x8000:
-      return u.variation.get_y_delta (font, store);
+      return u.variation.get_y_delta (font, store, store_cache);
 #endif
     default:
       return 0;
@@ -3557,7 +4066,8 @@ struct Device
     }
   }
 
-  Device* copy (hb_serialize_context_t *c, const hb_map_t *layout_variation_idx_map=nullptr) const
+  Device* copy (hb_serialize_context_t *c,
+                const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map=nullptr) const
   {
     TRACE_SERIALIZE (this);
     switch (u.b.format) {
@@ -3569,14 +4079,14 @@ struct Device
 #endif
 #ifndef HB_NO_VAR
     case 0x8000:
-      return_trace (reinterpret_cast<Device *> (u.variation.copy (c, layout_variation_idx_map)));
+      return_trace (reinterpret_cast<Device *> (u.variation.copy (c, layout_variation_idx_delta_map)));
 #endif
     default:
       return_trace (nullptr);
     }
   }
 
-  void collect_variation_indices (hb_set_t *layout_variation_indices) const
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
   {
     switch (u.b.format) {
 #ifndef HB_NO_HINTING
@@ -3587,7 +4097,7 @@ struct Device
 #endif
 #ifndef HB_NO_VAR
     case 0x8000:
-      u.variation.record_variation_index (layout_variation_indices);
+      u.variation.collect_variation_index (c);
       return;
 #endif
     default:
@@ -3595,6 +4105,18 @@ struct Device
     }
   }
 
+  unsigned get_variation_index () const
+  {
+    switch (u.b.format) {
+#ifndef HB_NO_VAR
+    case 0x8000:
+      return u.variation.varIdx;
+#endif
+    default:
+      return HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
+    }
+  }
+
   protected:
   union {
   DeviceHeader         b;
index a76d644..c8a2cf8 100644 (file)
 #ifndef HB_OT_LAYOUT_GDEF_TABLE_HH
 #define HB_OT_LAYOUT_GDEF_TABLE_HH
 
-#include "hb-ot-layout-common.hh"
-
-#include "hb-font.hh"
-
-
-namespace OT {
-
-
-/*
- * Attachment List Table
- */
-
-/* Array of contour point indices--in increasing numerical order */
-struct AttachPoint : Array16Of<HBUINT16>
-{
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!out)) return_trace (false);
-
-    return_trace (out->serialize (c->serializer, + iter ()));
-  }
-};
-
-struct AttachList
-{
-  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)
-    {
-      if (point_count)
-       *point_count = 0;
-      return 0;
-    }
-
-    const AttachPoint &points = this+attachPoint[index];
-
-    if (point_count)
-    {
-      + points.sub_array (start_offset, point_count)
-      | hb_sink (hb_array (point_array, *point_count))
-      ;
-    }
-
-    return points.len;
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-
-    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
-    + hb_zip (this+coverage, attachPoint)
-    | hb_filter (glyphset, hb_first)
-    | hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second)
-    | hb_map (hb_first)
-    | hb_map (glyph_map)
-    | hb_sink (new_coverage)
-    ;
-    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
-    return_trace (bool (new_coverage));
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
-  }
-
-  protected:
-  Offset16To<Coverage>
-               coverage;               /* Offset to Coverage table -- from
-                                        * beginning of AttachList table */
-  Array16OfOffset16To<AttachPoint>
-               attachPoint;            /* Array of AttachPoint tables
-                                        * in Coverage Index order */
-  public:
-  DEFINE_SIZE_ARRAY (4, attachPoint);
-};
-
-/*
- * Ligature Caret Table
- */
-
-struct CaretValueFormat1
-{
-  friend struct CaretValue;
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->embed (this);
-    if (unlikely (!out)) return_trace (false);
-    return_trace (true);
-  }
-
-  private:
-  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);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this));
-  }
-
-  protected:
-  HBUINT16     caretValueFormat;       /* Format identifier--format = 1 */
-  FWORD                coordinate;             /* X or Y value, in design units */
-  public:
-  DEFINE_SIZE_STATIC (4);
-};
-
-struct CaretValueFormat2
-{
-  friend struct CaretValue;
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->embed (this);
-    if (unlikely (!out)) return_trace (false);
-    return_trace (true);
-  }
-
-  private:
-  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;
-    font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y);
-    return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this));
-  }
-
-  protected:
-  HBUINT16     caretValueFormat;       /* Format identifier--format = 2 */
-  HBUINT16     caretValuePoint;        /* Contour point index on glyph */
-  public:
-  DEFINE_SIZE_STATIC (4);
-};
-
-struct CaretValueFormat3
-{
-  friend struct CaretValue;
-
-  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);
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->embed (this);
-    if (unlikely (!out)) return_trace (false);
-
-    return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out),
-                                                  hb_serialize_context_t::Head, c->plan->layout_variation_idx_map));
-  }
-
-  void collect_variation_indices (hb_set_t *layout_variation_indices) const
-  { (this+deviceTable).collect_variation_indices (layout_variation_indices); }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
-  }
-
-  protected:
-  HBUINT16     caretValueFormat;       /* Format identifier--format = 3 */
-  FWORD                coordinate;             /* X or Y value, in design units */
-  Offset16To<Device>
-               deviceTable;            /* Offset to Device table for X or Y
-                                        * value--from beginning of CaretValue
-                                        * table */
-  public:
-  DEFINE_SIZE_STATIC (6);
-};
-
-struct CaretValue
-{
-  hb_position_t get_caret_value (hb_font_t *font,
-                                hb_direction_t direction,
-                                hb_codepoint_t glyph_id,
-                                const VariationStore &var_store) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.get_caret_value (font, direction);
-    case 2: return u.format2.get_caret_value (font, direction, glyph_id);
-    case 3: return u.format3.get_caret_value (font, direction, var_store);
-    default:return 0;
-    }
-  }
-
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
-    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  void collect_variation_indices (hb_set_t *layout_variation_indices) const
-  {
-    switch (u.format) {
-    case 1:
-    case 2:
-      return;
-    case 3:
-      u.format3.collect_variation_indices (layout_variation_indices);
-      return;
-    default: return;
-    }
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    if (!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));
-    case 3: return_trace (u.format3.sanitize (c));
-    default:return_trace (true);
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16             format;         /* Format identifier */
-  CaretValueFormat1    format1;
-  CaretValueFormat2    format2;
-  CaretValueFormat3    format3;
-  } u;
-  public:
-  DEFINE_SIZE_UNION (2, format);
-};
-
-struct LigGlyph
-{
-  unsigned get_lig_carets (hb_font_t            *font,
-                          hb_direction_t        direction,
-                          hb_codepoint_t        glyph_id,
-                          const VariationStore &var_store,
-                          unsigned              start_offset,
-                          unsigned             *caret_count /* IN/OUT */,
-                          hb_position_t        *caret_array /* OUT */) const
-  {
-    if (caret_count)
-    {
-      + carets.sub_array (start_offset, caret_count)
-      | hb_map (hb_add (this))
-      | hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); })
-      | hb_sink (hb_array (caret_array, *caret_count))
-      ;
-    }
-
-    return carets.len;
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-
-    + hb_iter (carets)
-    | hb_apply (subset_offset_array (c, out->carets, this))
-    ;
-
-    return_trace (bool (out->carets));
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    for (const Offset16To<CaretValue>& offset : carets.iter ())
-      (this+offset).collect_variation_indices (c->layout_variation_indices);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (carets.sanitize (c, this));
-  }
-
-  protected:
-  Array16OfOffset16To<CaretValue>
-               carets;                 /* Offset array of CaretValue tables
-                                        * --from beginning of LigGlyph table
-                                        * --in increasing coordinate order */
-  public:
-  DEFINE_SIZE_ARRAY (2, carets);
-};
-
-struct LigCaretList
-{
-  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)
-    {
-      if (caret_count)
-       *caret_count = 0;
-      return 0;
-    }
-    const LigGlyph &lig_glyph = this+ligGlyph[index];
-    return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-
-    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
-    + hb_zip (this+coverage, ligGlyph)
-    | hb_filter (glyphset, hb_first)
-    | hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second)
-    | hb_map (hb_first)
-    | hb_map (glyph_map)
-    | hb_sink (new_coverage)
-    ;
-    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
-    return_trace (bool (new_coverage));
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    + hb_zip (this+coverage, ligGlyph)
-    | hb_filter (c->glyph_set, hb_first)
-    | hb_map (hb_second)
-    | hb_map (hb_add (this))
-    | hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); })
-    ;
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
-  }
-
-  protected:
-  Offset16To<Coverage>
-               coverage;               /* Offset to Coverage table--from
-                                        * beginning of LigCaretList table */
-  Array16OfOffset16To<LigGlyph>
-               ligGlyph;               /* Array of LigGlyph tables
-                                        * in Coverage Index order */
-  public:
-  DEFINE_SIZE_ARRAY (4, ligGlyph);
-};
-
-
-struct MarkGlyphSetsFormat1
-{
-  bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
-  { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->format = format;
-
-    bool ret = true;
-    for (const Offset32To<Coverage>& offset : coverage.iter ())
-    {
-      auto *o = out->coverage.serialize_append (c->serializer);
-      if (unlikely (!o))
-      {
-       ret = false;
-       break;
-      }
-
-      //not using o->serialize_subset (c, offset, this, out) here because
-      //OTS doesn't allow null offset.
-      //See issue: https://github.com/khaledhosny/ots/issues/172
-      c->serializer->push ();
-      c->dispatch (this+offset);
-      c->serializer->add_link (*o, c->serializer->pop_pack ());
-    }
-
-    return_trace (ret && out->coverage.len);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (coverage.sanitize (c, this));
-  }
-
-  protected:
-  HBUINT16     format;                 /* Format identifier--format = 1 */
-  Array16Of<Offset32To<Coverage>>
-               coverage;               /* Array of long offsets to mark set
-                                        * coverage tables */
-  public:
-  DEFINE_SIZE_ARRAY (4, coverage);
-};
-
-struct MarkGlyphSets
-{
-  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);
-    default:return false;
-    }
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    switch (u.format) {
-    case 1: return_trace (u.format1.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);
-    switch (u.format) {
-    case 1: return_trace (u.format1.sanitize (c));
-    default:return_trace (true);
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16             format;         /* Format identifier */
-  MarkGlyphSetsFormat1 format1;
-  } u;
-  public:
-  DEFINE_SIZE_UNION (2, format);
-};
-
-
-/*
- * GDEF -- Glyph Definition
- * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
- */
-
-
-struct GDEF
-{
-  static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
-
-  enum GlyphClasses {
-    UnclassifiedGlyph  = 0,
-    BaseGlyph          = 1,
-    LigatureGlyph      = 2,
-    MarkGlyph          = 3,
-    ComponentGlyph     = 4
-  };
-
-  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); }
-  void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
-  { (this+glyphClassDef).collect_class (glyphs, klass); }
-
-  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); }
-
-  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); }
-
-  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); }
-
-  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); }
-
-  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); }
-
-  /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
-   * 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. */
-  unsigned int get_glyph_props (hb_codepoint_t glyph) const
-  {
-    unsigned int klass = get_glyph_class (glyph);
-
-    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), "");
-    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), "");
-    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), "");
-
-    switch (klass) {
-    default:                   return 0;
-    case BaseGlyph:            return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
-    case LigatureGlyph:                return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
-    case MarkGlyph:
-         klass = get_mark_attachment_type (glyph);
-         return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
-    }
-  }
-
-  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
-                                  hb_face_t *face) const;
-
-  struct accelerator_t
-  {
-    accelerator_t (hb_face_t *face)
-    {
-      table = hb_sanitize_context_t ().reference_table<GDEF> (face);
-      if (unlikely (table->is_blocklisted (table.get_blob (), face)))
-      {
-       hb_blob_destroy (table.get_blob ());
-       table = hb_blob_get_empty ();
-      }
-    }
-    ~accelerator_t () { 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);
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  { (this+ligCaretList).collect_variation_indices (c); }
-
-  void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
-                                      hb_map_t *layout_variation_idx_map /* OUT */) const
-  {
-    if (version.to_int () < 0x00010003u || !varStore) return;
-    if (layout_variation_indices->is_empty ()) return;
-
-    unsigned new_major = 0, new_minor = 0;
-    unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
-    for (unsigned idx : layout_variation_indices->iter ())
-    {
-      uint16_t major = idx >> 16;
-      if (major >= (this+varStore).get_sub_table_count ()) break;
-      if (major != last_major)
-      {
-       new_minor = 0;
-       ++new_major;
-      }
-
-      unsigned new_idx = (new_major << 16) + new_minor;
-      layout_variation_idx_map->set (idx, new_idx);
-      ++new_minor;
-      last_major = major;
-    }
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->embed (*this);
-    if (unlikely (!out)) return_trace (false);
-
-    bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
-    bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
-    bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
-    bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
-
-    bool subset_markglyphsetsdef = true;
-    if (version.to_int () >= 0x00010002u)
-    {
-      subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
-      if (!subset_markglyphsetsdef &&
-         version.to_int () == 0x00010002u)
-       out->version.minor = 0;
-    }
-
-    bool subset_varstore = true;
-    if (version.to_int () >= 0x00010003u)
-    {
-      subset_varstore = out->varStore.serialize_subset (c, varStore, this);
-      if (!subset_varstore && version.to_int () == 0x00010003u)
-       out->version.minor = 2;
-    }
-
-    return_trace (subset_glyphclassdef || subset_attachlist ||
-                 subset_ligcaretlist || subset_markattachclassdef ||
-                 (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
-                 (out->version.to_int () >= 0x00010003u && subset_varstore));
-  }
-
-  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
-                                        * 0x00010003u */
-  Offset16To<ClassDef>
-               glyphClassDef;          /* Offset to class definition table
-                                        * for glyph type--from beginning of
-                                        * GDEF header (may be Null) */
-  Offset16To<AttachList>
-               attachList;             /* Offset to list of glyphs with
-                                        * attachment points--from beginning
-                                        * of GDEF header (may be Null) */
-  Offset16To<LigCaretList>
-               ligCaretList;           /* Offset to list of positioning points
-                                        * for ligature carets--from beginning
-                                        * of GDEF header (may be Null) */
-  Offset16To<ClassDef>
-               markAttachClassDef;     /* Offset to class definition table for
-                                        * mark attachment type--from beginning
-                                        * of GDEF header (may be Null) */
-  Offset16To<MarkGlyphSets>
-               markGlyphSetsDef;       /* Offset to the table of mark set
-                                        * definitions--from beginning of GDEF
-                                        * header (may be NULL).  Introduced
-                                        * in version 0x00010002. */
-  Offset32To<VariationStore>
-               varStore;               /* Offset to the table of Item Variation
-                                        * Store--from beginning of GDEF
-                                        * header (may be NULL).  Introduced
-                                        * in version 0x00010003. */
-  public:
-  DEFINE_SIZE_MIN (12);
-};
-
-struct GDEF_accelerator_t : GDEF::accelerator_t {
-  GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {}
-};
-
-} /* namespace OT */
-
+#include "OT/Layout/GDEF/GDEF.hh"
 
 #endif /* HB_OT_LAYOUT_GDEF_TABLE_HH */
index 2f9186a..0cfa139 100644 (file)
 #ifndef HB_OT_LAYOUT_GPOS_TABLE_HH
 #define HB_OT_LAYOUT_GPOS_TABLE_HH
 
-#include "hb-ot-layout-gsubgpos.hh"
-
-
-namespace OT {
-
-struct MarkArray;
-static void Markclass_closure_and_remap_indexes (const Coverage  &mark_coverage,
-                                                const MarkArray &mark_array,
-                                                const hb_set_t  &glyphset,
-                                                hb_map_t*        klass_mapping /* INOUT */);
-
-/* buffer **position** var allocations */
-#define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
-#define attach_type() var.u8[2] /* attachment type */
-/* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */
-
-enum attach_type_t {
-  ATTACH_TYPE_NONE     = 0X00,
-
-  /* Each attachment should be either a mark or a cursive; can't be both. */
-  ATTACH_TYPE_MARK     = 0X01,
-  ATTACH_TYPE_CURSIVE  = 0X02,
-};
-
-
-/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
-
-typedef HBUINT16 Value;
-
-typedef UnsizedArrayOf<Value> ValueRecord;
-
-struct ValueFormat : HBUINT16
-{
-  enum Flags {
-    xPlacement = 0x0001u,      /* Includes horizontal adjustment for placement */
-    yPlacement = 0x0002u,      /* Includes vertical adjustment for placement */
-    xAdvance   = 0x0004u,      /* Includes horizontal adjustment for advance */
-    yAdvance   = 0x0008u,      /* Includes vertical adjustment for advance */
-    xPlaDevice = 0x0010u,      /* Includes horizontal Device table for placement */
-    yPlaDevice = 0x0020u,      /* Includes vertical Device table for placement */
-    xAdvDevice = 0x0040u,      /* Includes horizontal Device table for advance */
-    yAdvDevice = 0x0080u,      /* Includes vertical Device table for advance */
-    ignored    = 0x0F00u,      /* Was used in TrueType Open for MM fonts */
-    reserved   = 0xF000u,      /* For future use */
-
-    devices    = 0x00F0u       /* Mask for having any Device table */
-  };
-
-/* All fields are options.  Only those available advance the value pointer. */
-#if 0
-  HBINT16              xPlacement;     /* Horizontal adjustment for
-                                        * placement--in design units */
-  HBINT16              yPlacement;     /* Vertical adjustment for
-                                        * placement--in design units */
-  HBINT16              xAdvance;       /* Horizontal adjustment for
-                                        * advance--in design units (only used
-                                        * for horizontal writing) */
-  HBINT16              yAdvance;       /* Vertical adjustment for advance--in
-                                        * design units (only used for vertical
-                                        * writing) */
-  Offset16To<Device>   xPlaDevice;     /* Offset to Device table for
-                                        * horizontal placement--measured from
-                                        * beginning of PosTable (may be NULL) */
-  Offset16To<Device>   yPlaDevice;     /* Offset to Device table for vertical
-                                        * placement--measured from beginning
-                                        * of PosTable (may be NULL) */
-  Offset16To<Device>   xAdvDevice;     /* Offset to Device table for
-                                        * horizontal advance--measured from
-                                        * beginning of PosTable (may be NULL) */
-  Offset16To<Device>   yAdvDevice;     /* Offset to Device table for vertical
-                                        * advance--measured from beginning of
-                                        * PosTable (may be NULL) */
-#endif
-
-  IntType& operator = (uint16_t i) { v = i; return *this; }
-
-  unsigned int get_len () const  { return hb_popcount ((unsigned int) *this); }
-  unsigned int get_size () const { return get_len () * Value::static_size; }
-
-  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 ret;
-
-    hb_font_t *font = c->font;
-    bool horizontal =
-#ifndef HB_NO_VERTICAL
-      HB_DIRECTION_IS_HORIZONTAL (c->direction)
-#else
-      true
-#endif
-      ;
-
-    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, &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, &ret));
-      values++;
-    }
-
-    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 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, &ret)).get_x_delta (font, store);
-      values++;
-    }
-    if (format & yPlaDevice) {
-      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, &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, &ret)).get_y_delta (font, store);
-      values++;
-    }
-    return ret;
-  }
-
-  unsigned int get_effective_format (const Value *values) const
-  {
-    unsigned int format = *this;
-    for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) {
-      if (format & flag) should_drop (*values++, (Flags) flag, &format);
-    }
-
-    return format;
-  }
-
-  template<typename Iterator,
-      hb_requires (hb_is_iterator (Iterator))>
-  unsigned int get_effective_format (Iterator it) const {
-    unsigned int new_format = 0;
-
-    for (const hb_array_t<const Value>& values : it)
-      new_format = new_format | get_effective_format (&values);
-
-    return new_format;
-  }
-
-  void copy_values (hb_serialize_context_t *c,
-                    unsigned int new_format,
-                    const void *base,
-                    const Value *values,
-                    const hb_map_t *layout_variation_idx_map) const
-  {
-    unsigned int format = *this;
-    if (!format) return;
-
-    if (format & xPlacement) copy_value (c, new_format, xPlacement, *values++);
-    if (format & yPlacement) copy_value (c, new_format, yPlacement, *values++);
-    if (format & xAdvance)   copy_value (c, new_format, xAdvance, *values++);
-    if (format & yAdvance)   copy_value (c, new_format, yAdvance, *values++);
-
-    if (format & xPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
-    if (format & yPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
-    if (format & xAdvDevice) copy_device (c, base, values++, layout_variation_idx_map);
-    if (format & yAdvDevice) copy_device (c, base, values++, layout_variation_idx_map);
-  }
-
-  void copy_value (hb_serialize_context_t *c,
-                   unsigned int new_format,
-                   Flags flag,
-                   Value value) const
-  {
-    // Filter by new format.
-    if (!(new_format & flag)) return;
-    c->copy (value);
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
-                                 const void *base,
-                                 const hb_array_t<const Value>& values) const
-  {
-    unsigned format = *this;
-    unsigned i = 0;
-    if (format & xPlacement) i++;
-    if (format & yPlacement) i++;
-    if (format & xAdvance) i++;
-    if (format & yAdvance) i++;
-    if (format & xPlaDevice)
-    {
-      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
-      i++;
-    }
-
-    if (format & ValueFormat::yPlaDevice)
-    {
-      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
-      i++;
-    }
-
-    if (format & ValueFormat::xAdvDevice)
-    {
-
-      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
-      i++;
-    }
-
-    if (format & ValueFormat::yAdvDevice)
-    {
-
-      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
-      i++;
-    }
-  }
-
-  private:
-  bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
-  {
-    unsigned int format = *this;
-
-    if (format & xPlacement) values++;
-    if (format & yPlacement) values++;
-    if (format & xAdvance)   values++;
-    if (format & yAdvance)   values++;
-
-    if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
-    if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
-    if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
-    if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
-
-    return true;
-  }
-
-  static inline Offset16To<Device>& get_device (Value* value)
-  {
-    return *static_cast<Offset16To<Device> *> (value);
-  }
-  static inline const Offset16To<Device>& get_device (const Value* value, bool *worked=nullptr)
-  {
-    if (worked) *worked |= bool (*value);
-    return *static_cast<const Offset16To<Device> *> (value);
-  }
-
-  bool copy_device (hb_serialize_context_t *c, const void *base,
-                   const Value *src_value, const hb_map_t *layout_variation_idx_map) const
-  {
-    Value      *dst_value = c->copy (*src_value);
-
-    if (!dst_value) return false;
-    if (*dst_value == 0) return true;
-
-    *dst_value = 0;
-    c->push ();
-    if ((base + get_device (src_value)).copy (c, layout_variation_idx_map))
-    {
-      c->add_link (*dst_value, c->pop_pack ());
-      return true;
-    }
-    else
-    {
-      c->pop_discard ();
-      return false;
-    }
-  }
-
-  static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr)
-  {
-    if (worked) *worked |= bool (*value);
-    return *reinterpret_cast<const HBINT16 *> (value);
-  }
-
-  public:
-
-  bool has_device () const
-  {
-    unsigned int format = *this;
-    return (format & devices) != 0;
-  }
-
-  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)));
-  }
-
-  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_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);
-      values += len;
-    }
-
-    return_trace (true);
-  }
-
-  /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
-  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);
-
-    if (!has_device ()) return_trace (true);
-
-    for (unsigned int i = 0; i < count; i++) {
-      if (!sanitize_value_devices (c, base, values))
-       return_trace (false);
-      values += stride;
-    }
-
-    return_trace (true);
-  }
-
- private:
-
-  void should_drop (Value value, Flags flag, unsigned int* format) const
-  {
-    if (value) return;
-    *format = *format & ~flag;
-  }
-
-};
-
-template<typename Iterator, typename SrcLookup>
-static void SinglePos_serialize (hb_serialize_context_t *c,
-                                const SrcLookup *src,
-                                Iterator it,
-                                const hb_map_t *layout_variation_idx_map);
-
-
-struct AnchorFormat1
-{
-  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);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this));
-  }
-
-  AnchorFormat1* copy (hb_serialize_context_t *c) const
-  {
-    TRACE_SERIALIZE (this);
-    AnchorFormat1* out = c->embed<AnchorFormat1> (this);
-    if (!out) return_trace (out);
-    out->format = 1;
-    return_trace (out);
-  }
-
-  protected:
-  HBUINT16     format;                 /* Format identifier--format = 1 */
-  FWORD                xCoordinate;            /* Horizontal value--in design units */
-  FWORD                yCoordinate;            /* Vertical value--in design units */
-  public:
-  DEFINE_SIZE_STATIC (6);
-};
-
-struct AnchorFormat2
-{
-  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;
-
-#ifdef HB_NO_HINTING
-    *x = font->em_fscale_x (xCoordinate);
-    *y = font->em_fscale_y (yCoordinate);
-    return;
-#endif
-
-    unsigned int x_ppem = font->x_ppem;
-    unsigned int y_ppem = font->y_ppem;
-    hb_position_t cx = 0, cy = 0;
-    bool ret;
-
-    ret = (x_ppem || y_ppem) &&
-         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);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this));
-  }
-
-  AnchorFormat2* copy (hb_serialize_context_t *c) const
-  {
-    TRACE_SERIALIZE (this);
-    return_trace (c->embed<AnchorFormat2> (this));
-  }
-
-  protected:
-  HBUINT16     format;                 /* Format identifier--format = 2 */
-  FWORD                xCoordinate;            /* Horizontal value--in design units */
-  FWORD                yCoordinate;            /* Vertical value--in design units */
-  HBUINT16     anchorPoint;            /* Index to glyph contour point */
-  public:
-  DEFINE_SIZE_STATIC (8);
-};
-
-struct AnchorFormat3
-{
-  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);
-
-    if (font->x_ppem || font->num_coords)
-      *x += (this+xDeviceTable).get_x_delta (font, c->var_store);
-    if (font->y_ppem || font->num_coords)
-      *y += (this+yDeviceTable).get_y_delta (font, c->var_store);
-  }
-
-  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));
-  }
-
-  AnchorFormat3* copy (hb_serialize_context_t *c,
-                      const hb_map_t *layout_variation_idx_map) const
-  {
-    TRACE_SERIALIZE (this);
-    if (!layout_variation_idx_map) return_trace (nullptr);
-
-    auto *out = c->embed<AnchorFormat3> (this);
-    if (unlikely (!out)) return_trace (nullptr);
-
-    out->xDeviceTable.serialize_copy (c, xDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map);
-    out->yDeviceTable.serialize_copy (c, yDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map);
-    return_trace (out);
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    (this+xDeviceTable).collect_variation_indices (c->layout_variation_indices);
-    (this+yDeviceTable).collect_variation_indices (c->layout_variation_indices);
-  }
-
-  protected:
-  HBUINT16     format;                 /* Format identifier--format = 3 */
-  FWORD                xCoordinate;            /* Horizontal value--in design units */
-  FWORD                yCoordinate;            /* Vertical value--in design units */
-  Offset16To<Device>
-               xDeviceTable;           /* Offset to Device table for X
-                                        * coordinate-- from beginning of
-                                        * Anchor table (may be NULL) */
-  Offset16To<Device>
-               yDeviceTable;           /* Offset to Device table for Y
-                                        * coordinate-- from beginning of
-                                        * Anchor table (may be NULL) */
-  public:
-  DEFINE_SIZE_STATIC (10);
-};
-
-struct Anchor
-{
-  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) {
-    case 1: u.format1.get_anchor (c, glyph_id, x, y); return;
-    case 2: u.format2.get_anchor (c, glyph_id, x, y); return;
-    case 3: u.format3.get_anchor (c, glyph_id, x, y); return;
-    default:                                         return;
-    }
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    if (!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));
-    case 3: return_trace (u.format3.sanitize (c));
-    default:return_trace (true);
-    }
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    switch (u.format) {
-    case 1: return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
-    case 2:
-      if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
-      {
-        // AnchorFormat 2 just containins extra hinting information, so
-        // if hints are being dropped convert to format 1.
-        return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
-      }
-      return_trace (bool (reinterpret_cast<Anchor *> (u.format2.copy (c->serializer))));
-    case 3: return_trace (bool (reinterpret_cast<Anchor *> (u.format3.copy (c->serializer,
-                                                                            c->plan->layout_variation_idx_map))));
-    default:return_trace (false);
-    }
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    switch (u.format) {
-    case 1: case 2:
-      return;
-    case 3:
-      u.format3.collect_variation_indices (c);
-      return;
-    default: return;
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16             format;         /* Format identifier */
-  AnchorFormat1                format1;
-  AnchorFormat2                format2;
-  AnchorFormat3                format3;
-  } u;
-  public:
-  DEFINE_SIZE_UNION (2, format);
-};
-
-
-struct AnchorMatrix
-{
-  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];
-  }
-
-  template <typename Iterator,
-           hb_requires (hb_is_iterator (Iterator))>
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
-                                 Iterator index_iter) const
-  {
-    for (unsigned i : index_iter)
-      (this+matrixZ[i]).collect_variation_indices (c);
-  }
-
-  template <typename Iterator,
-      hb_requires (hb_is_iterator (Iterator))>
-  bool subset (hb_subset_context_t *c,
-               unsigned             num_rows,
-               Iterator             index_iter) const
-  {
-    TRACE_SUBSET (this);
-
-    auto *out = c->serializer->start_embed (this);
-
-    if (!index_iter) return_trace (false);
-    if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
-
-    out->rows = num_rows;
-    for (const unsigned i : index_iter)
-    {
-      auto *offset = c->serializer->embed (matrixZ[i]);
-      if (!offset) return_trace (false);
-      offset->serialize_subset (c, matrixZ[i], this);
-    }
-
-    return_trace (true);
-  }
-
-  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_mul_overflows (rows, cols))) return_trace (false);
-    unsigned int count = rows * cols;
-    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);
-  }
-
-  HBUINT16     rows;                   /* Number of rows */
-  UnsizedArrayOf<Offset16To<Anchor>>
-               matrixZ;                /* Matrix of offsets to Anchor tables--
-                                        * from beginning of AnchorMatrix table */
-  public:
-  DEFINE_SIZE_ARRAY (2, matrixZ);
-};
-
-
-struct MarkRecord
-{
-  friend struct MarkArray;
-
-  unsigned get_class () const { return (unsigned) klass; }
-  bool sanitize (hb_sanitize_context_t *c, const void *base) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
-  }
-
-  MarkRecord *subset (hb_subset_context_t    *c,
-                      const void             *src_base,
-                      const hb_map_t         *klass_mapping) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->embed (this);
-    if (unlikely (!out)) return_trace (nullptr);
-
-    out->klass = klass_mapping->get (klass);
-    out->markAnchor.serialize_subset (c, markAnchor, src_base);
-    return_trace (out);
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
-                                 const void *src_base) const
-  {
-    (src_base+markAnchor).collect_variation_indices (c);
-  }
-
-  protected:
-  HBUINT16     klass;                  /* Class defined for this mark */
-  Offset16To<Anchor>
-               markAnchor;             /* Offset to Anchor table--from
-                                        * beginning of MarkArray table */
-  public:
-  DEFINE_SIZE_STATIC (4);
-};
-
-struct MarkArray : Array16Of<MarkRecord>       /* Array of MarkRecords--in Coverage order */
-{
-  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;
-    const MarkRecord &record = Array16Of<MarkRecord>::operator[](mark_index);
-    unsigned int mark_class = record.klass;
-
-    const Anchor& mark_anchor = this + record.markAnchor;
-    bool found;
-    const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
-    /* If this subtable doesn't have an anchor for this base and this class,
-     * return false such that the subsequent subtables have a chance at it. */
-    if (unlikely (!found)) return_trace (false);
-
-    float mark_x, mark_y, base_x, base_y;
-
-    buffer->unsafe_to_break (glyph_pos, buffer->idx + 1);
-    mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y);
-    glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
-
-    hb_glyph_position_t &o = buffer->cur_pos();
-    o.x_offset = roundf (base_x - mark_x);
-    o.y_offset = roundf (base_y - mark_y);
-    o.attach_type() = ATTACH_TYPE_MARK;
-    o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
-    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
-
-    buffer->idx++;
-    return_trace (true);
-  }
-
-  template <typename Iterator,
-      hb_requires (hb_is_iterator (Iterator))>
-  bool subset (hb_subset_context_t *c,
-               Iterator                    coverage,
-               const hb_map_t      *klass_mapping) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-
-    auto* out = c->serializer->start_embed (this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-
-    auto mark_iter =
-    + hb_zip (coverage, this->iter ())
-    | hb_filter (glyphset, hb_first)
-    | hb_map (hb_second)
-    ;
-
-    unsigned new_length = 0;
-    for (const auto& mark_record : mark_iter) {
-      if (unlikely (!mark_record.subset (c, this, klass_mapping)))
-        return_trace (false);
-      new_length++;
-    }
-
-    if (unlikely (!c->serializer->check_assign (out->len, new_length,
-                                                HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)))
-      return_trace (false);
-
-    return_trace (true);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (Array16Of<MarkRecord>::sanitize (c, this));
-  }
-};
-
-
-/* Lookups */
-
-struct SinglePosFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return (this+coverage).intersects (glyphs); }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    if (!valueFormat.has_device ()) return;
-
-    auto it =
-    + hb_iter (this+coverage)
-    | hb_filter (c->glyph_set)
-    ;
-
-    if (!it) return;
-    valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ()));
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
-
-  const Coverage &get_coverage () const { return this+coverage; }
-
-  ValueFormat get_value_format () const { return valueFormat; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    hb_buffer_t *buffer = c->buffer;
-    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
-
-    valueFormat.apply_value (c, this, values, buffer->cur_pos());
-
-    buffer->idx++;
-    return_trace (true);
-  }
-
-  template<typename Iterator,
-      typename SrcLookup,
-      hb_requires (hb_is_iterator (Iterator))>
-  void serialize (hb_serialize_context_t *c,
-                 const SrcLookup *src,
-                 Iterator it,
-                 ValueFormat newFormat,
-                 const hb_map_t *layout_variation_idx_map)
-  {
-    if (unlikely (!c->extend_min (this))) return;
-    if (unlikely (!c->check_assign (valueFormat,
-                                    newFormat,
-                                    HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
-
-    for (const hb_array_t<const Value>& _ : + it | hb_map (hb_second))
-    {
-      src->get_value_format ().copy_values (c, newFormat, src,  &_, layout_variation_idx_map);
-      // Only serialize the first entry in the iterator, the rest are assumed to
-      // be the same.
-      break;
-    }
-
-    auto glyphs =
-    + it
-    | hb_map_retains_sorting (hb_first)
-    ;
-
-    coverage.serialize_serialize (c, glyphs);
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto it =
-    + hb_iter (this+coverage)
-    | hb_filter (glyphset)
-    | hb_map_retains_sorting (glyph_map)
-    | hb_zip (hb_repeat (values.as_array (valueFormat.get_len ())))
-    ;
-
-    bool ret = bool (it);
-    SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
-    return_trace (ret);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-                 coverage.sanitize (c, this) &&
-                 valueFormat.sanitize_value (c, this, values));
-  }
-
-  protected:
-  HBUINT16     format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
-               coverage;               /* Offset to Coverage table--from
-                                        * beginning of subtable */
-  ValueFormat  valueFormat;            /* Defines the types of data in the
-                                        * ValueRecord */
-  ValueRecord  values;                 /* Defines positioning
-                                        * value(s)--applied to all glyphs in
-                                        * the Coverage table */
-  public:
-  DEFINE_SIZE_ARRAY (6, values);
-};
-
-struct SinglePosFormat2
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return (this+coverage).intersects (glyphs); }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    if (!valueFormat.has_device ()) return;
-
-    auto it =
-    + hb_zip (this+coverage, hb_range ((unsigned) valueCount))
-    | hb_filter (c->glyph_set, hb_first)
-    ;
-
-    if (!it) return;
-
-    unsigned sub_length = valueFormat.get_len ();
-    const hb_array_t<const Value> values_array = values.as_array (valueCount * sub_length);
-
-    for (unsigned i : + it
-                     | hb_map (hb_second))
-      valueFormat.collect_variation_indices (c, this, values_array.sub_array (i * sub_length, sub_length));
-
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
-
-  const Coverage &get_coverage () const { return this+coverage; }
-
-  ValueFormat get_value_format () const { return valueFormat; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    hb_buffer_t *buffer = c->buffer;
-    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
-
-    if (likely (index >= valueCount)) return_trace (false);
-
-    valueFormat.apply_value (c, this,
-                            &values[index * valueFormat.get_len ()],
-                            buffer->cur_pos());
-
-    buffer->idx++;
-    return_trace (true);
-  }
-
-  template<typename Iterator,
-      typename SrcLookup,
-      hb_requires (hb_is_iterator (Iterator))>
-  void serialize (hb_serialize_context_t *c,
-                 const SrcLookup *src,
-                 Iterator it,
-                 ValueFormat newFormat,
-                 const hb_map_t *layout_variation_idx_map)
-  {
-    auto out = c->extend_min (this);
-    if (unlikely (!out)) return;
-    if (unlikely (!c->check_assign (valueFormat, newFormat, HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
-    if (unlikely (!c->check_assign (valueCount, it.len (), HB_SERIALIZE_ERROR_ARRAY_OVERFLOW))) return;
-
-    + it
-    | hb_map (hb_second)
-    | hb_apply ([&] (hb_array_t<const Value> _)
-    { src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map); })
-    ;
-
-    auto glyphs =
-    + it
-    | hb_map_retains_sorting (hb_first)
-    ;
-
-    coverage.serialize_serialize (c, glyphs);
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    unsigned sub_length = valueFormat.get_len ();
-    auto values_array = values.as_array (valueCount * sub_length);
-
-    auto it =
-    + hb_zip (this+coverage, hb_range ((unsigned) valueCount))
-    | hb_filter (glyphset, hb_first)
-    | hb_map_retains_sorting ([&] (const hb_pair_t<hb_codepoint_t, unsigned>& _)
-                             {
-                               return hb_pair (glyph_map[_.first],
-                                               values_array.sub_array (_.second * sub_length,
-                                                                       sub_length));
-                             })
-    ;
-
-    bool ret = bool (it);
-    SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
-    return_trace (ret);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-                 coverage.sanitize (c, this) &&
-                 valueFormat.sanitize_values (c, this, values, valueCount));
-  }
-
-  protected:
-  HBUINT16     format;                 /* Format identifier--format = 2 */
-  Offset16To<Coverage>
-               coverage;               /* Offset to Coverage table--from
-                                        * beginning of subtable */
-  ValueFormat  valueFormat;            /* Defines the types of data in the
-                                        * ValueRecord */
-  HBUINT16     valueCount;             /* Number of ValueRecords */
-  ValueRecord  values;                 /* Array of ValueRecords--positioning
-                                        * values applied to glyphs */
-  public:
-  DEFINE_SIZE_ARRAY (8, values);
-};
-
-struct SinglePos
-{
-  template<typename Iterator,
-          hb_requires (hb_is_iterator (Iterator))>
-  unsigned get_format (Iterator glyph_val_iter_pairs)
-  {
-    hb_array_t<const Value> first_val_iter = hb_second (*glyph_val_iter_pairs);
-
-    for (const auto iter : glyph_val_iter_pairs)
-      for (const auto _ : hb_zip (iter.second, first_val_iter))
-       if (_.first != _.second)
-         return 2;
-
-    return 1;
-  }
-
-
-  template<typename Iterator,
-      typename SrcLookup,
-      hb_requires (hb_is_iterator (Iterator))>
-  void serialize (hb_serialize_context_t *c,
-                 const SrcLookup* src,
-                 Iterator glyph_val_iter_pairs,
-                 const hb_map_t *layout_variation_idx_map)
-  {
-    if (unlikely (!c->extend_min (u.format))) return;
-    unsigned format = 2;
-    ValueFormat new_format = src->get_value_format ();
-
-    if (glyph_val_iter_pairs)
-    {
-      format = get_format (glyph_val_iter_pairs);
-      new_format = src->get_value_format ().get_effective_format (+ glyph_val_iter_pairs | hb_map (hb_second));
-    }
-
-    u.format = format;
-    switch (u.format) {
-    case 1: u.format1.serialize (c,
-                                 src,
-                                 glyph_val_iter_pairs,
-                                 new_format,
-                                 layout_variation_idx_map);
-      return;
-    case 2: u.format2.serialize (c,
-                                 src,
-                                 glyph_val_iter_pairs,
-                                 new_format,
-                                 layout_variation_idx_map);
-      return;
-    default:return;
-    }
-  }
-
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16             format;         /* Format identifier */
-  SinglePosFormat1     format1;
-  SinglePosFormat2     format2;
-  } u;
-};
-
-template<typename Iterator, typename SrcLookup>
-static void
-SinglePos_serialize (hb_serialize_context_t *c,
-                    const SrcLookup *src,
-                    Iterator it,
-                    const hb_map_t *layout_variation_idx_map)
-{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_map); }
-
-
-struct PairValueRecord
-{
-  friend struct PairSet;
-
-  int cmp (hb_codepoint_t k) const
-  { return secondGlyph.cmp (k); }
-
-  struct context_t
-  {
-    const void                 *base;
-    const ValueFormat  *valueFormats;
-    const ValueFormat  *newFormats;
-    unsigned           len1; /* valueFormats[0].get_len() */
-    const hb_map_t     *glyph_map;
-    const hb_map_t      *layout_variation_idx_map;
-  };
-
-  bool subset (hb_subset_context_t *c,
-               context_t *closure) const
-  {
-    TRACE_SERIALIZE (this);
-    auto *s = c->serializer;
-    auto *out = s->start_embed (*this);
-    if (unlikely (!s->extend_min (out))) return_trace (false);
-
-    out->secondGlyph = (*closure->glyph_map)[secondGlyph];
-
-    closure->valueFormats[0].copy_values (s,
-                                          closure->newFormats[0],
-                                          closure->base, &values[0],
-                                          closure->layout_variation_idx_map);
-    closure->valueFormats[1].copy_values (s,
-                                          closure->newFormats[1],
-                                          closure->base,
-                                          &values[closure->len1],
-                                          closure->layout_variation_idx_map);
-
-    return_trace (true);
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
-                                 const ValueFormat *valueFormats,
-                                 const void *base) const
-  {
-    unsigned record1_len = valueFormats[0].get_len ();
-    unsigned record2_len = valueFormats[1].get_len ();
-    const hb_array_t<const Value> values_array = values.as_array (record1_len + record2_len);
-
-    if (valueFormats[0].has_device ())
-      valueFormats[0].collect_variation_indices (c, base, values_array.sub_array (0, record1_len));
-
-    if (valueFormats[1].has_device ())
-      valueFormats[1].collect_variation_indices (c, base, values_array.sub_array (record1_len, record2_len));
-  }
-
-  bool intersects (const hb_set_t& glyphset) const
-  {
-    return glyphset.has(secondGlyph);
-  }
-
-  const Value* get_values_1 () const
-  {
-    return &values[0];
-  }
-
-  const Value* get_values_2 (ValueFormat format1) const
-  {
-    return &values[format1.get_len ()];
-  }
-
-  protected:
-  HBGlyphID16  secondGlyph;            /* GlyphID of second glyph in the
-                                        * pair--first glyph is listed in the
-                                        * Coverage table */
-  ValueRecord  values;                 /* Positioning data for the first glyph
-                                        * followed by for second glyph */
-  public:
-  DEFINE_SIZE_ARRAY (2, values);
-};
-
-struct PairSet
-{
-  friend struct PairPosFormat1;
-
-  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
-  {
-    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;
-    c->input->add_array (&record->secondGlyph, len, record_size);
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
-                                 const ValueFormat *valueFormats) const
-  {
-    unsigned len1 = valueFormats[0].get_len ();
-    unsigned len2 = valueFormats[1].get_len ();
-    unsigned record_size = HBUINT16::static_size * (1 + len1 + len2);
-
-    const PairValueRecord *record = &firstPairValueRecord;
-    unsigned count = len;
-    for (unsigned i = 0; i < count; i++)
-    {
-      if (c->glyph_set->has (record->secondGlyph))
-      { record->collect_variation_indices (c, valueFormats, this); }
-
-      record = &StructAtOffset<const PairValueRecord> (record, record_size);
-    }
-  }
-
-  bool apply (hb_ot_apply_context_t *c,
-             const ValueFormat *valueFormats,
-             unsigned int pos) const
-  {
-    TRACE_APPLY (this);
-    hb_buffer_t *buffer = c->buffer;
-    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 = hb_bsearch (buffer->info[pos].codepoint,
-                                               &firstPairValueRecord,
-                                               len,
-                                               record_size);
-    if (record)
-    {
-      bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
-      bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
-      if (applied_first || applied_second)
-       buffer->unsafe_to_break (buffer->idx, pos + 1);
-      if (len2)
-       pos++;
-      buffer->idx = pos;
-      return_trace (true);
-    }
-    buffer->unsafe_to_concat (buffer->idx, pos + 1);
-    return_trace (false);
-  }
-
-  bool subset (hb_subset_context_t *c,
-              const ValueFormat valueFormats[2],
-               const ValueFormat newFormats[2]) const
-  {
-    TRACE_SUBSET (this);
-    auto snap = c->serializer->snapshot ();
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->len = 0;
-
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    unsigned len1 = valueFormats[0].get_len ();
-    unsigned len2 = valueFormats[1].get_len ();
-    unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
-
-    PairValueRecord::context_t context =
-    {
-      this,
-      valueFormats,
-      newFormats,
-      len1,
-      &glyph_map,
-      c->plan->layout_variation_idx_map
-    };
-
-    const PairValueRecord *record = &firstPairValueRecord;
-    unsigned count = len, num = 0;
-    for (unsigned i = 0; i < count; i++)
-    {
-      if (glyphset.has (record->secondGlyph)
-        && record->subset (c, &context)) num++;
-      record = &StructAtOffset<const PairValueRecord> (record, record_size);
-    }
-
-    out->len = num;
-    if (!num) c->serializer->revert (snap);
-    return_trace (num);
-  }
-
-  struct sanitize_closure_t
-  {
-    const ValueFormat *valueFormats;
-    unsigned int len1; /* valueFormats[0].get_len() */
-    unsigned int stride; /* 1 + len1 + len2 */
-  };
-
-  bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
-  {
-    TRACE_SANITIZE (this);
-    if (!(c->check_struct (this)
-       && c->check_range (&firstPairValueRecord,
-                         len,
-                         HBUINT16::static_size,
-                         closure->stride))) return_trace (false);
-
-    unsigned int count = len;
-    const PairValueRecord *record = &firstPairValueRecord;
-    return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
-                 closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride));
-  }
-
-  protected:
-  HBUINT16             len;    /* Number of PairValueRecords */
-  PairValueRecord      firstPairValueRecord;
-                               /* Array of PairValueRecords--ordered
-                                * by GlyphID of the second glyph */
-  public:
-  DEFINE_SIZE_MIN (2);
-};
-
-struct PairPosFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    return
-    + hb_zip (this+coverage, pairSet)
-    | hb_filter (*glyphs, hb_first)
-    | hb_map (hb_second)
-    | hb_map ([glyphs, this] (const Offset16To<PairSet> &_)
-             { return (this+_).intersects (glyphs, valueFormat); })
-    | hb_any
-    ;
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    if ((!valueFormat[0].has_device ()) && (!valueFormat[1].has_device ())) return;
-
-    auto it =
-    + hb_zip (this+coverage, pairSet)
-    | hb_filter (c->glyph_set, hb_first)
-    | hb_map (hb_second)
-    ;
-
-    if (!it) return;
-    + it
-    | hb_map (hb_add (this))
-    | hb_apply ([&] (const PairSet& _) { _.collect_variation_indices (c, valueFormat); })
-    ;
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-    unsigned int count = pairSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      (this+pairSet[i]).collect_glyphs (c, valueFormat);
-  }
-
-  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;
-    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
-
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
-    skippy_iter.reset (buffer->idx, 1);
-    unsigned unsafe_to;
-    if (!skippy_iter.next (&unsafe_to))
-    {
-      buffer->unsafe_to_concat (buffer->idx, unsafe_to);
-      return_trace (false);
-    }
-
-    return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx));
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->format = format;
-    out->valueFormat[0] = valueFormat[0];
-    out->valueFormat[1] = valueFormat[1];
-    if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
-    {
-      hb_pair_t<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset);
-      out->valueFormat[0] = newFormats.first;
-      out->valueFormat[1] = newFormats.second;
-    }
-
-    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
-
-    + hb_zip (this+coverage, pairSet)
-    | hb_filter (glyphset, hb_first)
-    | hb_filter ([this, c, out] (const Offset16To<PairSet>& _)
-                {
-                   auto snap = c->serializer->snapshot ();
-                  auto *o = out->pairSet.serialize_append (c->serializer);
-                  if (unlikely (!o)) return false;
-                  bool ret = o->serialize_subset (c, _, this, valueFormat, out->valueFormat);
-                  if (!ret)
-                  {
-                    out->pairSet.pop ();
-                    c->serializer->revert (snap);
-                  }
-                  return ret;
-                },
-                hb_second)
-    | hb_map (hb_first)
-    | hb_map (glyph_map)
-    | hb_sink (new_coverage)
-    ;
-
-    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
-
-    return_trace (bool (new_coverage));
-  }
-
-
-  hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const
-  {
-    unsigned len1 = valueFormat[0].get_len ();
-    unsigned len2 = valueFormat[1].get_len ();
-    unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
-
-    unsigned format1 = 0;
-    unsigned format2 = 0;
-    for (const Offset16To<PairSet>& _ :
-             + hb_zip (this+coverage, pairSet) | hb_filter (glyphset, hb_first) | hb_map (hb_second))
-    {
-      const PairSet& set = (this + _);
-      const PairValueRecord *record = &set.firstPairValueRecord;
-
-      for (unsigned i = 0; i < set.len; i++)
-      {
-        if (record->intersects (glyphset))
-        {
-          format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 ());
-          format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]));
-        }
-        record = &StructAtOffset<const PairValueRecord> (record, record_size);
-      }
-    }
-
-    return hb_pair (format1, format2);
-  }
-
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-
-    if (!c->check_struct (this)) return_trace (false);
-
-    unsigned int len1 = valueFormat[0].get_len ();
-    unsigned int len2 = valueFormat[1].get_len ();
-    PairSet::sanitize_closure_t closure =
-    {
-      valueFormat,
-      len1,
-      1 + len1 + len2
-    };
-
-    return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
-  }
-
-  protected:
-  HBUINT16     format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
-               coverage;               /* Offset to Coverage table--from
-                                        * beginning of subtable */
-  ValueFormat  valueFormat[2];         /* [0] Defines the types of data in
-                                        * ValueRecord1--for the first glyph
-                                        * in the pair--may be zero (0) */
-                                       /* [1] Defines the types of data in
-                                        * ValueRecord2--for the second glyph
-                                        * in the pair--may be zero (0) */
-  Array16OfOffset16To<PairSet>
-               pairSet;                /* Array of PairSet tables
-                                        * ordered by Coverage Index */
-  public:
-  DEFINE_SIZE_ARRAY (10, pairSet);
-};
-
-struct PairPosFormat2
-{
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    return (this+coverage).intersects (glyphs) &&
-          (this+classDef2).intersects (glyphs);
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    if (!intersects (c->glyph_set)) return;
-    if ((!valueFormat1.has_device ()) && (!valueFormat2.has_device ())) return;
-
-    hb_set_t klass1_glyphs, klass2_glyphs;
-    if (!(this+classDef1).collect_coverage (&klass1_glyphs)) return;
-    if (!(this+classDef2).collect_coverage (&klass2_glyphs)) return;
-
-    hb_set_t class1_set, class2_set;
-    for (const unsigned cp : + c->glyph_set->iter () | hb_filter (this + coverage))
-    {
-      if (!klass1_glyphs.has (cp)) class1_set.add (0);
-      else
-      {
-        unsigned klass1 = (this+classDef1).get (cp);
-        class1_set.add (klass1);
-      }
-    }
-
-    class2_set.add (0);
-    for (const unsigned cp : + c->glyph_set->iter () | hb_filter (klass2_glyphs))
-    {
-      unsigned klass2 = (this+classDef2).get (cp);
-      class2_set.add (klass2);
-    }
-
-    if (class1_set.is_empty ()
-        || class2_set.is_empty ()
-        || (class2_set.get_population() == 1 && class2_set.has(0)))
-      return;
-
-    unsigned len1 = valueFormat1.get_len ();
-    unsigned len2 = valueFormat2.get_len ();
-    const hb_array_t<const Value> values_array = values.as_array ((unsigned)class1Count * (unsigned) class2Count * (len1 + len2));
-    for (const unsigned class1_idx : class1_set.iter ())
-    {
-      for (const unsigned class2_idx : class2_set.iter ())
-      {
-       unsigned start_offset = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
-       if (valueFormat1.has_device ())
-         valueFormat1.collect_variation_indices (c, this, values_array.sub_array (start_offset, len1));
-
-       if (valueFormat2.has_device ())
-         valueFormat2.collect_variation_indices (c, this, values_array.sub_array (start_offset+len1, len2));
-      }
-    }
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-    if (unlikely (!(this+classDef2).collect_coverage (c->input))) return;
-  }
-
-  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;
-    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
-
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
-    skippy_iter.reset (buffer->idx, 1);
-    unsigned unsafe_to;
-    if (!skippy_iter.next (&unsafe_to))
-    {
-      buffer->unsafe_to_concat (buffer->idx, unsafe_to);
-      return_trace (false);
-    }
-
-    unsigned int len1 = valueFormat1.get_len ();
-    unsigned int len2 = valueFormat2.get_len ();
-    unsigned int record_len = len1 + len2;
-
-    unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
-    unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
-    if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
-    {
-      buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
-      return_trace (false);
-    }
-
-    const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
-
-    bool applied_first = false, applied_second = false;
-
-
-    /* Isolate simple kerning and apply it half to each side.
-     * Results in better cursor positinoing / underline drawing.
-     *
-     * Disabled, because causes issues... :-(
-     * https://github.com/harfbuzz/harfbuzz/issues/3408
-     * https://github.com/harfbuzz/harfbuzz/pull/3235#issuecomment-1029814978
-     */
-#ifndef HB_SPLIT_KERN
-    if (0)
-#endif
-    {
-      if (!len2)
-      {
-       const hb_direction_t dir = buffer->props.direction;
-       const bool horizontal = HB_DIRECTION_IS_HORIZONTAL (dir);
-       const bool backward = HB_DIRECTION_IS_BACKWARD (dir);
-       unsigned mask = horizontal ? ValueFormat::xAdvance : ValueFormat::yAdvance;
-       if (backward)
-         mask |= mask >> 2; /* Add eg. xPlacement in RTL. */
-       /* Add Devices. */
-       mask |= mask << 4;
-
-       if (valueFormat1 & ~mask)
-         goto bail;
-
-       /* Is simple kern. Apply value on an empty position slot,
-        * then split it between sides. */
-
-       hb_glyph_position_t pos{};
-       if (valueFormat1.apply_value (c, this, v, pos))
-       {
-         hb_position_t *src  = &pos.x_advance;
-         hb_position_t *dst1 = &buffer->cur_pos().x_advance;
-         hb_position_t *dst2 = &buffer->pos[skippy_iter.idx].x_advance;
-         unsigned i = horizontal ? 0 : 1;
-
-         hb_position_t kern  = src[i];
-         hb_position_t kern1 = kern >> 1;
-         hb_position_t kern2 = kern - kern1;
-
-         if (!backward)
-         {
-           dst1[i] += kern1;
-           dst2[i] += kern2;
-           dst2[i + 2] += kern2;
-         }
-         else
-         {
-           dst1[i] += kern1;
-           dst1[i + 2] += src[i + 2] - kern2;
-           dst2[i] += kern2;
-         }
-
-         applied_first = applied_second = kern != 0;
-         goto success;
-       }
-       goto boring;
-      }
-    }
-    bail:
-
-
-    applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos());
-    applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
-
-    success:
-    if (applied_first || applied_second)
-      buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1);
-    else
-    boring:
-      buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
-
-
-    buffer->idx = skippy_iter.idx;
-    if (len2)
-      buffer->idx++;
-
-    return_trace (true);
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->format = format;
-
-    hb_map_t klass1_map;
-    out->classDef1.serialize_subset (c, classDef1, this, &klass1_map, true, true, &(this + coverage));
-    out->class1Count = klass1_map.get_population ();
-
-    hb_map_t klass2_map;
-    out->classDef2.serialize_subset (c, classDef2, this, &klass2_map, true, false);
-    out->class2Count = klass2_map.get_population ();
-
-    unsigned len1 = valueFormat1.get_len ();
-    unsigned len2 = valueFormat2.get_len ();
-
-    hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2);
-    if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
-      newFormats = compute_effective_value_formats (klass1_map, klass2_map);
-
-    out->valueFormat1 = newFormats.first;
-    out->valueFormat2 = newFormats.second;
-
-    for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
-    {
-      for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
-      {
-        unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
-        valueFormat1.copy_values (c->serializer, newFormats.first, this, &values[idx], c->plan->layout_variation_idx_map);
-        valueFormat2.copy_values (c->serializer, newFormats.second, this, &values[idx + len1], c->plan->layout_variation_idx_map);
-      }
-    }
-
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto it =
-    + hb_iter (this+coverage)
-    | hb_filter (glyphset)
-    | hb_map_retains_sorting (glyph_map)
-    ;
-
-    out->coverage.serialize_serialize (c->serializer, it);
-    return_trace (out->class1Count && out->class2Count && bool (it));
-  }
-
-
-  hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_map_t& klass1_map,
-                                                                 const hb_map_t& klass2_map) const
-  {
-    unsigned len1 = valueFormat1.get_len ();
-    unsigned len2 = valueFormat2.get_len ();
-
-    unsigned format1 = 0;
-    unsigned format2 = 0;
-
-    for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
-    {
-      for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
-      {
-        unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
-        format1 = format1 | valueFormat1.get_effective_format (&values[idx]);
-        format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]);
-      }
-    }
-
-    return hb_pair (format1, format2);
-  }
-
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    if (!(c->check_struct (this)
-       && coverage.sanitize (c, this)
-       && classDef1.sanitize (c, this)
-       && classDef2.sanitize (c, this))) return_trace (false);
-
-    unsigned int len1 = valueFormat1.get_len ();
-    unsigned int len2 = valueFormat2.get_len ();
-    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_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));
-  }
-
-  protected:
-  HBUINT16     format;                 /* Format identifier--format = 2 */
-  Offset16To<Coverage>
-               coverage;               /* Offset to Coverage table--from
-                                        * beginning of subtable */
-  ValueFormat  valueFormat1;           /* ValueRecord definition--for the
-                                        * first glyph of the pair--may be zero
-                                        * (0) */
-  ValueFormat  valueFormat2;           /* ValueRecord definition--for the
-                                        * second glyph of the pair--may be
-                                        * zero (0) */
-  Offset16To<ClassDef>
-               classDef1;              /* Offset to ClassDef table--from
-                                        * beginning of PairPos subtable--for
-                                        * the first glyph of the pair */
-  Offset16To<ClassDef>
-               classDef2;              /* Offset to ClassDef table--from
-                                        * beginning of PairPos subtable--for
-                                        * the second glyph of the pair */
-  HBUINT16     class1Count;            /* Number of classes in ClassDef1
-                                        * table--includes Class0 */
-  HBUINT16     class2Count;            /* Number of classes in ClassDef2
-                                        * table--includes Class0 */
-  ValueRecord  values;                 /* Matrix of value pairs:
-                                        * class1-major, class2-minor,
-                                        * Each entry has value1 and value2 */
-  public:
-  DEFINE_SIZE_ARRAY (16, values);
-};
-
-struct PairPos
-{
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16             format;         /* Format identifier */
-  PairPosFormat1       format1;
-  PairPosFormat2       format2;
-  } u;
-};
-
-
-struct EntryExitRecord
-{
-  friend struct CursivePosFormat1;
-
-  bool sanitize (hb_sanitize_context_t *c, const void *base) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
-                                 const void *src_base) const
-  {
-    (src_base+entryAnchor).collect_variation_indices (c);
-    (src_base+exitAnchor).collect_variation_indices (c);
-  }
-
-  EntryExitRecord* subset (hb_subset_context_t *c,
-                           const void *src_base) const
-  {
-    TRACE_SERIALIZE (this);
-    auto *out = c->serializer->embed (this);
-    if (unlikely (!out)) return_trace (nullptr);
-
-    out->entryAnchor.serialize_subset (c, entryAnchor, src_base);
-    out->exitAnchor.serialize_subset (c, exitAnchor, src_base);
-    return_trace (out);
-  }
-
-  protected:
-  Offset16To<Anchor>
-               entryAnchor;            /* Offset to EntryAnchor table--from
-                                        * beginning of CursivePos
-                                        * subtable--may be NULL */
-  Offset16To<Anchor>
-               exitAnchor;             /* Offset to ExitAnchor table--from
-                                        * beginning of CursivePos
-                                        * subtable--may be NULL */
-  public:
-  DEFINE_SIZE_STATIC (4);
-};
-
-static void
-reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent);
-
-struct CursivePosFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return (this+coverage).intersects (glyphs); }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    + hb_zip (this+coverage, entryExitRecord)
-    | hb_filter (c->glyph_set, hb_first)
-    | hb_map (hb_second)
-    | hb_apply ([&] (const EntryExitRecord& record) { record.collect_variation_indices (c, this); })
-    ;
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
-
-  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;
-
-    const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
-    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);
-    unsigned unsafe_from;
-    if (!skippy_iter.prev (&unsafe_from))
-    {
-      buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
-      return_trace (false);
-    }
-
-    const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
-    if (!prev_record.exitAnchor)
-    {
-      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
-      return_trace (false);
-    }
-
-    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+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;
-
-    hb_position_t d;
-    /* Main-direction adjustment */
-    switch (c->direction) {
-      case HB_DIRECTION_LTR:
-       pos[i].x_advance  = roundf (exit_x) + pos[i].x_offset;
-
-       d = roundf (entry_x) + pos[j].x_offset;
-       pos[j].x_advance -= d;
-       pos[j].x_offset  -= d;
-       break;
-      case HB_DIRECTION_RTL:
-       d = roundf (exit_x) + pos[i].x_offset;
-       pos[i].x_advance -= d;
-       pos[i].x_offset  -= d;
-
-       pos[j].x_advance  = roundf (entry_x) + pos[j].x_offset;
-       break;
-      case HB_DIRECTION_TTB:
-       pos[i].y_advance  = roundf (exit_y) + pos[i].y_offset;
-
-       d = roundf (entry_y) + pos[j].y_offset;
-       pos[j].y_advance -= d;
-       pos[j].y_offset  -= d;
-       break;
-      case HB_DIRECTION_BTT:
-       d = roundf (exit_y) + pos[i].y_offset;
-       pos[i].y_advance -= d;
-       pos[i].y_offset  -= d;
-
-       pos[j].y_advance  = roundf (entry_y);
-       break;
-      case HB_DIRECTION_INVALID:
-      default:
-       break;
-    }
-
-    /* Cross-direction adjustment */
-
-    /* We attach child to parent (think graph theory and rooted trees whereas
-     * the root stays on baseline and each node aligns itself against its
-     * parent.
-     *
-     * Optimize things for the case of RightToLeft, as that's most common in
-     * Arabic. */
-    unsigned int child  = i;
-    unsigned int parent = j;
-    hb_position_t x_offset = entry_x - exit_x;
-    hb_position_t y_offset = entry_y - exit_y;
-    if  (!(c->lookup_props & LookupFlag::RightToLeft))
-    {
-      unsigned int k = child;
-      child = parent;
-      parent = k;
-      x_offset = -x_offset;
-      y_offset = -y_offset;
-    }
-
-    /* If child was already connected to someone else, walk through its old
-     * chain and reverse the link direction, such that the whole tree of its
-     * previous connection now attaches to new parent.  Watch out for case
-     * where new parent is on the path from old chain...
-     */
-    reverse_cursive_minor_offset (pos, child, c->direction, parent);
-
-    pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
-    pos[child].attach_chain() = (int) parent - (int) child;
-    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
-    if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
-      pos[child].y_offset = y_offset;
-    else
-      pos[child].x_offset = x_offset;
-
-    /* If parent was attached to child, separate them.
-     * https://github.com/harfbuzz/harfbuzz/issues/2469
-     */
-    if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain()))
-      pos[parent].attach_chain() = 0;
-
-    buffer->idx++;
-    return_trace (true);
-  }
-
-  template <typename Iterator,
-           hb_requires (hb_is_iterator (Iterator))>
-  void serialize (hb_subset_context_t *c,
-                 Iterator it,
-                 const void *src_base)
-  {
-    if (unlikely (!c->serializer->extend_min ((*this)))) return;
-    this->format = 1;
-    this->entryExitRecord.len = it.len ();
-
-    for (const EntryExitRecord& entry_record : + it
-                                              | hb_map (hb_second))
-      entry_record.subset (c, src_base);
-
-    auto glyphs =
-    + it
-    | hb_map_retains_sorting (hb_first)
-    ;
-
-    coverage.serialize_serialize (c->serializer, glyphs);
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!out)) return_trace (false);
-
-    auto it =
-    + hb_zip (this+coverage, entryExitRecord)
-    | hb_filter (glyphset, hb_first)
-    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const EntryExitRecord&> p) -> hb_pair_t<hb_codepoint_t, const EntryExitRecord&>
-                             { return hb_pair (glyph_map[p.first], p.second);})
-    ;
-
-    bool ret = bool (it);
-    out->serialize (c, it, this);
-    return_trace (ret);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
-  }
-
-  protected:
-  HBUINT16     format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
-               coverage;               /* Offset to Coverage table--from
-                                        * beginning of subtable */
-  Array16Of<EntryExitRecord>
-               entryExitRecord;        /* Array of EntryExit records--in
-                                        * Coverage Index order */
-  public:
-  DEFINE_SIZE_ARRAY (6, entryExitRecord);
-};
-
-struct CursivePos
-{
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16             format;         /* Format identifier */
-  CursivePosFormat1    format1;
-  } u;
-};
-
-
-typedef AnchorMatrix BaseArray;                /* base-major--
-                                        * in order of BaseCoverage Index--,
-                                        * mark-minor--
-                                        * ordered by class--zero-based. */
-
-static void Markclass_closure_and_remap_indexes (const Coverage  &mark_coverage,
-                                                const MarkArray &mark_array,
-                                                const hb_set_t  &glyphset,
-                                                hb_map_t*        klass_mapping /* INOUT */)
-{
-  hb_set_t orig_classes;
-
-  + hb_zip (mark_coverage, mark_array)
-  | hb_filter (glyphset, hb_first)
-  | hb_map (hb_second)
-  | hb_map (&MarkRecord::get_class)
-  | hb_sink (orig_classes)
-  ;
-
-  unsigned idx = 0;
-  for (auto klass : orig_classes.iter ())
-  {
-    if (klass_mapping->has (klass)) continue;
-    klass_mapping->set (klass, idx);
-    idx++;
-  }
-}
-
-struct MarkBasePosFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    return (this+markCoverage).intersects (glyphs) &&
-          (this+baseCoverage).intersects (glyphs);
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    + hb_zip (this+markCoverage, this+markArray)
-    | hb_filter (c->glyph_set, hb_first)
-    | hb_map (hb_second)
-    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
-    ;
-
-    hb_map_t klass_mapping;
-    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);
-
-    unsigned basecount = (this+baseArray).rows;
-    auto base_iter =
-    + hb_zip (this+baseCoverage, hb_range (basecount))
-    | hb_filter (c->glyph_set, hb_first)
-    | hb_map (hb_second)
-    ;
-
-    hb_sorted_vector_t<unsigned> base_indexes;
-    for (const unsigned row : base_iter)
-    {
-      + hb_range ((unsigned) classCount)
-      | hb_filter (klass_mapping)
-      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
-      | hb_sink (base_indexes)
-      ;
-    }
-    (this+baseArray).collect_variation_indices (c, base_indexes.iter ());
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
-    if (unlikely (!(this+baseCoverage).collect_coverage (c->input))) return;
-  }
-
-  const Coverage &get_coverage () const { return this+markCoverage; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    hb_buffer_t *buffer = c->buffer;
-    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (mark_index == NOT_COVERED)) return_trace (false);
-
-    /* Now we search backwards for a non-mark glyph */
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
-    skippy_iter.reset (buffer->idx, 1);
-    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
-    do {
-      unsigned unsafe_from;
-      if (!skippy_iter.prev (&unsafe_from))
-      {
-       buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
-       return_trace (false);
-      }
-
-      /* We only want to attach to the first of a MultipleSubst sequence.
-       * https://github.com/harfbuzz/harfbuzz/issues/740
-       * 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]) !=
-          _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx - 1]) + 1
-          ))
-       break;
-      skippy_iter.reject ();
-    } 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); }
-
-    unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint);
-    if (base_index == NOT_COVERED)
-    {
-      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
-      return_trace (false);
-    }
-
-    return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->format = format;
-
-    hb_map_t klass_mapping;
-    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
-
-    if (!klass_mapping.get_population ()) return_trace (false);
-    out->classCount = klass_mapping.get_population ();
-
-    auto mark_iter =
-    + hb_zip (this+markCoverage, this+markArray)
-    | hb_filter (glyphset, hb_first)
-    ;
-
-    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
-    + mark_iter
-    | hb_map (hb_first)
-    | hb_map (glyph_map)
-    | hb_sink (new_coverage)
-    ;
-
-    if (!out->markCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
-      return_trace (false);
-
-    out->markArray.serialize_subset (c, markArray, this,
-                                     (this+markCoverage).iter (),
-                                     &klass_mapping);
-
-    unsigned basecount = (this+baseArray).rows;
-    auto base_iter =
-    + hb_zip (this+baseCoverage, hb_range (basecount))
-    | hb_filter (glyphset, hb_first)
-    ;
-
-    new_coverage.reset ();
-    + base_iter
-    | hb_map (hb_first)
-    | hb_map (glyph_map)
-    | hb_sink (new_coverage)
-    ;
-
-    if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
-      return_trace (false);
-
-    hb_sorted_vector_t<unsigned> base_indexes;
-    for (const unsigned row : + base_iter
-                             | hb_map (hb_second))
-    {
-      + hb_range ((unsigned) classCount)
-      | hb_filter (klass_mapping)
-      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
-      | hb_sink (base_indexes)
-      ;
-    }
-
-    out->baseArray.serialize_subset (c, baseArray, this,
-                                     base_iter.len (),
-                                     base_indexes.iter ());
-
-    return_trace (true);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-                 markCoverage.sanitize (c, this) &&
-                 baseCoverage.sanitize (c, this) &&
-                 markArray.sanitize (c, this) &&
-                 baseArray.sanitize (c, this, (unsigned int) classCount));
-  }
-
-  protected:
-  HBUINT16     format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
-               markCoverage;           /* Offset to MarkCoverage table--from
-                                        * beginning of MarkBasePos subtable */
-  Offset16To<Coverage>
-               baseCoverage;           /* Offset to BaseCoverage table--from
-                                        * beginning of MarkBasePos subtable */
-  HBUINT16     classCount;             /* Number of classes defined for marks */
-  Offset16To<MarkArray>
-               markArray;              /* Offset to MarkArray table--from
-                                        * beginning of MarkBasePos subtable */
-  Offset16To<BaseArray>
-               baseArray;              /* Offset to BaseArray table--from
-                                        * beginning of MarkBasePos subtable */
-  public:
-  DEFINE_SIZE_STATIC (12);
-};
-
-struct MarkBasePos
-{
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16             format;         /* Format identifier */
-  MarkBasePosFormat1   format1;
-  } u;
-};
-
-
-typedef AnchorMatrix LigatureAttach;   /* component-major--
-                                        * in order of writing direction--,
-                                        * mark-minor--
-                                        * ordered by class--zero-based. */
-
-/* Array of LigatureAttach tables ordered by LigatureCoverage Index */
-struct LigatureArray : List16OfOffset16To<LigatureAttach>
-{
-  template <typename Iterator,
-           hb_requires (hb_is_iterator (Iterator))>
-  bool subset (hb_subset_context_t *c,
-               Iterator                    coverage,
-              unsigned             class_count,
-              const hb_map_t      *klass_mapping) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-
-    auto *out = c->serializer->start_embed (this);
-    if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
-
-    for (const auto _ : + hb_zip (coverage, *this)
-                 | hb_filter (glyphset, hb_first))
-    {
-      auto *matrix = out->serialize_append (c->serializer);
-      if (unlikely (!matrix)) return_trace (false);
-
-      const LigatureAttach& src = (this + _.second);
-      auto indexes =
-          + hb_range (src.rows * class_count)
-          | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
-          ;
-      matrix->serialize_subset (c,
-                               _.second,
-                               this,
-                                src.rows,
-                                indexes);
-    }
-    return_trace (this->len);
-  }
-};
-
-struct MarkLigPosFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    return (this+markCoverage).intersects (glyphs) &&
-          (this+ligatureCoverage).intersects (glyphs);
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    + hb_zip (this+markCoverage, this+markArray)
-    | hb_filter (c->glyph_set, hb_first)
-    | hb_map (hb_second)
-    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
-    ;
-
-    hb_map_t klass_mapping;
-    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);
-
-    unsigned ligcount = (this+ligatureArray).len;
-    auto lig_iter =
-    + hb_zip (this+ligatureCoverage, hb_range (ligcount))
-    | hb_filter (c->glyph_set, hb_first)
-    | hb_map (hb_second)
-    ;
-
-    const LigatureArray& lig_array = this+ligatureArray;
-    for (const unsigned i : lig_iter)
-    {
-      hb_sorted_vector_t<unsigned> lig_indexes;
-      unsigned row_count = lig_array[i].rows;
-      for (unsigned row : + hb_range (row_count))
-      {
-       + hb_range ((unsigned) classCount)
-       | hb_filter (klass_mapping)
-       | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
-       | hb_sink (lig_indexes)
-       ;
-      }
-
-      lig_array[i].collect_variation_indices (c, lig_indexes.iter ());
-    }
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
-    if (unlikely (!(this+ligatureCoverage).collect_coverage (c->input))) return;
-  }
-
-  const Coverage &get_coverage () const { return this+markCoverage; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    hb_buffer_t *buffer = c->buffer;
-    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (mark_index == NOT_COVERED)) return_trace (false);
-
-    /* Now we search backwards for a non-mark glyph */
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
-    skippy_iter.reset (buffer->idx, 1);
-    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
-    unsigned unsafe_from;
-    if (!skippy_iter.prev (&unsafe_from))
-    {
-      buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
-      return_trace (false);
-    }
-
-    /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
-    //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
-
-    unsigned int j = skippy_iter.idx;
-    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
-    if (lig_index == NOT_COVERED)
-    {
-      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
-      return_trace (false);
-    }
-
-    const LigatureArray& lig_array = this+ligatureArray;
-    const LigatureAttach& lig_attach = lig_array[lig_index];
-
-    /* Find component to attach to */
-    unsigned int comp_count = lig_attach.rows;
-    if (unlikely (!comp_count))
-    {
-      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
-      return_trace (false);
-    }
-
-    /* We must now check whether the ligature ID of the current mark glyph
-     * is identical to the ligature ID of the found ligature.  If yes, we
-     * can directly use the component index.  If not, we attach the mark
-     * glyph to the last component of the ligature. */
-    unsigned int comp_index;
-    unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
-    unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
-    unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
-    if (lig_id && lig_id == mark_id && mark_comp > 0)
-      comp_index = hb_min (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
-    else
-      comp_index = comp_count - 1;
-
-    return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->format = format;
-
-    hb_map_t klass_mapping;
-    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
-
-    if (!klass_mapping.get_population ()) return_trace (false);
-    out->classCount = klass_mapping.get_population ();
-
-    auto mark_iter =
-    + hb_zip (this+markCoverage, this+markArray)
-    | hb_filter (glyphset, hb_first)
-    ;
-
-    auto new_mark_coverage =
-    + mark_iter
-    | hb_map_retains_sorting (hb_first)
-    | hb_map_retains_sorting (glyph_map)
-    ;
-
-    if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage))
-      return_trace (false);
-
-    out->markArray.serialize_subset (c, markArray, this,
-                                     (this+markCoverage).iter (),
-                                     &klass_mapping);
-
-    auto new_ligature_coverage =
-    + hb_iter (this + ligatureCoverage)
-    | hb_filter (glyphset)
-    | hb_map_retains_sorting (glyph_map)
-    ;
-
-    if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage))
-      return_trace (false);
-
-    out->ligatureArray.serialize_subset (c, ligatureArray, this,
-                                         hb_iter (this+ligatureCoverage), classCount, &klass_mapping);
-
-    return_trace (true);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-                 markCoverage.sanitize (c, this) &&
-                 ligatureCoverage.sanitize (c, this) &&
-                 markArray.sanitize (c, this) &&
-                 ligatureArray.sanitize (c, this, (unsigned int) classCount));
-  }
-
-  protected:
-  HBUINT16     format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
-               markCoverage;           /* Offset to Mark Coverage table--from
-                                        * beginning of MarkLigPos subtable */
-  Offset16To<Coverage>
-               ligatureCoverage;       /* Offset to Ligature Coverage
-                                        * table--from beginning of MarkLigPos
-                                        * subtable */
-  HBUINT16     classCount;             /* Number of defined mark classes */
-  Offset16To<MarkArray>
-               markArray;              /* Offset to MarkArray table--from
-                                        * beginning of MarkLigPos subtable */
-  Offset16To<LigatureArray>
-               ligatureArray;          /* Offset to LigatureArray table--from
-                                        * beginning of MarkLigPos subtable */
-  public:
-  DEFINE_SIZE_STATIC (12);
-};
-
-
-struct MarkLigPos
-{
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16             format;         /* Format identifier */
-  MarkLigPosFormat1    format1;
-  } u;
-};
-
-
-typedef AnchorMatrix Mark2Array;       /* mark2-major--
-                                        * in order of Mark2Coverage Index--,
-                                        * mark1-minor--
-                                        * ordered by class--zero-based. */
-
-struct MarkMarkPosFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    return (this+mark1Coverage).intersects (glyphs) &&
-          (this+mark2Coverage).intersects (glyphs);
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    + hb_zip (this+mark1Coverage, this+mark1Array)
-    | hb_filter (c->glyph_set, hb_first)
-    | hb_map (hb_second)
-    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+mark1Array)); })
-    ;
-
-    hb_map_t klass_mapping;
-    Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, *c->glyph_set, &klass_mapping);
-
-    unsigned mark2_count = (this+mark2Array).rows;
-    auto mark2_iter =
-    + hb_zip (this+mark2Coverage, hb_range (mark2_count))
-    | hb_filter (c->glyph_set, hb_first)
-    | hb_map (hb_second)
-    ;
-
-    hb_sorted_vector_t<unsigned> mark2_indexes;
-    for (const unsigned row : mark2_iter)
-    {
-      + hb_range ((unsigned) classCount)
-      | hb_filter (klass_mapping)
-      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
-      | hb_sink (mark2_indexes)
-      ;
-    }
-    (this+mark2Array).collect_variation_indices (c, mark2_indexes.iter ());
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+mark1Coverage).collect_coverage (c->input))) return;
-    if (unlikely (!(this+mark2Coverage).collect_coverage (c->input))) return;
-  }
-
-  const Coverage &get_coverage () const { return this+mark1Coverage; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    hb_buffer_t *buffer = c->buffer;
-    unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (mark1_index == NOT_COVERED)) return_trace (false);
-
-    /* now we search backwards for a suitable mark glyph until a non-mark glyph */
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
-    skippy_iter.reset (buffer->idx, 1);
-    skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
-    unsigned unsafe_from;
-    if (!skippy_iter.prev (&unsafe_from))
-    {
-      buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
-      return_trace (false);
-    }
-
-    if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]))
-    {
-      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
-      return_trace (false);
-    }
-
-    unsigned int j = skippy_iter.idx;
-
-    unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
-    unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
-    unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
-    unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
-
-    if (likely (id1 == id2))
-    {
-      if (id1 == 0) /* Marks belonging to the same base. */
-       goto good;
-      else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
-       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. */
-      if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
-       goto good;
-    }
-
-    /* Didn't match. */
-    buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
-    return_trace (false);
-
-    good:
-    unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
-    if (mark2_index == NOT_COVERED)
-    {
-      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
-      return_trace (false);
-    }
-
-    return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->format = format;
-
-    hb_map_t klass_mapping;
-    Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, glyphset, &klass_mapping);
-
-    if (!klass_mapping.get_population ()) return_trace (false);
-    out->classCount = klass_mapping.get_population ();
-
-    auto mark1_iter =
-    + hb_zip (this+mark1Coverage, this+mark1Array)
-    | hb_filter (glyphset, hb_first)
-    ;
-
-    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
-    + mark1_iter
-    | hb_map (hb_first)
-    | hb_map (glyph_map)
-    | hb_sink (new_coverage)
-    ;
-
-    if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
-      return_trace (false);
-
-    out->mark1Array.serialize_subset (c, mark1Array, this,
-                                      (this+mark1Coverage).iter (),
-                                      &klass_mapping);
-
-    unsigned mark2count = (this+mark2Array).rows;
-    auto mark2_iter =
-    + hb_zip (this+mark2Coverage, hb_range (mark2count))
-    | hb_filter (glyphset, hb_first)
-    ;
-
-    new_coverage.reset ();
-    + mark2_iter
-    | hb_map (hb_first)
-    | hb_map (glyph_map)
-    | hb_sink (new_coverage)
-    ;
-
-    if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
-      return_trace (false);
-
-    hb_sorted_vector_t<unsigned> mark2_indexes;
-    for (const unsigned row : + mark2_iter
-                             | hb_map (hb_second))
-    {
-      + hb_range ((unsigned) classCount)
-      | hb_filter (klass_mapping)
-      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
-      | hb_sink (mark2_indexes)
-      ;
-    }
-
-    out->mark2Array.serialize_subset (c, mark2Array, this, mark2_iter.len (), mark2_indexes.iter ());
-
-    return_trace (true);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-                 mark1Coverage.sanitize (c, this) &&
-                 mark2Coverage.sanitize (c, this) &&
-                 mark1Array.sanitize (c, this) &&
-                 mark2Array.sanitize (c, this, (unsigned int) classCount));
-  }
-
-  protected:
-  HBUINT16     format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
-               mark1Coverage;          /* Offset to Combining Mark1 Coverage
-                                        * table--from beginning of MarkMarkPos
-                                        * subtable */
-  Offset16To<Coverage>
-               mark2Coverage;          /* Offset to Combining Mark2 Coverage
-                                        * table--from beginning of MarkMarkPos
-                                        * subtable */
-  HBUINT16     classCount;             /* Number of defined mark classes */
-  Offset16To<MarkArray>
-               mark1Array;             /* Offset to Mark1Array table--from
-                                        * beginning of MarkMarkPos subtable */
-  Offset16To<Mark2Array>
-               mark2Array;             /* Offset to Mark2Array table--from
-                                        * beginning of MarkMarkPos subtable */
-  public:
-  DEFINE_SIZE_STATIC (12);
-};
-
-struct MarkMarkPos
-{
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16             format;         /* Format identifier */
-  MarkMarkPosFormat1   format1;
-  } u;
-};
-
-
-struct ContextPos : Context {};
-
-struct ChainContextPos : ChainContext {};
-
-struct ExtensionPos : Extension<ExtensionPos>
-{
-  typedef struct PosLookupSubTable SubTable;
-};
-
-
-
-/*
- * PosLookup
- */
-
-
-struct PosLookupSubTable
-{
-  friend struct Lookup;
-  friend struct PosLookup;
-
-  enum Type {
-    Single             = 1,
-    Pair               = 2,
-    Cursive            = 3,
-    MarkBase           = 4,
-    MarkLig            = 5,
-    MarkMark           = 6,
-    Context            = 7,
-    ChainContext       = 8,
-    Extension          = 9
-  };
-
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, lookup_type);
-    switch (lookup_type) {
-    case Single:               return_trace (u.single.dispatch (c, std::forward<Ts> (ds)...));
-    case Pair:                 return_trace (u.pair.dispatch (c, std::forward<Ts> (ds)...));
-    case Cursive:              return_trace (u.cursive.dispatch (c, std::forward<Ts> (ds)...));
-    case MarkBase:             return_trace (u.markBase.dispatch (c, std::forward<Ts> (ds)...));
-    case MarkLig:              return_trace (u.markLig.dispatch (c, std::forward<Ts> (ds)...));
-    case MarkMark:             return_trace (u.markMark.dispatch (c, std::forward<Ts> (ds)...));
-    case Context:              return_trace (u.context.dispatch (c, std::forward<Ts> (ds)...));
-    case ChainContext:         return_trace (u.chainContext.dispatch (c, std::forward<Ts> (ds)...));
-    case Extension:            return_trace (u.extension.dispatch (c, std::forward<Ts> (ds)...));
-    default:                   return_trace (c->default_return_value ());
-    }
-  }
-
-  bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const
-  {
-    hb_intersects_context_t c (glyphs);
-    return dispatch (&c, lookup_type);
-  }
-
-  protected:
-  union {
-  SinglePos            single;
-  PairPos              pair;
-  CursivePos           cursive;
-  MarkBasePos          markBase;
-  MarkLigPos           markLig;
-  MarkMarkPos          markMark;
-  ContextPos           context;
-  ChainContextPos      chainContext;
-  ExtensionPos         extension;
-  } u;
-  public:
-  DEFINE_SIZE_MIN (0);
-};
-
-
-struct PosLookup : Lookup
-{
-  typedef struct PosLookupSubTable SubTable;
-
-  const SubTable& get_subtable (unsigned int i) const
-  { return Lookup::get_subtable<SubTable> (i); }
-
-  bool is_reverse () const
-  {
-    return false;
-  }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    return_trace (dispatch (c));
-  }
-
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    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); }
-
-  hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
-  {
-    if (c->is_lookup_visited (this_index))
-      return hb_closure_lookups_context_t::default_return_value ();
-
-    c->set_lookup_visited (this_index);
-    if (!intersects (c->glyphs))
-    {
-      c->set_lookup_inactive (this_index);
-      return hb_closure_lookups_context_t::default_return_value ();
-    }
-    c->set_recurse_func (dispatch_closure_lookups_recurse_func);
-
-    hb_closure_lookups_context_t::return_t ret = dispatch (c);
-    return ret;
-  }
-
-  template <typename set_t>
-  void collect_coverage (set_t *glyphs) const
-  {
-    hb_collect_coverage_context_t<set_t> c (glyphs);
-    dispatch (&c);
-  }
-
-  static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
-
-  template <typename context_t>
-  static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
-
-  HB_INTERNAL static hb_closure_lookups_context_t::return_t dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index);
-
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); }
-
-  bool subset (hb_subset_context_t *c) const
-  { return Lookup::subset<SubTable> (c); }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  { return Lookup::sanitize<SubTable> (c); }
-};
-
-/*
- * GPOS -- Glyph Positioning
- * https://docs.microsoft.com/en-us/typography/opentype/spec/gpos
- */
-
-struct GPOS : GSUBGPOS
-{
-  static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS;
-
-  const PosLookup& get_lookup (unsigned int i) const
-  { return static_cast<const 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);
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    hb_subset_layout_context_t l (c, tableTag, c->plan->gpos_lookups, c->plan->gpos_langsys, c->plan->gpos_features);
-    return GSUBGPOS::subset<PosLookup> (&l);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  { return GSUBGPOS::sanitize<PosLookup> (c); }
-
-  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
-                                  hb_face_t *face) const;
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    for (unsigned i = 0; i < GSUBGPOS::get_lookup_count (); i++)
-    {
-      if (!c->gpos_lookups->has (i)) continue;
-      const PosLookup &l = get_lookup (i);
-      l.dispatch (c);
-    }
-  }
-
-  void closure_lookups (hb_face_t      *face,
-                       const hb_set_t *glyphs,
-                       hb_set_t       *lookup_indexes /* IN/OUT */) const
-  { GSUBGPOS::closure_lookups<PosLookup> (face, glyphs, lookup_indexes); }
-
-  typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t;
-};
-
-
-static void
-reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
-{
-  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
-  if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
-    return;
-
-  pos[i].attach_chain() = 0;
-
-  unsigned int j = (int) i + chain;
-
-  /* Stop if we see new parent in the chain. */
-  if (j == new_parent)
-    return;
-
-  reverse_cursive_minor_offset (pos, j, direction, new_parent);
-
-  if (HB_DIRECTION_IS_HORIZONTAL (direction))
-    pos[j].y_offset = -pos[i].y_offset;
-  else
-    pos[j].x_offset = -pos[i].x_offset;
-
-  pos[j].attach_chain() = -chain;
-  pos[j].attach_type() = type;
-}
-static void
-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. */
-  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
-  if (likely (!chain))
-    return;
-
-  pos[i].attach_chain() = 0;
-
-  unsigned int j = (int) i + chain;
-
-  if (unlikely (j >= len))
-    return;
-
-  propagate_attachment_offsets (pos, len, j, direction);
-
-  assert (!!(type & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE));
-
-  if (type & ATTACH_TYPE_CURSIVE)
-  {
-    if (HB_DIRECTION_IS_HORIZONTAL (direction))
-      pos[i].y_offset += pos[j].y_offset;
-    else
-      pos[i].x_offset += pos[j].x_offset;
-  }
-  else /*if (type & ATTACH_TYPE_MARK)*/
-  {
-    pos[i].x_offset += pos[j].x_offset;
-    pos[i].y_offset += pos[j].y_offset;
-
-    assert (j < i);
-    if (HB_DIRECTION_IS_FORWARD (direction))
-      for (unsigned int k = j; k < i; k++) {
-       pos[i].x_offset -= pos[k].x_advance;
-       pos[i].y_offset -= pos[k].y_advance;
-      }
-    else
-      for (unsigned int k = j + 1; k < i + 1; k++) {
-       pos[i].x_offset += pos[k].x_advance;
-       pos[i].y_offset += pos[k].y_advance;
-      }
-  }
-}
-
-void
-GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
-{
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
-}
-
-void
-GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
-{
-  //_hb_buffer_assert_gsubgpos_vars (buffer);
-}
-
-void
-GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
-{
-  _hb_buffer_assert_gsubgpos_vars (buffer);
-
-  unsigned int len;
-  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
-  hb_direction_t direction = buffer->props.direction;
-
-  /* Handle attachments */
-  if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
-    for (unsigned i = 0; i < len; i++)
-      propagate_attachment_offsets (pos, len, i, direction);
-
-  if (unlikely (font->slant))
-  {
-    for (unsigned i = 0; i < len; i++)
-      if (unlikely (pos[i].y_offset))
-        pos[i].x_offset += _hb_roundf (font->slant_xy * pos[i].y_offset);
-  }
-}
-
-
-struct GPOS_accelerator_t : GPOS::accelerator_t {
-  GPOS_accelerator_t (hb_face_t *face) : GPOS::accelerator_t (face) {}
-};
+#include "OT/Layout/GPOS/GPOS.hh"
 
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
 
+// TODO(garretrieger): Move into new layout directory.
 /* Out-of-class implementation for methods recursing */
-
 #ifndef HB_NO_OT_LAYOUT
 template <typename context_t>
 /*static*/ typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
@@ -3121,27 +45,36 @@ template <typename context_t>
   return l.dispatch (c);
 }
 
-/*static*/ inline hb_closure_lookups_context_t::return_t PosLookup::dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index)
+template <>
+inline hb_closure_lookups_context_t::return_t
+PosLookup::dispatch_recurse_func<hb_closure_lookups_context_t> (hb_closure_lookups_context_t *c, unsigned this_index)
 {
   const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (this_index);
   return l.closure_lookups (c, this_index);
 }
 
-/*static*/ bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
+template <>
+inline bool PosLookup::dispatch_recurse_func<hb_ot_apply_context_t> (hb_ot_apply_context_t *c, unsigned int lookup_index)
 {
-  const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index);
+  auto *gpos = c->face->table.GPOS.get_relaxed ();
+  const PosLookup &l = gpos->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);
   c->set_lookup_props (l.get_props ());
-  bool ret = l.dispatch (c);
+
+  bool ret = false;
+  auto *accel = gpos->get_accel (lookup_index);
+  ret = accel && accel->apply (c, l.get_subtable_count (), false);
+
   c->set_lookup_index (saved_lookup_index);
   c->set_lookup_props (saved_lookup_props);
   return ret;
 }
 #endif
 
-
+} /* namespace GPOS_impl */
+} /* namespace Layout */
 } /* namespace OT */
 
 
index 0b0bc54..fd8a68b 100644 (file)
 #ifndef HB_OT_LAYOUT_GSUB_TABLE_HH
 #define HB_OT_LAYOUT_GSUB_TABLE_HH
 
-#include "hb-ot-layout-gsubgpos.hh"
-
+#include "OT/Layout/GSUB/GSUB.hh"
 
 namespace OT {
+namespace Layout {
+namespace GSUB_impl {
 
-typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
-
-template<typename Iterator>
-static void SingleSubst_serialize (hb_serialize_context_t *c,
-                                  Iterator it);
-
-
-struct SingleSubstFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return (this+coverage).intersects (glyphs); }
-
-  bool may_have_non_1to1 () const
-  { return false; }
-
-  void closure (hb_closure_context_t *c) const
-  {
-    unsigned d = deltaGlyphID;
-
-    + hb_iter (this+coverage)
-    | hb_filter (c->parent_active_glyphs ())
-    | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
-    | hb_sink (c->output)
-    ;
-
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-    unsigned d = deltaGlyphID;
-    + hb_iter (this+coverage)
-    | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
-    | hb_sink (c->output)
-    ;
-  }
-
-  const Coverage &get_coverage () const { return this+coverage; }
-
-  bool would_apply (hb_would_apply_context_t *c) const
-  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
-
-  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);
-    if (likely (index == NOT_COVERED)) return_trace (false);
-
-    /* According to the Adobe Annotated OpenType Suite, result is always
-     * limited to 16bit. */
-    glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
-    c->replace_glyph (glyph_id);
-
-    return_trace (true);
-  }
-
-  template<typename Iterator,
-          hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
-  bool serialize (hb_serialize_context_t *c,
-                 Iterator glyphs,
-                 unsigned delta)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (this))) return_trace (false);
-    if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
-    c->check_assign (deltaGlyphID, delta, HB_SERIALIZE_ERROR_INT_OVERFLOW);
-    return_trace (true);
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    hb_codepoint_t delta = deltaGlyphID;
-
-    auto it =
-    + hb_iter (this+coverage)
-    | hb_filter (glyphset)
-    | hb_map_retains_sorting ([&] (hb_codepoint_t g) {
-                               return hb_codepoint_pair_t (g,
-                                                           (g + delta) & 0xFFFF); })
-    | hb_filter (glyphset, hb_second)
-    | hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t
-                             { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
-    ;
-
-    bool ret = bool (it);
-    SingleSubst_serialize (c->serializer, it);
-    return_trace (ret);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
-  }
-
-  protected:
-  HBUINT16     format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
-               coverage;               /* Offset to Coverage table--from
-                                        * beginning of Substitution table */
-  HBUINT16     deltaGlyphID;           /* Add to original GlyphID to get
-                                        * substitute GlyphID, modulo 0x10000 */
-  public:
-  DEFINE_SIZE_STATIC (6);
-};
-
-struct SingleSubstFormat2
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return (this+coverage).intersects (glyphs); }
-
-  bool may_have_non_1to1 () const
-  { return false; }
-
-  void closure (hb_closure_context_t *c) const
-  {
-    + hb_zip (this+coverage, substitute)
-    | hb_filter (c->parent_active_glyphs (), hb_first)
-    | hb_map (hb_second)
-    | hb_sink (c->output)
-    ;
-
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-    + hb_zip (this+coverage, substitute)
-    | hb_map (hb_second)
-    | hb_sink (c->output)
-    ;
-  }
-
-  const Coverage &get_coverage () const { return this+coverage; }
-
-  bool would_apply (hb_would_apply_context_t *c) const
-  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    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);
-
-    c->replace_glyph (substitute[index]);
-
-    return_trace (true);
-  }
-
-  template<typename Iterator,
-          hb_requires (hb_is_sorted_source_of (Iterator,
-                                               hb_codepoint_pair_t))>
-  bool serialize (hb_serialize_context_t *c,
-                 Iterator it)
-  {
-    TRACE_SERIALIZE (this);
-    auto substitutes =
-      + it
-      | hb_map (hb_second)
-      ;
-    auto glyphs =
-      + it
-      | hb_map_retains_sorting (hb_first)
-      ;
-    if (unlikely (!c->extend_min (this))) return_trace (false);
-    if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
-    if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
-    return_trace (true);
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto it =
-    + hb_zip (this+coverage, substitute)
-    | hb_filter (glyphset, hb_first)
-    | hb_filter (glyphset, hb_second)
-    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t
-                             { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
-    ;
-
-    bool ret = bool (it);
-    SingleSubst_serialize (c->serializer, it);
-    return_trace (ret);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
-  }
-
-  protected:
-  HBUINT16     format;                 /* Format identifier--format = 2 */
-  Offset16To<Coverage>
-               coverage;               /* Offset to Coverage table--from
-                                        * beginning of Substitution table */
-  Array16Of<HBGlyphID16>
-               substitute;             /* Array of substitute
-                                        * GlyphIDs--ordered by Coverage Index */
-  public:
-  DEFINE_SIZE_ARRAY (6, substitute);
-};
-
-struct SingleSubst
-{
-
-  template<typename Iterator,
-          hb_requires (hb_is_sorted_source_of (Iterator,
-                                               const hb_codepoint_pair_t))>
-  bool serialize (hb_serialize_context_t *c,
-                 Iterator glyphs)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (u.format))) return_trace (false);
-    unsigned format = 2;
-    unsigned delta = 0;
-    if (glyphs)
-    {
-      format = 1;
-      auto get_delta = [=] (hb_codepoint_pair_t _)
-                      { return (unsigned) (_.second - _.first) & 0xFFFF; };
-      delta = get_delta (*glyphs);
-      if (!hb_all (++(+glyphs), delta, get_delta)) format = 2;
-    }
-    u.format = format;
-    switch (u.format) {
-    case 1: return_trace (u.format1.serialize (c,
-                                              + glyphs
-                                              | hb_map_retains_sorting (hb_first),
-                                              delta));
-    case 2: return_trace (u.format2.serialize (c, glyphs));
-    default:return_trace (false);
-    }
-  }
-
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16             format;         /* Format identifier */
-  SingleSubstFormat1   format1;
-  SingleSubstFormat2   format2;
-  } u;
-};
-
-template<typename Iterator>
-static void
-SingleSubst_serialize (hb_serialize_context_t *c,
-                      Iterator it)
-{ c->start_embed<SingleSubst> ()->serialize (c, it); }
-
-struct Sequence
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return hb_all (substitute, glyphs); }
-
-  void closure (hb_closure_context_t *c) const
-  { 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); }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    unsigned int count = substitute.len;
-
-    /* Special-case to make it in-place and not consider this
-     * as a "multiplied" substitution. */
-    if (unlikely (count == 1))
-    {
-      c->replace_glyph (substitute.arrayZ[0]);
-      return_trace (true);
-    }
-    /* Spec disallows this, but Uniscribe allows it.
-     * https://github.com/harfbuzz/harfbuzz/issues/253 */
-    else if (unlikely (count == 0))
-    {
-      c->buffer->delete_glyph ();
-      return_trace (true);
-    }
-
-    unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
-                        HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
-    unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur());
-
-    for (unsigned int i = 0; i < count; i++)
-    {
-      /* If is attached to a ligature, don't disturb that.
-       * https://github.com/harfbuzz/harfbuzz/issues/3069 */
-      if (!lig_id)
-       _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
-      c->output_glyph_for_component (substitute.arrayZ[i], klass);
-    }
-    c->buffer->skip_glyph ();
-
-    return_trace (true);
-  }
-
-  template <typename Iterator,
-           hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
-  bool serialize (hb_serialize_context_t *c,
-                 Iterator subst)
-  {
-    TRACE_SERIALIZE (this);
-    return_trace (substitute.serialize (c, subst));
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    if (!intersects (&glyphset)) return_trace (false);
-
-    auto it =
-    + hb_iter (substitute)
-    | hb_map (glyph_map)
-    ;
-
-    auto *out = c->serializer->start_embed (*this);
-    return_trace (out->serialize (c->serializer, it));
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (substitute.sanitize (c));
-  }
-
-  protected:
-  Array16Of<HBGlyphID16>
-               substitute;             /* String of GlyphIDs to substitute */
-  public:
-  DEFINE_SIZE_ARRAY (2, substitute);
-};
-
-struct MultipleSubstFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return (this+coverage).intersects (glyphs); }
-
-  bool may_have_non_1to1 () const
-  { return true; }
-
-  void closure (hb_closure_context_t *c) const
-  {
-    + hb_zip (this+coverage, sequence)
-    | hb_filter (c->parent_active_glyphs (), hb_first)
-    | hb_map (hb_second)
-    | hb_map (hb_add (this))
-    | hb_apply ([c] (const Sequence &_) { _.closure (c); })
-    ;
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-    + hb_zip (this+coverage, sequence)
-    | hb_map (hb_second)
-    | hb_map (hb_add (this))
-    | hb_apply ([c] (const Sequence &_) { _.collect_glyphs (c); })
-    ;
-  }
-
-  const Coverage &get_coverage () const { return this+coverage; }
-
-  bool would_apply (hb_would_apply_context_t *c) const
-  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-
-    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
-
-    return_trace ((this+sequence[index]).apply (c));
-  }
-
-  bool serialize (hb_serialize_context_t *c,
-                 hb_sorted_array_t<const HBGlyphID16> glyphs,
-                 hb_array_t<const unsigned int> substitute_len_list,
-                 hb_array_t<const HBGlyphID16> substitute_glyphs_list)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (this))) return_trace (false);
-    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_serialize (c, substitute_glyphs_list.sub_array (0, substitute_len))))
-       return_trace (false);
-      substitute_glyphs_list += substitute_len;
-    }
-    return_trace (coverage.serialize_serialize (c, glyphs));
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->format = format;
-
-    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
-    + hb_zip (this+coverage, sequence)
-    | hb_filter (glyphset, hb_first)
-    | hb_filter (subset_offset_array (c, out->sequence, this), hb_second)
-    | hb_map (hb_first)
-    | hb_map (glyph_map)
-    | hb_sink (new_coverage)
-    ;
-    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
-    return_trace (bool (new_coverage));
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
-  }
-
-  protected:
-  HBUINT16     format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
-               coverage;               /* Offset to Coverage table--from
-                                        * beginning of Substitution table */
-  Array16OfOffset16To<Sequence>
-               sequence;               /* Array of Sequence tables
-                                        * ordered by Coverage Index */
-  public:
-  DEFINE_SIZE_ARRAY (6, sequence);
-};
-
-struct MultipleSubst
-{
-  bool serialize (hb_serialize_context_t *c,
-                 hb_sorted_array_t<const HBGlyphID16> glyphs,
-                 hb_array_t<const unsigned int> substitute_len_list,
-                 hb_array_t<const HBGlyphID16> substitute_glyphs_list)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (u.format))) return_trace (false);
-    unsigned int format = 1;
-    u.format = format;
-    switch (u.format) {
-    case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list));
-    default:return_trace (false);
-    }
-  }
-
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16             format;         /* Format identifier */
-  MultipleSubstFormat1 format1;
-  } u;
-};
-
-struct AlternateSet
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return hb_any (alternates, glyphs); }
-
-  void closure (hb_closure_context_t *c) const
-  { c->output->add_array (alternates.arrayZ, alternates.len); }
-
-  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_VALUE, randomize feature if it is the rand feature. */
-    if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
-    {
-      /* Maybe we can do better than unsafe-to-break all; but since we are
-       * changing random state, it would be hard to track that.  Good 'nough. */
-      c->buffer->unsafe_to_break (0, c->buffer->len);
-      alt_index = c->random_number () % count + 1;
-    }
-
-    if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
-
-    c->replace_glyph (alternates[alt_index - 1]);
-
-    return_trace (true);
-  }
-
-  unsigned
-  get_alternates (unsigned        start_offset,
-                 unsigned       *alternate_count  /* IN/OUT.  May be NULL. */,
-                 hb_codepoint_t *alternate_glyphs /* OUT.     May be NULL. */) const
-  {
-    if (alternates.len && alternate_count)
-    {
-      + alternates.sub_array (start_offset, alternate_count)
-      | hb_sink (hb_array (alternate_glyphs, *alternate_count))
-      ;
-    }
-    return alternates.len;
-  }
-
-  template <typename Iterator,
-           hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
-  bool serialize (hb_serialize_context_t *c,
-                 Iterator alts)
-  {
-    TRACE_SERIALIZE (this);
-    return_trace (alternates.serialize (c, alts));
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto it =
-      + hb_iter (alternates)
-      | hb_filter (glyphset)
-      | hb_map (glyph_map)
-      ;
-
-    auto *out = c->serializer->start_embed (*this);
-    return_trace (out->serialize (c->serializer, it) &&
-                 out->alternates);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (alternates.sanitize (c));
-  }
-
-  protected:
-  Array16Of<HBGlyphID16>
-               alternates;             /* Array of alternate GlyphIDs--in
-                                        * arbitrary order */
-  public:
-  DEFINE_SIZE_ARRAY (2, alternates);
-};
-
-struct AlternateSubstFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return (this+coverage).intersects (glyphs); }
-
-  bool may_have_non_1to1 () const
-  { return false; }
-
-  void closure (hb_closure_context_t *c) const
-  {
-    + hb_zip (this+coverage, alternateSet)
-    | hb_filter (c->parent_active_glyphs (), hb_first)
-    | hb_map (hb_second)
-    | hb_map (hb_add (this))
-    | hb_apply ([c] (const AlternateSet &_) { _.closure (c); })
-    ;
-
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-    + hb_zip (this+coverage, alternateSet)
-    | hb_map (hb_second)
-    | hb_map (hb_add (this))
-    | hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); })
-    ;
-  }
-
-  const Coverage &get_coverage () const { return this+coverage; }
-
-  bool would_apply (hb_would_apply_context_t *c) const
-  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
-
-  unsigned
-  get_glyph_alternates (hb_codepoint_t  gid,
-                       unsigned        start_offset,
-                       unsigned       *alternate_count  /* IN/OUT.  May be NULL. */,
-                       hb_codepoint_t *alternate_glyphs /* OUT.     May be NULL. */) const
-  { return (this+alternateSet[(this+coverage).get_coverage (gid)])
-          .get_alternates (start_offset, alternate_count, alternate_glyphs); }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-
-    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
-
-    return_trace ((this+alternateSet[index]).apply (c));
-  }
-
-  bool serialize (hb_serialize_context_t *c,
-                 hb_sorted_array_t<const HBGlyphID16> glyphs,
-                 hb_array_t<const unsigned int> alternate_len_list,
-                 hb_array_t<const HBGlyphID16> alternate_glyphs_list)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (this))) return_trace (false);
-    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_serialize (c, alternate_glyphs_list.sub_array (0, alternate_len))))
-       return_trace (false);
-      alternate_glyphs_list += alternate_len;
-    }
-    return_trace (coverage.serialize_serialize (c, glyphs));
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->format = format;
-
-    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
-    + hb_zip (this+coverage, alternateSet)
-    | hb_filter (glyphset, hb_first)
-    | hb_filter (subset_offset_array (c, out->alternateSet, this), hb_second)
-    | hb_map (hb_first)
-    | hb_map (glyph_map)
-    | hb_sink (new_coverage)
-    ;
-    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
-    return_trace (bool (new_coverage));
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
-  }
-
-  protected:
-  HBUINT16     format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
-               coverage;               /* Offset to Coverage table--from
-                                        * beginning of Substitution table */
-  Array16OfOffset16To<AlternateSet>
-               alternateSet;           /* Array of AlternateSet tables
-                                        * ordered by Coverage Index */
-  public:
-  DEFINE_SIZE_ARRAY (6, alternateSet);
-};
-
-struct AlternateSubst
-{
-  bool serialize (hb_serialize_context_t *c,
-                 hb_sorted_array_t<const HBGlyphID16> glyphs,
-                 hb_array_t<const unsigned int> alternate_len_list,
-                 hb_array_t<const HBGlyphID16> alternate_glyphs_list)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (u.format))) return_trace (false);
-    unsigned int format = 1;
-    u.format = format;
-    switch (u.format) {
-    case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list));
-    default:return_trace (false);
-    }
-  }
-
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16             format;         /* Format identifier */
-  AlternateSubstFormat1        format1;
-  } u;
-};
-
-
-struct Ligature
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return hb_all (component, glyphs); }
-
-  void closure (hb_closure_context_t *c) const
-  {
-    if (!intersects (c->glyphs)) return;
-    c->output->add (ligGlyph);
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    c->input->add_array (component.arrayZ, component.get_length ());
-    c->output->add (ligGlyph);
-  }
-
-  bool would_apply (hb_would_apply_context_t *c) const
-  {
-    if (c->len != component.lenP1)
-      return false;
-
-    for (unsigned int i = 1; i < c->len; i++)
-      if (likely (c->glyphs[i] != component[i]))
-       return false;
-
-    return true;
-  }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    unsigned int count = component.lenP1;
-
-    if (unlikely (!count)) return_trace (false);
-
-    /* Special-case to make it in-place and not consider this
-     * as a "ligated" substitution. */
-    if (unlikely (count == 1))
-    {
-      c->replace_glyph (ligGlyph);
-      return_trace (true);
-    }
-
-    unsigned int total_component_count = 0;
-
-    unsigned int match_end = 0;
-    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
-
-    if (likely (!match_input (c, count,
-                             &component[1],
-                             match_glyph,
-                             nullptr,
-                             &match_end,
-                             match_positions,
-                             &total_component_count)))
-    {
-      c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
-      return_trace (false);
-    }
-
-    ligate_input (c,
-                 count,
-                 match_positions,
-                 match_end,
-                 ligGlyph,
-                 total_component_count);
-
-    return_trace (true);
-  }
-
-  template <typename Iterator,
-           hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
-  bool serialize (hb_serialize_context_t *c,
-                 hb_codepoint_t ligature,
-                 Iterator components /* Starting from second */)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (this))) return_trace (false);
-    ligGlyph = ligature;
-    if (unlikely (!component.serialize (c, components))) return_trace (false);
-    return_trace (true);
-  }
-
-  bool subset (hb_subset_context_t *c, unsigned coverage_idx) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false);
-    // Ensure Coverage table is always packed after this.
-    c->serializer->add_virtual_link (coverage_idx);
-
-    auto it =
-      + hb_iter (component)
-      | hb_map (glyph_map)
-      ;
-
-    auto *out = c->serializer->start_embed (*this);
-    return_trace (out->serialize (c->serializer,
-                                 glyph_map[ligGlyph],
-                                 it));
-  }
-
-  public:
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
-  }
-
-  protected:
-  HBGlyphID16  ligGlyph;               /* GlyphID of ligature to substitute */
-  HeadlessArrayOf<HBGlyphID16>
-               component;              /* Array of component GlyphIDs--start
-                                        * with the second  component--ordered
-                                        * in writing direction */
-  public:
-  DEFINE_SIZE_ARRAY (4, component);
-};
-
-struct LigatureSet
-{
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    return
-    + hb_iter (ligature)
-    | hb_map (hb_add (this))
-    | hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); })
-    | hb_any
-    ;
-  }
-
-  void closure (hb_closure_context_t *c) const
-  {
-    + hb_iter (ligature)
-    | hb_map (hb_add (this))
-    | hb_apply ([c] (const Ligature &_) { _.closure (c); })
-    ;
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    + hb_iter (ligature)
-    | hb_map (hb_add (this))
-    | hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); })
-    ;
-  }
-
-  bool would_apply (hb_would_apply_context_t *c) const
-  {
-    return
-    + hb_iter (ligature)
-    | hb_map (hb_add (this))
-    | hb_map ([c] (const Ligature &_) { return _.would_apply (c); })
-    | hb_any
-    ;
-  }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    unsigned int num_ligs = ligature.len;
-    for (unsigned int i = 0; i < num_ligs; i++)
-    {
-      const Ligature &lig = this+ligature[i];
-      if (lig.apply (c)) return_trace (true);
-    }
-
-    return_trace (false);
-  }
-
-  bool serialize (hb_serialize_context_t *c,
-                 hb_array_t<const HBGlyphID16> ligatures,
-                 hb_array_t<const unsigned int> component_count_list,
-                 hb_array_t<const HBGlyphID16> &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, ligatures.length))) return_trace (false);
-    for (unsigned int i = 0; i < ligatures.length; i++)
-    {
-      unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
-      if (unlikely (!ligature[i].serialize_serialize (c,
-                                                      ligatures[i],
-                                                      component_list.sub_array (0, component_count))))
-       return_trace (false);
-      component_list += component_count;
-    }
-    return_trace (true);
-  }
-
-  bool subset (hb_subset_context_t *c, unsigned coverage_idx) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-
-    + hb_iter (ligature)
-    | hb_filter (subset_offset_array (c, out->ligature, this, coverage_idx))
-    | hb_drain
-    ;
-
-    if (bool (out->ligature))
-      // Ensure Coverage table is always packed after this.
-      c->serializer->add_virtual_link (coverage_idx);
-
-    return_trace (bool (out->ligature));
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (ligature.sanitize (c, this));
-  }
-
-  protected:
-  Array16OfOffset16To<Ligature>
-               ligature;               /* Array LigatureSet tables
-                                        * ordered by preference */
-  public:
-  DEFINE_SIZE_ARRAY (2, ligature);
-};
-
-struct LigatureSubstFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    return
-    + hb_zip (this+coverage, ligatureSet)
-    | hb_filter (*glyphs, hb_first)
-    | hb_map (hb_second)
-    | hb_map ([this, glyphs] (const Offset16To<LigatureSet> &_)
-             { return (this+_).intersects (glyphs); })
-    | hb_any
-    ;
-  }
-
-  bool may_have_non_1to1 () const
-  { return true; }
-
-  void closure (hb_closure_context_t *c) const
-  {
-    + hb_zip (this+coverage, ligatureSet)
-    | hb_filter (c->parent_active_glyphs (), hb_first)
-    | hb_map (hb_second)
-    | hb_map (hb_add (this))
-    | hb_apply ([c] (const LigatureSet &_) { _.closure (c); })
-    ;
-
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-
-    + hb_zip (this+coverage, ligatureSet)
-    | hb_map (hb_second)
-    | hb_map (hb_add (this))
-    | hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); })
-    ;
-  }
-
-  const Coverage &get_coverage () const { return this+coverage; }
-
-  bool would_apply (hb_would_apply_context_t *c) const
-  {
-    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
-    if (likely (index == NOT_COVERED)) return false;
-
-    const LigatureSet &lig_set = this+ligatureSet[index];
-    return lig_set.would_apply (c);
-  }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-
-    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));
-  }
-
-  bool serialize (hb_serialize_context_t *c,
-                 hb_sorted_array_t<const HBGlyphID16> first_glyphs,
-                 hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
-                 hb_array_t<const HBGlyphID16> ligatures_list,
-                 hb_array_t<const unsigned int> component_count_list,
-                 hb_array_t<const HBGlyphID16> 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, 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_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_serialize (c, first_glyphs));
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->format = format;
-
-    // Due to a bug in some older versions of windows 7 the Coverage table must be
-    // packed after the LigatureSet and Ligature tables, so serialize Coverage first
-    // which places it last in the packed order.
-    hb_set_t new_coverage;
-    + hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this)))
-    | hb_filter (glyphset, hb_first)
-    | hb_filter ([&] (const LigatureSet& _) {
-      return _.intersects (&glyphset);
-    }, hb_second)
-    | hb_map (hb_first)
-    | hb_sink (new_coverage);
-
-    if (!c->serializer->push<Coverage> ()
-        ->serialize (c->serializer,
-                     + new_coverage.iter () | hb_map_retains_sorting (glyph_map)))
-    {
-      c->serializer->pop_discard ();
-      return_trace (false);
-    }
-
-    unsigned coverage_idx = c->serializer->pop_pack ();
-     c->serializer->add_link (out->coverage, coverage_idx);
-
-    + hb_zip (this+coverage, ligatureSet)
-    | hb_filter (new_coverage, hb_first)
-    | hb_map (hb_second)
-    // to ensure that the repacker always orders the coverage table after the LigatureSet
-    // and LigatureSubtable's they will be linked to the Coverage table via a virtual link
-    // the coverage table object idx is passed down to facilitate this.
-    | hb_apply (subset_offset_array (c, out->ligatureSet, this, coverage_idx))
-    ;
-
-    return_trace (bool (new_coverage));
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
-  }
-
-  protected:
-  HBUINT16     format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
-               coverage;               /* Offset to Coverage table--from
-                                        * beginning of Substitution table */
-  Array16OfOffset16To<LigatureSet>
-               ligatureSet;            /* Array LigatureSet tables
-                                        * ordered by Coverage Index */
-  public:
-  DEFINE_SIZE_ARRAY (6, ligatureSet);
-};
-
-struct LigatureSubst
-{
-  bool serialize (hb_serialize_context_t *c,
-                 hb_sorted_array_t<const HBGlyphID16> first_glyphs,
-                 hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
-                 hb_array_t<const HBGlyphID16> ligatures_list,
-                 hb_array_t<const unsigned int> component_count_list,
-                 hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (u.format))) return_trace (false);
-    unsigned int format = 1;
-    u.format = format;
-    switch (u.format) {
-    case 1: return_trace (u.format1.serialize (c,
-                                              first_glyphs,
-                                              ligature_per_first_glyph_count_list,
-                                              ligatures_list,
-                                              component_count_list,
-                                              component_list));
-    default:return_trace (false);
-    }
-  }
-
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16             format;         /* Format identifier */
-  LigatureSubstFormat1 format1;
-  } u;
-};
-
-
-struct ContextSubst : Context {};
-
-struct ChainContextSubst : ChainContext {};
-
-struct ExtensionSubst : Extension<ExtensionSubst>
-{
-  typedef struct SubstLookupSubTable SubTable;
-  bool is_reverse () const;
-};
-
-
-struct ReverseChainSingleSubstFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    if (!(this+coverage).intersects (glyphs))
-      return false;
-
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<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;
-  }
-
-  bool may_have_non_1to1 () const
-  { return false; }
-
-  void closure (hb_closure_context_t *c) const
-  {
-    if (!intersects (c->glyphs)) return;
-
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
-
-    + hb_zip (this+coverage, substitute)
-    | hb_filter (c->parent_active_glyphs (), hb_first)
-    | hb_map (hb_second)
-    | hb_sink (c->output)
-    ;
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-
-    unsigned int count;
-
-    count = backtrack.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!(this+backtrack[i]).collect_coverage (c->before))) return;
-
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-    count = lookahead.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!(this+lookahead[i]).collect_coverage (c->after))) return;
-
-    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
-    count = substitute.len;
-    c->output->add_array (substitute.arrayZ, substitute.len);
-  }
-
-  const Coverage &get_coverage () const { return this+coverage; }
-
-  bool would_apply (hb_would_apply_context_t *c) const
-  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
-      return_trace (false); /* No chaining to this type */
-
-    unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
-
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
-
-    if (unlikely (index >= substitute.len)) return_trace (false);
-
-    unsigned int start_index = 0, end_index = 0;
-    if (match_backtrack (c,
-                        backtrack.len, (HBUINT16 *) backtrack.arrayZ,
-                        match_coverage, this,
-                        &start_index) &&
-       match_lookahead (c,
-                        lookahead.len, (HBUINT16 *) lookahead.arrayZ,
-                        match_coverage, this,
-                        c->buffer->idx + 1, &end_index))
-    {
-      c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
-      c->replace_glyph_inplace (substitute[index]);
-      /* Note: We DON'T decrease buffer->idx.  The main loop does it
-       * for us.  This is useful for preventing surprises if someone
-       * calls us through a Context lookup. */
-      return_trace (true);
-    }
-    else
-    {
-      c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index);
-      return_trace (false);
-    }
-  }
-
-  template<typename Iterator,
-           hb_requires (hb_is_iterator (Iterator))>
-  bool serialize_coverage_offset_array (hb_subset_context_t *c, Iterator it) const
-  {
-    TRACE_SERIALIZE (this);
-    auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> ();
-
-    if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
-      return_trace (false);
-
-    for (auto& offset : it) {
-      auto *o = out->serialize_append (c->serializer);
-      if (unlikely (!o) || !o->serialize_subset (c, offset, this))
-        return_trace (false);
-    }
-
-    return_trace (true);
-  }
-
-  template<typename Iterator, typename BacktrackIterator, typename LookaheadIterator,
-           hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_pair_t)),
-           hb_requires (hb_is_iterator (BacktrackIterator)),
-           hb_requires (hb_is_iterator (LookaheadIterator))>
-  bool serialize (hb_subset_context_t *c,
-                  Iterator coverage_subst_iter,
-                  BacktrackIterator backtrack_iter,
-                  LookaheadIterator lookahead_iter) const
-  {
-    TRACE_SERIALIZE (this);
-
-    auto *out = c->serializer->start_embed (this);
-    if (unlikely (!c->serializer->check_success (out))) return_trace (false);
-    if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
-    if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false);
-
-    if (!serialize_coverage_offset_array (c, backtrack_iter)) return_trace (false);
-    if (!serialize_coverage_offset_array (c, lookahead_iter)) return_trace (false);
-
-    auto *substitute_out = c->serializer->start_embed<Array16Of<HBGlyphID16>> ();
-    auto substitutes =
-    + coverage_subst_iter
-    | hb_map (hb_second)
-    ;
-
-    auto glyphs =
-    + coverage_subst_iter
-    | hb_map_retains_sorting (hb_first)
-    ;
-    if (unlikely (! c->serializer->check_success (substitute_out->serialize (c->serializer, substitutes))))
-        return_trace (false);
-
-    if (unlikely (!out->coverage.serialize_serialize (c->serializer, glyphs)))
-      return_trace (false);
-    return_trace (true);
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
-
-    auto it =
-    + hb_zip (this+coverage, substitute)
-    | hb_filter (glyphset, hb_first)
-    | hb_filter (glyphset, hb_second)
-    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t
-                              { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
-    ;
-
-    return_trace (bool (it) && serialize (c, it, backtrack.iter (), lookahead.iter ()));
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
-      return_trace (false);
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-    if (!lookahead.sanitize (c, this))
-      return_trace (false);
-    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
-    return_trace (substitute.sanitize (c));
-  }
-
-  protected:
-  HBUINT16     format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
-               coverage;               /* Offset to Coverage table--from
-                                        * beginning of table */
-  Array16OfOffset16To<Coverage>
-               backtrack;              /* Array of coverage tables
-                                        * in backtracking sequence, in glyph
-                                        * sequence order */
-  Array16OfOffset16To<Coverage>
-               lookaheadX;             /* Array of coverage tables
-                                        * in lookahead sequence, in glyph
-                                        * sequence order */
-  Array16Of<HBGlyphID16>
-               substituteX;            /* Array of substitute
-                                        * GlyphIDs--ordered by Coverage Index */
-  public:
-  DEFINE_SIZE_MIN (10);
-};
-
-struct ReverseChainSingleSubst
-{
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16                             format;         /* Format identifier */
-  ReverseChainSingleSubstFormat1       format1;
-  } u;
-};
-
-
-
-/*
- * SubstLookup
- */
-
-struct SubstLookupSubTable
-{
-  friend struct Lookup;
-  friend struct SubstLookup;
-
-  enum Type {
-    Single             = 1,
-    Multiple           = 2,
-    Alternate          = 3,
-    Ligature           = 4,
-    Context            = 5,
-    ChainContext       = 6,
-    Extension          = 7,
-    ReverseChainSingle = 8
-  };
-
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, lookup_type);
-    switch (lookup_type) {
-    case Single:               return_trace (u.single.dispatch (c, std::forward<Ts> (ds)...));
-    case Multiple:             return_trace (u.multiple.dispatch (c, std::forward<Ts> (ds)...));
-    case Alternate:            return_trace (u.alternate.dispatch (c, std::forward<Ts> (ds)...));
-    case Ligature:             return_trace (u.ligature.dispatch (c, std::forward<Ts> (ds)...));
-    case Context:              return_trace (u.context.dispatch (c, std::forward<Ts> (ds)...));
-    case ChainContext:         return_trace (u.chainContext.dispatch (c, std::forward<Ts> (ds)...));
-    case Extension:            return_trace (u.extension.dispatch (c, std::forward<Ts> (ds)...));
-    case ReverseChainSingle:   return_trace (u.reverseChainContextSingle.dispatch (c, std::forward<Ts> (ds)...));
-    default:                   return_trace (c->default_return_value ());
-    }
-  }
-
-  bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const
-  {
-    hb_intersects_context_t c (glyphs);
-    return dispatch (&c, lookup_type);
-  }
-
-  protected:
-  union {
-  SingleSubst                  single;
-  MultipleSubst                        multiple;
-  AlternateSubst               alternate;
-  LigatureSubst                        ligature;
-  ContextSubst                 context;
-  ChainContextSubst            chainContext;
-  ExtensionSubst               extension;
-  ReverseChainSingleSubst      reverseChainContextSingle;
-  } u;
-  public:
-  DEFINE_SIZE_MIN (0);
-};
-
-
-struct SubstLookup : Lookup
-{
-  typedef SubstLookupSubTable SubTable;
-
-  const SubTable& get_subtable (unsigned int i) const
-  { return Lookup::get_subtable<SubTable> (i); }
-
-  static inline bool lookup_type_is_reverse (unsigned int lookup_type)
-  { return lookup_type == SubTable::ReverseChainSingle; }
-
-  bool is_reverse () const
-  {
-    unsigned int type = get_type ();
-    if (unlikely (type == SubTable::Extension))
-      return reinterpret_cast<const ExtensionSubst &> (get_subtable (0)).is_reverse ();
-    return lookup_type_is_reverse (type);
-  }
-
-  bool may_have_non_1to1 () const
-  {
-    hb_have_non_1to1_context_t c;
-    return dispatch (&c);
-  }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    return_trace (dispatch (c));
-  }
-
-  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
-  {
-    if (!c->should_visit_lookup (this_index))
-      return hb_closure_context_t::default_return_value ();
-
-    c->set_recurse_func (dispatch_closure_recurse_func);
-
-    hb_closure_context_t::return_t ret = dispatch (c);
-
-    c->flush ();
-
-    return ret;
-  }
-
-  hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
-  {
-    if (c->is_lookup_visited (this_index))
-      return hb_closure_lookups_context_t::default_return_value ();
-
-    c->set_lookup_visited (this_index);
-    if (!intersects (c->glyphs))
-    {
-      c->set_lookup_inactive (this_index);
-      return hb_closure_lookups_context_t::default_return_value ();
-    }
-
-    c->set_recurse_func (dispatch_closure_lookups_recurse_func);
-
-    hb_closure_lookups_context_t::return_t ret = dispatch (c);
-    return ret;
-  }
-
-  hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
-    return dispatch (c);
-  }
-
-  template <typename set_t>
-  void collect_coverage (set_t *glyphs) const
-  {
-    hb_collect_coverage_context_t<set_t> c (glyphs);
-    dispatch (&c);
-  }
-
-  bool would_apply (hb_would_apply_context_t *c,
-                   const hb_ot_layout_lookup_accelerator_t *accel) const
-  {
-    if (unlikely (!c->len)) return false;
-    if (!accel->may_have (c->glyphs[0])) return false;
-      return dispatch (c);
-  }
-
-  static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
-
-  bool serialize_single (hb_serialize_context_t *c,
-                        uint32_t lookup_props,
-                        hb_sorted_array_t<const HBGlyphID16> glyphs,
-                        hb_array_t<const HBGlyphID16> substitutes)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
-    if (c->push<SubTable> ()->u.single.serialize (c, hb_zip (glyphs, substitutes)))
-    {
-      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
-      return_trace (true);
-    }
-    c->pop_discard ();
-    return_trace (false);
-  }
-
-  bool serialize_multiple (hb_serialize_context_t *c,
-                          uint32_t lookup_props,
-                          hb_sorted_array_t<const HBGlyphID16> glyphs,
-                          hb_array_t<const unsigned int> substitute_len_list,
-                          hb_array_t<const HBGlyphID16> substitute_glyphs_list)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
-    if (c->push<SubTable> ()->u.multiple.
-        serialize (c,
-                   glyphs,
-                   substitute_len_list,
-                   substitute_glyphs_list))
-    {
-      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
-      return_trace (true);
-    }
-    c->pop_discard ();
-    return_trace (false);
-  }
-
-  bool serialize_alternate (hb_serialize_context_t *c,
-                           uint32_t lookup_props,
-                           hb_sorted_array_t<const HBGlyphID16> glyphs,
-                           hb_array_t<const unsigned int> alternate_len_list,
-                           hb_array_t<const HBGlyphID16> alternate_glyphs_list)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
-
-    if (c->push<SubTable> ()->u.alternate.
-        serialize (c,
-                   glyphs,
-                   alternate_len_list,
-                   alternate_glyphs_list))
-    {
-      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
-      return_trace (true);
-    }
-    c->pop_discard ();
-    return_trace (false);
-  }
-
-  bool serialize_ligature (hb_serialize_context_t *c,
-                          uint32_t lookup_props,
-                          hb_sorted_array_t<const HBGlyphID16> first_glyphs,
-                          hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
-                          hb_array_t<const HBGlyphID16> ligatures_list,
-                          hb_array_t<const unsigned int> component_count_list,
-                          hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
-    if (c->push<SubTable> ()->u.ligature.
-        serialize (c,
-                   first_glyphs,
-                   ligature_per_first_glyph_count_list,
-                   ligatures_list,
-                   component_count_list,
-                   component_list))
-    {
-      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
-      return_trace (true);
-    }
-    c->pop_discard ();
-    return_trace (false);
-  }
-
-  template <typename context_t>
-  static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
-
-  static inline typename hb_closure_context_t::return_t closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index);
-
-  static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index)
-  {
-    if (!c->should_visit_lookup (lookup_index))
-      return hb_empty_t ();
-
-    hb_closure_context_t::return_t ret = closure_glyphs_recurse_func (c, lookup_index, covered_seq_indices, seq_index, end_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;
-  }
-
-  HB_INTERNAL static hb_closure_lookups_context_t::return_t dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned lookup_index);
-
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); }
-
-  bool subset (hb_subset_context_t *c) const
-  { return Lookup::subset<SubTable> (c); }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  { return Lookup::sanitize<SubTable> (c); }
-};
-
-/*
- * GSUB -- Glyph Substitution
- * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
- */
-
-struct GSUB : GSUBGPOS
-{
-  static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
-
-  const SubstLookup& get_lookup (unsigned int i) const
-  { return static_cast<const SubstLookup &> (GSUBGPOS::get_lookup (i)); }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_langsys, c->plan->gsub_features);
-    return GSUBGPOS::subset<SubstLookup> (&l);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  { return GSUBGPOS::sanitize<SubstLookup> (c); }
-
-  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
-                                  hb_face_t *face) const;
-
-  void closure_lookups (hb_face_t      *face,
-                       const hb_set_t *glyphs,
-                       hb_set_t       *lookup_indexes /* IN/OUT */) const
-  { GSUBGPOS::closure_lookups<SubstLookup> (face, glyphs, lookup_indexes); }
-
-  typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
-};
-
-
-struct GSUB_accelerator_t : GSUB::accelerator_t {
-  GSUB_accelerator_t (hb_face_t *face) : GSUB::accelerator_t (face) {}
-};
-
-
+// TODO(garretrieger): Move into the new layout directory.
 /* Out-of-class implementation for methods recursing */
 
 #ifndef HB_NO_OT_LAYOUT
@@ -1772,27 +58,36 @@ template <typename context_t>
   return l.dispatch (c);
 }
 
-/*static*/ inline hb_closure_lookups_context_t::return_t SubstLookup::dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index)
+template <>
+inline hb_closure_lookups_context_t::return_t
+SubstLookup::dispatch_recurse_func<hb_closure_lookups_context_t> (hb_closure_lookups_context_t *c, unsigned this_index)
 {
   const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (this_index);
   return l.closure_lookups (c, this_index);
 }
 
-/*static*/ bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
+template <>
+inline bool SubstLookup::dispatch_recurse_func<hb_ot_apply_context_t> (hb_ot_apply_context_t *c, unsigned int lookup_index)
 {
-  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
+  auto *gsub = c->face->table.GSUB.get_relaxed ();
+  const SubstLookup &l = gsub->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);
   c->set_lookup_props (l.get_props ());
-  bool ret = l.dispatch (c);
+
+  bool ret = false;
+  auto *accel = gsub->get_accel (lookup_index);
+  ret = accel && accel->apply (c, l.get_subtable_count (), false);
+
   c->set_lookup_index (saved_lookup_index);
   c->set_lookup_props (saved_lookup_props);
   return ret;
 }
 #endif
 
-
+} /* namespace GSUB_impl */
+} /* namespace Layout */
 } /* namespace OT */
 
 
index 65de131..662ec9d 100644 (file)
@@ -100,8 +100,8 @@ struct hb_closure_context_t :
 
   bool is_lookup_done (unsigned int lookup_index)
   {
-    if (done_lookups_glyph_count->in_error () ||
-        done_lookups_glyph_set->in_error ())
+    if (unlikely (done_lookups_glyph_count->in_error () ||
+                 done_lookups_glyph_set->in_error ()))
       return true;
 
     /* Have we visited this lookup with the current set of glyphs? */
@@ -109,17 +109,13 @@ struct hb_closure_context_t :
     {
       done_lookups_glyph_count->set (lookup_index, glyphs->get_population ());
 
-      if (!done_lookups_glyph_set->get (lookup_index))
+      if (!done_lookups_glyph_set->has (lookup_index))
       {
-       hb_set_t* empty_set = hb_set_create ();
-       if (unlikely (!done_lookups_glyph_set->set (lookup_index, empty_set)))
-       {
-         hb_set_destroy (empty_set);
+       if (unlikely (!done_lookups_glyph_set->set (lookup_index, hb::unique_ptr<hb_set_t> {hb_set_create ()})))
          return true;
-       }
       }
 
-      hb_set_clear (done_lookups_glyph_set->get (lookup_index));
+      done_lookups_glyph_set->get (lookup_index)->clear ();
     }
 
     hb_set_t *covered_glyph_set = done_lookups_glyph_set->get (lookup_index);
@@ -147,14 +143,17 @@ struct hb_closure_context_t :
     return active_glyphs_stack.tail ();
   }
 
-  hb_set_t& push_cur_active_glyphs ()
+  hb_set_t* push_cur_active_glyphs ()
   {
-    return *active_glyphs_stack.push ();
+    hb_set_t *s = active_glyphs_stack.push ();
+    if (unlikely (active_glyphs_stack.in_error ()))
+      return nullptr;
+    return s;
   }
 
   bool pop_cur_done_glyphs ()
   {
-    if (active_glyphs_stack.length < 1)
+    if (!active_glyphs_stack)
       return false;
 
     active_glyphs_stack.pop ();
@@ -165,21 +164,19 @@ struct hb_closure_context_t :
   hb_set_t *glyphs;
   hb_set_t output[1];
   hb_vector_t<hb_set_t> active_glyphs_stack;
-  recurse_func_t recurse_func;
+  recurse_func_t recurse_func = nullptr;
   unsigned int nesting_level_left;
 
   hb_closure_context_t (hb_face_t *face_,
                        hb_set_t *glyphs_,
                        hb_map_t *done_lookups_glyph_count_,
-                       hb_hashmap_t<unsigned, hb_set_t *> *done_lookups_glyph_set_,
+                       hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *done_lookups_glyph_set_,
                        unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
                          face (face_),
                          glyphs (glyphs_),
-                         recurse_func (nullptr),
                          nesting_level_left (nesting_level_left_),
                          done_lookups_glyph_count (done_lookups_glyph_count_),
-                         done_lookups_glyph_set (done_lookups_glyph_set_),
-                         lookup_count (0)
+                         done_lookups_glyph_set (done_lookups_glyph_set_)
   {}
 
   ~hb_closure_context_t () { flush (); }
@@ -197,8 +194,8 @@ struct hb_closure_context_t :
 
   private:
   hb_map_t *done_lookups_glyph_count;
-  hb_hashmap_t<unsigned, hb_set_t *> *done_lookups_glyph_set;
-  unsigned int lookup_count;
+  hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *done_lookups_glyph_set;
+  unsigned int lookup_count = 0;
 };
 
 
@@ -400,30 +397,19 @@ struct hb_collect_coverage_context_t :
   set_t *set;
 };
 
-
 struct hb_ot_apply_context_t :
        hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
 {
   struct matcher_t
   {
-    matcher_t () :
-            lookup_props (0),
-            ignore_zwnj (false),
-            ignore_zwj (false),
-            mask (-1),
-#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
-            syllable arg1(0),
-#undef arg1
-            match_func (nullptr),
-            match_data (nullptr) {}
-
-    typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
+    typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data);
 
     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_per_syllable (bool per_syllable_) { per_syllable = per_syllable_; }
+    void set_syllable (uint8_t syllable_)  { syllable = per_syllable ? syllable_ : 0; }
     void set_match_func (match_func_t match_func_,
                         const void *match_data_)
     { match_func = match_func_; match_data = match_data_; }
@@ -434,15 +420,18 @@ struct hb_ot_apply_context_t :
       MATCH_MAYBE
     };
 
-    may_match_t may_match (const hb_glyph_info_t &info,
-                          const HBUINT16        *glyph_data) const
+#ifndef HB_OPTIMIZE_SIZE
+    HB_ALWAYS_INLINE
+#endif
+    may_match_t may_match (hb_glyph_info_t &info,
+                          hb_codepoint_t 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 (infoglyph_data, match_data) ? MATCH_YES : MATCH_NO;
 
       return MATCH_MAYBE;
     }
@@ -453,6 +442,9 @@ struct hb_ot_apply_context_t :
       SKIP_MAYBE
     };
 
+#ifndef HB_OPTIMIZE_SIZE
+    HB_ALWAYS_INLINE
+#endif
     may_skip_t may_skip (const hb_ot_apply_context_t *c,
                         const hb_glyph_info_t       &info) const
     {
@@ -468,13 +460,14 @@ struct hb_ot_apply_context_t :
     }
 
     protected:
-    unsigned int lookup_props;
-    bool ignore_zwnj;
-    bool ignore_zwj;
-    hb_mask_t mask;
-    uint8_t syllable;
-    match_func_t match_func;
-    const void *match_data;
+    unsigned int lookup_props = 0;
+    hb_mask_t mask = -1;
+    bool ignore_zwnj = false;
+    bool ignore_zwj = false;
+    bool per_syllable = false;
+    uint8_t syllable = 0;
+    match_func_t match_func = nullptr;
+    const void *match_data = nullptr;
   };
 
   struct skipping_iterator_t
@@ -482,7 +475,11 @@ struct hb_ot_apply_context_t :
     void init (hb_ot_apply_context_t *c_, bool context_match = false)
     {
       c = c_;
-      match_glyph_data = nullptr;
+      end = c->buffer->len;
+      match_glyph_data16 = nullptr;
+#ifndef HB_NO_BEYOND_64K
+      match_glyph_data24 = nullptr;
+#endif
       matcher.set_match_func (nullptr, nullptr);
       matcher.set_lookup_props (c->lookup_props);
       /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
@@ -490,98 +487,146 @@ struct hb_ot_apply_context_t :
       /* 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);
+      /* Per syllable matching is only for GSUB. */
+      matcher.set_per_syllable (c->table_index == 0 && c->per_syllable);
+      matcher.set_syllable (0);
     }
     void set_lookup_props (unsigned int lookup_props)
     {
       matcher.set_lookup_props (lookup_props);
     }
     void set_match_func (matcher_t::match_func_t match_func_,
-                        const void *match_data_,
-                        const HBUINT16 glyph_data[])
+                        const void *match_data_)
     {
       matcher.set_match_func (match_func_, match_data_);
-      match_glyph_data = glyph_data;
     }
+    void set_glyph_data (const HBUINT16 glyph_data[])
+    {
+      match_glyph_data16 = glyph_data;
+#ifndef HB_NO_BEYOND_64K
+      match_glyph_data24 = nullptr;
+#endif
+    }
+#ifndef HB_NO_BEYOND_64K
+    void set_glyph_data (const HBUINT24 glyph_data[])
+    {
+      match_glyph_data16 = nullptr;
+      match_glyph_data24 = glyph_data;
+    }
+#endif
 
-    void reset (unsigned int start_index_,
-               unsigned int num_items_)
+#ifndef HB_OPTIMIZE_SIZE
+    HB_ALWAYS_INLINE
+#endif
+    void reset (unsigned int start_index_)
     {
       idx = start_index_;
-      num_items = num_items_;
       end = c->buffer->len;
       matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
     }
 
+#ifndef HB_OPTIMIZE_SIZE
+    HB_ALWAYS_INLINE
+#endif
+    void reset_fast (unsigned int start_index_)
+    {
+      // Doesn't set end or syllable. Used by GPOS which doesn't care / change.
+      idx = start_index_;
+    }
+
     void reject ()
     {
-      num_items++;
-      if (match_glyph_data) match_glyph_data--;
+      backup_glyph_data ();
     }
 
     matcher_t::may_skip_t
+#ifndef HB_OPTIMIZE_SIZE
+    HB_ALWAYS_INLINE
+#endif
     may_skip (const hb_glyph_info_t &info) const
     { return matcher.may_skip (c, info); }
 
-    bool next (unsigned *unsafe_to = nullptr)
+    enum match_t {
+      MATCH,
+      NOT_MATCH,
+      SKIP
+    };
+
+#ifndef HB_OPTIMIZE_SIZE
+    HB_ALWAYS_INLINE
+#endif
+    match_t match (hb_glyph_info_t &info)
     {
-      assert (num_items > 0);
-      while (idx + num_items < end)
-      {
-       idx++;
-       const hb_glyph_info_t &info = c->buffer->info[idx];
+      matcher_t::may_skip_t skip = matcher.may_skip (c, info);
+      if (unlikely (skip == matcher_t::SKIP_YES))
+       return SKIP;
 
-       matcher_t::may_skip_t skip = matcher.may_skip (c, info);
-       if (unlikely (skip == matcher_t::SKIP_YES))
-         continue;
+      matcher_t::may_match_t match = matcher.may_match (info, get_glyph_data ());
+      if (match == matcher_t::MATCH_YES ||
+         (match == matcher_t::MATCH_MAYBE &&
+          skip == matcher_t::SKIP_NO))
+       return MATCH;
 
-       matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
-       if (match == matcher_t::MATCH_YES ||
-           (match == matcher_t::MATCH_MAYBE &&
-            skip == matcher_t::SKIP_NO))
-       {
-         num_items--;
-         if (match_glyph_data) match_glyph_data++;
-         return true;
-       }
+      if (skip == matcher_t::SKIP_NO)
+        return NOT_MATCH;
+
+      return SKIP;
+  }
 
-       if (skip == matcher_t::SKIP_NO)
+#ifndef HB_OPTIMIZE_SIZE
+    HB_ALWAYS_INLINE
+#endif
+    bool next (unsigned *unsafe_to = nullptr)
+    {
+      const signed stop = (signed) end - 1;
+      while ((signed) idx < stop)
+      {
+       idx++;
+       switch (match (c->buffer->info[idx]))
        {
-         if (unsafe_to)
-           *unsafe_to = idx + 1;
-         return false;
+         case MATCH:
+         {
+           advance_glyph_data ();
+           return true;
+         }
+         case NOT_MATCH:
+         {
+           if (unsafe_to)
+             *unsafe_to = idx + 1;
+           return false;
+         }
+         case SKIP:
+           continue;
        }
       }
       if (unsafe_to)
         *unsafe_to = end;
       return false;
     }
+#ifndef HB_OPTIMIZE_SIZE
+    HB_ALWAYS_INLINE
+#endif
     bool prev (unsigned *unsafe_from = nullptr)
     {
-      assert (num_items > 0);
-      while (idx > num_items - 1)
+      const unsigned stop = 0;
+      while (idx > stop)
       {
        idx--;
-       const hb_glyph_info_t &info = c->buffer->out_info[idx];
-
-       matcher_t::may_skip_t skip = matcher.may_skip (c, info);
-       if (unlikely (skip == matcher_t::SKIP_YES))
-         continue;
-
-       matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
-       if (match == matcher_t::MATCH_YES ||
-           (match == matcher_t::MATCH_MAYBE &&
-            skip == matcher_t::SKIP_NO))
+       switch (match (c->buffer->out_info[idx]))
        {
-         num_items--;
-         if (match_glyph_data) match_glyph_data++;
-         return true;
-       }
-
-       if (skip == matcher_t::SKIP_NO)
-       {
-         if (unsafe_from)
-           *unsafe_from = hb_max (1u, idx) - 1u;
-         return false;
+         case MATCH:
+         {
+           advance_glyph_data ();
+           return true;
+         }
+         case NOT_MATCH:
+         {
+           if (unsafe_from)
+             *unsafe_from = hb_max (1u, idx) - 1u;
+           return false;
+         }
+         case SKIP:
+           continue;
        }
       }
       if (unsafe_from)
@@ -589,13 +634,46 @@ struct hb_ot_apply_context_t :
       return false;
     }
 
+    HB_ALWAYS_INLINE
+    hb_codepoint_t
+    get_glyph_data ()
+    {
+      if (match_glyph_data16) return *match_glyph_data16;
+#ifndef HB_NO_BEYOND_64K
+      else
+      if (match_glyph_data24) return *match_glyph_data24;
+#endif
+      return 0;
+    }
+    HB_ALWAYS_INLINE
+    void
+    advance_glyph_data ()
+    {
+      if (match_glyph_data16) match_glyph_data16++;
+#ifndef HB_NO_BEYOND_64K
+      else
+      if (match_glyph_data24) match_glyph_data24++;
+#endif
+    }
+    void
+    backup_glyph_data ()
+    {
+      if (match_glyph_data16) match_glyph_data16--;
+#ifndef HB_NO_BEYOND_64K
+      else
+      if (match_glyph_data24) match_glyph_data24--;
+#endif
+    }
+
     unsigned int idx;
     protected:
     hb_ot_apply_context_t *c;
     matcher_t matcher;
-    const HBUINT16 *match_glyph_data;
+    const HBUINT16 *match_glyph_data16;
+#ifndef HB_NO_BEYOND_64K
+    const HBUINT24 *match_glyph_data24;
+#endif
 
-    unsigned int num_items;
     unsigned int end;
   };
 
@@ -609,7 +687,10 @@ struct hb_ot_apply_context_t :
   return_t recurse (unsigned int sub_lookup_index)
   {
     if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
+    {
+      buffer->shaping_failed = true;
       return default_return_value ();
+    }
 
     nesting_level_left--;
     bool ret = recurse_func (this, sub_lookup_index);
@@ -619,34 +700,42 @@ struct hb_ot_apply_context_t :
 
   skipping_iterator_t iter_input, iter_context;
 
+  unsigned int table_index; /* GSUB/GPOS */
   hb_font_t *font;
   hb_face_t *face;
   hb_buffer_t *buffer;
-  recurse_func_t recurse_func;
+  hb_sanitize_context_t sanitizer;
+  recurse_func_t recurse_func = nullptr;
   const GDEF &gdef;
+  const GDEF::accelerator_t &gdef_accel;
   const VariationStore &var_store;
+  VariationStore::cache_t *var_store_cache;
+  hb_set_digest_t digest;
 
   hb_direction_t direction;
-  hb_mask_t lookup_mask;
-  unsigned int table_index; /* GSUB/GPOS */
-  unsigned int lookup_index;
-  unsigned int lookup_props;
-  unsigned int nesting_level_left;
+  hb_mask_t lookup_mask = 1;
+  unsigned int lookup_index = (unsigned) -1;
+  unsigned int lookup_props = 0;
+  unsigned int nesting_level_left = HB_MAX_NESTING_LEVEL;
 
   bool has_glyph_classes;
-  bool auto_zwnj;
-  bool auto_zwj;
-  bool random;
-
-  uint32_t random_state;
+  bool auto_zwnj = true;
+  bool auto_zwj = true;
+  bool per_syllable = false;
+  bool random = false;
+  uint32_t random_state = 1;
+  unsigned new_syllables = (unsigned) -1;
 
+  signed last_base = -1; // GPOS uses
+  unsigned last_base_until = 0; // GPOS uses
 
   hb_ot_apply_context_t (unsigned int table_index_,
                         hb_font_t *font_,
-                        hb_buffer_t *buffer_) :
-                       iter_input (), iter_context (),
+                        hb_buffer_t *buffer_,
+                        hb_blob_t *table_blob_) :
+                       table_index (table_index_),
                        font (font_), face (font->face), buffer (buffer_),
-                       recurse_func (nullptr),
+                       sanitizer (table_blob_),
                        gdef (
 #ifndef HB_NO_OT_LAYOUT
                              *face->table.GDEF->table
@@ -654,18 +743,32 @@ struct hb_ot_apply_context_t :
                              Null (GDEF)
 #endif
                             ),
+                       gdef_accel (
+#ifndef HB_NO_OT_LAYOUT
+                             *face->table.GDEF
+#else
+                             Null (GDEF::accelerator_t)
+#endif
+                            ),
                        var_store (gdef.get_var_store ()),
+                       var_store_cache (
+#ifndef HB_NO_VAR
+                                        table_index == 1 && font->num_coords ? var_store.create_cache () : nullptr
+#else
+                                        nullptr
+#endif
+                                       ),
+                       digest (buffer_->digest ()),
                        direction (buffer_->props.direction),
-                       lookup_mask (1),
-                       table_index (table_index_),
-                       lookup_index ((unsigned int) -1),
-                       lookup_props (0),
-                       nesting_level_left (HB_MAX_NESTING_LEVEL),
-                       has_glyph_classes (gdef.has_glyph_classes ()),
-                       auto_zwnj (true),
-                       auto_zwj (true),
-                       random (false),
-                       random_state (1) { init_iters (); }
+                       has_glyph_classes (gdef.has_glyph_classes ())
+  { init_iters (); }
+
+  ~hb_ot_apply_context_t ()
+  {
+#ifndef HB_NO_VAR
+    VariationStore::destroy_cache (var_store_cache);
+#endif
+  }
 
   void init_iters ()
   {
@@ -673,9 +776,10 @@ struct hb_ot_apply_context_t :
     iter_context.init (this, true);
   }
 
-  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_lookup_mask (hb_mask_t mask, bool init = true) { lookup_mask = mask; last_base = -1; last_base_until = 0; if (init) init_iters (); }
+  void set_auto_zwj (bool auto_zwj_, bool init = true) { auto_zwj = auto_zwj_; if (init) init_iters (); }
+  void set_auto_zwnj (bool auto_zwnj_, bool init = true) { auto_zwnj = auto_zwnj_; if (init) init_iters (); }
+  void set_per_syllable (bool per_syllable_, bool init = true) { per_syllable = per_syllable_; if (init) 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_; }
@@ -696,7 +800,7 @@ struct hb_ot_apply_context_t :
      * match_props has the set index.
      */
     if (match_props & LookupFlag::UseMarkFilteringSet)
-      return gdef.mark_set_covers (match_props >> 16, glyph);
+      return gdef_accel.mark_set_covers (match_props >> 16, glyph);
 
     /* The second byte of match_props has the meaning
      * "ignore marks of attachment type different than
@@ -708,10 +812,12 @@ struct hb_ot_apply_context_t :
     return true;
   }
 
+#ifndef HB_OPTIMIZE_SIZE
+  HB_ALWAYS_INLINE
+#endif
   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);
 
     /* Not covered, if, for example, glyph class is ligature and
@@ -721,7 +827,7 @@ struct hb_ot_apply_context_t :
       return false;
 
     if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
-      return match_properties_mark (glyph, glyph_props, match_props);
+      return match_properties_mark (info->codepoint, glyph_props, match_props);
 
     return true;
   }
@@ -729,8 +835,13 @@ struct hb_ot_apply_context_t :
   void _set_glyph_class (hb_codepoint_t glyph_index,
                          unsigned int class_guess = 0,
                          bool ligature = false,
-                         bool component = false) const
+                         bool component = false)
   {
+    digest.add (glyph_index);
+
+    if (new_syllables != (unsigned) -1)
+      buffer->cur().syllable() = new_syllables;
+
     unsigned int props = _hb_glyph_info_get_glyph_props (&buffer->cur());
     props |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
     if (ligature)
@@ -749,7 +860,7 @@ struct hb_ot_apply_context_t :
     if (likely (has_glyph_classes))
     {
       props &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
-      _hb_glyph_info_set_glyph_props (&buffer->cur(), props | gdef.get_glyph_props (glyph_index));
+      _hb_glyph_info_set_glyph_props (&buffer->cur(), props | gdef_accel.get_glyph_props (glyph_index));
     }
     else if (class_guess)
     {
@@ -760,24 +871,24 @@ struct hb_ot_apply_context_t :
       _hb_glyph_info_set_glyph_props (&buffer->cur(), props);
   }
 
-  void replace_glyph (hb_codepoint_t glyph_index) const
+  void replace_glyph (hb_codepoint_t glyph_index)
   {
     _set_glyph_class (glyph_index);
     (void) buffer->replace_glyph (glyph_index);
   }
-  void replace_glyph_inplace (hb_codepoint_t glyph_index) const
+  void replace_glyph_inplace (hb_codepoint_t glyph_index)
   {
     _set_glyph_class (glyph_index);
     buffer->cur().codepoint = glyph_index;
   }
   void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
-                                   unsigned int class_guess) const
+                                   unsigned int class_guess)
   {
     _set_glyph_class (glyph_index, class_guess, true);
     (void) buffer->replace_glyph (glyph_index);
   }
   void output_glyph_for_component (hb_codepoint_t glyph_index,
-                                  unsigned int class_guess) const
+                                  unsigned int class_guess)
   {
     _set_glyph_class (glyph_index, class_guess, false, true);
     (void) buffer->output_glyph (glyph_index);
@@ -785,65 +896,155 @@ struct hb_ot_apply_context_t :
 };
 
 
-struct hb_get_subtables_context_t :
-       hb_dispatch_context_t<hb_get_subtables_context_t>
+struct hb_accelerate_subtables_context_t :
+       hb_dispatch_context_t<hb_accelerate_subtables_context_t>
 {
   template <typename Type>
-  static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
+  static inline bool apply_to (const void *obj, 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);
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+  template <typename T>
+  static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (bool, obj->apply_cached (c) )
+  template <typename T>
+  static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<0>) HB_RETURN (bool, obj->apply (c) )
+  template <typename Type>
+  static inline bool apply_cached_to (const void *obj, hb_ot_apply_context_t *c)
+  {
+    const Type *typed_obj = (const Type *) obj;
+    return apply_cached_ (typed_obj, c, hb_prioritize);
+  }
+
+  template <typename T>
+  static inline auto cache_func_ (const T *obj, hb_ot_apply_context_t *c, bool enter, hb_priority<1>) HB_RETURN (bool, obj->cache_func (c, enter) )
+  template <typename T>
+  static inline bool cache_func_ (const T *obj, hb_ot_apply_context_t *c, bool enter, hb_priority<0>) { return false; }
+  template <typename Type>
+  static inline bool cache_func_to (const void *obj, hb_ot_apply_context_t *c, bool enter)
+  {
+    const Type *typed_obj = (const Type *) obj;
+    return cache_func_ (typed_obj, c, enter, hb_prioritize);
+  }
+#endif
+
+  typedef bool (*hb_apply_func_t) (const void *obj, hb_ot_apply_context_t *c);
+  typedef bool (*hb_cache_func_t) (const void *obj, hb_ot_apply_context_t *c, bool enter);
 
   struct hb_applicable_t
   {
+    friend struct hb_accelerate_subtables_context_t;
+    friend struct hb_ot_layout_lookup_accelerator_t;
+
     template <typename T>
-    void init (const T &obj_, hb_apply_func_t apply_func_)
+    void init (const T &obj_,
+              hb_apply_func_t apply_func_
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+              , hb_apply_func_t apply_cached_func_
+              , hb_cache_func_t cache_func_
+#endif
+               )
     {
       obj = &obj_;
       apply_func = apply_func_;
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+      apply_cached_func = apply_cached_func_;
+      cache_func = cache_func_;
+#endif
       digest.init ();
       obj_.get_coverage ().collect_coverage (&digest);
     }
 
-    bool apply (OT::hb_ot_apply_context_t *c) const
+    bool apply (hb_ot_apply_context_t *c) const
     {
       return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
     }
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+    bool apply_cached (hb_ot_apply_context_t *c) const
+    {
+      return digest.may_have (c->buffer->cur().codepoint) &&  apply_cached_func (obj, c);
+    }
+    bool cache_enter (hb_ot_apply_context_t *c) const
+    {
+      return cache_func (obj, c, true);
+    }
+    void cache_leave (hb_ot_apply_context_t *c) const
+    {
+      cache_func (obj, c, false);
+    }
+#endif
 
     private:
     const void *obj;
     hb_apply_func_t apply_func;
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+    hb_apply_func_t apply_cached_func;
+    hb_cache_func_t cache_func;
+#endif
     hb_set_digest_t digest;
   };
 
-  typedef hb_vector_t<hb_applicable_t> array_t;
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+  template <typename T>
+  auto cache_cost (const T &obj, hb_priority<1>) HB_AUTO_RETURN ( obj.cache_cost () )
+  template <typename T>
+  auto cache_cost (const T &obj, hb_priority<0>) HB_AUTO_RETURN ( 0u )
+#endif
 
   /* Dispatch interface. */
   template <typename T>
   return_t dispatch (const T &obj)
   {
-    hb_applicable_t *entry = array.push();
-    entry->init (obj, apply_to<T>);
+    hb_applicable_t *entry = &array[i++];
+
+    entry->init (obj,
+                apply_to<T>
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+                , apply_cached_to<T>
+                , cache_func_to<T>
+#endif
+                );
+
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+    /* Cache handling
+     *
+     * We allow one subtable from each lookup to use a cache. The assumption
+     * being that multiple subtables of the same lookup cannot use a cache
+     * because the resources they would use will collide.  As such, we ask
+     * each subtable to tell us how much it costs (which a cache would avoid),
+     * and we allocate the cache opportunity to the costliest subtable.
+     */
+    unsigned cost = cache_cost (obj, hb_prioritize);
+    if (cost > cache_user_cost)
+    {
+      cache_user_idx = i - 1;
+      cache_user_cost = cost;
+    }
+#endif
+
     return hb_empty_t ();
   }
   static return_t default_return_value () { return hb_empty_t (); }
 
-  hb_get_subtables_context_t (array_t &array_) :
-                             array (array_) {}
-
-  array_t &array;
-};
+  hb_accelerate_subtables_context_t (hb_applicable_t *array_) :
+                                    array (array_) {}
 
+  hb_applicable_t *array;
+  unsigned i = 0;
 
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+  unsigned cache_user_idx = (unsigned) -1;
+  unsigned cache_user_cost = 0;
+#endif
+};
 
 
-typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
-typedef void (*intersected_glyphs_func_t) (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs);
-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);
+typedef bool (*intersects_func_t) (const hb_set_t *glyphs, unsigned value, const void *data, void *cache);
+typedef void (*intersected_glyphs_func_t) (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs, void *cache);
+typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, unsigned value, const void *data);
+typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data);
 
 struct ContextClosureFuncs
 {
@@ -858,100 +1059,176 @@ struct ContextApplyFuncs
 {
   match_func_t match;
 };
+struct ChainContextApplyFuncs
+{
+  match_func_t match[3];
+};
 
 
-static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
+static inline bool intersects_glyph (const hb_set_t *glyphs, unsigned value, const void *data HB_UNUSED, void *cache HB_UNUSED)
 {
   return glyphs->has (value);
 }
-static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
+static inline bool intersects_class (const hb_set_t *glyphs, unsigned value, const void *data, void *cache)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
-  return class_def.intersects_class (glyphs, value);
+  hb_map_t *map = (hb_map_t *) cache;
+
+  hb_codepoint_t *cached_v;
+  if (map->has (value, &cached_v))
+    return *cached_v;
+
+  bool v = class_def.intersects_class (glyphs, value);
+  map->set (value, v);
+
+  return v;
 }
-static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
+static inline bool intersects_coverage (const hb_set_t *glyphs, unsigned value, const void *data, void *cache HB_UNUSED)
 {
-  const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value;
+  Offset16To<Coverage> coverage;
+  coverage = value;
   return (data+coverage).intersects (glyphs);
 }
 
 
-static inline void intersected_glyph (const hb_set_t *glyphs HB_UNUSED, const void *data, unsigned value, hb_set_t *intersected_glyphs)
+static inline void intersected_glyph (const hb_set_t *glyphs HB_UNUSED, const void *data, unsigned value, hb_set_t *intersected_glyphs, HB_UNUSED void *cache)
 {
   unsigned g = reinterpret_cast<const HBUINT16 *>(data)[value];
   intersected_glyphs->add (g);
 }
-static inline void intersected_class_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs)
+
+using intersected_class_cache_t = hb_hashmap_t<unsigned, hb_set_t>;
+
+static inline void intersected_class_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs, void *cache)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
-  class_def.intersected_class_glyphs (glyphs, value, intersected_glyphs);
+
+  intersected_class_cache_t *map = (intersected_class_cache_t *) cache;
+
+  hb_set_t *cached_v;
+  if (map->has (value, &cached_v))
+  {
+    intersected_glyphs->union_ (*cached_v);
+    return;
+  }
+
+  hb_set_t v;
+  class_def.intersected_class_glyphs (glyphs, value, &v);
+
+  intersected_glyphs->union_ (v);
+
+  map->set (value, std::move (v));
 }
-static inline void intersected_coverage_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs)
+
+static inline void intersected_coverage_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs, HB_UNUSED void *cache)
 {
   Offset16To<Coverage> coverage;
   coverage = value;
-  (data+coverage).intersected_coverage_glyphs (glyphs, intersected_glyphs);
+  (data+coverage).intersect_set (*glyphs, *intersected_glyphs);
 }
 
 
+template <typename HBUINT>
 static inline bool array_is_subset_of (const hb_set_t *glyphs,
                                       unsigned int count,
-                                      const HBUINT16 values[],
+                                      const HBUINT values[],
                                       intersects_func_t intersects_func,
-                                      const void *intersects_data)
+                                      const void *intersects_data,
+                                      void *cache)
 {
-  for (const HBUINT16 &_ : + hb_iter (values, count))
-    if (!intersects_func (glyphs, _, intersects_data)) return false;
+  for (const auto &_ : + hb_iter (values, count))
+    if (!intersects_func (glyphs, _, intersects_data, cache)) return false;
   return true;
 }
 
 
-static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
+static inline void collect_glyph (hb_set_t *glyphs, unsigned value, const void *data HB_UNUSED)
 {
   glyphs->add (value);
 }
-static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
+static inline void collect_class (hb_set_t *glyphs, unsigned value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   class_def.collect_class (glyphs, value);
 }
-static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
+static inline void collect_coverage (hb_set_t *glyphs, unsigned value, const void *data)
 {
-  const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value;
+  Offset16To<Coverage> coverage;
+  coverage = value;
   (data+coverage).collect_coverage (glyphs);
 }
+template <typename HBUINT>
 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
                                  hb_set_t *glyphs,
                                  unsigned int count,
-                                 const HBUINT16 values[],
+                                 const HBUINT values[],
                                  collect_glyphs_func_t collect_func,
                                  const void *collect_data)
 {
   return
   + hb_iter (values, count)
-  | hb_apply ([&] (const HBUINT16 &_) { collect_func (glyphs, _, collect_data); })
+  | hb_apply ([&] (const HBUINT &_) { collect_func (glyphs, _, collect_data); })
   ;
 }
 
 
-static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED)
+static inline bool match_always (hb_glyph_info_t &info HB_UNUSED, unsigned value HB_UNUSED, const void *data HB_UNUSED)
+{
+  return true;
+}
+static inline bool match_glyph (hb_glyph_info_t &info, unsigned value, const void *data HB_UNUSED)
 {
-  return glyph_id == value;
+  return info.codepoint == value;
 }
-static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
+static inline bool match_class (hb_glyph_info_t &info, unsigned value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
-  return class_def.get_class (glyph_id) == value;
+  return class_def.get_class (info.codepoint) == value;
 }
-static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
+static inline bool match_class_cached (hb_glyph_info_t &info, unsigned value, const void *data)
 {
-  const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value;
-  return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
+  unsigned klass = info.syllable();
+  if (klass < 255)
+    return klass == value;
+  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
+  klass = class_def.get_class (info.codepoint);
+  if (likely (klass < 255))
+    info.syllable() = klass;
+  return klass == value;
+}
+static inline bool match_class_cached1 (hb_glyph_info_t &info, unsigned value, const void *data)
+{
+  unsigned klass = info.syllable() & 0x0F;
+  if (klass < 15)
+    return klass == value;
+  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
+  klass = class_def.get_class (info.codepoint);
+  if (likely (klass < 15))
+    info.syllable() = (info.syllable() & 0xF0) | klass;
+  return klass == value;
+}
+static inline bool match_class_cached2 (hb_glyph_info_t &info, unsigned value, const void *data)
+{
+  unsigned klass = (info.syllable() & 0xF0) >> 4;
+  if (klass < 15)
+    return klass == value;
+  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
+  klass = class_def.get_class (info.codepoint);
+  if (likely (klass < 15))
+    info.syllable() = (info.syllable() & 0x0F) | (klass << 4);
+  return klass == value;
+}
+static inline bool match_coverage (hb_glyph_info_t &info, unsigned value, const void *data)
+{
+  Offset16To<Coverage> coverage;
+  coverage = value;
+  return (data+coverage).get_coverage (info.codepoint) != NOT_COVERED;
 }
 
+template <typename HBUINT>
 static inline bool would_match_input (hb_would_apply_context_t *c,
                                      unsigned int count, /* Including the first glyph (not matched) */
-                                     const HBUINT16 input[], /* Array of input values--start with second glyph */
+                                     const HBUINT input[], /* Array of input values--start with second glyph */
                                      match_func_t match_func,
                                      const void *match_data)
 {
@@ -959,19 +1236,27 @@ static inline bool would_match_input (hb_would_apply_context_t *c,
     return false;
 
   for (unsigned int i = 1; i < count; i++)
-    if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
+  {
+    hb_glyph_info_t info;
+    info.codepoint = c->glyphs[i];
+    if (likely (!match_func (info, input[i - 1], match_data)))
       return false;
+  }
 
   return true;
 }
-static inline bool match_input (hb_ot_apply_context_t *c,
-                               unsigned int count, /* Including the first glyph (not matched) */
-                               const HBUINT16 input[], /* Array of input values--start with second glyph */
-                               match_func_t match_func,
-                               const void *match_data,
-                               unsigned int *end_position,
-                               unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
-                               unsigned int *p_total_component_count = nullptr)
+template <typename HBUINT>
+#ifndef HB_OPTIMIZE_SIZE
+HB_ALWAYS_INLINE
+#endif
+static bool match_input (hb_ot_apply_context_t *c,
+                        unsigned int count, /* Including the first glyph (not matched) */
+                        const HBUINT input[], /* Array of input values--start with second glyph */
+                        match_func_t match_func,
+                        const void *match_data,
+                        unsigned int *end_position,
+                        unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
+                        unsigned int *p_total_component_count = nullptr)
 {
   TRACE_APPLY (nullptr);
 
@@ -980,8 +1265,9 @@ static inline bool match_input (hb_ot_apply_context_t *c,
   hb_buffer_t *buffer = c->buffer;
 
   hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
-  skippy_iter.reset (buffer->idx, count - 1);
-  skippy_iter.set_match_func (match_func, match_data, input);
+  skippy_iter.reset (buffer->idx);
+  skippy_iter.set_match_func (match_func, match_data);
+  skippy_iter.set_glyph_data (input);
 
   /*
    * This is perhaps the trickiest part of OpenType...  Remarks:
@@ -1008,7 +1294,6 @@ static inline bool match_input (hb_ot_apply_context_t *c,
    */
 
   unsigned int total_component_count = 0;
-  total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
 
   unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
   unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
@@ -1019,7 +1304,6 @@ static inline bool match_input (hb_ot_apply_context_t *c,
     LIGBASE_MAY_SKIP
   } ligbase = LIGBASE_NOT_CHECKED;
 
-  match_positions[0] = buffer->idx;
   for (unsigned int i = 1; i < count; i++)
   {
     unsigned unsafe_to;
@@ -1084,7 +1368,12 @@ static inline bool match_input (hb_ot_apply_context_t *c,
   *end_position = skippy_iter.idx + 1;
 
   if (p_total_component_count)
+  {
+    total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
     *p_total_component_count = total_component_count;
+  }
+
+  match_positions[0] = buffer->idx;
 
   return_trace (true);
 }
@@ -1202,18 +1491,23 @@ static inline bool ligate_input (hb_ot_apply_context_t *c,
   return_trace (true);
 }
 
-static inline bool match_backtrack (hb_ot_apply_context_t *c,
-                                   unsigned int count,
-                                   const HBUINT16 backtrack[],
-                                   match_func_t match_func,
-                                   const void *match_data,
-                                   unsigned int *match_start)
+template <typename HBUINT>
+#ifndef HB_OPTIMIZE_SIZE
+HB_ALWAYS_INLINE
+#endif
+static bool match_backtrack (hb_ot_apply_context_t *c,
+                            unsigned int count,
+                            const HBUINT backtrack[],
+                            match_func_t match_func,
+                            const void *match_data,
+                            unsigned int *match_start)
 {
   TRACE_APPLY (nullptr);
 
   hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
-  skippy_iter.reset (c->buffer->backtrack_len (), count);
-  skippy_iter.set_match_func (match_func, match_data, backtrack);
+  skippy_iter.reset (c->buffer->backtrack_len ());
+  skippy_iter.set_match_func (match_func, match_data);
+  skippy_iter.set_glyph_data (backtrack);
 
   for (unsigned int i = 0; i < count; i++)
   {
@@ -1229,19 +1523,24 @@ static inline bool match_backtrack (hb_ot_apply_context_t *c,
   return_trace (true);
 }
 
-static inline bool match_lookahead (hb_ot_apply_context_t *c,
-                                   unsigned int count,
-                                   const HBUINT16 lookahead[],
-                                   match_func_t match_func,
-                                   const void *match_data,
-                                   unsigned int start_index,
-                                   unsigned int *end_index)
+template <typename HBUINT>
+#ifndef HB_OPTIMIZE_SIZE
+HB_ALWAYS_INLINE
+#endif
+static bool match_lookahead (hb_ot_apply_context_t *c,
+                            unsigned int count,
+                            const HBUINT lookahead[],
+                            match_func_t match_func,
+                            const void *match_data,
+                            unsigned int start_index,
+                            unsigned int *end_index)
 {
   TRACE_APPLY (nullptr);
 
   hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
-  skippy_iter.reset (start_index - 1, count);
-  skippy_iter.set_match_func (match_func, match_data, lookahead);
+  skippy_iter.reset (start_index - 1);
+  skippy_iter.set_match_func (match_func, match_data);
+  skippy_iter.set_glyph_data (lookahead);
 
   for (unsigned int i = 0; i < count; i++)
   {
@@ -1305,27 +1604,30 @@ static unsigned serialize_lookuprecord_array (hb_serialize_context_t *c,
 
 enum ContextFormat { SimpleContext = 1, ClassBasedContext = 2, CoverageBasedContext = 3 };
 
+template <typename HBUINT>
 static void context_closure_recurse_lookups (hb_closure_context_t *c,
-                                            unsigned inputCount, const HBUINT16 input[],
+                                            unsigned inputCount, const HBUINT input[],
                                             unsigned lookupCount,
                                             const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */,
                                             unsigned value,
                                             ContextFormat context_format,
                                             const void *data,
-                                            intersected_glyphs_func_t intersected_glyphs_func)
+                                            intersected_glyphs_func_t intersected_glyphs_func,
+                                            void *cache)
 {
-  hb_set_t *covered_seq_indicies = hb_set_create ();
+  hb_set_t covered_seq_indicies;
+  hb_set_t pos_glyphs;
   for (unsigned int i = 0; i < lookupCount; i++)
   {
     unsigned seqIndex = lookupRecord[i].sequenceIndex;
     if (seqIndex >= inputCount) continue;
 
     bool has_pos_glyphs = false;
-    hb_set_t pos_glyphs;
 
-    if (hb_set_is_empty (covered_seq_indicies) || !hb_set_has (covered_seq_indicies, seqIndex))
+    if (!covered_seq_indicies.has (seqIndex))
     {
       has_pos_glyphs = true;
+      pos_glyphs.clear ();
       if (seqIndex == 0)
       {
         switch (context_format) {
@@ -1333,7 +1635,7 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c,
           pos_glyphs.add (value);
           break;
         case ContextFormat::ClassBasedContext:
-          intersected_glyphs_func (&c->parent_active_glyphs (), data, value, &pos_glyphs);
+          intersected_glyphs_func (&c->parent_active_glyphs (), data, value, &pos_glyphs, cache);
           break;
         case ContextFormat::CoverageBasedContext:
           pos_glyphs.set (c->parent_active_glyphs ());
@@ -1350,27 +1652,28 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c,
           input_value = input[seqIndex - 1];
         }
 
-        intersected_glyphs_func (c->glyphs, input_data, input_value, &pos_glyphs);
+        intersected_glyphs_func (c->glyphs, input_data, input_value, &pos_glyphs, cache);
       }
     }
 
-    covered_seq_indicies->add (seqIndex);
+    covered_seq_indicies.add (seqIndex);
+    hb_set_t *cur_active_glyphs = c->push_cur_active_glyphs ();
+    if (unlikely (!cur_active_glyphs))
+      return;
     if (has_pos_glyphs) {
-      c->push_cur_active_glyphs () = pos_glyphs;
+      *cur_active_glyphs = std::move (pos_glyphs);
     } else {
-      c->push_cur_active_glyphs ().set (*c->glyphs);
+      *cur_active_glyphs = *c->glyphs;
     }
 
     unsigned endIndex = inputCount;
     if (context_format == ContextFormat::CoverageBasedContext)
       endIndex += 1;
 
-    c->recurse (lookupRecord[i].lookupListIndex, covered_seq_indicies, seqIndex, endIndex);
+    c->recurse (lookupRecord[i].lookupListIndex, &covered_seq_indicies, seqIndex, endIndex);
 
     c->pop_cur_done_glyphs ();
   }
-
-  hb_set_destroy (covered_seq_indicies);
 }
 
 template <typename context_t>
@@ -1410,9 +1713,10 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
     if (idx >= count)
       continue;
 
-    /* Don't recurse to ourself at same position.
-     * Note that this test is too naive, it doesn't catch longer loops. */
-    if (unlikely (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index))
+    unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
+
+    /* This can happen if earlier recursed lookups deleted many entries. */
+    if (unlikely (match_positions[idx] >= orig_len))
       continue;
 
     if (unlikely (!buffer->move_to (match_positions[idx])))
@@ -1421,10 +1725,28 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
     if (unlikely (buffer->max_ops <= 0))
       break;
 
-    unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      if (buffer->have_output)
+        c->buffer->sync_so_far ();
+      c->buffer->message (c->font,
+                         "recursing to lookup %u at %u",
+                         (unsigned) lookupRecord[i].lookupListIndex,
+                         buffer->idx);
+    }
+
     if (!c->recurse (lookupRecord[i].lookupListIndex))
       continue;
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      if (buffer->have_output)
+        c->buffer->sync_so_far ();
+      c->buffer->message (c->font,
+                         "recursed to lookup %u",
+                         (unsigned) lookupRecord[i].lookupListIndex);
+    }
+
     unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
     int delta = new_len - orig_len;
 
@@ -1447,25 +1769,27 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
      *     NOT the one after it.
      *
      *   - If buffer length was decreased by n, it does not necessarily
-     *     mean that n match positions where removed, as there might
-     *     have been marks and default-ignorables in the sequence.  We
-     *     should instead drop match positions between current-position
-     *     and current-position + n instead. Though, am not sure which
-     *     one is better. Both cases have valid uses. Sigh.
+     *     mean that n match positions where removed, as there recursed-to
+     *     lookup might had a different LookupFlag.  Here's a constructed
+     *     case of that:
+     *     https://github.com/harfbuzz/harfbuzz/discussions/3538
      *
      * It should be possible to construct tests for both of these cases.
      */
 
     end += delta;
-    if (end <= int (match_positions[idx]))
+    if (end < int (match_positions[idx]))
     {
       /* End might end up being smaller than match_positions[idx] if the recursed
-       * lookup ended up removing many items, more than we have had matched.
-       * Just never rewind end back and get out of here.
-       * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
+       * lookup ended up removing many items.
+       * Just never rewind end beyond start of current position, since that is
+       * not possible in the recursed lookup.  Also adjust delta as such.
+       *
+       * https://bugs.chromium.org/p/chromium/issues/detail?id=659496
+       * https://github.com/harfbuzz/harfbuzz/issues/1611
+       */
+      delta += match_positions[idx] - end;
       end = match_positions[idx];
-      /* There can't be any further changes. */
-      break;
     }
 
     unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
@@ -1477,7 +1801,7 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
     }
     else
     {
-      /* NOTE: delta is negative. */
+      /* NOTE: delta is non-positive. */
       delta = hb_max (delta, (int) next - (int) count);
       next -= delta;
     }
@@ -1509,6 +1833,8 @@ struct ContextClosureLookupContext
   ContextClosureFuncs funcs;
   ContextFormat context_format;
   const void *intersects_data;
+  void *intersects_cache;
+  void *intersected_glyphs_cache;
 };
 
 struct ContextCollectGlyphsLookupContext
@@ -1523,19 +1849,23 @@ struct ContextApplyLookupContext
   const void *match_data;
 };
 
+template <typename HBUINT>
 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 */
+                                      const HBUINT input[], /* Array of input values--start with second glyph */
                                       ContextClosureLookupContext &lookup_context)
 {
   return array_is_subset_of (glyphs,
                             inputCount ? inputCount - 1 : 0, input,
-                            lookup_context.funcs.intersects, lookup_context.intersects_data);
+                            lookup_context.funcs.intersects,
+                            lookup_context.intersects_data,
+                            lookup_context.intersects_cache);
 }
 
+template <typename HBUINT>
 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 */
+                                          const HBUINT input[], /* Array of input values--start with second glyph */
                                           unsigned int lookupCount,
                                           const LookupRecord lookupRecord[],
                                           unsigned value, /* Index of first glyph in Coverage or Class value in ClassDef table */
@@ -1550,12 +1880,14 @@ static inline void context_closure_lookup (hb_closure_context_t *c,
                                     value,
                                     lookup_context.context_format,
                                     lookup_context.intersects_data,
-                                    lookup_context.funcs.intersected_glyphs);
+                                    lookup_context.funcs.intersected_glyphs,
+                                    lookup_context.intersected_glyphs_cache);
 }
 
+template <typename HBUINT>
 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
                                                  unsigned int inputCount, /* Including the first glyph (not matched) */
-                                                 const HBUINT16 input[], /* Array of input values--start with second glyph */
+                                                 const HBUINT input[], /* Array of input values--start with second glyph */
                                                  unsigned int lookupCount,
                                                  const LookupRecord lookupRecord[],
                                                  ContextCollectGlyphsLookupContext &lookup_context)
@@ -1567,23 +1899,27 @@ static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c
                   lookupCount, lookupRecord);
 }
 
+template <typename HBUINT>
 static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
                                               unsigned int inputCount, /* Including the first glyph (not matched) */
-                                              const HBUINT16 input[], /* Array of input values--start with second glyph */
+                                              const HBUINT input[], /* Array of input values--start with second glyph */
                                               unsigned int lookupCount HB_UNUSED,
                                               const LookupRecord lookupRecord[] HB_UNUSED,
-                                              ContextApplyLookupContext &lookup_context)
+                                              const ContextApplyLookupContext &lookup_context)
 {
   return would_match_input (c,
                            inputCount, input,
                            lookup_context.funcs.match, lookup_context.match_data);
 }
-static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
-                                        unsigned int inputCount, /* Including the first glyph (not matched) */
-                                        const HBUINT16 input[], /* Array of input values--start with second glyph */
-                                        unsigned int lookupCount,
-                                        const LookupRecord lookupRecord[],
-                                        ContextApplyLookupContext &lookup_context)
+
+template <typename HBUINT>
+HB_ALWAYS_INLINE
+static bool context_apply_lookup (hb_ot_apply_context_t *c,
+                                 unsigned int inputCount, /* Including the first glyph (not matched) */
+                                 const HBUINT input[], /* Array of input values--start with second glyph */
+                                 unsigned int lookupCount,
+                                 const LookupRecord lookupRecord[],
+                                 const ContextApplyLookupContext &lookup_context)
 {
   unsigned match_end = 0;
   unsigned match_positions[HB_MAX_CONTEXT_LENGTH];
@@ -1606,8 +1942,12 @@ static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
   }
 }
 
+template <typename Types>
 struct Rule
 {
+  template <typename T>
+  friend struct RuleSet;
+
   bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
   {
     return context_intersects (glyphs,
@@ -1619,8 +1959,8 @@ struct Rule
   {
     if (unlikely (c->lookup_limit_exceeded ())) return;
 
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
-                                                      (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
+    const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+                                          (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
     context_closure_lookup (c,
                            inputCount, inputZ.arrayZ,
                            lookupCount, lookupRecord.arrayZ,
@@ -1633,16 +1973,16 @@ struct Rule
     if (unlikely (c->lookup_limit_exceeded ())) return;
     if (!intersects (c->glyphs, lookup_context)) return;
 
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
-                                                      (inputZ.as_array (inputCount ? inputCount - 1 : 0));
+    const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+                                          (inputZ.as_array (inputCount ? inputCount - 1 : 0));
     recurse_lookups (c, lookupCount, lookupRecord.arrayZ);
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c,
                       ContextCollectGlyphsLookupContext &lookup_context) const
   {
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
-                                                      (inputZ.as_array (inputCount ? inputCount - 1 : 0));
+    const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+                                          (inputZ.as_array (inputCount ? inputCount - 1 : 0));
     context_collect_glyphs_lookup (c,
                                   inputCount, inputZ.arrayZ,
                                   lookupCount, lookupRecord.arrayZ,
@@ -1650,10 +1990,10 @@ struct Rule
   }
 
   bool would_apply (hb_would_apply_context_t *c,
-                   ContextApplyLookupContext &lookup_context) const
+                   const ContextApplyLookupContext &lookup_context) const
   {
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
-                                                      (inputZ.as_array (inputCount ? inputCount - 1 : 0));
+    const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+                                          (inputZ.as_array (inputCount ? inputCount - 1 : 0));
     return context_would_apply_lookup (c,
                                       inputCount, inputZ.arrayZ,
                                       lookupCount, lookupRecord.arrayZ,
@@ -1661,11 +2001,11 @@ struct Rule
   }
 
   bool apply (hb_ot_apply_context_t *c,
-             ContextApplyLookupContext &lookup_context) const
+             const ContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
-                                                      (inputZ.as_array (inputCount ? inputCount - 1 : 0));
+    const auto &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));
   }
 
@@ -1678,7 +2018,7 @@ struct Rule
     if (unlikely (!c->extend_min (out))) return_trace (false);
 
     out->inputCount = inputCount;
-    const hb_array_t<const HBUINT16> input = inputZ.as_array (inputCount - 1);
+    const auto input = inputZ.as_array (inputCount - 1);
     for (const auto org : input)
     {
       HBUINT16 d;
@@ -1686,8 +2026,8 @@ struct Rule
       c->copy (d);
     }
 
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
-                                                      (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
+    const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+                                          (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
 
     unsigned count = serialize_lookuprecord_array (c, lookupRecord.as_array (lookupCount), lookup_map);
     return_trace (c->check_assign (out->lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
@@ -1699,7 +2039,7 @@ struct Rule
   {
     TRACE_SUBSET (this);
     if (unlikely (!inputCount)) return_trace (false);
-    const hb_array_t<const HBUINT16> input = inputZ.as_array (inputCount - 1);
+    const auto input = inputZ.as_array (inputCount - 1);
 
     const hb_map_t *mapping = klass_map == nullptr ? c->plan->glyph_map : klass_map;
     if (!hb_all (input, mapping)) return_trace (false);
@@ -1710,8 +2050,7 @@ struct Rule
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (inputCount.sanitize (c) &&
-                 lookupCount.sanitize (c) &&
+    return_trace (c->check_struct (this) &&
                  c->check_range (inputZ.arrayZ,
                                  inputZ.item_size * (inputCount ? inputCount - 1 : 0) +
                                  LookupRecord::static_size * lookupCount));
@@ -1722,7 +2061,7 @@ struct Rule
                                         * glyph sequence--includes the first
                                         * glyph */
   HBUINT16     lookupCount;            /* Number of LookupRecords */
-  UnsizedArrayOf<HBUINT16>
+  UnsizedArrayOf<typename Types::HBUINT>
                inputZ;                 /* Array of match inputs--start with
                                         * second glyph */
 /*UnsizedArrayOf<LookupRecord>
@@ -1732,8 +2071,11 @@ struct Rule
   DEFINE_SIZE_ARRAY (4, inputZ);
 };
 
+template <typename Types>
 struct RuleSet
 {
+  using Rule = OT::Rule<Types>;
+
   bool intersects (const hb_set_t *glyphs,
                   ContextClosureLookupContext &lookup_context) const
   {
@@ -1778,7 +2120,7 @@ struct RuleSet
   }
 
   bool would_apply (hb_would_apply_context_t *c,
-                   ContextApplyLookupContext &lookup_context) const
+                   const ContextApplyLookupContext &lookup_context) const
   {
     return
     + hb_iter (rule)
@@ -1789,16 +2131,108 @@ struct RuleSet
   }
 
   bool apply (hb_ot_apply_context_t *c,
-             ContextApplyLookupContext &lookup_context) const
+             const ContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
-    return_trace (
-    + hb_iter (rule)
-    | hb_map (hb_add (this))
-    | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
-    | hb_any
-    )
-    ;
+
+    unsigned num_rules = rule.len;
+
+#ifndef HB_NO_OT_RULESETS_FAST_PATH
+    if (HB_OPTIMIZE_SIZE_VAL || num_rules <= 4)
+#endif
+    {
+    slow:
+      return_trace (
+      + hb_iter (rule)
+      | hb_map (hb_add (this))
+      | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
+      | hb_any
+      )
+      ;
+    }
+
+    /* This version is optimized for speed by matching the first & second
+     * components of the rule here, instead of calling into the matching code.
+     *
+     * Replicated from LigatureSet::apply(). */
+
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (c->buffer->idx);
+    skippy_iter.set_match_func (match_always, nullptr);
+    skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
+    unsigned unsafe_to = (unsigned) -1, unsafe_to1 = 0, unsafe_to2 = 0;
+    hb_glyph_info_t *first = nullptr, *second = nullptr;
+    bool matched = skippy_iter.next ();
+    if (likely (matched))
+    {
+      first = &c->buffer->info[skippy_iter.idx];
+      unsafe_to = skippy_iter.idx + 1;
+
+      if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
+      {
+       /* Can't use the fast path if eg. the next char is a default-ignorable
+        * or other skippable. */
+        goto slow;
+      }
+    }
+    else
+    {
+      /* Failed to match a next glyph. Only try applying rules that have
+       * no further input. */
+      return_trace (
+      + hb_iter (rule)
+      | hb_map (hb_add (this))
+      | hb_filter ([&] (const Rule &_) { return _.inputCount <= 1; })
+      | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
+      | hb_any
+      )
+      ;
+    }
+    matched = skippy_iter.next ();
+    if (likely (matched && !skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])))
+    {
+      second = &c->buffer->info[skippy_iter.idx];
+      unsafe_to2 = skippy_iter.idx + 1;
+    }
+
+    auto match_input = lookup_context.funcs.match;
+    auto *input_data = lookup_context.match_data;
+    for (unsigned int i = 0; i < num_rules; i++)
+    {
+      const auto &r = this+rule.arrayZ[i];
+
+      const auto &input = r.inputZ;
+
+      if (r.inputCount <= 1 ||
+         (!match_input ||
+          match_input (*first, input.arrayZ[0], input_data)))
+      {
+        if (!second ||
+           (r.inputCount <= 2 ||
+            (!match_input ||
+             match_input (*second, input.arrayZ[1], input_data)))
+          )
+       {
+         if (r.apply (c, lookup_context))
+         {
+           if (unsafe_to != (unsigned) -1)
+             c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
+           return_trace (true);
+         }
+       }
+       else
+         unsafe_to = unsafe_to2;
+      }
+      else
+      {
+       if (unsafe_to == (unsigned) -1)
+         unsafe_to = unsafe_to1;
+      }
+    }
+    if (likely (unsafe_to != (unsigned) -1))
+      c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
+
+    return_trace (false);
   }
 
   bool subset (hb_subset_context_t *c,
@@ -1846,8 +2280,11 @@ struct RuleSet
 };
 
 
-struct ContextFormat1
+template <typename Types>
+struct ContextFormat1_4
 {
+  using RuleSet = OT::RuleSet<Types>;
+
   bool intersects (const hb_set_t *glyphs) const
   {
     struct ContextClosureLookupContext lookup_context = {
@@ -1871,9 +2308,9 @@ struct ContextFormat1
 
   void closure (hb_closure_context_t *c) const
   {
-    hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs ();
-    get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (),
-                                                 cur_active_glyphs);
+    hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
+    if (unlikely (!cur_active_glyphs)) return;
+    get_coverage ().intersect_set (c->previous_parent_active_glyphs (), *cur_active_glyphs);
 
     struct ContextClosureLookupContext lookup_context = {
       {intersects_glyph, intersected_glyph},
@@ -1895,7 +2332,7 @@ struct ContextFormat1
   void closure_lookups (hb_closure_lookups_context_t *c) const
   {
     struct ContextClosureLookupContext lookup_context = {
-      {intersects_glyph, intersected_glyph},
+      {intersects_glyph, nullptr},
       ContextFormat::SimpleContext,
       nullptr
     };
@@ -1962,7 +2399,7 @@ struct ContextFormat1
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
     out->format = format;
 
-    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
+    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? &c->plan->gsub_lookups : &c->plan->gpos_lookups;
     hb_sorted_vector_t<hb_codepoint_t> new_coverage;
     + hb_zip (this+coverage, ruleSet)
     | hb_filter (glyphset, hb_first)
@@ -1984,19 +2421,22 @@ struct ContextFormat1
 
   protected:
   HBUINT16     format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
                                         * beginning of table */
-  Array16OfOffset16To<RuleSet>
+  Array16Of<typename Types::template OffsetTo<RuleSet>>
                ruleSet;                /* Array of RuleSet tables
                                         * ordered by Coverage Index */
   public:
-  DEFINE_SIZE_ARRAY (6, ruleSet);
+  DEFINE_SIZE_ARRAY (2 + 2 * Types::size, ruleSet);
 };
 
 
-struct ContextFormat2
+template <typename Types>
+struct ContextFormat2_5
 {
+  using RuleSet = OT::RuleSet<SmallTypes>;
+
   bool intersects (const hb_set_t *glyphs) const
   {
     if (!(this+coverage).intersects (glyphs))
@@ -2004,14 +2444,16 @@ struct ContextFormat2
 
     const ClassDef &class_def = this+classDef;
 
+    hb_map_t cache;
     struct ContextClosureLookupContext lookup_context = {
-      {intersects_class, intersected_class_glyphs},
+      {intersects_class, nullptr},
       ContextFormat::ClassBasedContext,
-      &class_def
+      &class_def,
+      &cache
     };
 
     hb_set_t retained_coverage_glyphs;
-    (this+coverage).intersected_coverage_glyphs (glyphs, &retained_coverage_glyphs);
+    (this+coverage).intersect_set (*glyphs, retained_coverage_glyphs);
 
     hb_set_t coverage_glyph_classes;
     class_def.intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
@@ -2037,23 +2479,28 @@ struct ContextFormat2
     if (!(this+coverage).intersects (c->glyphs))
       return;
 
-    hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs ();
-    get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (),
-                                                 cur_active_glyphs);
+    hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
+    if (unlikely (!cur_active_glyphs)) return;
+    get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
+                                  *cur_active_glyphs);
 
     const ClassDef &class_def = this+classDef;
 
+    hb_map_t cache;
+    intersected_class_cache_t intersected_cache;
     struct ContextClosureLookupContext lookup_context = {
       {intersects_class, intersected_class_glyphs},
       ContextFormat::ClassBasedContext,
-      &class_def
+      &class_def,
+      &cache,
+      &intersected_cache
     };
 
     + hb_enumerate (ruleSet)
     | hb_filter ([&] (unsigned _)
     { return class_def.intersects_class (&c->parent_active_glyphs (), _); },
                 hb_first)
-    | hb_apply ([&] (const hb_pair_t<unsigned, const Offset16To<RuleSet>&> _)
+    | hb_apply ([&] (const hb_pair_t<unsigned, const typename Types::template OffsetTo<RuleSet>&> _)
                 {
                   const RuleSet& rule_set = this+_.second;
                   rule_set.closure (c, _.first, lookup_context);
@@ -2070,10 +2517,12 @@ struct ContextFormat2
 
     const ClassDef &class_def = this+classDef;
 
+    hb_map_t cache;
     struct ContextClosureLookupContext lookup_context = {
-      {intersects_class, intersected_class_glyphs},
+      {intersects_class, nullptr},
       ContextFormat::ClassBasedContext,
-      &class_def
+      &class_def,
+      &cache
     };
 
     + hb_iter (ruleSet)
@@ -2118,19 +2567,52 @@ struct ContextFormat2
 
   const Coverage &get_coverage () const { return this+coverage; }
 
-  bool apply (hb_ot_apply_context_t *c) const
+  unsigned cache_cost () const
+  {
+    unsigned c = (this+classDef).cost () * ruleSet.len;
+    return c >= 4 ? c : 0;
+  }
+  bool cache_func (hb_ot_apply_context_t *c, bool enter) const
+  {
+    if (enter)
+    {
+      if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable))
+       return false;
+      auto &info = c->buffer->info;
+      unsigned count = c->buffer->len;
+      for (unsigned i = 0; i < count; i++)
+       info[i].syllable() = 255;
+      c->new_syllables = 255;
+      return true;
+    }
+    else
+    {
+      c->new_syllables = (unsigned) -1;
+      HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable);
+      return true;
+    }
+  }
+
+  bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
+  bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
+  bool _apply (hb_ot_apply_context_t *c, bool cached) const
   {
     TRACE_APPLY (this);
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     const ClassDef &class_def = this+classDef;
-    index = class_def.get_class (c->buffer->cur().codepoint);
-    const RuleSet &rule_set = this+ruleSet[index];
+
     struct ContextApplyLookupContext lookup_context = {
-      {match_class},
+      {cached ? match_class_cached : match_class},
       &class_def
     };
+
+    if (cached && c->buffer->cur().syllable() < 255)
+      index = c->buffer->cur().syllable ();
+    else
+      index = class_def.get_class (c->buffer->cur().codepoint);
+    const RuleSet &rule_set = this+ruleSet[index];
     return_trace (rule_set.apply (c, lookup_context));
   }
 
@@ -2148,14 +2630,15 @@ struct ContextFormat2
 
     const hb_set_t* glyphset = c->plan->glyphset_gsub ();
     hb_set_t retained_coverage_glyphs;
-    (this+coverage).intersected_coverage_glyphs (glyphset, &retained_coverage_glyphs);
+    (this+coverage).intersect_set (*glyphset, retained_coverage_glyphs);
 
     hb_set_t coverage_glyph_classes;
     (this+classDef).intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
 
-    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
+    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? &c->plan->gsub_lookups : &c->plan->gpos_lookups;
     bool ret = true;
     int non_zero_index = -1, index = 0;
+    auto snapshot = c->serializer->snapshot();
     for (const auto& _ : + hb_enumerate (ruleSet)
                         | hb_filter (klass_map, hb_first))
     {
@@ -2167,8 +2650,10 @@ struct ContextFormat2
       }
 
       if (coverage_glyph_classes.has (_.first) &&
-         o->serialize_subset (c, _.second, this, lookup_map, &klass_map))
+         o->serialize_subset (c, _.second, this, lookup_map, &klass_map)) {
        non_zero_index = index;
+        snapshot = c->serializer->snapshot();
+      }
 
       index++;
     }
@@ -2182,6 +2667,7 @@ struct ContextFormat2
       out->ruleSet.pop ();
       index--;
     }
+    c->serializer->revert (snapshot);
 
     return_trace (bool (out->ruleSet));
   }
@@ -2194,29 +2680,31 @@ struct ContextFormat2
 
   protected:
   HBUINT16     format;                 /* Format identifier--format = 2 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
                                         * beginning of table */
-  Offset16To<ClassDef>
+  typename Types::template OffsetTo<ClassDef>
                classDef;               /* Offset to glyph ClassDef table--from
                                         * beginning of table */
-  Array16OfOffset16To<RuleSet>
+  Array16Of<typename Types::template OffsetTo<RuleSet>>
                ruleSet;                /* Array of RuleSet tables
                                         * ordered by class */
   public:
-  DEFINE_SIZE_ARRAY (8, ruleSet);
+  DEFINE_SIZE_ARRAY (4 + 2 * Types::size, ruleSet);
 };
 
 
 struct ContextFormat3
 {
+  using RuleSet = OT::RuleSet<SmallTypes>;
+
   bool intersects (const hb_set_t *glyphs) const
   {
     if (!(this+coverageZ[0]).intersects (glyphs))
       return false;
 
     struct ContextClosureLookupContext lookup_context = {
-      {intersects_coverage, intersected_coverage_glyphs},
+      {intersects_coverage, nullptr},
       ContextFormat::CoverageBasedContext,
       this
     };
@@ -2233,10 +2721,10 @@ struct ContextFormat3
     if (!(this+coverageZ[0]).intersects (c->glyphs))
       return;
 
-    hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs ();
-    get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (),
-                                                 cur_active_glyphs);
-
+    hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
+    if (unlikely (!cur_active_glyphs)) return;
+    get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
+                                  *cur_active_glyphs);
 
     const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
     struct ContextClosureLookupContext lookup_context = {
@@ -2326,8 +2814,8 @@ struct ContextFormat3
       if (!o->serialize_subset (c, offset, this)) return_trace (false);
     }
 
-    const UnsizedArrayOf<LookupRecord>& lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>> (coverageZ.as_array (glyphCount));
-    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
+    const auto& lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>> (coverageZ.as_array (glyphCount));
+    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? &c->plan->gsub_lookups : &c->plan->gpos_lookups;
 
 
     unsigned count = serialize_lookuprecord_array (c->serializer, lookupRecord.as_array (lookupCount), lookup_map);
@@ -2337,14 +2825,14 @@ struct ContextFormat3
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (!c->check_struct (this)) return_trace (false);
+    if (unlikely (!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.arrayZ, count)) return_trace (false);
+    if (unlikely (!count)) return_trace (false); /* We want to access coverageZ[0] freely. */
+    if (unlikely (!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);
+      if (unlikely (!coverageZ[i].sanitize (c, this))) return_trace (false);
     const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
-    return_trace (c->check_array (lookupRecord, lookupCount));
+    return_trace (likely (c->check_array (lookupRecord, lookupCount)));
   }
 
   protected:
@@ -2367,22 +2855,30 @@ struct Context
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
     case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+#ifndef HB_NO_BEYOND_64K
+    case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+    case 5: return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  HBUINT16             format;         /* Format identifier */
-  ContextFormat1       format1;
-  ContextFormat2       format2;
-  ContextFormat3       format3;
+  HBUINT16                     format;         /* Format identifier */
+  ContextFormat1_4<SmallTypes> format1;
+  ContextFormat2_5<SmallTypes> format2;
+  ContextFormat3               format3;
+#ifndef HB_NO_BEYOND_64K
+  ContextFormat1_4<MediumTypes>        format4;
+  ContextFormat2_5<MediumTypes>        format5;
+#endif
   } u;
 };
 
@@ -2394,6 +2890,8 @@ struct ChainContextClosureLookupContext
   ContextClosureFuncs funcs;
   ContextFormat context_format;
   const void *intersects_data[3];
+  void *intersects_cache[3];
+  void *intersected_glyphs_cache;
 };
 
 struct ChainContextCollectGlyphsLookupContext
@@ -2404,37 +2902,45 @@ struct ChainContextCollectGlyphsLookupContext
 
 struct ChainContextApplyLookupContext
 {
-  ContextApplyFuncs funcs;
+  ChainContextApplyFuncs funcs;
   const void *match_data[3];
 };
 
+template <typename HBUINT>
 static inline bool chain_context_intersects (const hb_set_t *glyphs,
                                             unsigned int backtrackCount,
-                                            const HBUINT16 backtrack[],
+                                            const HBUINT backtrack[],
                                             unsigned int inputCount, /* Including the first glyph (not matched) */
-                                            const HBUINT16 input[], /* Array of input values--start with second glyph */
+                                            const HBUINT input[], /* Array of input values--start with second glyph */
                                             unsigned int lookaheadCount,
-                                            const HBUINT16 lookahead[],
+                                            const HBUINT lookahead[],
                                             ChainContextClosureLookupContext &lookup_context)
 {
   return array_is_subset_of (glyphs,
                             backtrackCount, backtrack,
-                            lookup_context.funcs.intersects, lookup_context.intersects_data[0])
+                            lookup_context.funcs.intersects,
+                            lookup_context.intersects_data[0],
+                            lookup_context.intersects_cache[0])
       && array_is_subset_of (glyphs,
                             inputCount ? inputCount - 1 : 0, input,
-                            lookup_context.funcs.intersects, lookup_context.intersects_data[1])
+                            lookup_context.funcs.intersects,
+                            lookup_context.intersects_data[1],
+                            lookup_context.intersects_cache[1])
       && array_is_subset_of (glyphs,
                             lookaheadCount, lookahead,
-                            lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
+                            lookup_context.funcs.intersects,
+                            lookup_context.intersects_data[2],
+                            lookup_context.intersects_cache[2]);
 }
 
+template <typename HBUINT>
 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
                                                 unsigned int backtrackCount,
-                                                const HBUINT16 backtrack[],
+                                                const HBUINT backtrack[],
                                                 unsigned int inputCount, /* Including the first glyph (not matched) */
-                                                const HBUINT16 input[], /* Array of input values--start with second glyph */
+                                                const HBUINT input[], /* Array of input values--start with second glyph */
                                                 unsigned int lookaheadCount,
-                                                const HBUINT16 lookahead[],
+                                                const HBUINT lookahead[],
                                                 unsigned int lookupCount,
                                                 const LookupRecord lookupRecord[],
                                                 unsigned value,
@@ -2451,16 +2957,18 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c,
                     value,
                     lookup_context.context_format,
                     lookup_context.intersects_data[1],
-                    lookup_context.funcs.intersected_glyphs);
+                    lookup_context.funcs.intersected_glyphs,
+                    lookup_context.intersected_glyphs_cache);
 }
 
+template <typename HBUINT>
 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
                                                        unsigned int backtrackCount,
-                                                       const HBUINT16 backtrack[],
+                                                       const HBUINT backtrack[],
                                                        unsigned int inputCount, /* Including the first glyph (not matched) */
-                                                       const HBUINT16 input[], /* Array of input values--start with second glyph */
+                                                       const HBUINT input[], /* Array of input values--start with second glyph */
                                                        unsigned int lookaheadCount,
-                                                       const HBUINT16 lookahead[],
+                                                       const HBUINT lookahead[],
                                                        unsigned int lookupCount,
                                                        const LookupRecord lookupRecord[],
                                                        ChainContextCollectGlyphsLookupContext &lookup_context)
@@ -2478,44 +2986,47 @@ static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_contex
                   lookupCount, lookupRecord);
 }
 
+template <typename HBUINT>
 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
                                                     unsigned int backtrackCount,
-                                                    const HBUINT16 backtrack[] HB_UNUSED,
+                                                    const HBUINT backtrack[] HB_UNUSED,
                                                     unsigned int inputCount, /* Including the first glyph (not matched) */
-                                                    const HBUINT16 input[], /* Array of input values--start with second glyph */
+                                                    const HBUINT input[], /* Array of input values--start with second glyph */
                                                     unsigned int lookaheadCount,
-                                                    const HBUINT16 lookahead[] HB_UNUSED,
+                                                    const HBUINT lookahead[] HB_UNUSED,
                                                     unsigned int lookupCount HB_UNUSED,
                                                     const LookupRecord lookupRecord[] HB_UNUSED,
-                                                    ChainContextApplyLookupContext &lookup_context)
+                                                    const ChainContextApplyLookupContext &lookup_context)
 {
   return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
       && would_match_input (c,
                            inputCount, input,
-                           lookup_context.funcs.match, lookup_context.match_data[1]);
+                           lookup_context.funcs.match[1], lookup_context.match_data[1]);
 }
 
-static inline bool chain_context_apply_lookup (hb_ot_apply_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[],
-                                              ChainContextApplyLookupContext &lookup_context)
+template <typename HBUINT>
+HB_ALWAYS_INLINE
+static bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
+                                       unsigned int backtrackCount,
+                                       const HBUINT backtrack[],
+                                       unsigned int inputCount, /* Including the first glyph (not matched) */
+                                       const HBUINT input[], /* Array of input values--start with second glyph */
+                                       unsigned int lookaheadCount,
+                                       const HBUINT lookahead[],
+                                       unsigned int lookupCount,
+                                       const LookupRecord lookupRecord[],
+                                       const ChainContextApplyLookupContext &lookup_context)
 {
   unsigned end_index = c->buffer->idx;
   unsigned match_end = 0;
   unsigned match_positions[HB_MAX_CONTEXT_LENGTH];
   if (!(match_input (c,
                     inputCount, input,
-                    lookup_context.funcs.match, lookup_context.match_data[1],
+                    lookup_context.funcs.match[1], lookup_context.match_data[1],
                     &match_end, match_positions) && (end_index = match_end)
        && match_lookahead (c,
                           lookaheadCount, lookahead,
-                          lookup_context.funcs.match, lookup_context.match_data[2],
+                          lookup_context.funcs.match[2], lookup_context.match_data[2],
                           match_end, &end_index)))
   {
     c->buffer->unsafe_to_concat (c->buffer->idx, end_index);
@@ -2525,7 +3036,7 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
   unsigned start_index = c->buffer->out_len;
   if (!match_backtrack (c,
                        backtrackCount, backtrack,
-                       lookup_context.funcs.match, lookup_context.match_data[0],
+                       lookup_context.funcs.match[0], lookup_context.match_data[0],
                        &start_index))
   {
     c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index);
@@ -2540,12 +3051,16 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
   return true;
 }
 
+template <typename Types>
 struct ChainRule
 {
+  template <typename T>
+  friend struct ChainRuleSet;
+
   bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
   {
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
     return chain_context_intersects (glyphs,
                                     backtrack.len, backtrack.arrayZ,
                                     input.lenP1, input.arrayZ,
@@ -2558,9 +3073,9 @@ struct ChainRule
   {
     if (unlikely (c->lookup_limit_exceeded ())) return;
 
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     chain_context_closure_lookup (c,
                                  backtrack.len, backtrack.arrayZ,
                                  input.lenP1, input.arrayZ,
@@ -2576,18 +3091,18 @@ struct ChainRule
     if (unlikely (c->lookup_limit_exceeded ())) return;
     if (!intersects (c->glyphs, lookup_context)) return;
 
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     recurse_lookups (c, lookup.len, lookup.arrayZ);
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c,
                       ChainContextCollectGlyphsLookupContext &lookup_context) const
   {
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     chain_context_collect_glyphs_lookup (c,
                                         backtrack.len, backtrack.arrayZ,
                                         input.lenP1, input.arrayZ,
@@ -2597,11 +3112,11 @@ struct ChainRule
   }
 
   bool would_apply (hb_would_apply_context_t *c,
-                   ChainContextApplyLookupContext &lookup_context) const
+                   const ChainContextApplyLookupContext &lookup_context) const
   {
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     return chain_context_would_apply_lookup (c,
                                             backtrack.len, backtrack.arrayZ,
                                             input.lenP1, input.arrayZ,
@@ -2609,12 +3124,13 @@ struct ChainRule
                                             lookup.arrayZ, lookup_context);
   }
 
-  bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+  bool apply (hb_ot_apply_context_t *c,
+             const ChainContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     return_trace (chain_context_apply_lookup (c,
                                              backtrack.len, backtrack.arrayZ,
                                              input.lenP1, input.arrayZ,
@@ -2640,29 +3156,27 @@ struct ChainRule
                  const hb_map_t *lookahead_map = nullptr) const
   {
     TRACE_SERIALIZE (this);
-    auto *out = c->start_embed (this);
-    if (unlikely (!out)) return_trace (false);
 
     const hb_map_t *mapping = backtrack_map;
     serialize_array (c, backtrack.len, + backtrack.iter ()
                                       | hb_map (mapping));
 
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
     if (input_map) mapping = input_map;
     serialize_array (c, input.lenP1, + input.iter ()
                                     | hb_map (mapping));
 
-    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
     if (lookahead_map) mapping = lookahead_map;
     serialize_array (c, lookahead.len, + lookahead.iter ()
                                       | hb_map (mapping));
 
-    const Array16Of<LookupRecord> &lookupRecord = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
 
-    HBUINT16* lookupCount = c->embed (&(lookupRecord.len));
+    HBUINT16* lookupCount = c->embed (&(lookup.len));
     if (!lookupCount) return_trace (false);
 
-    unsigned count = serialize_lookuprecord_array (c, lookupRecord.as_array (), lookup_map);
+    unsigned count = serialize_lookuprecord_array (c, lookup.as_array (), lookup_map);
     return_trace (c->check_assign (*lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
   }
 
@@ -2674,8 +3188,8 @@ struct ChainRule
   {
     TRACE_SUBSET (this);
 
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
 
     if (!backtrack_map)
     {
@@ -2703,24 +3217,25 @@ struct ChainRule
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (!backtrack.sanitize (c)) return_trace (false);
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    if (!input.sanitize (c)) return_trace (false);
-    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
-    if (!lookahead.sanitize (c)) return_trace (false);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
-    return_trace (lookup.sanitize (c));
+    /* Hyper-optimized sanitized because this is really hot. */
+    if (unlikely (!backtrack.len.sanitize (c))) return_trace (false);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    if (unlikely (!input.lenP1.sanitize (c))) return_trace (false);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    if (unlikely (!lookahead.len.sanitize (c))) return_trace (false);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
+    return_trace (likely (lookup.sanitize (c)));
   }
 
   protected:
-  Array16Of<HBUINT16>
+  Array16Of<typename Types::HBUINT>
                backtrack;              /* Array of backtracking values
                                         * (to be matched before the input
                                         * sequence) */
-  HeadlessArrayOf<HBUINT16>
+  HeadlessArray16Of<typename Types::HBUINT>
                inputX;                 /* Array of input values (start with
                                         * second glyph) */
-  Array16Of<HBUINT16>
+  Array16Of<typename Types::HBUINT>
                lookaheadX;             /* Array of lookahead values's (to be
                                         * matched after the input sequence) */
   Array16Of<LookupRecord>
@@ -2730,8 +3245,11 @@ struct ChainRule
   DEFINE_SIZE_MIN (8);
 };
 
+template <typename Types>
 struct ChainRuleSet
 {
+  using ChainRule = OT::ChainRule<Types>;
+
   bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
   {
     return
@@ -2772,7 +3290,8 @@ struct ChainRuleSet
     ;
   }
 
-  bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+  bool would_apply (hb_would_apply_context_t *c,
+                   const ChainContextApplyLookupContext &lookup_context) const
   {
     return
     + hb_iter (rule)
@@ -2782,16 +3301,123 @@ struct ChainRuleSet
     ;
   }
 
-  bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+  bool apply (hb_ot_apply_context_t *c,
+             const ChainContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
-    return_trace (
-    + hb_iter (rule)
-    | hb_map (hb_add (this))
-    | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
-    | hb_any
-    )
-    ;
+
+    unsigned num_rules = rule.len;
+
+#ifndef HB_NO_OT_RULESETS_FAST_PATH
+    if (HB_OPTIMIZE_SIZE_VAL || num_rules <= 4)
+#endif
+    {
+    slow:
+      return_trace (
+      + hb_iter (rule)
+      | hb_map (hb_add (this))
+      | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
+      | hb_any
+      )
+      ;
+    }
+
+    /* This version is optimized for speed by matching the first & second
+     * components of the rule here, instead of calling into the matching code.
+     *
+     * Replicated from LigatureSet::apply(). */
+
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (c->buffer->idx);
+    skippy_iter.set_match_func (match_always, nullptr);
+    skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
+    unsigned unsafe_to = (unsigned) -1, unsafe_to1 = 0, unsafe_to2 = 0;
+    hb_glyph_info_t *first = nullptr, *second = nullptr;
+    bool matched = skippy_iter.next ();
+    if (likely (matched))
+    {
+      first = &c->buffer->info[skippy_iter.idx];
+      unsafe_to1 = skippy_iter.idx + 1;
+
+      if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
+      {
+       /* Can't use the fast path if eg. the next char is a default-ignorable
+        * or other skippable. */
+        goto slow;
+      }
+    }
+    else
+    {
+      /* Failed to match a next glyph. Only try applying rules that have
+       * no further input and lookahead. */
+      return_trace (
+      + hb_iter (rule)
+      | hb_map (hb_add (this))
+      | hb_filter ([&] (const ChainRule &_)
+                  {
+                    const auto &input = StructAfter<decltype (_.inputX)> (_.backtrack);
+                    const auto &lookahead = StructAfter<decltype (_.lookaheadX)> (input);
+                    return input.lenP1 <= 1 && lookahead.len == 0;
+                  })
+      | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
+      | hb_any
+      )
+      ;
+    }
+    matched = skippy_iter.next ();
+    if (likely (matched && !skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])))
+     {
+      second = &c->buffer->info[skippy_iter.idx];
+      unsafe_to2 = skippy_iter.idx + 1;
+     }
+
+    auto match_input = lookup_context.funcs.match[1];
+    auto match_lookahead = lookup_context.funcs.match[2];
+    auto *input_data = lookup_context.match_data[1];
+    auto *lookahead_data = lookup_context.match_data[2];
+    for (unsigned int i = 0; i < num_rules; i++)
+    {
+      const auto &r = this+rule.arrayZ[i];
+
+      const auto &input = StructAfter<decltype (r.inputX)> (r.backtrack);
+      const auto &lookahead = StructAfter<decltype (r.lookaheadX)> (input);
+
+      unsigned lenP1 = hb_max ((unsigned) input.lenP1, 1u);
+      if (lenP1 > 1 ?
+          (!match_input ||
+           match_input (*first, input.arrayZ[0], input_data))
+         :
+          (!lookahead.len || !match_lookahead ||
+           match_lookahead (*first, lookahead.arrayZ[0], lookahead_data)))
+      {
+        if (!second ||
+           (lenP1 > 2 ?
+            (!match_input ||
+             match_input (*second, input.arrayZ[1], input_data))
+            :
+            (lookahead.len <= 2 - lenP1 || !match_lookahead ||
+             match_lookahead (*second, lookahead.arrayZ[2 - lenP1], lookahead_data))))
+       {
+         if (r.apply (c, lookup_context))
+         {
+           if (unsafe_to != (unsigned) -1)
+             c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
+           return_trace (true);
+         }
+       }
+       else
+         unsafe_to = unsafe_to2;
+      }
+      else
+      {
+       if (unsafe_to == (unsigned) -1)
+         unsafe_to = unsafe_to1;
+      }
+    }
+    if (likely (unsafe_to != (unsigned) -1))
+      c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
+
+    return_trace (false);
   }
 
   bool subset (hb_subset_context_t *c,
@@ -2844,8 +3470,11 @@ struct ChainRuleSet
   DEFINE_SIZE_ARRAY (2, rule);
 };
 
-struct ChainContextFormat1
+template <typename Types>
+struct ChainContextFormat1_4
 {
+  using ChainRuleSet = OT::ChainRuleSet<Types>;
+
   bool intersects (const hb_set_t *glyphs) const
   {
     struct ChainContextClosureLookupContext lookup_context = {
@@ -2869,9 +3498,10 @@ struct ChainContextFormat1
 
   void closure (hb_closure_context_t *c) const
   {
-    hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs ();
-    get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (),
-                                                 cur_active_glyphs);
+    hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
+    if (unlikely (!cur_active_glyphs)) return;
+    get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
+                                  *cur_active_glyphs);
 
     struct ChainContextClosureLookupContext lookup_context = {
       {intersects_glyph, intersected_glyph},
@@ -2893,7 +3523,7 @@ struct ChainContextFormat1
   void closure_lookups (hb_closure_lookups_context_t *c) const
   {
     struct ChainContextClosureLookupContext lookup_context = {
-      {intersects_glyph, intersected_glyph},
+      {intersects_glyph, nullptr},
       ContextFormat::SimpleContext,
       {nullptr, nullptr, nullptr}
     };
@@ -2927,7 +3557,7 @@ struct ChainContextFormat1
   {
     const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_glyph},
+      {{match_glyph, match_glyph, match_glyph}},
       {nullptr, nullptr, nullptr}
     };
     return rule_set.would_apply (c, lookup_context);
@@ -2943,7 +3573,7 @@ struct ChainContextFormat1
 
     const ChainRuleSet &rule_set = this+ruleSet[index];
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_glyph},
+      {{match_glyph, match_glyph, match_glyph}},
       {nullptr, nullptr, nullptr}
     };
     return_trace (rule_set.apply (c, lookup_context));
@@ -2959,7 +3589,7 @@ struct ChainContextFormat1
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
     out->format = format;
 
-    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
+    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? &c->plan->gsub_lookups : &c->plan->gpos_lookups;
     hb_sorted_vector_t<hb_codepoint_t> new_coverage;
     + hb_zip (this+coverage, ruleSet)
     | hb_filter (glyphset, hb_first)
@@ -2981,18 +3611,21 @@ struct ChainContextFormat1
 
   protected:
   HBUINT16     format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
                                         * beginning of table */
-  Array16OfOffset16To<ChainRuleSet>
+  Array16Of<typename Types::template OffsetTo<ChainRuleSet>>
                ruleSet;                /* Array of ChainRuleSet tables
                                         * ordered by Coverage Index */
   public:
-  DEFINE_SIZE_ARRAY (6, ruleSet);
+  DEFINE_SIZE_ARRAY (2 + 2 * Types::size, ruleSet);
 };
 
-struct ChainContextFormat2
+template <typename Types>
+struct ChainContextFormat2_5
 {
+  using ChainRuleSet = OT::ChainRuleSet<SmallTypes>;
+
   bool intersects (const hb_set_t *glyphs) const
   {
     if (!(this+coverage).intersects (glyphs))
@@ -3002,16 +3635,18 @@ struct ChainContextFormat2
     const ClassDef &input_class_def = this+inputClassDef;
     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
 
+    hb_map_t caches[3] = {};
     struct ChainContextClosureLookupContext lookup_context = {
-      {intersects_class, intersected_class_glyphs},
+      {intersects_class, nullptr},
       ContextFormat::ClassBasedContext,
       {&backtrack_class_def,
        &input_class_def,
-       &lookahead_class_def}
+       &lookahead_class_def},
+      {&caches[0], &caches[1], &caches[2]}
     };
 
     hb_set_t retained_coverage_glyphs;
-    (this+coverage).intersected_coverage_glyphs (glyphs, &retained_coverage_glyphs);
+    (this+coverage).intersect_set (*glyphs, retained_coverage_glyphs);
 
     hb_set_t coverage_glyph_classes;
     input_class_def.intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
@@ -3036,28 +3671,32 @@ struct ChainContextFormat2
     if (!(this+coverage).intersects (c->glyphs))
       return;
 
-    hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs ();
-    get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (),
-                                                 cur_active_glyphs);
-
+    hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
+    if (unlikely (!cur_active_glyphs)) return;
+    get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
+                                  *cur_active_glyphs);
 
     const ClassDef &backtrack_class_def = this+backtrackClassDef;
     const ClassDef &input_class_def = this+inputClassDef;
     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
 
+    hb_map_t caches[3] = {};
+    intersected_class_cache_t intersected_cache;
     struct ChainContextClosureLookupContext lookup_context = {
       {intersects_class, intersected_class_glyphs},
       ContextFormat::ClassBasedContext,
       {&backtrack_class_def,
        &input_class_def,
-       &lookahead_class_def}
+       &lookahead_class_def},
+      {&caches[0], &caches[1], &caches[2]},
+      &intersected_cache
     };
 
     + hb_enumerate (ruleSet)
     | hb_filter ([&] (unsigned _)
     { return input_class_def.intersects_class (&c->parent_active_glyphs (), _); },
                 hb_first)
-    | hb_apply ([&] (const hb_pair_t<unsigned, const Offset16To<ChainRuleSet>&> _)
+    | hb_apply ([&] (const hb_pair_t<unsigned, const typename Types::template OffsetTo<ChainRuleSet>&> _)
                 {
                   const ChainRuleSet& chainrule_set = this+_.second;
                   chainrule_set.closure (c, _.first, lookup_context);
@@ -3076,12 +3715,14 @@ struct ChainContextFormat2
     const ClassDef &input_class_def = this+inputClassDef;
     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
 
+    hb_map_t caches[3] = {};
     struct ChainContextClosureLookupContext lookup_context = {
-      {intersects_class, intersected_class_glyphs},
+      {intersects_class, nullptr},
       ContextFormat::ClassBasedContext,
       {&backtrack_class_def,
        &input_class_def,
-       &lookahead_class_def}
+       &lookahead_class_def},
+      {&caches[0], &caches[1], &caches[2]}
     };
 
     + hb_iter (ruleSet)
@@ -3127,7 +3768,7 @@ struct ChainContextFormat2
     unsigned int index = input_class_def.get_class (c->glyphs[0]);
     const ChainRuleSet &rule_set = this+ruleSet[index];
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_class},
+      {{match_class, match_class, match_class}},
       {&backtrack_class_def,
        &input_class_def,
        &lookahead_class_def}
@@ -3137,7 +3778,35 @@ struct ChainContextFormat2
 
   const Coverage &get_coverage () const { return this+coverage; }
 
-  bool apply (hb_ot_apply_context_t *c) const
+  unsigned cache_cost () const
+  {
+    unsigned c = (this+lookaheadClassDef).cost () * ruleSet.len;
+    return c >= 4 ? c : 0;
+  }
+  bool cache_func (hb_ot_apply_context_t *c, bool enter) const
+  {
+    if (enter)
+    {
+      if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable))
+       return false;
+      auto &info = c->buffer->info;
+      unsigned count = c->buffer->len;
+      for (unsigned i = 0; i < count; i++)
+       info[i].syllable() = 255;
+      c->new_syllables = 255;
+      return true;
+    }
+    else
+    {
+      c->new_syllables = (unsigned) -1;
+      HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable);
+      return true;
+    }
+  }
+
+  bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
+  bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
+  bool _apply (hb_ot_apply_context_t *c, bool cached) const
   {
     TRACE_APPLY (this);
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
@@ -3147,14 +3816,23 @@ struct ChainContextFormat2
     const ClassDef &input_class_def = this+inputClassDef;
     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
 
-    index = input_class_def.get_class (c->buffer->cur().codepoint);
-    const ChainRuleSet &rule_set = this+ruleSet[index];
+    /* match_class_caches1 is slightly faster. Use it for lookahead,
+     * which is typically longer. */
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_class},
+      {{cached && &backtrack_class_def == &lookahead_class_def ? match_class_cached1 : match_class,
+        cached ? match_class_cached2 : match_class,
+        cached ? match_class_cached1 : match_class}},
       {&backtrack_class_def,
        &input_class_def,
        &lookahead_class_def}
     };
+
+    // Note: Corresponds to match_class_cached2
+    if (cached && ((c->buffer->cur().syllable() & 0xF0) >> 4) < 15)
+      index = (c->buffer->cur().syllable () & 0xF0) >> 4;
+    else
+      index = input_class_def.get_class (c->buffer->cur().codepoint);
+    const ChainRuleSet &rule_set = this+ruleSet[index];
     return_trace (rule_set.apply (c, lookup_context));
   }
 
@@ -3182,14 +3860,14 @@ struct ChainContextFormat2
 
     const hb_set_t* glyphset = c->plan->glyphset_gsub ();
     hb_set_t retained_coverage_glyphs;
-    (this+coverage).intersected_coverage_glyphs (glyphset, &retained_coverage_glyphs);
+    (this+coverage).intersect_set (*glyphset, retained_coverage_glyphs);
 
     hb_set_t coverage_glyph_classes;
     (this+inputClassDef).intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
 
     int non_zero_index = -1, index = 0;
     bool ret = true;
-    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
+    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? &c->plan->gsub_lookups : &c->plan->gpos_lookups;
     auto last_non_zero = c->serializer->snapshot ();
     for (const auto& _ : + hb_enumerate (ruleSet)
                         | hb_filter (input_klass_map, hb_first))
@@ -3237,40 +3915,42 @@ struct ChainContextFormat2
 
   protected:
   HBUINT16     format;                 /* Format identifier--format = 2 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
                                         * beginning of table */
-  Offset16To<ClassDef>
+  typename Types::template OffsetTo<ClassDef>
                backtrackClassDef;      /* Offset to glyph ClassDef table
                                         * containing backtrack sequence
                                         * data--from beginning of table */
-  Offset16To<ClassDef>
+  typename Types::template OffsetTo<ClassDef>
                inputClassDef;          /* Offset to glyph ClassDef
                                         * table containing input sequence
                                         * data--from beginning of table */
-  Offset16To<ClassDef>
+  typename Types::template OffsetTo<ClassDef>
                lookaheadClassDef;      /* Offset to glyph ClassDef table
                                         * containing lookahead sequence
                                         * data--from beginning of table */
-  Array16OfOffset16To<ChainRuleSet>
+  Array16Of<typename Types::template OffsetTo<ChainRuleSet>>
                ruleSet;                /* Array of ChainRuleSet tables
                                         * ordered by class */
   public:
-  DEFINE_SIZE_ARRAY (12, ruleSet);
+  DEFINE_SIZE_ARRAY (4 + 4 * Types::size, ruleSet);
 };
 
 struct ChainContextFormat3
 {
+  using RuleSet = OT::RuleSet<SmallTypes>;
+
   bool intersects (const hb_set_t *glyphs) const
   {
-    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
 
     if (!(this+input[0]).intersects (glyphs))
       return false;
 
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
     struct ChainContextClosureLookupContext lookup_context = {
-      {intersects_coverage, intersected_coverage_glyphs},
+      {intersects_coverage, nullptr},
       ContextFormat::CoverageBasedContext,
       {this, this, this}
     };
@@ -3286,18 +3966,19 @@ struct ChainContextFormat3
 
   void closure (hb_closure_context_t *c) const
   {
-    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
 
     if (!(this+input[0]).intersects (c->glyphs))
       return;
 
-    hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs ();
-    get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (),
-                                                 cur_active_glyphs);
-
+    hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
+    if (unlikely (!cur_active_glyphs))
+      return;
+    get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
+                                  *cur_active_glyphs);
 
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     struct ChainContextClosureLookupContext lookup_context = {
       {intersects_coverage, intersected_coverage_glyphs},
       ContextFormat::CoverageBasedContext,
@@ -3318,9 +3999,9 @@ struct ChainContextFormat3
     if (!intersects (c->glyphs))
       return;
 
-    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     recurse_lookups (c, lookup.len, lookup.arrayZ);
   }
 
@@ -3328,12 +4009,13 @@ struct ChainContextFormat3
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
 
     (this+input[0]).collect_coverage (c->input);
 
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
+
     struct ChainContextCollectGlyphsLookupContext lookup_context = {
       {collect_coverage},
       {this, this, this}
@@ -3348,11 +4030,11 @@ struct ChainContextFormat3
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_coverage},
+      {{match_coverage, match_coverage, match_coverage}},
       {this, this, this}
     };
     return chain_context_would_apply_lookup (c,
@@ -3364,22 +4046,22 @@ struct ChainContextFormat3
 
   const Coverage &get_coverage () const
   {
-    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
     return this+input[0];
   }
 
   bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
 
     unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_coverage},
+      {{match_coverage, match_coverage, match_coverage}},
       {this, this, this}
     };
     return_trace (chain_context_apply_lookup (c,
@@ -3412,42 +4094,40 @@ struct ChainContextFormat3
   {
     TRACE_SUBSET (this);
 
-    auto *out = c->serializer->start_embed (this);
-    if (unlikely (!out)) return_trace (false);
     if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
 
     if (!serialize_coverage_offsets (c, backtrack.iter (), this))
       return_trace (false);
 
-    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
     if (!serialize_coverage_offsets (c, input.iter (), this))
       return_trace (false);
 
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
     if (!serialize_coverage_offsets (c, lookahead.iter (), this))
       return_trace (false);
 
-    const Array16Of<LookupRecord> &lookupRecord = StructAfter<Array16Of<LookupRecord>> (lookahead);
-    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
+    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? &c->plan->gsub_lookups : &c->plan->gpos_lookups;
 
-    HBUINT16 *lookupCount = c->serializer->copy<HBUINT16> (lookupRecord.len);
+    HBUINT16 *lookupCount = c->serializer->copy<HBUINT16> (lookup.len);
     if (!lookupCount) return_trace (false);
 
-    unsigned count = serialize_lookuprecord_array (c->serializer, lookupRecord.as_array (), lookup_map);
+    unsigned count = serialize_lookuprecord_array (c->serializer, lookup.as_array (), lookup_map);
     return_trace (c->serializer->check_assign (*lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (!backtrack.sanitize (c, this)) return_trace (false);
-    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-    if (!input.sanitize (c, this)) return_trace (false);
-    if (!input.len) return_trace (false); /* To be consistent with Context. */
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
-    if (!lookahead.sanitize (c, this)) return_trace (false);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
-    return_trace (lookup.sanitize (c));
+    if (unlikely (!backtrack.sanitize (c, this))) return_trace (false);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    if (unlikely (!input.sanitize (c, this))) return_trace (false);
+    if (unlikely (!input.len)) return_trace (false); /* To be consistent with Context. */
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    if (unlikely (!lookahead.sanitize (c, this))) return_trace (false);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
+    return_trace (likely (lookup.sanitize (c)));
   }
 
   protected:
@@ -3476,22 +4156,30 @@ struct ChainContext
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
     case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+#ifndef HB_NO_BEYOND_64K
+    case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+    case 5: return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  HBUINT16             format; /* Format identifier */
-  ChainContextFormat1  format1;
-  ChainContextFormat2  format2;
-  ChainContextFormat3  format3;
+  HBUINT16                             format; /* Format identifier */
+  ChainContextFormat1_4<SmallTypes>    format1;
+  ChainContextFormat2_5<SmallTypes>    format2;
+  ChainContextFormat3                  format3;
+#ifndef HB_NO_BEYOND_64K
+  ChainContextFormat1_4<MediumTypes>   format4;
+  ChainContextFormat2_5<MediumTypes>   format5;
+#endif
   } u;
 };
 
@@ -3508,8 +4196,8 @@ struct ExtensionFormat1
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
+    if (unlikely (!c->may_dispatch (this, this))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, format);
-    if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
     return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type (), std::forward<Ts> (ds)...));
   }
 
@@ -3529,7 +4217,7 @@ struct ExtensionFormat1
     TRACE_SUBSET (this);
 
     auto *out = c->serializer->start_embed (this);
-    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
 
     out->format = format;
     out->extensionLookupType = extensionLookupType;
@@ -3587,8 +4275,8 @@ struct Extension
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
     case 1: return_trace (u.format1.dispatch (c, std::forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
@@ -3610,66 +4298,319 @@ struct Extension
 struct hb_ot_layout_lookup_accelerator_t
 {
   template <typename TLookup>
-  void init (const TLookup &lookup)
-  {
-    digest.init ();
-    lookup.collect_coverage (&digest);
+  static hb_ot_layout_lookup_accelerator_t *create (const TLookup &lookup)
+  {
+    unsigned count = lookup.get_subtable_count ();
+
+    unsigned size = sizeof (hb_ot_layout_lookup_accelerator_t) -
+                   HB_VAR_ARRAY * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t) +
+                   count * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t);
+
+    /* The following is a calloc because when we are collecting subtables,
+     * some of them might be invalid and hence not collect; as a result,
+     * we might not fill in all the count entries of the subtables array.
+     * Zeroing it allows the set digest to gatekeep it without having to
+     * initialize it further. */
+    auto *thiz = (hb_ot_layout_lookup_accelerator_t *) hb_calloc (1, size);
+    if (unlikely (!thiz))
+      return nullptr;
+
+    hb_accelerate_subtables_context_t c_accelerate_subtables (thiz->subtables);
+    lookup.dispatch (&c_accelerate_subtables);
+
+    thiz->digest.init ();
+    for (auto& subtable : hb_iter (thiz->subtables, count))
+      thiz->digest.add (subtable.digest);
+
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+    thiz->cache_user_idx = c_accelerate_subtables.cache_user_idx;
+    for (unsigned i = 0; i < count; i++)
+      if (i != thiz->cache_user_idx)
+       thiz->subtables[i].apply_cached_func = thiz->subtables[i].apply_func;
+#endif
 
-    subtables.init ();
-    OT::hb_get_subtables_context_t c_get_subtables (subtables);
-    lookup.dispatch (&c_get_subtables);
+    return thiz;
   }
-  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
+#ifndef HB_OPTIMIZE_SIZE
+  HB_ALWAYS_INLINE
+#endif
+  bool apply (hb_ot_apply_context_t *c, unsigned subtables_count, bool use_cache) const
   {
-    for (unsigned int i = 0; i < subtables.length; i++)
-      if (subtables[i].apply (c))
-       return true;
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+    if (use_cache)
+    {
+      return
+      + hb_iter (hb_iter (subtables, subtables_count))
+      | hb_map ([&c] (const hb_accelerate_subtables_context_t::hb_applicable_t &_) { return _.apply_cached (c); })
+      | hb_any
+      ;
+    }
+    else
+#endif
+    {
+      return
+      + hb_iter (hb_iter (subtables, subtables_count))
+      | hb_map ([&c] (const hb_accelerate_subtables_context_t::hb_applicable_t &_) { return _.apply (c); })
+      | hb_any
+      ;
+    }
     return false;
   }
 
-  private:
+  bool cache_enter (hb_ot_apply_context_t *c) const
+  {
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+    return cache_user_idx != (unsigned) -1 &&
+          subtables[cache_user_idx].cache_enter (c);
+#else
+    return false;
+#endif
+  }
+  void cache_leave (hb_ot_apply_context_t *c) const
+  {
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+    subtables[cache_user_idx].cache_leave (c);
+#endif
+  }
+
+
   hb_set_digest_t digest;
-  hb_get_subtables_context_t::array_t subtables;
+  private:
+#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
+  unsigned cache_user_idx = (unsigned) -1;
+#endif
+  hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY];
+};
+
+template <typename Types>
+struct GSUBGPOSVersion1_2
+{
+  friend struct GSUBGPOS;
+
+  protected:
+  FixedVersion<>version;       /* Version of the GSUB/GPOS table--initially set
+                                * to 0x00010000u */
+  typename Types:: template OffsetTo<ScriptList>
+               scriptList;     /* ScriptList table */
+  typename Types::template OffsetTo<FeatureList>
+               featureList;    /* FeatureList table */
+  typename Types::template OffsetTo<LookupList<Types>>
+               lookupList;     /* LookupList table */
+  Offset32To<FeatureVariations>
+               featureVars;    /* Offset to Feature Variations
+                                  table--from beginning of table
+                                * (may be NULL).  Introduced
+                                * in version 0x00010001. */
+  public:
+  DEFINE_SIZE_MIN (4 + 3 * Types::size);
+
+  unsigned int get_size () const
+  {
+    return min_size +
+          (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
+  }
+
+  const typename Types::template OffsetTo<LookupList<Types>>* get_lookup_list_offset () const
+  {
+    return &lookupList;
+  }
+
+  template <typename TLookup>
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    typedef List16OfOffsetTo<TLookup, typename Types::HBUINT> TLookupList;
+    if (unlikely (!(scriptList.sanitize (c, this) &&
+                   featureList.sanitize (c, this) &&
+                   reinterpret_cast<const typename Types::template OffsetTo<TLookupList> &> (lookupList).sanitize (c, this))))
+      return_trace (false);
+
+#ifndef HB_NO_VAR
+    if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this))))
+      return_trace (false);
+#endif
+
+    return_trace (true);
+  }
+
+  template <typename TLookup>
+  bool subset (hb_subset_layout_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+
+    auto *out = c->subset_context->serializer->start_embed (this);
+    if (unlikely (!c->subset_context->serializer->extend_min (out))) return_trace (false);
+
+    out->version = version;
+
+    typedef LookupOffsetList<TLookup, typename Types::HBUINT> TLookupList;
+    reinterpret_cast<typename Types::template OffsetTo<TLookupList> &> (out->lookupList)
+       .serialize_subset (c->subset_context,
+                          reinterpret_cast<const typename Types::template OffsetTo<TLookupList> &> (lookupList),
+                          this,
+                          c);
+
+    reinterpret_cast<typename Types::template OffsetTo<RecordListOfFeature> &> (out->featureList)
+       .serialize_subset (c->subset_context,
+                          reinterpret_cast<const typename Types::template OffsetTo<RecordListOfFeature> &> (featureList),
+                          this,
+                          c);
+
+    out->scriptList.serialize_subset (c->subset_context,
+                                     scriptList,
+                                     this,
+                                     c);
+
+#ifndef HB_NO_VAR
+    if (version.to_int () >= 0x00010001u)
+    {
+      auto snapshot = c->subset_context->serializer->snapshot ();
+      if (!c->subset_context->serializer->extend_min (&out->featureVars))
+        return_trace (false);
+
+      // TODO(qxliu76): the current implementation doesn't correctly handle feature variations
+      //                that are dropped by instancing when the associated conditions don't trigger.
+      //                Since partial instancing isn't yet supported this isn't an issue yet but will
+      //                need to be fixed for partial instancing.
+
+
+
+      // if all axes are pinned all feature vars are dropped.
+      bool ret = !c->subset_context->plan->all_axes_pinned
+                 && out->featureVars.serialize_subset (c->subset_context, featureVars, this, c);
+      if (!ret && version.major == 1)
+      {
+        c->subset_context->serializer->revert (snapshot);
+       out->version.major = 1;
+       out->version.minor = 0;
+      }
+    }
+#endif
+
+    return_trace (true);
+  }
 };
 
 struct GSUBGPOS
 {
-  bool has_data () const { return version.to_int (); }
+  unsigned int get_size () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.get_size ();
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.get_size ();
+#endif
+    default: return u.version.static_size;
+    }
+  }
+
+  template <typename TLookup>
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!u.version.sanitize (c))) return_trace (false);
+    switch (u.version.major) {
+    case 1: return_trace (u.version1.sanitize<TLookup> (c));
+#ifndef HB_NO_BEYOND_64K
+    case 2: return_trace (u.version2.sanitize<TLookup> (c));
+#endif
+    default: return_trace (true);
+    }
+  }
+
+  template <typename TLookup>
+  bool subset (hb_subset_layout_context_t *c) const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.subset<TLookup> (c);
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.subset<TLookup> (c);
+#endif
+    default: return false;
+    }
+  }
+
+  const ScriptList &get_script_list () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.scriptList;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.scriptList;
+#endif
+    default: return Null (ScriptList);
+    }
+  }
+  const FeatureList &get_feature_list () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.featureList;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.featureList;
+#endif
+    default: return Null (FeatureList);
+    }
+  }
+  unsigned int get_lookup_count () const
+  {
+    switch (u.version.major) {
+    case 1: return (this+u.version1.lookupList).len;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return (this+u.version2.lookupList).len;
+#endif
+    default: return 0;
+    }
+  }
+  const Lookup& get_lookup (unsigned int i) const
+  {
+    switch (u.version.major) {
+    case 1: return (this+u.version1.lookupList)[i];
+#ifndef HB_NO_BEYOND_64K
+    case 2: return (this+u.version2.lookupList)[i];
+#endif
+    default: return Null (Lookup);
+    }
+  }
+  const FeatureVariations &get_feature_variations () const
+  {
+    switch (u.version.major) {
+    case 1: return (u.version.to_int () >= 0x00010001u ? this+u.version1.featureVars : Null (FeatureVariations));
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.featureVars;
+#endif
+    default: return Null (FeatureVariations);
+    }
+  }
+
+  bool has_data () const { return u.version.to_int (); }
   unsigned int get_script_count () const
-  { return (this+scriptList).len; }
+  { return get_script_list ().len; }
   const Tag& get_script_tag (unsigned int i) const
-  { return (this+scriptList).get_tag (i); }
+  { return get_script_list ().get_tag (i); }
   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); }
+  { return get_script_list ().get_tags (start_offset, script_count, script_tags); }
   const Script& get_script (unsigned int i) const
-  { return (this+scriptList)[i]; }
+  { return get_script_list ()[i]; }
   bool find_script_index (hb_tag_t tag, unsigned int *index) const
-  { return (this+scriptList).find_index (tag, index); }
+  { return get_script_list ().find_index (tag, index); }
 
   unsigned int get_feature_count () const
-  { return (this+featureList).len; }
+  { return get_feature_list ().len; }
   hb_tag_t get_feature_tag (unsigned int i) const
-  { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
+  { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : get_feature_list ().get_tag (i); }
   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); }
+  { return get_feature_list ().get_tags (start_offset, feature_count, feature_tags); }
   const Feature& get_feature (unsigned int i) const
-  { return (this+featureList)[i]; }
+  { return get_feature_list ()[i]; }
   bool find_feature_index (hb_tag_t tag, unsigned int *index) const
-  { return (this+featureList).find_index (tag, index); }
-
-  unsigned int get_lookup_count () const
-  { return (this+lookupList).len; }
-  const Lookup& get_lookup (unsigned int i) const
-  { return (this+lookupList)[i]; }
+  { return get_feature_list ().find_index (tag, index); }
 
   bool find_variations_index (const int *coords, unsigned int num_coords,
                              unsigned int *index) const
@@ -3678,18 +4619,17 @@ struct GSUBGPOS
     *index = FeatureVariations::NOT_FOUND_INDEX;
     return false;
 #endif
-    return (version.to_int () >= 0x00010001u ? this+featureVars : Null (FeatureVariations))
-           .find_index (coords, num_coords, index);
+    return get_feature_variations ().find_index (coords, num_coords, index);
   }
   const Feature& get_feature_variation (unsigned int feature_index,
                                        unsigned int variations_index) const
   {
 #ifndef HB_NO_VAR
     if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
-       version.to_int () >= 0x00010001u)
+       u.version.to_int () >= 0x00010001u)
     {
-      const Feature *feature = (this+featureVars).find_substitute (variations_index,
-                                                                  feature_index);
+      const Feature *feature = get_feature_variations ().find_substitute (variations_index,
+                                                                         feature_index);
       if (feature)
        return *feature;
     }
@@ -3698,23 +4638,30 @@ struct GSUBGPOS
   }
 
   void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
+                                         const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
                                          hb_set_t       *lookup_indexes /* OUT */) const
   {
 #ifndef HB_NO_VAR
-    if (version.to_int () >= 0x00010001u)
-      (this+featureVars).collect_lookups (feature_indexes, lookup_indexes);
+    get_feature_variations ().collect_lookups (feature_indexes, feature_substitutes_map, lookup_indexes);
 #endif
   }
 
+#ifndef HB_NO_VAR
+  void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
+  { get_feature_variations ().collect_feature_substitutes_with_variations (c); }
+#endif
+
   template <typename TLookup>
   void closure_lookups (hb_face_t      *face,
                        const hb_set_t *glyphs,
                        hb_set_t       *lookup_indexes /* IN/OUT */) const
   {
     hb_set_t visited_lookups, inactive_lookups;
-    OT::hb_closure_lookups_context_t c (face, glyphs, &visited_lookups, &inactive_lookups);
+    hb_closure_lookups_context_t c (face, glyphs, &visited_lookups, &inactive_lookups);
 
-    for (unsigned lookup_index : + hb_iter (lookup_indexes))
+    c.set_recurse_func (TLookup::template dispatch_recurse_func<hb_closure_lookups_context_t>);
+
+    for (unsigned lookup_index : *lookup_indexes)
       reinterpret_cast<const TLookup &> (get_lookup (lookup_index)).closure_lookups (&c, lookup_index);
 
     hb_set_union (lookup_indexes, &visited_lookups);
@@ -3722,7 +4669,8 @@ struct GSUBGPOS
   }
 
   void prune_langsys (const hb_map_t *duplicate_feature_map,
-                      hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map,
+                      const hb_set_t *layout_scripts,
+                      hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map,
                       hb_set_t       *new_feature_indexes /* OUT */) const
   {
     hb_prune_langsys_context_t c (this, script_langsys_map, duplicate_feature_map, new_feature_indexes);
@@ -3730,124 +4678,16 @@ struct GSUBGPOS
     unsigned count = get_script_count ();
     for (unsigned script_index = 0; script_index < count; script_index++)
     {
+      const Tag& tag = get_script_tag (script_index);
+      if (!layout_scripts->has (tag)) continue;
       const Script& s = get_script (script_index);
       s.prune_langsys (&c, script_index);
     }
   }
 
-  template <typename TLookup>
-  bool subset (hb_subset_layout_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->subset_context->serializer->embed (*this);
-    if (unlikely (!out)) return_trace (false);
-
-    typedef LookupOffsetList<TLookup> TLookupList;
-    reinterpret_cast<Offset16To<TLookupList> &> (out->lookupList)
-       .serialize_subset (c->subset_context,
-                          reinterpret_cast<const Offset16To<TLookupList> &> (lookupList),
-                          this,
-                          c);
-
-    reinterpret_cast<Offset16To<RecordListOfFeature> &> (out->featureList)
-       .serialize_subset (c->subset_context,
-                          reinterpret_cast<const Offset16To<RecordListOfFeature> &> (featureList),
-                          this,
-                          c);
-
-    out->scriptList.serialize_subset (c->subset_context,
-                                     scriptList,
-                                     this,
-                                     c);
-
-#ifndef HB_NO_VAR
-    if (version.to_int () >= 0x00010001u)
-    {
-      bool ret = out->featureVars.serialize_subset (c->subset_context, featureVars, this, c);
-      if (!ret)
-      {
-       out->version.major = 1;
-       out->version.minor = 0;
-      }
-    }
-#endif
-
-    return_trace (true);
-  }
-
-  void find_duplicate_features (const hb_map_t *lookup_indices,
-                                const hb_set_t *feature_indices,
-                                hb_map_t *duplicate_feature_map /* OUT */) const
-  {
-    if (feature_indices->is_empty ()) return;
-    hb_hashmap_t<hb_tag_t, hb_set_t *> unique_features;
-    //find out duplicate features after subset
-    for (unsigned i : feature_indices->iter ())
-    {
-      hb_tag_t t = get_feature_tag (i);
-      if (t == HB_MAP_VALUE_INVALID) continue;
-      if (!unique_features.has (t))
-      {
-        hb_set_t* indices = hb_set_create ();
-        if (unlikely (indices == hb_set_get_empty () ||
-                      !unique_features.set (t, indices)))
-        {
-          hb_set_destroy (indices);
-          for (auto _ : unique_features.iter ())
-            hb_set_destroy (_.second);
-          return;
-        }
-        if (unique_features.get (t))
-          unique_features.get (t)->add (i);
-        duplicate_feature_map->set (i, i);
-        continue;
-      }
-
-      bool found = false;
-
-      hb_set_t* same_tag_features = unique_features.get (t);
-      for (unsigned other_f_index : same_tag_features->iter ())
-      {
-        const Feature& f = get_feature (i);
-        const Feature& other_f = get_feature (other_f_index);
-
-        auto f_iter =
-        + hb_iter (f.lookupIndex)
-        | hb_filter (lookup_indices)
-        ;
-
-        auto other_f_iter =
-        + hb_iter (other_f.lookupIndex)
-        | hb_filter (lookup_indices)
-        ;
-
-        bool is_equal = true;
-        for (; f_iter && other_f_iter; f_iter++, other_f_iter++)
-        {
-          unsigned a = *f_iter;
-          unsigned b = *other_f_iter;
-          if (a != b) { is_equal = false; break; }
-        }
-
-        if (is_equal == false || f_iter || other_f_iter) continue;
-
-        found = true;
-        duplicate_feature_map->set (i, other_f_index);
-        break;
-      }
-
-      if (found == false)
-      {
-        same_tag_features->add (i);
-        duplicate_feature_map->set (i, i);
-      }
-    }
-
-    for (auto _ : unique_features.iter ())
-      hb_set_destroy (_.second);
-  }
-
   void prune_features (const hb_map_t *lookup_indices, /* IN */
+                      const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* IN */
+                      const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map, /* IN */
                       hb_set_t       *feature_indices /* IN/OUT */) const
   {
 #ifndef HB_NO_VAR
@@ -3855,8 +4695,7 @@ struct GSUBGPOS
     // if the FeatureVariation's table and the alternate version(s) intersect the
     // set of lookup indices.
     hb_set_t alternate_feature_indices;
-    if (version.to_int () >= 0x00010001u)
-      (this+featureVars).closure_features (lookup_indices, &alternate_feature_indices);
+    get_feature_variations ().closure_features (lookup_indices, feature_record_cond_idx_map, &alternate_feature_indices);
     if (unlikely (alternate_feature_indices.in_error()))
     {
       feature_indices->err ();
@@ -3864,9 +4703,8 @@ struct GSUBGPOS
     }
 #endif
 
-    for (unsigned i : feature_indices->iter())
+    for (unsigned i : hb_iter (feature_indices))
     {
-      const Feature& f = get_feature (i);
       hb_tag_t tag =  get_feature_tag (i);
       if (tag == HB_TAG ('p', 'r', 'e', 'f'))
         // Note: Never ever drop feature 'pref', even if it's empty.
@@ -3876,11 +4714,16 @@ struct GSUBGPOS
         continue;
 
 
-      if (!f.featureParams.is_null () &&
+      const Feature *f = &(get_feature (i));
+      const Feature** p = nullptr;
+      if (feature_substitutes_map->has (i, &p))
+        f = *p;
+
+      if (!f->featureParams.is_null () &&
           tag == HB_TAG ('s', 'i', 'z', 'e'))
         continue;
 
-      if (!f.intersects_lookup_indexes (lookup_indices)
+      if (!f->intersects_lookup_indexes (lookup_indices)
 #ifndef HB_NO_VAR
           && !alternate_feature_indices.has (i)
 #endif
@@ -3889,30 +4732,16 @@ struct GSUBGPOS
     }
   }
 
-  unsigned int get_size () const
+  void collect_name_ids (const hb_map_t *feature_index_map,
+                         hb_set_t *nameids_to_retain /* OUT */) 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 List16OfOffset16To<TLookup> TLookupList;
-    if (unlikely (!(version.sanitize (c) &&
-                   likely (version.major == 1) &&
-                   scriptList.sanitize (c, this) &&
-                   featureList.sanitize (c, this) &&
-                   reinterpret_cast<const Offset16To<TLookupList> &> (lookupList).sanitize (c, this))))
-      return_trace (false);
-
-#ifndef HB_NO_VAR
-    if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this))))
-      return_trace (false);
-#endif
-
-    return_trace (true);
+    unsigned count = get_feature_count ();
+    for (unsigned i = 0 ; i < count; i++)
+    {
+      if (!feature_index_map->has (i)) continue;
+      hb_tag_t tag = get_feature_tag (i);
+      get_feature (i).collect_name_ids (tag, nameids_to_retain);
+    }
   }
 
   template <typename T>
@@ -3920,7 +4749,10 @@ struct GSUBGPOS
   {
     accelerator_t (hb_face_t *face)
     {
-      this->table = hb_sanitize_context_t ().reference_table<T> (face);
+      hb_sanitize_context_t sc;
+      sc.lazy_some_gpos = true;
+      this->table = sc.reference_table<T> (face);
+
       if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
       {
        hb_blob_destroy (this->table.get_blob ());
@@ -3929,46 +4761,61 @@ struct GSUBGPOS
 
       this->lookup_count = table->get_lookup_count ();
 
-      this->accels = (hb_ot_layout_lookup_accelerator_t *) hb_calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
+      this->accels = (hb_atomic_ptr_t<hb_ot_layout_lookup_accelerator_t> *) hb_calloc (this->lookup_count, sizeof (*accels));
       if (unlikely (!this->accels))
       {
        this->lookup_count = 0;
        this->table.destroy ();
        this->table = hb_blob_get_empty ();
       }
-
-      for (unsigned int i = 0; i < this->lookup_count; i++)
-       this->accels[i].init (table->get_lookup (i));
     }
     ~accelerator_t ()
     {
       for (unsigned int i = 0; i < this->lookup_count; i++)
-       this->accels[i].fini ();
+       hb_free (this->accels[i]);
       hb_free (this->accels);
       this->table.destroy ();
     }
 
+    hb_blob_t *get_blob () const { return table.get_blob (); }
+
+    hb_ot_layout_lookup_accelerator_t *get_accel (unsigned lookup_index) const
+    {
+      if (unlikely (lookup_index >= lookup_count)) return nullptr;
+
+    retry:
+      auto *accel = accels[lookup_index].get_acquire ();
+      if (unlikely (!accel))
+      {
+       accel = hb_ot_layout_lookup_accelerator_t::create (table->get_lookup (lookup_index));
+       if (unlikely (!accel))
+         return nullptr;
+
+       if (unlikely (!accels[lookup_index].cmpexch (nullptr, accel)))
+       {
+         hb_free (accel);
+         goto retry;
+       }
+      }
+
+      return accel;
+    }
+
     hb_blob_ptr_t<T> table;
     unsigned int lookup_count;
-    hb_ot_layout_lookup_accelerator_t *accels;
+    hb_atomic_ptr_t<hb_ot_layout_lookup_accelerator_t> *accels;
   };
 
   protected:
-  FixedVersion<>version;       /* Version of the GSUB/GPOS table--initially set
-                                * to 0x00010000u */
-  Offset16To<ScriptList>
-               scriptList;     /* ScriptList table */
-  Offset16To<FeatureList>
-               featureList;    /* FeatureList table */
-  Offset16To<LookupList>
-               lookupList;     /* LookupList table */
-  Offset32To<FeatureVariations>
-               featureVars;    /* Offset to Feature Variations
-                                  table--from beginning of table
-                                * (may be NULL).  Introduced
-                                * in version 0x00010001. */
+  union {
+  FixedVersion<>                       version;        /* Version identifier */
+  GSUBGPOSVersion1_2<SmallTypes>       version1;
+#ifndef HB_NO_BEYOND_64K
+  GSUBGPOSVersion1_2<MediumTypes>      version2;
+#endif
+  } u;
   public:
-  DEFINE_SIZE_MIN (10);
+  DEFINE_SIZE_MIN (4);
 };
 
 
index a599eea..2eb8535 100644 (file)
@@ -46,7 +46,7 @@
 #include "hb-ot-layout-gdef-table.hh"
 #include "hb-ot-layout-gsub-table.hh"
 #include "hb-ot-layout-gpos-table.hh"
-#include "hb-ot-layout-base-table.hh" // Just so we compile it; unused otherwise.
+#include "hb-ot-layout-base-table.hh"
 #include "hb-ot-layout-jstf-table.hh" // Just so we compile it; unused otherwise.
 #include "hb-ot-name-table.hh"
 #include "hb-ot-os2-table.hh"
@@ -54,6 +54,9 @@
 #include "hb-aat-layout-morx-table.hh"
 #include "hb-aat-layout-opbd-table.hh" // Just so we compile it; unused otherwise.
 
+using OT::Layout::GSUB;
+using OT::Layout::GPOS;
+
 /**
  * SECTION:hb-ot-layout
  * @title: hb-ot-layout
@@ -61,6 +64,8 @@
  * @include: hb-ot.h
  *
  * Functions for querying OpenType Layout features in the font face.
+ * See the [OpenType specification](http://www.microsoft.com/typography/otspec/)
+ * for details.
  **/
 
 
@@ -76,7 +81,7 @@
  * Tests whether a face includes any kerning data in the 'kern' table.
  * Does NOT test for kerning lookups in the GPOS table.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 bool
@@ -92,7 +97,7 @@ hb_ot_layout_has_kerning (hb_face_t *face)
  * Tests whether a face includes any state-machine kerning in the 'kern' table.
  * Does NOT examine the GPOS table.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 bool
@@ -112,7 +117,7 @@ hb_ot_layout_has_machine_kerning (hb_face_t *face)
  *
  * Does NOT examine the GPOS table.
  *
- * Return value: %true is data found, %false otherwise
+ * Return value: `true` is data found, `false` otherwise
  *
  **/
 bool
@@ -252,13 +257,13 @@ _hb_ot_layout_set_glyph_props (hb_font_t *font,
 {
   _hb_buffer_assert_gsubgpos_vars (buffer);
 
-  const OT::GDEF &gdef = *font->face->table.GDEF->table;
+  const auto &gdef = *font->face->table.GDEF;
   unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
   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;
+    _hb_glyph_info_set_glyph_props (&info[i], gdef.get_glyph_props (info[i].codepoint));
+    _hb_glyph_info_clear_lig_props (&info[i]);
   }
 }
 
@@ -270,7 +275,7 @@ _hb_ot_layout_set_glyph_props (hb_font_t *font,
  *
  * Tests whether a face has any glyph classes defined in its GDEF table.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 hb_bool_t
@@ -361,6 +366,13 @@ hb_ot_layout_get_attach_points (hb_face_t      *face,
  * Fetches a list of the caret positions defined for a ligature glyph in the GDEF
  * table of the font. The list returned will begin at the offset provided.
  *
+ * Note that a ligature that is formed from n characters will have n-1
+ * caret positions. The first character is not represented in the array,
+ * since its caret position is the glyph position.
+ *
+ * The positions returned by this function are 'unshaped', and will have to
+ * be fixed up for kerning that may be applied to the ligature glyph.
+ *
  * Return value: Total number of ligature caret positions for @glyph.
  *
  **/
@@ -382,7 +394,7 @@ hb_ot_layout_get_ligature_carets (hb_font_t      *font,
  */
 
 bool
-OT::GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED,
+GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED,
                          hb_face_t *face) const
 {
 #ifdef HB_NO_OT_LAYOUT_BLOCKLIST
@@ -392,7 +404,7 @@ OT::GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED,
 }
 
 bool
-OT::GPOS::is_blocklisted (hb_blob_t *blob HB_UNUSED,
+GPOS::is_blocklisted (hb_blob_t *blob HB_UNUSED,
                          hb_face_t *face HB_UNUSED) const
 {
 #ifdef HB_NO_OT_LAYOUT_BLOCKLIST
@@ -452,7 +464,7 @@ hb_ot_layout_table_get_script_tags (hb_face_t    *face,
  * Fetches the index if a given script tag in the specified face's GSUB table
  * or GPOS table.
  *
- * Return value: %true if the script is found, %false otherwise
+ * Return value: `true` if the script is found, `false` otherwise
  *
  **/
 hb_bool_t
@@ -491,8 +503,8 @@ hb_ot_layout_table_find_script (hb_face_t    *face,
  * @face: #hb_face_t to work upon
  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
  * @script_tags: Array of #hb_tag_t script tags
- * @script_index: (out): The index of the requested script tag
- * @chosen_script: (out): #hb_tag_t of the script tag requested
+ * @script_index: (out): The index of the chosen script
+ * @chosen_script: (out): #hb_tag_t of the chosen script
  *
  * Deprecated since 2.0.0
  **/
@@ -522,11 +534,11 @@ hb_ot_layout_table_choose_script (hb_face_t      *face,
  *
  * If the table does not have any of the requested scripts, then `DFLT`,
  * `dflt`, and `latn` tags are tried in that order. If the table still does not
- * have any of these scripts, @script_index and @chosen_script are set to
- * #HB_OT_LAYOUT_NO_SCRIPT_INDEX.
+ * have any of these scripts, @script_index is set to
+ * #HB_OT_LAYOUT_NO_SCRIPT_INDEX and @chosen_script is set to #HB_TAG_NONE.
  *
  * Return value:
- * %true if one of the requested scripts is selected, %false if a fallback
+ * `true` if one of the requested scripts is selected, `false` if a fallback
  * script is selected or if no scripts are selected.
  *
  * Since: 2.0.0
@@ -577,7 +589,7 @@ hb_ot_layout_table_select_script (hb_face_t      *face,
 
   if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
   if (chosen_script)
-    *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
+    *chosen_script = HB_TAG_NONE;
   return false;
 }
 
@@ -592,9 +604,13 @@ hb_ot_layout_table_select_script (hb_face_t      *face,
  * @feature_tags: (out) (array length=feature_count): Array of feature tags found in the table
  *
  * Fetches a list of all feature tags in the given face's GSUB or GPOS table.
+ * Note that there might be duplicate feature tags, belonging to different
+ * script/language-system pairs of the table.
  *
  * Return value: Total number of feature tags.
  *
+ * Since: 0.6.0
+ *
  **/
 unsigned int
 hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
@@ -619,7 +635,10 @@ hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
  * Fetches the index for a given feature tag in the specified face's GSUB table
  * or GPOS table.
  *
- * Return value: %true if the feature is found, %false otherwise
+ * Return value: `true` if the feature is found, `false` otherwise
+ *
+ * Since: 0.6.0
+ *
  **/
 bool
 hb_ot_layout_table_find_feature (hb_face_t    *face,
@@ -659,6 +678,8 @@ hb_ot_layout_table_find_feature (hb_face_t    *face,
  *
  * Return value: Total number of language tags.
  *
+ * Since: 0.6.0
+ *
  **/
 unsigned int
 hb_ot_layout_script_get_language_tags (hb_face_t    *face,
@@ -686,7 +707,7 @@ hb_ot_layout_script_get_language_tags (hb_face_t    *face,
  * Fetches the index of a given language tag in the specified face's GSUB table
  * or GPOS table, underneath the specified script tag.
  *
- * Return value: %true if the language tag is found, %false otherwise
+ * Return value: `true` if the language tag is found, `false` otherwise
  *
  * Since: 0.6.0
  * Deprecated: 2.0.0
@@ -709,32 +730,35 @@ hb_ot_layout_script_find_language (hb_face_t    *face,
 
 
 /**
- * hb_ot_layout_script_select_language:
+ * hb_ot_layout_script_select_language2:
  * @face: #hb_face_t to work upon
  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
  * @script_index: The index of the requested script tag
  * @language_count: The number of languages in the specified script
  * @language_tags: The array of language tags
- * @language_index: (out): The index of the requested language
+ * @language_index: (out): The index of the chosen language
+ * @chosen_language: (out): #hb_tag_t of the chosen language
  *
  * Fetches the index of the first language tag fom @language_tags that is present
  * in the specified face's GSUB or GPOS table, underneath the specified script
  * index.
  *
- * If none of the given language tags is found, %false is returned and
- * @language_index is set to the default language index.
+ * If none of the given language tags is found, `false` is returned and
+ * @language_index is set to #HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX and
+ * @chosen_language is set to #HB_TAG_NONE.
  *
- * Return value: %true if one of the given language tags is found, %false otherwise
+ * Return value: `true` if one of the given language tags is found, `false` otherwise
  *
- * Since: 2.0.0
+ * Since: 7.0.0
  **/
 hb_bool_t
-hb_ot_layout_script_select_language (hb_face_t      *face,
+hb_ot_layout_script_select_language2 (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 */)
+                                    unsigned int   *language_index /* OUT */,
+                                    hb_tag_t       *chosen_language /* 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);
@@ -743,18 +767,61 @@ hb_ot_layout_script_select_language (hb_face_t      *face,
   for (i = 0; i < language_count; i++)
   {
     if (s.find_lang_sys_index (language_tags[i], language_index))
+    {
+      if (chosen_language)
+        *chosen_language = language_tags[i];
       return true;
+    }
   }
 
   /* try finding 'dflt' */
   if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
+  {
+    if (chosen_language)
+      *chosen_language = HB_OT_TAG_DEFAULT_LANGUAGE;
     return false;
+  }
 
   if (language_index)
     *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
+  if (chosen_language)
+    *chosen_language = HB_TAG_NONE;
   return false;
 }
 
+/**
+ * hb_ot_layout_script_select_language:
+ * @face: #hb_face_t to work upon
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
+ * @script_index: The index of the requested script tag
+ * @language_count: The number of languages in the specified script
+ * @language_tags: The array of language tags
+ * @language_index: (out): The index of the requested language
+ *
+ * Fetches the index of the first language tag fom @language_tags that is present
+ * in the specified face's GSUB or GPOS table, underneath the specified script
+ * index.
+ *
+ * If none of the given language tags is found, `false` is returned and
+ * @language_index is set to the default language index.
+ *
+ * Return value: `true` if one of the given language tags is found, `false` otherwise
+ *
+ * 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 */)
+{
+  return hb_ot_layout_script_select_language2 (face, table_tag,
+                                              script_index,
+                                              language_count, language_tags,
+                                              language_index, nullptr);
+}
 
 /**
  * hb_ot_layout_language_get_required_feature_index:
@@ -767,7 +834,9 @@ hb_ot_layout_script_select_language (hb_face_t      *face,
  * Fetches the index of a requested feature in the given face's GSUB or GPOS table,
  * underneath the specified script and language.
  *
- * Return value: %true if the feature is found, %false otherwise
+ * Return value: `true` if the feature is found, `false` otherwise
+ *
+ * Since: 0.6.0
  *
  **/
 hb_bool_t
@@ -798,7 +867,7 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t    *face,
  * Fetches the tag of a requested feature index in the given face's GSUB or GPOS table,
  * underneath the specified script and language.
  *
- * Return value: %true if the feature is found, %false otherwise
+ * Return value: `true` if the feature is found, `false` otherwise
  *
  * Since: 0.9.30
  **/
@@ -837,6 +906,9 @@ hb_ot_layout_language_get_required_feature (hb_face_t    *face,
  * returned will begin at the offset provided.
  *
  * Return value: Total number of features.
+ *
+ * Since: 0.6.0
+ *
  **/
 unsigned int
 hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
@@ -870,6 +942,9 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
  * returned will begin at the offset provided.
  *
  * Return value: Total number of feature tags.
+ *
+ * Since: 0.6.0
+ *
  **/
 unsigned int
 hb_ot_layout_language_get_feature_tags (hb_face_t    *face,
@@ -908,7 +983,9 @@ hb_ot_layout_language_get_feature_tags (hb_face_t    *face,
  * Fetches the index of a given feature tag in the specified face's GSUB table
  * or GPOS table, underneath the specified script and language.
  *
- * Return value: %true if the feature is found, %false otherwise
+ * Return value: `true` if the feature is found, `false` otherwise
+ *
+ * Since: 0.6.0
  *
  **/
 hb_bool_t
@@ -999,7 +1076,7 @@ struct hb_collect_features_context_t
   hb_collect_features_context_t (hb_face_t *face,
                                 hb_tag_t   table_tag,
                                 hb_set_t  *feature_indices_,
-                                 const hb_tag_t *features)
+                                const hb_tag_t *features)
 
     : g (get_gsubgpos_table (face, table_tag)),
       feature_indices (feature_indices_),
@@ -1026,7 +1103,7 @@ struct hb_collect_features_context_t
     {
       hb_tag_t tag = g.get_feature_tag (i);
       if (features_set.has (tag))
-        feature_indices_filter.add(i);
+       feature_indices_filter.add(i);
     }
   }
 
@@ -1158,10 +1235,13 @@ script_collect_features (hb_collect_features_context_t *c,
  * hb_ot_layout_collect_features:
  * @face: #hb_face_t to work upon
  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
- * @scripts: The array of scripts to collect features for
- * @languages: The array of languages to collect features for
- * @features: The array of features to collect
- * @feature_indexes: (out): The array of feature indexes found for the query
+ * @scripts: (nullable) (array zero-terminated=1): The array of scripts to collect features for,
+ *   terminated by %HB_TAG_NONE
+ * @languages: (nullable) (array zero-terminated=1): The array of languages to collect features for,
+ *   terminated by %HB_TAG_NONE
+ * @features: (nullable) (array zero-terminated=1): The array of features to collect,
+ *   terminated by %HB_TAG_NONE
+ * @feature_indexes: (out): The set of feature indexes found for the query
  *
  * Fetches a list of all feature indexes in the specified face's GSUB table
  * or GPOS table, underneath the specified scripts, languages, and features.
@@ -1202,14 +1282,60 @@ hb_ot_layout_collect_features (hb_face_t      *face,
   }
 }
 
+/**
+ * hb_ot_layout_collect_features_map:
+ * @face: #hb_face_t to work upon
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
+ * @script_index: The index of the requested script tag
+ * @language_index: The index of the requested language tag
+ * @feature_map: (out): The map of feature tag to feature index.
+ *
+ * Fetches the mapping from feature tags to feature indexes for
+ * the specified script and language.
+ *
+ * Since: 8.1.0
+ **/
+void
+hb_ot_layout_collect_features_map (hb_face_t      *face,
+                                  hb_tag_t        table_tag,
+                                  unsigned        script_index,
+                                  unsigned        language_index,
+                                  hb_map_t       *feature_map /* 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);
+
+  unsigned int count = l.get_feature_indexes (0, nullptr, nullptr);
+  feature_map->alloc (count);
+
+  /* Loop in reverse, such that earlier entries win. That emulates
+   * a linear search, which seems to be what other implementations do.
+   * We found that with arialuni_t.ttf, the "ur" language system has
+   * duplicate features, and the earlier ones work but not later ones.
+   */
+  for (unsigned int i = count; i; i--)
+  {
+    unsigned feature_index = 0;
+    unsigned feature_count = 1;
+    l.get_feature_indexes (i - 1, &feature_count, &feature_index);
+    if (!feature_count)
+      break;
+    hb_tag_t feature_tag = g.get_feature_tag (feature_index);
+    feature_map->set (feature_tag, feature_index);
+  }
+}
+
 
 /**
  * hb_ot_layout_collect_lookups:
  * @face: #hb_face_t to work upon
  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
- * @scripts: The array of scripts to collect lookups for
- * @languages: The array of languages to collect lookups for
- * @features: The array of features to collect lookups for
+ * @scripts: (nullable) (array zero-terminated=1): The array of scripts to collect lookups for,
+ *   terminated by %HB_TAG_NONE
+ * @languages: (nullable) (array zero-terminated=1): The array of languages to collect lookups for,
+ *   terminated by %HB_TAG_NONE
+ * @features: (nullable) (array zero-terminated=1): The array of features to collect lookups for,
+ *   terminated by %HB_TAG_NONE
  * @lookup_indexes: (out): The array of lookup indexes found for the query
  *
  * Fetches a list of all feature-lookup indexes in the specified face's GSUB
@@ -1233,11 +1359,10 @@ hb_ot_layout_collect_lookups (hb_face_t      *face,
   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);)
+  for (auto feature_index : feature_indexes)
     g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes);
 
-  g.feature_variation_collect_lookups (&feature_indexes, lookup_indexes);
+  g.feature_variation_collect_lookups (&feature_indexes, nullptr, lookup_indexes);
 }
 
 
@@ -1305,7 +1430,9 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
  * Fetches a list of feature variations in the specified face's GSUB table
  * or GPOS table, at the specified variation coordinates.
  *
- * Return value: %true if feature variations were found, %false otherwise.
+ * Return value: `true` if feature variations were found, `false` otherwise.
+ *
+ * Since: 1.4.0
  *
  **/
 hb_bool_t
@@ -1338,6 +1465,8 @@ hb_ot_layout_table_find_feature_variations (hb_face_t    *face,
  *
  * Return value: Total number of lookups.
  *
+ * Since: 1.4.0
+ *
  **/
 unsigned int
 hb_ot_layout_feature_with_variations_get_lookups (hb_face_t    *face,
@@ -1368,7 +1497,9 @@ hb_ot_layout_feature_with_variations_get_lookups (hb_face_t    *face,
  *
  * Tests whether the specified face includes any GSUB substitutions.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
+ *
+ * Since: 0.6.0
  *
  **/
 hb_bool_t
@@ -1390,7 +1521,7 @@ hb_ot_layout_has_substitution (hb_face_t *face)
  * Tests whether a specified lookup in the specified face would
  * trigger a substitution on the given glyph sequence.
  *
- * Return value: %true if a substitution would be triggered, %false otherwise
+ * Return value: `true` if a substitution would be triggered, `false` otherwise
  *
  * Since: 0.9.7
  **/
@@ -1401,11 +1532,13 @@ hb_ot_layout_lookup_would_substitute (hb_face_t            *face,
                                      unsigned int          glyphs_length,
                                      hb_bool_t             zero_context)
 {
-  if (unlikely (lookup_index >= face->table.GSUB->lookup_count)) return false;
+  auto &gsub = face->table.GSUB;
+  if (unlikely (lookup_index >= gsub->lookup_count)) return false;
   OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context);
 
-  const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);
-  return l.would_apply (&c, &face->table.GSUB->accels[lookup_index]);
+  const OT::SubstLookup& l = gsub->table->get_lookup (lookup_index);
+  auto *accel = gsub->get_accel (lookup_index);
+  return accel && l.would_apply (&c, accel);
 }
 
 
@@ -1425,56 +1558,6 @@ hb_ot_layout_substitute_start (hb_font_t    *font,
   _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;
-}
-
 /**
  * hb_ot_layout_lookup_substitute_closure:
  * @face: #hb_face_t to work upon
@@ -1492,15 +1575,12 @@ hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
                                        hb_set_t     *glyphs /* OUT */)
 {
   hb_map_t done_lookups_glyph_count;
-  hb_hashmap_t<unsigned, hb_set_t *> done_lookups_glyph_set;
+  hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> done_lookups_glyph_set;
   OT::hb_closure_context_t c (face, glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set);
 
   const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);
 
   l.closure (&c, lookup_index);
-
-  for (auto _ : done_lookups_glyph_set.iter ())
-    hb_set_destroy (_.second);
 }
 
 /**
@@ -1520,9 +1600,9 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t      *face,
                                         hb_set_t       *glyphs /* OUT */)
 {
   hb_map_t done_lookups_glyph_count;
-  hb_hashmap_t<unsigned, hb_set_t *> done_lookups_glyph_set;
+  hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> done_lookups_glyph_set;
   OT::hb_closure_context_t c (face, glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set);
-  const OT::GSUB& gsub = *face->table.GSUB->table;
+  const GSUB& gsub = *face->table.GSUB->table;
 
   unsigned int iteration_count = 0;
   unsigned int glyphs_length;
@@ -1532,7 +1612,7 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t      *face,
     glyphs_length = glyphs->get_population ();
     if (lookups)
     {
-      for (hb_codepoint_t lookup_index = HB_SET_VALUE_INVALID; hb_set_next (lookups, &lookup_index);)
+      for (auto lookup_index : *lookups)
        gsub.get_lookup (lookup_index).closure (&c, lookup_index);
     }
     else
@@ -1542,13 +1622,10 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t      *face,
     }
   } while (iteration_count++ <= HB_CLOSURE_MAX_STAGES &&
           glyphs_length != glyphs->get_population ());
-
-  for (auto _ : done_lookups_glyph_set.iter ())
-    hb_set_destroy (_.second);
 }
 
 /*
- * OT::GPOS
+ * GPOS
  */
 
 
@@ -1558,7 +1635,7 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t      *face,
  *
  * Tests whether the specified face includes any GPOS positioning.
  *
- * Return value: %true if the face has GPOS data, %false otherwise
+ * Return value: `true` if the face has GPOS data, `false` otherwise
  *
  **/
 hb_bool_t
@@ -1579,7 +1656,7 @@ hb_ot_layout_has_positioning (hb_face_t *face)
 void
 hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
 {
-  OT::GPOS::position_start (font, buffer);
+  GPOS::position_start (font, buffer);
 }
 
 
@@ -1594,7 +1671,7 @@ hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
 void
 hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer)
 {
-  OT::GPOS::position_finish_advances (font, buffer);
+  GPOS::position_finish_advances (font, buffer);
 }
 
 /**
@@ -1608,7 +1685,7 @@ hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer)
 void
 hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
 {
-  OT::GPOS::position_finish_offsets (font, buffer);
+  GPOS::position_finish_offsets (font, buffer);
 }
 
 
@@ -1631,7 +1708,7 @@ hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
  * For more information on this distinction, see the [`size` feature documentation](
  * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size).
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.10
  **/
@@ -1643,7 +1720,7 @@ hb_ot_layout_get_size_params (hb_face_t       *face,
                              unsigned int    *range_start,       /* OUT.  May be NULL */
                              unsigned int    *range_end          /* OUT.  May be NULL */)
 {
-  const OT::GPOS &gpos = *face->table.GPOS->table;
+  const 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 ();
@@ -1675,6 +1752,8 @@ hb_ot_layout_get_size_params (hb_face_t       *face,
 
   return false;
 }
+
+
 /**
  * hb_ot_layout_feature_get_name_ids:
  * @face: #hb_face_t to work upon
@@ -1695,7 +1774,7 @@ hb_ot_layout_get_size_params (hb_face_t       *face,
  * Fetches name indices from feature parameters for "Stylistic Set" ('ssXX') or
  * "Character Variant" ('cvXX') features.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.0.0
  **/
@@ -1794,46 +1873,45 @@ hb_ot_layout_feature_get_characters (hb_face_t      *face,
 struct GSUBProxy
 {
   static constexpr unsigned table_index = 0u;
-  static constexpr bool inplace = false;
+  static constexpr bool always_inplace = false;
   typedef OT::SubstLookup Lookup;
 
   GSUBProxy (hb_face_t *face) :
-    table (*face->table.GSUB->table),
-    accels (face->table.GSUB->accels) {}
+    accel (*face->table.GSUB) {}
 
-  const OT::GSUB &table;
-  const OT::hb_ot_layout_lookup_accelerator_t *accels;
+  const GSUB::accelerator_t &accel;
 };
 
 struct GPOSProxy
 {
   static constexpr unsigned table_index = 1u;
-  static constexpr bool inplace = true;
+  static constexpr bool always_inplace = true;
   typedef OT::PosLookup Lookup;
 
   GPOSProxy (hb_face_t *face) :
-    table (*face->table.GPOS->table),
-    accels (face->table.GPOS->accels) {}
+    accel (*face->table.GPOS) {}
 
-  const OT::GPOS &table;
-  const OT::hb_ot_layout_lookup_accelerator_t *accels;
+  const GPOS::accelerator_t &accel;
 };
 
 
 static inline bool
 apply_forward (OT::hb_ot_apply_context_t *c,
-              const OT::hb_ot_layout_lookup_accelerator_t &accel)
+              const OT::hb_ot_layout_lookup_accelerator_t &accel,
+              unsigned subtable_count)
 {
+  bool use_cache = accel.cache_enter (c);
+
   bool ret = false;
   hb_buffer_t *buffer = c->buffer;
   while (buffer->idx < buffer->len && buffer->successful)
   {
     bool applied = false;
-    if (accel.may_have (buffer->cur().codepoint) &&
+    if (accel.digest.may_have (buffer->cur().codepoint) &&
        (buffer->cur().mask & c->lookup_mask) &&
        c->check_glyph_property (&buffer->cur(), c->lookup_props))
      {
-       applied = accel.apply (c);
+       applied = accel.apply (c, subtable_count, use_cache);
      }
 
     if (applied)
@@ -1841,21 +1919,26 @@ apply_forward (OT::hb_ot_apply_context_t *c,
     else
       (void) buffer->next_glyph ();
   }
+
+  if (use_cache)
+    accel.cache_leave (c);
+
   return ret;
 }
 
 static inline bool
 apply_backward (OT::hb_ot_apply_context_t *c,
-              const OT::hb_ot_layout_lookup_accelerator_t &accel)
+              const OT::hb_ot_layout_lookup_accelerator_t &accel,
+              unsigned subtable_count)
 {
   bool ret = false;
   hb_buffer_t *buffer = c->buffer;
   do
   {
-    if (accel.may_have (buffer->cur().codepoint) &&
+    if (accel.digest.may_have (buffer->cur().codepoint) &&
        (buffer->cur().mask & c->lookup_mask) &&
        c->check_glyph_property (&buffer->cur(), c->lookup_props))
-     ret |= accel.apply (c);
+      ret |= accel.apply (c, subtable_count, false);
 
     /* The reverse lookup doesn't "advance" cursor (for good reason). */
     buffer->idx--;
@@ -1866,28 +1949,31 @@ apply_backward (OT::hb_ot_apply_context_t *c,
 }
 
 template <typename Proxy>
-static inline void
+static inline bool
 apply_string (OT::hb_ot_apply_context_t *c,
              const typename Proxy::Lookup &lookup,
              const OT::hb_ot_layout_lookup_accelerator_t &accel)
 {
   hb_buffer_t *buffer = c->buffer;
+  unsigned subtable_count = lookup.get_subtable_count ();
 
   if (unlikely (!buffer->len || !c->lookup_mask))
-    return;
+    return false;
+
+  bool ret = false;
 
   c->set_lookup_props (lookup.get_props ());
 
   if (likely (!lookup.is_reverse ()))
   {
     /* in/out forward substitution/positioning */
-    if (!Proxy::inplace)
+    if (!Proxy::always_inplace)
       buffer->clear_output ();
 
     buffer->idx = 0;
-    apply_forward (c, accel);
+    ret = apply_forward (c, accel, subtable_count);
 
-    if (!Proxy::inplace)
+    if (!Proxy::always_inplace)
       buffer->sync ();
   }
   else
@@ -1895,8 +1981,10 @@ apply_string (OT::hb_ot_apply_context_t *c,
     /* in-place backward substitution/positioning */
     assert (!buffer->have_output);
     buffer->idx = buffer->len - 1;
-    apply_backward (c, accel);
+    ret = apply_backward (c, accel, subtable_count);
   }
+
+  return ret;
 }
 
 template <typename Proxy>
@@ -1907,47 +1995,78 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
 {
   const unsigned int table_index = proxy.table_index;
   unsigned int i = 0;
-  OT::hb_ot_apply_context_t c (table_index, font, buffer);
-  c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
+  OT::hb_ot_apply_context_t c (table_index, font, buffer, proxy.accel.get_blob ());
+  c.set_recurse_func (Proxy::Lookup::template dispatch_recurse_func<OT::hb_ot_apply_context_t>);
 
   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++)
     {
-      unsigned int lookup_index = lookups[table_index][i].index;
-      if (!buffer->message (font, "start lookup %d", lookup_index)) continue;
-      c.set_lookup_index (lookup_index);
-      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);
-      c.set_random (lookups[table_index][i].random);
-
-      apply_string<Proxy> (&c,
-                          proxy.table.get_lookup (lookup_index),
-                          proxy.accels[lookup_index]);
-      (void) buffer->message (font, "end lookup %d", lookup_index);
+      auto &lookup = lookups[table_index][i];
+
+      unsigned int lookup_index = lookup.index;
+
+      auto *accel = proxy.accel.get_accel (lookup_index);
+      if (unlikely (!accel)) continue;
+
+      if (buffer->messaging () &&
+         !buffer->message (font, "start lookup %u feature '%c%c%c%c'", lookup_index, HB_UNTAG (lookup.feature_tag))) continue;
+
+      /* c.digest is a digest of all the current glyphs in the buffer
+       * (plus some past glyphs).
+       *
+       * Only try applying the lookup if there is any overlap. */
+      if (accel->digest.may_have (c.digest))
+      {
+       c.set_lookup_index (lookup_index);
+       c.set_lookup_mask (lookup.mask, false);
+       c.set_auto_zwj (lookup.auto_zwj, false);
+       c.set_auto_zwnj (lookup.auto_zwnj, false);
+       c.set_random (lookup.random);
+       c.set_per_syllable (lookup.per_syllable, false);
+       /* apply_string's set_lookup_props initializes the iterators. */
+
+       apply_string<Proxy> (&c,
+                            proxy.accel.table->get_lookup (lookup_index),
+                            *accel);
+      }
+      else if (buffer->messaging ())
+       (void) buffer->message (font, "skipped lookup %u feature '%c%c%c%c' because no glyph matches", lookup_index, HB_UNTAG (lookup.feature_tag));
+
+      if (buffer->messaging ())
+       (void) buffer->message (font, "end lookup %u feature '%c%c%c%c'", lookup_index, HB_UNTAG (lookup.feature_tag));
     }
 
     if (stage->pause_func)
-      stage->pause_func (plan, font, buffer);
+    {
+      if (stage->pause_func (plan, font, buffer))
+      {
+       /* Refresh working buffer digest since buffer changed. */
+       c.digest = buffer->digest ();
+      }
+    }
   }
 }
 
 void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
 {
   GSUBProxy proxy (font->face);
-  if (!buffer->message (font, "start table GSUB")) return;
+  if (buffer->messaging () &&
+      !buffer->message (font, "start table GSUB script tag '%c%c%c%c'", HB_UNTAG (chosen_script[0]))) return;
   apply (proxy, plan, font, buffer);
-  (void) buffer->message (font, "end table GSUB");
+  if (buffer->messaging ())
+    (void) buffer->message (font, "end table GSUB script tag '%c%c%c%c'", HB_UNTAG (chosen_script[0]));
 }
 
 void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
 {
   GPOSProxy proxy (font->face);
-  if (!buffer->message (font, "start table GPOS")) return;
+  if (buffer->messaging () &&
+      !buffer->message (font, "start table GPOS script tag '%c%c%c%c'", HB_UNTAG (chosen_script[1]))) return;
   apply (proxy, plan, font, buffer);
-  (void) buffer->message (font, "end table GPOS");
+  if (buffer->messaging ())
+    (void) buffer->message (font, "end table GPOS script tag '%c%c%c%c'", HB_UNTAG (chosen_script[1]));
 }
 
 void
@@ -1959,6 +2078,183 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
 }
 
 #ifndef HB_NO_BASE
+
+static void
+choose_base_tags (hb_script_t    script,
+                 hb_language_t  language,
+                 hb_tag_t      *script_tag,
+                 hb_tag_t      *language_tag)
+{
+  hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
+  unsigned script_count = ARRAY_LENGTH (script_tags);
+
+  hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
+  unsigned language_count = ARRAY_LENGTH (language_tags);
+
+  hb_ot_tags_from_script_and_language (script, language,
+                                      &script_count, script_tags,
+                                      &language_count, language_tags);
+
+  *script_tag = script_count ? script_tags[script_count - 1] : HB_OT_TAG_DEFAULT_SCRIPT;
+  *language_tag = language_count ? language_tags[language_count - 1] : HB_OT_TAG_DEFAULT_LANGUAGE;
+}
+
+/**
+ * hb_ot_layout_get_font_extents:
+ * @font: a font
+ * @direction: text direction.
+ * @script_tag:  script tag.
+ * @language_tag: language tag.
+ * @extents: (out) (nullable): font extents if found.
+ *
+ * Fetches script/language-specific font extents.  These values are
+ * looked up in the `BASE` table's `MinMax` records.
+ *
+ * If no such extents are found, the default extents for the font are
+ * fetched. As such, the return value of this function can for the
+ * most part be ignored.  Note that the per-script/language extents
+ * do not have a line-gap value, and the line-gap is set to zero in
+ * that case.
+ *
+ * Return value: `true` if found script/language-specific font extents.
+ *
+ * Since: 8.0.0
+ **/
+hb_bool_t
+hb_ot_layout_get_font_extents (hb_font_t         *font,
+                              hb_direction_t     direction,
+                              hb_tag_t           script_tag,
+                              hb_tag_t           language_tag,
+                              hb_font_extents_t *extents)
+{
+  hb_position_t min, max;
+  if (font->face->table.BASE->get_min_max (font, direction, script_tag, language_tag, HB_TAG_NONE,
+                                          &min, &max))
+  {
+    if (extents)
+    {
+      extents->ascender  = max;
+      extents->descender = min;
+      extents->line_gap  = 0;
+    }
+    return true;
+  }
+
+  hb_font_get_extents_for_direction (font, direction, extents);
+  return false;
+}
+
+/**
+ * hb_ot_layout_get_font_extents2:
+ * @font: a font
+ * @direction: text direction.
+ * @script:  script.
+ * @language: (nullable): language.
+ * @extents: (out) (nullable): font extents if found.
+ *
+ * Fetches script/language-specific font extents.  These values are
+ * looked up in the `BASE` table's `MinMax` records.
+ *
+ * If no such extents are found, the default extents for the font are
+ * fetched. As such, the return value of this function can for the
+ * most part be ignored.  Note that the per-script/language extents
+ * do not have a line-gap value, and the line-gap is set to zero in
+ * that case.
+ *
+ * This function is like hb_ot_layout_get_font_extents() but takes
+ * #hb_script_t and #hb_language_t instead of OpenType #hb_tag_t.
+ *
+ * Return value: `true` if found script/language-specific font extents.
+ *
+ * Since: 8.0.0
+ **/
+hb_bool_t
+hb_ot_layout_get_font_extents2 (hb_font_t         *font,
+                               hb_direction_t     direction,
+                               hb_script_t        script,
+                               hb_language_t      language,
+                               hb_font_extents_t *extents)
+{
+  hb_tag_t script_tag, language_tag;
+  choose_base_tags (script, language, &script_tag, &language_tag);
+  return hb_ot_layout_get_font_extents (font,
+                                       direction,
+                                       script_tag,
+                                       language_tag,
+                                       extents);
+}
+
+/**
+ * hb_ot_layout_get_horizontal_baseline_tag_for_script:
+ * @script: a script tag.
+ *
+ * Fetches the dominant horizontal baseline tag used by @script.
+ *
+ * Return value: dominant baseline tag for the @script.
+ *
+ * Since: 4.0.0
+ **/
+hb_ot_layout_baseline_tag_t
+hb_ot_layout_get_horizontal_baseline_tag_for_script (hb_script_t script)
+{
+  /* Keep in sync with hb_ot_layout_get_baseline_with_fallback */
+  switch ((int) script)
+  {
+    /* Unicode-1.1 additions */
+    case HB_SCRIPT_BENGALI:
+    case HB_SCRIPT_DEVANAGARI:
+    case HB_SCRIPT_GUJARATI:
+    case HB_SCRIPT_GURMUKHI:
+    /* Unicode-2.0 additions */
+    case HB_SCRIPT_TIBETAN:
+    /* Unicode-4.0 additions */
+    case HB_SCRIPT_LIMBU:
+    /* Unicode-4.1 additions */
+    case HB_SCRIPT_SYLOTI_NAGRI:
+    /* Unicode-5.0 additions */
+    case HB_SCRIPT_PHAGS_PA:
+    /* Unicode-5.2 additions */
+    case HB_SCRIPT_MEETEI_MAYEK:
+    /* Unicode-6.1 additions */
+    case HB_SCRIPT_SHARADA:
+    case HB_SCRIPT_TAKRI:
+    /* Unicode-7.0 additions */
+    case HB_SCRIPT_MODI:
+    case HB_SCRIPT_SIDDHAM:
+    case HB_SCRIPT_TIRHUTA:
+    /* Unicode-9.0 additions */
+    case HB_SCRIPT_MARCHEN:
+    case HB_SCRIPT_NEWA:
+    /* Unicode-10.0 additions */
+    case HB_SCRIPT_SOYOMBO:
+    case HB_SCRIPT_ZANABAZAR_SQUARE:
+    /* Unicode-11.0 additions */
+    case HB_SCRIPT_DOGRA:
+    case HB_SCRIPT_GUNJALA_GONDI:
+    /* Unicode-12.0 additions */
+    case HB_SCRIPT_NANDINAGARI:
+      return HB_OT_LAYOUT_BASELINE_TAG_HANGING;
+
+    /* Unicode-1.1 additions */
+    case HB_SCRIPT_HANGUL:
+    case HB_SCRIPT_HAN:
+    case HB_SCRIPT_HIRAGANA:
+    case HB_SCRIPT_KATAKANA:
+    /* Unicode-3.0 additions */
+    case HB_SCRIPT_BOPOMOFO:
+    /* Unicode-9.0 additions */
+    case HB_SCRIPT_TANGUT:
+    /* Unicode-10.0 additions */
+    case HB_SCRIPT_NUSHU:
+    /* Unicode-13.0 additions */
+    case HB_SCRIPT_KHITAN_SMALL_SCRIPT:
+      return HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT;
+
+    default:
+      return HB_OT_LAYOUT_BASELINE_TAG_ROMAN;
+  }
+}
+
 /**
  * hb_ot_layout_get_baseline:
  * @font: a font
@@ -1966,11 +2262,11 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
  * @direction: text direction.
  * @script_tag:  script tag.
  * @language_tag: language tag, currently unused.
- * @coord: (out): baseline value if found.
+ * @coord: (out) (nullable): baseline value if found.
  *
  * Fetches a baseline value from the face.
  *
- * Return value: %true if found baseline value in the font.
+ * Return value: `true` if found baseline value in the font.
  *
  * Since: 2.6.0
  **/
@@ -1982,13 +2278,302 @@ hb_ot_layout_get_baseline (hb_font_t                   *font,
                           hb_tag_t                     language_tag,
                           hb_position_t               *coord        /* OUT.  May be NULL. */)
 {
-  bool result = font->face->table.BASE->get_baseline (font, baseline_tag, direction, script_tag, language_tag, coord);
+  return font->face->table.BASE->get_baseline (font, baseline_tag, direction, script_tag, language_tag, coord);
+}
+
+/**
+ * hb_ot_layout_get_baseline2:
+ * @font: a font
+ * @baseline_tag: a baseline tag
+ * @direction: text direction.
+ * @script:  script.
+ * @language: (nullable): language, currently unused.
+ * @coord: (out) (nullable): baseline value if found.
+ *
+ * Fetches a baseline value from the face.
+ *
+ * This function is like hb_ot_layout_get_baseline() but takes
+ * #hb_script_t and #hb_language_t instead of OpenType #hb_tag_t.
+ *
+ * Return value: `true` if found baseline value in the font.
+ *
+ * Since: 8.0.0
+ **/
+hb_bool_t
+hb_ot_layout_get_baseline2 (hb_font_t                   *font,
+                           hb_ot_layout_baseline_tag_t  baseline_tag,
+                           hb_direction_t               direction,
+                           hb_script_t                  script,
+                           hb_language_t                language,
+                           hb_position_t               *coord        /* OUT.  May be NULL. */)
+{
+  hb_tag_t script_tag, language_tag;
+  choose_base_tags (script, language, &script_tag, &language_tag);
+  return hb_ot_layout_get_baseline (font,
+                                   baseline_tag,
+                                   direction,
+                                   script_tag,
+                                   language_tag,
+                                   coord);
+}
+
+/**
+ * hb_ot_layout_get_baseline_with_fallback:
+ * @font: a font
+ * @baseline_tag: a baseline tag
+ * @direction: text direction.
+ * @script_tag:  script tag.
+ * @language_tag: language tag, currently unused.
+ * @coord: (out): baseline value if found.
+ *
+ * Fetches a baseline value from the face, and synthesizes
+ * it if the font does not have it.
+ *
+ * Since: 4.0.0
+ **/
+void
+hb_ot_layout_get_baseline_with_fallback (hb_font_t                   *font,
+                                        hb_ot_layout_baseline_tag_t  baseline_tag,
+                                        hb_direction_t               direction,
+                                        hb_tag_t                     script_tag,
+                                        hb_tag_t                     language_tag,
+                                        hb_position_t               *coord /* OUT */)
+{
+  if (hb_ot_layout_get_baseline (font,
+                                baseline_tag,
+                                direction,
+                                script_tag,
+                                language_tag,
+                                coord))
+    return;
+
+  /* Synthesize missing baselines.
+   * See https://www.w3.org/TR/css-inline-3/#baseline-synthesis-fonts
+   */
+  switch (baseline_tag)
+  {
+  case HB_OT_LAYOUT_BASELINE_TAG_ROMAN:
+    *coord = 0; // FIXME origin ?
+    break;
+
+  case HB_OT_LAYOUT_BASELINE_TAG_MATH:
+    {
+      hb_codepoint_t glyph;
+      hb_glyph_extents_t extents;
+      if (HB_DIRECTION_IS_HORIZONTAL (direction) &&
+         (hb_font_get_nominal_glyph (font, 0x2212u, &glyph) ||
+          hb_font_get_nominal_glyph (font, '-', &glyph)) &&
+         hb_font_get_glyph_extents (font, glyph, &extents))
+      {
+       *coord = extents.y_bearing + extents.height / 2;
+      }
+      else
+      {
+       hb_position_t x_height = font->y_scale / 2;
+#ifndef HB_NO_METRICS
+       hb_ot_metrics_get_position_with_fallback (font, HB_OT_METRICS_TAG_X_HEIGHT, &x_height);
+#endif
+       *coord = x_height / 2;
+      }
+    }
+    break;
+
+  case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT:
+  case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT:
+    {
+      hb_position_t embox_top, embox_bottom;
+
+      hb_ot_layout_get_baseline_with_fallback (font,
+                                              HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
+                                              direction,
+                                              script_tag,
+                                              language_tag,
+                                              &embox_top);
+      hb_ot_layout_get_baseline_with_fallback (font,
+                                              HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
+                                              direction,
+                                              script_tag,
+                                              language_tag,
+                                              &embox_bottom);
+
+      if (baseline_tag == HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT)
+       *coord = embox_top + (embox_bottom - embox_top) / 10;
+      else
+       *coord = embox_bottom + (embox_top - embox_bottom) / 10;
+    }
+    break;
+
+  case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT:
+    if (hb_ot_layout_get_baseline (font,
+                                  HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
+                                  direction,
+                                  script_tag,
+                                  language_tag,
+                                  coord))
+      *coord += HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale;
+    else
+    {
+      hb_font_extents_t font_extents;
+      hb_font_get_extents_for_direction (font, direction, &font_extents);
+      *coord = font_extents.ascender;
+    }
+    break;
+
+  case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT:
+    if (hb_ot_layout_get_baseline (font,
+                                  HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
+                                  direction,
+                                  script_tag,
+                                  language_tag,
+                                  coord))
+      *coord -= HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale;
+    else
+    {
+      hb_font_extents_t font_extents;
+      hb_font_get_extents_for_direction (font, direction, &font_extents);
+      *coord = font_extents.descender;
+    }
+    break;
 
-  if (result && coord)
-    *coord = HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (*coord) : font->em_scale_x (*coord);
+  case HB_OT_LAYOUT_BASELINE_TAG_HANGING:
+    if (HB_DIRECTION_IS_HORIZONTAL (direction))
+    {
+      hb_codepoint_t ch;
+      hb_codepoint_t glyph;
+      hb_glyph_extents_t extents;
+
+      /* Keep in sync with hb_ot_layout_get_horizontal_baseline_for_script */
+      switch ((int) script_tag)
+      {
+      /* Unicode-1.1 additions */
+      case HB_SCRIPT_BENGALI:          ch = 0x0995u; break;
+      case HB_SCRIPT_DEVANAGARI:       ch = 0x0915u; break;
+      case HB_SCRIPT_GUJARATI:         ch = 0x0a95u; break;
+      case HB_SCRIPT_GURMUKHI:         ch = 0x0a15u; break;
+      /* Unicode-2.0 additions */
+      case HB_SCRIPT_TIBETAN:          ch = 0x0f40u; break;
+      /* Unicode-4.0 additions */
+      case HB_SCRIPT_LIMBU:            ch = 0x1901u; break;
+      /* Unicode-4.1 additions */
+      case HB_SCRIPT_SYLOTI_NAGRI:     ch = 0xa807u; break;
+      /* Unicode-5.0 additions */
+      case HB_SCRIPT_PHAGS_PA:         ch = 0xa840u; break;
+      /* Unicode-5.2 additions */
+      case HB_SCRIPT_MEETEI_MAYEK:     ch = 0xabc0u; break;
+      /* Unicode-6.1 additions */
+      case HB_SCRIPT_SHARADA:          ch = 0x11191u; break;
+      case HB_SCRIPT_TAKRI:            ch = 0x1168cu; break;
+      /* Unicode-7.0 additions */
+      case HB_SCRIPT_MODI:             ch = 0x1160eu;break;
+      case HB_SCRIPT_SIDDHAM:          ch = 0x11590u; break;
+      case HB_SCRIPT_TIRHUTA:          ch = 0x1148fu; break;
+      /* Unicode-9.0 additions */
+      case HB_SCRIPT_MARCHEN:          ch = 0x11c72u; break;
+      case HB_SCRIPT_NEWA:             ch = 0x1140eu; break;
+      /* Unicode-10.0 additions */
+      case HB_SCRIPT_SOYOMBO:          ch = 0x11a5cu; break;
+      case HB_SCRIPT_ZANABAZAR_SQUARE: ch = 0x11a0bu; break;
+      /* Unicode-11.0 additions */
+      case HB_SCRIPT_DOGRA:            ch = 0x1180au; break;
+      case HB_SCRIPT_GUNJALA_GONDI:    ch = 0x11d6cu; break;
+      /* Unicode-12.0 additions */
+      case HB_SCRIPT_NANDINAGARI:      ch = 0x119b0u; break;
+      default:                         ch = 0;        break;
+      }
+
+      if (ch &&
+         hb_font_get_nominal_glyph (font, ch, &glyph) &&
+         hb_font_get_glyph_extents (font, glyph, &extents))
+       *coord = extents.y_bearing;
+      else
+       *coord = font->y_scale * 6 / 10; // FIXME makes assumptions about origin
+    }
+    else
+      *coord = font->x_scale * 6 / 10; // FIXME makes assumptions about origin
+    break;
+
+  case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL:
+    {
+      hb_position_t top, bottom;
+      hb_ot_layout_get_baseline_with_fallback (font,
+                                              HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
+                                              direction,
+                                              script_tag,
+                                              language_tag,
+                                              &top);
+      hb_ot_layout_get_baseline_with_fallback (font,
+                                              HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
+                                              direction,
+                                              script_tag,
+                                              language_tag,
+                                              &bottom);
+      *coord = (top + bottom) / 2;
 
-  return result;
+    }
+    break;
+
+  case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL:
+    {
+      hb_position_t top, bottom;
+      hb_ot_layout_get_baseline_with_fallback (font,
+                                              HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT,
+                                              direction,
+                                              script_tag,
+                                              language_tag,
+                                              &top);
+      hb_ot_layout_get_baseline_with_fallback (font,
+                                              HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT,
+                                              direction,
+                                              script_tag,
+                                              language_tag,
+                                              &bottom);
+      *coord = (top + bottom) / 2;
+
+    }
+    break;
+
+  case _HB_OT_LAYOUT_BASELINE_TAG_MAX_VALUE:
+  default:
+    *coord = 0;
+    break;
+  }
 }
+
+/**
+ * hb_ot_layout_get_baseline_with_fallback2:
+ * @font: a font
+ * @baseline_tag: a baseline tag
+ * @direction: text direction.
+ * @script:  script.
+ * @language: (nullable): language, currently unused.
+ * @coord: (out): baseline value if found.
+ *
+ * Fetches a baseline value from the face, and synthesizes
+ * it if the font does not have it.
+ *
+ * This function is like hb_ot_layout_get_baseline_with_fallback() but takes
+ * #hb_script_t and #hb_language_t instead of OpenType #hb_tag_t.
+ *
+ * Since: 8.0.0
+ **/
+void
+hb_ot_layout_get_baseline_with_fallback2 (hb_font_t                   *font,
+                                         hb_ot_layout_baseline_tag_t  baseline_tag,
+                                         hb_direction_t               direction,
+                                         hb_script_t                  script,
+                                         hb_language_t                language,
+                                         hb_position_t               *coord        /* OUT */)
+{
+  hb_tag_t script_tag, language_tag;
+  choose_base_tags (script, language, &script_tag, &language_tag);
+  hb_ot_layout_get_baseline_with_fallback (font,
+                                          baseline_tag,
+                                          direction,
+                                          script_tag,
+                                          language_tag,
+                                          coord);
+}
+
 #endif
 
 
@@ -1998,11 +2583,6 @@ struct hb_get_glyph_alternates_dispatch_t :
   static return_t default_return_value () { return 0; }
   bool stop_sublookup_iteration (return_t r) const { return r; }
 
-  hb_face_t *face;
-
-  hb_get_glyph_alternates_dispatch_t (hb_face_t *face) :
-                                       face (face) {}
-
   private:
   template <typename T, typename ...Ts> auto
   _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN
@@ -2016,6 +2596,7 @@ struct hb_get_glyph_alternates_dispatch_t :
   ( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )
 };
 
+#ifndef HB_NO_LAYOUT_RARELY_USED
 /**
  * hb_ot_layout_lookup_get_glyph_alternates:
  * @face: a face.
@@ -2041,11 +2622,80 @@ hb_ot_layout_lookup_get_glyph_alternates (hb_face_t      *face,
                                          unsigned       *alternate_count  /* IN/OUT.  May be NULL. */,
                                          hb_codepoint_t *alternate_glyphs /* OUT.     May be NULL. */)
 {
-  hb_get_glyph_alternates_dispatch_t c (face);
+  hb_get_glyph_alternates_dispatch_t c;
   const OT::SubstLookup &lookup = face->table.GSUB->table->get_lookup (lookup_index);
   auto ret = lookup.dispatch (&c, glyph, start_offset, alternate_count, alternate_glyphs);
   if (!ret && alternate_count) *alternate_count = 0;
   return ret;
 }
 
+
+struct hb_position_single_dispatch_t :
+       hb_dispatch_context_t<hb_position_single_dispatch_t, bool>
+{
+  static return_t default_return_value () { return false; }
+  bool stop_sublookup_iteration (return_t r) const { return r; }
+
+  private:
+  template <typename T, typename ...Ts> auto
+  _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN
+  ( obj.position_single (std::forward<Ts> (ds)...) )
+  template <typename T, typename ...Ts> auto
+  _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN
+  ( default_return_value () )
+  public:
+  template <typename T, typename ...Ts> auto
+  dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN
+  ( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )
+};
+
+/**
+ * hb_ot_layout_lookup_get_optical_bound:
+ * @font: a font.
+ * @lookup_index: index of the feature lookup to query.
+ * @direction: edge of the glyph to query.
+ * @glyph: a glyph id.
+ *
+ * Fetches the optical bound of a glyph positioned at the margin of text.
+ * The direction identifies which edge of the glyph to query.
+ *
+ * Return value: Adjustment value. Negative values mean the glyph will stick out of the margin.
+ *
+ * Since: 5.3.0
+ **/
+hb_position_t
+hb_ot_layout_lookup_get_optical_bound (hb_font_t      *font,
+                                      unsigned        lookup_index,
+                                      hb_direction_t  direction,
+                                      hb_codepoint_t  glyph)
+{
+  const OT::PosLookup &lookup = font->face->table.GPOS->table->get_lookup (lookup_index);
+  hb_blob_t *blob = font->face->table.GPOS->get_blob ();
+  hb_glyph_position_t pos = {0};
+  hb_position_single_dispatch_t c;
+  lookup.dispatch (&c, font, blob, direction, glyph, pos);
+  hb_position_t ret = 0;
+  switch (direction)
+  {
+    case HB_DIRECTION_LTR:
+      ret = pos.x_offset;
+      break;
+    case HB_DIRECTION_RTL:
+      ret = pos.x_advance - pos.x_offset;
+      break;
+    case HB_DIRECTION_TTB:
+      ret = pos.y_offset;
+      break;
+    case HB_DIRECTION_BTT:
+      ret = pos.y_advance - pos.y_offset;
+      break;
+    case HB_DIRECTION_INVALID:
+    default:
+      break;
+  }
+  return ret;
+}
+#endif
+
+
 #endif
index d47ba0f..386b98d 100644 (file)
@@ -255,6 +255,15 @@ hb_ot_layout_script_select_language (hb_face_t      *face,
                                     unsigned int   *language_index /* OUT */);
 
 HB_EXTERN hb_bool_t
+hb_ot_layout_script_select_language2 (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_tag_t       *chosen_language /* OUT */);
+
+HB_EXTERN hb_bool_t
 hb_ot_layout_language_get_required_feature_index (hb_face_t    *face,
                                                  hb_tag_t      table_tag,
                                                  unsigned int  script_index,
@@ -316,6 +325,13 @@ hb_ot_layout_collect_features (hb_face_t      *face,
                               hb_set_t       *feature_indexes /* OUT */);
 
 HB_EXTERN void
+hb_ot_layout_collect_features_map (hb_face_t      *face,
+                                  hb_tag_t        table_tag,
+                                  unsigned        script_index,
+                                  unsigned        language_index,
+                                  hb_map_t       *feature_map /* OUT */);
+
+HB_EXTERN void
 hb_ot_layout_collect_lookups (hb_face_t      *face,
                              hb_tag_t        table_tag,
                              const hb_tag_t *scripts,
@@ -332,31 +348,6 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
                                    hb_set_t     *glyphs_after,  /* OUT.  May be NULL */
                                    hb_set_t     *glyphs_output  /* OUT.  May be NULL */);
 
-#ifdef HB_NOT_IMPLEMENTED
-typedef struct
-{
-  const hb_codepoint_t *before,
-  unsigned int          before_length,
-  const hb_codepoint_t *input,
-  unsigned int          input_length,
-  const hb_codepoint_t *after,
-  unsigned int          after_length,
-} hb_ot_layout_glyph_sequence_t;
-
-typedef hb_bool_t
-(*hb_ot_layout_glyph_sequence_func_t) (hb_font_t    *font,
-                                      hb_tag_t      table_tag,
-                                      unsigned int  lookup_index,
-                                      const hb_ot_layout_glyph_sequence_t *sequence,
-                                      void         *user_data);
-
-HB_EXTERN void
-Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t    *face,
-                                        hb_tag_t      table_tag,
-                                        unsigned int  lookup_index,
-                                        hb_ot_layout_glyph_sequence_func_t callback,
-                                        void         *user_data);
-#endif
 
 /* Variations support */
 
@@ -411,19 +402,6 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t      *face,
                                         hb_set_t       *glyphs);
 
 
-#ifdef HB_NOT_IMPLEMENTED
-/* Note: You better have GDEF when using this API, or marks won't do much. */
-HB_EXTERN hb_bool_t
-Xhb_ot_layout_lookup_substitute (hb_font_t            *font,
-                               unsigned int          lookup_index,
-                               const hb_ot_layout_glyph_sequence_t *sequence,
-                               unsigned int          out_size,
-                               hb_codepoint_t       *glyphs_out,   /* OUT */
-                               unsigned int         *clusters_out, /* OUT */
-                               unsigned int         *out_length    /* OUT */);
-#endif
-
-
 /*
  * GPOS
  */
@@ -431,15 +409,6 @@ Xhb_ot_layout_lookup_substitute (hb_font_t            *font,
 HB_EXTERN hb_bool_t
 hb_ot_layout_has_positioning (hb_face_t *face);
 
-#ifdef HB_NOT_IMPLEMENTED
-/* Note: You better have GDEF when using this API, or marks won't do much. */
-HB_EXTERN hb_bool_t
-Xhb_ot_layout_lookup_position (hb_font_t            *font,
-                             unsigned int          lookup_index,
-                             const hb_ot_layout_glyph_sequence_t *sequence,
-                             hb_glyph_position_t  *positions /* IN / OUT */);
-#endif
-
 /* 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
@@ -450,6 +419,16 @@ hb_ot_layout_get_size_params (hb_face_t       *face,
                              unsigned int    *range_start,       /* OUT.  May be NULL */
                              unsigned int    *range_end          /* OUT.  May be NULL */);
 
+HB_EXTERN hb_position_t
+hb_ot_layout_lookup_get_optical_bound (hb_font_t      *font,
+                                      unsigned        lookup_index,
+                                      hb_direction_t  direction,
+                                      hb_codepoint_t  glyph);
+
+
+/*
+ * GSUB/GPOS
+ */
 
 HB_EXTERN hb_bool_t
 hb_ot_layout_feature_get_name_ids (hb_face_t       *face,
@@ -470,10 +449,25 @@ hb_ot_layout_feature_get_characters (hb_face_t      *face,
                                     unsigned int   *char_count    /* IN/OUT.  May be NULL */,
                                     hb_codepoint_t *characters    /* OUT.     May be NULL */);
 
+
 /*
  * BASE
  */
 
+HB_EXTERN hb_bool_t
+hb_ot_layout_get_font_extents (hb_font_t         *font,
+                              hb_direction_t     direction,
+                              hb_tag_t           script_tag,
+                              hb_tag_t           language_tag,
+                              hb_font_extents_t *extents);
+
+HB_EXTERN hb_bool_t
+hb_ot_layout_get_font_extents2 (hb_font_t         *font,
+                               hb_direction_t     direction,
+                               hb_script_t        script,
+                               hb_language_t      language,
+                               hb_font_extents_t *extents);
+
 /**
  * hb_ot_layout_baseline_tag_t:
  * @HB_OT_LAYOUT_BASELINE_TAG_ROMAN: The baseline used by alphabetic scripts such as Latin, Cyrillic and Greek.
@@ -487,9 +481,11 @@ hb_ot_layout_feature_get_characters (hb_face_t      *face,
  * if the direction is horizontal or vertical, respectively.
  * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT: Ideographic character face top or right edge,
  * if the direction is horizontal or vertical, respectively.
+ * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL: The center of the ideographic character face. Since: 4.0.0
  * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT: Ideographic em-box bottom or left edge,
  * if the direction is horizontal or vertical, respectively.
  * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT: Ideographic em-box top or right edge baseline,
+ * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL: The center of the ideographic em-box. Since: 4.0.0
  * if the direction is horizontal or vertical, respectively.
  * @HB_OT_LAYOUT_BASELINE_TAG_MATH: The baseline about which mathematical characters are centered.
  * In vertical writing mode when mathematical characters rotated 90 degrees clockwise, are centered.
@@ -503,14 +499,19 @@ typedef enum {
   HB_OT_LAYOUT_BASELINE_TAG_HANGING                    = HB_TAG ('h','a','n','g'),
   HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT   = HB_TAG ('i','c','f','b'),
   HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT     = HB_TAG ('i','c','f','t'),
+  HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL          = HB_TAG ('I','c','f','c'),
   HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT  = HB_TAG ('i','d','e','o'),
   HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT    = HB_TAG ('i','d','t','p'),
+  HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL         = HB_TAG ('I','d','c','e'),
   HB_OT_LAYOUT_BASELINE_TAG_MATH                       = HB_TAG ('m','a','t','h'),
 
   /*< private >*/
   _HB_OT_LAYOUT_BASELINE_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
 } hb_ot_layout_baseline_tag_t;
 
+HB_EXTERN hb_ot_layout_baseline_tag_t
+hb_ot_layout_get_horizontal_baseline_tag_for_script (hb_script_t script);
+
 HB_EXTERN hb_bool_t
 hb_ot_layout_get_baseline (hb_font_t                   *font,
                           hb_ot_layout_baseline_tag_t  baseline_tag,
@@ -519,6 +520,30 @@ hb_ot_layout_get_baseline (hb_font_t                   *font,
                           hb_tag_t                     language_tag,
                           hb_position_t               *coord        /* OUT.  May be NULL. */);
 
+HB_EXTERN hb_bool_t
+hb_ot_layout_get_baseline2 (hb_font_t                   *font,
+                           hb_ot_layout_baseline_tag_t  baseline_tag,
+                           hb_direction_t               direction,
+                           hb_script_t                  script,
+                           hb_language_t                language,
+                           hb_position_t               *coord        /* OUT.  May be NULL. */);
+
+HB_EXTERN void
+hb_ot_layout_get_baseline_with_fallback (hb_font_t                   *font,
+                                        hb_ot_layout_baseline_tag_t  baseline_tag,
+                                        hb_direction_t               direction,
+                                        hb_tag_t                     script_tag,
+                                        hb_tag_t                     language_tag,
+                                        hb_position_t               *coord        /* OUT */);
+
+HB_EXTERN void
+hb_ot_layout_get_baseline_with_fallback2 (hb_font_t                   *font,
+                                         hb_ot_layout_baseline_tag_t  baseline_tag,
+                                         hb_direction_t               direction,
+                                         hb_script_t                  script,
+                                         hb_language_t                language,
+                                         hb_position_t               *coord        /* OUT */);
+
 HB_END_DECLS
 
 #endif /* HB_OT_LAYOUT_H */
index ede8f00..d718893 100644 (file)
@@ -102,19 +102,19 @@ HB_INTERNAL void
 hb_ot_layout_substitute_start (hb_font_t    *font,
                               hb_buffer_t  *buffer);
 
-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;
+namespace Layout {
+namespace GSUB_impl {
+  struct SubstLookup;
+}
+}
 }
 
 HB_INTERNAL void
 hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
-                               const OT::SubstLookup &lookup,
+                               const OT::Layout::GSUB_impl::SubstLookup &lookup,
                                const OT::hb_ot_layout_lookup_accelerator_t &accel);
 
 
@@ -168,17 +168,6 @@ _hb_next_syllable (hb_buffer_t *buffer, unsigned int start)
   return start;
 }
 
-static inline void
-_hb_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;
-}
-
 
 /* unicode_props */
 
@@ -459,7 +448,7 @@ _hb_glyph_info_get_lig_id (const hb_glyph_info_t *info)
 static inline bool
 _hb_glyph_info_ligated_internal (const hb_glyph_info_t *info)
 {
-  return !!(info->lig_props() & IS_LIG_BASE);
+  return info->lig_props() & IS_LIG_BASE;
 }
 
 static inline unsigned int
@@ -485,6 +474,8 @@ static inline uint8_t
 _hb_allocate_lig_id (hb_buffer_t *buffer)
 {
   uint8_t lig_id = buffer->next_serial () & 0x07;
+  if (unlikely (!lig_id))
+    lig_id = _hb_allocate_lig_id (buffer); /* in case of overflow */
   return lig_id;
 }
 
@@ -505,37 +496,37 @@ _hb_glyph_info_get_glyph_props (const hb_glyph_info_t *info)
 static inline bool
 _hb_glyph_info_is_base_glyph (const hb_glyph_info_t *info)
 {
-  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
+  return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
 }
 
 static inline bool
 _hb_glyph_info_is_ligature (const hb_glyph_info_t *info)
 {
-  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE);
+  return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
 }
 
 static inline bool
 _hb_glyph_info_is_mark (const hb_glyph_info_t *info)
 {
-  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
+  return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK;
 }
 
 static inline bool
 _hb_glyph_info_substituted (const hb_glyph_info_t *info)
 {
-  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
+  return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
 }
 
 static inline bool
 _hb_glyph_info_ligated (const hb_glyph_info_t *info)
 {
-  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED);
+  return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
 }
 
 static inline bool
 _hb_glyph_info_multiplied (const hb_glyph_info_t *info)
 {
-  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
+  return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
 }
 
 static inline bool
@@ -557,7 +548,7 @@ _hb_glyph_info_clear_substituted (hb_glyph_info_t *info)
   info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
 }
 
-static inline void
+static inline bool
 _hb_clear_substitution_flags (const hb_ot_shape_plan_t *plan HB_UNUSED,
                              hb_font_t *font HB_UNUSED,
                              hb_buffer_t *buffer)
@@ -566,6 +557,7 @@ _hb_clear_substitution_flags (const hb_ot_shape_plan_t *plan HB_UNUSED,
   unsigned int count = buffer->len;
   for (unsigned int i = 0; i < count; i++)
     _hb_glyph_info_clear_substituted (&info[i]);
+  return false;
 }
 
 
@@ -594,13 +586,11 @@ _hb_buffer_allocate_gsubgpos_vars (hb_buffer_t *buffer)
 {
   HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
   HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
-  HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
 }
 
 static inline void
 _hb_buffer_deallocate_gsubgpos_vars (hb_buffer_t *buffer)
 {
-  HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
   HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
   HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
 }
@@ -610,7 +600,6 @@ _hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer)
 {
   HB_BUFFER_ASSERT_VAR (buffer, glyph_props);
   HB_BUFFER_ASSERT_VAR (buffer, lig_props);
-  HB_BUFFER_ASSERT_VAR (buffer, syllable);
 }
 
 /* Make sure no one directly touches our props... */
index 12ceea5..fac73eb 100644 (file)
@@ -43,16 +43,16 @@ void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_o
 
 
 hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
-                                         const hb_segment_properties_t *props_)
+                                         const hb_segment_properties_t &props_)
 {
-  memset (this, 0, sizeof (*this));
+  hb_memset (this, 0, sizeof (*this));
 
   feature_infos.init ();
   for (unsigned int table_index = 0; table_index < 2; table_index++)
     stages[table_index].init ();
 
   face = face_;
-  props = *props_;
+  props = props_;
 
   /* 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. */
@@ -109,6 +109,21 @@ void hb_ot_map_builder_t::add_feature (hb_tag_t tag,
   info->stage[1] = current_stage[1];
 }
 
+bool hb_ot_map_builder_t::has_feature (hb_tag_t tag)
+{
+  for (unsigned int table_index = 0; table_index < 2; table_index++)
+  {
+    if (hb_ot_layout_language_find_feature (face,
+                                           table_tags[table_index],
+                                           script_index[table_index],
+                                           language_index[table_index],
+                                           tag,
+                                           nullptr))
+      return true;
+  }
+  return false;
+}
+
 void
 hb_ot_map_builder_t::add_lookups (hb_ot_map_t  &m,
                                  unsigned int  table_index,
@@ -117,7 +132,9 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t  &m,
                                  hb_mask_t     mask,
                                  bool          auto_zwnj,
                                  bool          auto_zwj,
-                                 bool          random)
+                                 bool          random,
+                                 bool          per_syllable,
+                                 hb_tag_t      feature_tag)
 {
   unsigned int lookup_indices[32];
   unsigned int offset, len;
@@ -145,6 +162,8 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t  &m,
       lookup->auto_zwnj = auto_zwnj;
       lookup->auto_zwj = auto_zwj;
       lookup->random = random;
+      lookup->per_syllable = per_syllable;
+      lookup->feature_tag = feature_tag;
     }
 
     offset += len;
@@ -194,35 +213,46 @@ hb_ot_map_builder_t::compile (hb_ot_map_t                  &m,
   /* Sort features and merge duplicates */
   if (feature_infos.length)
   {
-    feature_infos.qsort ();
+    if (!is_simple)
+      feature_infos.qsort ();
+    auto *f = feature_infos.arrayZ;
     unsigned int j = 0;
-    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];
+    unsigned count = feature_infos.length;
+    for (unsigned int i = 1; i < count; i++)
+      if (f[i].tag != f[j].tag)
+       f[++j] = f[i];
       else {
-       if (feature_infos[i].flags & F_GLOBAL) {
-         feature_infos[j].flags |= F_GLOBAL;
-         feature_infos[j].max_value = feature_infos[i].max_value;
-         feature_infos[j].default_value = feature_infos[i].default_value;
+       if (f[i].flags & F_GLOBAL) {
+         f[j].flags |= F_GLOBAL;
+         f[j].max_value = f[i].max_value;
+         f[j].default_value = f[i].default_value;
        } else {
-         if (feature_infos[j].flags & F_GLOBAL)
-           feature_infos[j].flags ^= F_GLOBAL;
-         feature_infos[j].max_value = hb_max (feature_infos[j].max_value, feature_infos[i].max_value);
+         if (f[j].flags & F_GLOBAL)
+           f[j].flags ^= F_GLOBAL;
+         f[j].max_value = hb_max (f[j].max_value, f[i].max_value);
          /* Inherit default_value from j */
        }
-       feature_infos[j].flags |= (feature_infos[i].flags & F_HAS_FALLBACK);
-       feature_infos[j].stage[0] = hb_min (feature_infos[j].stage[0], feature_infos[i].stage[0]);
-       feature_infos[j].stage[1] = hb_min (feature_infos[j].stage[1], feature_infos[i].stage[1]);
+       f[j].flags |= (f[i].flags & F_HAS_FALLBACK);
+       f[j].stage[0] = hb_min (f[j].stage[0], f[i].stage[0]);
+       f[j].stage[1] = hb_min (f[j].stage[1], f[i].stage[1]);
       }
     feature_infos.shrink (j + 1);
   }
 
+  hb_map_t feature_indices[2];
+  for (unsigned int table_index = 0; table_index < 2; table_index++)
+    hb_ot_layout_collect_features_map (face,
+                                      table_tags[table_index],
+                                      script_index[table_index],
+                                      language_index[table_index],
+                                      &feature_indices[table_index]);
 
   /* Allocate bits now */
   static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), "");
   unsigned int next_bit = hb_popcount (HB_GLYPH_FLAG_DEFINED) + 1;
 
-  for (unsigned int i = 0; i < feature_infos.length; i++)
+  unsigned count = feature_infos.length;
+  for (unsigned int i = 0; i < count; i++)
   {
     const feature_info_t *info = &feature_infos[i];
 
@@ -238,7 +268,6 @@ hb_ot_map_builder_t::compile (hb_ot_map_t                  &m,
     if (!info->max_value || next_bit + bits_needed >= global_bit_shift)
       continue; /* Feature disabled, or not enough bits. */
 
-
     bool found = false;
     unsigned int feature_index[2];
     for (unsigned int table_index = 0; table_index < 2; table_index++)
@@ -246,12 +275,14 @@ hb_ot_map_builder_t::compile (hb_ot_map_t                  &m,
       if (required_feature_tag[table_index] == info->tag)
        required_feature_stage[table_index] = info->stage[table_index];
 
-      found |= (bool) hb_ot_layout_language_find_feature (face,
-                                                         table_tags[table_index],
-                                                         script_index[table_index],
-                                                         language_index[table_index],
-                                                         info->tag,
-                                                         &feature_index[table_index]);
+      hb_codepoint_t *index;
+      if (feature_indices[table_index].has (info->tag, &index))
+      {
+        feature_index[table_index] = *index;
+        found = true;
+      }
+      else
+        feature_index[table_index] = HB_OT_LAYOUT_NO_FEATURE_INDEX;
     }
     if (!found && (info->flags & F_GLOBAL_SEARCH))
     {
@@ -277,6 +308,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t                  &m,
     map->auto_zwnj = !(info->flags & F_MANUAL_ZWNJ);
     map->auto_zwj = !(info->flags & F_MANUAL_ZWJ);
     map->random = !!(info->flags & F_RANDOM);
+    map->per_syllable = !!(info->flags & F_PER_SYLLABLE);
     if ((info->flags & F_GLOBAL) && info->max_value == 1) {
       /* Uses the global bit */
       map->shift = global_bit_shift;
@@ -290,8 +322,9 @@ hb_ot_map_builder_t::compile (hb_ot_map_t                  &m,
     map->_1_mask = (1u << map->shift) & map->mask;
     map->needs_fallback = !found;
   }
-  feature_infos.shrink (0); /* Done with these */
-
+  //feature_infos.shrink (0); /* Done with these */
+  if (is_simple)
+    m.features.qsort ();
 
   add_gsub_pause (nullptr);
   add_gpos_pause (nullptr);
@@ -299,6 +332,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t                  &m,
   for (unsigned int table_index = 0; table_index < 2; table_index++)
   {
     /* Collect lookup indices for features */
+    auto &lookups = m.lookups[table_index];
 
     unsigned int stage_index = 0;
     unsigned int last_num_lookups = 0;
@@ -311,35 +345,39 @@ hb_ot_map_builder_t::compile (hb_ot_map_t                  &m,
                     key.variations_index[table_index],
                     global_bit_mask);
 
-      for (unsigned i = 0; i < m.features.length; i++)
-       if (m.features[i].stage[table_index] == stage)
+      for (auto &feature : m.features)
+      {
+       if (feature.stage[table_index] == stage)
          add_lookups (m, table_index,
-                      m.features[i].index[table_index],
+                      feature.index[table_index],
                       key.variations_index[table_index],
-                      m.features[i].mask,
-                      m.features[i].auto_zwnj,
-                      m.features[i].auto_zwj,
-                      m.features[i].random);
+                      feature.mask,
+                      feature.auto_zwnj,
+                      feature.auto_zwj,
+                      feature.random,
+                      feature.per_syllable,
+                      feature.tag);
+      }
 
       /* Sort lookups and merge duplicates */
-      if (last_num_lookups < m.lookups[table_index].length)
+      if (last_num_lookups + 1 < lookups.length)
       {
-       m.lookups[table_index].qsort (last_num_lookups, m.lookups[table_index].length);
+       lookups.as_array ().sub_array (last_num_lookups, lookups.length - last_num_lookups).qsort ();
 
        unsigned int j = last_num_lookups;
-       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];
+       for (unsigned int i = j + 1; i < lookups.length; i++)
+         if (lookups.arrayZ[i].index != lookups.arrayZ[j].index)
+           lookups.arrayZ[++j] = lookups.arrayZ[i];
          else
          {
-           m.lookups[table_index][j].mask |= m.lookups[table_index][i].mask;
-           m.lookups[table_index][j].auto_zwnj &= m.lookups[table_index][i].auto_zwnj;
-           m.lookups[table_index][j].auto_zwj &= m.lookups[table_index][i].auto_zwj;
+           lookups.arrayZ[j].mask |= lookups.arrayZ[i].mask;
+           lookups.arrayZ[j].auto_zwnj &= lookups.arrayZ[i].auto_zwnj;
+           lookups.arrayZ[j].auto_zwj &= lookups.arrayZ[i].auto_zwj;
          }
-       m.lookups[table_index].shrink (j + 1);
+       lookups.shrink (j + 1);
       }
 
-      last_num_lookups = m.lookups[table_index].length;
+      last_num_lookups = lookups.length;
 
       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 ();
index 5f2afae..8af8129 100644 (file)
@@ -56,9 +56,17 @@ struct hb_ot_map_t
     unsigned int auto_zwnj : 1;
     unsigned int auto_zwj : 1;
     unsigned int random : 1;
+    unsigned int per_syllable : 1;
 
     int cmp (const hb_tag_t tag_) const
     { return tag_ < tag ? -1 : tag_ > tag ? 1 : 0; }
+
+    HB_INTERNAL static int cmp (const void *pa, const void *pb)
+    {
+      const feature_map_t *a = (const feature_map_t *) pa;
+      const feature_map_t *b = (const feature_map_t *) pb;
+      return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0;
+    }
   };
 
   struct lookup_map_t {
@@ -66,7 +74,9 @@ struct hb_ot_map_t
     unsigned short auto_zwnj : 1;
     unsigned short auto_zwj : 1;
     unsigned short random : 1;
+    unsigned short per_syllable : 1;
     hb_mask_t mask;
+    hb_tag_t feature_tag;
 
     HB_INTERNAL static int cmp (const void *pa, const void *pb)
     {
@@ -76,7 +86,9 @@ struct hb_ot_map_t
     }
   };
 
-  typedef void (*pause_func_t) (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);
+  /* Pause functions return true if new glyph indices might have been
+   * added to the buffer.  This is used to update buffer digest. */
+  typedef bool (*pause_func_t) (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);
 
   struct stage_map_t {
     unsigned int last_lookup; /* Cumulative */
@@ -85,13 +97,13 @@ struct hb_ot_map_t
 
   void init ()
   {
-    memset (this, 0, sizeof (*this));
+    hb_memset (this, 0, sizeof (*this));
 
-    features.init ();
+    features.init0 ();
     for (unsigned int table_index = 0; table_index < 2; table_index++)
     {
-      lookups[table_index].init ();
-      stages[table_index].init ();
+      lookups[table_index].init0 ();
+      stages[table_index].init0 ();
     }
   }
   void fini ()
@@ -137,19 +149,15 @@ struct hb_ot_map_t
     return map ? map->stage[table_index] : UINT_MAX;
   }
 
-  void get_stage_lookups (unsigned int table_index, unsigned int stage,
-                         const struct lookup_map_t **plookups, unsigned int *lookup_count) const
+  hb_array_t<const hb_ot_map_t::lookup_map_t>
+  get_stage_lookups (unsigned int table_index, unsigned int stage) const
   {
     if (unlikely (stage > stages[table_index].length))
-    {
-      *plookups = nullptr;
-      *lookup_count = 0;
-      return;
-    }
+      return hb_array<const hb_ot_map_t::lookup_map_t> (nullptr, 0);
+
     unsigned int start = stage ? stages[table_index][stage - 1].last_lookup : 0;
     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;
+    return lookups[table_index].as_array ().sub_array (start, end - start);
   }
 
   HB_INTERNAL void collect_lookups (unsigned int table_index, hb_set_t *lookups) const;
@@ -165,7 +173,7 @@ struct hb_ot_map_t
 
   private:
 
-  hb_mask_t global_mask;
+  hb_mask_t global_mask = 0;
 
   hb_sorted_vector_t<feature_map_t> features;
   hb_vector_t<lookup_map_t> lookups[2]; /* GSUB/GPOS */
@@ -183,7 +191,8 @@ enum hb_ot_map_feature_flags_t
   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. */
+  F_RANDOM             = 0x0020u, /* Randomly select a glyph from an AlternateSubstFormat1 subtable. */
+  F_PER_SYLLABLE       = 0x0040u  /* Contain lookup application to within syllable. */
 };
 HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t);
 
@@ -201,7 +210,7 @@ struct hb_ot_map_builder_t
   public:
 
   HB_INTERNAL hb_ot_map_builder_t (hb_face_t *face_,
-                                  const hb_segment_properties_t *props_);
+                                  const hb_segment_properties_t &props_);
 
   HB_INTERNAL ~hb_ot_map_builder_t ();
 
@@ -209,6 +218,8 @@ struct hb_ot_map_builder_t
                                hb_ot_map_feature_flags_t flags=F_NONE,
                                unsigned int value=1);
 
+  HB_INTERNAL bool has_feature (hb_tag_t tag);
+
   void add_feature (const hb_ot_map_feature_t &feat)
   { add_feature (feat.tag, feat.flags); }
 
@@ -237,7 +248,9 @@ struct hb_ot_map_builder_t
                                hb_mask_t     mask,
                                bool          auto_zwnj = true,
                                bool          auto_zwj = true,
-                               bool          random = false);
+                               bool          random = false,
+                               bool          per_syllable = false,
+                               hb_tag_t      feature_tag = HB_TAG(' ',' ',' ',' '));
 
   struct feature_info_t {
     hb_tag_t tag;
@@ -267,6 +280,7 @@ struct hb_ot_map_builder_t
 
   hb_face_t *face;
   hb_segment_properties_t props;
+  bool is_simple;
 
   hb_tag_t chosen_script[2];
   bool found_script[2];
index d834d94..b11da46 100644 (file)
@@ -73,15 +73,14 @@ struct MathConstants
   {
     TRACE_SERIALIZE (this);
     auto *out = c->start_embed (this);
-    if (unlikely (!out)) return_trace (nullptr);
 
     HBINT16 *p = c->allocate_size<HBINT16> (HBINT16::static_size * 2);
     if (unlikely (!p)) return_trace (nullptr);
-    memcpy (p, percentScaleDown, HBINT16::static_size * 2);
+    hb_memcpy (p, percentScaleDown, HBINT16::static_size * 2);
 
     HBUINT16 *m = c->allocate_size<HBUINT16> (HBUINT16::static_size * 2);
     if (unlikely (!m)) return_trace (nullptr);
-    memcpy (m, minHeight, HBUINT16::static_size * 2);
+    hb_memcpy (m, minHeight, HBUINT16::static_size * 2);
 
     unsigned count = ARRAY_LENGTH (mathValueRecords);
     for (unsigned i = 0; i < count; i++)
@@ -201,7 +200,7 @@ struct MathItalicsCorrectionInfo
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
+    const hb_set_t &glyphset = c->plan->_glyphset_mathed;
     const hb_map_t &glyph_map = *c->plan->glyph_map;
 
     auto *out = c->serializer->start_embed (*this);
@@ -254,7 +253,7 @@ struct MathTopAccentAttachment
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
+    const hb_set_t &glyphset = c->plan->_glyphset_mathed;
     const hb_map_t &glyph_map = *c->plan->glyph_map;
 
     auto *out = c->serializer->start_embed (*this);
@@ -310,7 +309,6 @@ struct MathKern
   {
     TRACE_SERIALIZE (this);
     auto *out = c->start_embed (this);
-    if (unlikely (!out)) return_trace (nullptr);
 
     if (unlikely (!c->embed (heightCount))) return_trace (nullptr);
 
@@ -486,7 +484,7 @@ struct MathKernInfo
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
+    const hb_set_t &glyphset = c->plan->_glyphset_mathed;
     const hb_map_t &glyph_map = *c->plan->glyph_map;
 
     auto *out = c->serializer->start_embed (*this);
@@ -567,11 +565,12 @@ struct MathGlyphInfo
     out->mathItalicsCorrectionInfo.serialize_subset (c, mathItalicsCorrectionInfo, this);
     out->mathTopAccentAttachment.serialize_subset (c, mathTopAccentAttachment, this);
 
-    const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
+    const hb_set_t &glyphset = c->plan->_glyphset_mathed;
     const hb_map_t &glyph_map = *c->plan->glyph_map;
 
     auto it =
     + hb_iter (this+extendedShapeCoverage)
+    | hb_take (c->plan->source->get_num_glyphs ())
     | hb_filter (glyphset)
     | hb_map_retains_sorting (glyph_map)
     ;
@@ -757,8 +756,6 @@ struct MathGlyphAssembly
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!out)) return_trace (false);
 
     if (!c->serializer->copy (italicsCorrection, this)) return_trace (false);
     if (!c->serializer->copy<HBUINT16> (partRecords.len)) return_trace (false);
@@ -786,7 +783,7 @@ struct MathGlyphAssembly
     if (parts_count)
     {
       int64_t mult = font->dir_mult (direction);
-      for (auto _ : hb_zip (partRecords.sub_array (start_offset, parts_count),
+      for (auto _ : hb_zip (partRecords.as_array ().sub_array (start_offset, parts_count),
                            hb_array (parts, *parts_count)))
        _.first.extract (_.second, mult, font);
     }
@@ -855,7 +852,7 @@ struct MathGlyphConstruction
     if (variants_count)
     {
       int64_t mult = font->dir_mult (direction);
-      for (auto _ : hb_zip (mathGlyphVariantRecord.sub_array (start_offset, variants_count),
+      for (auto _ : hb_zip (mathGlyphVariantRecord.as_array ().sub_array (start_offset, variants_count),
                            hb_array (variants, *variants_count)))
        _.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)};
     }
@@ -938,20 +935,20 @@ struct MathVariants
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
+    const hb_set_t &glyphset = c->plan->_glyphset_mathed;
     const hb_map_t &glyph_map = *c->plan->glyph_map;
 
     auto *out = c->serializer->start_embed (*this);
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
     if (!c->serializer->check_assign (out->minConnectorOverlap, minConnectorOverlap, HB_SERIALIZE_ERROR_INT_OVERFLOW))
       return_trace (false);
-    
+
     hb_sorted_vector_t<hb_codepoint_t> new_vert_coverage;
     hb_sorted_vector_t<hb_codepoint_t> new_hori_coverage;
     hb_set_t indices;
     collect_coverage_and_indices (new_vert_coverage, vertGlyphCoverage, 0, vertGlyphCount, indices, glyphset, glyph_map);
     collect_coverage_and_indices (new_hori_coverage, horizGlyphCoverage, vertGlyphCount, vertGlyphCount + horizGlyphCount, indices, glyphset, glyph_map);
-    
+
     if (!c->serializer->check_assign (out->vertGlyphCount, new_vert_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
       return_trace (false);
     if (!c->serializer->check_assign (out->horizGlyphCount, new_hori_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
@@ -963,10 +960,10 @@ struct MathVariants
       if (!o) return_trace (false);
       o->serialize_subset (c, glyphConstruction[i], this);
     }
-    
+
     if (new_vert_coverage)
       out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ());
-    
+
     if (new_hori_coverage)
     out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ());
     return_trace (true);
index f44ac35..876ad25 100644 (file)
@@ -56,7 +56,7 @@
  *
  * Tests whether a face has a `MATH` table.
  *
- * Return value: %true if the table is found, %false otherwise
+ * Return value: `true` if the table is found, `false` otherwise
  *
  * Since: 1.3.3
  **/
@@ -76,7 +76,7 @@ hb_ot_math_has_data (hb_face_t *face)
  *
  * However, if the requested constant is #HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN,
  * #HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN or
- * #HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN, then the return value is
+ * #HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT, then the return value is
  * an integer between 0 and 100 representing that percentage.
  *
  * Return value: the requested constant or zero
@@ -142,7 +142,7 @@ hb_ot_math_get_glyph_top_accent_attachment (hb_font_t *font,
  *
  * Tests whether the given glyph index is an extended shape in the face.
  *
- * Return value: %true if the glyph is an extended shape, %false otherwise
+ * Return value: `true` if the glyph is an extended shape, `false` otherwise
  *
  * Since: 1.3.3
  **/
index 3a019ef..0f4cc41 100644 (file)
@@ -100,7 +100,7 @@ struct maxp
     maxp *maxp_prime = c->serializer->embed (this);
     if (unlikely (!maxp_prime)) return_trace (false);
 
-    maxp_prime->numGlyphs = c->plan->num_output_glyphs ();
+    maxp_prime->numGlyphs = hb_min (c->plan->num_output_glyphs (), 0xFFFFu);
     if (maxp_prime->version.major == 1)
     {
       const maxpV1Tail *src_v1 = &StructAfter<maxpV1Tail> (*this);
@@ -109,11 +109,24 @@ struct maxp
 
       if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
        drop_hint_fields (dest_v1);
+
+      if (c->plan->normalized_coords)
+        instancing_update_fields (c->plan->head_maxp_info, dest_v1);
     }
 
     return_trace (true);
   }
 
+  void instancing_update_fields (head_maxp_info_t& maxp_info, maxpV1Tail* dest_v1) const
+  {
+    dest_v1->maxPoints = maxp_info.maxPoints;
+    dest_v1->maxContours = maxp_info.maxContours;
+    dest_v1->maxCompositePoints = maxp_info.maxCompositePoints;
+    dest_v1->maxCompositeContours = maxp_info.maxCompositeContours;
+    dest_v1->maxComponentElements = maxp_info.maxComponentElements;
+    dest_v1->maxComponentDepth = maxp_info.maxComponentDepth;
+  }
+
   static void drop_hint_fields (maxpV1Tail* dest_v1)
   {
     dest_v1->maxZones = 1;
index 93e64c5..e1b68bc 100644 (file)
@@ -84,7 +84,7 @@ struct meta
     {
       if (count)
       {
-       + table->dataMaps.sub_array (start_offset, count)
+       + table->dataMaps.as_array ().sub_array (start_offset, count)
        | hb_map (&DataMap::get_tag)
        | hb_map ([](hb_tag_t tag) { return (hb_ot_meta_tag_t) tag; })
        | hb_sink (hb_array (entries, *count))
index 103808c..e314d94 100644 (file)
@@ -71,12 +71,12 @@ _hb_ot_metrics_get_position_common (hb_font_t           *font,
 #endif
 #define GET_METRIC_X(TABLE, ATTR) \
   (face->table.TABLE->has_data () && \
-    (position && (*position = font->em_scalef_x (_fix_ascender_descender ( \
-      face->table.TABLE->ATTR + GET_VAR, metrics_tag))), true))
+    ((void) (position && (*position = font->em_scalef_x (_fix_ascender_descender ( \
+      face->table.TABLE->ATTR + GET_VAR, metrics_tag)))), true))
 #define GET_METRIC_Y(TABLE, ATTR) \
   (face->table.TABLE->has_data () && \
-    (position && (*position = font->em_scalef_y (_fix_ascender_descender ( \
-      face->table.TABLE->ATTR + GET_VAR, metrics_tag))), true))
+    ((void) (position && (*position = font->em_scalef_y (_fix_ascender_descender ( \
+      face->table.TABLE->ATTR + GET_VAR, metrics_tag)))), true))
 
   case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER:
     return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoAscender)) ||
@@ -154,10 +154,10 @@ hb_ot_metrics_get_position (hb_font_t           *font,
 #endif
 #define GET_METRIC_X(TABLE, ATTR) \
   (face->table.TABLE->has_data () && \
-    (position && (*position = font->em_scalef_x (face->table.TABLE->ATTR + GET_VAR)), true))
+    ((void) (position && (*position = font->em_scalef_x (face->table.TABLE->ATTR + GET_VAR))), true))
 #define GET_METRIC_Y(TABLE, ATTR) \
   (face->table.TABLE->has_data () && \
-    (position && (*position = font->em_scalef_y (face->table.TABLE->ATTR + GET_VAR)), true))
+    ((void) (position && (*position = font->em_scalef_y (face->table.TABLE->ATTR + GET_VAR))), true))
   case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT:  return GET_METRIC_Y (OS2, usWinAscent);
   case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT: return GET_METRIC_Y (OS2, usWinDescent);
 
@@ -196,7 +196,7 @@ hb_ot_metrics_get_position (hb_font_t           *font,
        *position *= mult;
 
        if (font->slant)
-         *position += _hb_roundf (mult * font->slant_xy * rise);
+         *position += roundf (mult * font->slant_xy * rise);
       }
 
       return ret;
@@ -238,6 +238,145 @@ hb_ot_metrics_get_position (hb_font_t           *font,
   }
 }
 
+/**
+ * hb_ot_metrics_get_position_with_fallback:
+ * @font: an #hb_font_t object.
+ * @metrics_tag: tag of metrics value you like to fetch.
+ * @position: (out) (optional): result of metrics value from the font.
+ *
+ * Fetches metrics value corresponding to @metrics_tag from @font,
+ * and synthesizes a value if it the value is missing in the font.
+ *
+ * Since: 4.0.0
+ **/
+void
+hb_ot_metrics_get_position_with_fallback (hb_font_t           *font,
+                                         hb_ot_metrics_tag_t  metrics_tag,
+                                         hb_position_t       *position     /* OUT */)
+{
+  hb_font_extents_t font_extents;
+  hb_codepoint_t glyph;
+  hb_glyph_extents_t extents;
+
+  if (hb_ot_metrics_get_position (font, metrics_tag, position))
+    {
+      if ((metrics_tag != HB_OT_METRICS_TAG_STRIKEOUT_SIZE &&
+           metrics_tag != HB_OT_METRICS_TAG_UNDERLINE_SIZE) ||
+          *position != 0)
+        return;
+    }
+
+  switch (metrics_tag)
+  {
+  case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER:
+  case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT:
+    hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
+    *position = font_extents.ascender;
+    break;
+
+  case HB_OT_METRICS_TAG_VERTICAL_ASCENDER:
+    hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents);
+    *position = font_extents.ascender;
+    break;
+
+  case HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER:
+  case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT:
+    hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
+    *position = font_extents.descender;
+    break;
+
+  case HB_OT_METRICS_TAG_VERTICAL_DESCENDER:
+    hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents);
+    *position = font_extents.ascender;
+    break;
+
+  case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP:
+    hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
+    *position = font_extents.line_gap;
+    break;
+
+  case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP:
+    hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents);
+    *position = font_extents.line_gap;
+    break;
+
+  case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE:
+  case HB_OT_METRICS_TAG_VERTICAL_CARET_RISE:
+    *position = 1;
+    break;
+
+  case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN:
+  case HB_OT_METRICS_TAG_VERTICAL_CARET_RUN:
+    *position = 0;
+    break;
+
+  case HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET:
+  case HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET:
+    *position = 0;
+    break;
+
+  case HB_OT_METRICS_TAG_X_HEIGHT:
+    if (hb_font_get_nominal_glyph (font, 'x', &glyph) &&
+        hb_font_get_glyph_extents (font, glyph, &extents))
+      *position = extents.y_bearing;
+    else
+      *position = font->y_scale / 2;
+    break;
+
+  case HB_OT_METRICS_TAG_CAP_HEIGHT:
+    if (hb_font_get_nominal_glyph (font, 'O', &glyph) &&
+        hb_font_get_glyph_extents (font, glyph, &extents))
+      *position = extents.height + 2 * extents.y_bearing;
+    else
+      *position = font->y_scale * 2 / 3;
+    break;
+
+  case HB_OT_METRICS_TAG_STRIKEOUT_SIZE:
+  case HB_OT_METRICS_TAG_UNDERLINE_SIZE:
+    *position = font->y_scale / 18;
+    break;
+
+  case HB_OT_METRICS_TAG_STRIKEOUT_OFFSET:
+    {
+      hb_position_t ascender;
+      hb_ot_metrics_get_position_with_fallback (font,
+                                                HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER,
+                                                &ascender);
+      *position = ascender / 2;
+    }
+    break;
+
+  case HB_OT_METRICS_TAG_UNDERLINE_OFFSET:
+    *position = - font->y_scale / 18;
+    break;
+
+  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE:
+  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE:
+    *position = font->x_scale * 10 / 12;
+    break;
+
+  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE:
+  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE:
+    *position = font->y_scale * 10 / 12;
+    break;
+
+  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET:
+  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET:
+    *position = 0;
+    break;
+
+  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET:
+  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET:
+    *position = font->y_scale / 5;
+    break;
+
+  case _HB_OT_METRICS_TAG_MAX_VALUE:
+  default:
+    *position = 0;
+    break;
+  }
+}
+
 #ifndef HB_NO_VAR
 /**
  * hb_ot_metrics_get_variation:
index 5841fc8..30de500 100644 (file)
@@ -110,6 +110,11 @@ hb_ot_metrics_get_position (hb_font_t           *font,
                            hb_ot_metrics_tag_t  metrics_tag,
                            hb_position_t       *position     /* OUT.  May be NULL. */);
 
+HB_EXTERN void
+hb_ot_metrics_get_position_with_fallback (hb_font_t           *font,
+                                         hb_ot_metrics_tag_t  metrics_tag,
+                                         hb_position_t       *position     /* OUT */);
+
 HB_EXTERN float
 hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag);
 
index c496dc2..0e0f2d6 100644 (file)
@@ -45,7 +45,7 @@ struct hb_ot_language_map_t
 };
 
 static const hb_ot_language_map_t
-hb_ms_language_map[] =
+_hb_ms_language_map[] =
 {
   {0x0001,     "ar"},  /* ??? */
   {0x0004,     "zh"},  /* ??? */
@@ -298,7 +298,7 @@ hb_ms_language_map[] =
 };
 
 static const hb_ot_language_map_t
-hb_mac_language_map[] =
+_hb_mac_language_map[] =
 {
   {  0,        "en"},  /* English */
   {  1,        "fr"},  /* French */
@@ -441,16 +441,16 @@ 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_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));
+                                  _hb_mac_language_map,
+                                  ARRAY_LENGTH (_hb_mac_language_map));
 }
 
 #endif /* HB_OT_NAME_LANGUAGE_STATIC_HH */
index d52367e..8565322 100644 (file)
 #ifndef HB_OT_NAME_TABLE_HH
 #define HB_OT_NAME_TABLE_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
-{
-  hb_language_t language (hb_face_t *face) const
-  {
-#ifndef HB_NO_OT_NAME_LANGUAGE
-    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);
-
-#ifndef HB_NO_OT_NAME_LANGUAGE_AAT
-    if (p == 0)
-      return face->table.ltag->get_language (l);
-#endif
-
-#endif
-    return HB_LANGUAGE_INVALID;
-  }
-
-  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;
-  }
-
-  NameRecord* copy (hb_serialize_context_t *c, const void *base) const
-  {
-    TRACE_SERIALIZE (this);
-    auto *out = c->embed (this);
-    if (unlikely (!out)) return_trace (nullptr);
-    out->offset.serialize_copy (c, offset, base, 0, hb_serialize_context_t::Tail, length);
-    return_trace (out);
-  }
-
-  bool isUnicode () const
-  {
-    unsigned int p = platformID;
-    unsigned int e = encodingID;
-
-    return (p == 0 ||
-           (p == 3 && (e == 0 || e == 1 || e == 10)));
-  }
-
-  static int cmp (const void *pa, const void *pb)
-  {
-    const NameRecord *a = (const NameRecord *)pa;
-    const NameRecord *b = (const NameRecord *)pb;
-
-    if (a->platformID != b->platformID)
-      return a->platformID - b->platformID;
-
-    if (a->encodingID != b->encodingID)
-      return a->encodingID - b->encodingID;
-
-    if (a->languageID != b->languageID)
-      return a->languageID - b->languageID;
-
-    if (a->nameID != b->nameID)
-      return a->nameID - b->nameID;
-
-    if (a->length != b->length)
-      return a->length - b->length;
-
-    return 0;
-  }
-
-  bool sanitize (hb_sanitize_context_t *c, const void *base) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && offset.sanitize (c, base, length));
-  }
-
-  HBUINT16     platformID;     /* Platform ID. */
-  HBUINT16     encodingID;     /* Platform-specific encoding ID. */
-  HBUINT16     languageID;     /* Language ID. */
-  HBUINT16     nameID;         /* Name ID. */
-  HBUINT16     length;         /* String length (in bytes). */
-  NNOffset16To<UnsizedArrayOf<HBUINT8>>
-               offset;         /* String offset from start of storage area (in bytes). */
-  public:
-  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;
-
-  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;
-
-  if (a->entry_index != b->entry_index)
-    return a->entry_index - b->entry_index;
-
-  return 0;
-}
-
-struct name
-{
-  static constexpr hb_tag_t tableTag = HB_OT_TAG_name;
-
-  unsigned int get_size () const
-  { return min_size + count * nameRecordZ.item_size; }
-
-  template <typename Iterator,
-           hb_requires (hb_is_source_of (Iterator, const NameRecord &))>
-  bool serialize (hb_serialize_context_t *c,
-                 Iterator it,
-                 const void *src_string_pool)
-  {
-    TRACE_SERIALIZE (this);
-
-    if (unlikely (!c->extend_min ((*this))))  return_trace (false);
-
-    this->format = 0;
-    this->count = it.len ();
-
-    NameRecord *name_records = (NameRecord *) hb_calloc (it.len (), NameRecord::static_size);
-    if (unlikely (!name_records)) return_trace (false);
-
-    hb_array_t<NameRecord> records (name_records, it.len ());
-
-    for (const NameRecord& record : it)
-    {
-      memcpy (name_records, &record, NameRecord::static_size);
-      name_records++;
-    }
-
-    records.qsort ();
-
-    c->copy_all (records, src_string_pool);
-    hb_free (records.arrayZ);
-
-
-    if (unlikely (c->ran_out_of_room ())) return_trace (false);
-
-    this->stringOffset = c->length ();
-
-    return_trace (true);
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-
-    name *name_prime = c->serializer->start_embed<name> ();
-    if (unlikely (!name_prime)) return_trace (false);
-
-    auto it =
-    + nameRecordZ.as_array (count)
-    | hb_filter (c->plan->name_ids, &NameRecord::nameID)
-    | hb_filter (c->plan->name_languages, &NameRecord::languageID)
-    | hb_filter ([&] (const NameRecord& namerecord) {
-      return
-          (c->plan->flags & HB_SUBSET_FLAGS_NAME_LEGACY)
-          || namerecord.isUnicode ();
-    })
-    ;
-
-    name_prime->serialize (c->serializer, it, std::addressof (this + stringOffset));
-    return_trace (name_prime->count);
-  }
-
-  bool sanitize_records (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    const void *string_pool = (this+stringOffset).arrayZ;
-    return_trace (nameRecordZ.sanitize (c, count, string_pool));
-  }
-
-  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 (nameRecordZ.arrayZ, count) &&
-                 c->check_range (this, stringOffset) &&
-                 sanitize_records (c));
-  }
-
-  struct accelerator_t
-  {
-    accelerator_t (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.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);
-    }
-    ~accelerator_t ()
-    {
-      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 = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names,
-                                                   this->names.length,
-                                                   sizeof (hb_ot_name_entry_t),
-                                                   _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. */
-  NNOffset16To<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, nameRecordZ);
-};
-
-#undef entry_index
-#undef entry_score
-
-struct name_accelerator_t : name::accelerator_t {
-  name_accelerator_t (hb_face_t *face) : name::accelerator_t (face) {}
-};
-
-} /* namespace OT */
-
+#include "OT/name/name.hh"
 
 #endif /* HB_OT_NAME_TABLE_HH */
index c35ac5b..6adf1e8 100644 (file)
@@ -64,52 +64,6 @@ hb_ot_name_list_names (hb_face_t    *face,
   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,
@@ -130,10 +84,10 @@ hb_ot_name_get_utf (hb_face_t       *face,
     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);
+      return OT::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);
+      return OT::hb_ot_name_convert_utf<hb_ascii_t, utf_t> (bytes, text_size, text);
   }
 
   if (text_size)
@@ -227,5 +181,4 @@ hb_ot_name_get_utf32 (hb_face_t       *face,
   return hb_ot_name_get_utf<hb_utf32_t> (face, name_id, language, text_size, text);
 }
 
-
 #endif
index 1ea4b55..03e664b 100644 (file)
@@ -33,9 +33,8 @@
 
 HB_BEGIN_DECLS
 
-
 /**
- * hb_ot_name_id_t:
+ * hb_ot_name_id_predefined_t:
  * @HB_OT_NAME_ID_COPYRIGHT: Copyright notice
  * @HB_OT_NAME_ID_FONT_FAMILY: Font Family name
  * @HB_OT_NAME_ID_FONT_SUBFAMILY: Font Subfamily name
@@ -65,16 +64,14 @@ HB_BEGIN_DECLS
  * @HB_OT_NAME_ID_VARIATIONS_PS_PREFIX: Variations PostScript Name Prefix
  * @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.
+ * An enum type representing the pre-defined name IDs.
  *
  * For more information on these fields, see the
  * [OpenType spec](https://docs.microsoft.com/en-us/typography/opentype/spec/name#name-ids).
  *
- * Since: 2.0.0
+ * Since: 7.0.0
  **/
-enum
+typedef enum
 {
   HB_OT_NAME_ID_COPYRIGHT              = 0,
   HB_OT_NAME_ID_FONT_FAMILY            = 1,
@@ -104,8 +101,17 @@ enum
   HB_OT_NAME_ID_VARIATIONS_PS_PREFIX   = 25,
 
   HB_OT_NAME_ID_INVALID                        = 0xFFFF
-};
+} hb_ot_name_id_predefined_t;
 
+/**
+ * hb_ot_name_id_t:
+ *
+ * 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
+ **/
 typedef unsigned int hb_ot_name_id_t;
 
 
index f0035e2..19330b9 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "hb-open-type.hh"
 #include "hb-ot-os2-unicode-ranges.hh"
+#include "hb-ot-var-mvar-table.hh"
 
 #include "hb-set.hh"
 
@@ -62,6 +63,7 @@ struct OS2V2Tail
   bool has_data () const { return sxHeight || sCapHeight; }
 
   const OS2V2Tail * operator -> () const { return this; }
+  OS2V2Tail * operator -> () { return this; }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -166,22 +168,106 @@ struct OS2
     }
   }
 
+  float map_wdth_to_widthclass(float width) const
+  {
+    if (width < 50) return 1.0f;
+    if (width > 200) return 9.0f;
+
+    float ratio = (width - 50) / 12.5f;
+    int a = (int) floorf (ratio);
+    int b = (int) ceilf (ratio);
+
+    /* follow this maping:
+     * https://docs.microsoft.com/en-us/typography/opentype/spec/os2#uswidthclass
+     */
+    if (b <= 6) // 50-125
+    {
+      if (a == b) return a + 1.0f;
+    }
+    else if (b == 7) // no mapping for 137.5
+    {
+      a = 6;
+      b = 8;
+    }
+    else if (b == 8)
+    {
+      if (a == b) return 8.0f; // 150
+      a = 6;
+    }
+    else
+    {
+      if (a == b && a == 12) return 9.0f; //200
+      b = 12;
+      a = 8;
+    }
+
+    float va = 50 + a * 12.5f;
+    float vb = 50 + b * 12.5f;
+
+    float ret =  a + (width - va) / (vb - va);
+    if (a <= 6) ret += 1.0f;
+    return ret;
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
     OS2 *os2_prime = c->serializer->embed (this);
     if (unlikely (!os2_prime)) return_trace (false);
+
+#ifndef HB_NO_VAR
+    if (c->plan->normalized_coords)
+    {
+      auto &MVAR = *c->plan->source->table.MVAR;
+      auto *table = os2_prime;
+
+      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER,         sTypoAscender);
+      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER,        sTypoDescender);
+      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP,         sTypoLineGap);
+      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT,  usWinAscent);
+      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT, usWinDescent);
+      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE,         ySubscriptXSize);
+      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE,         ySubscriptYSize);
+      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET,       ySubscriptXOffset);
+      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET,       ySubscriptYOffset);
+      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE,       ySuperscriptXSize);
+      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE,       ySuperscriptYSize);
+      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET,     ySuperscriptXOffset);
+      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET,     ySuperscriptYOffset);
+      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_STRIKEOUT_SIZE,              yStrikeoutSize);
+      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_STRIKEOUT_OFFSET,            yStrikeoutPosition);
+
+      if (os2_prime->version >= 2)
+      {
+        auto *table = & const_cast<OS2V2Tail &> (os2_prime->v2 ());
+        HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_X_HEIGHT,                   sxHeight);
+        HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_CAP_HEIGHT,                 sCapHeight);
+      }
+    }
+#endif
+
+    Triple *axis_range;
+    if (c->plan->user_axes_location.has (HB_TAG ('w','g','h','t'), &axis_range))
+    {
+      unsigned weight_class = static_cast<unsigned> (roundf (hb_clamp (axis_range->middle, 1.0f, 1000.0f)));
+      if (os2_prime->usWeightClass != weight_class)
+        os2_prime->usWeightClass = weight_class;
+    }
+
+    if (c->plan->user_axes_location.has (HB_TAG ('w','d','t','h'), &axis_range))
+    {
+      unsigned width_class = static_cast<unsigned> (roundf (map_wdth_to_widthclass (axis_range->middle)));
+      if (os2_prime->usWidthClass != width_class)
+        os2_prime->usWidthClass = width_class;
+    }
+
     if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
       return_trace (true);
 
-    /* when --gids option is not used, no need to do collect_mapping that is
-       * iterating all codepoints in each subtable, which is not efficient */
-    uint16_t min_cp, max_cp;
-    find_min_and_max_codepoint (c->plan->unicodes, &min_cp, &max_cp);
-    os2_prime->usFirstCharIndex = min_cp;
-    os2_prime->usLastCharIndex = max_cp;
+    os2_prime->usFirstCharIndex = hb_min (0xFFFFu, c->plan->unicodes.get_min ());
+    os2_prime->usLastCharIndex  = hb_min (0xFFFFu, c->plan->unicodes.get_max ());
 
-    _update_unicode_ranges (c->plan->unicodes, os2_prime->ulUnicodeRange);
+    _update_unicode_ranges (&c->plan->unicodes, os2_prime->ulUnicodeRange);
 
     return_trace (true);
   }
@@ -189,12 +275,15 @@ struct OS2
   void _update_unicode_ranges (const hb_set_t *codepoints,
                               HBUINT32 ulUnicodeRange[4]) const
   {
-    HBUINT32   newBits[4];
+    HBUINT32 newBits[4];
     for (unsigned int i = 0; i < 4; i++)
       newBits[i] = 0;
 
-    hb_codepoint_t cp = HB_SET_VALUE_INVALID;
-    while (codepoints->next (&cp)) {
+    /* This block doesn't show up in profiles. If it ever did,
+     * we can rewrite it to iterate over OS/2 ranges and use
+     * set iteration to check if the range matches. */
+    for (auto cp : *codepoints)
+    {
       unsigned int bit = _hb_ot_os2_get_unicode_range_bit (cp);
       if (bit < 128)
       {
@@ -216,17 +305,11 @@ struct OS2
       ulUnicodeRange[i] = ulUnicodeRange[i] & newBits[i]; // set bits only if set in the original
   }
 
-  static void find_min_and_max_codepoint (const hb_set_t *codepoints,
-                                         uint16_t *min_cp, /* OUT */
-                                         uint16_t *max_cp  /* OUT */)
-  {
-    *min_cp = hb_min (0xFFFFu, codepoints->get_min ());
-    *max_cp = hb_min (0xFFFFu, codepoints->get_max ());
-  }
-
-  /* https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681 */
+  /* https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681
+   * https://docs.microsoft.com/en-us/typography/legacy/legacy_arabic_fonts */
   enum font_page_t
   {
+    FONT_PAGE_NONE             = 0,
     FONT_PAGE_HEBREW           = 0xB100, /* Hebrew Windows 3.1 font page */
     FONT_PAGE_SIMP_ARABIC      = 0xB200, /* Simplified Arabic Windows 3.1 font page */
     FONT_PAGE_TRAD_ARABIC      = 0xB300, /* Traditional Arabic Windows 3.1 font page */
index 9613d2d..01e6a46 100644 (file)
@@ -34,10 +34,10 @@ namespace OT {
 struct OS2Range
 {
   int cmp (hb_codepoint_t key) const
-  { return (key < start) ? -1 : key <= end ? 0 : +1; }
+  { return (key < first) ? -1 : key <= last ? 0 : +1; }
 
-  hb_codepoint_t start;
-  hb_codepoint_t end;
+  hb_codepoint_t first;
+  hb_codepoint_t last;
   unsigned int bit;
 };
 
@@ -223,7 +223,7 @@ static unsigned int
 _hb_ot_os2_get_unicode_range_bit (hb_codepoint_t cp)
 {
   auto *range = hb_sorted_array (_hb_os2_unicode_ranges).bsearch (cp);
-  return range ? range->bit : -1;
+  return range ? range->bit : (unsigned) -1;
 }
 
 } /* namespace OT */
index 0f3cd8e..d442336 100644 (file)
@@ -52,16 +52,16 @@ HB_INTERNAL bool postV2Tail::serialize (hb_serialize_context_t *c,
   {
     unsigned glyph_id = _.first;
     unsigned new_index = _.second;
-    
+
     if (new_index < 258) continue;
     if (copied_indices.has (new_index)) continue;
     copied_indices.add (new_index);
-    
+
     hb_bytes_t s = reinterpret_cast<const post::accelerator_t*> (_post)->find_glyph_name (glyph_id);
     HBUINT8 *o = c->allocate_size<HBUINT8> (HBUINT8::static_size * (s.length + 1));
     if (unlikely (!o)) return_trace (false);
     if (!c->check_assign (o[0], s.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
-    memcpy (o+1, s.arrayZ, HBUINT8::static_size * s.length);
+    hb_memcpy (o+1, s.arrayZ, HBUINT8::static_size * s.length);
   }
 
   return_trace (true);
@@ -78,15 +78,23 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const
 
   post::accelerator_t _post (c->plan->source);
 
-  hb_hashmap_t<hb_bytes_t, unsigned, std::nullptr_t, unsigned, nullptr, (unsigned)-1> glyph_name_to_new_index;
+  hb_hashmap_t<hb_bytes_t, uint32_t, true> glyph_name_to_new_index;
+
+  old_new_index_map.alloc (num_glyphs);
+  old_gid_new_index_map.alloc (num_glyphs);
+  glyph_name_to_new_index.alloc (num_glyphs);
+
   for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++)
   {
     hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
     unsigned old_index = glyphNameIndex[old_gid];
 
     unsigned new_index;
-    if (old_index <= 257) new_index = old_index;
-    else if (old_new_index_map.has (old_index)) new_index = old_new_index_map.get (old_index);
+    const uint32_t *new_index2;
+    if (old_index <= 257)
+      new_index = old_index;
+    else if (old_new_index_map.has (old_index, &new_index2))
+      new_index = *new_index2;
     else
     {
       hb_bytes_t s = _post.find_glyph_name (old_gid);
index a4844e9..aaecc34 100644 (file)
@@ -28,6 +28,7 @@
 #define HB_OT_POST_TABLE_HH
 
 #include "hb-open-type.hh"
+#include "hb-ot-var-mvar-table.hh"
 
 #define HB_STRING_ARRAY_NAME format1_names
 #define HB_STRING_ARRAY_LIST "hb-ot-post-macroman.hh"
@@ -84,7 +85,7 @@ struct post
     post *post_prime = c->allocate_min<post> ();
     if (unlikely (!post_prime))  return_trace (false);
 
-    memcpy (post_prime, this, post::min_size);
+    hb_memcpy (post_prime, this, post::min_size);
     if (!glyph_names)
       return_trace (c->check_assign (post_prime->version.major, 3,
                                      HB_SERIALIZE_ERROR_INT_OVERFLOW)); // Version 3 does not have any glyph names.
@@ -95,13 +96,31 @@ struct post
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    post *post_prime = c->serializer->start_embed<post> ();
-    if (unlikely (!post_prime)) return_trace (false);
+    auto *post_prime = c->serializer->start_embed<post> ();
 
     bool glyph_names = c->plan->flags & HB_SUBSET_FLAGS_GLYPH_NAMES;
     if (!serialize (c->serializer, glyph_names))
       return_trace (false);
 
+#ifndef HB_NO_VAR
+    if (c->plan->normalized_coords)
+    {
+      auto &MVAR = *c->plan->source->table.MVAR;
+      auto *table = post_prime;
+
+      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_UNDERLINE_SIZE,   underlineThickness);
+      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_UNDERLINE_OFFSET, underlinePosition);
+    }
+#endif
+
+    Triple *axis_range;
+    if (c->plan->user_axes_location.has (HB_TAG ('s','l','n','t'), &axis_range))
+    {
+      float italic_angle = hb_max (-90.f, hb_min (axis_range->middle, 90.f));
+      if (post_prime->italicAngle.to_float () != italic_angle)
+        post_prime->italicAngle.set_float (italic_angle);
+    }
+
     if (glyph_names && version.major == 2)
       return_trace (v2X.subset (c));
 
@@ -126,6 +145,7 @@ struct post
       pool = &StructAfter<uint8_t> (v2.glyphNameIndex);
 
       const uint8_t *end = (const uint8_t *) (const void *) table + table_length;
+      index_to_offset.alloc (hb_min (face->get_num_glyphs (), table_length / 8));
       for (const uint8_t *data = pool;
           index_to_offset.length < 65535 && data < end && data + *data < end;
           data += 1 + *data)
@@ -133,7 +153,7 @@ struct post
     }
     ~accelerator_t ()
     {
-      hb_free (gids_sorted_by_name.get ());
+      hb_free (gids_sorted_by_name.get_acquire ());
       table.destroy ();
     }
 
@@ -160,7 +180,7 @@ struct post
       if (unlikely (!len)) return false;
 
     retry:
-      uint16_t *gids = gids_sorted_by_name.get ();
+      uint16_t *gids = gids_sorted_by_name.get_acquire ();
 
       if (unlikely (!gids))
       {
@@ -263,10 +283,10 @@ struct post
   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)));
+    return_trace (c->check_struct (this) &&
+                 (version.to_int () == 0x00010000 ||
+                  (version.to_int () == 0x00020000 && v2X.sanitize (c)) ||
+                  version.to_int () == 0x00030000));
   }
 
   public:
@@ -274,7 +294,7 @@ struct post
                                         * 0x00020000 for version 2.0
                                         * 0x00025000 for version 2.5 (deprecated)
                                         * 0x00030000 for version 3.0 */
-  HBFixed      italicAngle;            /* Italic angle in counter-clockwise degrees
+  F16DOT16     italicAngle;            /* Italic angle in counter-clockwise degrees
                                         * from the vertical. Zero for upright text,
                                         * negative for text that leans to the right
                                         * (forward). */
diff --git a/src/hb-ot-shape-complex-indic-machine.hh b/src/hb-ot-shape-complex-indic-machine.hh
deleted file mode 100644 (file)
index 74bf3ca..0000000
+++ /dev/null
@@ -1,603 +0,0 @@
-
-#line 1 "hb-ot-shape-complex-indic-machine.rl"
-/*
- * Copyright © 2011,2012  Google, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
-
-#include "hb.hh"
-
-enum indic_syllable_type_t {
-  indic_consonant_syllable,
-  indic_vowel_syllable,
-  indic_standalone_cluster,
-  indic_symbol_cluster,
-  indic_broken_cluster,
-  indic_non_indic_cluster,
-};
-
-
-#line 45 "hb-ot-shape-complex-indic-machine.hh"
-#define indic_syllable_machine_ex_A 10u
-#define indic_syllable_machine_ex_C 1u
-#define indic_syllable_machine_ex_CM 17u
-#define indic_syllable_machine_ex_CS 19u
-#define indic_syllable_machine_ex_DOTTEDCIRCLE 12u
-#define indic_syllable_machine_ex_H 4u
-#define indic_syllable_machine_ex_M 7u
-#define indic_syllable_machine_ex_N 3u
-#define indic_syllable_machine_ex_PLACEHOLDER 11u
-#define indic_syllable_machine_ex_RS 13u
-#define indic_syllable_machine_ex_Ra 16u
-#define indic_syllable_machine_ex_Repha 15u
-#define indic_syllable_machine_ex_SM 8u
-#define indic_syllable_machine_ex_Symbol 18u
-#define indic_syllable_machine_ex_V 2u
-#define indic_syllable_machine_ex_ZWJ 6u
-#define indic_syllable_machine_ex_ZWNJ 5u
-
-
-#line 65 "hb-ot-shape-complex-indic-machine.hh"
-static const unsigned char _indic_syllable_machine_trans_keys[] = {
-       8u, 8u, 4u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 
-       4u, 13u, 4u, 8u, 8u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 6u, 6u, 16u, 16u, 
-       4u, 8u, 4u, 13u, 4u, 13u, 4u, 13u, 8u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 
-       6u, 6u, 16u, 16u, 4u, 8u, 4u, 8u, 4u, 13u, 8u, 8u, 5u, 7u, 5u, 8u, 
-       4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 4u, 8u, 5u, 8u, 8u, 8u, 1u, 19u, 
-       3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 5u, 10u, 5u, 10u, 10u, 10u, 5u, 10u, 
-       1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 4u, 10u, 5u, 10u, 4u, 10u, 5u, 10u, 
-       3u, 10u, 5u, 10u, 3u, 17u, 3u, 17u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 
-       3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 
-       1u, 16u, 3u, 10u, 4u, 10u, 5u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, 3u, 10u, 
-       5u, 10u, 3u, 17u, 3u, 17u, 4u, 8u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 
-       3u, 17u, 1u, 16u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 1u, 16u, 3u, 10u, 
-       4u, 10u, 5u, 10u, 3u, 17u, 4u, 10u, 5u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 
-       3u, 17u, 4u, 13u, 4u, 8u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 
-       1u, 16u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 1u, 16u, 3u, 10u, 4u, 10u, 
-       5u, 10u, 3u, 17u, 4u, 10u, 5u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 1u, 17u, 
-       3u, 17u, 1u, 17u, 4u, 13u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 3u, 10u, 
-       5u, 10u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 0
-};
-
-static const char _indic_syllable_machine_key_spans[] = {
-       1, 5, 3, 4, 5, 1, 1, 5, 
-       10, 5, 1, 3, 4, 5, 1, 1, 
-       5, 10, 10, 10, 1, 3, 4, 5, 
-       1, 1, 5, 5, 10, 1, 3, 4, 
-       5, 1, 1, 5, 5, 4, 1, 19, 
-       15, 15, 14, 16, 6, 6, 1, 6, 
-       16, 16, 16, 8, 7, 6, 7, 6, 
-       8, 6, 15, 15, 15, 15, 14, 16, 
-       15, 15, 14, 16, 6, 1, 6, 16, 
-       16, 8, 7, 6, 7, 6, 6, 8, 
-       6, 15, 15, 5, 15, 15, 14, 16, 
-       15, 16, 6, 1, 6, 16, 16, 8, 
-       7, 6, 15, 7, 6, 6, 8, 6, 
-       15, 10, 5, 15, 15, 14, 16, 15, 
-       16, 6, 1, 6, 16, 16, 8, 7, 
-       6, 15, 7, 6, 6, 8, 6, 17, 
-       15, 17, 10, 6, 1, 6, 16, 8, 
-       6, 6, 1, 6, 16
-};
-
-static const short _indic_syllable_machine_index_offsets[] = {
-       0, 2, 8, 12, 17, 23, 25, 27, 
-       33, 44, 50, 52, 56, 61, 67, 69, 
-       71, 77, 88, 99, 110, 112, 116, 121, 
-       127, 129, 131, 137, 143, 154, 156, 160, 
-       165, 171, 173, 175, 181, 187, 192, 194, 
-       214, 230, 246, 261, 278, 285, 292, 294, 
-       301, 318, 335, 352, 361, 369, 376, 384, 
-       391, 400, 407, 423, 439, 455, 471, 486, 
-       503, 519, 535, 550, 567, 574, 576, 583, 
-       600, 617, 626, 634, 641, 649, 656, 663, 
-       672, 679, 695, 711, 717, 733, 749, 764, 
-       781, 797, 814, 821, 823, 830, 847, 864, 
-       873, 881, 888, 904, 912, 919, 926, 935, 
-       942, 958, 969, 975, 991, 1007, 1022, 1039, 
-       1055, 1072, 1079, 1081, 1088, 1105, 1122, 1131, 
-       1139, 1146, 1162, 1170, 1177, 1184, 1193, 1200, 
-       1218, 1234, 1252, 1263, 1270, 1272, 1279, 1296, 
-       1305, 1312, 1319, 1321, 1328
-};
-
-static const unsigned char _indic_syllable_machine_indicies[] = {
-       1, 0, 2, 3, 3, 4, 1, 0, 
-       3, 3, 4, 0, 3, 3, 4, 1, 
-       0, 5, 3, 3, 4, 1, 0, 6, 
-       0, 7, 0, 8, 3, 3, 4, 1, 
-       0, 2, 3, 3, 4, 1, 0, 0, 
-       0, 0, 9, 0, 11, 12, 12, 13, 
-       14, 10, 14, 10, 12, 12, 13, 10, 
-       12, 12, 13, 14, 10, 15, 12, 12, 
-       13, 14, 10, 16, 10, 17, 10, 18, 
-       12, 12, 13, 14, 10, 11, 12, 12, 
-       13, 14, 10, 10, 10, 10, 19, 10, 
-       11, 12, 12, 13, 14, 10, 10, 10, 
-       10, 20, 10, 22, 23, 23, 24, 25, 
-       21, 21, 21, 21, 26, 21, 25, 21, 
-       23, 23, 24, 27, 23, 23, 24, 25, 
-       21, 28, 23, 23, 24, 25, 21, 29, 
-       21, 30, 21, 22, 23, 23, 24, 25, 
-       21, 31, 23, 23, 24, 25, 21, 33, 
-       34, 34, 35, 36, 32, 32, 32, 32, 
-       37, 32, 36, 32, 34, 34, 35, 32, 
-       34, 34, 35, 36, 32, 38, 34, 34, 
-       35, 36, 32, 39, 32, 40, 32, 33, 
-       34, 34, 35, 36, 32, 41, 34, 34, 
-       35, 36, 32, 23, 23, 24, 1, 0, 
-       43, 42, 45, 46, 47, 48, 49, 50, 
-       24, 25, 44, 51, 52, 52, 26, 44, 
-       53, 54, 55, 56, 57, 44, 59, 60, 
-       61, 62, 4, 1, 58, 63, 58, 58, 
-       9, 58, 58, 58, 64, 58, 65, 60, 
-       66, 66, 4, 1, 58, 63, 58, 58, 
-       58, 58, 58, 58, 64, 58, 60, 66, 
-       66, 4, 1, 58, 63, 58, 58, 58, 
-       58, 58, 58, 64, 58, 45, 58, 58, 
-       58, 67, 68, 58, 1, 58, 63, 58, 
-       58, 58, 58, 58, 45, 58, 69, 69, 
-       58, 1, 58, 63, 58, 63, 58, 58, 
-       70, 58, 63, 58, 63, 58, 63, 58, 
-       58, 58, 58, 63, 58, 45, 58, 71, 
-       58, 69, 69, 58, 1, 58, 63, 58, 
-       58, 58, 58, 58, 45, 58, 45, 58, 
-       58, 58, 69, 69, 58, 1, 58, 63, 
-       58, 58, 58, 58, 58, 45, 58, 45, 
-       58, 58, 58, 69, 68, 58, 1, 58, 
-       63, 58, 58, 58, 58, 58, 45, 58, 
-       72, 7, 73, 74, 4, 1, 58, 63, 
-       58, 7, 73, 74, 4, 1, 58, 63, 
-       58, 73, 73, 4, 1, 58, 63, 58, 
-       75, 76, 76, 4, 1, 58, 63, 58, 
-       67, 77, 58, 1, 58, 63, 58, 67, 
-       58, 69, 69, 58, 1, 58, 63, 58, 
-       69, 77, 58, 1, 58, 63, 58, 59, 
-       60, 66, 66, 4, 1, 58, 63, 58, 
-       58, 58, 58, 58, 58, 64, 58, 59, 
-       60, 61, 66, 4, 1, 58, 63, 58, 
-       58, 9, 58, 58, 58, 64, 58, 79, 
-       80, 81, 82, 13, 14, 78, 83, 78, 
-       78, 20, 78, 78, 78, 84, 78, 85, 
-       80, 86, 82, 13, 14, 78, 83, 78, 
-       78, 78, 78, 78, 78, 84, 78, 80, 
-       86, 82, 13, 14, 78, 83, 78, 78, 
-       78, 78, 78, 78, 84, 78, 87, 78, 
-       78, 78, 88, 89, 78, 14, 78, 83, 
-       78, 78, 78, 78, 78, 87, 78, 90, 
-       80, 91, 92, 13, 14, 78, 83, 78, 
-       78, 19, 78, 78, 78, 84, 78, 93, 
-       80, 86, 86, 13, 14, 78, 83, 78, 
-       78, 78, 78, 78, 78, 84, 78, 80, 
-       86, 86, 13, 14, 78, 83, 78, 78, 
-       78, 78, 78, 78, 84, 78, 87, 78, 
-       78, 78, 94, 89, 78, 14, 78, 83, 
-       78, 78, 78, 78, 78, 87, 78, 83, 
-       78, 78, 95, 78, 83, 78, 83, 78, 
-       83, 78, 78, 78, 78, 83, 78, 87, 
-       78, 96, 78, 94, 94, 78, 14, 78, 
-       83, 78, 78, 78, 78, 78, 87, 78, 
-       87, 78, 78, 78, 94, 94, 78, 14, 
-       78, 83, 78, 78, 78, 78, 78, 87, 
-       78, 97, 17, 98, 99, 13, 14, 78, 
-       83, 78, 17, 98, 99, 13, 14, 78, 
-       83, 78, 98, 98, 13, 14, 78, 83, 
-       78, 100, 101, 101, 13, 14, 78, 83, 
-       78, 88, 102, 78, 14, 78, 83, 78, 
-       94, 94, 78, 14, 78, 83, 78, 88, 
-       78, 94, 94, 78, 14, 78, 83, 78, 
-       94, 102, 78, 14, 78, 83, 78, 90, 
-       80, 86, 86, 13, 14, 78, 83, 78, 
-       78, 78, 78, 78, 78, 84, 78, 90, 
-       80, 91, 86, 13, 14, 78, 83, 78, 
-       78, 19, 78, 78, 78, 84, 78, 11, 
-       12, 12, 13, 14, 78, 79, 80, 86, 
-       82, 13, 14, 78, 83, 78, 78, 78, 
-       78, 78, 78, 84, 78, 104, 48, 105, 
-       105, 24, 25, 103, 51, 103, 103, 103, 
-       103, 103, 103, 55, 103, 48, 105, 105, 
-       24, 25, 103, 51, 103, 103, 103, 103, 
-       103, 103, 55, 103, 106, 103, 103, 103, 
-       107, 108, 103, 25, 103, 51, 103, 103, 
-       103, 103, 103, 106, 103, 47, 48, 109, 
-       110, 24, 25, 103, 51, 103, 103, 26, 
-       103, 103, 103, 55, 103, 106, 103, 103, 
-       103, 111, 108, 103, 25, 103, 51, 103, 
-       103, 103, 103, 103, 106, 103, 51, 103, 
-       103, 112, 103, 51, 103, 51, 103, 51, 
-       103, 103, 103, 103, 51, 103, 106, 103, 
-       113, 103, 111, 111, 103, 25, 103, 51, 
-       103, 103, 103, 103, 103, 106, 103, 106, 
-       103, 103, 103, 111, 111, 103, 25, 103, 
-       51, 103, 103, 103, 103, 103, 106, 103, 
-       114, 30, 115, 116, 24, 25, 103, 51, 
-       103, 30, 115, 116, 24, 25, 103, 51, 
-       103, 115, 115, 24, 25, 103, 51, 103, 
-       47, 48, 105, 105, 24, 25, 103, 51, 
-       103, 103, 103, 103, 103, 103, 55, 103, 
-       117, 118, 118, 24, 25, 103, 51, 103, 
-       107, 119, 103, 25, 103, 51, 103, 111, 
-       111, 103, 25, 103, 51, 103, 107, 103, 
-       111, 111, 103, 25, 103, 51, 103, 111, 
-       119, 103, 25, 103, 51, 103, 47, 48, 
-       109, 105, 24, 25, 103, 51, 103, 103, 
-       26, 103, 103, 103, 55, 103, 22, 23, 
-       23, 24, 25, 120, 120, 120, 120, 26, 
-       120, 22, 23, 23, 24, 25, 120, 122, 
-       123, 124, 125, 35, 36, 121, 126, 121, 
-       121, 37, 121, 121, 121, 127, 121, 128, 
-       123, 125, 125, 35, 36, 121, 126, 121, 
-       121, 121, 121, 121, 121, 127, 121, 123, 
-       125, 125, 35, 36, 121, 126, 121, 121, 
-       121, 121, 121, 121, 127, 121, 129, 121, 
-       121, 121, 130, 131, 121, 36, 121, 126, 
-       121, 121, 121, 121, 121, 129, 121, 122, 
-       123, 124, 52, 35, 36, 121, 126, 121, 
-       121, 37, 121, 121, 121, 127, 121, 129, 
-       121, 121, 121, 132, 131, 121, 36, 121, 
-       126, 121, 121, 121, 121, 121, 129, 121, 
-       126, 121, 121, 133, 121, 126, 121, 126, 
-       121, 126, 121, 121, 121, 121, 126, 121, 
-       129, 121, 134, 121, 132, 132, 121, 36, 
-       121, 126, 121, 121, 121, 121, 121, 129, 
-       121, 129, 121, 121, 121, 132, 132, 121, 
-       36, 121, 126, 121, 121, 121, 121, 121, 
-       129, 121, 135, 40, 136, 137, 35, 36, 
-       121, 126, 121, 40, 136, 137, 35, 36, 
-       121, 126, 121, 136, 136, 35, 36, 121, 
-       126, 121, 122, 123, 125, 125, 35, 36, 
-       121, 126, 121, 121, 121, 121, 121, 121, 
-       127, 121, 138, 139, 139, 35, 36, 121, 
-       126, 121, 130, 140, 121, 36, 121, 126, 
-       121, 132, 132, 121, 36, 121, 126, 121, 
-       130, 121, 132, 132, 121, 36, 121, 126, 
-       121, 132, 140, 121, 36, 121, 126, 121, 
-       45, 46, 47, 48, 109, 105, 24, 25, 
-       103, 51, 52, 52, 26, 103, 103, 45, 
-       55, 103, 59, 141, 61, 62, 4, 1, 
-       58, 63, 58, 58, 9, 58, 58, 58, 
-       64, 58, 45, 46, 47, 48, 142, 143, 
-       24, 144, 58, 145, 58, 52, 26, 58, 
-       58, 45, 55, 58, 22, 146, 146, 24, 
-       144, 58, 63, 58, 58, 26, 58, 145, 
-       58, 58, 147, 58, 145, 58, 145, 58, 
-       145, 58, 58, 58, 58, 145, 58, 45, 
-       58, 71, 22, 146, 146, 24, 144, 58, 
-       63, 58, 58, 58, 58, 58, 45, 58, 
-       149, 148, 150, 150, 148, 43, 148, 151, 
-       148, 150, 150, 148, 43, 148, 151, 148, 
-       151, 148, 148, 152, 148, 151, 148, 151, 
-       148, 151, 148, 148, 148, 148, 151, 148, 
-       45, 120, 120, 120, 120, 120, 120, 120, 
-       120, 120, 52, 120, 120, 120, 120, 45, 
-       120, 0
-};
-
-static const unsigned char _indic_syllable_machine_trans_targs[] = {
-       39, 45, 50, 2, 51, 5, 6, 53, 
-       57, 58, 39, 67, 11, 73, 68, 14, 
-       15, 75, 80, 81, 84, 39, 89, 21, 
-       95, 90, 98, 39, 24, 25, 97, 103, 
-       39, 112, 30, 118, 113, 121, 33, 34, 
-       120, 126, 39, 137, 39, 40, 60, 85, 
-       87, 105, 106, 91, 107, 127, 128, 99, 
-       135, 140, 39, 41, 43, 8, 59, 46, 
-       54, 42, 1, 44, 48, 0, 47, 49, 
-       52, 3, 4, 55, 7, 56, 39, 61, 
-       63, 18, 83, 69, 76, 62, 9, 64, 
-       78, 71, 65, 17, 82, 66, 10, 70, 
-       72, 74, 12, 13, 77, 16, 79, 39, 
-       86, 26, 88, 101, 93, 19, 104, 20, 
-       92, 94, 96, 22, 23, 100, 27, 102, 
-       39, 39, 108, 110, 28, 35, 114, 122, 
-       109, 111, 124, 116, 29, 115, 117, 119, 
-       31, 32, 123, 36, 125, 129, 130, 134, 
-       131, 132, 37, 133, 39, 136, 38, 138, 
-       139
-};
-
-static const char _indic_syllable_machine_trans_actions[] = {
-       1, 0, 2, 0, 2, 0, 0, 2, 
-       2, 2, 3, 2, 0, 2, 0, 0, 
-       0, 2, 2, 2, 2, 4, 2, 0, 
-       5, 0, 5, 6, 0, 0, 5, 2, 
-       7, 2, 0, 2, 0, 2, 0, 0, 
-       2, 2, 8, 0, 11, 2, 2, 5, 
-       0, 12, 12, 0, 2, 5, 2, 5, 
-       2, 0, 13, 2, 0, 0, 2, 0, 
-       2, 2, 0, 2, 2, 0, 0, 2, 
-       2, 0, 0, 0, 0, 2, 14, 2, 
-       0, 0, 2, 0, 2, 2, 0, 2, 
-       2, 2, 2, 0, 2, 2, 0, 0, 
-       2, 2, 0, 0, 0, 0, 2, 15, 
-       5, 0, 5, 2, 2, 0, 5, 0, 
-       0, 2, 5, 0, 0, 0, 0, 2, 
-       16, 17, 2, 0, 0, 0, 0, 2, 
-       2, 2, 2, 2, 0, 0, 2, 2, 
-       0, 0, 0, 0, 2, 0, 18, 18, 
-       0, 0, 0, 0, 19, 2, 0, 0, 
-       0
-};
-
-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, 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, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 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 _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, 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, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 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 _indic_syllable_machine_eof_trans[] = {
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 11, 11, 11, 11, 11, 11, 11, 
-       11, 11, 11, 22, 22, 28, 22, 22, 
-       22, 22, 22, 22, 33, 33, 33, 33, 
-       33, 33, 33, 33, 33, 1, 43, 0, 
-       59, 59, 59, 59, 59, 59, 59, 59, 
-       59, 59, 59, 59, 59, 59, 59, 59, 
-       59, 59, 59, 59, 79, 79, 79, 79, 
-       79, 79, 79, 79, 79, 79, 79, 79, 
-       79, 79, 79, 79, 79, 79, 79, 79, 
-       79, 79, 79, 79, 79, 104, 104, 104, 
-       104, 104, 104, 104, 104, 104, 104, 104, 
-       104, 104, 104, 104, 104, 104, 104, 104, 
-       104, 121, 121, 122, 122, 122, 122, 122, 
-       122, 122, 122, 122, 122, 122, 122, 122, 
-       122, 122, 122, 122, 122, 122, 122, 104, 
-       59, 59, 59, 59, 59, 59, 59, 149, 
-       149, 149, 149, 149, 121
-};
-
-static const int indic_syllable_machine_start = 39;
-static const int indic_syllable_machine_first_final = 39;
-static const int indic_syllable_machine_error = -1;
-
-static const int indic_syllable_machine_en_main = 39;
-
-
-#line 46 "hb-ot-shape-complex-indic-machine.rl"
-
-
-
-#line 102 "hb-ot-shape-complex-indic-machine.rl"
-
-
-#define found_syllable(syllable_type) \
-  HB_STMT_START { \
-    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; \
-    syllable_serial++; \
-    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
-  } HB_STMT_END
-
-static void
-find_syllables_indic (hb_buffer_t *buffer)
-{
-  unsigned int p, pe, eof, ts, te, act;
-  int cs;
-  hb_glyph_info_t *info = buffer->info;
-  
-#line 440 "hb-ot-shape-complex-indic-machine.hh"
-       {
-       cs = indic_syllable_machine_start;
-       ts = 0;
-       te = 0;
-       act = 0;
-       }
-
-#line 122 "hb-ot-shape-complex-indic-machine.rl"
-
-
-  p = 0;
-  pe = eof = buffer->len;
-
-  unsigned int syllable_serial = 1;
-  
-#line 456 "hb-ot-shape-complex-indic-machine.hh"
-       {
-       int _slen;
-       int _trans;
-       const unsigned char *_keys;
-       const unsigned char *_inds;
-       if ( p == pe )
-               goto _test_eof;
-_resume:
-       switch ( _indic_syllable_machine_from_state_actions[cs] ) {
-       case 10:
-#line 1 "NONE"
-       {ts = p;}
-       break;
-#line 470 "hb-ot-shape-complex-indic-machine.hh"
-       }
-
-       _keys = _indic_syllable_machine_trans_keys + (cs<<1);
-       _inds = _indic_syllable_machine_indicies + _indic_syllable_machine_index_offsets[cs];
-
-       _slen = _indic_syllable_machine_key_spans[cs];
-       _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].indic_category()) &&
-               ( info[p].indic_category()) <= _keys[1] ?
-               ( info[p].indic_category()) - _keys[0] : _slen ];
-
-_eof_trans:
-       cs = _indic_syllable_machine_trans_targs[_trans];
-
-       if ( _indic_syllable_machine_trans_actions[_trans] == 0 )
-               goto _again;
-
-       switch ( _indic_syllable_machine_trans_actions[_trans] ) {
-       case 2:
-#line 1 "NONE"
-       {te = p+1;}
-       break;
-       case 11:
-#line 98 "hb-ot-shape-complex-indic-machine.rl"
-       {te = p+1;{ found_syllable (indic_non_indic_cluster); }}
-       break;
-       case 13:
-#line 93 "hb-ot-shape-complex-indic-machine.rl"
-       {te = p;p--;{ found_syllable (indic_consonant_syllable); }}
-       break;
-       case 14:
-#line 94 "hb-ot-shape-complex-indic-machine.rl"
-       {te = p;p--;{ found_syllable (indic_vowel_syllable); }}
-       break;
-       case 17:
-#line 95 "hb-ot-shape-complex-indic-machine.rl"
-       {te = p;p--;{ found_syllable (indic_standalone_cluster); }}
-       break;
-       case 19:
-#line 96 "hb-ot-shape-complex-indic-machine.rl"
-       {te = p;p--;{ found_syllable (indic_symbol_cluster); }}
-       break;
-       case 15:
-#line 97 "hb-ot-shape-complex-indic-machine.rl"
-       {te = p;p--;{ found_syllable (indic_broken_cluster); }}
-       break;
-       case 16:
-#line 98 "hb-ot-shape-complex-indic-machine.rl"
-       {te = p;p--;{ found_syllable (indic_non_indic_cluster); }}
-       break;
-       case 1:
-#line 93 "hb-ot-shape-complex-indic-machine.rl"
-       {{p = ((te))-1;}{ found_syllable (indic_consonant_syllable); }}
-       break;
-       case 3:
-#line 94 "hb-ot-shape-complex-indic-machine.rl"
-       {{p = ((te))-1;}{ found_syllable (indic_vowel_syllable); }}
-       break;
-       case 7:
-#line 95 "hb-ot-shape-complex-indic-machine.rl"
-       {{p = ((te))-1;}{ found_syllable (indic_standalone_cluster); }}
-       break;
-       case 8:
-#line 96 "hb-ot-shape-complex-indic-machine.rl"
-       {{p = ((te))-1;}{ found_syllable (indic_symbol_cluster); }}
-       break;
-       case 4:
-#line 97 "hb-ot-shape-complex-indic-machine.rl"
-       {{p = ((te))-1;}{ found_syllable (indic_broken_cluster); }}
-       break;
-       case 6:
-#line 1 "NONE"
-       {       switch( act ) {
-       case 1:
-       {{p = ((te))-1;} found_syllable (indic_consonant_syllable); }
-       break;
-       case 5:
-       {{p = ((te))-1;} found_syllable (indic_broken_cluster); }
-       break;
-       case 6:
-       {{p = ((te))-1;} found_syllable (indic_non_indic_cluster); }
-       break;
-       }
-       }
-       break;
-       case 18:
-#line 1 "NONE"
-       {te = p+1;}
-#line 93 "hb-ot-shape-complex-indic-machine.rl"
-       {act = 1;}
-       break;
-       case 5:
-#line 1 "NONE"
-       {te = p+1;}
-#line 97 "hb-ot-shape-complex-indic-machine.rl"
-       {act = 5;}
-       break;
-       case 12:
-#line 1 "NONE"
-       {te = p+1;}
-#line 98 "hb-ot-shape-complex-indic-machine.rl"
-       {act = 6;}
-       break;
-#line 573 "hb-ot-shape-complex-indic-machine.hh"
-       }
-
-_again:
-       switch ( _indic_syllable_machine_to_state_actions[cs] ) {
-       case 9:
-#line 1 "NONE"
-       {ts = 0;}
-       break;
-#line 582 "hb-ot-shape-complex-indic-machine.hh"
-       }
-
-       if ( ++p != pe )
-               goto _resume;
-       _test_eof: {}
-       if ( p == eof )
-       {
-       if ( _indic_syllable_machine_eof_trans[cs] > 0 ) {
-               _trans = _indic_syllable_machine_eof_trans[cs] - 1;
-               goto _eof_trans;
-       }
-       }
-
-       }
-
-#line 130 "hb-ot-shape-complex-indic-machine.rl"
-
-}
-
-#undef found_syllable
-
-#endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-indic-table.cc b/src/hb-ot-shape-complex-indic-table.cc
deleted file mode 100644 (file)
index 326aa9f..0000000
+++ /dev/null
@@ -1,501 +0,0 @@
-/* == Start of generated table == */
-/*
- * The following table is generated by running:
- *
- *   ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt
- *
- * on files with these headers:
- *
- * # IndicSyllabicCategory-14.0.0.txt
- * # Date: 2021-05-22, 01:01:00 GMT [KW, RP]
- * # IndicPositionalCategory-14.0.0.txt
- * # Date: 2021-05-22, 01:01:00 GMT [KW, RP]
- * # Blocks-14.0.0.txt
- * # Date: 2021-01-22, 23:29:00 GMT [KW]
- */
-
-#include "hb.hh"
-
-#ifndef HB_NO_OT_SHAPE
-
-#include "hb-ot-shape-complex-indic.hh"
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-macros"
-
-#define ISC_A    INDIC_SYLLABIC_CATEGORY_AVAGRAHA                    /*   17 chars; Avagraha */
-#define ISC_Bi   INDIC_SYLLABIC_CATEGORY_BINDU                       /*   91 chars; Bindu */
-#define ISC_BJN  INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER       /*   20 chars; Brahmi_Joining_Number */
-#define ISC_Ca   INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK           /*   59 chars; Cantillation_Mark */
-#define ISC_C    INDIC_SYLLABIC_CATEGORY_CONSONANT                   /* 2206 chars; Consonant */
-#define ISC_CD   INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD              /*   14 chars; Consonant_Dead */
-#define ISC_CF   INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL             /*   70 chars; Consonant_Final */
-#define ISC_CHL  INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER       /*    5 chars; Consonant_Head_Letter */
-#define ISC_CIP  INDIC_SYLLABIC_CATEGORY_CONSONANT_INITIAL_POSTFIXED /*    1 chars; Consonant_Initial_Postfixed */
-#define ISC_CK   INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER            /*    2 chars; Consonant_Killer */
-#define ISC_CM   INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL            /*   31 chars; Consonant_Medial */
-#define ISC_CP   INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER       /*   22 chars; Consonant_Placeholder */
-#define ISC_CPR  INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA   /*    3 chars; Consonant_Preceding_Repha */
-#define ISC_CPrf INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED          /*   10 chars; Consonant_Prefixed */
-#define ISC_CS   INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED         /*   94 chars; Consonant_Subjoined */
-#define ISC_CSR  INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA  /*    1 chars; Consonant_Succeeding_Repha */
-#define ISC_CWS  INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER      /*    8 chars; Consonant_With_Stacker */
-#define ISC_GM   INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK             /*    3 chars; Gemination_Mark */
-#define ISC_IS   INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER           /*   12 chars; Invisible_Stacker */
-#define ISC_ZWJ  INDIC_SYLLABIC_CATEGORY_JOINER                      /*    1 chars; Joiner */
-#define ISC_ML   INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER            /*    1 chars; Modifying_Letter */
-#define ISC_ZWNJ INDIC_SYLLABIC_CATEGORY_NON_JOINER                  /*    1 chars; Non_Joiner */
-#define ISC_N    INDIC_SYLLABIC_CATEGORY_NUKTA                       /*   32 chars; Nukta */
-#define ISC_Nd   INDIC_SYLLABIC_CATEGORY_NUMBER                      /*  491 chars; Number */
-#define ISC_NJ   INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER               /*    1 chars; Number_Joiner */
-#define ISC_x    INDIC_SYLLABIC_CATEGORY_OTHER                       /*    1 chars; Other */
-#define ISC_PK   INDIC_SYLLABIC_CATEGORY_PURE_KILLER                 /*   25 chars; Pure_Killer */
-#define ISC_RS   INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER            /*    2 chars; Register_Shifter */
-#define ISC_SM   INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER           /*   25 chars; Syllable_Modifier */
-#define ISC_TL   INDIC_SYLLABIC_CATEGORY_TONE_LETTER                 /*    7 chars; Tone_Letter */
-#define ISC_TM   INDIC_SYLLABIC_CATEGORY_TONE_MARK                   /*   42 chars; Tone_Mark */
-#define ISC_V    INDIC_SYLLABIC_CATEGORY_VIRAMA                      /*   27 chars; Virama */
-#define ISC_Vs   INDIC_SYLLABIC_CATEGORY_VISARGA                     /*   35 chars; Visarga */
-#define ISC_Vo   INDIC_SYLLABIC_CATEGORY_VOWEL                       /*   30 chars; Vowel */
-#define ISC_M    INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT             /*  686 chars; Vowel_Dependent */
-#define ISC_VI   INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT           /*  486 chars; Vowel_Independent */
-
-#define IMC_B    INDIC_MATRA_CATEGORY_BOTTOM                         /*  352 chars; Bottom */
-#define IMC_BL   INDIC_MATRA_CATEGORY_BOTTOM_AND_LEFT                /*    1 chars; Bottom_And_Left */
-#define IMC_BR   INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT               /*    4 chars; Bottom_And_Right */
-#define IMC_L    INDIC_MATRA_CATEGORY_LEFT                           /*   64 chars; Left */
-#define IMC_LR   INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT                 /*   22 chars; Left_And_Right */
-#define IMC_x    INDIC_MATRA_CATEGORY_NOT_APPLICABLE                 /*    1 chars; Not_Applicable */
-#define IMC_O    INDIC_MATRA_CATEGORY_OVERSTRUCK                     /*   10 chars; Overstruck */
-#define IMC_R    INDIC_MATRA_CATEGORY_RIGHT                          /*  290 chars; Right */
-#define IMC_T    INDIC_MATRA_CATEGORY_TOP                            /*  418 chars; Top */
-#define IMC_TB   INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM                 /*   10 chars; Top_And_Bottom */
-#define IMC_TBL  INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_LEFT        /*    2 chars; Top_And_Bottom_And_Left */
-#define IMC_TBR  INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT       /*    1 chars; Top_And_Bottom_And_Right */
-#define IMC_TL   INDIC_MATRA_CATEGORY_TOP_AND_LEFT                   /*    6 chars; Top_And_Left */
-#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)
-
-
-static const uint16_t indic_table[] = {
-
-
-#define indic_offset_0x0028u 0
-
-
-  /* Basic Latin */
-
-  /* 0028 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(CP,x),  _(x,x),  _(x,x),
-  /* 0030 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-  /* 0038 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-
-#define indic_offset_0x00b0u 24
-
-
-  /* Latin-1 Supplement */
-
-  /* 00B0 */  _(x,x),  _(x,x), _(SM,x), _(SM,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 00B8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 00C0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 00C8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 00D0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(CP,x),
-
-#define indic_offset_0x0900u 64
-
-
-  /* Devanagari */
-
-  /* 0900 */ _(Bi,T), _(Bi,T), _(Bi,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
-  /* 0908 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
-  /* 0910 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0918 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0920 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0928 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0930 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0938 */  _(C,x),  _(C,x),  _(M,T),  _(M,R),  _(N,B),  _(A,x),  _(M,R),  _(M,L),
-  /* 0940 */  _(M,R),  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(M,T),  _(M,T),  _(M,T),
-  /* 0948 */  _(M,T),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(V,B),  _(M,L),  _(M,R),
-  /* 0950 */  _(x,x), _(Ca,T), _(Ca,B),  _(x,T),  _(x,T),  _(M,T),  _(M,B),  _(M,B),
-  /* 0958 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0960 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
-  /* 0968 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-  /* 0970 */  _(x,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
-  /* 0978 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-
-  /* Bengali */
-
-  /* 0980 */ _(CP,x), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
-  /* 0988 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x),  _(x,x), _(VI,x),
-  /* 0990 */ _(VI,x),  _(x,x),  _(x,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0998 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 09A0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 09A8 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 09B0 */  _(C,x),  _(x,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),
-  /* 09B8 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,B),  _(A,x),  _(M,R),  _(M,L),
-  /* 09C0 */  _(M,R),  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(x,x),  _(x,x),  _(M,L),
-  /* 09C8 */  _(M,L),  _(x,x),  _(x,x), _(M,LR), _(M,LR),  _(V,B), _(CD,x),  _(x,x),
-  /* 09D0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,R),
-  /* 09D8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),
-  /* 09E0 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
-  /* 09E8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-  /* 09F0 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 09F8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(Bi,x),  _(x,x), _(SM,T),  _(x,x),
-
-  /* Gurmukhi */
-
-  /* 0A00 */  _(x,x), _(Bi,T), _(Bi,T), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
-  /* 0A08 */ _(VI,x), _(VI,x), _(VI,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(VI,x),
-  /* 0A10 */ _(VI,x),  _(x,x),  _(x,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0A18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0A20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0A28 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0A30 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),
-  /* 0A38 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,B),  _(x,x),  _(M,R),  _(M,L),
-  /* 0A40 */  _(M,R),  _(M,B),  _(M,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,T),
-  /* 0A48 */  _(M,T),  _(x,x),  _(x,x),  _(M,T),  _(M,T),  _(V,B),  _(x,x),  _(x,x),
-  /* 0A50 */  _(x,x), _(Ca,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0A58 */  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(x,x),
-  /* 0A60 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
-  /* 0A68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-  /* 0A70 */ _(Bi,T), _(GM,T), _(CP,x), _(CP,x),  _(x,x), _(CM,B),  _(x,x),  _(x,x),
-  /* 0A78 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-
-  /* Gujarati */
-
-  /* 0A80 */  _(x,x), _(Bi,T), _(Bi,T), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
-  /* 0A88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x), _(VI,x),
-  /* 0A90 */ _(VI,x), _(VI,x),  _(x,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0A98 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0AA0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0AA8 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0AB0 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0AB8 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,B),  _(A,x),  _(M,R),  _(M,L),
-  /* 0AC0 */  _(M,R),  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(M,T),  _(x,x),  _(M,T),
-  /* 0AC8 */  _(M,T), _(M,TR),  _(x,x),  _(M,R),  _(M,R),  _(V,B),  _(x,x),  _(x,x),
-  /* 0AD0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0AD8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0AE0 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
-  /* 0AE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-  /* 0AF0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0AF8 */  _(x,x),  _(C,x), _(Ca,T), _(Ca,T), _(Ca,T),  _(N,T),  _(N,T),  _(N,T),
-
-  /* Oriya */
-
-  /* 0B00 */  _(x,x), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
-  /* 0B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x),  _(x,x), _(VI,x),
-  /* 0B10 */ _(VI,x),  _(x,x),  _(x,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0B18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0B20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0B28 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0B30 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0B38 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,B),  _(A,x),  _(M,R),  _(M,T),
-  /* 0B40 */  _(M,R),  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(x,x),  _(x,x),  _(M,L),
-  /* 0B48 */ _(M,TL),  _(x,x),  _(x,x), _(M,LR),_(M,TLR),  _(V,B),  _(x,x),  _(x,x),
-  /* 0B50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,T),  _(M,T), _(M,TR),
-  /* 0B58 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),
-  /* 0B60 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
-  /* 0B68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-  /* 0B70 */  _(x,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0B78 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-
-  /* Tamil */
-
-  /* 0B80 */  _(x,x),  _(x,x), _(Bi,T), _(ML,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
-  /* 0B88 */ _(VI,x), _(VI,x), _(VI,x),  _(x,x),  _(x,x),  _(x,x), _(VI,x), _(VI,x),
-  /* 0B90 */ _(VI,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(x,x),  _(x,x),
-  /* 0B98 */  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),
-  /* 0BA0 */  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0BA8 */  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),
-  /* 0BB0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0BB8 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,R),  _(M,R),
-  /* 0BC0 */  _(M,T),  _(M,R),  _(M,R),  _(x,x),  _(x,x),  _(x,x),  _(M,L),  _(M,L),
-  /* 0BC8 */  _(M,L),  _(x,x), _(M,LR), _(M,LR), _(M,LR),  _(V,T),  _(x,x),  _(x,x),
-  /* 0BD0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,R),
-  /* 0BD8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0BE0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
-  /* 0BE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-  /* 0BF0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0BF8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-
-  /* Telugu */
-
-  /* 0C00 */ _(Bi,T), _(Bi,R), _(Bi,R), _(Vs,R), _(Bi,T), _(VI,x), _(VI,x), _(VI,x),
-  /* 0C08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x), _(VI,x), _(VI,x),
-  /* 0C10 */ _(VI,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0C18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0C20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0C28 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0C30 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0C38 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,B),  _(A,x),  _(M,T),  _(M,T),
-  /* 0C40 */  _(M,T),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(x,x),  _(M,T),  _(M,T),
-  /* 0C48 */ _(M,TB),  _(x,x),  _(M,T),  _(M,T),  _(M,T),  _(V,T),  _(x,x),  _(x,x),
-  /* 0C50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,T),  _(M,B),  _(x,x),
-  /* 0C58 */  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x), _(CD,x),  _(x,x),  _(x,x),
-  /* 0C60 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
-  /* 0C68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-  /* 0C70 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0C78 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-
-  /* Kannada */
-
-  /* 0C80 */ _(Bi,x), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
-  /* 0C88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x), _(VI,x), _(VI,x),
-  /* 0C90 */ _(VI,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0C98 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0CA0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0CA8 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0CB0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0CB8 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,B),  _(A,x),  _(M,R),  _(M,T),
-  /* 0CC0 */ _(M,TR),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(x,x),  _(M,T), _(M,TR),
-  /* 0CC8 */ _(M,TR),  _(x,x), _(M,TR), _(M,TR),  _(M,T),  _(V,T),  _(x,x),  _(x,x),
-  /* 0CD0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,R),  _(M,R),  _(x,x),
-  /* 0CD8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(CD,x),  _(C,x),  _(x,x),
-  /* 0CE0 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
-  /* 0CE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-  /* 0CF0 */  _(x,x),_(CWS,x),_(CWS,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0CF8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-
-  /* Malayalam */
-
-  /* 0D00 */ _(Bi,T), _(Bi,T), _(Bi,R), _(Vs,R), _(Bi,x), _(VI,x), _(VI,x), _(VI,x),
-  /* 0D08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x), _(VI,x), _(VI,x),
-  /* 0D10 */ _(VI,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0D18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0D20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0D28 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0D30 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0D38 */  _(C,x),  _(C,x),  _(C,x), _(PK,T), _(PK,T),  _(A,x),  _(M,R),  _(M,R),
-  /* 0D40 */  _(M,R),  _(M,R),  _(M,R),  _(M,B),  _(M,B),  _(x,x),  _(M,L),  _(M,L),
-  /* 0D48 */  _(M,L),  _(x,x), _(M,LR), _(M,LR), _(M,LR),  _(V,T),_(CPR,T),  _(x,x),
-  /* 0D50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(CD,x), _(CD,x), _(CD,x),  _(M,R),
-  /* 0D58 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(VI,x),
-  /* 0D60 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
-  /* 0D68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-  /* 0D70 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0D78 */  _(x,x),  _(x,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x),
-
-  /* Sinhala */
-
-  /* 0D80 */  _(x,x), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
-  /* 0D88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
-  /* 0D90 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x),
-  /* 0D98 */  _(x,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0DA0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0DA8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0DB0 */  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0DB8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(x,x),  _(x,x),
-  /* 0DC0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),
-  /* 0DC8 */  _(x,x),  _(x,x),  _(V,T),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,R),
-  /* 0DD0 */  _(M,R),  _(M,R),  _(M,T),  _(M,T),  _(M,B),  _(x,x),  _(M,B),  _(x,x),
-  /* 0DD8 */  _(M,R),  _(M,L), _(M,TL),  _(M,L), _(M,LR),_(M,TLR), _(M,LR),  _(M,R),
-  /* 0DE0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
-  /* 0DE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-  /* 0DF0 */  _(x,x),  _(x,x),  _(M,R),  _(M,R),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-
-#define indic_offset_0x1000u 1336
-
-
-  /* Myanmar */
-
-  /* 1000 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 1008 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 1010 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 1018 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 1020 */  _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
-  /* 1028 */ _(VI,x), _(VI,x), _(VI,x),  _(M,R),  _(M,R),  _(M,T),  _(M,T),  _(M,B),
-  /* 1030 */  _(M,B),  _(M,L),  _(M,T),  _(M,T),  _(M,T),  _(M,T), _(Bi,T), _(TM,B),
-  /* 1038 */ _(Vs,R), _(IS,x), _(PK,T), _(CM,R),_(CM,TBL), _(CM,B), _(CM,B),  _(C,x),
-  /* 1040 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-  /* 1048 */ _(Nd,x), _(Nd,x),  _(x,x), _(CP,x),  _(x,x),  _(x,x), _(CP,x),  _(x,x),
-  /* 1050 */  _(C,x),  _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(M,R),  _(M,R),
-  /* 1058 */  _(M,B),  _(M,B),  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(CM,B), _(CM,B),
-  /* 1060 */ _(CM,B),  _(C,x),  _(M,R), _(TM,R), _(TM,R),  _(C,x),  _(C,x),  _(M,R),
-  /* 1068 */  _(M,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R),  _(C,x),  _(C,x),
-  /* 1070 */  _(C,x),  _(M,T),  _(M,T),  _(M,T),  _(M,T),  _(C,x),  _(C,x),  _(C,x),
-  /* 1078 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 1080 */  _(C,x),  _(C,x), _(CM,B),  _(M,R),  _(M,L),  _(M,T),  _(M,T), _(TM,R),
-  /* 1088 */ _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,B),  _(C,x), _(TM,R),
-  /* 1090 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-  /* 1098 */ _(Nd,x), _(Nd,x), _(TM,R), _(TM,R),  _(M,R),  _(M,T),  _(x,x),  _(x,x),
-
-#define indic_offset_0x1780u 1496
-
-
-  /* Khmer */
-
-  /* 1780 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 1788 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 1790 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 1798 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 17A0 */  _(C,x),  _(C,x),  _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
-  /* 17A8 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
-  /* 17B0 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x),  _(x,x),  _(M,R),  _(M,T),
-  /* 17B8 */  _(M,T),  _(M,T),  _(M,T),  _(M,B),  _(M,B),  _(M,B), _(M,TL),_(M,TLR),
-  /* 17C0 */ _(M,LR),  _(M,L),  _(M,L),  _(M,L), _(M,LR), _(M,LR), _(Bi,T), _(Vs,R),
-  /* 17C8 */  _(M,R), _(RS,T), _(RS,T), _(SM,T),_(CSR,T), _(CK,T), _(SM,T), _(SM,T),
-  /* 17D0 */ _(SM,T), _(PK,T), _(IS,x), _(SM,T),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 17D8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(A,x), _(SM,T),  _(x,x),  _(x,x),
-  /* 17E0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-  /* 17E8 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-
-#define indic_offset_0x1cd0u 1608
-
-
-  /* Vedic Extensions */
-
-  /* 1CD0 */ _(Ca,T), _(Ca,T), _(Ca,T),  _(x,x), _(Ca,O), _(Ca,B), _(Ca,B), _(Ca,B),
-  /* 1CD8 */ _(Ca,B), _(Ca,B), _(Ca,T), _(Ca,T), _(Ca,B), _(Ca,B), _(Ca,B), _(Ca,B),
-  /* 1CE0 */ _(Ca,T), _(Ca,R),  _(x,O),  _(x,O),  _(x,O),  _(x,O),  _(x,O),  _(x,O),
-  /* 1CE8 */  _(x,O),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,B),  _(x,x),  _(x,x),
-  /* 1CF0 */  _(x,x),  _(x,x), _(CD,x), _(CD,x), _(Ca,T),_(CWS,x),_(CWS,x), _(Ca,R),
-  /* 1CF8 */ _(Ca,x), _(Ca,x), _(CP,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-
-#define indic_offset_0x2008u 1656
-
-
-  /* General Punctuation */
-
-  /* 2008 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),_(ZWNJ,x),_(ZWJ,x),  _(x,x),  _(x,x),
-  /* 2010 */ _(CP,x), _(CP,x), _(CP,x), _(CP,x), _(CP,x),  _(x,x),  _(x,x),  _(x,x),
-
-#define indic_offset_0x2070u 1672
-
-
-  /* Superscripts and Subscripts */
-
-  /* 2070 */  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(SM,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 2078 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 2080 */  _(x,x),  _(x,x), _(SM,x), _(SM,x), _(SM,x),  _(x,x),  _(x,x),  _(x,x),
-
-#define indic_offset_0xa8e0u 1696
-
-
-  /* Devanagari Extended */
-
-  /* A8E0 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T),
-  /* A8E8 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T),
-  /* A8F0 */ _(Ca,T), _(Ca,T), _(Bi,x), _(Bi,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* A8F8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(VI,x),  _(M,T),
-
-#define indic_offset_0xa9e0u 1728
-
-
-  /* Myanmar Extended-B */
-
-  /* A9E0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(M,T),  _(x,x),  _(C,x),
-  /* A9E8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* A9F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-  /* A9F8 */ _(Nd,x), _(Nd,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),
-
-#define indic_offset_0xaa60u 1760
-
-
-  /* Myanmar Extended-A */
-
-  /* AA60 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* AA68 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* AA70 */  _(x,x),  _(C,x),  _(C,x),  _(C,x), _(CP,x), _(CP,x), _(CP,x),  _(x,x),
-  /* AA78 */  _(x,x),  _(x,x),  _(C,x), _(TM,R), _(TM,T), _(TM,R),  _(C,x),  _(C,x),
-
-}; /* Table items: 1792; occupancy: 71% */
-
-uint16_t
-hb_indic_get_categories (hb_codepoint_t u)
-{
-  switch (u >> 12)
-  {
-    case 0x0u:
-      if (unlikely (u == 0x00A0u)) return _(CP,x);
-      if (hb_in_range<hb_codepoint_t> (u, 0x0028u, 0x003Fu)) return indic_table[u - 0x0028u + indic_offset_0x0028u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x00B0u, 0x00D7u)) return indic_table[u - 0x00B0u + indic_offset_0x00b0u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x0900u, 0x0DF7u)) return indic_table[u - 0x0900u + indic_offset_0x0900u];
-      break;
-
-    case 0x1u:
-      if (hb_in_range<hb_codepoint_t> (u, 0x1000u, 0x109Fu)) return indic_table[u - 0x1000u + indic_offset_0x1000u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x1780u, 0x17EFu)) return indic_table[u - 0x1780u + indic_offset_0x1780u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x1CD0u, 0x1CFFu)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
-      break;
-
-    case 0x2u:
-      if (unlikely (u == 0x25CCu)) return _(CP,x);
-      if (hb_in_range<hb_codepoint_t> (u, 0x2008u, 0x2017u)) return indic_table[u - 0x2008u + indic_offset_0x2008u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x2070u, 0x2087u)) return indic_table[u - 0x2070u + indic_offset_0x2070u];
-      break;
-
-    case 0xAu:
-      if (hb_in_range<hb_codepoint_t> (u, 0xA8E0u, 0xA8FFu)) return indic_table[u - 0xA8E0u + indic_offset_0xa8e0u];
-      if (hb_in_range<hb_codepoint_t> (u, 0xA9E0u, 0xA9FFu)) return indic_table[u - 0xA9E0u + indic_offset_0xa9e0u];
-      if (hb_in_range<hb_codepoint_t> (u, 0xAA60u, 0xAA7Fu)) return indic_table[u - 0xAA60u + indic_offset_0xaa60u];
-      break;
-
-    default:
-      break;
-  }
-  return _(x,x);
-}
-
-#undef _
-
-#undef ISC_A
-#undef ISC_Bi
-#undef ISC_BJN
-#undef ISC_Ca
-#undef ISC_C
-#undef ISC_CD
-#undef ISC_CF
-#undef ISC_CHL
-#undef ISC_CIP
-#undef ISC_CK
-#undef ISC_CM
-#undef ISC_CP
-#undef ISC_CPR
-#undef ISC_CPrf
-#undef ISC_CS
-#undef ISC_CSR
-#undef ISC_CWS
-#undef ISC_GM
-#undef ISC_IS
-#undef ISC_ZWJ
-#undef ISC_ML
-#undef ISC_ZWNJ
-#undef ISC_N
-#undef ISC_Nd
-#undef ISC_NJ
-#undef ISC_x
-#undef ISC_PK
-#undef ISC_RS
-#undef ISC_SM
-#undef ISC_TL
-#undef ISC_TM
-#undef ISC_V
-#undef ISC_Vs
-#undef ISC_Vo
-#undef ISC_M
-#undef ISC_VI
-
-#undef IMC_B
-#undef IMC_BL
-#undef IMC_BR
-#undef IMC_L
-#undef IMC_LR
-#undef IMC_x
-#undef IMC_O
-#undef IMC_R
-#undef IMC_T
-#undef IMC_TB
-#undef IMC_TBL
-#undef IMC_TBR
-#undef IMC_TL
-#undef IMC_TLR
-#undef IMC_TR
-#undef IMC_VOL
-
-#endif
-
-/* == End of generated table == */
diff --git a/src/hb-ot-shape-complex-indic.hh b/src/hb-ot-shape-complex-indic.hh
deleted file mode 100644 (file)
index dcb28a4..0000000
+++ /dev/null
@@ -1,430 +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_OT_SHAPE_COMPLEX_INDIC_HH
-#define HB_OT_SHAPE_COMPLEX_INDIC_HH
-
-#include "hb.hh"
-
-#include "hb-ot-shape-complex-syllabic.hh"
-
-
-/* buffer var allocations */
-#define indic_category() complex_var_u8_category() /* indic_category_t */
-#define indic_position() complex_var_u8_auxiliary() /* indic_position_t */
-
-
-/* Cateories used in the OpenType spec:
- * https://docs.microsoft.com/en-us/typography/script-development/devanagari
- */
-/* Note: This enum is duplicated in the -machine.rl source file.
- * Not sure how to avoid duplication. */
-enum indic_category_t {
-  OT_X = 0,
-  OT_C = 1,
-  OT_V = 2,
-  OT_N = 3,
-  OT_H = 4,
-  OT_ZWNJ = 5,
-  OT_ZWJ = 6,
-  OT_M = 7,
-  OT_SM = 8,
-  /* OT_VD = 9, UNUSED; we use OT_A instead. */
-  OT_A = 10,
-  OT_PLACEHOLDER = 11,
-  OT_DOTTEDCIRCLE = 12,
-  OT_RS = 13, /* Register Shifter, used in Khmer OT spec. */
-  OT_Coeng = 14, /* Khmer-style Virama. */
-  OT_Repha = 15, /* Atomically-encoded logical or visual repha. */
-  OT_Ra = 16,
-  OT_CM = 17,  /* Consonant-Medial. */
-  OT_Symbol = 18, /* Avagraha, etc that take marks (SM,A,VD). */
-  OT_CS = 19,
-
-  /* The following are used by Khmer & Myanmar shapers.  Defined
-   * here for them to share. */
-  OT_VAbv    = 26,
-  OT_VBlw    = 27,
-  OT_VPre    = 28,
-  OT_VPst    = 29,
-};
-
-#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 JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ))
-
-
-/* Visual positions in a syllable from left to right. */
-enum indic_position_t {
-  POS_START = 0,
-
-  POS_RA_TO_BECOME_REPH = 1,
-  POS_PRE_M = 2,
-  POS_PRE_C = 3,
-
-  POS_BASE_C = 4,
-  POS_AFTER_MAIN = 5,
-
-  POS_ABOVE_C = 6,
-
-  POS_BEFORE_SUB = 7,
-  POS_BELOW_C = 8,
-  POS_AFTER_SUB = 9,
-
-  POS_BEFORE_POST = 10,
-  POS_POST_C = 11,
-  POS_AFTER_POST = 12,
-
-  POS_FINAL_C = 13,
-  POS_SMVD = 14,
-
-  POS_END = 15
-};
-
-/* Categories used in IndicSyllabicCategory.txt from UCD. */
-enum indic_syllabic_category_t {
-  INDIC_SYLLABIC_CATEGORY_OTHER                                = OT_X,
-
-  INDIC_SYLLABIC_CATEGORY_AVAGRAHA                     = OT_Symbol,
-  INDIC_SYLLABIC_CATEGORY_BINDU                                = OT_SM,
-  INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER                = OT_PLACEHOLDER, /* Don't care. */
-  INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK            = OT_A,
-  INDIC_SYLLABIC_CATEGORY_CONSONANT                    = OT_C,
-  INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD               = OT_C,
-  INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL              = OT_CM,
-  INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER                = OT_C,
-  INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER             = OT_M, /* U+17CD only. */
-  INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL             = OT_CM,
-  INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER                = OT_PLACEHOLDER,
-  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_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,
-  INDIC_SYLLABIC_CATEGORY_JOINER                       = OT_ZWJ,
-  INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER             = OT_X,
-  INDIC_SYLLABIC_CATEGORY_NON_JOINER                   = OT_ZWNJ,
-  INDIC_SYLLABIC_CATEGORY_NUKTA                                = OT_N,
-  INDIC_SYLLABIC_CATEGORY_NUMBER                       = OT_PLACEHOLDER,
-  INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER                        = OT_PLACEHOLDER, /* Don't care. */
-  INDIC_SYLLABIC_CATEGORY_PURE_KILLER                  = OT_M, /* Is like a vowel matra. */
-  INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER             = OT_RS,
-  INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER            = OT_SM,
-  INDIC_SYLLABIC_CATEGORY_TONE_LETTER                  = OT_X,
-  INDIC_SYLLABIC_CATEGORY_TONE_MARK                    = OT_N,
-  INDIC_SYLLABIC_CATEGORY_VIRAMA                       = OT_H,
-  INDIC_SYLLABIC_CATEGORY_VISARGA                      = OT_SM,
-  INDIC_SYLLABIC_CATEGORY_VOWEL                                = OT_V,
-  INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT              = OT_M,
-  INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT            = OT_V
-};
-
-/* Categories used in IndicSMatraCategory.txt from UCD */
-enum indic_matra_category_t {
-  INDIC_MATRA_CATEGORY_NOT_APPLICABLE                  = POS_END,
-
-  INDIC_MATRA_CATEGORY_LEFT                            = POS_PRE_C,
-  INDIC_MATRA_CATEGORY_TOP                             = POS_ABOVE_C,
-  INDIC_MATRA_CATEGORY_BOTTOM                          = POS_BELOW_C,
-  INDIC_MATRA_CATEGORY_RIGHT                           = POS_POST_C,
-
-  /* These should resolve to the position of the last part of the split sequence. */
-  INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT                        = INDIC_MATRA_CATEGORY_RIGHT,
-  INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT                  = INDIC_MATRA_CATEGORY_RIGHT,
-  INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM                  = INDIC_MATRA_CATEGORY_BOTTOM,
-  INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_LEFT         = INDIC_MATRA_CATEGORY_BOTTOM,
-  INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT                = INDIC_MATRA_CATEGORY_RIGHT,
-  INDIC_MATRA_CATEGORY_TOP_AND_LEFT                    = INDIC_MATRA_CATEGORY_TOP,
-  INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT          = INDIC_MATRA_CATEGORY_RIGHT,
-  INDIC_MATRA_CATEGORY_TOP_AND_RIGHT                   = INDIC_MATRA_CATEGORY_RIGHT,
-
-  INDIC_MATRA_CATEGORY_OVERSTRUCK                      = POS_AFTER_MAIN,
-  INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT               = POS_PRE_M
-};
-
-#define INDIC_COMBINE_CATEGORIES(S,M) \
-  ( \
-    static_assert_expr (S < 255 && M < 255) + \
-    ( S | \
-     ( \
-      ( \
-       S == INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL || \
-       S == INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK || \
-       S == INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER || \
-       S == INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA || \
-       S == INDIC_SYLLABIC_CATEGORY_VIRAMA || \
-       S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT || \
-       false \
-       ? M : INDIC_MATRA_CATEGORY_NOT_APPLICABLE \
-      ) << 8 \
-     ) \
-    ) \
-   )
-
-HB_INTERNAL uint16_t
-hb_indic_get_categories (hb_codepoint_t u);
-
-
-static inline bool
-is_one_of (const hb_glyph_info_t &info, unsigned int flags)
-{
-  /* If it ligated, all bets are off. */
-  if (_hb_glyph_info_ligated (&info)) return false;
-  return !!(FLAG_UNSAFE (info.indic_category()) & flags);
-}
-
-static inline bool
-is_joiner (const hb_glyph_info_t &info)
-{
-  return is_one_of (info, JOINER_FLAGS);
-}
-
-static inline bool
-is_consonant (const hb_glyph_info_t &info)
-{
-  return is_one_of (info, CONSONANT_FLAGS);
-}
-
-static inline bool
-is_halant (const hb_glyph_info_t &info)
-{
-  return is_one_of (info, FLAG (OT_H));
-}
-
-#define IN_HALF_BLOCK(u, Base) (((u) & ~0x7Fu) == (Base))
-
-#define IS_DEVA(u) (IN_HALF_BLOCK (u, 0x0900u))
-#define IS_BENG(u) (IN_HALF_BLOCK (u, 0x0980u))
-#define IS_GURU(u) (IN_HALF_BLOCK (u, 0x0A00u))
-#define IS_GUJR(u) (IN_HALF_BLOCK (u, 0x0A80u))
-#define IS_ORYA(u) (IN_HALF_BLOCK (u, 0x0B00u))
-#define IS_TAML(u) (IN_HALF_BLOCK (u, 0x0B80u))
-#define IS_TELU(u) (IN_HALF_BLOCK (u, 0x0C00u))
-#define IS_KNDA(u) (IN_HALF_BLOCK (u, 0x0C80u))
-#define IS_MLYM(u) (IN_HALF_BLOCK (u, 0x0D00u))
-#define IS_SINH(u) (IN_HALF_BLOCK (u, 0x0D80u))
-
-
-#define MATRA_POS_LEFT(u)      POS_PRE_M
-#define MATRA_POS_RIGHT(u)     ( \
-                                 IS_DEVA(u) ? POS_AFTER_SUB  : \
-                                 IS_BENG(u) ? POS_AFTER_POST : \
-                                 IS_GURU(u) ? POS_AFTER_POST : \
-                                 IS_GUJR(u) ? POS_AFTER_POST : \
-                                 IS_ORYA(u) ? POS_AFTER_POST : \
-                                 IS_TAML(u) ? POS_AFTER_POST : \
-                                 IS_TELU(u) ? (u <= 0x0C42u ? POS_BEFORE_SUB : POS_AFTER_SUB) : \
-                                 IS_KNDA(u) ? (u < 0x0CC3u || u > 0xCD6u ? POS_BEFORE_SUB : POS_AFTER_SUB) : \
-                                 IS_MLYM(u) ? POS_AFTER_POST : \
-                                 IS_SINH(u) ? POS_AFTER_SUB  : \
-                                 /*default*/  POS_AFTER_SUB    \
-                               )
-#define MATRA_POS_TOP(u)       ( /* BENG and MLYM don't have top matras. */ \
-                                 IS_DEVA(u) ? POS_AFTER_SUB  : \
-                                 IS_GURU(u) ? POS_AFTER_POST : /* Deviate from spec */ \
-                                 IS_GUJR(u) ? POS_AFTER_SUB  : \
-                                 IS_ORYA(u) ? POS_AFTER_MAIN : \
-                                 IS_TAML(u) ? POS_AFTER_SUB  : \
-                                 IS_TELU(u) ? POS_BEFORE_SUB : \
-                                 IS_KNDA(u) ? POS_BEFORE_SUB : \
-                                 IS_SINH(u) ? POS_AFTER_SUB  : \
-                                 /*default*/  POS_AFTER_SUB    \
-                               )
-#define MATRA_POS_BOTTOM(u)    ( \
-                                 IS_DEVA(u) ? POS_AFTER_SUB  : \
-                                 IS_BENG(u) ? POS_AFTER_SUB  : \
-                                 IS_GURU(u) ? POS_AFTER_POST : \
-                                 IS_GUJR(u) ? POS_AFTER_POST : \
-                                 IS_ORYA(u) ? POS_AFTER_SUB  : \
-                                 IS_TAML(u) ? POS_AFTER_POST : \
-                                 IS_TELU(u) ? POS_BEFORE_SUB : \
-                                 IS_KNDA(u) ? POS_BEFORE_SUB : \
-                                 IS_MLYM(u) ? POS_AFTER_POST : \
-                                 IS_SINH(u) ? POS_AFTER_SUB  : \
-                                 /*default*/  POS_AFTER_SUB    \
-                               )
-
-static inline indic_position_t
-matra_position_indic (hb_codepoint_t u, indic_position_t side)
-{
-  switch ((int) side)
-  {
-    case POS_PRE_C:    return MATRA_POS_LEFT (u);
-    case POS_POST_C:   return MATRA_POS_RIGHT (u);
-    case POS_ABOVE_C:  return MATRA_POS_TOP (u);
-    case POS_BELOW_C:  return MATRA_POS_BOTTOM (u);
-  }
-  return side;
-}
-
-/* XXX
- * This is a hack for now.  We should move this data into the main Indic table.
- * Or completely remove it and just check in the tables.
- */
-static const hb_codepoint_t ra_chars[] = {
-  0x0930u, /* Devanagari */
-  0x09B0u, /* Bengali */
-  0x09F0u, /* Bengali */
-  0x0A30u, /* Gurmukhi */      /* No Reph */
-  0x0AB0u, /* Gujarati */
-  0x0B30u, /* Oriya */
-  0x0BB0u, /* Tamil */         /* No Reph */
-  0x0C30u, /* Telugu */                /* Reph formed only with ZWJ */
-  0x0CB0u, /* Kannada */
-  0x0D30u, /* Malayalam */     /* No Reph, Logical Repha */
-
-  0x0DBBu, /* Sinhala */       /* Reph formed only with ZWJ */
-};
-
-static inline bool
-is_ra (hb_codepoint_t u)
-{
-  return hb_array (ra_chars).lfind (u);
-}
-
-static inline void
-set_indic_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 & 0xFFu);
-  indic_position_t pos = (indic_position_t) (type >> 8);
-
-
-  /*
-   * Re-assign category
-   */
-
-  /* The following act more like the Bindus. */
-  if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x0953u, 0x0954u)))
-    cat = OT_SM;
-  /* The following act like consonants. */
-  else if (unlikely (hb_in_ranges<hb_codepoint_t> (u, 0x0A72u, 0x0A73u,
-                                     0x1CF5u, 0x1CF6u)))
-    cat = OT_C;
-  /* TODO: The following should only be allowed after a Visarga.
-   * For now, just treat them like regular tone marks. */
-  else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1CE2u, 0x1CE8u)))
-    cat = OT_A;
-  /* TODO: The following should only be allowed after some of
-   * the nasalization marks, maybe only for U+1CE9..U+1CF1.
-   * For now, just treat them like tone marks. */
-  else if (unlikely (u == 0x1CEDu))
-    cat = OT_A;
-  /* The following take marks in standalone clusters, similar to Avagraha. */
-  else if (unlikely (hb_in_ranges<hb_codepoint_t> (u, 0xA8F2u, 0xA8F7u,
-                                     0x1CE9u, 0x1CECu,
-                                     0x1CEEu, 0x1CF1u)))
-  {
-    cat = OT_Symbol;
-    static_assert (((int) INDIC_SYLLABIC_CATEGORY_AVAGRAHA == OT_Symbol), "");
-  }
-  else if (unlikely (u == 0x0A51u))
-  {
-    /* https://github.com/harfbuzz/harfbuzz/issues/524 */
-    cat = OT_M;
-    pos = POS_BELOW_C;
-  }
-
-  /* According to ScriptExtensions.txt, these Grantha marks may also be used in Tamil,
-   * so the Indic shaper needs to know their categories. */
-  else if (unlikely (u == 0x11301u || u == 0x11303u)) cat = OT_SM;
-  else if (unlikely (u == 0x1133Bu || u == 0x1133Cu)) cat = OT_N;
-
-  else if (unlikely (u == 0x0AFBu)) cat = OT_N; /* https://github.com/harfbuzz/harfbuzz/issues/552 */
-  else if (unlikely (u == 0x0B55u)) cat = OT_N; /* https://github.com/harfbuzz/harfbuzz/issues/2849 */
-
-  else if (unlikely (u == 0x0980u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/issues/538 */
-  else if (unlikely (u == 0x09FCu)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/1613 */
-  else if (unlikely (u == 0x0C80u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/623 */
-  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 (is_ra (u))
-      cat = OT_Ra;
-  }
-  else if (cat == OT_M)
-  {
-    pos = matra_position_indic (u, pos);
-  }
-  else if ((FLAG_UNSAFE (cat) & (FLAG (OT_SM) /* | FLAG (OT_VD) */ | FLAG (OT_A) | FLAG (OT_Symbol))))
-  {
-    pos = POS_SMVD;
-  }
-
-  if (unlikely (u == 0x0B01u)) pos = POS_BEFORE_SUB; /* Oriya Bindu is BeforeSub in the spec. */
-
-
-
-  info.indic_category() = cat;
-  info.indic_position() = pos;
-}
-
-struct hb_indic_would_substitute_feature_t
-{
-  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*/,
-                           map->get_feature_stage (0/*GSUB*/, feature_tag),
-                           &lookups, &count);
-  }
-
-  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 (face, lookups[i].index, glyphs, glyphs_count, zero_context))
-       return true;
-    return false;
-  }
-
-  private:
-  const hb_ot_map_t::lookup_map_t *lookups;
-  unsigned int count;
-  bool zero_context;
-};
-
-
-#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
deleted file mode 100644 (file)
index c52f72f..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-
-#line 1 "hb-ot-shape-complex-khmer-machine.rl"
-/*
- * Copyright © 2011,2012  Google, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
-
-#include "hb.hh"
-
-enum khmer_syllable_type_t {
-  khmer_consonant_syllable,
-  khmer_broken_cluster,
-  khmer_non_khmer_cluster,
-};
-
-
-#line 42 "hb-ot-shape-complex-khmer-machine.hh"
-#define khmer_syllable_machine_ex_C 1u
-#define khmer_syllable_machine_ex_Coeng 14u
-#define khmer_syllable_machine_ex_DOTTEDCIRCLE 12u
-#define khmer_syllable_machine_ex_PLACEHOLDER 11u
-#define khmer_syllable_machine_ex_Ra 16u
-#define khmer_syllable_machine_ex_Robatic 20u
-#define khmer_syllable_machine_ex_V 2u
-#define khmer_syllable_machine_ex_VAbv 26u
-#define khmer_syllable_machine_ex_VBlw 27u
-#define khmer_syllable_machine_ex_VPre 28u
-#define khmer_syllable_machine_ex_VPst 29u
-#define khmer_syllable_machine_ex_Xgroup 21u
-#define khmer_syllable_machine_ex_Ygroup 22u
-#define khmer_syllable_machine_ex_ZWJ 6u
-#define khmer_syllable_machine_ex_ZWNJ 5u
-
-
-#line 60 "hb-ot-shape-complex-khmer-machine.hh"
-static const unsigned char _khmer_syllable_machine_trans_keys[] = {
-       5u, 26u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 5u, 21u, 
-       5u, 26u, 5u, 21u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 
-       5u, 21u, 5u, 26u, 5u, 21u, 5u, 26u, 1u, 29u, 5u, 29u, 5u, 29u, 5u, 29u, 
-       22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 5u, 29u, 1u, 16u, 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[] = {
-       22, 17, 22, 17, 16, 17, 22, 17, 
-       22, 17, 17, 22, 17, 16, 17, 22, 
-       17, 22, 17, 22, 29, 25, 25, 25, 
-       1, 18, 25, 25, 25, 16, 22, 25, 
-       25, 1, 18, 25, 25, 16, 25, 25
-};
-
-static const short _khmer_syllable_machine_index_offsets[] = {
-       0, 23, 41, 64, 82, 99, 117, 140, 
-       158, 181, 199, 217, 240, 258, 275, 293, 
-       316, 334, 357, 375, 398, 428, 454, 480, 
-       506, 508, 527, 553, 579, 605, 622, 645, 
-       671, 697, 699, 718, 744, 770, 787, 813
-};
-
-static const char _khmer_syllable_machine_indicies[] = {
-       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, 3, 0, 0, 0, 0, 4, 0, 
-       5, 5, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       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, 14, 
-       14, 13, 13, 13, 13, 13, 13, 13, 
-       13, 13, 13, 13, 13, 13, 13, 15, 
-       13, 14, 14, 16, 16, 16, 16, 16, 
-       16, 16, 16, 16, 16, 16, 16, 16, 
-       16, 15, 16, 16, 16, 16, 17, 16, 
-       18, 18, 16, 16, 16, 16, 16, 16, 
-       16, 16, 16, 16, 16, 16, 16, 16, 
-       17, 16, 19, 19, 16, 16, 16, 16, 
-       16, 16, 16, 16, 16, 16, 16, 16, 
-       16, 19, 16, 20, 20, 16, 16, 16, 
-       16, 16, 16, 16, 16, 16, 16, 16, 
-       16, 16, 16, 21, 16, 22, 22, 16, 
-       16, 16, 16, 16, 16, 16, 16, 16, 
-       16, 16, 16, 16, 16, 23, 16, 16, 
-       16, 16, 17, 16, 22, 22, 16, 16, 
-       16, 16, 16, 16, 16, 16, 16, 16, 
-       16, 16, 16, 16, 23, 16, 24, 24, 
-       16, 16, 16, 16, 16, 16, 16, 16, 
-       16, 16, 16, 16, 16, 16, 25, 16, 
-       16, 16, 16, 17, 16, 24, 24, 16, 
-       16, 16, 16, 16, 16, 16, 16, 16, 
-       16, 16, 16, 16, 16, 25, 16, 14, 
-       14, 16, 16, 16, 16, 16, 16, 16, 
-       16, 16, 16, 16, 16, 16, 26, 15, 
-       16, 16, 16, 16, 17, 16, 28, 28, 
-       27, 27, 29, 29, 27, 27, 27, 27, 
-       2, 2, 27, 30, 27, 28, 27, 27, 
-       27, 27, 15, 19, 27, 27, 27, 17, 
-       23, 25, 21, 27, 32, 32, 31, 31, 
-       31, 31, 31, 31, 31, 33, 31, 31, 
-       31, 31, 31, 2, 3, 6, 31, 31, 
-       31, 4, 10, 12, 8, 31, 34, 34, 
-       31, 31, 31, 31, 31, 31, 31, 35, 
-       31, 31, 31, 31, 31, 31, 3, 6, 
-       31, 31, 31, 4, 10, 12, 8, 31, 
-       5, 5, 31, 31, 31, 31, 31, 31, 
-       31, 35, 31, 31, 31, 31, 31, 31, 
-       4, 6, 31, 31, 31, 31, 31, 31, 
-       8, 31, 6, 31, 7, 7, 31, 31, 
-       31, 31, 31, 31, 31, 35, 31, 31, 
-       31, 31, 31, 31, 8, 6, 31, 36, 
-       36, 31, 31, 31, 31, 31, 31, 31, 
-       35, 31, 31, 31, 31, 31, 31, 10, 
-       6, 31, 31, 31, 4, 31, 31, 8, 
-       31, 37, 37, 31, 31, 31, 31, 31, 
-       31, 31, 35, 31, 31, 31, 31, 31, 
-       31, 12, 6, 31, 31, 31, 4, 10, 
-       31, 8, 31, 34, 34, 31, 31, 31, 
-       31, 31, 31, 31, 33, 31, 31, 31, 
-       31, 31, 31, 3, 6, 31, 31, 31, 
-       4, 10, 12, 8, 31, 28, 28, 31, 
-       31, 31, 31, 31, 31, 31, 31, 31, 
-       31, 31, 31, 31, 28, 31, 14, 14, 
-       38, 38, 38, 38, 38, 38, 38, 38, 
-       38, 38, 38, 38, 38, 38, 15, 38, 
-       38, 38, 38, 17, 38, 40, 40, 39, 
-       39, 39, 39, 39, 39, 39, 41, 39, 
-       39, 39, 39, 39, 39, 15, 19, 39, 
-       39, 39, 17, 23, 25, 21, 39, 18, 
-       18, 39, 39, 39, 39, 39, 39, 39, 
-       41, 39, 39, 39, 39, 39, 39, 17, 
-       19, 39, 39, 39, 39, 39, 39, 21, 
-       39, 19, 39, 20, 20, 39, 39, 39, 
-       39, 39, 39, 39, 41, 39, 39, 39, 
-       39, 39, 39, 21, 19, 39, 42, 42, 
-       39, 39, 39, 39, 39, 39, 39, 41, 
-       39, 39, 39, 39, 39, 39, 23, 19, 
-       39, 39, 39, 17, 39, 39, 21, 39, 
-       43, 43, 39, 39, 39, 39, 39, 39, 
-       39, 41, 39, 39, 39, 39, 39, 39, 
-       25, 19, 39, 39, 39, 17, 23, 39, 
-       21, 39, 44, 44, 39, 39, 39, 39, 
-       39, 39, 39, 39, 39, 39, 39, 39, 
-       39, 44, 39, 45, 45, 39, 39, 39, 
-       39, 39, 39, 39, 30, 39, 39, 39, 
-       39, 39, 26, 15, 19, 39, 39, 39, 
-       17, 23, 25, 21, 39, 40, 40, 39, 
-       39, 39, 39, 39, 39, 39, 30, 39, 
-       39, 39, 39, 39, 39, 15, 19, 39, 
-       39, 39, 17, 23, 25, 21, 39, 0
-};
-
-static const char _khmer_syllable_machine_trans_targs[] = {
-       20, 1, 28, 22, 23, 3, 24, 5, 
-       25, 7, 26, 9, 27, 20, 10, 31, 
-       20, 32, 12, 33, 14, 34, 16, 35, 
-       18, 36, 39, 20, 21, 30, 37, 20, 
-       0, 29, 2, 4, 6, 8, 20, 20, 
-       11, 13, 15, 17, 38, 19
-};
-
-static const char _khmer_syllable_machine_trans_actions[] = {
-       1, 0, 2, 2, 2, 0, 0, 0, 
-       2, 0, 2, 0, 2, 3, 0, 4, 
-       5, 2, 0, 0, 0, 2, 0, 2, 
-       0, 2, 4, 8, 2, 9, 0, 10, 
-       0, 0, 0, 0, 0, 0, 11, 12, 
-       0, 0, 0, 0, 4, 0
-};
-
-static const char _khmer_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, 6, 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, 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
-};
-
-static const unsigned char _khmer_syllable_machine_eof_trans[] = {
-       1, 1, 1, 1, 1, 1, 1, 1, 
-       1, 1, 14, 17, 17, 17, 17, 17, 
-       17, 17, 17, 17, 0, 32, 32, 32, 
-       32, 32, 32, 32, 32, 32, 39, 40, 
-       40, 40, 40, 40, 40, 40, 40, 40
-};
-
-static const int khmer_syllable_machine_start = 20;
-static const int khmer_syllable_machine_first_final = 20;
-static const int khmer_syllable_machine_error = -1;
-
-static const int khmer_syllable_machine_en_main = 20;
-
-
-#line 43 "hb-ot-shape-complex-khmer-machine.rl"
-
-
-
-#line 86 "hb-ot-shape-complex-khmer-machine.rl"
-
-
-#define found_syllable(syllable_type) \
-  HB_STMT_START { \
-    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; \
-    syllable_serial++; \
-    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
-  } HB_STMT_END
-
-static void
-find_syllables_khmer (hb_buffer_t *buffer)
-{
-  unsigned int p, pe, eof, ts, te, act HB_UNUSED;
-  int cs;
-  hb_glyph_info_t *info = buffer->info;
-  
-#line 266 "hb-ot-shape-complex-khmer-machine.hh"
-       {
-       cs = khmer_syllable_machine_start;
-       ts = 0;
-       te = 0;
-       act = 0;
-       }
-
-#line 106 "hb-ot-shape-complex-khmer-machine.rl"
-
-
-  p = 0;
-  pe = eof = buffer->len;
-
-  unsigned int syllable_serial = 1;
-  
-#line 282 "hb-ot-shape-complex-khmer-machine.hh"
-       {
-       int _slen;
-       int _trans;
-       const unsigned char *_keys;
-       const char *_inds;
-       if ( p == pe )
-               goto _test_eof;
-_resume:
-       switch ( _khmer_syllable_machine_from_state_actions[cs] ) {
-       case 7:
-#line 1 "NONE"
-       {ts = p;}
-       break;
-#line 296 "hb-ot-shape-complex-khmer-machine.hh"
-       }
-
-       _keys = _khmer_syllable_machine_trans_keys + (cs<<1);
-       _inds = _khmer_syllable_machine_indicies + _khmer_syllable_machine_index_offsets[cs];
-
-       _slen = _khmer_syllable_machine_key_spans[cs];
-       _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].khmer_category()) &&
-               ( info[p].khmer_category()) <= _keys[1] ?
-               ( info[p].khmer_category()) - _keys[0] : _slen ];
-
-_eof_trans:
-       cs = _khmer_syllable_machine_trans_targs[_trans];
-
-       if ( _khmer_syllable_machine_trans_actions[_trans] == 0 )
-               goto _again;
-
-       switch ( _khmer_syllable_machine_trans_actions[_trans] ) {
-       case 2:
-#line 1 "NONE"
-       {te = p+1;}
-       break;
-       case 8:
-#line 82 "hb-ot-shape-complex-khmer-machine.rl"
-       {te = p+1;{ found_syllable (khmer_non_khmer_cluster); }}
-       break;
-       case 10:
-#line 80 "hb-ot-shape-complex-khmer-machine.rl"
-       {te = p;p--;{ found_syllable (khmer_consonant_syllable); }}
-       break;
-       case 12:
-#line 81 "hb-ot-shape-complex-khmer-machine.rl"
-       {te = p;p--;{ found_syllable (khmer_broken_cluster); }}
-       break;
-       case 11:
-#line 82 "hb-ot-shape-complex-khmer-machine.rl"
-       {te = p;p--;{ found_syllable (khmer_non_khmer_cluster); }}
-       break;
-       case 1:
-#line 80 "hb-ot-shape-complex-khmer-machine.rl"
-       {{p = ((te))-1;}{ found_syllable (khmer_consonant_syllable); }}
-       break;
-       case 5:
-#line 81 "hb-ot-shape-complex-khmer-machine.rl"
-       {{p = ((te))-1;}{ found_syllable (khmer_broken_cluster); }}
-       break;
-       case 3:
-#line 1 "NONE"
-       {       switch( act ) {
-       case 2:
-       {{p = ((te))-1;} found_syllable (khmer_broken_cluster); }
-       break;
-       case 3:
-       {{p = ((te))-1;} found_syllable (khmer_non_khmer_cluster); }
-       break;
-       }
-       }
-       break;
-       case 4:
-#line 1 "NONE"
-       {te = p+1;}
-#line 81 "hb-ot-shape-complex-khmer-machine.rl"
-       {act = 2;}
-       break;
-       case 9:
-#line 1 "NONE"
-       {te = p+1;}
-#line 82 "hb-ot-shape-complex-khmer-machine.rl"
-       {act = 3;}
-       break;
-#line 366 "hb-ot-shape-complex-khmer-machine.hh"
-       }
-
-_again:
-       switch ( _khmer_syllable_machine_to_state_actions[cs] ) {
-       case 6:
-#line 1 "NONE"
-       {ts = 0;}
-       break;
-#line 375 "hb-ot-shape-complex-khmer-machine.hh"
-       }
-
-       if ( ++p != pe )
-               goto _resume;
-       _test_eof: {}
-       if ( p == eof )
-       {
-       if ( _khmer_syllable_machine_eof_trans[cs] > 0 ) {
-               _trans = _khmer_syllable_machine_eof_trans[cs] - 1;
-               goto _eof_trans;
-       }
-       }
-
-       }
-
-#line 114 "hb-ot-shape-complex-khmer-machine.rl"
-
-}
-
-#undef found_syllable
-
-#endif /* HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-khmer.hh b/src/hb-ot-shape-complex-khmer.hh
deleted file mode 100644 (file)
index 35bfbb6..0000000
+++ /dev/null
@@ -1,115 +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_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,
-};
-
-using khmer_position_t = indic_position_t;
-
-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 & 0xFFu);
-  khmer_position_t pos = (khmer_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 = (khmer_category_t) OT_VPre; break;
-      case POS_BELOW_C:        cat = (khmer_category_t) OT_VBlw; break;
-      case POS_ABOVE_C:        cat = (khmer_category_t) OT_VAbv; break;
-      case POS_POST_C: cat = (khmer_category_t) 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
deleted file mode 100644 (file)
index f4ef330..0000000
+++ /dev/null
@@ -1,492 +0,0 @@
-
-#line 1 "hb-ot-shape-complex-myanmar-machine.rl"
-/*
- * Copyright © 2011,2012  Google, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH
-
-#include "hb.hh"
-
-enum myanmar_syllable_type_t {
-  myanmar_consonant_syllable,
-  myanmar_punctuation_cluster,
-  myanmar_broken_cluster,
-  myanmar_non_myanmar_cluster,
-};
-
-
-#line 43 "hb-ot-shape-complex-myanmar-machine.hh"
-#define myanmar_syllable_machine_ex_A 10u
-#define myanmar_syllable_machine_ex_As 18u
-#define myanmar_syllable_machine_ex_C 1u
-#define myanmar_syllable_machine_ex_CS 19u
-#define myanmar_syllable_machine_ex_D 32u
-#define myanmar_syllable_machine_ex_D0 20u
-#define myanmar_syllable_machine_ex_DB 3u
-#define myanmar_syllable_machine_ex_GB 11u
-#define myanmar_syllable_machine_ex_H 4u
-#define myanmar_syllable_machine_ex_IV 2u
-#define myanmar_syllable_machine_ex_MH 21u
-#define myanmar_syllable_machine_ex_ML 33u
-#define myanmar_syllable_machine_ex_MR 22u
-#define myanmar_syllable_machine_ex_MW 23u
-#define myanmar_syllable_machine_ex_MY 24u
-#define myanmar_syllable_machine_ex_P 31u
-#define myanmar_syllable_machine_ex_PT 25u
-#define myanmar_syllable_machine_ex_Ra 16u
-#define myanmar_syllable_machine_ex_V 8u
-#define myanmar_syllable_machine_ex_VAbv 26u
-#define myanmar_syllable_machine_ex_VBlw 27u
-#define myanmar_syllable_machine_ex_VPre 28u
-#define myanmar_syllable_machine_ex_VPst 29u
-#define myanmar_syllable_machine_ex_VS 30u
-#define myanmar_syllable_machine_ex_ZWJ 6u
-#define myanmar_syllable_machine_ex_ZWNJ 5u
-
-
-#line 72 "hb-ot-shape-complex-myanmar-machine.hh"
-static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
-       1u, 33u, 3u, 33u, 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u, 
-       3u, 33u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 33u, 1u, 16u, 3u, 33u, 3u, 33u, 
-       3u, 29u, 3u, 29u, 3u, 29u, 3u, 30u, 3u, 29u, 3u, 33u, 3u, 33u, 3u, 33u, 
-       3u, 33u, 3u, 33u, 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u, 
-       3u, 33u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 33u, 1u, 16u, 3u, 33u, 3u, 33u, 
-       3u, 33u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 30u, 3u, 29u, 3u, 33u, 3u, 33u, 
-       3u, 33u, 3u, 33u, 3u, 33u, 3u, 33u, 3u, 33u, 1u, 33u, 1u, 32u, 8u, 8u, 
-       0
-};
-
-static const char _myanmar_syllable_machine_key_spans[] = {
-       33, 31, 25, 4, 25, 23, 21, 21, 
-       31, 27, 27, 27, 31, 16, 31, 31, 
-       27, 27, 27, 28, 27, 31, 31, 31, 
-       31, 31, 25, 4, 25, 23, 21, 21, 
-       31, 27, 27, 27, 31, 16, 31, 31, 
-       31, 27, 27, 27, 28, 27, 31, 31, 
-       31, 31, 31, 31, 31, 33, 32, 1
-};
-
-static const short _myanmar_syllable_machine_index_offsets[] = {
-       0, 34, 66, 92, 97, 123, 147, 169, 
-       191, 223, 251, 279, 307, 339, 356, 388, 
-       420, 448, 476, 504, 533, 561, 593, 625, 
-       657, 689, 721, 747, 752, 778, 802, 824, 
-       846, 878, 906, 934, 962, 994, 1011, 1043, 
-       1075, 1107, 1135, 1163, 1191, 1220, 1248, 1280, 
-       1312, 1344, 1376, 1408, 1440, 1472, 1506, 1539
-};
-
-static const char _myanmar_syllable_machine_indicies[] = {
-       1, 1, 2, 3, 4, 4, 0, 5, 
-       0, 6, 1, 0, 0, 0, 0, 7, 
-       0, 8, 9, 0, 10, 11, 12, 13, 
-       14, 15, 16, 17, 18, 19, 20, 1, 
-       21, 0, 23, 24, 25, 25, 22, 26, 
-       22, 27, 22, 22, 22, 22, 22, 22, 
-       22, 28, 22, 22, 29, 30, 31, 32, 
-       33, 34, 35, 36, 37, 38, 22, 22, 
-       39, 22, 25, 25, 22, 26, 22, 22, 
-       22, 22, 22, 22, 22, 22, 22, 40, 
-       22, 22, 22, 22, 22, 22, 33, 22, 
-       22, 22, 37, 22, 25, 25, 22, 26, 
-       22, 25, 25, 22, 26, 22, 22, 22, 
-       22, 22, 22, 22, 22, 22, 22, 22, 
-       22, 22, 22, 22, 22, 33, 22, 22, 
-       22, 37, 22, 41, 22, 25, 25, 22, 
-       26, 22, 33, 22, 22, 22, 22, 22, 
-       22, 22, 42, 22, 22, 22, 22, 22, 
-       22, 33, 22, 25, 25, 22, 26, 22, 
-       22, 22, 22, 22, 22, 22, 22, 22, 
-       42, 22, 22, 22, 22, 22, 22, 33, 
-       22, 25, 25, 22, 26, 22, 22, 22, 
-       22, 22, 22, 22, 22, 22, 22, 22, 
-       22, 22, 22, 22, 22, 33, 22, 23, 
-       22, 25, 25, 22, 26, 22, 27, 22, 
-       22, 22, 22, 22, 22, 22, 43, 22, 
-       22, 44, 22, 22, 22, 33, 45, 22, 
-       22, 37, 22, 22, 22, 43, 22, 23, 
-       22, 25, 25, 22, 26, 22, 27, 22, 
-       22, 22, 22, 22, 22, 22, 22, 22, 
-       22, 22, 22, 22, 22, 33, 22, 22, 
-       22, 37, 22, 23, 22, 25, 25, 22, 
-       26, 22, 27, 22, 22, 22, 22, 22, 
-       22, 22, 43, 22, 22, 22, 22, 22, 
-       22, 33, 45, 22, 22, 37, 22, 23, 
-       22, 25, 25, 22, 26, 22, 27, 22, 
-       22, 22, 22, 22, 22, 22, 22, 22, 
-       22, 22, 22, 22, 22, 33, 45, 22, 
-       22, 37, 22, 23, 22, 25, 25, 22, 
-       26, 22, 27, 22, 22, 22, 22, 22, 
-       22, 22, 43, 22, 22, 22, 22, 22, 
-       22, 33, 45, 22, 22, 37, 22, 22, 
-       22, 43, 22, 1, 1, 22, 22, 22, 
-       22, 22, 22, 22, 22, 22, 22, 22, 
-       22, 22, 1, 22, 23, 22, 25, 25, 
-       22, 26, 22, 27, 22, 22, 22, 22, 
-       22, 22, 22, 28, 22, 22, 29, 30, 
-       31, 32, 33, 34, 35, 36, 37, 22, 
-       22, 22, 39, 22, 23, 22, 25, 25, 
-       22, 26, 22, 27, 22, 22, 22, 22, 
-       22, 22, 22, 46, 22, 22, 22, 22, 
-       22, 22, 33, 34, 35, 36, 37, 22, 
-       22, 22, 39, 22, 23, 22, 25, 25, 
-       22, 26, 22, 27, 22, 22, 22, 22, 
-       22, 22, 22, 22, 22, 22, 22, 22, 
-       22, 22, 33, 34, 35, 36, 37, 22, 
-       23, 22, 25, 25, 22, 26, 22, 27, 
-       22, 22, 22, 22, 22, 22, 22, 22, 
-       22, 22, 22, 22, 22, 22, 33, 34, 
-       35, 22, 37, 22, 23, 22, 25, 25, 
-       22, 26, 22, 27, 22, 22, 22, 22, 
-       22, 22, 22, 22, 22, 22, 22, 22, 
-       22, 22, 33, 22, 35, 22, 37, 22, 
-       23, 22, 25, 25, 22, 26, 22, 27, 
-       22, 22, 22, 22, 22, 22, 22, 22, 
-       22, 22, 22, 22, 22, 22, 33, 34, 
-       35, 36, 37, 46, 22, 23, 22, 25, 
-       25, 22, 26, 22, 27, 22, 22, 22, 
-       22, 22, 22, 22, 46, 22, 22, 22, 
-       22, 22, 22, 33, 34, 35, 36, 37, 
-       22, 23, 22, 25, 25, 22, 26, 22, 
-       27, 22, 22, 22, 22, 22, 22, 22, 
-       22, 22, 22, 29, 22, 31, 22, 33, 
-       34, 35, 36, 37, 22, 22, 22, 39, 
-       22, 23, 22, 25, 25, 22, 26, 22, 
-       27, 22, 22, 22, 22, 22, 22, 22, 
-       46, 22, 22, 29, 22, 22, 22, 33, 
-       34, 35, 36, 37, 22, 22, 22, 39, 
-       22, 23, 22, 25, 25, 22, 26, 22, 
-       27, 22, 22, 22, 22, 22, 22, 22, 
-       47, 22, 22, 29, 30, 31, 22, 33, 
-       34, 35, 36, 37, 22, 22, 22, 39, 
-       22, 23, 22, 25, 25, 22, 26, 22, 
-       27, 22, 22, 22, 22, 22, 22, 22, 
-       22, 22, 22, 29, 30, 31, 22, 33, 
-       34, 35, 36, 37, 22, 22, 22, 39, 
-       22, 23, 24, 25, 25, 22, 26, 22, 
-       27, 22, 22, 22, 22, 22, 22, 22, 
-       28, 22, 22, 29, 30, 31, 32, 33, 
-       34, 35, 36, 37, 22, 22, 22, 39, 
-       22, 49, 49, 48, 5, 48, 48, 48, 
-       48, 48, 48, 48, 48, 48, 50, 48, 
-       48, 48, 48, 48, 48, 14, 48, 48, 
-       48, 18, 48, 49, 49, 48, 5, 48, 
-       49, 49, 48, 5, 48, 48, 48, 48, 
-       48, 48, 48, 48, 48, 48, 48, 48, 
-       48, 48, 48, 48, 14, 48, 48, 48, 
-       18, 48, 51, 48, 49, 49, 48, 5, 
-       48, 14, 48, 48, 48, 48, 48, 48, 
-       48, 52, 48, 48, 48, 48, 48, 48, 
-       14, 48, 49, 49, 48, 5, 48, 48, 
-       48, 48, 48, 48, 48, 48, 48, 52, 
-       48, 48, 48, 48, 48, 48, 14, 48, 
-       49, 49, 48, 5, 48, 48, 48, 48, 
-       48, 48, 48, 48, 48, 48, 48, 48, 
-       48, 48, 48, 48, 14, 48, 2, 48, 
-       49, 49, 48, 5, 48, 6, 48, 48, 
-       48, 48, 48, 48, 48, 53, 48, 48, 
-       54, 48, 48, 48, 14, 55, 48, 48, 
-       18, 48, 48, 48, 53, 48, 2, 48, 
-       49, 49, 48, 5, 48, 6, 48, 48, 
-       48, 48, 48, 48, 48, 48, 48, 48, 
-       48, 48, 48, 48, 14, 48, 48, 48, 
-       18, 48, 2, 48, 49, 49, 48, 5, 
-       48, 6, 48, 48, 48, 48, 48, 48, 
-       48, 53, 48, 48, 48, 48, 48, 48, 
-       14, 55, 48, 48, 18, 48, 2, 48, 
-       49, 49, 48, 5, 48, 6, 48, 48, 
-       48, 48, 48, 48, 48, 48, 48, 48, 
-       48, 48, 48, 48, 14, 55, 48, 48, 
-       18, 48, 2, 48, 49, 49, 48, 5, 
-       48, 6, 48, 48, 48, 48, 48, 48, 
-       48, 53, 48, 48, 48, 48, 48, 48, 
-       14, 55, 48, 48, 18, 48, 48, 48, 
-       53, 48, 56, 56, 48, 48, 48, 48, 
-       48, 48, 48, 48, 48, 48, 48, 48, 
-       48, 56, 48, 2, 3, 49, 49, 48, 
-       5, 48, 6, 48, 48, 48, 48, 48, 
-       48, 48, 8, 48, 48, 10, 11, 12, 
-       13, 14, 15, 16, 17, 18, 19, 48, 
-       48, 21, 48, 2, 48, 49, 49, 48, 
-       5, 48, 6, 48, 48, 48, 48, 48, 
-       48, 48, 8, 48, 48, 10, 11, 12, 
-       13, 14, 15, 16, 17, 18, 48, 48, 
-       48, 21, 48, 2, 48, 49, 49, 48, 
-       5, 48, 6, 48, 48, 48, 48, 48, 
-       48, 48, 57, 48, 48, 48, 48, 48, 
-       48, 14, 15, 16, 17, 18, 48, 48, 
-       48, 21, 48, 2, 48, 49, 49, 48, 
-       5, 48, 6, 48, 48, 48, 48, 48, 
-       48, 48, 48, 48, 48, 48, 48, 48, 
-       48, 14, 15, 16, 17, 18, 48, 2, 
-       48, 49, 49, 48, 5, 48, 6, 48, 
-       48, 48, 48, 48, 48, 48, 48, 48, 
-       48, 48, 48, 48, 48, 14, 15, 16, 
-       48, 18, 48, 2, 48, 49, 49, 48, 
-       5, 48, 6, 48, 48, 48, 48, 48, 
-       48, 48, 48, 48, 48, 48, 48, 48, 
-       48, 14, 48, 16, 48, 18, 48, 2, 
-       48, 49, 49, 48, 5, 48, 6, 48, 
-       48, 48, 48, 48, 48, 48, 48, 48, 
-       48, 48, 48, 48, 48, 14, 15, 16, 
-       17, 18, 57, 48, 2, 48, 49, 49, 
-       48, 5, 48, 6, 48, 48, 48, 48, 
-       48, 48, 48, 57, 48, 48, 48, 48, 
-       48, 48, 14, 15, 16, 17, 18, 48, 
-       2, 48, 49, 49, 48, 5, 48, 6, 
-       48, 48, 48, 48, 48, 48, 48, 48, 
-       48, 48, 10, 48, 12, 48, 14, 15, 
-       16, 17, 18, 48, 48, 48, 21, 48, 
-       2, 48, 49, 49, 48, 5, 48, 6, 
-       48, 48, 48, 48, 48, 48, 48, 57, 
-       48, 48, 10, 48, 48, 48, 14, 15, 
-       16, 17, 18, 48, 48, 48, 21, 48, 
-       2, 48, 49, 49, 48, 5, 48, 6, 
-       48, 48, 48, 48, 48, 48, 48, 58, 
-       48, 48, 10, 11, 12, 48, 14, 15, 
-       16, 17, 18, 48, 48, 48, 21, 48, 
-       2, 48, 49, 49, 48, 5, 48, 6, 
-       48, 48, 48, 48, 48, 48, 48, 48, 
-       48, 48, 10, 11, 12, 48, 14, 15, 
-       16, 17, 18, 48, 48, 48, 21, 48, 
-       2, 3, 49, 49, 48, 5, 48, 6, 
-       48, 48, 48, 48, 48, 48, 48, 8, 
-       48, 48, 10, 11, 12, 13, 14, 15, 
-       16, 17, 18, 48, 48, 48, 21, 48, 
-       23, 24, 25, 25, 22, 26, 22, 27, 
-       22, 22, 22, 22, 22, 22, 22, 59, 
-       22, 22, 29, 30, 31, 32, 33, 34, 
-       35, 36, 37, 38, 22, 22, 39, 22, 
-       23, 60, 25, 25, 22, 26, 22, 27, 
-       22, 22, 22, 22, 22, 22, 22, 28, 
-       22, 22, 29, 30, 31, 32, 33, 34, 
-       35, 36, 37, 22, 22, 22, 39, 22, 
-       1, 1, 2, 3, 49, 49, 48, 5, 
-       48, 6, 1, 48, 48, 48, 48, 1, 
-       48, 8, 48, 48, 10, 11, 12, 13, 
-       14, 15, 16, 17, 18, 19, 48, 1, 
-       21, 48, 1, 1, 61, 61, 61, 61, 
-       61, 61, 61, 61, 1, 61, 61, 61, 
-       61, 1, 61, 61, 61, 61, 61, 61, 
-       61, 61, 61, 61, 61, 61, 61, 61, 
-       61, 1, 61, 62, 61, 0
-};
-
-static const char _myanmar_syllable_machine_trans_targs[] = {
-       0, 1, 26, 37, 0, 27, 33, 51, 
-       39, 54, 40, 46, 47, 48, 29, 42, 
-       43, 44, 32, 50, 55, 45, 0, 2, 
-       13, 0, 3, 9, 14, 15, 21, 22, 
-       23, 5, 17, 18, 19, 8, 25, 20, 
-       4, 6, 7, 10, 12, 11, 16, 24, 
-       0, 0, 28, 30, 31, 34, 36, 35, 
-       38, 41, 49, 52, 53, 0, 0
-};
-
-static const char _myanmar_syllable_machine_trans_actions[] = {
-       3, 0, 0, 0, 4, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 5, 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, 
-       7, 8, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 9, 10
-};
-
-static const char _myanmar_syllable_machine_to_state_actions[] = {
-       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, 
-       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 _myanmar_syllable_machine_from_state_actions[] = {
-       2, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       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 _myanmar_syllable_machine_eof_trans[] = {
-       0, 23, 23, 23, 23, 23, 23, 23, 
-       23, 23, 23, 23, 23, 23, 23, 23, 
-       23, 23, 23, 23, 23, 23, 23, 23, 
-       23, 23, 49, 49, 49, 49, 49, 49, 
-       49, 49, 49, 49, 49, 49, 49, 49, 
-       49, 49, 49, 49, 49, 49, 49, 49, 
-       49, 49, 49, 23, 23, 49, 62, 62
-};
-
-static const int myanmar_syllable_machine_start = 0;
-static const int myanmar_syllable_machine_first_final = 0;
-static const int myanmar_syllable_machine_error = -1;
-
-static const int myanmar_syllable_machine_en_main = 0;
-
-
-#line 44 "hb-ot-shape-complex-myanmar-machine.rl"
-
-
-
-#line 102 "hb-ot-shape-complex-myanmar-machine.rl"
-
-
-#define found_syllable(syllable_type) \
-  HB_STMT_START { \
-    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; \
-    syllable_serial++; \
-    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
-  } HB_STMT_END
-
-static void
-find_syllables_myanmar (hb_buffer_t *buffer)
-{
-  unsigned int p, pe, eof, ts, te, act HB_UNUSED;
-  int cs;
-  hb_glyph_info_t *info = buffer->info;
-  
-#line 382 "hb-ot-shape-complex-myanmar-machine.hh"
-       {
-       cs = myanmar_syllable_machine_start;
-       ts = 0;
-       te = 0;
-       act = 0;
-       }
-
-#line 122 "hb-ot-shape-complex-myanmar-machine.rl"
-
-
-  p = 0;
-  pe = eof = buffer->len;
-
-  unsigned int syllable_serial = 1;
-  
-#line 398 "hb-ot-shape-complex-myanmar-machine.hh"
-       {
-       int _slen;
-       int _trans;
-       const unsigned char *_keys;
-       const char *_inds;
-       if ( p == pe )
-               goto _test_eof;
-_resume:
-       switch ( _myanmar_syllable_machine_from_state_actions[cs] ) {
-       case 2:
-#line 1 "NONE"
-       {ts = p;}
-       break;
-#line 412 "hb-ot-shape-complex-myanmar-machine.hh"
-       }
-
-       _keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
-       _inds = _myanmar_syllable_machine_indicies + _myanmar_syllable_machine_index_offsets[cs];
-
-       _slen = _myanmar_syllable_machine_key_spans[cs];
-       _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].myanmar_category()) &&
-               ( info[p].myanmar_category()) <= _keys[1] ?
-               ( info[p].myanmar_category()) - _keys[0] : _slen ];
-
-_eof_trans:
-       cs = _myanmar_syllable_machine_trans_targs[_trans];
-
-       if ( _myanmar_syllable_machine_trans_actions[_trans] == 0 )
-               goto _again;
-
-       switch ( _myanmar_syllable_machine_trans_actions[_trans] ) {
-       case 6:
-#line 94 "hb-ot-shape-complex-myanmar-machine.rl"
-       {te = p+1;{ found_syllable (myanmar_consonant_syllable); }}
-       break;
-       case 4:
-#line 95 "hb-ot-shape-complex-myanmar-machine.rl"
-       {te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }}
-       break;
-       case 10:
-#line 96 "hb-ot-shape-complex-myanmar-machine.rl"
-       {te = p+1;{ found_syllable (myanmar_punctuation_cluster); }}
-       break;
-       case 8:
-#line 97 "hb-ot-shape-complex-myanmar-machine.rl"
-       {te = p+1;{ found_syllable (myanmar_broken_cluster); }}
-       break;
-       case 3:
-#line 98 "hb-ot-shape-complex-myanmar-machine.rl"
-       {te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }}
-       break;
-       case 5:
-#line 94 "hb-ot-shape-complex-myanmar-machine.rl"
-       {te = p;p--;{ found_syllable (myanmar_consonant_syllable); }}
-       break;
-       case 7:
-#line 97 "hb-ot-shape-complex-myanmar-machine.rl"
-       {te = p;p--;{ found_syllable (myanmar_broken_cluster); }}
-       break;
-       case 9:
-#line 98 "hb-ot-shape-complex-myanmar-machine.rl"
-       {te = p;p--;{ found_syllable (myanmar_non_myanmar_cluster); }}
-       break;
-#line 462 "hb-ot-shape-complex-myanmar-machine.hh"
-       }
-
-_again:
-       switch ( _myanmar_syllable_machine_to_state_actions[cs] ) {
-       case 1:
-#line 1 "NONE"
-       {ts = 0;}
-       break;
-#line 471 "hb-ot-shape-complex-myanmar-machine.hh"
-       }
-
-       if ( ++p != pe )
-               goto _resume;
-       _test_eof: {}
-       if ( p == eof )
-       {
-       if ( _myanmar_syllable_machine_eof_trans[cs] > 0 ) {
-               _trans = _myanmar_syllable_machine_eof_trans[cs] - 1;
-               goto _eof_trans;
-       }
-       }
-
-       }
-
-#line 130 "hb-ot-shape-complex-myanmar-machine.rl"
-
-}
-
-#undef found_syllable
-
-#endif /* HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-myanmar.hh b/src/hb-ot-shape-complex-myanmar.hh
deleted file mode 100644 (file)
index 7fbca38..0000000
+++ /dev/null
@@ -1,177 +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_MYANMAR_HH
-#define HB_OT_SHAPE_COMPLEX_MYANMAR_HH
-
-#include "hb.hh"
-
-#include "hb-ot-shape-complex-indic.hh"
-
-
-/* buffer var allocations */
-#define myanmar_category() indic_category() /* myanmar_category_t */
-#define myanmar_position() indic_position() /* myanmar_position_t */
-
-
-/* Note: This enum is duplicated in the -machine.rl source file.
- * Not sure how to avoid duplication. */
-enum myanmar_category_t {
-  OT_As  = 18,  /* Asat */
-  OT_D0  = 20, /* Digit zero */
-  OT_DB  = OT_N, /* Dot below */
-  OT_GB  = OT_PLACEHOLDER,
-  OT_MH  = 21, /* Various consonant medial types */
-  OT_MR  = 22, /* Various consonant medial types */
-  OT_MW  = 23, /* Various consonant medial types */
-  OT_MY  = 24, /* Various consonant medial types */
-  OT_PT  = 25, /* Pwo and other tones */
-  //OT_VAbv = 26,
-  //OT_VBlw = 27,
-  //OT_VPre = 28,
-  //OT_VPst = 29,
-  OT_VS   = 30, /* Variation selectors */
-  OT_P    = 31, /* Punctuation */
-  OT_D    = 32, /* Digits except zero */
-  OT_ML   = 33, /* Various consonant medial types */
-};
-
-using myanmar_position_t = indic_position_t;
-
-static inline void
-set_myanmar_properties (hb_glyph_info_t &info)
-{
-  hb_codepoint_t u = info.codepoint;
-  unsigned int type = hb_indic_get_categories (u);
-  unsigned int cat = type & 0xFFu;
-  myanmar_position_t pos = (myanmar_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 = OT_VS;
-
-  switch (u)
-  {
-    case 0x104Eu:
-      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 = OT_GB;
-      break;
-
-    case 0x1004u: case 0x101Bu: case 0x105Au:
-      cat = OT_Ra;
-      break;
-
-    case 0x1032u: case 0x1036u:
-      cat = OT_A;
-      break;
-
-    case 0x1039u:
-      cat = OT_H;
-      break;
-
-    case 0x103Au:
-      cat = OT_As;
-      break;
-
-    case 0x1041u: case 0x1042u: case 0x1043u: case 0x1044u:
-    case 0x1045u: case 0x1046u: case 0x1047u: case 0x1048u:
-    case 0x1049u: case 0x1090u: case 0x1091u: case 0x1092u:
-    case 0x1093u: case 0x1094u: case 0x1095u: case 0x1096u:
-    case 0x1097u: case 0x1098u: case 0x1099u:
-      cat = OT_D;
-      break;
-
-    case 0x1040u:
-      cat = OT_D; /* XXX The spec says D0, but Uniscribe doesn't seem to do. */
-      break;
-
-    case 0x103Eu:
-      cat = OT_MH;
-      break;
-
-    case 0x1060u:
-      cat = OT_ML;
-      break;
-
-    case 0x103Cu:
-      cat = OT_MR;
-      break;
-
-    case 0x103Du: case 0x1082u:
-      cat = OT_MW;
-      break;
-
-    case 0x103Bu: case 0x105Eu: case 0x105Fu:
-      cat = OT_MY;
-      break;
-
-    case 0x1063u: case 0x1064u: case 0x1069u: case 0x106Au:
-    case 0x106Bu: case 0x106Cu: case 0x106Du: case 0xAA7Bu:
-      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 = OT_SM;
-      break;
-
-    case 0x104Au: case 0x104Bu:
-      cat = OT_P;
-      break;
-
-    case 0xAA74u: case 0xAA75u: case 0xAA76u:
-      /* https://github.com/harfbuzz/harfbuzz/issues/218 */
-      cat = OT_C;
-      break;
-  }
-
-  if (cat == OT_M)
-  {
-    switch ((int) pos)
-    {
-      case POS_PRE_C:  cat = (myanmar_category_t) OT_VPre;
-                       pos = POS_PRE_M; break;
-      case POS_ABOVE_C:        cat = (myanmar_category_t) OT_VAbv;   break;
-      case POS_BELOW_C:        cat = (myanmar_category_t) OT_VBlw;   break;
-      case POS_POST_C: cat = (myanmar_category_t) OT_VPst;   break;
-    }
-  }
-
-  info.myanmar_category() = cat;
-  info.myanmar_position() = pos;
-}
-
-
-#endif /* HB_OT_SHAPE_COMPLEX_MYANMAR_HH */
diff --git a/src/hb-ot-shape-complex-use-machine.hh b/src/hb-ot-shape-complex-use-machine.hh
deleted file mode 100644 (file)
index c3920b2..0000000
+++ /dev/null
@@ -1,576 +0,0 @@
-
-#line 1 "hb-ot-shape-complex-use-machine.rl"
-/*
- * Copyright © 2015  Mozilla Foundation.
- * Copyright © 2015  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.
- *
- * Mozilla Author(s): Jonathan Kew
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
-
-#include "hb.hh"
-
-#include "hb-ot-shape-complex-syllabic.hh"
-
-/* buffer var allocations */
-#define use_category() complex_var_u8_category()
-
-#define USE(Cat) use_syllable_machine_ex_##Cat
-
-enum use_syllable_type_t {
-  use_virama_terminated_cluster,
-  use_sakot_terminated_cluster,
-  use_standard_cluster,
-  use_number_joiner_terminated_cluster,
-  use_numeral_cluster,
-  use_symbol_cluster,
-  use_hieroglyph_cluster,
-  use_broken_cluster,
-  use_non_cluster,
-};
-
-
-#line 57 "hb-ot-shape-complex-use-machine.hh"
-#define use_syllable_machine_ex_B 1u
-#define use_syllable_machine_ex_CGJ 6u
-#define use_syllable_machine_ex_CMAbv 31u
-#define use_syllable_machine_ex_CMBlw 32u
-#define use_syllable_machine_ex_CS 43u
-#define use_syllable_machine_ex_FAbv 24u
-#define use_syllable_machine_ex_FBlw 25u
-#define use_syllable_machine_ex_FMAbv 45u
-#define use_syllable_machine_ex_FMBlw 46u
-#define use_syllable_machine_ex_FMPst 47u
-#define use_syllable_machine_ex_FPst 26u
-#define use_syllable_machine_ex_G 49u
-#define use_syllable_machine_ex_GB 5u
-#define use_syllable_machine_ex_H 12u
-#define use_syllable_machine_ex_HN 13u
-#define use_syllable_machine_ex_HVM 44u
-#define use_syllable_machine_ex_J 50u
-#define use_syllable_machine_ex_MAbv 27u
-#define use_syllable_machine_ex_MBlw 28u
-#define use_syllable_machine_ex_MPre 30u
-#define use_syllable_machine_ex_MPst 29u
-#define use_syllable_machine_ex_N 4u
-#define use_syllable_machine_ex_O 0u
-#define use_syllable_machine_ex_R 18u
-#define use_syllable_machine_ex_SB 51u
-#define use_syllable_machine_ex_SE 52u
-#define use_syllable_machine_ex_SMAbv 41u
-#define use_syllable_machine_ex_SMBlw 42u
-#define use_syllable_machine_ex_SUB 11u
-#define use_syllable_machine_ex_Sk 48u
-#define use_syllable_machine_ex_VAbv 33u
-#define use_syllable_machine_ex_VBlw 34u
-#define use_syllable_machine_ex_VMAbv 37u
-#define use_syllable_machine_ex_VMBlw 38u
-#define use_syllable_machine_ex_VMPre 23u
-#define use_syllable_machine_ex_VMPst 39u
-#define use_syllable_machine_ex_VPre 22u
-#define use_syllable_machine_ex_VPst 35u
-#define use_syllable_machine_ex_ZWNJ 14u
-
-
-#line 99 "hb-ot-shape-complex-use-machine.hh"
-static const unsigned char _use_syllable_machine_trans_keys[] = {
-       0u, 51u, 41u, 42u, 42u, 42u, 11u, 48u, 11u, 48u, 1u, 1u, 22u, 48u, 23u, 48u, 
-       24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, 
-       1u, 1u, 24u, 48u, 23u, 48u, 23u, 48u, 23u, 48u, 22u, 48u, 22u, 48u, 22u, 48u, 
-       11u, 48u, 1u, 48u, 13u, 13u, 4u, 4u, 11u, 48u, 11u, 48u, 1u, 1u, 22u, 48u, 
-       23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 
-       24u, 48u, 1u, 1u, 24u, 48u, 23u, 48u, 23u, 48u, 23u, 48u, 22u, 48u, 22u, 48u, 
-       22u, 48u, 11u, 48u, 1u, 48u, 4u, 4u, 13u, 13u, 1u, 48u, 11u, 48u, 41u, 42u, 
-       42u, 42u, 1u, 5u, 50u, 52u, 49u, 52u, 49u, 51u, 0
-};
-
-static const char _use_syllable_machine_key_spans[] = {
-       52, 2, 1, 38, 38, 1, 27, 26, 
-       24, 23, 22, 2, 1, 25, 25, 25, 
-       1, 25, 26, 26, 26, 27, 27, 27, 
-       38, 48, 1, 1, 38, 38, 1, 27, 
-       26, 24, 23, 22, 2, 1, 25, 25, 
-       25, 1, 25, 26, 26, 26, 27, 27, 
-       27, 38, 48, 1, 1, 48, 38, 2, 
-       1, 5, 3, 4, 3
-};
-
-static const short _use_syllable_machine_index_offsets[] = {
-       0, 53, 56, 58, 97, 136, 138, 166, 
-       193, 218, 242, 265, 268, 270, 296, 322, 
-       348, 350, 376, 403, 430, 457, 485, 513, 
-       541, 580, 629, 631, 633, 672, 711, 713, 
-       741, 768, 793, 817, 840, 843, 845, 871, 
-       897, 923, 925, 951, 978, 1005, 1032, 1060, 
-       1088, 1116, 1155, 1204, 1206, 1208, 1257, 1296, 
-       1299, 1301, 1307, 1311, 1316
-};
-
-static const char _use_syllable_machine_indicies[] = {
-       0, 1, 2, 2, 3, 4, 2, 2, 
-       2, 2, 2, 5, 6, 7, 2, 2, 
-       2, 2, 8, 2, 2, 2, 9, 10, 
-       11, 12, 13, 14, 15, 9, 16, 17, 
-       18, 19, 20, 21, 2, 22, 23, 24, 
-       2, 25, 26, 27, 28, 29, 30, 31, 
-       6, 32, 2, 33, 2, 0, 35, 34, 
-       35, 34, 37, 38, 36, 36, 36, 36, 
-       36, 36, 36, 36, 36, 39, 40, 41, 
-       42, 43, 44, 45, 39, 46, 1, 47, 
-       48, 49, 50, 36, 51, 52, 53, 36, 
-       36, 36, 36, 54, 55, 56, 57, 38, 
-       36, 37, 38, 36, 36, 36, 36, 36, 
-       36, 36, 36, 36, 39, 40, 41, 42, 
-       43, 44, 45, 39, 46, 47, 47, 48, 
-       49, 50, 36, 51, 52, 53, 36, 36, 
-       36, 36, 54, 55, 56, 57, 38, 36, 
-       37, 58, 39, 40, 41, 42, 43, 36, 
-       36, 36, 36, 36, 36, 48, 49, 50, 
-       36, 51, 52, 53, 36, 36, 36, 36, 
-       40, 55, 56, 57, 59, 36, 40, 41, 
-       42, 43, 36, 36, 36, 36, 36, 36, 
-       36, 36, 36, 36, 51, 52, 53, 36, 
-       36, 36, 36, 36, 55, 56, 57, 59, 
-       36, 41, 42, 43, 36, 36, 36, 36, 
-       36, 36, 36, 36, 36, 36, 36, 36, 
-       36, 36, 36, 36, 36, 36, 55, 56, 
-       57, 36, 42, 43, 36, 36, 36, 36, 
-       36, 36, 36, 36, 36, 36, 36, 36, 
-       36, 36, 36, 36, 36, 36, 55, 56, 
-       57, 36, 43, 36, 36, 36, 36, 36, 
-       36, 36, 36, 36, 36, 36, 36, 36, 
-       36, 36, 36, 36, 36, 55, 56, 57, 
-       36, 55, 56, 36, 56, 36, 41, 42, 
-       43, 36, 36, 36, 36, 36, 36, 36, 
-       36, 36, 36, 51, 52, 53, 36, 36, 
-       36, 36, 36, 55, 56, 57, 59, 36, 
-       41, 42, 43, 36, 36, 36, 36, 36, 
-       36, 36, 36, 36, 36, 36, 52, 53, 
-       36, 36, 36, 36, 36, 55, 56, 57, 
-       59, 36, 41, 42, 43, 36, 36, 36, 
-       36, 36, 36, 36, 36, 36, 36, 36, 
-       36, 53, 36, 36, 36, 36, 36, 55, 
-       56, 57, 59, 36, 61, 60, 41, 42, 
-       43, 36, 36, 36, 36, 36, 36, 36, 
-       36, 36, 36, 36, 36, 36, 36, 36, 
-       36, 36, 36, 55, 56, 57, 59, 36, 
-       40, 41, 42, 43, 36, 36, 36, 36, 
-       36, 36, 48, 49, 50, 36, 51, 52, 
-       53, 36, 36, 36, 36, 40, 55, 56, 
-       57, 59, 36, 40, 41, 42, 43, 36, 
-       36, 36, 36, 36, 36, 36, 49, 50, 
-       36, 51, 52, 53, 36, 36, 36, 36, 
-       40, 55, 56, 57, 59, 36, 40, 41, 
-       42, 43, 36, 36, 36, 36, 36, 36, 
-       36, 36, 50, 36, 51, 52, 53, 36, 
-       36, 36, 36, 40, 55, 56, 57, 59, 
-       36, 39, 40, 41, 42, 43, 36, 45, 
-       39, 36, 36, 36, 48, 49, 50, 36, 
-       51, 52, 53, 36, 36, 36, 36, 40, 
-       55, 56, 57, 59, 36, 39, 40, 41, 
-       42, 43, 36, 36, 39, 36, 36, 36, 
-       48, 49, 50, 36, 51, 52, 53, 36, 
-       36, 36, 36, 40, 55, 56, 57, 59, 
-       36, 39, 40, 41, 42, 43, 44, 45, 
-       39, 36, 36, 36, 48, 49, 50, 36, 
-       51, 52, 53, 36, 36, 36, 36, 40, 
-       55, 56, 57, 59, 36, 37, 38, 36, 
-       36, 36, 36, 36, 36, 36, 36, 36, 
-       39, 40, 41, 42, 43, 44, 45, 39, 
-       46, 36, 47, 48, 49, 50, 36, 51, 
-       52, 53, 36, 36, 36, 36, 54, 55, 
-       56, 57, 38, 36, 37, 58, 58, 58, 
-       58, 58, 58, 58, 58, 58, 58, 58, 
-       58, 58, 58, 58, 58, 58, 58, 58, 
-       58, 58, 40, 41, 42, 43, 58, 58, 
-       58, 58, 58, 58, 58, 58, 58, 58, 
-       51, 52, 53, 58, 58, 58, 58, 58, 
-       55, 56, 57, 59, 58, 63, 62, 3, 
-       64, 37, 38, 36, 36, 36, 36, 36, 
-       36, 36, 36, 36, 39, 40, 41, 42, 
-       43, 44, 45, 39, 46, 1, 47, 48, 
-       49, 50, 36, 51, 52, 53, 36, 0, 
-       35, 36, 54, 55, 56, 57, 38, 36, 
-       5, 6, 65, 65, 65, 65, 65, 65, 
-       65, 65, 65, 9, 10, 11, 12, 13, 
-       14, 15, 9, 16, 18, 18, 19, 20, 
-       21, 65, 22, 23, 24, 65, 65, 65, 
-       65, 28, 29, 30, 31, 6, 65, 5, 
-       65, 9, 10, 11, 12, 13, 65, 65, 
-       65, 65, 65, 65, 19, 20, 21, 65, 
-       22, 23, 24, 65, 65, 65, 65, 10, 
-       29, 30, 31, 66, 65, 10, 11, 12, 
-       13, 65, 65, 65, 65, 65, 65, 65, 
-       65, 65, 65, 22, 23, 24, 65, 65, 
-       65, 65, 65, 29, 30, 31, 66, 65, 
-       11, 12, 13, 65, 65, 65, 65, 65, 
-       65, 65, 65, 65, 65, 65, 65, 65, 
-       65, 65, 65, 65, 65, 29, 30, 31, 
-       65, 12, 13, 65, 65, 65, 65, 65, 
-       65, 65, 65, 65, 65, 65, 65, 65, 
-       65, 65, 65, 65, 65, 29, 30, 31, 
-       65, 13, 65, 65, 65, 65, 65, 65, 
-       65, 65, 65, 65, 65, 65, 65, 65, 
-       65, 65, 65, 65, 29, 30, 31, 65, 
-       29, 30, 65, 30, 65, 11, 12, 13, 
-       65, 65, 65, 65, 65, 65, 65, 65, 
-       65, 65, 22, 23, 24, 65, 65, 65, 
-       65, 65, 29, 30, 31, 66, 65, 11, 
-       12, 13, 65, 65, 65, 65, 65, 65, 
-       65, 65, 65, 65, 65, 23, 24, 65, 
-       65, 65, 65, 65, 29, 30, 31, 66, 
-       65, 11, 12, 13, 65, 65, 65, 65, 
-       65, 65, 65, 65, 65, 65, 65, 65, 
-       24, 65, 65, 65, 65, 65, 29, 30, 
-       31, 66, 65, 67, 65, 11, 12, 13, 
-       65, 65, 65, 65, 65, 65, 65, 65, 
-       65, 65, 65, 65, 65, 65, 65, 65, 
-       65, 65, 29, 30, 31, 66, 65, 10, 
-       11, 12, 13, 65, 65, 65, 65, 65, 
-       65, 19, 20, 21, 65, 22, 23, 24, 
-       65, 65, 65, 65, 10, 29, 30, 31, 
-       66, 65, 10, 11, 12, 13, 65, 65, 
-       65, 65, 65, 65, 65, 20, 21, 65, 
-       22, 23, 24, 65, 65, 65, 65, 10, 
-       29, 30, 31, 66, 65, 10, 11, 12, 
-       13, 65, 65, 65, 65, 65, 65, 65, 
-       65, 21, 65, 22, 23, 24, 65, 65, 
-       65, 65, 10, 29, 30, 31, 66, 65, 
-       9, 10, 11, 12, 13, 65, 15, 9, 
-       65, 65, 65, 19, 20, 21, 65, 22, 
-       23, 24, 65, 65, 65, 65, 10, 29, 
-       30, 31, 66, 65, 9, 10, 11, 12, 
-       13, 65, 65, 9, 65, 65, 65, 19, 
-       20, 21, 65, 22, 23, 24, 65, 65, 
-       65, 65, 10, 29, 30, 31, 66, 65, 
-       9, 10, 11, 12, 13, 14, 15, 9, 
-       65, 65, 65, 19, 20, 21, 65, 22, 
-       23, 24, 65, 65, 65, 65, 10, 29, 
-       30, 31, 66, 65, 5, 6, 65, 65, 
-       65, 65, 65, 65, 65, 65, 65, 9, 
-       10, 11, 12, 13, 14, 15, 9, 16, 
-       65, 18, 19, 20, 21, 65, 22, 23, 
-       24, 65, 65, 65, 65, 28, 29, 30, 
-       31, 6, 65, 5, 65, 65, 65, 65, 
-       65, 65, 65, 65, 65, 65, 65, 65, 
-       65, 65, 65, 65, 65, 65, 65, 65, 
-       65, 10, 11, 12, 13, 65, 65, 65, 
-       65, 65, 65, 65, 65, 65, 65, 22, 
-       23, 24, 65, 65, 65, 65, 65, 29, 
-       30, 31, 66, 65, 68, 65, 7, 65, 
-       1, 65, 65, 65, 1, 65, 65, 65, 
-       65, 65, 5, 6, 7, 65, 65, 65, 
-       65, 65, 65, 65, 65, 9, 10, 11, 
-       12, 13, 14, 15, 9, 16, 17, 18, 
-       19, 20, 21, 65, 22, 23, 24, 65, 
-       25, 26, 65, 28, 29, 30, 31, 6, 
-       65, 5, 6, 65, 65, 65, 65, 65, 
-       65, 65, 65, 65, 9, 10, 11, 12, 
-       13, 14, 15, 9, 16, 17, 18, 19, 
-       20, 21, 65, 22, 23, 24, 65, 65, 
-       65, 65, 28, 29, 30, 31, 6, 65, 
-       25, 26, 65, 26, 65, 1, 69, 69, 
-       69, 1, 69, 71, 70, 32, 70, 32, 
-       71, 70, 71, 70, 32, 70, 33, 70, 
-       0
-};
-
-static const char _use_syllable_machine_trans_targs[] = {
-       1, 3, 0, 26, 28, 29, 30, 51, 
-       53, 31, 32, 33, 34, 35, 46, 47, 
-       48, 54, 49, 43, 44, 45, 38, 39, 
-       40, 55, 56, 57, 50, 36, 37, 0, 
-       58, 60, 0, 2, 0, 4, 5, 6, 
-       7, 8, 9, 10, 21, 22, 23, 24, 
-       18, 19, 20, 13, 14, 15, 25, 11, 
-       12, 0, 0, 16, 0, 17, 0, 27, 
-       0, 0, 41, 42, 52, 0, 0, 59
-};
-
-static const char _use_syllable_machine_trans_actions[] = {
-       0, 0, 3, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 4, 
-       0, 0, 5, 0, 6, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 7, 8, 0, 9, 0, 10, 0, 
-       11, 12, 0, 0, 0, 13, 14, 0
-};
-
-static const char _use_syllable_machine_to_state_actions[] = {
-       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, 
-       0, 0, 0, 0, 0, 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[] = {
-       2, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 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[] = {
-       0, 35, 35, 37, 37, 59, 37, 37, 
-       37, 37, 37, 37, 37, 37, 37, 37, 
-       61, 37, 37, 37, 37, 37, 37, 37, 
-       37, 59, 63, 65, 37, 66, 66, 66, 
-       66, 66, 66, 66, 66, 66, 66, 66, 
-       66, 66, 66, 66, 66, 66, 66, 66, 
-       66, 66, 66, 66, 66, 66, 66, 66, 
-       66, 70, 71, 71, 71
-};
-
-static const int use_syllable_machine_start = 0;
-static const int use_syllable_machine_first_final = 0;
-static const int use_syllable_machine_error = -1;
-
-static const int use_syllable_machine_en_main = 0;
-
-
-#line 58 "hb-ot-shape-complex-use-machine.rl"
-
-
-
-#line 179 "hb-ot-shape-complex-use-machine.rl"
-
-
-#define found_syllable(syllable_type) \
-  HB_STMT_START { \
-    if (0) fprintf (stderr, "syllable %d..%d %s\n", (*ts).second.first, (*te).second.first, #syllable_type); \
-    for (unsigned i = (*ts).second.first; i < (*te).second.first; ++i) \
-      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
-    syllable_serial++; \
-    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
-  } HB_STMT_END
-
-
-template <typename Iter>
-struct machine_index_t :
-  hb_iter_with_fallback_t<machine_index_t<Iter>,
-                         typename Iter::item_t>
-{
-  machine_index_t (const Iter& it) : it (it) {}
-  machine_index_t (const machine_index_t& o) : it (o.it) {}
-
-  static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
-  static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
-
-  typename Iter::item_t __item__ () const { return *it; }
-  typename Iter::item_t __item_at__ (unsigned i) const { return it[i]; }
-  unsigned __len__ () const { return it.len (); }
-  void __next__ () { ++it; }
-  void __forward__ (unsigned n) { it += n; }
-  void __prev__ () { --it; }
-  void __rewind__ (unsigned n) { it -= n; }
-  void operator = (unsigned n)
-  { unsigned index = (*it).first; if (index < n) it += n - index; else if (index > n) it -= index - n; }
-  void operator = (const machine_index_t& o) { *this = (*o.it).first; }
-  bool operator == (const machine_index_t& o) const { return (*it).first == (*o.it).first; }
-  bool operator != (const machine_index_t& o) const { return !(*this == o); }
-
-  private:
-  Iter it;
-};
-struct
-{
-  template <typename Iter,
-           hb_requires (hb_is_iterable (Iter))>
-  machine_index_t<hb_iter_type<Iter>>
-  operator () (Iter&& it) const
-  { return machine_index_t<hb_iter_type<Iter>> (hb_iter (it)); }
-}
-HB_FUNCOBJ (machine_index);
-
-
-
-static bool
-not_ccs_default_ignorable (const hb_glyph_info_t &i)
-{ return !(i.use_category() == USE(CGJ) && _hb_glyph_info_is_default_ignorable (&i)); }
-
-static inline void
-find_syllables_use (hb_buffer_t *buffer)
-{
-  hb_glyph_info_t *info = buffer->info;
-  auto p =
-    + hb_iter (info, buffer->len)
-    | hb_enumerate
-    | hb_filter ([] (const hb_glyph_info_t &i) { return not_ccs_default_ignorable (i); },
-                hb_second)
-    | hb_filter ([&] (const hb_pair_t<unsigned, const hb_glyph_info_t &> p)
-                {
-                  if (p.second.use_category() == USE(ZWNJ))
-                    for (unsigned i = p.first + 1; i < buffer->len; ++i)
-                      if (not_ccs_default_ignorable (info[i]))
-                        return !_hb_glyph_info_is_unicode_mark (&info[i]);
-                  return true;
-                })
-    | hb_enumerate
-    | machine_index
-    ;
-  auto pe = p + p.len ();
-  auto eof = +pe;
-  auto ts = +p;
-  auto te = +p;
-  unsigned int act HB_UNUSED;
-  int cs;
-  
-#line 453 "hb-ot-shape-complex-use-machine.hh"
-       {
-       cs = use_syllable_machine_start;
-       ts = 0;
-       te = 0;
-       act = 0;
-       }
-
-#line 263 "hb-ot-shape-complex-use-machine.rl"
-
-
-  unsigned int syllable_serial = 1;
-  
-#line 466 "hb-ot-shape-complex-use-machine.hh"
-       {
-       int _slen;
-       int _trans;
-       const unsigned char *_keys;
-       const char *_inds;
-       if ( p == pe )
-               goto _test_eof;
-_resume:
-       switch ( _use_syllable_machine_from_state_actions[cs] ) {
-       case 2:
-#line 1 "NONE"
-       {ts = p;}
-       break;
-#line 480 "hb-ot-shape-complex-use-machine.hh"
-       }
-
-       _keys = _use_syllable_machine_trans_keys + (cs<<1);
-       _inds = _use_syllable_machine_indicies + _use_syllable_machine_index_offsets[cs];
-
-       _slen = _use_syllable_machine_key_spans[cs];
-       _trans = _inds[ _slen > 0 && _keys[0] <=( (*p).second.second.use_category()) &&
-               ( (*p).second.second.use_category()) <= _keys[1] ?
-               ( (*p).second.second.use_category()) - _keys[0] : _slen ];
-
-_eof_trans:
-       cs = _use_syllable_machine_trans_targs[_trans];
-
-       if ( _use_syllable_machine_trans_actions[_trans] == 0 )
-               goto _again;
-
-       switch ( _use_syllable_machine_trans_actions[_trans] ) {
-       case 7:
-#line 169 "hb-ot-shape-complex-use-machine.rl"
-       {te = p+1;{ found_syllable (use_standard_cluster); }}
-       break;
-       case 4:
-#line 174 "hb-ot-shape-complex-use-machine.rl"
-       {te = p+1;{ found_syllable (use_broken_cluster); }}
-       break;
-       case 3:
-#line 175 "hb-ot-shape-complex-use-machine.rl"
-       {te = p+1;{ found_syllable (use_non_cluster); }}
-       break;
-       case 8:
-#line 167 "hb-ot-shape-complex-use-machine.rl"
-       {te = p;p--;{ found_syllable (use_virama_terminated_cluster); }}
-       break;
-       case 9:
-#line 168 "hb-ot-shape-complex-use-machine.rl"
-       {te = p;p--;{ found_syllable (use_sakot_terminated_cluster); }}
-       break;
-       case 6:
-#line 169 "hb-ot-shape-complex-use-machine.rl"
-       {te = p;p--;{ found_syllable (use_standard_cluster); }}
-       break;
-       case 11:
-#line 170 "hb-ot-shape-complex-use-machine.rl"
-       {te = p;p--;{ found_syllable (use_number_joiner_terminated_cluster); }}
-       break;
-       case 10:
-#line 171 "hb-ot-shape-complex-use-machine.rl"
-       {te = p;p--;{ found_syllable (use_numeral_cluster); }}
-       break;
-       case 5:
-#line 172 "hb-ot-shape-complex-use-machine.rl"
-       {te = p;p--;{ found_syllable (use_symbol_cluster); }}
-       break;
-       case 14:
-#line 173 "hb-ot-shape-complex-use-machine.rl"
-       {te = p;p--;{ found_syllable (use_hieroglyph_cluster); }}
-       break;
-       case 12:
-#line 174 "hb-ot-shape-complex-use-machine.rl"
-       {te = p;p--;{ found_syllable (use_broken_cluster); }}
-       break;
-       case 13:
-#line 175 "hb-ot-shape-complex-use-machine.rl"
-       {te = p;p--;{ found_syllable (use_non_cluster); }}
-       break;
-#line 546 "hb-ot-shape-complex-use-machine.hh"
-       }
-
-_again:
-       switch ( _use_syllable_machine_to_state_actions[cs] ) {
-       case 1:
-#line 1 "NONE"
-       {ts = 0;}
-       break;
-#line 555 "hb-ot-shape-complex-use-machine.hh"
-       }
-
-       if ( ++p != pe )
-               goto _resume;
-       _test_eof: {}
-       if ( p == eof )
-       {
-       if ( _use_syllable_machine_eof_trans[cs] > 0 ) {
-               _trans = _use_syllable_machine_eof_trans[cs] - 1;
-               goto _eof_trans;
-       }
-       }
-
-       }
-
-#line 268 "hb-ot-shape-complex-use-machine.rl"
-
-}
-
-#undef found_syllable
-
-#endif /* HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-use-table.hh b/src/hb-ot-shape-complex-use-table.hh
deleted file mode 100644 (file)
index 7a3a995..0000000
+++ /dev/null
@@ -1,1283 +0,0 @@
-/* == Start of generated table == */
-/*
- * The following table is generated by running:
- *
- *   ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt ArabicShaping.txt DerivedCoreProperties.txt UnicodeData.txt Blocks.txt Scripts.txt IndicSyllabicCategory-Additional.txt IndicPositionalCategory-Additional.txt
- *
- * on files with these headers:
- *
- * # IndicSyllabicCategory-14.0.0.txt
- * # Date: 2021-05-22, 01:01:00 GMT [KW, RP]
- * # IndicPositionalCategory-14.0.0.txt
- * # Date: 2021-05-22, 01:01:00 GMT [KW, RP]
- * # ArabicShaping-14.0.0.txt
- * # Date: 2021-05-21, 01:54:00 GMT [KW, RP]
- * # DerivedCoreProperties-14.0.0.txt
- * # Date: 2021-08-12, 23:12:53 GMT
- * # Blocks-14.0.0.txt
- * # Date: 2021-01-22, 23:29:00 GMT [KW]
- * # Scripts-14.0.0.txt
- * # Date: 2021-07-10, 00:35:31 GMT
- * # Override values For Indic_Syllabic_Category
- * # Not derivable
- * # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
- * # Updated for Unicode 10.0 by Andrew Glass 2017-07-25
- * # Updated for Unicode 12.1 by Andrew Glass 2019-05-24
- * # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
- * # Updated for Unicode 14.0 by Andrew Glass 2021-09-25
- * # Override values For Indic_Positional_Category
- * # Not derivable
- * # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
- * # Updated for Unicode 10.0 by Andrew Glass 2017-07-25
- * # Ammended for Unicode 10.0 by Andrew Glass 2018-09-21
- * # Updated for L2/19-083    by Andrew Glass 2019-05-06
- * # Updated for Unicode 12.1 by Andrew Glass 2019-05-30
- * # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
- * # Updated for Unicode 14.0 by Andrew Glass 2021-09-28
- * UnicodeData.txt does not have a header.
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_USE_TABLE_HH
-#define HB_OT_SHAPE_COMPLEX_USE_TABLE_HH
-
-#include "hb.hh"
-
-#include "hb-ot-shape-complex-use-machine.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 */
-#define G      USE(G)  /* HIEROGLYPH */
-#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 J      USE(J)  /* HIEROGLYPH_JOINER */
-#define N      USE(N)  /* BASE_NUM */
-#define O      USE(O)  /* OTHER */
-#define R      USE(R)  /* REPHA */
-#define SB     USE(SB) /* HIEROGLYPH_SEGMENT_BEGIN */
-#define SE     USE(SE) /* HIEROGLYPH_SEGMENT_END */
-#define SUB    USE(SUB)        /* CONS_SUB */
-#define Sk     USE(Sk) /* SAKOT */
-#define ZWNJ   USE(ZWNJ)       /* ZWNJ */
-#define CMAbv  USE(CMAbv)
-#define CMBlw  USE(CMBlw)
-#define FAbv   USE(FAbv)
-#define FBlw   USE(FBlw)
-#define FPst   USE(FPst)
-#define FMAbv  USE(FMAbv)
-#define FMBlw  USE(FMBlw)
-#define FMPst  USE(FMPst)
-#define MAbv   USE(MAbv)
-#define MBlw   USE(MBlw)
-#define MPst   USE(MPst)
-#define MPre   USE(MPre)
-#define SMAbv  USE(SMAbv)
-#define SMBlw  USE(SMBlw)
-#define VAbv   USE(VAbv)
-#define VBlw   USE(VBlw)
-#define VPst   USE(VPst)
-#define VPre   USE(VPre)
-#define VMAbv  USE(VMAbv)
-#define VMBlw  USE(VMBlw)
-#define VMPst  USE(VMPst)
-#define VMPre  USE(VMPre)
-#pragma GCC diagnostic pop
-
-static const uint8_t use_table[] = {
-
-
-#define use_offset_0x0028u 0
-
-
-  /* Basic Latin */
-                                                                         O,     O,     O,     O,     O,    GB,     O,     O,
-  /* 0030 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
-
-#define use_offset_0x00a0u 24
-
-
-  /* Latin-1 Supplement */
-
-  /* 00A0 */    GB,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 00B0 */     O,     O, FMPst, FMPst,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 00C0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 00D0 */     O,     O,     O,     O,     O,     O,     O,    GB,
-
-#define use_offset_0x0348u 80
-
-
-  /* Combining Diacritical Marks */
-                                                                         O,     O,     O,     O,     O,     O,     O,   CGJ,
-
-#define use_offset_0x0640u 88
-
-
-  /* Arabic */
-
-  /* 0640 */     B,     O,     O,     O,     O,     O,     O,     O,
-
-#define use_offset_0x07c8u 96
-
-
-  /* NKo */
-                                                                         O,     O,     B,     B,     B,     B,     B,     B,
-  /* 07D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 07E0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,
-  /* 07F0 */ VMAbv, VMAbv, VMAbv, VMAbv,     O,     O,     O,     O,     O,     O,     B,     O,     O, VMAbv,     O,     O,
-
-#define use_offset_0x0840u 152
-
-
-  /* Mandaic */
-
-  /* 0840 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0850 */     B,     B,     B,     B,     B,     B,     B,     B,     B, CMBlw, CMBlw, CMBlw,     O,     O,     O,     O,
-
-#define use_offset_0x0900u 184
-
-
-  /* Devanagari */
-
-  /* 0900 */ VMAbv, VMAbv, VMAbv, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0910 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0920 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0930 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VAbv,  VPst, CMBlw,     B,  VPst,  VPre,
-  /* 0940 */  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,  VPst,  VPst,  VPst,  VPst,     H,  VPre,  VPst,
-  /* 0950 */     O, VMAbv, VMBlw,     O,     O,  VAbv,  VBlw,  VBlw,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0960 */     B,     B,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0970 */     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-
-  /* Bengali */
-
-  /* 0980 */    GB, VMAbv, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     B,
-  /* 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,     O,     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, FMAbv,     O,
-
-  /* Gurmukhi */
-
-  /* 0A00 */     O, VMAbv, VMAbv, VMPst,     O,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     B,
-  /* 0A10 */     B,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0A20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
-  /* 0A30 */     B,     O,     B,     B,     O,     B,     B,     O,     B,     B,     O,     O, CMBlw,     O,  VPst,  VPre,
-  /* 0A40 */  VPst,  VBlw,  VBlw,     O,     O,     O,     O,  VAbv,  VAbv,     O,     O,  VAbv,  VAbv,     H,     O,     O,
-  /* 0A50 */     O, VMBlw,     O,     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,     O,     B,     O,
-  /* 0A60 */     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0A70 */ VMAbv, CMAbv,    GB,    GB,     O,  MBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Gujarati */
-
-  /* 0A80 */     O, VMAbv, VMAbv, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,
-  /* 0A90 */     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0AA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
-  /* 0AB0 */     B,     O,     B,     B,     O,     B,     B,     B,     B,     B,     O,     O, CMBlw,     B,  VPst,  VPre,
-  /* 0AC0 */  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,     O,  VAbv,  VAbv,  VAbv,     O,  VPst,  VPst,     H,     O,     O,
-  /* 0AD0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 0AE0 */     B,     B,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0AF0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     B, VMAbv, VMAbv, VMAbv, CMAbv, CMAbv, CMAbv,
-
-  /* Oriya */
-
-  /* 0B00 */     O, VMAbv, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     B,
-  /* 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,
-  /* 0B50 */     O,     O,     O,     O,     O,  VAbv,  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,
-
-  /* Tamil */
-
-  /* 0B80 */     O,     O, VMAbv,     O,     O,     B,     B,     B,     B,     B,     B,     O,     O,     O,     B,     B,
-  /* 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,
-  /* 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,
-
-  /* Telugu */
-
-  /* 0C00 */ VMAbv, VMPst, VMPst, VMPst, VMAbv,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
-  /* 0C10 */     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0C20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
-  /* 0C30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O, CMBlw,     B,  VAbv,  VAbv,
-  /* 0C40 */  VAbv,  VPst,  VPst,  VPst,  VPst,     O,  VAbv,  VAbv,  VAbv,     O,  VAbv,  VAbv,  VAbv,     H,     O,     O,
-  /* 0C50 */     O,     O,     O,     O,     O,  VAbv,  VBlw,     O,     B,     B,     B,     O,     O,     O,     O,     O,
-  /* 0C60 */     B,     B,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0C70 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Kannada */
-
-  /* 0C80 */     B, VMAbv, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
-  /* 0C90 */     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0CA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
-  /* 0CB0 */     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     O,     O, CMBlw,     B,  VPst,  VAbv,
-  /* 0CC0 */  VAbv,  VPst,  VPst,  VPst,  VPst,     O,  VAbv,  VAbv,  VAbv,     O,  VAbv,  VAbv,  VAbv,     H,     O,     O,
-  /* 0CD0 */     O,     O,     O,     O,     O,  VPst,  VPst,     O,     O,     O,     O,     O,     O,     O,     B,     O,
-  /* 0CE0 */     B,     B,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0CF0 */     O,    CS,    CS,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Malayalam */
-
-  /* 0D00 */ VMAbv, VMAbv, VMPst, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
-  /* 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,
-  /* 0D50 */     O,     O,     O,     O,     O,     O,     O,  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,     O,     O,     O,     O,     O,     O,
-
-  /* Sinhala */
-
-  /* 0D80 */     O, VMAbv, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0D90 */     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     B,     B,     B,     B,     B,     B,
-  /* 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,
-  /* 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_0x0f00u 1456
-
-
-  /* Tibetan */
-
-  /* 0F00 */     B,     B,     O,     O,     B,     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 0F10 */     O,     O,     O,     O,     O,     O,     O,     O,  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,  FBlw,     O,  FBlw,     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, CMBlw,  VBlw,  VAbv,  VAbv,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VBlw,  VBlw, VMAbv,     O,
-  /* 0F80 */  VBlw,  VAbv, VMAbv, VMAbv,  VBlw,     O, 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,  FBlw,     O,
-
-#define use_offset_0x1000u 1656
-
-
-  /* Myanmar */
-
-  /* 1000 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1010 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1020 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VPst,  VPst,  VAbv,  VAbv,  VBlw,
-  /* 1030 */  VBlw,  VPre,  VAbv,  VAbv,  VAbv,  VAbv, VMAbv, VMBlw, VMPst,     H,  VAbv,  MPst,  MPre,  MBlw,  MBlw,     B,
-  /* 1040 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,    GB,     O,     O,    GB,     O,
-  /* 1050 */     B,     B,     B,     B,     B,     B,  VPst,  VPst,  VBlw,  VBlw,     B,     B,     B,     B,  MBlw,  MBlw,
-  /* 1060 */  MBlw,     B,  VPst, VMPst, VMPst,     B,     B,  VPst,  VPst, VMPst, VMPst, VMPst, VMPst, VMPst,     B,     B,
-  /* 1070 */     B,  VAbv,  VAbv,  VAbv,  VAbv,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 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 1816
-
-
-  /* Tagalog */
-
-  /* 1700 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1710 */     B,     B,  VAbv,  VBlw,  VBlw,  VPst,     O,     O,     O,     O,     O,     O,     O,     O,     O,     B,
-
-  /* Hanunoo */
-
-  /* 1720 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1730 */     B,     B,  VAbv,  VBlw,  VPst,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Buhid */
-
-  /* 1740 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1750 */     B,     B,  VAbv,  VBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Tagbanwa */
-
-  /* 1760 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
-  /* 1770 */     B,     O,  VAbv,  VBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Khmer */
-
-  /* 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,   CGJ,   CGJ,  VPst,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VBlw,  VPre,  VPre,
-  /* 17C0 */  VPre,  VPre,  VPre,  VPre,  VPre,  VPre, VMAbv, VMPst,  VPst, VMAbv, VMAbv, FMAbv,  FAbv, CMAbv, FMAbv, VMAbv,
-  /* 17D0 */ FMAbv,  VAbv,     H, FMAbv,     O,     O,     O,     O,     O,     O,     O,     O,     B, FMAbv,     O,     O,
-  /* 17E0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
-  /* 17F0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Mongolian */
-
-  /* 1800 */     B,     O,     O,     O,     O,     O,     O,     B,     O,     O,     B,   CGJ,   CGJ,   CGJ,     O,   CGJ,
-  /* 1810 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 1820 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1830 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1840 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1850 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1860 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1870 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,     O,
-  /* 1880 */    GB,    GB,    GB,    GB,    GB, CMAbv, CMAbv,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1890 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B, CMBlw,     B,     O,     O,     O,     O,     O,
-
-#define use_offset_0x1900u 2248
-
-
-  /* Limbu */
-
-  /* 1900 */    GB,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1910 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,
-  /* 1920 */  VAbv,  VAbv,  VBlw,  VPst,  VPst,  VAbv,  VAbv,  VAbv,  VAbv,   SUB,   SUB,   SUB,     O,     O,     O,     O,
-  /* 1930 */  FPst,  FPst, VMBlw,  FPst,  FPst,  FPst,  FPst,  FPst,  FPst,  FBlw, VMAbv, FMBlw,     O,     O,     O,     O,
-  /* 1940 */     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-
-  /* Tai Le */
-
-  /* 1950 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1960 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,
-  /* 1970 */     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* New Tai Lue */
-
-  /* 1980 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1990 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 19A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,
-  /* 19B0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 19C0 */     B,     B,     B,     B,     B,     B,     B,     B, VMPst, VMPst,     O,     O,     O,     O,     O,     O,
-  /* 19D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,
-  /* 19E0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 19F0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Buginese */
-
-  /* 1A00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1A10 */     B,     B,     B,     B,     B,     B,     B,  VAbv,  VAbv,  VPre,  VPst,  VAbv,     O,     O,     O,     O,
-
-  /* Tai Tham */
-
-  /* 1A20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1A30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1A40 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1A50 */     B,     B,     B,     B,     B,  MPre,  MBlw,   SUB,  FAbv,  FAbv,  MAbv,   SUB,   SUB,   SUB,   SUB,     O,
-  /* 1A60 */    Sk,  VPst,  VAbv,  VPst,  VPst,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VAbv,  VBlw,  VPst,  VPre,  VPre,
-  /* 1A70 */  VPre,  VPre,  VPre,  VAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,  VAbv, VMAbv, VMAbv,     O,     O, VMBlw,
-  /* 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 2664
-
-
-  /* Balinese */
-
-  /* 1B00 */ VMAbv, VMAbv, VMAbv,  FAbv, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 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,     B,     O,     O,     O,
-  /* 1B50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,    GB,    GB,     O,     O,    GB,
-  /* 1B60 */     O,     O,    GB,     O,     O,     O,     O,     O,    GB,     O,     O, SMAbv, SMBlw, SMAbv, SMAbv, SMAbv,
-  /* 1B70 */ SMAbv, SMAbv, SMAbv, SMAbv,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Sundanese */
-
-  /* 1B80 */ VMAbv,  FAbv, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1B90 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1BA0 */     B,   SUB,   SUB,   SUB,  VAbv,  VBlw,  VPre,  VPst,  VAbv,  VAbv,  VPst,     H,   SUB,   SUB,     B,     B,
-  /* 1BB0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-
-  /* Batak */
-
-  /* 1BC0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1BD0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1BE0 */     B,     B,     B,     B,     B,     B, CMAbv,  VPst,  VAbv,  VAbv,  VPst,  VPst,  VPst,  VAbv,  VPst,  VAbv,
-  /* 1BF0 */  FAbv,  FAbv, CMBlw, CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Lepcha */
-
-  /* 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,
-  /* 1C30 */  FAbv,  FAbv,  FAbv,  FAbv, VMPre, VMPre, FMAbv, 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 3000
-
-
-  /* Vedic Extensions */
-
-  /* 1CD0 */ VMAbv, VMAbv, VMAbv,     O, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMAbv, VMAbv, VMBlw, VMBlw, VMBlw, VMBlw,
-  /* 1CE0 */ VMAbv, VMPst, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw,     O,     O,     O,     O, VMBlw,     O,     O,
-  /* 1CF0 */     O,     O,     O,     O, VMAbv,    CS,    CS, VMPst, VMAbv, VMAbv,    GB,     O,     O,     O,     O,     O,
-
-#define use_offset_0x1df8u 3048
-
-
-  /* Combining Diacritical Marks Supplement */
-                                                                         O,     O,     O, FMAbv,     O,     O,     O,     O,
-
-#define use_offset_0x2008u 3056
-
-
-  /* General Punctuation */
-                                                                         O,     O,     O,     O,  ZWNJ,   CGJ,     O,     O,
-  /* 2010 */    GB,    GB,    GB,    GB,    GB,     O,     O,     O,
-
-#define use_offset_0x2070u 3072
-
-
-  /* Superscripts and Subscripts */
-
-  /* 2070 */     O,     O,     O,     O, FMPst,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 2080 */     O,     O, FMPst, FMPst, FMPst,     O,     O,     O,
-
-#define use_offset_0x20f0u 3096
-
-
-  /* Combining Diacritical Marks for Symbols */
-
-  /* 20F0 */ VMAbv,     O,     O,     O,     O,     O,     O,     O,
-
-#define use_offset_0x25c8u 3104
-
-
-  /* Geometric Shapes */
-                                                                         O,     O,     O,     O,     B,     O,     O,     O,
-
-#define use_offset_0x2d30u 3112
-
-
-  /* Tifinagh */
-
-  /* 2D30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 2D40 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 2D50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 2D60 */     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,     O,     B,
-  /* 2D70 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     H,
-
-#define use_offset_0xa800u 3192
-
-
-  /* Syloti Nagri */
-
-  /* A800 */     B,     B,  VAbv,     B,     B,     B,     H,     B,     B,     B,     B, VMAbv,     B,     B,     B,     B,
-  /* A810 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* A820 */     B,     B,     B,  VPst,  VPst,  VBlw,  VAbv,  VPst,     O,     O,     O,     O,  VBlw,     O,     O,     O,
-  /* A830 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Phags-pa */
-
-  /* A840 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* A850 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* A860 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* A870 */     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Saurashtra */
-
-  /* A880 */ VMPst, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* A890 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* A8A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* A8B0 */     B,     B,     B,     B,  MPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,
-  /* A8C0 */  VPst,  VPst,  VPst,  VPst,     H, VMAbv,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* A8D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
-
-  /* Devanagari Extended */
-
-  /* A8E0 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,
-  /* A8F0 */ VMAbv, VMAbv,     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     B,  VAbv,
-
-  /* Kayah Li */
-
-  /* A900 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* A910 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* A920 */     B,     B,     B,     B,     B,     B,  VAbv,  VAbv,  VAbv,  VAbv,  VAbv, VMBlw, VMBlw, VMBlw,     O,     O,
-
-  /* Rejang */
-
-  /* A930 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* A940 */     B,     B,     B,     B,     B,     B,     B,  VBlw,  VBlw,  VBlw,  VAbv,  VBlw,  VBlw,  VBlw,  VBlw,  FAbv,
-  /* A950 */  FAbv,  FAbv,  FPst,  VPst,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* A960 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* A970 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Javanese */
-
-  /* A980 */ VMAbv, VMAbv,  FAbv, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* A990 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* A9A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* A9B0 */     B,     B,     B, CMAbv,  VPst,  VPst,  VAbv,  VAbv,  VBlw,  VBlw,  VPre,  VPre,  VAbv,  MBlw,  MPst,  MBlw,
-  /* A9C0 */     H,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* A9D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
-
-  /* Myanmar Extended-B */
-
-  /* A9E0 */     B,     B,     B,     B,     B,  VAbv,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* A9F0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,
-
-  /* Cham */
-
-  /* AA00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* AA10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* AA20 */     B,     B,     B,     B,     B,     B,     B,     B,     B, VMAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VAbv,  VPre,
-  /* AA30 */  VPre,  VAbv,  VBlw,  MPst,  MPre,  MAbv,  MBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* AA40 */     B,     B,     B,  FAbv,     B,     B,     B,     B,     B,     B,     B,     B,  FAbv,  FPst,     O,     O,
-  /* AA50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
-
-  /* Myanmar Extended-A */
-
-  /* AA60 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* AA70 */     O,     B,     B,     B,    GB,    GB,    GB,     O,     O,     O,     B, VMPst, VMAbv, VMPst,     B,     B,
-
-  /* Tai Viet */
-
-  /* AA80 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* AA90 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* AAA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* AAB0 */  VAbv,     B,  VAbv,  VAbv,  VBlw,     B,     B,  VAbv,  VAbv,     B,     B,     B,     B,     B,  VAbv, VMAbv,
-  /* AAC0 */     B, VMAbv,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* AAD0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Meetei Mayek Extensions */
-
-  /* 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 3952
-
-
-  /* Meetei Mayek */
-
-  /* ABC0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* ABD0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 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 4016
-
-
-  /* Variation Selectors */
-
-  /* FE00 */   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,
-
-#define use_offset_0x10570u 4032
-
-
-  /* Vithkuqi */
-
-  /* 10570 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,
-  /* 10580 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,
-  /* 10590 */     B,     B,     B,     O,     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 105A0 */     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 105B0 */     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     O,     O,     O,
-
-#define use_offset_0x10a00u 4112
-
-
-  /* Kharoshthi */
-
-  /* 10A00 */     B,  VBlw,  VBlw,  VBlw,     O,  VAbv,  VBlw,     O,     O,     O,     O,     O,  VPst, VMBlw, VMBlw, VMAbv,
-  /* 10A10 */     B,     B,     B,     B,     O,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,
-  /* 10A20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 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_0x10ac0u 4192
-
-
-  /* Manichaean */
-
-  /* 10AC0 */     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,
-  /* 10AD0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 10AE0 */     B,     B,     B,     B,     B, CMBlw, CMBlw,     O,     O,     O,     O,     B,     B,     B,     B,     B,
-
-#define use_offset_0x10b80u 4240
-
-
-  /* Psalter Pahlavi */
-
-  /* 10B80 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 10B90 */     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 10BA0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,     B,     B,     O,
-
-#define use_offset_0x10d00u 4288
-
-
-  /* Hanifi Rohingya */
-
-  /* 10D00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 10D10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 10D20 */     B,     B,     B,     B, VMAbv, VMAbv, VMAbv, CMAbv,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 10D30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
-
-#define use_offset_0x10e80u 4352
-
-
-  /* Yezidi */
-
-  /* 10E80 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 10E90 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 10EA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,  VAbv,  VAbv,     O,     O,     O,
-  /* 10EB0 */     B,     B,     O,     O,     O,     O,     O,     O,
-
-#define use_offset_0x10f30u 4408
-
-
-  /* Sogdian */
-
-  /* 10F30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 10F40 */     B,     B,     B,     B,     B,     B, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw,
-  /* 10F50 */ VMBlw,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 10F60 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Old Uyghur */
-
-  /* 10F70 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 10F80 */     B,     B, CMBlw, CMBlw, CMBlw, CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 10F90 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 10FA0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Chorasmian */
-
-  /* 10FB0 */     B,     O,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 10FC0 */     O,     B,     B,     B,     B,     O,     O,     O,     O,     B,     B,     B,     O,     O,     O,     O,
-  /* 10FD0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 10FE0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 10FF0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Brahmi */
-
-  /* 11000 */ VMPst, VMAbv, VMPst,    CS,    CS,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 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,
-  /* 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 */  VAbv,     B,     B,  VAbv,  VAbv,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,    HN,
-
-  /* Kaithi */
-
-  /* 11080 */ VMAbv, VMAbv, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11090 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 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,
-  /* 110C0 */     O,     O,  VBlw,     O,     O,     O,     O,     O,
-
-#define use_offset_0x11100u 4816
-
-
-  /* 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,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VPre,  VBlw,  VAbv,  VAbv,
-  /* 11130 */  VBlw,  VAbv,  VAbv,     H, CMAbv,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11140 */     O,     O,     O,     O,     B,  VPst,  VPst,     B,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Mahajani */
-
-  /* 11150 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11160 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11170 */     B,     B,     B, CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Sharada */
-
-  /* 11180 */ VMAbv, VMAbv, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 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,    GB, FMBlw, CMBlw,  VAbv,  VBlw,     O,  VPre, VMAbv,
-  /* 111D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,
-
-  /* Sinhala Archaic Numbers */
-
-  /* 111E0 */     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 111F0 */     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Khojki */
-
-  /* 11200 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11210 */     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 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 5136
-
-
-  /* Multani */
-
-  /* 11280 */     B,     B,     B,     B,     B,     B,     B,     O,     B,     O,     B,     B,     B,     B,     O,     B,
-  /* 11290 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,
-  /* 112A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Khudawadi */
-
-  /* 112B0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 112C0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 112D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B, VMAbv,
-  /* 112E0 */  VPst,  VPre,  VPst,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv, CMBlw,  VBlw,     O,     O,     O,     O,     O,
-  /* 112F0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
-
-  /* Grantha */
-
-  /* 11300 */ VMAbv, VMAbv, VMAbv, VMAbv,     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,   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 5384
-
-
-  /* Newa */
-
-  /* 11400 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11410 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11420 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11430 */     B,     B,     B,     B,     B,  VPst,  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,
-  /* 11440 */  VPst,  VPst,     H, VMAbv, VMAbv, VMPst, CMBlw,     B,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 11450 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O, FMAbv,     B,
-  /* 11460 */    CS,    CS,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 11470 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Tirhuta */
-
-  /* 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,
-  /* 114C0 */ VMAbv, VMAbv,     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 5608
-
-
-  /* Siddham */
-
-  /* 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,
-  /* 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,
-  /* 115F0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Modi */
-
-  /* 11600 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11610 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11620 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11630 */  VPst,  VPst,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VPst,  VPst, VMAbv, VMPst,     H,
-  /* 11640 */  VAbv,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 11650 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
-  /* 11660 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 11670 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Takri */
-
-  /* 11680 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11690 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 116A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B, VMAbv, VMPst,  VAbv,  VPre,  VPst,
-  /* 116B0 */  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,     H, CMBlw,     B,     O,     O,     O,     O,     O,     O,     O,
-  /* 116C0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
-  /* 116D0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 116E0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 116F0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Ahom */
-
-  /* 11700 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11710 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,  MBlw,  MPre,  MAbv,
-  /* 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,
-  /* 11740 */     B,     B,     B,     B,     B,     B,     B,     O,
-
-#define use_offset_0x11800u 6064
-
-
-  /* Dogra */
-
-  /* 11800 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11810 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 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_0x11900u 6128
-
-
-  /* Dives Akuru */
-
-  /* 11900 */     B,     B,     B,     B,     B,     B,     B,     O,     O,     B,     O,     O,     B,     B,     B,     B,
-  /* 11910 */     B,     B,     B,     B,     O,     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11920 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11930 */  VPst,  VPst,  VPst,  VPst,  VPst,  VPre,     O,  VPre,  VPre,     O,     O, VMAbv, VMAbv,  VPst,     H,     R,
-  /* 11940 */  MPst,     R,  MPst, CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 11950 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
-
-#define use_offset_0x119a0u 6224
-
-
-  /* Nandinagari */
-
-  /* 119A0 */     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     B,     B,     B,     B,     B,     B,
-  /* 119B0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 119C0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 119D0 */     B,  VPst,  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,     O,     O,  VAbv,  VAbv,  VPst,  VPst, VMPst, VMPst,
-  /* 119E0 */     H,     B,     O,     O,  VPre,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 119F0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Zanabazar Square */
-
-  /* 11A00 */     B,  VAbv,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,     B,     B,     B,     B,     B,
-  /* 11A10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11A20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11A30 */     B,     B,     B, FMBlw,  VBlw, VMAbv, VMAbv, VMAbv, VMAbv, VMPst,     R,  MBlw,  MBlw,  MBlw,  MBlw,    GB,
-  /* 11A40 */     O,     O,     O,     O,     O,    GB,     O,     H,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Soyombo */
-
-  /* 11A50 */     B,  VAbv,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VPst,  VPst,  VBlw,  VBlw,  VBlw,     B,     B,     B,     B,
-  /* 11A60 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11A70 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11A80 */     B,     B,     B,     B,     R,     R,     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 6480
-
-
-  /* Bhaiksuki */
-
-  /* 11C00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
-  /* 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,    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,
-
-  /* Marchen */
-
-  /* 11C70 */     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11C80 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11C90 */     O,     O,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,
-  /* 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 6664
-
-
-  /* Masaram Gondi */
-
-  /* 11D00 */     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     O,     B,     B,     B,     B,     B,
-  /* 11D10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11D20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11D30 */     B,  VAbv,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,     O,     O,     O,  VAbv,     O,  VAbv,  VAbv,     O,  VAbv,
-  /* 11D40 */ VMAbv, VMAbv, CMBlw,  VAbv,  VBlw,     H,     R,  MBlw,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 11D50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
-
-  /* Gunjala Gondi */
-
-  /* 11D60 */     B,     B,     B,     B,     B,     B,     O,     B,     B,     O,     B,     B,     B,     B,     B,     B,
-  /* 11D70 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11D80 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VPst,  VPst,  VPst,  VPst,  VPst,     O,
-  /* 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 6840
-
-
-  /* Makasar */
-
-  /* 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,
-
-#define use_offset_0x13000u 6864
-
-
-  /* Egyptian Hieroglyphs */
-
-  /* 13000 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13010 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13020 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13030 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13040 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13050 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13060 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13070 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13080 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13090 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 130A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 130B0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 130C0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 130D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 130E0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 130F0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13100 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13110 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13120 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13130 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13140 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13150 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13160 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13170 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13180 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13190 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 131A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 131B0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 131C0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 131D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 131E0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 131F0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13200 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13210 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13220 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13230 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13240 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13250 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13260 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13270 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13280 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13290 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 132A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 132B0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 132C0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 132D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 132E0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 132F0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13300 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13310 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13320 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13330 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13340 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13350 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13360 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13370 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13380 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13390 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 133A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 133B0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 133C0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 133D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 133E0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 133F0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13400 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13410 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 13420 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,
-
-  /* Egyptian Hieroglyph Format Controls */
-
-  /* 13430 */     H,     H,     H,     H,     H,     H,     H,     B,     B,     O,     O,     O,     O,     O,     O,     O,
-
-#define use_offset_0x16ac0u 7952
-
-
-  /* Tangsa */
-
-  /* 16AC0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
-  /* 16AD0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 16AE0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 16AF0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Pahawh Hmong */
-
-  /* 16B00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 16B10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 16B20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 16B30 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,     O,
-
-#define use_offset_0x16f00u 8072
-
-
-  /* Miao */
-
-  /* 16F00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 16F10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 16F20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 16F30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 16F40 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O, CMBlw,
-  /* 16F50 */     O,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,
-  /* 16F60 */  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,
-  /* 16F70 */  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,
-  /* 16F80 */  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,     O,     O,     O,     O,     O,     O,     O, VMBlw,
-  /* 16F90 */ VMBlw, VMBlw, VMBlw,     O,     O,     O,     O,     O,
-
-#define use_offset_0x16fe0u 8224
-
-
-  /* Ideographic Symbols and Punctuation */
-
-  /* 16FE0 */     O,     O,     O,     O,     B,     O,     O,     O,
-
-#define use_offset_0x18b00u 8232
-
-
-  /* Khitan Small Script */
-
-  /* 18B00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18B10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18B20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18B30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18B40 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18B50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18B60 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18B70 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18B80 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18B90 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18BA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18BB0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18BC0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18BD0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18BE0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18BF0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18C00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18C10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18C20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18C30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18C40 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18C50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18C60 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18C70 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18C80 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18C90 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18CA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18CB0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18CC0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 18CD0 */     B,     B,     B,     B,     B,     B,     O,     O,
-
-#define use_offset_0x1bc00u 8704
-
-
-  /* Duployan */
-
-  /* 1BC00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1BC10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1BC20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1BC30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1BC40 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1BC50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1BC60 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,
-  /* 1BC70 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,
-  /* 1BC80 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,     O,
-  /* 1BC90 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O, CMBlw, CMBlw,     O,
-
-#define use_offset_0x1e100u 8864
-
-
-  /* Nyiakeng Puachue Hmong */
-
-  /* 1E100 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1E110 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1E120 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,
-  /* 1E130 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,     B,     B,     B,     B,     B,     B,     B,     O,     O,
-  /* 1E140 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     B,     B,
-
-#define use_offset_0x1e290u 8944
-
-
-  /* Toto */
-
-  /* 1E290 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1E2A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B, VMAbv,     O,
-  /* 1E2B0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Wancho */
-
-  /* 1E2C0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1E2D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1E2E0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B, VMAbv, VMAbv, VMAbv, VMAbv,
-  /* 1E2F0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
-
-#define use_offset_0x1e900u 9056
-
-
-  /* Adlam */
-
-  /* 1E900 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1E910 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1E920 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1E930 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1E940 */     B,     B,     B,     B, CMAbv, CMAbv, CMAbv, CMAbv, CMAbv, CMAbv, CMAbv,     B,     O,     O,     O,     O,
-  /* 1E950 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
-
-#define use_offset_0xe0100u 9152
-
-
-  /* Variation Selectors Supplement */
-
-  /* E0100 */   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,
-  /* E0110 */   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,
-  /* E0120 */   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,
-  /* E0130 */   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,
-  /* E0140 */   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,
-  /* E0150 */   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,
-  /* E0160 */   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,
-  /* E0170 */   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,
-  /* E0180 */   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,
-  /* E0190 */   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,
-  /* E01A0 */   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,
-  /* E01B0 */   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,
-  /* E01C0 */   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,
-  /* E01D0 */   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,
-  /* E01E0 */   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,
-
-}; /* Table items: 9392; occupancy: 79% */
-
-static inline uint8_t
-hb_use_get_category (hb_codepoint_t u)
-{
-  switch (u >> 12)
-  {
-    case 0x0u:
-      if (hb_in_range<hb_codepoint_t> (u, 0x0028u, 0x003Fu)) return use_table[u - 0x0028u + use_offset_0x0028u];
-      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, 0x0640u, 0x0647u)) return use_table[u - 0x0640u + use_offset_0x0640u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x07C8u, 0x07FFu)) return use_table[u - 0x07C8u + use_offset_0x07c8u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x0840u, 0x085Fu)) return use_table[u - 0x0840u + use_offset_0x0840u];
-      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, 0x0F00u, 0x0FC7u)) return use_table[u - 0x0F00u + use_offset_0x0f00u];
-      break;
-
-    case 0x1u:
-      if (hb_in_range<hb_codepoint_t> (u, 0x1000u, 0x109Fu)) return use_table[u - 0x1000u + use_offset_0x1000u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x1700u, 0x18AFu)) return use_table[u - 0x1700u + use_offset_0x1700u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x1900u, 0x1A9Fu)) return use_table[u - 0x1900u + use_offset_0x1900u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x1B00u, 0x1C4Fu)) return use_table[u - 0x1B00u + use_offset_0x1b00u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x1CD0u, 0x1CFFu)) return use_table[u - 0x1CD0u + use_offset_0x1cd0u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x1DF8u, 0x1DFFu)) return use_table[u - 0x1DF8u + use_offset_0x1df8u];
-      break;
-
-    case 0x2u:
-      if (hb_in_range<hb_codepoint_t> (u, 0x2008u, 0x2017u)) return use_table[u - 0x2008u + use_offset_0x2008u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x2070u, 0x2087u)) return use_table[u - 0x2070u + use_offset_0x2070u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x20F0u, 0x20F7u)) return use_table[u - 0x20F0u + use_offset_0x20f0u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x25C8u, 0x25CFu)) return use_table[u - 0x25C8u + use_offset_0x25c8u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x2D30u, 0x2D7Fu)) return use_table[u - 0x2D30u + use_offset_0x2d30u];
-      break;
-
-    case 0xAu:
-      if (hb_in_range<hb_codepoint_t> (u, 0xA800u, 0xAAF7u)) return use_table[u - 0xA800u + use_offset_0xa800u];
-      if (hb_in_range<hb_codepoint_t> (u, 0xABC0u, 0xABFFu)) return use_table[u - 0xABC0u + use_offset_0xabc0u];
-      break;
-
-    case 0xFu:
-      if (hb_in_range<hb_codepoint_t> (u, 0xFE00u, 0xFE0Fu)) return use_table[u - 0xFE00u + use_offset_0xfe00u];
-      break;
-
-    case 0x10u:
-      if (hb_in_range<hb_codepoint_t> (u, 0x10570u, 0x105BFu)) return use_table[u - 0x10570u + use_offset_0x10570u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x10A00u, 0x10A4Fu)) return use_table[u - 0x10A00u + use_offset_0x10a00u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x10AC0u, 0x10AEFu)) return use_table[u - 0x10AC0u + use_offset_0x10ac0u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x10B80u, 0x10BAFu)) return use_table[u - 0x10B80u + use_offset_0x10b80u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x10D00u, 0x10D3Fu)) return use_table[u - 0x10D00u + use_offset_0x10d00u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x10E80u, 0x10EB7u)) return use_table[u - 0x10E80u + use_offset_0x10e80u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x10F30u, 0x110C7u)) return use_table[u - 0x10F30u + use_offset_0x10f30u];
-      break;
-
-    case 0x11u:
-      if (hb_in_range<hb_codepoint_t> (u, 0x10F30u, 0x110C7u)) return use_table[u - 0x10F30u + use_offset_0x10f30u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x11100u, 0x1123Fu)) return use_table[u - 0x11100u + use_offset_0x11100u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x11280u, 0x11377u)) return use_table[u - 0x11280u + use_offset_0x11280u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x11400u, 0x114DFu)) return use_table[u - 0x11400u + use_offset_0x11400u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x11580u, 0x11747u)) return use_table[u - 0x11580u + use_offset_0x11580u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x11800u, 0x1183Fu)) return use_table[u - 0x11800u + use_offset_0x11800u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x11900u, 0x1195Fu)) return use_table[u - 0x11900u + use_offset_0x11900u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x119A0u, 0x11A9Fu)) return use_table[u - 0x119A0u + use_offset_0x119a0u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x11C00u, 0x11CB7u)) return use_table[u - 0x11C00u + use_offset_0x11c00u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x11D00u, 0x11DAFu)) return use_table[u - 0x11D00u + use_offset_0x11d00u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x11EE0u, 0x11EF7u)) return use_table[u - 0x11EE0u + use_offset_0x11ee0u];
-      break;
-
-    case 0x13u:
-      if (hb_in_range<hb_codepoint_t> (u, 0x13000u, 0x1343Fu)) return use_table[u - 0x13000u + use_offset_0x13000u];
-      break;
-
-    case 0x16u:
-      if (hb_in_range<hb_codepoint_t> (u, 0x16AC0u, 0x16B37u)) return use_table[u - 0x16AC0u + use_offset_0x16ac0u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x16F00u, 0x16F97u)) return use_table[u - 0x16F00u + use_offset_0x16f00u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x16FE0u, 0x16FE7u)) return use_table[u - 0x16FE0u + use_offset_0x16fe0u];
-      break;
-
-    case 0x18u:
-      if (hb_in_range<hb_codepoint_t> (u, 0x18B00u, 0x18CD7u)) return use_table[u - 0x18B00u + use_offset_0x18b00u];
-      break;
-
-    case 0x1Bu:
-      if (hb_in_range<hb_codepoint_t> (u, 0x1BC00u, 0x1BC9Fu)) return use_table[u - 0x1BC00u + use_offset_0x1bc00u];
-      break;
-
-    case 0x1Eu:
-      if (hb_in_range<hb_codepoint_t> (u, 0x1E100u, 0x1E14Fu)) return use_table[u - 0x1E100u + use_offset_0x1e100u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x1E290u, 0x1E2FFu)) return use_table[u - 0x1E290u + use_offset_0x1e290u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x1E900u, 0x1E95Fu)) return use_table[u - 0x1E900u + use_offset_0x1e900u];
-      break;
-
-    case 0xE0u:
-      if (hb_in_range<hb_codepoint_t> (u, 0xE0100u, 0xE01EFu)) return use_table[u - 0xE0100u + use_offset_0xe0100u];
-      break;
-
-    default:
-      break;
-  }
-  return USE(O);
-}
-
-#undef B
-#undef CGJ
-#undef CS
-#undef G
-#undef GB
-#undef H
-#undef HN
-#undef HVM
-#undef J
-#undef N
-#undef O
-#undef R
-#undef SB
-#undef SE
-#undef SUB
-#undef Sk
-#undef ZWNJ
-#undef CMAbv
-#undef CMBlw
-#undef FAbv
-#undef FBlw
-#undef FPst
-#undef FMAbv
-#undef FMBlw
-#undef FMPst
-#undef MAbv
-#undef MBlw
-#undef MPst
-#undef MPre
-#undef SMAbv
-#undef SMBlw
-#undef VAbv
-#undef VBlw
-#undef VPst
-#undef VPre
-#undef VMAbv
-#undef VMBlw
-#undef VMPst
-#undef VMPre
-
-
-#endif /* HB_OT_SHAPE_COMPLEX_USE_TABLE_HH */
-/* == End of generated table == */
index aa5a8ee..69dbec0 100644 (file)
@@ -29,7 +29,7 @@
 #ifndef HB_NO_OT_SHAPE
 
 #include "hb-ot-shape-normalize.hh"
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shaper.hh"
 #include "hb-ot-shape.hh"
 
 
@@ -69,7 +69,7 @@
  *   - When a font does not support a character but supports its canonical
  *     decomposition, well, use the decomposition.
  *
- *   - The complex shapers can customize the compose and decompose functions to
+ *   - The shapers can customize the compose and decompose functions to
  *     offload some of their requirements to the normalizer.  For example, the
  *     Indic shaper may want to disallow recomposing of two matras.
  */
@@ -143,8 +143,7 @@ decompose (const hb_ot_shape_normalize_context_t *c, bool shortest, hb_codepoint
     return 1;
   }
 
-  unsigned int ret;
-  if ((ret = decompose (c, shortest, a))) {
+  if (unsigned ret = decompose (c, shortest, a)) {
     if (b) {
       output_char (buffer, b, b_glyph);
       return ret + 1;
@@ -223,7 +222,7 @@ 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. */
+  /* Currently if there's a variation-selector we give-up on normalization, 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;) {
@@ -342,7 +341,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
     {
       unsigned int end;
       for (end = buffer->idx + 1; end < count; end++)
-       if (unlikely (_hb_glyph_info_is_unicode_mark (&buffer->info[end])))
+       if (_hb_glyph_info_is_unicode_mark (&buffer->info[end]))
          break;
 
       if (end < count)
@@ -384,18 +383,19 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
   if (!all_simple && buffer->message(font, "start reorder"))
   {
     count = buffer->len;
+    hb_glyph_info_t *info = buffer->info;
     for (unsigned int i = 0; i < count; i++)
     {
-      if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]) == 0)
+      if (_hb_glyph_info_get_modified_combining_class (&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)
+       if (_hb_glyph_info_get_modified_combining_class (&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) {
+      if (end - i > HB_OT_SHAPE_MAX_COMBINING_MARKS) {
        i = end;
        continue;
       }
@@ -415,11 +415,13 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
      * If it did NOT, then make it skippable.
      * https://github.com/harfbuzz/harfbuzz/issues/554
      */
-    for (unsigned int i = 1; i + 1 < buffer->len; i++)
-      if (buffer->info[i].codepoint == 0x034Fu/*CGJ*/ &&
-         (info_cc(buffer->info[i+1]) == 0 || info_cc(buffer->info[i-1]) <= info_cc(buffer->info[i+1])))
+    unsigned count = buffer->len;
+    hb_glyph_info_t *info = buffer->info;
+    for (unsigned int i = 1; i + 1 < count; i++)
+      if (info[i].codepoint == 0x034Fu/*CGJ*/ &&
+         (info_cc(info[i+1]) == 0 || info_cc(info[i-1]) <= info_cc(info[i+1])))
       {
-       _hb_glyph_info_unhide (&buffer->info[i]);
+       _hb_glyph_info_unhide (&info[i]);
       }
   }
 
index 4bd8aaf..90f596a 100644 (file)
@@ -37,7 +37,7 @@
 #include "hb-shaper-impl.hh"
 
 #include "hb-ot-shape.hh"
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shaper.hh"
 #include "hb-ot-shape-fallback.hh"
 #include "hb-ot-shape-normalize.hh"
 
 
 #include "hb-aat-layout.hh"
 
+static inline bool
+_hb_codepoint_is_regional_indicator (hb_codepoint_t u)
+{ return hb_in_range<hb_codepoint_t> (u, 0x1F1E6u, 0x1F1FFu); }
 
 #ifndef HB_NO_AAT_SHAPE
 static inline bool
-_hb_apply_morx (hb_face_t *face, const hb_segment_properties_t *props)
+_hb_apply_morx (hb_face_t *face, const hb_segment_properties_t &props)
 {
   /* https://github.com/harfbuzz/harfbuzz/issues/2124 */
   return hb_aat_layout_has_substitution (face) &&
-        (HB_DIRECTION_IS_HORIZONTAL (props->direction) || !hb_ot_layout_has_substitution (face));
+        (HB_DIRECTION_IS_HORIZONTAL (props.direction) || !hb_ot_layout_has_substitution (face));
 }
 #endif
 
@@ -74,23 +77,24 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
                              unsigned int                    num_user_features);
 
 hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t                     *face,
-                                             const hb_segment_properties_t *props) :
+                                             const hb_segment_properties_t &props) :
                                                face (face),
-                                               props (*props),
-                                               map (face, props),
-                                               aat_map (face, props)
+                                               props (props),
+                                               map (face, props)
 #ifndef HB_NO_AAT_SHAPE
                                                , apply_morx (_hb_apply_morx (face, props))
 #endif
 {
-  shaper = hb_ot_shape_complex_categorize (this);
+  shaper = hb_ot_shaper_categorize (this);
 
   script_zero_marks = shaper->zero_width_marks != HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE;
   script_fallback_mark_positioning = shaper->fallback_position;
 
+#ifndef HB_NO_AAT_SHAPE
   /* https://github.com/harfbuzz/harfbuzz/issues/1528 */
-  if (apply_morx && shaper != &_hb_ot_complex_shaper_default)
-    shaper = &_hb_ot_complex_shaper_dumber;
+  if (apply_morx && shaper != &_hb_ot_shaper_default)
+    shaper = &_hb_ot_shaper_dumber;
+#endif
 }
 
 void
@@ -100,10 +104,6 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t           &plan,
   plan.props = props;
   plan.shaper = shaper;
   map.compile (plan.map, key);
-#ifndef HB_NO_AAT_SHAPE
-  if (apply_morx)
-    aat_map.compile (plan.aat_map);
-#endif
 
 #ifndef HB_NO_OT_SHAPE_FRACTIONS
   plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c'));
@@ -217,12 +217,9 @@ hb_ot_shape_plan_t::init0 (hb_face_t                     *face,
                           const hb_shape_plan_key_t     *key)
 {
   map.init ();
-#ifndef HB_NO_AAT_SHAPE
-  aat_map.init ();
-#endif
 
   hb_ot_shape_planner_t planner (face,
-                                &key->props);
+                                key->props);
 
   hb_ot_shape_collect_features (&planner,
                                key->user_features,
@@ -236,9 +233,6 @@ hb_ot_shape_plan_t::init0 (hb_face_t                     *face,
     if (unlikely (!data))
     {
       map.fini ();
-#ifndef HB_NO_AAT_SHAPE
-      aat_map.fini ();
-#endif
       return false;
     }
   }
@@ -253,21 +247,13 @@ hb_ot_shape_plan_t::fini ()
     shaper->data_destroy (const_cast<void *> (data));
 
   map.fini ();
-#ifndef HB_NO_AAT_SHAPE
-  aat_map.fini ();
-#endif
 }
 
 void
 hb_ot_shape_plan_t::substitute (hb_font_t   *font,
                                hb_buffer_t *buffer) const
 {
-#ifndef HB_NO_AAT_SHAPE
-  if (unlikely (apply_morx))
-    hb_aat_layout_substitute (this, font, buffer);
-  else
-#endif
-    map.substitute (this, font, buffer);
+  map.substitute (this, font, buffer);
 }
 
 void
@@ -327,6 +313,8 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
 {
   hb_ot_map_builder_t *map = &planner->map;
 
+  map->is_simple = true;
+
   map->enable_feature (HB_TAG('r','v','r','n'));
   map->add_gsub_pause (nullptr);
 
@@ -368,7 +356,10 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
   map->enable_feature (HB_TAG ('H','A','R','F')); /* Considered discretionary. */
 
   if (planner->shaper->collect_features)
+  {
+    map->is_simple = false;
     planner->shaper->collect_features (planner);
+  }
 
   map->enable_feature (HB_TAG ('B','u','z','z')); /* Considered required. */
   map->enable_feature (HB_TAG ('B','U','Z','Z')); /* Considered discretionary. */
@@ -392,6 +383,8 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
     map->enable_feature (HB_TAG ('v','e','r','t'), F_GLOBAL_SEARCH);
   }
 
+  if (num_user_features)
+    map->is_simple = false;
   for (unsigned int i = 0; i < num_user_features; i++)
   {
     const hb_feature_t *feature = &user_features[i];
@@ -401,18 +394,6 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
                      feature->value);
   }
 
-#ifndef HB_NO_AAT_SHAPE
-  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);
-    }
-  }
-#endif
-
   if (planner->shaper->override_features)
     planner->shaper->override_features (planner);
 }
@@ -495,18 +476,27 @@ hb_set_unicode_props (hb_buffer_t *buffer)
   {
     _hb_glyph_info_set_unicode_props (&info[i], buffer);
 
+    unsigned gen_cat = _hb_glyph_info_get_general_category (&info[i]);
+    if (FLAG_UNSAFE (gen_cat) &
+       (FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) |
+        FLAG (HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER) |
+        FLAG (HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER) |
+        FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) |
+        FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR)))
+      continue;
+
     /* 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 &&
+    if (unlikely (gen_cat == HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL &&
                  hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x1F3FBu, 0x1F3FFu)))
     {
       _hb_glyph_info_set_continuation (&info[i]);
     }
     /* Regional_Indicators are hairy as hell...
      * https://github.com/harfbuzz/harfbuzz/issues/2265 */
-    else if (unlikely (i && hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x1F1E6u, 0x1F1FFu)))
+    else if (unlikely (i && _hb_codepoint_is_regional_indicator (info[i].codepoint)))
     {
-      if (hb_in_range<hb_codepoint_t> (info[i - 1].codepoint, 0x1F1E6u, 0x1F1FFu) &&
+      if (_hb_codepoint_is_regional_indicator (info[i - 1].codepoint) &&
          !_hb_glyph_info_is_continuation (&info[i - 1]))
        _hb_glyph_info_set_continuation (&info[i]);
     }
@@ -524,18 +514,20 @@ hb_set_unicode_props (hb_buffer_t *buffer)
     }
 #endif
     /* Or part of the Other_Grapheme_Extend that is not marks.
-     * As of Unicode 11 that is just:
+     * As of Unicode 15 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.
+     * it separate results in more granular clusters.
      * Tags are used for Emoji sub-region flag sequences:
      * https://github.com/harfbuzz/harfbuzz/issues/1556
+     * Katakana ones were requested:
+     * https://github.com/harfbuzz/harfbuzz/issues/3844
      */
-    else if (unlikely (hb_in_range<hb_codepoint_t> (info[i].codepoint, 0xE0020u, 0xE007Fu)))
+    else if (unlikely (hb_in_ranges<hb_codepoint_t> (info[i].codepoint, 0xFF9Eu, 0xFF9Fu, 0xE0020u, 0xE007Fu)))
       _hb_glyph_info_set_continuation (&info[i]);
   }
 }
@@ -598,24 +590,33 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
    * direction, so that features like ligatures will work as intended.
    *
    * https://github.com/harfbuzz/harfbuzz/issues/501
+   *
+   * Similar thing about Regional_Indicators; They are bidi=L, but Script=Common.
+   * If they are present in a run of natively-RTL text, they get assigned a script
+   * with natively RTL direction, which would result in wrong shaping if we
+   * assign such native RTL direction to them then. Detect that as well.
+   *
+   * https://github.com/harfbuzz/harfbuzz/issues/3314
    */
   if (unlikely (horiz_dir == HB_DIRECTION_RTL && direction == HB_DIRECTION_LTR))
   {
-    bool found_number = false, found_letter = false;
+    bool found_number = false, found_letter = false, found_ri = false;
     const auto* info = buffer->info;
     const auto count = buffer->len;
     for (unsigned i = 0; i < count; i++)
     {
       auto gc = _hb_glyph_info_get_general_category (&info[i]);
       if (gc == HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
-        found_number = true;
+       found_number = true;
       else if (HB_UNICODE_GENERAL_CATEGORY_IS_LETTER (gc))
       {
-        found_letter = true;
-        break;
+       found_letter = true;
+       break;
       }
+      else if (_hb_codepoint_is_regional_indicator (info[i].codepoint))
+       found_ri = true;
     }
-    if (found_number && !found_letter)
+    if ((found_number || found_ri) && !found_letter)
       horiz_dir = HB_DIRECTION_LTR;
   }
 
@@ -764,6 +765,14 @@ hb_ot_shape_setup_masks_fraction (const hb_ot_shape_context_t *c)
             _hb_glyph_info_get_general_category (&info[end]) ==
             HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
        end++;
+      if (start == i || end == i + 1)
+      {
+        if (start == i)
+         buffer->unsafe_to_concat (start, start + 1);
+       if (end == i + 1)
+         buffer->unsafe_to_concat (end - 1, end);
+       continue;
+      }
 
       buffer->unsafe_to_break (start, end);
 
@@ -850,7 +859,7 @@ hb_ot_hide_default_ignorables (hb_buffer_t *buffer,
     }
   }
   else
-    hb_ot_layout_delete_glyphs_inplace (buffer, _hb_glyph_info_is_default_ignorable);
+    buffer->delete_glyphs_inplace (_hb_glyph_info_is_default_ignorable);
 }
 
 
@@ -915,7 +924,7 @@ hb_ot_substitute_default (const hb_ot_shape_context_t *c)
 }
 
 static inline void
-hb_ot_substitute_complex (const hb_ot_shape_context_t *c)
+hb_ot_substitute_plan (const hb_ot_shape_context_t *c)
 {
   hb_buffer_t *buffer = c->buffer;
 
@@ -924,7 +933,13 @@ hb_ot_substitute_complex (const hb_ot_shape_context_t *c)
   if (c->plan->fallback_glyph_classes)
     hb_synthesize_glyph_classes (c->buffer);
 
-  c->plan->substitute (c->font, buffer);
+#ifndef HB_NO_AAT_SHAPE
+  if (unlikely (c->plan->apply_morx))
+    hb_aat_layout_substitute (c->plan, c->font, c->buffer,
+                             c->user_features, c->num_user_features);
+  else
+#endif
+    c->plan->substitute (c->font, buffer);
 }
 
 static inline void
@@ -934,18 +949,24 @@ hb_ot_substitute_pre (const hb_ot_shape_context_t *c)
 
   _hb_buffer_allocate_gsubgpos_vars (c->buffer);
 
-  hb_ot_substitute_complex (c);
+  hb_ot_substitute_plan (c);
+
+#ifndef HB_NO_AAT_SHAPE
+  if (c->plan->apply_morx && c->plan->apply_gpos)
+    hb_aat_layout_remove_deleted_glyphs (c->buffer);
+#endif
 }
 
 static inline void
 hb_ot_substitute_post (const hb_ot_shape_context_t *c)
 {
-  hb_ot_hide_default_ignorables (c->buffer, c->font);
 #ifndef HB_NO_AAT_SHAPE
-  if (c->plan->apply_morx)
+  if (c->plan->apply_morx && !c->plan->apply_gpos)
     hb_aat_layout_remove_deleted_glyphs (c->buffer);
 #endif
 
+  hb_ot_hide_default_ignorables (c->buffer, c->font);
+
   if (c->plan->shaper->postprocess_glyphs &&
     c->buffer->message(c->font, "start postprocess-glyphs")) {
     c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);
@@ -1021,7 +1042,7 @@ hb_ot_position_default (const hb_ot_shape_context_t *c)
 }
 
 static inline void
-hb_ot_position_complex (const hb_ot_shape_context_t *c)
+hb_ot_position_plan (const hb_ot_shape_context_t *c)
 {
   unsigned int count = c->buffer->len;
   hb_glyph_info_t *info = c->buffer->info;
@@ -1033,7 +1054,7 @@ hb_ot_position_complex (const hb_ot_shape_context_t *c)
    * direction is backward we don't shift and it will end up
    * hanging over the next glyph after the final reordering.
    *
-   * Note: If fallback positinoing happens, we don't care about
+   * Note: If fallback positioning happens, we don't care about
    * this as it will be overridden.
    */
   bool adjust_offsets_when_zeroing = c->plan->adjust_mark_positioning_when_zeroing &&
@@ -1106,7 +1127,7 @@ hb_ot_position (const hb_ot_shape_context_t *c)
 
   hb_ot_position_default (c);
 
-  hb_ot_position_complex (c);
+  hb_ot_position_plan (c);
 
   if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
     hb_buffer_reverse (c->buffer);
@@ -1123,6 +1144,18 @@ hb_propagate_flags (hb_buffer_t *buffer)
   if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS))
     return;
 
+  /* If we are producing SAFE_TO_INSERT_TATWEEL, then do two things:
+   *
+   * - If the places that the Arabic shaper marked as SAFE_TO_INSERT_TATWEEL,
+   *   are UNSAFE_TO_BREAK, then clear the SAFE_TO_INSERT_TATWEEL,
+   * - Any place that is SAFE_TO_INSERT_TATWEEL, is also now UNSAFE_TO_BREAK.
+   *
+   * We couldn't make this interaction earlier. It has to be done here.
+   */
+  bool flip_tatweel = buffer->flags & HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL;
+
+  bool clear_concat = (buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0;
+
   hb_glyph_info_t *info = buffer->info;
 
   foreach_cluster (buffer, start, end)
@@ -1130,9 +1163,20 @@ hb_propagate_flags (hb_buffer_t *buffer)
     unsigned int mask = 0;
     for (unsigned int i = start; i < end; i++)
       mask |= info[i].mask & HB_GLYPH_FLAG_DEFINED;
-    if (mask)
-      for (unsigned int i = start; i < end; i++)
-       info[i].mask |= mask;
+
+    if (flip_tatweel)
+    {
+      if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
+       mask &= ~HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL;
+      if (mask & HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL)
+       mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT;
+    }
+
+    if (clear_concat)
+       mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_CONCAT;
+
+    for (unsigned int i = start; i < end; i++)
+      info[i].mask = mask;
   }
 }
 
@@ -1141,8 +1185,6 @@ hb_propagate_flags (hb_buffer_t *buffer)
 static void
 hb_ot_shape_internal (hb_ot_shape_context_t *c)
 {
-  c->buffer->enter ();
-
   /* Save the original direction, we use it later. */
   c->target_direction = c->buffer->props.direction;
 
index e8c8101..f84aa5c 100644 (file)
@@ -51,7 +51,7 @@ struct hb_ot_shape_plan_key_t
 
   bool equal (const hb_ot_shape_plan_key_t *other)
   {
-    return 0 == memcmp (this, other, sizeof (*this));
+    return 0 == hb_memcmp (this, other, sizeof (*this));
   }
 };
 
@@ -60,10 +60,11 @@ struct hb_shape_plan_key_t;
 
 struct hb_ot_shape_plan_t
 {
+  ~hb_ot_shape_plan_t () { fini (); }
+
   hb_segment_properties_t props;
-  const struct hb_ot_complex_shaper_t *shaper;
+  const struct hb_ot_shaper_t *shaper;
   hb_ot_map_t map;
-  hb_aat_map_t aat_map;
   const void *data;
 #ifndef HB_NO_OT_SHAPE_FRACTIONS
   hb_mask_t frac_mask, numr_mask, dnom_mask;
@@ -150,7 +151,6 @@ struct hb_ot_shape_planner_t
   hb_face_t *face;
   hb_segment_properties_t props;
   hb_ot_map_builder_t map;
-  hb_aat_map_builder_t aat_map;
 #ifndef HB_NO_AAT_SHAPE
   bool apply_morx : 1;
 #else
@@ -158,10 +158,10 @@ struct hb_ot_shape_planner_t
 #endif
   bool script_zero_marks : 1;
   bool script_fallback_mark_positioning : 1;
-  const struct hb_ot_complex_shaper_t *shaper;
+  const struct hb_ot_shaper_t *shaper;
 
   HB_INTERNAL hb_ot_shape_planner_t (hb_face_t                     *face,
-                                    const hb_segment_properties_t *props);
+                                    const hb_segment_properties_t &props);
 
   HB_INTERNAL void compile (hb_ot_shape_plan_t           &plan,
                            const hb_ot_shape_plan_key_t &key);
similarity index 77%
rename from src/hb-ot-shape-complex-arabic-fallback.hh
rename to src/hb-ot-shaper-arabic-fallback.hh
index 78f46c1..66a8bfb 100644 (file)
@@ -24,8 +24,8 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH
-#define HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH
+#ifndef HB_OT_SHAPER_ARABIC_FALLBACK_HH
+#define HB_OT_SHAPER_ARABIC_FALLBACK_HH
 
 #include "hb.hh"
 
 
 
 /* Features ordered the same as the entries in shaping_table rows,
- * followed by rlig.  Don't change. */
+ * followed by rlig.  Don't change.
+ *
+ * We currently support one subtable per lookup, and one lookup
+ * per feature.  But we allow duplicate features, so we use that!
+ */
 static const hb_tag_t arabic_fallback_features[] =
 {
   HB_TAG('i','n','i','t'),
@@ -42,6 +46,8 @@ static const hb_tag_t arabic_fallback_features[] =
   HB_TAG('f','i','n','a'),
   HB_TAG('i','s','o','l'),
   HB_TAG('r','l','i','g'),
+  HB_TAG('r','l','i','g'),
+  HB_TAG('r','l','i','g'),
 };
 
 static OT::SubstLookup *
@@ -95,20 +101,25 @@ arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUS
   return ret && !c.in_error () ? c.copy<OT::SubstLookup> () : nullptr;
 }
 
+template <typename T>
 static OT::SubstLookup *
 arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UNUSED,
-                                           hb_font_t *font)
+                                           hb_font_t *font,
+                                           const T &ligature_table,
+                                           unsigned lookup_flags)
 {
   OT::HBGlyphID16 first_glyphs[ARRAY_LENGTH_CONST (ligature_table)];
   unsigned int first_glyphs_indirection[ARRAY_LENGTH_CONST (ligature_table)];
   unsigned int ligature_per_first_glyph_count_list[ARRAY_LENGTH_CONST (first_glyphs)];
   unsigned int num_first_glyphs = 0;
 
-  /* We know that all our ligatures are 2-component */
+  /* We know that all our ligatures have the same number of components. */
   OT::HBGlyphID16 ligature_list[ARRAY_LENGTH_CONST (first_glyphs) * ARRAY_LENGTH_CONST(ligature_table[0].ligatures)];
   unsigned int component_count_list[ARRAY_LENGTH_CONST (ligature_list)];
-  OT::HBGlyphID16 component_list[ARRAY_LENGTH_CONST (ligature_list) * 1/* One extra component per ligature */];
+  OT::HBGlyphID16 component_list[ARRAY_LENGTH_CONST (ligature_list) *
+                                ARRAY_LENGTH_CONST (ligature_table[0].ligatures[0].components)];
   unsigned int num_ligatures = 0;
+  unsigned int num_components = 0;
 
   /* Populate arrays */
 
@@ -133,21 +144,38 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN
   {
     unsigned int first_glyph_idx = first_glyphs_indirection[i];
 
-    for (unsigned int second_glyph_idx = 0; second_glyph_idx < ARRAY_LENGTH (ligature_table[0].ligatures); second_glyph_idx++)
+    for (unsigned int ligature_idx = 0; ligature_idx < ARRAY_LENGTH (ligature_table[0].ligatures); ligature_idx++)
     {
-      hb_codepoint_t second_u   = ligature_table[first_glyph_idx].ligatures[second_glyph_idx].second;
-      hb_codepoint_t ligature_u = ligature_table[first_glyph_idx].ligatures[second_glyph_idx].ligature;
-      hb_codepoint_t second_glyph, ligature_glyph;
-      if (!second_u ||
-         !hb_font_get_glyph (font, second_u,   0, &second_glyph) ||
-         !hb_font_get_glyph (font, ligature_u, 0, &ligature_glyph))
+      hb_codepoint_t ligature_u = ligature_table[first_glyph_idx].ligatures[ligature_idx].ligature;
+      hb_codepoint_t ligature_glyph;
+      if (!hb_font_get_glyph (font, ligature_u, 0, &ligature_glyph))
        continue;
 
-      ligature_per_first_glyph_count_list[i]++;
+      const auto &components = ligature_table[first_glyph_idx].ligatures[ligature_idx].components;
+      unsigned component_count = ARRAY_LENGTH_CONST (components);
+
+      bool matched = true;
+      for (unsigned j = 0; j < component_count; j++)
+      {
+       hb_codepoint_t component_u   = ligature_table[first_glyph_idx].ligatures[ligature_idx].components[j];
+       hb_codepoint_t component_glyph;
+       if (!component_u ||
+           !hb_font_get_nominal_glyph (font, component_u, &component_glyph))
+       {
+         matched = false;
+         break;
+       }
+
+       component_list[num_components++] = component_glyph;
+      }
+      if (!matched)
+        continue;
 
+      component_count_list[num_ligatures] = 1 + component_count;
       ligature_list[num_ligatures] = ligature_glyph;
-      component_count_list[num_ligatures] = 2;
-      component_list[num_ligatures] = second_glyph;
+
+      ligature_per_first_glyph_count_list[i]++;
+
       num_ligatures++;
     }
   }
@@ -161,14 +189,13 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN
   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,
+                                        lookup_flags,
                                         hb_sorted_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));
+                                        hb_array (component_list, num_components));
   c.end_serialize ();
-  /* TODO sanitize the results? */
 
   return ret && !c.in_error () ? c.copy<OT::SubstLookup> () : nullptr;
 }
@@ -181,10 +208,18 @@ arabic_fallback_synthesize_lookup (const hb_ot_shape_plan_t *plan,
   if (feature_index < 4)
     return arabic_fallback_synthesize_lookup_single (plan, font, feature_index);
   else
-    return arabic_fallback_synthesize_lookup_ligature (plan, font);
+  {
+    switch (feature_index) {
+      case 4: return arabic_fallback_synthesize_lookup_ligature (plan, font, ligature_3_table, OT::LookupFlag::IgnoreMarks);
+      case 5: return arabic_fallback_synthesize_lookup_ligature (plan, font, ligature_table, OT::LookupFlag::IgnoreMarks);
+      case 6: return arabic_fallback_synthesize_lookup_ligature (plan, font, ligature_mark_table, 0);
+    }
+  }
+  assert (false);
+  return nullptr;
 }
 
-#define ARABIC_FALLBACK_MAX_LOOKUPS 5
+#define ARABIC_FALLBACK_MAX_LOOKUPS ARRAY_LENGTH_CONST (arabic_fallback_features)
 
 struct arabic_fallback_plan_t
 {
@@ -193,7 +228,7 @@ struct arabic_fallback_plan_t
 
   hb_mask_t mask_array[ARABIC_FALLBACK_MAX_LOOKUPS];
   OT::SubstLookup *lookup_array[ARABIC_FALLBACK_MAX_LOOKUPS];
-  OT::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];
 };
 
 #if defined(_WIN32) && !defined(HB_NO_WIN1256)
@@ -201,7 +236,7 @@ struct arabic_fallback_plan_t
 #endif
 
 #ifdef HB_WITH_WIN1256
-#include "hb-ot-shape-complex-arabic-win1256.hh"
+#include "hb-ot-shaper-arabic-win1256.hh"
 #endif
 
 struct ManifestLookup
@@ -230,9 +265,8 @@ arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan HB_UNUS
     return false;
 
   const Manifest &manifest = reinterpret_cast<const Manifest&> (arabic_win1256_gsub_lookups.manifest);
-  static_assert (sizeof (arabic_win1256_gsub_lookups.manifestData) ==
+  static_assert (sizeof (arabic_win1256_gsub_lookups.manifestData) <=
                 ARABIC_FALLBACK_MAX_LOOKUPS * sizeof (ManifestLookup), "");
-  /* TODO sanitize the table? */
 
   unsigned j = 0;
   unsigned int count = manifest.len;
@@ -244,7 +278,7 @@ arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan HB_UNUS
       fallback_plan->lookup_array[j] = const_cast<OT::SubstLookup*> (&(&manifest+manifest[i].lookupOffset));
       if (fallback_plan->lookup_array[j])
       {
-       fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]);
+       fallback_plan->accel_array[j] = OT::hb_ot_layout_lookup_accelerator_t::create (*fallback_plan->lookup_array[j]);
        j++;
       }
     }
@@ -264,7 +298,7 @@ arabic_fallback_plan_init_unicode (arabic_fallback_plan_t *fallback_plan,
                                   const hb_ot_shape_plan_t *plan,
                                   hb_font_t *font)
 {
-  static_assert ((ARRAY_LENGTH_CONST(arabic_fallback_features) <= ARABIC_FALLBACK_MAX_LOOKUPS), "");
+  static_assert ((ARRAY_LENGTH_CONST (arabic_fallback_features) <= ARABIC_FALLBACK_MAX_LOOKUPS), "");
   unsigned int j = 0;
   for (unsigned int i = 0; i < ARRAY_LENGTH(arabic_fallback_features) ; i++)
   {
@@ -274,7 +308,7 @@ arabic_fallback_plan_init_unicode (arabic_fallback_plan_t *fallback_plan,
       fallback_plan->lookup_array[j] = arabic_fallback_synthesize_lookup (plan, font, i);
       if (fallback_plan->lookup_array[j])
       {
-       fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]);
+       fallback_plan->accel_array[j] = OT::hb_ot_layout_lookup_accelerator_t::create (*fallback_plan->lookup_array[j]);
        j++;
       }
     }
@@ -321,7 +355,7 @@ arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan)
   for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
     if (fallback_plan->lookup_array[i])
     {
-      fallback_plan->accel_array[i].fini ();
+      hb_free (fallback_plan->accel_array[i]);
       if (fallback_plan->free_lookups)
        hb_free (fallback_plan->lookup_array[i]);
     }
@@ -334,15 +368,16 @@ arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan,
                            hb_font_t *font,
                            hb_buffer_t *buffer)
 {
-  OT::hb_ot_apply_context_t c (0, font, buffer);
+  OT::hb_ot_apply_context_t c (0, font, buffer, hb_blob_get_empty ());
   for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
     if (fallback_plan->lookup_array[i]) {
       c.set_lookup_mask (fallback_plan->mask_array[i]);
-      hb_ot_layout_substitute_lookup (&c,
-                                     *fallback_plan->lookup_array[i],
-                                     fallback_plan->accel_array[i]);
+      if (fallback_plan->accel_array[i])
+       hb_ot_layout_substitute_lookup (&c,
+                                       *fallback_plan->lookup_array[i],
+                                       *fallback_plan->accel_array[i]);
     }
 }
 
 
-#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH */
+#endif /* HB_OT_SHAPER_ARABIC_FALLBACK_HH */
similarity index 73%
rename from src/hb-ot-shape-complex-arabic-joining-list.hh
rename to src/hb-ot-shaper-arabic-joining-list.hh
index e6339ee..a5a7b84 100644 (file)
@@ -6,14 +6,14 @@
  *
  * on files with these headers:
  *
- * # ArabicShaping-14.0.0.txt
- * # Date: 2021-05-21, 01:54:00 GMT [KW, RP]
- * # Scripts-14.0.0.txt
- * # Date: 2021-07-10, 00:35:31 GMT
+ * # ArabicShaping-15.1.0.txt
+ * # Date: 2023-01-05
+ * # Scripts-15.1.0.txt
+ * # Date: 2023-07-28, 16:01:07 GMT
  */
 
-#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH
-#define HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH
+#ifndef HB_OT_SHAPER_ARABIC_JOINING_LIST_HH
+#define HB_OT_SHAPER_ARABIC_JOINING_LIST_HH
 
 static bool
 has_arabic_joining (hb_script_t script)
@@ -42,6 +42,6 @@ has_arabic_joining (hb_script_t script)
 }
 
 
-#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH */
+#endif /* HB_OT_SHAPER_ARABIC_JOINING_LIST_HH */
 
 /* == End of generated function == */
diff --git a/src/hb-ot-shaper-arabic-pua.hh b/src/hb-ot-shaper-arabic-pua.hh
new file mode 100644 (file)
index 0000000..ba86772
--- /dev/null
@@ -0,0 +1,118 @@
+/* == Start of generated table == */
+/*
+ * The following table is generated by running:
+ *
+ *   ./gen-arabic-pua.py
+ *
+ */
+
+#ifndef HB_OT_SHAPER_ARABIC_PUA_HH
+#define HB_OT_SHAPER_ARABIC_PUA_HH
+
+static const uint8_t
+_hb_arabic_u8[464] =
+{
+   84, 86, 85, 85, 85, 85, 85,213, 16, 34, 34, 34, 34, 34, 35, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 36, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 82, 16,  0,  0,  0,  0,  1,  2,  3,  4,
+    0,  0,  0,  5,  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0,  7,
+    0,  0,  8,  0,  0,  0,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0, 10,  0, 11, 12, 13, 14, 15,
+   16, 17, 18, 19, 20, 21,  0,  0,  0, 22,  0, 23,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0, 24, 25, 26, 27, 28, 29, 30, 31,
+   32, 33, 34, 35, 36, 37, 38, 39, 16, 34, 34, 34, 35, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 66, 16, 50, 68, 68, 68, 68, 68, 68,
+   68, 68, 68, 68,101, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+   71, 68, 68, 68, 68, 68, 68, 68,152,186, 76, 77, 68,254, 16, 50,
+    0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  4,  0,  0,  5,  6,
+    0,  0,  0,  0,  0,  0,  7,  8,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  0,  0,  0, 10,  0,
+    0,  0,  0,  0,  0, 11,  0,  0,  0,  0,  0,  0,  0, 12,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0, 13,  0,  0, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+   24, 25, 26, 27, 28, 23, 23, 29, 30, 31, 32, 33,  0,  0,  0,  0,
+    0,  0,  0, 34,  0,  0,  0, 35,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 36, 37, 38,  0,  0,  0,  0,  0,  0,  0, 39,  0,  0, 40,
+   41, 42,  0, 43, 44,  0,  0, 45, 46,  0, 47, 48, 49,  0,  0,  0,
+    0, 50,  0,  0, 51, 52,  0, 53, 54, 55, 56, 57, 58,  0,  0,  0,
+    0,  0, 59, 60, 61, 62, 63, 64,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 65,  0,  0, 66,
+    0,  0, 67,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   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,
+};
+static const uint16_t
+_hb_arabic_u16[720] =
+{
+      0,    0,    0,    0,    0,    0,    0,    0,61728,61729,61730,    0,    0,61733,    0,    0,
+  61736,61737,61738,61739,61790,61741,61742,61743,61872,61873,61874,61875,61876,61877,61878,61879,
+  61880,61881,61754,61755,    0,61757,    0,61759,    0,    0,    0,61787,61788,61789,    0,    0,
+      0,    0,    0,61731,    0,    0,    0,    0,    0,    0,    0,61732,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,    0,    0,61734,    0,    0,    0,    0,    0,    0,    0,61735,
+      0,    0,    0,    0,61740,    0,    0,    0,    0,    0,    0,61755,    0,    0,    0,61759,
+      0,61869,61765,61763,61883,61767,61882,61761,61770,61865,61772,61774,61777,61780,61783,61784,
+  61785,61786,61792,61794,61796,61798,61800,61801,61802,61806,61810,61696,61696,61696,61696,61696,
+  61791,61813,61816,61818,61820,61822,61921,61860,61861,61868,61864,61895,61896,61899,61892,61893,
+  61898,61897,61894,61696,61696,61696,61696,61696,61696,61696,61696,61696,61696,61696,61696,    0,
+  61744,61745,61746,61747,61748,61749,61750,61751,61752,61753,    0,61790,61790,    0,    0,    0,
+      0,    0,    0,    0,61708,61709,61710,61711,61756,61758,    0,    0,    0,    0,    0,    0,
+      0,61765,61766,61763,61764,61883,61883,61767,61768,61882,61871,61870,61870,61761,61762,61770,
+  61770,61769,61769,61865,61866,61772,61772,61771,61771,61774,61774,61773,61773,61777,61776,61775,
+  61775,61780,61779,61778,61778,61783,61782,61781,61781,61784,61784,61785,61785,61786,61786,61792,
+  61792,61794,61794,61793,61793,61796,61796,61795,61795,61798,61798,61797,61797,61800,61800,61799,
+  61799,61801,61801,61801,61801,61802,61802,61802,61802,61806,61805,61803,61804,61810,61809,61807,
+  61808,61813,61813,61811,61812,61816,61816,61814,61815,61818,61818,61817,61817,61820,61820,61819,
+  61819,61822,61822,61821,61821,61921,61921,61823,61823,61860,61859,61857,61858,61861,61861,61868,
+  61867,61864,61863,61862,61862,61888,61889,61886,61887,61890,61891,61885,61884,    0,    0,    0,
+      0,    0,    0,    0,61984,61985,61986,    0,    0,61989,    0,    0,61992,61993,61994,61995,
+  62046,61997,61998,61999,    0,    0,62010,62011,    0,62013,    0,62015,    0,    0,    0,62043,
+      0,62045,    0,    0,    0,    0,    0,61987,    0,    0,    0,61988,    0,    0,    0,61990,
+      0,    0,    0,61991,61996,    0,    0,    0,    0,    0,    0,62011,    0,    0,    0,62015,
+      0,62165,62021,62019,62170,62023,62169,62017,62028,62161,62032,62036,62040,62048,62052,62053,
+  62055,62057,62059,62064,62068,62072,62078,62114,62115,62122,62126,61952,61952,61952,61952,61952,
+  62047,62130,62134,62138,62142,62146,62150,62154,62155,62164,62160,62183,62184,62187,62180,62181,
+  62186,62185,62182,61952,61952,61952,61952,    0,62000,62001,62002,62003,62004,62005,62006,62007,
+  62008,62009,    0,62046,62046,    0,    0,    0,61964,61965,61966,61967,62012,62014,    0,    0,
+  61954,    0,61981,    0,    0,    0,61955,    0,61982,    0,61956,    0,    0,    0,62111,    0,
+      0,    0,    0,61970,61971,61972,61957,    0,61980,    0,    0,    0,    0,    0,61958,    0,
+  61983,    0,    0,    0,    0,    0,62191,    0,62188,62189,62192,    0,    0,    0,61973,    0,
+      0,62098,    0,    0,61974,    0,    0,62099,    0,    0,62101,    0,    0,61975,    0,    0,
+  62100,    0,    0,    0,62080,62081,62082,62102,    0,62083,62084,62085,62103,    0,    0,    0,
+  62106,    0,62107,    0,62108,    0,    0,    0,61976,    0,    0,    0,    0,62086,62087,62088,
+  62109,61978,62089,62090,62091,62110,62093,62094,    0,62104,    0,    0,    0,    0,62095,62096,
+  62097,62105,    0,    0,61977,    0,    0,    0,    0,    0,62075,62077,61968,    0,    0,    0,
+      0,62021,62022,62019,62020,62170,62171,62023,62024,62169,62168,62166,62167,62017,62018,62028,
+  62027,62025,62026,62161,62162,62032,62031,62029,62030,62036,62035,62033,62034,62040,62039,62037,
+  62038,62048,62044,62041,62042,62052,62051,62049,62050,62053,62054,62055,62056,62057,62058,62059,
+  62060,62064,62063,62061,62062,62068,62067,62065,62066,62072,62071,62069,62070,62078,62076,62073,
+  62074,62114,62113,62079,62193,62118,62117,62115,62116,62122,62121,62119,62120,62126,62125,62123,
+  62124,62130,62129,62127,62128,62134,62133,62131,62132,62138,62137,62135,62136,62142,62141,62139,
+  62140,62146,62145,62143,62144,62150,62149,62147,62148,62154,62153,62151,62152,62155,62156,62164,
+  62163,62160,62159,62157,62158,62176,62177,62174,62175,62178,62179,62172,62173,    0,    0,    0,
+};
+
+static inline unsigned
+_hb_arabic_b2 (const uint8_t* a, unsigned i)
+{
+  return (a[i>>2]>>((i&3u)<<1))&3u;
+}
+static inline unsigned
+_hb_arabic_b4 (const uint8_t* a, unsigned i)
+{
+  return (a[i>>1]>>((i&1u)<<2))&15u;
+}
+static inline uint_fast16_t
+_hb_arabic_pua_simp_map (unsigned u)
+{
+  return u<65277u?_hb_arabic_u16[((_hb_arabic_u8[40+(((_hb_arabic_b4(8+_hb_arabic_u8,((_hb_arabic_b2(_hb_arabic_u8,u>>3>>4>>4))<<4)+((u>>3>>4)&15u)))<<4)+((u>>3)&15u))])<<3)+((u)&7u)]:0;
+}
+static inline uint_fast16_t
+_hb_arabic_pua_trad_map (unsigned u)
+{
+  return u<65277u?_hb_arabic_u16[320+(((_hb_arabic_u8[208+(((_hb_arabic_b4(168+_hb_arabic_u8,((_hb_arabic_b4(136+_hb_arabic_u8,u>>2>>4>>4))<<4)+((u>>2>>4)&15u)))<<4)+((u>>2)&15u))])<<2)+((u)&3u))]:0;
+}
+
+#endif /* HB_OT_SHAPER_ARABIC_PUA_HH */
+
+/* == End of generated table == */
similarity index 74%
rename from src/hb-ot-shape-complex-arabic-table.hh
rename to src/hb-ot-shaper-arabic-table.hh
index c158964..336a139 100644 (file)
@@ -6,15 +6,15 @@
  *
  * on files with these headers:
  *
- * # ArabicShaping-14.0.0.txt
- * # Date: 2021-05-21, 01:54:00 GMT [KW, RP]
- * # Blocks-14.0.0.txt
- * # Date: 2021-01-22, 23:29:00 GMT [KW]
+ * # ArabicShaping-15.1.0.txt
+ * # Date: 2023-01-05
+ * # Blocks-15.1.0.txt
+ * # Date: 2023-07-28, 15:47:20 GMT
  * UnicodeData.txt does not have a header.
  */
 
-#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH
-#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH
+#ifndef HB_OT_SHAPER_ARABIC_TABLE_HH
+#define HB_OT_SHAPER_ARABIC_TABLE_HH
 
 
 #define A      JOINING_GROUP_ALAPH
@@ -416,26 +416,141 @@ static const uint16_t shaping_table[][4] =
 static const struct ligature_set_t {
  uint16_t first;
  struct ligature_pairs_t {
-   uint16_t second;
+   uint16_t components[1];
    uint16_t ligature;
- } ligatures[4];
+ } ligatures[14];
 } ligature_table[] =
 {
+  { 0xFE91u, {
+    { {0xFEE2u}, 0xFC08u }, /* ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM */
+    { {0xFEE4u}, 0xFC9Fu }, /* ARABIC LIGATURE BEH WITH MEEM INITIAL FORM */
+    { {0xFEA0u}, 0xFC9Cu }, /* ARABIC LIGATURE BEH WITH JEEM INITIAL FORM */
+    { {0xFEA4u}, 0xFC9Du }, /* ARABIC LIGATURE BEH WITH HAH INITIAL FORM */
+    { {0xFEA8u}, 0xFC9Eu }, /* ARABIC LIGATURE BEH WITH KHAH INITIAL FORM */
+  }},
+  { 0xFE92u, {
+    { {0xFEAEu}, 0xFC6Au }, /* ARABIC LIGATURE BEH WITH REH FINAL FORM */
+    { {0xFEE6u}, 0xFC6Du }, /* ARABIC LIGATURE BEH WITH NOON FINAL FORM */
+    { {0xFEF2u}, 0xFC6Fu }, /* ARABIC LIGATURE BEH WITH YEH FINAL FORM */
+  }},
+  { 0xFE97u, {
+    { {0xFEE2u}, 0xFC0Eu }, /* ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM */
+    { {0xFEE4u}, 0xFCA4u }, /* ARABIC LIGATURE TEH WITH MEEM INITIAL FORM */
+    { {0xFEA0u}, 0xFCA1u }, /* ARABIC LIGATURE TEH WITH JEEM INITIAL FORM */
+    { {0xFEA4u}, 0xFCA2u }, /* ARABIC LIGATURE TEH WITH HAH INITIAL FORM */
+    { {0xFEA8u}, 0xFCA3u }, /* ARABIC LIGATURE TEH WITH KHAH INITIAL FORM */
+  }},
+  { 0xFE98u, {
+    { {0xFEAEu}, 0xFC70u }, /* ARABIC LIGATURE TEH WITH REH FINAL FORM */
+    { {0xFEE6u}, 0xFC73u }, /* ARABIC LIGATURE TEH WITH NOON FINAL FORM */
+    { {0xFEF2u}, 0xFC75u }, /* ARABIC LIGATURE TEH WITH YEH FINAL FORM */
+  }},
+  { 0xFE9Bu, {
+    { {0xFEE2u}, 0xFC12u }, /* ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM */
+  }},
+  { 0xFE9Fu, {
+    { {0xFEE4u}, 0xFCA8u }, /* ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM */
+  }},
+  { 0xFEA3u, {
+    { {0xFEE4u}, 0xFCAAu }, /* ARABIC LIGATURE HAH WITH MEEM INITIAL FORM */
+  }},
+  { 0xFEA7u, {
+    { {0xFEE4u}, 0xFCACu }, /* ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM */
+  }},
+  { 0xFEB3u, {
+    { {0xFEE4u}, 0xFCB0u }, /* ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM */
+  }},
+  { 0xFEB7u, {
+    { {0xFEE4u}, 0xFD30u }, /* ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM */
+  }},
+  { 0xFED3u, {
+    { {0xFEF2u}, 0xFC32u }, /* ARABIC LIGATURE FEH WITH YEH ISOLATED FORM */
+  }},
   { 0xFEDFu, {
-    { 0xFE82u, 0xFEF5u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM */
-    { 0xFE84u, 0xFEF7u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM */
-    { 0xFE88u, 0xFEF9u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM */
-    { 0xFE8Eu, 0xFEFBu }, /* ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM */
+    { {0xFE9Eu}, 0xFC3Fu }, /* ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM */
+    { {0xFEA0u}, 0xFCC9u }, /* ARABIC LIGATURE LAM WITH JEEM INITIAL FORM */
+    { {0xFEA2u}, 0xFC40u }, /* ARABIC LIGATURE LAM WITH HAH ISOLATED FORM */
+    { {0xFEA4u}, 0xFCCAu }, /* ARABIC LIGATURE LAM WITH HAH INITIAL FORM */
+    { {0xFEA6u}, 0xFC41u }, /* ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM */
+    { {0xFEA8u}, 0xFCCBu }, /* ARABIC LIGATURE LAM WITH KHAH INITIAL FORM */
+    { {0xFEE2u}, 0xFC42u }, /* ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM */
+    { {0xFEE4u}, 0xFCCCu }, /* ARABIC LIGATURE LAM WITH MEEM INITIAL FORM */
+    { {0xFEF2u}, 0xFC44u }, /* ARABIC LIGATURE LAM WITH YEH ISOLATED FORM */
+    { {0xFEECu}, 0xFCCDu }, /* ARABIC LIGATURE LAM WITH HEH INITIAL FORM */
+    { {0xFE82u}, 0xFEF5u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM */
+    { {0xFE84u}, 0xFEF7u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM */
+    { {0xFE88u}, 0xFEF9u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM */
+    { {0xFE8Eu}, 0xFEFBu }, /* ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM */
   }},
   { 0xFEE0u, {
-    { 0xFE82u, 0xFEF6u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM */
-    { 0xFE84u, 0xFEF8u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM */
-    { 0xFE88u, 0xFEFAu }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM */
-    { 0xFE8Eu, 0xFEFCu }, /* ARABIC LIGATURE LAM WITH ALEF FINAL FORM */
+    { {0xFEF0u}, 0xFC86u }, /* ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM */
+    { {0xFE82u}, 0xFEF6u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM */
+    { {0xFE84u}, 0xFEF8u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM */
+    { {0xFE88u}, 0xFEFAu }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM */
+    { {0xFE8Eu}, 0xFEFCu }, /* ARABIC LIGATURE LAM WITH ALEF FINAL FORM */
+  }},
+  { 0xFEE3u, {
+    { {0xFEA0u}, 0xFCCEu }, /* ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM */
+    { {0xFEA4u}, 0xFCCFu }, /* ARABIC LIGATURE MEEM WITH HAH INITIAL FORM */
+    { {0xFEA8u}, 0xFCD0u }, /* ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM */
+    { {0xFEE4u}, 0xFCD1u }, /* ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM */
+  }},
+  { 0xFEE7u, {
+    { {0xFEE2u}, 0xFC4Eu }, /* ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM */
+    { {0xFEE4u}, 0xFCD5u }, /* ARABIC LIGATURE NOON WITH MEEM INITIAL FORM */
+    { {0xFEA0u}, 0xFCD2u }, /* ARABIC LIGATURE NOON WITH JEEM INITIAL FORM */
+    { {0xFEA4u}, 0xFCD3u }, /* ARABIC LIGATURE NOON WITH HAH INITIAL FORM */
+  }},
+  { 0xFEE8u, {
+    { {0xFEF2u}, 0xFC8Fu }, /* ARABIC LIGATURE NOON WITH YEH FINAL FORM */
+  }},
+  { 0xFEF3u, {
+    { {0xFEA0u}, 0xFCDAu }, /* ARABIC LIGATURE YEH WITH JEEM INITIAL FORM */
+    { {0xFEA4u}, 0xFCDBu }, /* ARABIC LIGATURE YEH WITH HAH INITIAL FORM */
+    { {0xFEA8u}, 0xFCDCu }, /* ARABIC LIGATURE YEH WITH KHAH INITIAL FORM */
+    { {0xFEE4u}, 0xFCDDu }, /* ARABIC LIGATURE YEH WITH MEEM INITIAL FORM */
+  }},
+  { 0xFEF4u, {
+    { {0xFEAEu}, 0xFC91u }, /* ARABIC LIGATURE YEH WITH REH FINAL FORM */
+    { {0xFEE6u}, 0xFC94u }, /* ARABIC LIGATURE YEH WITH NOON FINAL FORM */
+  }},
+};
+
+
+static const struct ligature_mark_set_t {
+ uint16_t first;
+ struct ligature_pairs_t {
+   uint16_t components[1];
+   uint16_t ligature;
+ } ligatures[5];
+} ligature_mark_table[] =
+{
+  { 0x0651u, {
+    { {0x064Cu}, 0xFC5Eu }, /* ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM */
+    { {0x064Eu}, 0xFC60u }, /* ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM */
+    { {0x064Fu}, 0xFC61u }, /* ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM */
+    { {0x0650u}, 0xFC62u }, /* ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM */
+    { {0x064Bu}, 0xF2EEu }, /* PUA ARABIC LIGATURE SHADDA WITH FATHATAN ISOLATED FORM */
+  }},
+};
+
+
+static const struct ligature_3_set_t {
+ uint16_t first;
+ struct ligature_triplets_t {
+   uint16_t components[2];
+   uint16_t ligature;
+ } ligatures[3];
+} ligature_3_table[] =
+{
+  { 0xFEDFu, {
+    { {0xFEE4u, 0xFEA4u}, 0xFD88u}, /* ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM */
+    { {0xFEE0u, 0xFEEAu}, 0xF201u}, /* PUA ARABIC LIGATURE LELLAH ISOLATED FORM */
+    { {0xFEE4u, 0xFEA0u}, 0xF211u}, /* PUA ARABIC LIGATURE LAM WITH MEEM WITH JEEM INITIAL FORM */
   }},
 };
 
 
-#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH */
+#endif /* HB_OT_SHAPER_ARABIC_TABLE_HH */
 
 /* == End of generated table == */
similarity index 98%
rename from src/hb-ot-shape-complex-arabic-win1256.hh
rename to src/hb-ot-shaper-arabic-win1256.hh
index 429974d..b8d481c 100644 (file)
@@ -24,7 +24,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH
+#ifndef HB_OT_SHAPER_ARABIC_WIN1256_HH
 
 
 /*
@@ -342,8 +342,8 @@ OT_TABLE_END
 #include "hb.hh" /* Make check-includes.sh happy. */
 #endif
 #ifdef OT_MEASURE
-#include "hb-ot-shape-complex-arabic-win1256.hh"
+#include "hb-ot-shaper-arabic-win1256.hh"
 #endif
 
-#define HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH
-#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH */
+#define HB_OT_SHAPER_ARABIC_WIN1256_HH
+#endif /* HB_OT_SHAPER_ARABIC_WIN1256_HH */
similarity index 89%
rename from src/hb-ot-shape-complex-arabic.cc
rename to src/hb-ot-shaper-arabic.cc
index 224f8b8..72dcc84 100644 (file)
 
 #ifndef HB_NO_OT_SHAPE
 
-#include "hb-ot-shape-complex-arabic.hh"
+#include "hb-ot-shaper-arabic.hh"
 #include "hb-ot-shape.hh"
 
 
 /* buffer var allocations */
-#define arabic_shaping_action() complex_var_u8_auxiliary() /* arabic shaping action */
+#define arabic_shaping_action() ot_shaper_var_u8_auxiliary() /* arabic shaping action */
 
-#define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_COMPLEX0
+#define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_SHAPER0
 
 /* See:
  * https://github.com/harfbuzz/harfbuzz/commit/6e6f82b6f3dde0fc6c3c7d991d9ec6cfff57823d#commitcomment-14248516 */
@@ -81,7 +81,7 @@ enum hb_arabic_joining_type_t {
   JOINING_TYPE_X = 8  /* means: use general-category to choose between U or T. */
 };
 
-#include "hb-ot-shape-complex-arabic-table.hh"
+#include "hb-ot-shaper-arabic-table.hh"
 
 static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat)
 {
@@ -161,16 +161,25 @@ static const struct arabic_state_table_entry {
 };
 
 
-static void
+static bool
 arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
                       hb_font_t *font,
                       hb_buffer_t *buffer);
 
-static void
+static bool
 record_stch (const hb_ot_shape_plan_t *plan,
             hb_font_t *font,
             hb_buffer_t *buffer);
 
+static bool
+deallocate_buffer_var (const hb_ot_shape_plan_t *plan,
+                      hb_font_t *font,
+                      hb_buffer_t *buffer)
+{
+  HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
+  return false;
+}
+
 static void
 collect_features_arabic (hb_ot_shape_planner_t *plan)
 {
@@ -193,26 +202,24 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
    * work.  However, testing shows that rlig and calt are applied
    * together for Mongolian in Uniscribe.  As such, we only add a
    * pause for Arabic, not other scripts.
-   *
-   * A pause after calt is required to make KFGQPC Uthmanic Script HAFS
-   * work correctly.  See https://github.com/harfbuzz/harfbuzz/issues/505
    */
 
 
   map->enable_feature (HB_TAG('s','t','c','h'));
   map->add_gsub_pause (record_stch);
 
-  map->enable_feature (HB_TAG('c','c','m','p'));
-  map->enable_feature (HB_TAG('l','o','c','l'));
+  map->enable_feature (HB_TAG('c','c','m','p'), F_MANUAL_ZWJ);
+  map->enable_feature (HB_TAG('l','o','c','l'), F_MANUAL_ZWJ);
 
   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], has_fallback ? F_HAS_FALLBACK : F_NONE);
+    map->add_feature (arabic_features[i], F_MANUAL_ZWJ | (has_fallback ? F_HAS_FALLBACK : F_NONE));
     map->add_gsub_pause (nullptr);
   }
+   map->add_gsub_pause (deallocate_buffer_var);
 
   /* 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
@@ -223,10 +230,16 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
   if (plan->props.script == HB_SCRIPT_ARABIC)
     map->add_gsub_pause (arabic_fallback_shape);
 
-  /* No pause after rclt.  See 98460779bae19e4d64d29461ff154b3527bf8420. */
-  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);
+   map->enable_feature (HB_TAG('c','a','l','t'), F_MANUAL_ZWJ);
+   /* https://github.com/harfbuzz/harfbuzz/issues/1573 */
+   if (!map->has_feature (HB_TAG('r','c','l','t')))
+   {
+     map->add_gsub_pause (nullptr);
+     map->enable_feature (HB_TAG('r','c','l','t'), F_MANUAL_ZWJ);
+   }
+
+   map->enable_feature (HB_TAG('l','i','g','a'), F_MANUAL_ZWJ);
+   map->enable_feature (HB_TAG('c','l','i','g'), F_MANUAL_ZWJ);
 
   /* The spec includes 'cswh'.  Earlier versions of Windows
    * used to enable this by default, but testing suggests
@@ -236,11 +249,11 @@ 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->enable_feature (HB_TAG('c','s','w','h'));
-  map->enable_feature (HB_TAG('m','s','e','t'));
+  //map->enable_feature (HB_TAG('c','s','w','h'), F_MANUAL_ZWJ);
+  map->enable_feature (HB_TAG('m','s','e','t'), F_MANUAL_ZWJ);
 }
 
-#include "hb-ot-shape-complex-arabic-fallback.hh"
+#include "hb-ot-shaper-arabic-fallback.hh"
 
 struct arabic_shape_plan_t
 {
@@ -319,7 +332,7 @@ arabic_joining (hb_buffer_t *buffer)
     if (entry->prev_action != NONE && prev != UINT_MAX)
     {
       info[prev].arabic_shaping_action() = entry->prev_action;
-      buffer->unsafe_to_break (prev, i + 1);
+      buffer->safe_to_insert_tatweel (prev, i + 1);
     }
     else
     {
@@ -353,7 +366,7 @@ arabic_joining (hb_buffer_t *buffer)
     if (entry->prev_action != NONE && prev != UINT_MAX)
     {
       info[prev].arabic_shaping_action() = entry->prev_action;
-      buffer->unsafe_to_break (prev, buffer->len);
+      buffer->safe_to_insert_tatweel (prev, buffer->len);
     }
     else if (2 <= state && state <= 5) /* States that have a possible prev_action. */
     {
@@ -400,19 +413,19 @@ setup_masks_arabic (const hb_ot_shape_plan_t *plan,
   setup_masks_arabic_plan (arabic_plan, buffer, plan->props.script);
 }
 
-static void
+static bool
 arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
                       hb_font_t *font,
                       hb_buffer_t *buffer)
 {
-#ifdef HB_NO_OT_SHAPE_COMPLEX_ARABIC_FALLBACK
-  return;
+#ifdef HB_NO_OT_SHAPER_ARABIC_FALLBACK
+  return false;
 #endif
 
   const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
 
   if (!arabic_plan->do_fallback)
-    return;
+    return false;
 
 retry:
   arabic_fallback_plan_t *fallback_plan = arabic_plan->fallback_plan;
@@ -428,6 +441,7 @@ retry:
   }
 
   arabic_fallback_plan_shape (fallback_plan, font, buffer);
+  return true;
 }
 
 /*
@@ -438,14 +452,14 @@ retry:
  * marks can use it as well.
  */
 
-static void
+static bool
 record_stch (const hb_ot_shape_plan_t *plan,
             hb_font_t *font HB_UNUSED,
             hb_buffer_t *buffer)
 {
   const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
   if (!arabic_plan->has_stch)
-    return;
+    return false;
 
   /* 'stch' feature was just applied.  Look for anything that multiplied,
    * and record it for stch treatment later.  Note that rtlm, frac, etc
@@ -461,6 +475,7 @@ record_stch (const hb_ot_shape_plan_t *plan,
       info[i].arabic_shaping_action() = comp % 2 ? STCH_REPEATING : STCH_FIXED;
       buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH;
     }
+  return false;
 }
 
 static void
@@ -471,8 +486,10 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
   if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH)))
     return;
 
-  /* The Arabic shaper currently always processes in RTL mode, so we should
-   * stretch / position the stretched pieces to the left / preceding glyphs. */
+  bool rtl = buffer->props.direction == HB_DIRECTION_RTL;
+
+  if (!rtl)
+    buffer->reverse ();
 
   /* We do a two pass implementation:
    * First pass calculates the exact number of extra glyphs we need,
@@ -541,9 +558,9 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
       }
       i++; // Don't touch i again.
 
-      DEBUG_MSG (ARABIC, nullptr, "%s stretch at (%d,%d,%d)",
+      DEBUG_MSG (ARABIC, nullptr, "%s stretch at (%u,%u,%u)",
                 step == MEASURE ? "measuring" : "cutting", context, start, end);
-      DEBUG_MSG (ARABIC, nullptr, "rest of word:    count=%d width %d", start - context, w_total);
+      DEBUG_MSG (ARABIC, nullptr, "rest of word:    count=%u width %d", start - context, w_total);
       DEBUG_MSG (ARABIC, nullptr, "fixed tiles:     count=%d width=%d", n_fixed, w_fixed);
       DEBUG_MSG (ARABIC, nullptr, "repeating tiles: count=%d width=%d", n_repeating, w_repeating);
 
@@ -562,7 +579,10 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
        ++n_copies;
        hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_remaining;
        if (excess > 0)
+       {
          extra_repeat_overlap = excess / (n_copies * n_repeating);
+         w_remaining = 0;
+       }
       }
 
       if (step == MEASURE)
@@ -573,7 +593,7 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
       else
       {
        buffer->unsafe_to_break (context, end);
-       hb_position_t x_offset = 0;
+       hb_position_t x_offset = w_remaining / 2;
        for (unsigned int k = end; k > start; k--)
        {
          hb_position_t width = font->get_glyph_h_advance (info[k - 1].codepoint);
@@ -582,18 +602,29 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
          if (info[k - 1].arabic_shaping_action() == STCH_REPEATING)
            repeat += n_copies;
 
-         DEBUG_MSG (ARABIC, nullptr, "appending %d copies of glyph %d; j=%d",
+         DEBUG_MSG (ARABIC, nullptr, "appending %u copies of glyph %u; j=%u",
                     repeat, info[k - 1].codepoint, j);
+         pos[k - 1].x_advance = 0;
          for (unsigned int n = 0; n < repeat; n++)
          {
-           x_offset -= width;
-           if (n > 0)
-             x_offset += extra_repeat_overlap;
+           if (rtl)
+           {
+             x_offset -= width;
+             if (n > 0)
+               x_offset += extra_repeat_overlap;
+           }
            pos[k - 1].x_offset = x_offset;
            /* Append copy. */
            --j;
            info[j] = info[k - 1];
            pos[j] = pos[k - 1];
+
+           if (!rtl)
+           {
+             x_offset += width;
+             if (n > 0)
+               x_offset -= extra_repeat_overlap;
+           }
          }
        }
       }
@@ -610,6 +641,9 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
       buffer->len = new_len;
     }
   }
+
+  if (!rtl)
+    buffer->reverse ();
 }
 
 
@@ -619,8 +653,6 @@ postprocess_glyphs_arabic (const hb_ot_shape_plan_t *plan,
                           hb_font_t                *font)
 {
   apply_stch (plan, buffer, font);
-
-  HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
 }
 
 /* https://www.unicode.org/reports/tr53/ */
@@ -662,15 +694,15 @@ reorder_marks_arabic (const hb_ot_shape_plan_t *plan HB_UNUSED,
 {
   hb_glyph_info_t *info = buffer->info;
 
-  DEBUG_MSG (ARABIC, buffer, "Reordering marks from %d to %d", start, end);
+  DEBUG_MSG (ARABIC, buffer, "Reordering marks from %u to %u", start, end);
 
   unsigned int i = start;
   for (unsigned int cc = 220; cc <= 230; cc += 10)
   {
-    DEBUG_MSG (ARABIC, buffer, "Looking for %d's starting at %d", cc, i);
+    DEBUG_MSG (ARABIC, buffer, "Looking for %u's starting at %u", cc, i);
     while (i < end && info_cc(info[i]) < cc)
       i++;
-    DEBUG_MSG (ARABIC, buffer, "Looking for %d's stopped at %d", cc, i);
+    DEBUG_MSG (ARABIC, buffer, "Looking for %u's stopped at %u", cc, i);
 
     if (i == end)
       break;
@@ -685,11 +717,11 @@ reorder_marks_arabic (const hb_ot_shape_plan_t *plan HB_UNUSED,
     if (i == j)
       continue;
 
-    DEBUG_MSG (ARABIC, buffer, "Found %d's from %d to %d", cc, i, j);
+    DEBUG_MSG (ARABIC, buffer, "Found %u's from %u to %u", cc, i, j);
 
     /* Shift it! */
-    DEBUG_MSG (ARABIC, buffer, "Shifting %d's: %d %d", cc, i, j);
-    hb_glyph_info_t temp[HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS];
+    DEBUG_MSG (ARABIC, buffer, "Shifting %u's: %u %u", cc, i, j);
+    hb_glyph_info_t temp[HB_OT_SHAPE_MAX_COMBINING_MARKS];
     assert (j - i <= ARRAY_LENGTH (temp));
     buffer->merge_clusters (start, j);
     memmove (temp, &info[i], (j - i) * sizeof (hb_glyph_info_t));
@@ -720,7 +752,7 @@ reorder_marks_arabic (const hb_ot_shape_plan_t *plan HB_UNUSED,
   }
 }
 
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
+const hb_ot_shaper_t _hb_ot_shaper_arabic =
 {
   collect_features_arabic,
   nullptr, /* override_features */
@@ -728,12 +760,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
   data_destroy_arabic,
   nullptr, /* preprocess_text */
   postprocess_glyphs_arabic,
-  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   nullptr, /* decompose */
   nullptr, /* compose */
   setup_masks_arabic,
-  HB_TAG_NONE, /* gpos_tag */
   reorder_marks_arabic,
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
similarity index 90%
rename from src/hb-ot-shape-complex-arabic.hh
rename to src/hb-ot-shaper-arabic.hh
index 5bf6ff6..a025b1a 100644 (file)
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_HH
-#define HB_OT_SHAPE_COMPLEX_ARABIC_HH
+#ifndef HB_OT_SHAPER_ARABIC_HH
+#define HB_OT_SHAPER_ARABIC_HH
 
 #include "hb.hh"
 
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shaper.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_HH */
+#endif /* HB_OT_SHAPER_ARABIC_HH */
similarity index 93%
rename from src/hb-ot-shape-complex-default.cc
rename to src/hb-ot-shaper-default.cc
index a755aea..f0404a4 100644 (file)
 
 #ifndef HB_NO_OT_SHAPE
 
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shaper.hh"
 
 
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
+const hb_ot_shaper_t _hb_ot_shaper_default =
 {
   nullptr, /* collect_features */
   nullptr, /* override_features */
@@ -39,19 +39,20 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
   nullptr, /* data_destroy */
   nullptr, /* preprocess_text */
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   nullptr, /* decompose */
   nullptr, /* compose */
   nullptr, /* setup_masks */
-  HB_TAG_NONE, /* gpos_tag */
   nullptr, /* reorder_marks */
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
 
+#ifndef HB_NO_AAT_SHAPE
 /* Same as default but no mark advance zeroing / fallback positioning.
  * Dumbest shaper ever, basically. */
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_dumber =
+const hb_ot_shaper_t _hb_ot_shaper_dumber =
 {
   nullptr, /* collect_features */
   nullptr, /* override_features */
@@ -59,15 +60,16 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_dumber =
   nullptr, /* data_destroy */
   nullptr, /* preprocess_text */
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   nullptr, /* decompose */
   nullptr, /* compose */
   nullptr, /* setup_masks */
-  HB_TAG_NONE, /* gpos_tag */
   nullptr, /* reorder_marks */
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
+#endif
 
 
 #endif
similarity index 98%
rename from src/hb-ot-shape-complex-hangul.cc
rename to src/hb-ot-shaper-hangul.cc
index 3bc9e9b..c90476b 100644 (file)
@@ -28,7 +28,7 @@
 
 #ifndef HB_NO_OT_SHAPE
 
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shaper.hh"
 
 
 /* Hangul shaper */
@@ -119,7 +119,7 @@ data_destroy_hangul (void *data)
 #define isHangulTone(u) (hb_in_range<hb_codepoint_t> ((u), 0x302Eu, 0x302Fu))
 
 /* buffer var allocations */
-#define hangul_shaping_feature() complex_var_u8_auxiliary() /* hangul jamo shaping feature */
+#define hangul_shaping_feature() ot_shaper_var_u8_auxiliary() /* hangul jamo shaping feature */
 
 static bool
 is_zero_width_char (hb_font_t *font,
@@ -414,7 +414,7 @@ setup_masks_hangul (const hb_ot_shape_plan_t *plan,
 }
 
 
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul =
+const hb_ot_shaper_t _hb_ot_shaper_hangul =
 {
   collect_features_hangul,
   override_features_hangul,
@@ -422,12 +422,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul =
   data_destroy_hangul,
   preprocess_text_hangul,
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
   nullptr, /* decompose */
   nullptr, /* compose */
   setup_masks_hangul,
-  HB_TAG_NONE, /* gpos_tag */
   nullptr, /* reorder_marks */
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
similarity index 82%
rename from src/hb-ot-shape-complex-hebrew.cc
rename to src/hb-ot-shaper-hebrew.cc
index 334d3de..e18edd6 100644 (file)
@@ -28,7 +28,7 @@
 
 #ifndef HB_NO_OT_SHAPE
 
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shaper.hh"
 
 
 static bool
@@ -74,7 +74,7 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c,
 
   bool found = (bool) c->unicode->compose (a, b, ab);
 
-#ifdef HB_NO_OT_SHAPE_COMPLEX_HEBREW_FALLBACK
+#ifdef HB_NO_OT_SHAPER_HEBREW_FALLBACK
   return found;
 #endif
 
@@ -89,7 +89,7 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c,
              found = true;
          }
          break;
-      case 0x05B7u: /* patah */
+      case 0x05B7u: /* PATAH */
          if (a == 0x05F2u) { /* YIDDISH YOD YOD */
              *ab = 0xFB1Fu;
              found = true;
@@ -162,8 +162,34 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c,
   return found;
 }
 
+static void
+reorder_marks_hebrew (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                     hb_buffer_t              *buffer,
+                     unsigned int              start,
+                     unsigned int              end)
+{
+  hb_glyph_info_t *info = buffer->info;
+
+  for (unsigned i = start + 2; i < end; i++)
+  {
+    unsigned c0 = info_cc (info[i - 2]);
+    unsigned c1 = info_cc (info[i - 1]);
+    unsigned c2 = info_cc (info[i - 0]);
+
+    if ((c0 == HB_MODIFIED_COMBINING_CLASS_CCC17 || c0 == HB_MODIFIED_COMBINING_CLASS_CCC18) /* patach or qamats */ &&
+       (c1 == HB_MODIFIED_COMBINING_CLASS_CCC10 || c1 == HB_MODIFIED_COMBINING_CLASS_CCC14) /* sheva or hiriq */ &&
+       (c2 == HB_MODIFIED_COMBINING_CLASS_CCC22 || c2 == HB_UNICODE_COMBINING_CLASS_BELOW) /* meteg or below */)
+    {
+      buffer->merge_clusters (i - 1, i + 1);
+      hb_swap (info[i - 1], info[i]);
+      break;
+    }
+  }
 
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
+
+}
+
+const hb_ot_shaper_t _hb_ot_shaper_hebrew =
 {
   nullptr, /* collect_features */
   nullptr, /* override_features */
@@ -171,12 +197,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
   nullptr, /* data_destroy */
   nullptr, /* preprocess_text */
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   nullptr, /* decompose */
   compose_hebrew,
   nullptr, /* setup_masks */
+  reorder_marks_hebrew,
   HB_TAG ('h','e','b','r'), /* gpos_tag. https://github.com/harfbuzz/harfbuzz/issues/347#issuecomment-267838368 */
-  nullptr, /* reorder_marks */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
diff --git a/src/hb-ot-shaper-indic-machine.hh b/src/hb-ot-shaper-indic-machine.hh
new file mode 100644 (file)
index 0000000..353e32d
--- /dev/null
@@ -0,0 +1,627 @@
+
+#line 1 "hb-ot-shaper-indic-machine.rl"
+/*
+ * Copyright © 2011,2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPER_INDIC_MACHINE_HH
+#define HB_OT_SHAPER_INDIC_MACHINE_HH
+
+#include "hb.hh"
+
+#include "hb-ot-layout.hh"
+#include "hb-ot-shaper-indic.hh"
+
+/* buffer var allocations */
+#define indic_category() ot_shaper_var_u8_category() /* indic_category_t */
+#define indic_position() ot_shaper_var_u8_auxiliary() /* indic_position_t */
+
+using indic_category_t = unsigned;
+using indic_position_t = ot_position_t;
+
+#define I_Cat(Cat) indic_syllable_machine_ex_##Cat
+
+enum indic_syllable_type_t {
+  indic_consonant_syllable,
+  indic_vowel_syllable,
+  indic_standalone_cluster,
+  indic_symbol_cluster,
+  indic_broken_cluster,
+  indic_non_indic_cluster,
+};
+
+
+#line 57 "hb-ot-shaper-indic-machine.hh"
+#define indic_syllable_machine_ex_A 9u
+#define indic_syllable_machine_ex_C 1u
+#define indic_syllable_machine_ex_CM 16u
+#define indic_syllable_machine_ex_CS 18u
+#define indic_syllable_machine_ex_DOTTEDCIRCLE 11u
+#define indic_syllable_machine_ex_H 4u
+#define indic_syllable_machine_ex_M 7u
+#define indic_syllable_machine_ex_MPst 13u
+#define indic_syllable_machine_ex_N 3u
+#define indic_syllable_machine_ex_PLACEHOLDER 10u
+#define indic_syllable_machine_ex_RS 12u
+#define indic_syllable_machine_ex_Ra 15u
+#define indic_syllable_machine_ex_Repha 14u
+#define indic_syllable_machine_ex_SM 8u
+#define indic_syllable_machine_ex_Symbol 17u
+#define indic_syllable_machine_ex_V 2u
+#define indic_syllable_machine_ex_VD 9u
+#define indic_syllable_machine_ex_X 0u
+#define indic_syllable_machine_ex_ZWJ 6u
+#define indic_syllable_machine_ex_ZWNJ 5u
+
+
+#line 80 "hb-ot-shaper-indic-machine.hh"
+static const unsigned char _indic_syllable_machine_trans_keys[] = {
+       8u, 8u, 4u, 13u, 5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 4u, 13u, 
+       8u, 8u, 5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 4u, 13u, 4u, 13u, 
+       8u, 8u, 5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 4u, 13u, 8u, 8u, 
+       5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 5u, 13u, 8u, 8u, 1u, 18u, 
+       3u, 16u, 3u, 16u, 4u, 16u, 1u, 15u, 5u, 9u, 5u, 9u, 9u, 9u, 5u, 9u, 
+       1u, 15u, 1u, 15u, 1u, 15u, 3u, 13u, 4u, 13u, 5u, 13u, 5u, 13u, 4u, 13u, 
+       5u, 9u, 3u, 9u, 5u, 9u, 3u, 16u, 3u, 16u, 3u, 16u, 3u, 16u, 4u, 16u, 
+       1u, 15u, 3u, 16u, 3u, 16u, 4u, 16u, 1u, 15u, 5u, 9u, 9u, 9u, 5u, 9u, 
+       1u, 15u, 1u, 15u, 3u, 13u, 4u, 13u, 5u, 13u, 5u, 13u, 4u, 13u, 5u, 9u, 
+       5u, 9u, 3u, 9u, 5u, 9u, 3u, 16u, 3u, 16u, 4u, 13u, 3u, 16u, 3u, 16u, 
+       4u, 16u, 1u, 15u, 3u, 16u, 1u, 15u, 5u, 9u, 9u, 9u, 5u, 9u, 1u, 15u, 
+       1u, 15u, 3u, 13u, 4u, 13u, 5u, 13u, 5u, 13u, 3u, 16u, 4u, 13u, 5u, 9u, 
+       5u, 9u, 3u, 9u, 5u, 9u, 3u, 16u, 4u, 13u, 4u, 13u, 3u, 16u, 3u, 16u, 
+       4u, 16u, 1u, 15u, 3u, 16u, 1u, 15u, 5u, 9u, 9u, 9u, 5u, 9u, 1u, 15u, 
+       1u, 15u, 3u, 13u, 4u, 13u, 5u, 13u, 5u, 13u, 3u, 16u, 4u, 13u, 5u, 9u, 
+       5u, 9u, 3u, 9u, 5u, 9u, 1u, 16u, 3u, 16u, 1u, 16u, 4u, 13u, 5u, 13u, 
+       5u, 13u, 9u, 9u, 5u, 9u, 1u, 15u, 3u, 9u, 5u, 9u, 5u, 9u, 9u, 9u, 
+       5u, 9u, 1u, 15u, 0
+};
+
+static const char _indic_syllable_machine_key_spans[] = {
+       1, 10, 9, 9, 1, 10, 10, 10, 
+       1, 9, 9, 1, 10, 10, 10, 10, 
+       1, 9, 9, 1, 10, 10, 10, 1, 
+       9, 9, 1, 10, 10, 9, 1, 18, 
+       14, 14, 13, 15, 5, 5, 1, 5, 
+       15, 15, 15, 11, 10, 9, 9, 10, 
+       5, 7, 5, 14, 14, 14, 14, 13, 
+       15, 14, 14, 13, 15, 5, 1, 5, 
+       15, 15, 11, 10, 9, 9, 10, 5, 
+       5, 7, 5, 14, 14, 10, 14, 14, 
+       13, 15, 14, 15, 5, 1, 5, 15, 
+       15, 11, 10, 9, 9, 14, 10, 5, 
+       5, 7, 5, 14, 10, 10, 14, 14, 
+       13, 15, 14, 15, 5, 1, 5, 15, 
+       15, 11, 10, 9, 9, 14, 10, 5, 
+       5, 7, 5, 16, 14, 16, 10, 9, 
+       9, 1, 5, 15, 7, 5, 5, 1, 
+       5, 15
+};
+
+static const short _indic_syllable_machine_index_offsets[] = {
+       0, 2, 13, 23, 33, 35, 46, 57, 
+       68, 70, 80, 90, 92, 103, 114, 125, 
+       136, 138, 148, 158, 160, 171, 182, 193, 
+       195, 205, 215, 217, 228, 239, 249, 251, 
+       270, 285, 300, 314, 330, 336, 342, 344, 
+       350, 366, 382, 398, 410, 421, 431, 441, 
+       452, 458, 466, 472, 487, 502, 517, 532, 
+       546, 562, 577, 592, 606, 622, 628, 630, 
+       636, 652, 668, 680, 691, 701, 711, 722, 
+       728, 734, 742, 748, 763, 778, 789, 804, 
+       819, 833, 849, 864, 880, 886, 888, 894, 
+       910, 926, 938, 949, 959, 969, 984, 995, 
+       1001, 1007, 1015, 1021, 1036, 1047, 1058, 1073, 
+       1088, 1102, 1118, 1133, 1149, 1155, 1157, 1163, 
+       1179, 1195, 1207, 1218, 1228, 1238, 1253, 1264, 
+       1270, 1276, 1284, 1290, 1307, 1322, 1339, 1350, 
+       1360, 1370, 1372, 1378, 1394, 1402, 1408, 1414, 
+       1416, 1422
+};
+
+static const unsigned char _indic_syllable_machine_indicies[] = {
+       1, 0, 2, 3, 3, 4, 5, 0, 
+       0, 0, 0, 4, 0, 3, 3, 4, 
+       6, 0, 0, 0, 0, 4, 0, 3, 
+       3, 4, 5, 0, 0, 0, 0, 4, 
+       0, 4, 0, 7, 3, 3, 4, 5, 
+       0, 0, 0, 0, 4, 0, 2, 3, 
+       3, 4, 5, 0, 0, 0, 8, 4, 
+       0, 10, 11, 11, 12, 13, 9, 9, 
+       9, 9, 12, 9, 14, 9, 11, 11, 
+       12, 15, 9, 9, 9, 9, 12, 9, 
+       11, 11, 12, 13, 9, 9, 9, 9, 
+       12, 9, 12, 9, 16, 11, 11, 12, 
+       13, 9, 9, 9, 9, 12, 9, 10, 
+       11, 11, 12, 13, 9, 9, 9, 17, 
+       12, 9, 10, 11, 11, 12, 13, 9, 
+       9, 9, 18, 12, 9, 20, 21, 21, 
+       22, 23, 19, 19, 19, 24, 22, 19, 
+       25, 19, 21, 21, 22, 27, 26, 26, 
+       26, 26, 22, 26, 21, 21, 22, 23, 
+       19, 19, 19, 19, 22, 19, 22, 26, 
+       20, 21, 21, 22, 23, 19, 19, 19, 
+       19, 22, 19, 28, 21, 21, 22, 23, 
+       19, 19, 19, 19, 22, 19, 30, 31, 
+       31, 32, 33, 29, 29, 29, 34, 32, 
+       29, 35, 29, 31, 31, 32, 36, 29, 
+       29, 29, 29, 32, 29, 31, 31, 32, 
+       33, 29, 29, 29, 29, 32, 29, 32, 
+       29, 30, 31, 31, 32, 33, 29, 29, 
+       29, 29, 32, 29, 37, 31, 31, 32, 
+       33, 29, 29, 29, 29, 32, 29, 21, 
+       21, 22, 38, 0, 0, 0, 0, 22, 
+       0, 40, 39, 42, 43, 44, 45, 46, 
+       47, 22, 23, 48, 49, 49, 24, 22, 
+       50, 51, 52, 53, 54, 41, 56, 57, 
+       58, 59, 4, 5, 60, 55, 55, 8, 
+       4, 55, 55, 61, 55, 62, 57, 63, 
+       63, 4, 5, 60, 55, 55, 55, 4, 
+       55, 55, 61, 55, 57, 63, 63, 4, 
+       5, 60, 55, 55, 55, 4, 55, 55, 
+       61, 55, 42, 55, 55, 55, 64, 65, 
+       55, 1, 60, 55, 55, 55, 55, 55, 
+       42, 55, 66, 66, 55, 1, 60, 55, 
+       60, 55, 55, 67, 60, 55, 60, 55, 
+       60, 55, 55, 55, 60, 55, 42, 55, 
+       68, 55, 66, 66, 55, 1, 60, 55, 
+       55, 55, 55, 55, 42, 55, 42, 55, 
+       55, 55, 66, 66, 55, 1, 60, 55, 
+       55, 55, 55, 55, 42, 55, 42, 55, 
+       55, 55, 66, 65, 55, 1, 60, 55, 
+       55, 55, 55, 55, 42, 55, 69, 70, 
+       71, 71, 4, 5, 60, 55, 55, 55, 
+       4, 55, 70, 71, 71, 4, 5, 60, 
+       55, 55, 55, 4, 55, 71, 71, 4, 
+       5, 60, 55, 55, 55, 4, 55, 60, 
+       55, 55, 67, 60, 55, 55, 55, 4, 
+       55, 72, 73, 73, 4, 5, 60, 55, 
+       55, 55, 4, 55, 64, 74, 55, 1, 
+       60, 55, 64, 55, 66, 66, 55, 1, 
+       60, 55, 66, 74, 55, 1, 60, 55, 
+       56, 57, 63, 63, 4, 5, 60, 55, 
+       55, 55, 4, 55, 55, 61, 55, 56, 
+       57, 58, 63, 4, 5, 60, 55, 55, 
+       8, 4, 55, 55, 61, 55, 76, 77, 
+       78, 79, 12, 13, 80, 75, 75, 18, 
+       12, 75, 75, 81, 75, 82, 77, 83, 
+       79, 12, 13, 80, 75, 75, 75, 12, 
+       75, 75, 81, 75, 77, 83, 79, 12, 
+       13, 80, 75, 75, 75, 12, 75, 75, 
+       81, 75, 84, 75, 75, 75, 85, 86, 
+       75, 14, 80, 75, 75, 75, 75, 75, 
+       84, 75, 87, 77, 88, 89, 12, 13, 
+       80, 75, 75, 17, 12, 75, 75, 81, 
+       75, 90, 77, 83, 83, 12, 13, 80, 
+       75, 75, 75, 12, 75, 75, 81, 75, 
+       77, 83, 83, 12, 13, 80, 75, 75, 
+       75, 12, 75, 75, 81, 75, 84, 75, 
+       75, 75, 91, 86, 75, 14, 80, 75, 
+       75, 75, 75, 75, 84, 75, 80, 75, 
+       75, 92, 80, 75, 80, 75, 80, 75, 
+       75, 75, 80, 75, 84, 75, 93, 75, 
+       91, 91, 75, 14, 80, 75, 75, 75, 
+       75, 75, 84, 75, 84, 75, 75, 75, 
+       91, 91, 75, 14, 80, 75, 75, 75, 
+       75, 75, 84, 75, 94, 95, 96, 96, 
+       12, 13, 80, 75, 75, 75, 12, 75, 
+       95, 96, 96, 12, 13, 80, 75, 75, 
+       75, 12, 75, 96, 96, 12, 13, 80, 
+       75, 75, 75, 12, 75, 80, 75, 75, 
+       92, 80, 75, 75, 75, 12, 75, 97, 
+       98, 98, 12, 13, 80, 75, 75, 75, 
+       12, 75, 85, 99, 75, 14, 80, 75, 
+       91, 91, 75, 14, 80, 75, 85, 75, 
+       91, 91, 75, 14, 80, 75, 91, 99, 
+       75, 14, 80, 75, 87, 77, 83, 83, 
+       12, 13, 80, 75, 75, 75, 12, 75, 
+       75, 81, 75, 87, 77, 88, 83, 12, 
+       13, 80, 75, 75, 17, 12, 75, 75, 
+       81, 75, 10, 11, 11, 12, 13, 75, 
+       75, 75, 75, 12, 75, 76, 77, 83, 
+       79, 12, 13, 80, 75, 75, 75, 12, 
+       75, 75, 81, 75, 101, 45, 102, 102, 
+       22, 23, 48, 100, 100, 100, 22, 100, 
+       100, 52, 100, 45, 102, 102, 22, 23, 
+       48, 100, 100, 100, 22, 100, 100, 52, 
+       100, 103, 100, 100, 100, 104, 105, 100, 
+       25, 48, 100, 100, 100, 100, 100, 103, 
+       100, 44, 45, 106, 107, 22, 23, 48, 
+       100, 100, 24, 22, 100, 100, 52, 100, 
+       103, 100, 100, 100, 108, 105, 100, 25, 
+       48, 100, 100, 100, 100, 100, 103, 100, 
+       48, 100, 100, 109, 48, 100, 48, 100, 
+       48, 100, 100, 100, 48, 100, 103, 100, 
+       110, 100, 108, 108, 100, 25, 48, 100, 
+       100, 100, 100, 100, 103, 100, 103, 100, 
+       100, 100, 108, 108, 100, 25, 48, 100, 
+       100, 100, 100, 100, 103, 100, 111, 112, 
+       113, 113, 22, 23, 48, 100, 100, 100, 
+       22, 100, 112, 113, 113, 22, 23, 48, 
+       100, 100, 100, 22, 100, 113, 113, 22, 
+       23, 48, 100, 100, 100, 22, 100, 48, 
+       100, 100, 109, 48, 100, 100, 100, 22, 
+       100, 44, 45, 102, 102, 22, 23, 48, 
+       100, 100, 100, 22, 100, 100, 52, 100, 
+       114, 115, 115, 22, 23, 48, 100, 100, 
+       100, 22, 100, 104, 116, 100, 25, 48, 
+       100, 108, 108, 100, 25, 48, 100, 104, 
+       100, 108, 108, 100, 25, 48, 100, 108, 
+       116, 100, 25, 48, 100, 44, 45, 106, 
+       102, 22, 23, 48, 100, 100, 24, 22, 
+       100, 100, 52, 100, 20, 21, 21, 22, 
+       23, 117, 117, 117, 24, 22, 117, 20, 
+       21, 21, 22, 23, 117, 117, 117, 117, 
+       22, 117, 119, 120, 121, 122, 32, 33, 
+       123, 118, 118, 34, 32, 118, 118, 124, 
+       118, 125, 120, 122, 122, 32, 33, 123, 
+       118, 118, 118, 32, 118, 118, 124, 118, 
+       120, 122, 122, 32, 33, 123, 118, 118, 
+       118, 32, 118, 118, 124, 118, 126, 118, 
+       118, 118, 127, 128, 118, 35, 123, 118, 
+       118, 118, 118, 118, 126, 118, 119, 120, 
+       121, 49, 32, 33, 123, 118, 118, 34, 
+       32, 118, 118, 124, 118, 126, 118, 118, 
+       118, 129, 128, 118, 35, 123, 118, 118, 
+       118, 118, 118, 126, 118, 123, 118, 118, 
+       130, 123, 118, 123, 118, 123, 118, 118, 
+       118, 123, 118, 126, 118, 131, 118, 129, 
+       129, 118, 35, 123, 118, 118, 118, 118, 
+       118, 126, 118, 126, 118, 118, 118, 129, 
+       129, 118, 35, 123, 118, 118, 118, 118, 
+       118, 126, 118, 132, 133, 134, 134, 32, 
+       33, 123, 118, 118, 118, 32, 118, 133, 
+       134, 134, 32, 33, 123, 118, 118, 118, 
+       32, 118, 134, 134, 32, 33, 123, 118, 
+       118, 118, 32, 118, 123, 118, 118, 130, 
+       123, 118, 118, 118, 32, 118, 119, 120, 
+       122, 122, 32, 33, 123, 118, 118, 118, 
+       32, 118, 118, 124, 118, 135, 136, 136, 
+       32, 33, 123, 118, 118, 118, 32, 118, 
+       127, 137, 118, 35, 123, 118, 129, 129, 
+       118, 35, 123, 118, 127, 118, 129, 129, 
+       118, 35, 123, 118, 129, 137, 118, 35, 
+       123, 118, 42, 43, 44, 45, 106, 102, 
+       22, 23, 48, 49, 49, 24, 22, 100, 
+       42, 52, 100, 56, 138, 58, 59, 4, 
+       5, 60, 55, 55, 8, 4, 55, 55, 
+       61, 55, 42, 43, 44, 45, 139, 140, 
+       22, 141, 142, 55, 49, 24, 22, 55, 
+       42, 52, 55, 20, 143, 143, 22, 141, 
+       60, 55, 55, 24, 22, 55, 60, 55, 
+       55, 67, 60, 55, 55, 55, 22, 55, 
+       142, 55, 55, 144, 142, 55, 55, 55, 
+       22, 55, 142, 55, 142, 55, 55, 55, 
+       142, 55, 42, 55, 68, 20, 143, 143, 
+       22, 141, 60, 55, 55, 55, 22, 55, 
+       42, 55, 146, 145, 147, 147, 145, 40, 
+       148, 145, 147, 147, 145, 40, 148, 145, 
+       148, 145, 145, 149, 148, 145, 148, 145, 
+       148, 145, 145, 145, 148, 145, 42, 117, 
+       117, 117, 117, 117, 117, 117, 117, 49, 
+       117, 117, 117, 117, 42, 117, 0
+};
+
+static const unsigned char _indic_syllable_machine_trans_targs[] = {
+       31, 37, 42, 2, 43, 46, 4, 50, 
+       51, 31, 60, 9, 66, 69, 61, 11, 
+       74, 75, 78, 31, 83, 17, 89, 92, 
+       93, 84, 31, 19, 98, 31, 107, 24, 
+       113, 116, 117, 108, 26, 122, 127, 31, 
+       134, 31, 32, 53, 79, 81, 100, 101, 
+       85, 102, 123, 124, 94, 132, 137, 31, 
+       33, 35, 6, 52, 38, 47, 34, 1, 
+       36, 40, 0, 39, 41, 44, 45, 3, 
+       48, 5, 49, 31, 54, 56, 14, 77, 
+       62, 70, 55, 7, 57, 72, 64, 58, 
+       13, 76, 59, 8, 63, 65, 67, 68, 
+       10, 71, 12, 73, 31, 80, 20, 82, 
+       96, 87, 15, 99, 16, 86, 88, 90, 
+       91, 18, 95, 21, 97, 31, 31, 103, 
+       105, 22, 27, 109, 118, 104, 106, 120, 
+       111, 23, 110, 112, 114, 115, 25, 119, 
+       28, 121, 125, 126, 131, 128, 129, 29, 
+       130, 31, 133, 30, 135, 136
+};
+
+static const char _indic_syllable_machine_trans_actions[] = {
+       1, 0, 2, 0, 2, 0, 0, 2, 
+       2, 3, 2, 0, 2, 0, 0, 0, 
+       2, 2, 2, 4, 2, 0, 5, 0, 
+       5, 0, 6, 0, 2, 7, 2, 0, 
+       2, 0, 2, 0, 0, 2, 0, 8, 
+       0, 11, 2, 2, 5, 0, 12, 12, 
+       0, 2, 5, 2, 5, 2, 0, 13, 
+       2, 0, 0, 2, 0, 2, 2, 0, 
+       2, 2, 0, 0, 2, 2, 2, 0, 
+       0, 0, 2, 14, 2, 0, 0, 2, 
+       0, 2, 2, 0, 2, 2, 2, 2, 
+       0, 2, 2, 0, 0, 2, 2, 2, 
+       0, 0, 0, 2, 15, 5, 0, 5, 
+       2, 2, 0, 5, 0, 0, 2, 5, 
+       5, 0, 0, 0, 2, 16, 17, 2, 
+       0, 0, 0, 0, 2, 2, 2, 2, 
+       2, 0, 0, 2, 2, 2, 0, 0, 
+       0, 2, 0, 18, 18, 0, 0, 0, 
+       0, 19, 2, 0, 0, 0
+};
+
+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, 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, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 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 _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, 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, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 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 _indic_syllable_machine_eof_trans[] = {
+       1, 1, 1, 1, 1, 1, 1, 10, 
+       10, 10, 10, 10, 10, 10, 10, 20, 
+       20, 27, 20, 27, 20, 20, 30, 30, 
+       30, 30, 30, 30, 30, 1, 40, 0, 
+       56, 56, 56, 56, 56, 56, 56, 56, 
+       56, 56, 56, 56, 56, 56, 56, 56, 
+       56, 56, 56, 56, 56, 76, 76, 76, 
+       76, 76, 76, 76, 76, 76, 76, 76, 
+       76, 76, 76, 76, 76, 76, 76, 76, 
+       76, 76, 76, 76, 76, 76, 76, 101, 
+       101, 101, 101, 101, 101, 101, 101, 101, 
+       101, 101, 101, 101, 101, 101, 101, 101, 
+       101, 101, 101, 101, 118, 118, 119, 119, 
+       119, 119, 119, 119, 119, 119, 119, 119, 
+       119, 119, 119, 119, 119, 119, 119, 119, 
+       119, 119, 119, 101, 56, 56, 56, 56, 
+       56, 56, 56, 56, 146, 146, 146, 146, 
+       146, 118
+};
+
+static const int indic_syllable_machine_start = 31;
+static const int indic_syllable_machine_first_final = 31;
+static const int indic_syllable_machine_error = -1;
+
+static const int indic_syllable_machine_en_main = 31;
+
+
+#line 58 "hb-ot-shaper-indic-machine.rl"
+
+
+
+#line 118 "hb-ot-shaper-indic-machine.rl"
+
+
+#define found_syllable(syllable_type) \
+  HB_STMT_START { \
+    if (0) fprintf (stderr, "syllable %u..%u %s\n", ts, te, #syllable_type); \
+    for (unsigned int i = ts; i < te; i++) \
+      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+    syllable_serial++; \
+    if (syllable_serial == 16) syllable_serial = 1; \
+  } HB_STMT_END
+
+inline void
+find_syllables_indic (hb_buffer_t *buffer)
+{
+  unsigned int p, pe, eof, ts, te, act;
+  int cs;
+  hb_glyph_info_t *info = buffer->info;
+  
+#line 464 "hb-ot-shaper-indic-machine.hh"
+       {
+       cs = indic_syllable_machine_start;
+       ts = 0;
+       te = 0;
+       act = 0;
+       }
+
+#line 138 "hb-ot-shaper-indic-machine.rl"
+
+
+  p = 0;
+  pe = eof = buffer->len;
+
+  unsigned int syllable_serial = 1;
+  
+#line 480 "hb-ot-shaper-indic-machine.hh"
+       {
+       int _slen;
+       int _trans;
+       const unsigned char *_keys;
+       const unsigned char *_inds;
+       if ( p == pe )
+               goto _test_eof;
+_resume:
+       switch ( _indic_syllable_machine_from_state_actions[cs] ) {
+       case 10:
+#line 1 "NONE"
+       {ts = p;}
+       break;
+#line 494 "hb-ot-shaper-indic-machine.hh"
+       }
+
+       _keys = _indic_syllable_machine_trans_keys + (cs<<1);
+       _inds = _indic_syllable_machine_indicies + _indic_syllable_machine_index_offsets[cs];
+
+       _slen = _indic_syllable_machine_key_spans[cs];
+       _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].indic_category()) &&
+               ( info[p].indic_category()) <= _keys[1] ?
+               ( info[p].indic_category()) - _keys[0] : _slen ];
+
+_eof_trans:
+       cs = _indic_syllable_machine_trans_targs[_trans];
+
+       if ( _indic_syllable_machine_trans_actions[_trans] == 0 )
+               goto _again;
+
+       switch ( _indic_syllable_machine_trans_actions[_trans] ) {
+       case 2:
+#line 1 "NONE"
+       {te = p+1;}
+       break;
+       case 11:
+#line 114 "hb-ot-shaper-indic-machine.rl"
+       {te = p+1;{ found_syllable (indic_non_indic_cluster); }}
+       break;
+       case 13:
+#line 109 "hb-ot-shaper-indic-machine.rl"
+       {te = p;p--;{ found_syllable (indic_consonant_syllable); }}
+       break;
+       case 14:
+#line 110 "hb-ot-shaper-indic-machine.rl"
+       {te = p;p--;{ found_syllable (indic_vowel_syllable); }}
+       break;
+       case 17:
+#line 111 "hb-ot-shaper-indic-machine.rl"
+       {te = p;p--;{ found_syllable (indic_standalone_cluster); }}
+       break;
+       case 19:
+#line 112 "hb-ot-shaper-indic-machine.rl"
+       {te = p;p--;{ found_syllable (indic_symbol_cluster); }}
+       break;
+       case 15:
+#line 113 "hb-ot-shaper-indic-machine.rl"
+       {te = p;p--;{ found_syllable (indic_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
+       break;
+       case 16:
+#line 114 "hb-ot-shaper-indic-machine.rl"
+       {te = p;p--;{ found_syllable (indic_non_indic_cluster); }}
+       break;
+       case 1:
+#line 109 "hb-ot-shaper-indic-machine.rl"
+       {{p = ((te))-1;}{ found_syllable (indic_consonant_syllable); }}
+       break;
+       case 3:
+#line 110 "hb-ot-shaper-indic-machine.rl"
+       {{p = ((te))-1;}{ found_syllable (indic_vowel_syllable); }}
+       break;
+       case 7:
+#line 111 "hb-ot-shaper-indic-machine.rl"
+       {{p = ((te))-1;}{ found_syllable (indic_standalone_cluster); }}
+       break;
+       case 8:
+#line 112 "hb-ot-shaper-indic-machine.rl"
+       {{p = ((te))-1;}{ found_syllable (indic_symbol_cluster); }}
+       break;
+       case 4:
+#line 113 "hb-ot-shaper-indic-machine.rl"
+       {{p = ((te))-1;}{ found_syllable (indic_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
+       break;
+       case 6:
+#line 1 "NONE"
+       {       switch( act ) {
+       case 1:
+       {{p = ((te))-1;} found_syllable (indic_consonant_syllable); }
+       break;
+       case 5:
+       {{p = ((te))-1;} found_syllable (indic_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }
+       break;
+       case 6:
+       {{p = ((te))-1;} found_syllable (indic_non_indic_cluster); }
+       break;
+       }
+       }
+       break;
+       case 18:
+#line 1 "NONE"
+       {te = p+1;}
+#line 109 "hb-ot-shaper-indic-machine.rl"
+       {act = 1;}
+       break;
+       case 5:
+#line 1 "NONE"
+       {te = p+1;}
+#line 113 "hb-ot-shaper-indic-machine.rl"
+       {act = 5;}
+       break;
+       case 12:
+#line 1 "NONE"
+       {te = p+1;}
+#line 114 "hb-ot-shaper-indic-machine.rl"
+       {act = 6;}
+       break;
+#line 597 "hb-ot-shaper-indic-machine.hh"
+       }
+
+_again:
+       switch ( _indic_syllable_machine_to_state_actions[cs] ) {
+       case 9:
+#line 1 "NONE"
+       {ts = 0;}
+       break;
+#line 606 "hb-ot-shaper-indic-machine.hh"
+       }
+
+       if ( ++p != pe )
+               goto _resume;
+       _test_eof: {}
+       if ( p == eof )
+       {
+       if ( _indic_syllable_machine_eof_trans[cs] > 0 ) {
+               _trans = _indic_syllable_machine_eof_trans[cs] - 1;
+               goto _eof_trans;
+       }
+       }
+
+       }
+
+#line 146 "hb-ot-shaper-indic-machine.rl"
+
+}
+
+#undef found_syllable
+
+#endif /* HB_OT_SHAPER_INDIC_MACHINE_HH */
similarity index 75%
rename from src/hb-ot-shape-complex-indic-machine.rl
rename to src/hb-ot-shaper-indic-machine.rl
index df9583f..f568a84 100644 (file)
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
+#ifndef HB_OT_SHAPER_INDIC_MACHINE_HH
+#define HB_OT_SHAPER_INDIC_MACHINE_HH
 
 #include "hb.hh"
 
+#include "hb-ot-layout.hh"
+#include "hb-ot-shaper-indic.hh"
+
+/* buffer var allocations */
+#define indic_category() ot_shaper_var_u8_category() /* indic_category_t */
+#define indic_position() ot_shaper_var_u8_auxiliary() /* indic_position_t */
+
+using indic_category_t = unsigned;
+using indic_position_t = ot_position_t;
+
+#define I_Cat(Cat) indic_syllable_machine_ex_##Cat
+
 enum indic_syllable_type_t {
   indic_consonant_syllable,
   indic_vowel_syllable,
@@ -47,6 +59,8 @@ enum indic_syllable_type_t {
 
 %%{
 
+
+export X    = 0;
 export C    = 1;
 export V    = 2;
 export N    = 3;
@@ -55,15 +69,18 @@ export ZWNJ = 5;
 export ZWJ  = 6;
 export M    = 7;
 export SM   = 8;
-export A    = 10;
-export PLACEHOLDER = 11;
-export DOTTEDCIRCLE = 12;
-export RS    = 13;
-export Repha = 15;
-export Ra    = 16;
-export CM    = 17;
-export Symbol= 18;
-export CS    = 19;
+export A    = 9;
+export VD   = 9;
+export PLACEHOLDER = 10;
+export DOTTEDCIRCLE = 11;
+export RS    = 12;
+export MPst  = 13;
+export Repha = 14;
+export Ra    = 15;
+export CM    = 16;
+export Symbol= 17;
+export CS    = 18;
+
 
 c = (C | Ra);                  # is_consonant
 n = ((ZWNJ?.RS)? (N.N?)?);     # is_consonant_modifier
@@ -71,10 +88,9 @@ z = ZWJ|ZWNJ;                        # is_joiner
 reph = (Ra H | Repha);         # possible reph
 
 cn = c.ZWJ?.n?;
-forced_rakar = ZWJ H ZWJ Ra;
 symbol = Symbol.N?;
-matra_group = z*.M.N?.(H | forced_rakar)?;
-syllable_tail = (z?.SM.SM?.ZWNJ?)? A*;
+matra_group = z*.(M | SM? MPst).N?.H?;
+syllable_tail = (z?.SM.SM?.ZWNJ?)? (A | VD)*;
 halant_group = (z?.H.(ZWJ.N?)?);
 final_halant_group = halant_group | H.ZWNJ;
 medial_group = CM?;
@@ -94,7 +110,7 @@ main := |*
        vowel_syllable          => { found_syllable (indic_vowel_syllable); };
        standalone_cluster      => { found_syllable (indic_standalone_cluster); };
        symbol_cluster          => { found_syllable (indic_symbol_cluster); };
-       broken_cluster          => { found_syllable (indic_broken_cluster); };
+       broken_cluster          => { found_syllable (indic_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; };
        other                   => { found_syllable (indic_non_indic_cluster); };
 *|;
 
@@ -103,14 +119,14 @@ main := |*
 
 #define found_syllable(syllable_type) \
   HB_STMT_START { \
-    if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
+    if (0) fprintf (stderr, "syllable %u..%u %s\n", ts, te, #syllable_type); \
     for (unsigned int i = ts; i < te; i++) \
       info[i].syllable() = (syllable_serial << 4) | syllable_type; \
     syllable_serial++; \
-    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+    if (syllable_serial == 16) syllable_serial = 1; \
   } HB_STMT_END
 
-static void
+inline void
 find_syllables_indic (hb_buffer_t *buffer)
 {
   unsigned int p, pe, eof, ts, te, act;
@@ -132,4 +148,4 @@ find_syllables_indic (hb_buffer_t *buffer)
 
 #undef found_syllable
 
-#endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */
+#endif /* HB_OT_SHAPER_INDIC_MACHINE_HH */
diff --git a/src/hb-ot-shaper-indic-table.cc b/src/hb-ot-shaper-indic-table.cc
new file mode 100644 (file)
index 0000000..d9899a6
--- /dev/null
@@ -0,0 +1,561 @@
+/* == Start of generated table == */
+/*
+ * The following table is generated by running:
+ *
+ *   ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt
+ *
+ * on files with these headers:
+ *
+ * # IndicSyllabicCategory-15.1.0.txt
+ * # Date: 2023-01-05
+ * # IndicPositionalCategory-15.1.0.txt
+ * # Date: 2023-01-05
+ * # Blocks-15.1.0.txt
+ * # Date: 2023-07-28, 15:47:20 GMT
+ */
+
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
+#include "hb-ot-shaper-indic.hh"
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-macros"
+
+#include "hb-ot-shaper-indic-machine.hh"
+#include "hb-ot-shaper-khmer-machine.hh"
+#include "hb-ot-shaper-myanmar-machine.hh"
+
+/* indic */
+#define OT_X I_Cat(X)
+#define OT_C I_Cat(C)
+#define OT_V I_Cat(V)
+#define OT_N I_Cat(N)
+#define OT_H I_Cat(H)
+#define OT_ZWNJ I_Cat(ZWNJ)
+#define OT_ZWJ I_Cat(ZWJ)
+#define OT_M I_Cat(M)
+#define OT_SM I_Cat(SM)
+#define OT_A I_Cat(A)
+#define OT_VD I_Cat(VD)
+#define OT_PLACEHOLDER I_Cat(PLACEHOLDER)
+#define OT_DOTTEDCIRCLE I_Cat(DOTTEDCIRCLE)
+#define OT_RS I_Cat(RS)
+#define OT_MPst I_Cat(MPst)
+#define OT_Repha I_Cat(Repha)
+#define OT_Ra I_Cat(Ra)
+#define OT_CM I_Cat(CM)
+#define OT_Symbol I_Cat(Symbol)
+#define OT_CS I_Cat(CS)
+/* khmer */
+#define OT_VAbv K_Cat(VAbv)
+#define OT_VBlw K_Cat(VBlw)
+#define OT_VPre K_Cat(VPre)
+#define OT_VPst K_Cat(VPst)
+#define OT_Robatic K_Cat(Robatic)
+#define OT_Xgroup K_Cat(Xgroup)
+#define OT_Ygroup K_Cat(Ygroup)
+/* myanmar */
+static_assert (OT_VAbv == M_Cat(VAbv), "");
+static_assert (OT_VBlw == M_Cat(VBlw), "");
+static_assert (OT_VPre == M_Cat(VPre), "");
+static_assert (OT_VPst == M_Cat(VPst), "");
+#define OT_IV M_Cat(IV)
+#define OT_As M_Cat(As)
+#define OT_DB M_Cat(DB)
+#define OT_GB M_Cat(GB)
+#define OT_MH M_Cat(MH)
+#define OT_MR M_Cat(MR)
+#define OT_MW M_Cat(MW)
+#define OT_MY M_Cat(MY)
+#define OT_PT M_Cat(PT)
+#define OT_VS M_Cat(VS)
+#define OT_ML M_Cat(ML)
+
+
+#define _OT_A    OT_A            /*  53 chars; A */
+#define _OT_As   OT_As           /*   1 chars; As */
+#define _OT_C    OT_C            /* 478 chars; C */
+#define _OT_CM   OT_CM           /*   1 chars; CM */
+#define _OT_CS   OT_CS           /*   2 chars; CS */
+#define _OT_DC   OT_DOTTEDCIRCLE /*   1 chars; DOTTEDCIRCLE */
+#define _OT_H    OT_H            /*  11 chars; H */
+#define _OT_M    OT_M            /* 142 chars; M */
+#define _OT_MH   OT_MH           /*   1 chars; MH */
+#define _OT_ML   OT_ML           /*   1 chars; ML */
+#define _OT_MP   OT_MPst         /*   1 chars; MPst */
+#define _OT_MR   OT_MR           /*   1 chars; MR */
+#define _OT_MW   OT_MW           /*   2 chars; MW */
+#define _OT_MY   OT_MY           /*   3 chars; MY */
+#define _OT_N    OT_N            /*  17 chars; N */
+#define _OT_GB   OT_PLACEHOLDER  /* 165 chars; PLACEHOLDER */
+#define _OT_PT   OT_PT           /*   8 chars; PT */
+#define _OT_R    OT_Ra           /*  14 chars; Ra */
+#define _OT_Rf   OT_Repha        /*   1 chars; Repha */
+#define _OT_Rt   OT_Robatic      /*   3 chars; Robatic */
+#define _OT_SM   OT_SM           /*  56 chars; SM */
+#define _OT_S    OT_Symbol       /*  22 chars; Symbol */
+#define _OT_V    OT_V            /* 172 chars; V */
+#define _OT_VA   OT_VAbv         /*  18 chars; VAbv */
+#define _OT_VB   OT_VBlw         /*   7 chars; VBlw */
+#define _OT_VL   OT_VPre         /*   5 chars; VPre */
+#define _OT_VR   OT_VPst         /*  13 chars; VPst */
+#define _OT_VS   OT_VS           /*  16 chars; VS */
+#define _OT_X    OT_X            /*   2 chars; X */
+#define _OT_Xg   OT_Xgroup       /*   7 chars; Xgroup */
+#define _OT_Yg   OT_Ygroup       /*   4 chars; Ygroup */
+#define _OT_ZWJ  OT_ZWJ          /*   1 chars; ZWJ */
+#define _OT_ZWNJ OT_ZWNJ         /*   1 chars; ZWNJ */
+
+#define _POS_T   POS_ABOVE_C     /*  22 chars; ABOVE_C */
+#define _POS_A   POS_AFTER_MAIN  /*   3 chars; AFTER_MAIN */
+#define _POS_AP  POS_AFTER_POST  /*  50 chars; AFTER_POST */
+#define _POS_AS  POS_AFTER_SUB   /*  51 chars; AFTER_SUB */
+#define _POS_C   POS_BASE_C      /* 833 chars; BASE_C */
+#define _POS_BS  POS_BEFORE_SUB  /*  25 chars; BEFORE_SUB */
+#define _POS_B   POS_BELOW_C     /*  13 chars; BELOW_C */
+#define _POS_X   POS_END         /*  71 chars; END */
+#define _POS_R   POS_POST_C      /*  13 chars; POST_C */
+#define _POS_L   POS_PRE_C       /*   5 chars; PRE_C */
+#define _POS_LM  POS_PRE_M       /*  14 chars; PRE_M */
+#define _POS_SM  POS_SMVD        /* 130 chars; SMVD */
+
+#pragma GCC diagnostic pop
+
+#define INDIC_COMBINE_CATEGORIES(S,M) ((S) | ((M) << 8))
+
+#define _(S,M) INDIC_COMBINE_CATEGORIES (_OT_##S, _POS_##M)
+
+
+static const uint16_t indic_table[] = {
+
+
+#define indic_offset_0x0028u 0
+
+
+  /* Basic Latin */
+
+  /* 0028 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X), _(GB,C),  _(X,X),  _(X,X),
+  /* 0030 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+  /* 0038 */ _(GB,C), _(GB,C),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+
+#define indic_offset_0x00b0u 24
+
+
+  /* Latin-1 Supplement */
+
+  /* 00B0 */  _(X,X),  _(X,X),_(SM,SM),_(SM,SM),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+  /* 00B8 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+  /* 00C0 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+  /* 00C8 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+  /* 00D0 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X), _(GB,C),
+
+#define indic_offset_0x0900u 64
+
+
+  /* Devanagari */
+
+  /* 0900 */_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM),  _(V,C),  _(V,C),  _(V,C),  _(V,C),
+  /* 0908 */  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),
+  /* 0910 */  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0918 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0920 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0928 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0930 */  _(R,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0938 */  _(C,C),  _(C,C), _(M,AS), _(M,AS),  _(N,X), _(S,SM), _(M,AS), _(M,LM),
+  /* 0940 */ _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS),
+  /* 0948 */ _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS),  _(H,B), _(M,LM), _(M,AS),
+  /* 0950 */  _(X,X), _(A,SM), _(A,SM),_(SM,SM),_(SM,SM), _(M,AS), _(M,AS), _(M,AS),
+  /* 0958 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0960 */  _(V,C),  _(V,C), _(M,AS), _(M,AS),  _(X,X),  _(X,X), _(GB,C), _(GB,C),
+  /* 0968 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+  /* 0970 */  _(X,X),  _(X,X),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),
+  /* 0978 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+
+  /* Bengali */
+
+  /* 0980 */ _(GB,C),_(SM,SM),_(SM,SM),_(SM,SM),  _(X,X),  _(V,C),  _(V,C),  _(V,C),
+  /* 0988 */  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(X,X),  _(X,X),  _(V,C),
+  /* 0990 */  _(V,C),  _(X,X),  _(X,X),  _(V,C),  _(V,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0998 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 09A0 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 09A8 */  _(C,C),  _(X,X),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 09B0 */  _(R,C),  _(X,X),  _(C,C),  _(X,X),  _(X,X),  _(X,X),  _(C,C),  _(C,C),
+  /* 09B8 */  _(C,C),  _(C,C),  _(X,X),  _(X,X),  _(N,X), _(S,SM), _(M,AP), _(M,LM),
+  /* 09C0 */ _(M,AP), _(M,AS), _(M,AS), _(M,AS), _(M,AS),  _(X,X),  _(X,X), _(M,LM),
+  /* 09C8 */ _(M,LM),  _(X,X),  _(X,X), _(M,AP), _(M,AP),  _(H,B),  _(C,C),  _(X,X),
+  /* 09D0 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X), _(M,AP),
+  /* 09D8 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(C,C),  _(C,C),  _(X,X),  _(C,C),
+  /* 09E0 */  _(V,C),  _(V,C), _(M,AS), _(M,AS),  _(X,X),  _(X,X), _(GB,C), _(GB,C),
+  /* 09E8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+  /* 09F0 */  _(R,C),  _(C,C),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+  /* 09F8 */  _(X,X),  _(X,X),  _(X,X),  _(X,X), _(GB,C),  _(X,X),_(SM,SM),  _(X,X),
+
+  /* Gurmukhi */
+
+  /* 0A00 */  _(X,X),_(SM,SM),_(SM,SM),_(SM,SM),  _(X,X),  _(V,C),  _(V,C),  _(V,C),
+  /* 0A08 */  _(V,C),  _(V,C),  _(V,C),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(V,C),
+  /* 0A10 */  _(V,C),  _(X,X),  _(X,X),  _(V,C),  _(V,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0A18 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0A20 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0A28 */  _(C,C),  _(X,X),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0A30 */  _(R,C),  _(X,X),  _(C,C),  _(C,C),  _(X,X),  _(C,C),  _(C,C),  _(X,X),
+  /* 0A38 */  _(C,C),  _(C,C),  _(X,X),  _(X,X),  _(N,X),  _(X,X), _(M,AP), _(M,LM),
+  /* 0A40 */_(MP,AP), _(M,AP), _(M,AP),  _(X,X),  _(X,X),  _(X,X),  _(X,X), _(M,AP),
+  /* 0A48 */ _(M,AP),  _(X,X),  _(X,X), _(M,AP), _(M,AP),  _(H,B),  _(X,X),  _(X,X),
+  /* 0A50 */  _(X,X),  _(M,B),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+  /* 0A58 */  _(X,X),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(X,X),  _(C,C),  _(X,X),
+  /* 0A60 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X), _(GB,C), _(GB,C),
+  /* 0A68 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+  /* 0A70 */_(SM,SM),_(SM,SM),  _(C,C),  _(C,C),  _(X,X), _(CM,C),  _(X,X),  _(X,X),
+  /* 0A78 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+
+  /* Gujarati */
+
+  /* 0A80 */  _(X,X),_(SM,SM),_(SM,SM),_(SM,SM),  _(X,X),  _(V,C),  _(V,C),  _(V,C),
+  /* 0A88 */  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(X,X),  _(V,C),
+  /* 0A90 */  _(V,C),  _(V,C),  _(X,X),  _(V,C),  _(V,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0A98 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0AA0 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0AA8 */  _(C,C),  _(X,X),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0AB0 */  _(R,C),  _(X,X),  _(C,C),  _(C,C),  _(X,X),  _(C,C),  _(C,C),  _(C,C),
+  /* 0AB8 */  _(C,C),  _(C,C),  _(X,X),  _(X,X),  _(N,X), _(S,SM), _(M,AP), _(M,LM),
+  /* 0AC0 */ _(M,AP), _(M,AP), _(M,AP), _(M,AP), _(M,AP), _(M,AS),  _(X,X), _(M,AS),
+  /* 0AC8 */ _(M,AS), _(M,AP),  _(X,X), _(M,AP), _(M,AP),  _(H,B),  _(X,X),  _(X,X),
+  /* 0AD0 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+  /* 0AD8 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+  /* 0AE0 */  _(V,C),  _(V,C), _(M,AP), _(M,AP),  _(X,X),  _(X,X), _(GB,C), _(GB,C),
+  /* 0AE8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+  /* 0AF0 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+  /* 0AF8 */  _(X,X),  _(C,C), _(A,SM),  _(N,X), _(A,SM),  _(N,X),  _(N,X),  _(N,X),
+
+  /* Oriya */
+
+  /* 0B00 */  _(X,X),_(SM,BS),_(SM,SM),_(SM,SM),  _(X,X),  _(V,C),  _(V,C),  _(V,C),
+  /* 0B08 */  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(X,X),  _(X,X),  _(V,C),
+  /* 0B10 */  _(V,C),  _(X,X),  _(X,X),  _(V,C),  _(V,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0B18 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0B20 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0B28 */  _(C,C),  _(X,X),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0B30 */  _(R,C),  _(X,X),  _(C,C),  _(C,C),  _(X,X),  _(C,C),  _(C,C),  _(C,C),
+  /* 0B38 */  _(C,C),  _(C,C),  _(X,X),  _(X,X),  _(N,X), _(S,SM), _(M,AP),  _(M,A),
+  /* 0B40 */ _(M,AP), _(M,AS), _(M,AS), _(M,AS), _(M,AS),  _(X,X),  _(X,X), _(M,LM),
+  /* 0B48 */  _(M,A),  _(X,X),  _(X,X), _(M,AP), _(M,AP),  _(H,B),  _(X,X),  _(X,X),
+  /* 0B50 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(N,X),  _(M,A), _(M,AP),
+  /* 0B58 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(C,C),  _(C,C),  _(X,X),  _(C,C),
+  /* 0B60 */  _(V,C),  _(V,C), _(M,AS), _(M,AS),  _(X,X),  _(X,X), _(GB,C), _(GB,C),
+  /* 0B68 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+  /* 0B70 */  _(X,X),  _(C,C),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+  /* 0B78 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+
+  /* Tamil */
+
+  /* 0B80 */  _(X,X),  _(X,X),_(SM,SM),  _(X,X),  _(X,X),  _(V,C),  _(V,C),  _(V,C),
+  /* 0B88 */  _(V,C),  _(V,C),  _(V,C),  _(X,X),  _(X,X),  _(X,X),  _(V,C),  _(V,C),
+  /* 0B90 */  _(V,C),  _(X,X),  _(V,C),  _(V,C),  _(V,C),  _(C,C),  _(X,X),  _(X,X),
+  /* 0B98 */  _(X,X),  _(C,C),  _(C,C),  _(X,X),  _(C,C),  _(X,X),  _(C,C),  _(C,C),
+  /* 0BA0 */  _(X,X),  _(X,X),  _(X,X),  _(C,C),  _(C,C),  _(X,X),  _(X,X),  _(X,X),
+  /* 0BA8 */  _(C,C),  _(C,C),  _(C,C),  _(X,X),  _(X,X),  _(X,X),  _(C,C),  _(C,C),
+  /* 0BB0 */  _(R,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0BB8 */  _(C,C),  _(C,C),  _(X,X),  _(X,X),  _(X,X),  _(X,X), _(M,AP), _(M,AP),
+  /* 0BC0 */ _(M,AS), _(M,AP), _(M,AP),  _(X,X),  _(X,X),  _(X,X), _(M,LM), _(M,LM),
+  /* 0BC8 */ _(M,LM),  _(X,X), _(M,AP), _(M,AP), _(M,AP),  _(H,T),  _(X,X),  _(X,X),
+  /* 0BD0 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X), _(M,AP),
+  /* 0BD8 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+  /* 0BE0 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X), _(GB,C), _(GB,C),
+  /* 0BE8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+  /* 0BF0 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+  /* 0BF8 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+
+  /* Telugu */
+
+  /* 0C00 */_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM),  _(V,C),  _(V,C),  _(V,C),
+  /* 0C08 */  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(X,X),  _(V,C),  _(V,C),
+  /* 0C10 */  _(V,C),  _(X,X),  _(V,C),  _(V,C),  _(V,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0C18 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0C20 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0C28 */  _(C,C),  _(X,X),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0C30 */  _(R,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0C38 */  _(C,C),  _(C,C),  _(X,X),  _(X,X),  _(N,X), _(S,SM), _(M,BS), _(M,BS),
+  /* 0C40 */ _(M,BS), _(M,BS), _(M,BS), _(M,AS), _(M,AS),  _(X,X), _(M,BS), _(M,BS),
+  /* 0C48 */ _(M,BS),  _(X,X), _(M,BS), _(M,BS), _(M,BS),  _(H,T),  _(X,X),  _(X,X),
+  /* 0C50 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X), _(M,BS), _(M,BS),  _(X,X),
+  /* 0C58 */  _(C,C),  _(C,C),  _(C,C),  _(X,X),  _(X,X),  _(C,C),  _(X,X),  _(X,X),
+  /* 0C60 */  _(V,C),  _(V,C), _(M,BS), _(M,BS),  _(X,X),  _(X,X), _(GB,C), _(GB,C),
+  /* 0C68 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+  /* 0C70 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+  /* 0C78 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+
+  /* Kannada */
+
+  /* 0C80 */ _(GB,C),_(SM,SM),_(SM,SM),_(SM,SM),  _(X,X),  _(V,C),  _(V,C),  _(V,C),
+  /* 0C88 */  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(X,X),  _(V,C),  _(V,C),
+  /* 0C90 */  _(V,C),  _(X,X),  _(V,C),  _(V,C),  _(V,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0C98 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0CA0 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0CA8 */  _(C,C),  _(X,X),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0CB0 */  _(R,C),  _(C,C),  _(C,C),  _(C,C),  _(X,X),  _(C,C),  _(C,C),  _(C,C),
+  /* 0CB8 */  _(C,C),  _(C,C),  _(X,X),  _(X,X),  _(N,X), _(S,SM), _(M,BS), _(M,BS),
+  /* 0CC0 */ _(M,BS), _(M,BS), _(M,BS), _(M,AS), _(M,AS),  _(X,X), _(M,BS), _(M,AS),
+  /* 0CC8 */ _(M,AS),  _(X,X), _(M,AS), _(M,AS), _(M,BS),  _(H,T),  _(X,X),  _(X,X),
+  /* 0CD0 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X), _(M,AS), _(M,AS),  _(X,X),
+  /* 0CD8 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(C,C),  _(C,C),  _(X,X),
+  /* 0CE0 */  _(V,C),  _(V,C), _(M,BS), _(M,BS),  _(X,X),  _(X,X), _(GB,C), _(GB,C),
+  /* 0CE8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+  /* 0CF0 */  _(X,X), _(CS,C), _(CS,C),_(SM,SM),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+  /* 0CF8 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+
+  /* Malayalam */
+
+  /* 0D00 */_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM), _(GB,C),  _(V,C),  _(V,C),  _(V,C),
+  /* 0D08 */  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(X,X),  _(V,C),  _(V,C),
+  /* 0D10 */  _(V,C),  _(X,X),  _(V,C),  _(V,C),  _(V,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0D18 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0D20 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0D28 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0D30 */  _(R,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 0D38 */  _(C,C),  _(C,C),  _(C,C), _(M,AS), _(M,AS), _(S,SM), _(M,AP), _(M,AP),
+  /* 0D40 */ _(M,AP), _(M,AP), _(M,AP), _(M,AP), _(M,AP),  _(X,X), _(M,LM), _(M,LM),
+  /* 0D48 */ _(M,LM),  _(X,X), _(M,AP), _(M,AP), _(M,AP),  _(H,T), _(Rf,X),  _(X,X),
+  /* 0D50 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(C,C),  _(C,C),  _(C,C), _(M,AP),
+  /* 0D58 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(V,C),
+  /* 0D60 */  _(V,C),  _(V,C), _(M,AP), _(M,AP),  _(X,X),  _(X,X), _(GB,C), _(GB,C),
+  /* 0D68 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+  /* 0D70 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+  /* 0D78 */  _(X,X),  _(X,X),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+
+#define indic_offset_0x1000u 1216
+
+
+  /* Myanmar */
+
+  /* 1000 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(R,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 1008 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 1010 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 1018 */  _(C,C),  _(C,C),  _(C,C),  _(R,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 1020 */  _(C,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),
+  /* 1028 */  _(V,C),  _(V,C),  _(V,C), _(VR,R), _(VR,R), _(VA,T), _(VA,T), _(VB,B),
+  /* 1030 */ _(VB,B), _(VL,L), _(A,SM), _(VA,T), _(VA,T), _(VA,T), _(A,SM),  _(N,X),
+  /* 1038 */_(SM,SM),  _(H,X), _(As,X), _(MY,X), _(MR,X), _(MW,X), _(MH,X),  _(C,C),
+  /* 1040 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+  /* 1048 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C),  _(X,X),  _(X,X),  _(C,C),  _(X,X),
+  /* 1050 */  _(C,C),  _(C,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C), _(VR,R), _(VR,R),
+  /* 1058 */ _(VB,B), _(VB,B),  _(R,C),  _(C,C),  _(C,C),  _(C,C), _(MY,X), _(MY,X),
+  /* 1060 */ _(ML,X),  _(C,C), _(VR,R), _(PT,X), _(PT,X),  _(C,C),  _(C,C), _(VR,R),
+  /* 1068 */ _(VR,R), _(PT,X), _(PT,X), _(PT,X), _(PT,X), _(PT,X),  _(C,C),  _(C,C),
+  /* 1070 */  _(C,C), _(VA,T), _(VA,T), _(VA,T), _(VA,T),  _(C,C),  _(C,C),  _(C,C),
+  /* 1078 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 1080 */  _(C,C),  _(C,C), _(MW,X), _(VR,R), _(VL,L), _(VA,T), _(VA,T),_(SM,SM),
+  /* 1088 */_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM),  _(C,C),_(SM,SM),
+  /* 1090 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+  /* 1098 */ _(GB,C), _(GB,C),_(SM,SM),_(SM,SM),_(SM,SM), _(VA,T),  _(X,X),  _(X,X),
+
+#define indic_offset_0x1780u 1376
+
+
+  /* Khmer */
+
+  /* 1780 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 1788 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 1790 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 1798 */  _(C,C),  _(C,C),  _(R,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* 17A0 */  _(C,C),  _(C,C),  _(C,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),
+  /* 17A8 */  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(V,C),
+  /* 17B0 */  _(V,C),  _(V,C),  _(V,C),  _(V,C),  _(X,X),  _(X,X), _(VR,R), _(VA,T),
+  /* 17B8 */ _(VA,T), _(VA,T), _(VA,T), _(VB,B), _(VB,B), _(VB,B), _(VA,T), _(VR,R),
+  /* 17C0 */ _(VR,R), _(VL,L), _(VL,L), _(VL,L), _(VR,R), _(VR,R), _(Xg,X), _(Yg,X),
+  /* 17C8 */ _(Yg,X), _(Rt,X), _(Rt,X), _(Xg,X), _(Rt,X), _(Xg,X), _(Xg,X), _(Xg,X),
+  /* 17D0 */ _(Xg,X), _(Xg,X),  _(H,X), _(Yg,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+  /* 17D8 */  _(X,X), _(GB,C),  _(X,X),  _(X,X), _(S,SM), _(Yg,X),  _(X,X),  _(X,X),
+  /* 17E0 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+  /* 17E8 */ _(GB,C), _(GB,C),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+
+#define indic_offset_0x1cd0u 1488
+
+
+  /* Vedic Extensions */
+
+  /* 1CD0 */ _(A,SM), _(A,SM), _(A,SM),  _(X,X), _(A,SM), _(A,SM), _(A,SM), _(A,SM),
+  /* 1CD8 */ _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM),
+  /* 1CE0 */ _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM),
+  /* 1CE8 */ _(A,SM), _(S,SM), _(S,SM), _(S,SM), _(S,SM), _(A,SM), _(S,SM), _(S,SM),
+  /* 1CF0 */ _(S,SM), _(S,SM),  _(C,C),  _(C,C), _(A,SM),  _(C,C),  _(C,C), _(A,SM),
+  /* 1CF8 */ _(A,SM), _(A,SM), _(GB,C),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+
+#define indic_offset_0x2008u 1536
+
+
+  /* General Punctuation */
+
+  /* 2008 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),_(ZWNJ,X),_(ZWJ,X),  _(X,X),  _(X,X),
+  /* 2010 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),  _(X,X),  _(X,X),
+  /* 2018 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+  /* 2020 */  _(X,X),  _(X,X), _(GB,C),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+
+#define indic_offset_0x2070u 1568
+
+
+  /* Superscripts and Subscripts */
+
+  /* 2070 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),_(SM,SM),  _(X,X),  _(X,X),  _(X,X),
+  /* 2078 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+  /* 2080 */  _(X,X),  _(X,X),_(SM,SM),_(SM,SM),_(SM,SM),  _(X,X),  _(X,X),  _(X,X),
+
+#define indic_offset_0x25f8u 1592
+
+
+  /* Geometric Shapes */
+
+  /* 25F8 */  _(X,X),  _(X,X),  _(X,X), _(GB,C), _(GB,C), _(GB,C), _(GB,C),  _(X,X),
+
+#define indic_offset_0xa8e0u 1600
+
+
+  /* Devanagari Extended */
+
+  /* A8E0 */ _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM),
+  /* A8E8 */ _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM),
+  /* A8F0 */ _(A,SM), _(A,SM), _(S,SM), _(S,SM), _(S,SM), _(S,SM), _(S,SM), _(S,SM),
+  /* A8F8 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(V,C), _(M,AS),
+
+#define indic_offset_0xa9e0u 1632
+
+
+  /* Myanmar Extended-B */
+
+  /* A9E0 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C), _(VA,T),  _(X,X),  _(C,C),
+  /* A9E8 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* A9F0 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+  /* A9F8 */ _(GB,C), _(GB,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(X,X),
+
+#define indic_offset_0xaa60u 1664
+
+
+  /* Myanmar Extended-A */
+
+  /* AA60 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* AA68 */  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
+  /* AA70 */  _(X,X),  _(C,C),  _(C,C),  _(C,C), _(GB,C), _(GB,C), _(GB,C),  _(X,X),
+  /* AA78 */  _(X,X),  _(X,X),  _(C,C), _(PT,X),  _(N,X),  _(N,X),  _(C,C),  _(C,C),
+
+#define indic_offset_0xfe00u 1696
+
+
+  /* Variation Selectors */
+
+  /* FE00 */ _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X),
+  /* FE08 */ _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X),
+
+#define indic_offset_0x11300u 1712
+
+
+  /* Grantha */
+
+  /* 11300 */  _(X,X),_(SM,SM),_(SM,SM),_(SM,SM),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+
+#define indic_offset_0x11338u 1720
+
+  /* 11338 */  _(X,X),  _(X,X),  _(X,X),  _(N,X),  _(N,X),  _(X,X),  _(X,X),  _(X,X),
+
+}; /* Table items: 1728; occupancy: 71% */
+
+uint16_t
+hb_indic_get_categories (hb_codepoint_t u)
+{
+  switch (u >> 12)
+  {
+    case 0x0u:
+      if (unlikely (u == 0x00A0u)) return _(GB,C);
+      if (hb_in_range<hb_codepoint_t> (u, 0x0028u, 0x003Fu)) return indic_table[u - 0x0028u + indic_offset_0x0028u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x00B0u, 0x00D7u)) return indic_table[u - 0x00B0u + indic_offset_0x00b0u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x0900u, 0x0D7Fu)) return indic_table[u - 0x0900u + indic_offset_0x0900u];
+      break;
+
+    case 0x1u:
+      if (hb_in_range<hb_codepoint_t> (u, 0x1000u, 0x109Fu)) return indic_table[u - 0x1000u + indic_offset_0x1000u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x1780u, 0x17EFu)) return indic_table[u - 0x1780u + indic_offset_0x1780u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x1CD0u, 0x1CFFu)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
+      break;
+
+    case 0x2u:
+      if (unlikely (u == 0x25CCu)) return _(DC,C);
+      if (hb_in_range<hb_codepoint_t> (u, 0x2008u, 0x2027u)) return indic_table[u - 0x2008u + indic_offset_0x2008u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x2070u, 0x2087u)) return indic_table[u - 0x2070u + indic_offset_0x2070u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x25F8u, 0x25FFu)) return indic_table[u - 0x25F8u + indic_offset_0x25f8u];
+      break;
+
+    case 0xAu:
+      if (hb_in_range<hb_codepoint_t> (u, 0xA8E0u, 0xA8FFu)) return indic_table[u - 0xA8E0u + indic_offset_0xa8e0u];
+      if (hb_in_range<hb_codepoint_t> (u, 0xA9E0u, 0xA9FFu)) return indic_table[u - 0xA9E0u + indic_offset_0xa9e0u];
+      if (hb_in_range<hb_codepoint_t> (u, 0xAA60u, 0xAA7Fu)) return indic_table[u - 0xAA60u + indic_offset_0xaa60u];
+      break;
+
+    case 0xFu:
+      if (hb_in_range<hb_codepoint_t> (u, 0xFE00u, 0xFE0Fu)) return indic_table[u - 0xFE00u + indic_offset_0xfe00u];
+      break;
+
+    case 0x11u:
+      if (hb_in_range<hb_codepoint_t> (u, 0x11300u, 0x11307u)) return indic_table[u - 0x11300u + indic_offset_0x11300u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x11338u, 0x1133Fu)) return indic_table[u - 0x11338u + indic_offset_0x11338u];
+      break;
+
+    default:
+      break;
+  }
+  return _(X,X);
+}
+
+#undef _
+#undef INDIC_COMBINE_CATEGORIES
+
+#undef _OT_A
+#undef _OT_As
+#undef _OT_C
+#undef _OT_CM
+#undef _OT_CS
+#undef _OT_DC
+#undef _OT_H
+#undef _OT_M
+#undef _OT_MH
+#undef _OT_ML
+#undef _OT_MP
+#undef _OT_MR
+#undef _OT_MW
+#undef _OT_MY
+#undef _OT_N
+#undef _OT_GB
+#undef _OT_PT
+#undef _OT_R
+#undef _OT_Rf
+#undef _OT_Rt
+#undef _OT_SM
+#undef _OT_S
+#undef _OT_V
+#undef _OT_VA
+#undef _OT_VB
+#undef _OT_VL
+#undef _OT_VR
+#undef _OT_VS
+#undef _OT_X
+#undef _OT_Xg
+#undef _OT_Yg
+#undef _OT_ZWJ
+#undef _OT_ZWNJ
+
+#undef _POS_T
+#undef _POS_A
+#undef _POS_AP
+#undef _POS_AS
+#undef _POS_C
+#undef _POS_BS
+#undef _POS_B
+#undef _POS_X
+#undef _POS_R
+#undef _POS_L
+#undef _POS_LM
+#undef _POS_SM
+
+#endif
+
+/* == End of generated table == */
similarity index 81%
rename from src/hb-ot-shape-complex-indic.cc
rename to src/hb-ot-shaper-indic.cc
index 4a8781c..f8c970f 100644 (file)
@@ -28,9 +28,9 @@
 
 #ifndef HB_NO_OT_SHAPE
 
-#include "hb-ot-shape-complex-indic.hh"
-#include "hb-ot-shape-complex-indic-machine.hh"
-#include "hb-ot-shape-complex-vowel-constraints.hh"
+#include "hb-ot-shaper-indic.hh"
+#include "hb-ot-shaper-indic-machine.hh"
+#include "hb-ot-shaper-vowel-constraints.hh"
 #include "hb-ot-layout.hh"
 
 
  */
 
 
+static inline void
+set_indic_properties (hb_glyph_info_t &info)
+{
+  hb_codepoint_t u = info.codepoint;
+  unsigned int type = hb_indic_get_categories (u);
+
+  info.indic_category() = (indic_category_t) (type & 0xFFu);
+  info.indic_position() = (indic_position_t) (type >> 8);
+}
+
+
+static inline bool
+is_one_of (const hb_glyph_info_t &info, unsigned int flags)
+{
+  /* If it ligated, all bets are off. */
+  if (_hb_glyph_info_ligated (&info)) return false;
+  return !!(FLAG_UNSAFE (info.indic_category()) & flags);
+}
+
+/* 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!
+ *
+ * Keep in sync with consonant_categories in the generator. */
+#define CONSONANT_FLAGS_INDIC (FLAG (I_Cat(C)) | FLAG (I_Cat(CS)) | FLAG (I_Cat(Ra)) | FLAG (I_Cat(CM)) | FLAG (I_Cat(V)) | FLAG (I_Cat(PLACEHOLDER)) | FLAG (I_Cat(DOTTEDCIRCLE)))
+
+static inline bool
+is_consonant (const hb_glyph_info_t &info)
+{
+  return is_one_of (info, CONSONANT_FLAGS_INDIC);
+}
+
+#define JOINER_FLAGS (FLAG (I_Cat(ZWJ)) | FLAG (I_Cat(ZWNJ)))
+
+static inline bool
+is_joiner (const hb_glyph_info_t &info)
+{
+  return is_one_of (info, JOINER_FLAGS);
+}
+
+static inline bool
+is_halant (const hb_glyph_info_t &info)
+{
+  return is_one_of (info, FLAG (I_Cat(H)));
+}
+
+struct hb_indic_would_substitute_feature_t
+{
+  void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_)
+  {
+    zero_context = zero_context_;
+    lookups = map->get_stage_lookups (0/*GSUB*/,
+                                     map->get_feature_stage (0/*GSUB*/, feature_tag));
+  }
+
+  bool would_substitute (const hb_codepoint_t *glyphs,
+                        unsigned int          glyphs_count,
+                        hb_face_t            *face) const
+  {
+    for (const auto &lookup : lookups)
+      if (hb_ot_layout_lookup_would_substitute (face, lookup.index, glyphs, glyphs_count, zero_context))
+       return true;
+    return false;
+  }
+
+  private:
+  hb_array_t<const hb_ot_map_t::lookup_map_t> lookups;
+  bool zero_context;
+};
+
+
 /*
  * Indic configurations.  Note that we do not want to keep every single script-specific
  * behavior in these tables necessarily.  This should mainly be used for per-script
  * instead of adding a new flag in these structs.
  */
 
-enum base_position_t {
-  BASE_POS_LAST_SINHALA,
-  BASE_POS_LAST
-};
 enum reph_position_t {
   REPH_POS_AFTER_MAIN  = POS_AFTER_MAIN,
   REPH_POS_BEFORE_SUB  = POS_BEFORE_SUB,
@@ -72,7 +141,6 @@ struct indic_config_t
   hb_script_t     script;
   bool            has_old_spec;
   hb_codepoint_t  virama;
-  base_position_t base_pos;
   reph_position_t reph_pos;
   reph_mode_t     reph_mode;
   blwf_mode_t     blwf_mode;
@@ -81,26 +149,19 @@ struct indic_config_t
 static const indic_config_t indic_configs[] =
 {
   /* Default.  Should be first. */
-  {HB_SCRIPT_INVALID,  false,      0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_DEVANAGARI,true, 0x094Du,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_BENGALI,  true, 0x09CDu,BASE_POS_LAST, REPH_POS_AFTER_SUB,  REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_GURMUKHI, true, 0x0A4Du,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_GUJARATI, true, 0x0ACDu,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_ORIYA,    true, 0x0B4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_TAMIL,    true, 0x0BCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_TELUGU,   true, 0x0C4Du,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY},
-  {HB_SCRIPT_KANNADA,  true, 0x0CCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY},
-  {HB_SCRIPT_MALAYALAM,        true, 0x0D4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_SINHALA,  false,0x0DCAu,BASE_POS_LAST_SINHALA,
-                                                    REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_INVALID,  false,      0,REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_DEVANAGARI,true, 0x094Du,REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_BENGALI,  true, 0x09CDu,REPH_POS_AFTER_SUB,  REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_GURMUKHI, true, 0x0A4Du,REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_GUJARATI, true, 0x0ACDu,REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_ORIYA,    true, 0x0B4Du,REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_TAMIL,    true, 0x0BCDu,REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_TELUGU,   true, 0x0C4Du,REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY},
+  {HB_SCRIPT_KANNADA,  true, 0x0CCDu,REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY},
+  {HB_SCRIPT_MALAYALAM,        true, 0x0D4Du,REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST},
 };
 
 
-
-/*
- * Indic shaper.
- */
-
 static const hb_ot_map_feature_t
 indic_features[] =
 {
@@ -109,17 +170,17 @@ indic_features[] =
    * These features are applied in order, one at a time, after initial_reordering,
    * constrained to the syllable.
    */
-  {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},
+  {HB_TAG('n','u','k','t'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('a','k','h','n'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('r','p','h','f'),        F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('r','k','r','f'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('p','r','e','f'),        F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('b','l','w','f'),        F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('a','b','v','f'),        F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('h','a','l','f'),        F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('p','s','t','f'),        F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('v','a','t','u'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
   /*
    * Other features.
    * These features are applied all at once, after final_reordering, constrained
@@ -127,12 +188,12 @@ indic_features[] =
    * Default Bengali font in Windows for example has intermixed
    * lookups for init,pres,abvs,blws features.
    */
-  {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},
+  {HB_TAG('i','n','i','t'),        F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('h','a','l','n'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
 };
 
 /*
@@ -162,15 +223,15 @@ enum {
   INDIC_BASIC_FEATURES = INDIC_INIT, /* Don't forget to update this! */
 };
 
-static void
+static bool
 setup_syllables_indic (const hb_ot_shape_plan_t *plan,
                       hb_font_t *font,
                       hb_buffer_t *buffer);
-static void
+static bool
 initial_reordering_indic (const hb_ot_shape_plan_t *plan,
                          hb_font_t *font,
                          hb_buffer_t *buffer);
-static void
+static bool
 final_reordering_indic (const hb_ot_shape_plan_t *plan,
                        hb_font_t *font,
                        hb_buffer_t *buffer);
@@ -183,10 +244,10 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
   /* Do this before any lookups have been applied. */
   map->add_gsub_pause (setup_syllables_indic);
 
-  map->enable_feature (HB_TAG('l','o','c','l'));
+  map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
   /* 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->enable_feature (HB_TAG('c','c','m','p'));
+  map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
 
 
   unsigned int i = 0;
@@ -201,14 +262,13 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
 
   for (; i < INDIC_NUM_FEATURES; i++)
     map->add_feature (indic_features[i]);
-
-  map->add_gsub_pause (_hb_clear_syllables);
 }
 
 static void
 override_features_indic (hb_ot_shape_planner_t *plan)
 {
   plan->map.disable_feature (HB_TAG('l','i','g','a'));
+  plan->map.add_gsub_pause (hb_syllabic_clear_var); // Don't need syllables anymore, use stop to free buffer var
 }
 
 
@@ -216,7 +276,7 @@ struct indic_shape_plan_t
 {
   bool load_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
   {
-    hb_codepoint_t glyph = virama_glyph.get_relaxed ();
+    hb_codepoint_t glyph = virama_glyph;
     if (unlikely (glyph == (hb_codepoint_t) -1))
     {
       if (!config->virama || !font->get_nominal_glyph (config->virama, &glyph))
@@ -226,7 +286,7 @@ struct indic_shape_plan_t
 
       /* Our get_nominal_glyph() function needs a font, so we can't get the virama glyph
        * during shape planning...  Instead, overwrite it here. */
-      virama_glyph.set_relaxed ((int) glyph);
+      virama_glyph = (int) glyph;
     }
 
     *pglyph = glyph;
@@ -270,7 +330,7 @@ data_create_indic (const hb_ot_shape_plan_t *plan)
 #ifndef HB_NO_UNISCRIBE_BUG_COMPATIBLE
   indic_plan->uniscribe_bug_compatible = hb_options ().uniscribe_bug_compatible;
 #endif
-  indic_plan->virama_glyph.set_relaxed (-1);
+  indic_plan->virama_glyph = -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.
@@ -353,14 +413,16 @@ setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
     set_indic_properties (info[i]);
 }
 
-static void
+static bool
 setup_syllables_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
                       hb_font_t *font HB_UNUSED,
                       hb_buffer_t *buffer)
 {
+  HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
   find_syllables_indic (buffer);
   foreach_syllable (buffer, start, end)
     buffer->unsafe_to_break (start, end);
+  return false;
 }
 
 static int
@@ -369,7 +431,7 @@ compare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
   int a = pa->indic_position();
   int b = pb->indic_position();
 
-  return a < b ? -1 : a == b ? 0 : +1;
+  return (int) a - (int) b;
 }
 
 
@@ -381,9 +443,6 @@ update_consonant_positions_indic (const hb_ot_shape_plan_t *plan,
 {
   const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
 
-  if (indic_plan->config->base_pos != BASE_POS_LAST)
-    return;
-
   hb_codepoint_t virama;
   if (indic_plan->load_virama_glyph (font, &virama))
   {
@@ -418,14 +477,12 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
    */
   if (buffer->props.script == HB_SCRIPT_KANNADA &&
       start + 3 <= end &&
-      is_one_of (info[start  ], FLAG (OT_Ra)) &&
-      is_one_of (info[start+1], FLAG (OT_H)) &&
-      is_one_of (info[start+2], FLAG (OT_ZWJ)))
+      is_one_of (info[start  ], FLAG (I_Cat(Ra))) &&
+      is_one_of (info[start+1], FLAG (I_Cat(H))) &&
+      is_one_of (info[start+2], FLAG (I_Cat(ZWJ))))
   {
     buffer->merge_clusters (start+1, start+3);
-    hb_glyph_info_t tmp = info[start+1];
-    info[start+1] = info[start+2];
-    info[start+2] = tmp;
+    hb_swap (info[start+1], info[start+2]);
   }
 
   /* 1. Find base consonant:
@@ -454,7 +511,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
        start + 3 <= end &&
        (
         (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) ||
-        (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ)
+        (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == I_Cat(ZWJ))
        ))
     {
       /* See if it matches the 'rphf' feature. */
@@ -472,7 +529,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
        base = start;
        has_reph = true;
       }
-    } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[start].indic_category() == OT_Repha)
+    } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[start].indic_category() == I_Cat(Repha))
     {
        limit += 1;
        while (limit < end && is_joiner (info[limit]))
@@ -481,84 +538,51 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
        has_reph = true;
     }
 
-    switch (indic_plan->config->base_pos)
     {
-      case BASE_POS_LAST:
-      {
-       /* -> starting from the end of the syllable, move backwards */
-       unsigned int i = end;
-       bool seen_below = false;
-       do {
-         i--;
-         /* -> until a consonant is found */
-         if (is_consonant (info[i]))
+      /* -> starting from the end of the syllable, move backwards */
+      unsigned int i = end;
+      bool seen_below = false;
+      do {
+       i--;
+       /* -> until a consonant is found */
+       if (is_consonant (info[i]))
+       {
+         /* -> that does not have a below-base or post-base form
+          * (post-base forms have to follow below-base forms), */
+         if (info[i].indic_position() != POS_BELOW_C &&
+             (info[i].indic_position() != POS_POST_C || seen_below))
          {
-           /* -> that does not have a below-base or post-base form
-            * (post-base forms have to follow below-base forms), */
-           if (info[i].indic_position() != POS_BELOW_C &&
-               (info[i].indic_position() != POS_POST_C || seen_below))
-           {
-             base = i;
-             break;
-           }
-           if (info[i].indic_position() == POS_BELOW_C)
-             seen_below = true;
-
-           /* -> or that is not a pre-base-reordering Ra,
-            *
-            * IMPLEMENTATION NOTES:
-            *
-            * Our pre-base-reordering Ra's are marked POS_POST_C, so will be skipped
-            * by the logic above already.
-            */
-
-           /* -> or arrive at the first consonant. The consonant stopped at will
-            * be the base. */
            base = i;
+           break;
          }
-         else
-         {
-           /* A ZWJ after a Halant stops the base search, and requests an explicit
-            * half form.
-            * A ZWJ before a Halant, requests a subjoined form instead, and hence
-            * search continues.  This is particularly important for Bengali
-            * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */
-           if (start < i &&
-               info[i].indic_category() == OT_ZWJ &&
-               info[i - 1].indic_category() == OT_H)
-             break;
-         }
-       } while (i > limit);
-      }
-      break;
+         if (info[i].indic_position() == POS_BELOW_C)
+           seen_below = true;
 
-      case BASE_POS_LAST_SINHALA:
-      {
-       /* Sinhala base positioning is slightly different from main Indic, in that:
-        * 1. Its ZWJ behavior is different,
-        * 2. We don't need to look into the font for consonant positions.
-        */
-
-       if (!has_reph)
-         base = limit;
-
-       /* Find the last base consonant that is not blocked by ZWJ.  If there is
-        * a ZWJ right before a base consonant, that would request a subjoined form. */
-       for (unsigned int i = limit; i < end; i++)
-         if (is_consonant (info[i]))
-         {
-           if (limit < i && info[i - 1].indic_category() == OT_ZWJ)
-             break;
-           else
-             base = i;
-         }
+         /* -> or that is not a pre-base-reordering Ra,
+          *
+          * IMPLEMENTATION NOTES:
+          *
+          * Our pre-base-reordering Ra's are marked POS_POST_C, so will be skipped
+          * by the logic above already.
+          */
 
-       /* Mark all subsequent consonants as below. */
-       for (unsigned int i = base + 1; i < end; i++)
-         if (is_consonant (info[i]))
-           info[i].indic_position() = POS_BELOW_C;
-      }
-      break;
+         /* -> or arrive at the first consonant. The consonant stopped at will
+          * be the base. */
+         base = i;
+       }
+       else
+       {
+         /* A ZWJ after a Halant stops the base search, and requests an explicit
+          * half form.
+          * A ZWJ before a Halant, requests a subjoined form instead, and hence
+          * search continues.  This is particularly important for Bengali
+          * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */
+         if (start < i &&
+             info[i].indic_category() == I_Cat(ZWJ) &&
+             info[i - 1].indic_category() == I_Cat(H))
+           break;
+       }
+      } while (i > limit);
     }
 
     /* -> If the syllable starts with Ra + Halant (in a script that has Reph)
@@ -613,18 +637,6 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
   if (base < end)
     info[base].indic_position() = POS_BASE_C;
 
-  /* Mark final consonants.  A final consonant is one appearing after a matra.
-   * Happens in Sinhala. */
-  for (unsigned int i = base + 1; i < end; i++)
-    if (info[i].indic_category() == OT_M) {
-      for (unsigned int j = i + 1; j < end; j++)
-       if (is_consonant (info[j])) {
-        info[j].indic_position() = POS_FINAL_C;
-        break;
-       }
-      break;
-    }
-
   /* Handle beginning Ra */
   if (has_reph)
     info[start].indic_position() = POS_RA_TO_BECOME_REPH;
@@ -661,14 +673,14 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
   {
     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)
+      if (info[i].indic_category() == I_Cat(H))
       {
        unsigned int j;
        for (j = end - 1; j > i; j--)
          if (is_consonant (info[j]) ||
-             (disallow_double_halants && info[j].indic_category() == OT_H))
+             (disallow_double_halants && info[j].indic_category() == I_Cat(H)))
            break;
-       if (info[j].indic_category() != OT_H && j > i) {
+       if (info[j].indic_category() != I_Cat(H) && j > i) {
          /* Move Halant to after last consonant. */
          hb_glyph_info_t t = info[i];
          memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0]));
@@ -683,20 +695,16 @@ 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 (I_Cat(N)) | FLAG (I_Cat(RS)) | FLAG (I_Cat(CM)) | FLAG (I_Cat(H)))))
       {
        info[i].indic_position() = last_pos;
-       if (unlikely (info[i].indic_category() == OT_H &&
+       if (unlikely (info[i].indic_category() == I_Cat(H) &&
                      info[i].indic_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
+          * TEST: U+092B,U+093F,U+094D
+          * We follow.
           */
          for (unsigned int j = i; j > start; j--)
            if (info[j - 1].indic_position() != POS_PRE_M) {
@@ -705,6 +713,9 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
            }
        }
       } else if (info[i].indic_position() != POS_SMVD) {
+       if (info[i].indic_category() == I_Cat(MPst) &&
+           i > start && info[i - 1].indic_category() == I_Cat(SM))
+         info[i - 1].indic_position() = info[i].indic_position();
        last_pos = (indic_position_t) info[i].indic_position();
       }
     }
@@ -720,7 +731,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
          if (info[j].indic_position() < POS_SMVD)
            info[j].indic_position() = info[i].indic_position();
        last = i;
-      } else if (info[i].indic_category() == OT_M)
+      } else if (FLAG_UNSAFE (info[i].indic_category()) & (FLAG (I_Cat(M)) | FLAG (I_Cat(MPst))))
        last = i;
   }
 
@@ -733,14 +744,40 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
 
     /* Sit tight, rock 'n roll! */
     hb_stable_sort (info + start, end - start, compare_indic_order);
-    /* Find base again */
+
+    /* Find base again; also flip left-matra sequence. */
+    unsigned first_left_matra = end;
+    unsigned last_left_matra = end;
     base = end;
     for (unsigned int i = start; i < end; i++)
+    {
       if (info[i].indic_position() == POS_BASE_C)
       {
        base = i;
        break;
       }
+      else if (info[i].indic_position() == POS_PRE_M)
+      {
+        if (first_left_matra == end)
+         first_left_matra = i;
+       last_left_matra = i;
+      }
+    }
+    /* https://github.com/harfbuzz/harfbuzz/issues/3863 */
+    if (first_left_matra < last_left_matra)
+    {
+      /* No need to merge clusters, handled later. */
+      buffer->reverse_range (first_left_matra, last_left_matra + 1);
+      /* Reverse back nuktas, etc. */
+      unsigned i = first_left_matra;
+      for (unsigned j = i; j <= last_left_matra; j++)
+       if (FLAG_UNSAFE (info[j].indic_category()) & (FLAG (I_Cat(M)) | FLAG (I_Cat(MPst))))
+       {
+         buffer->reverse_range (i, j + 1);
+         i = j + 1;
+       }
+    }
+
     /* Things are out-of-control for post base positions, they may shuffle
      * around like crazy.  In old-spec mode, we move halants around, so in
      * that case merge all clusters after base.  Otherwise, check the sort
@@ -851,10 +888,10 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
      * Test case: U+0924,U+094D,U+0930,U+094d,U+200D,U+0915
      */
     for (unsigned int i = start; i + 1 < base; i++)
-      if (info[i  ].indic_category() == OT_Ra &&
-         info[i+1].indic_category() == OT_H  &&
+      if (info[i  ].indic_category() == I_Cat(Ra) &&
+         info[i+1].indic_category() == I_Cat(H)  &&
          (i + 2 == base ||
-          info[i+2].indic_category() != OT_ZWJ))
+          info[i+2].indic_category() != I_Cat(ZWJ)))
       {
        info[i  ].mask |= indic_plan->mask_array[INDIC_BLWF];
        info[i+1].mask |= indic_plan->mask_array[INDIC_BLWF];
@@ -881,7 +918,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
   /* Apply ZWJ/ZWNJ effects */
   for (unsigned int i = start + 1; i < end; i++)
     if (is_joiner (info[i])) {
-      bool non_joiner = info[i].indic_category() == OT_ZWNJ;
+      bool non_joiner = info[i].indic_category() == I_Cat(ZWNJ);
       unsigned int j = i;
 
       do {
@@ -914,7 +951,7 @@ initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
     /* For dotted-circle, this is what Uniscribe does:
      * If dotted-circle is the last glyph, it just does nothing.
      * Ie. It doesn't form Reph. */
-    if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE)
+    if (buffer->info[end - 1].indic_category() == I_Cat(DOTTEDCIRCLE))
       return;
   }
 
@@ -946,25 +983,29 @@ initial_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
   }
 }
 
-static void
+static bool
 initial_reordering_indic (const hb_ot_shape_plan_t *plan,
                          hb_font_t *font,
                          hb_buffer_t *buffer)
 {
+  bool ret = false;
   if (!buffer->message (font, "start reordering indic initial"))
-    return;
+    return ret;
 
   update_consonant_positions_indic (plan, font, buffer);
-  hb_syllabic_insert_dotted_circles (font, buffer,
-                                    indic_broken_cluster,
-                                    OT_DOTTEDCIRCLE,
-                                    OT_Repha,
-                                    POS_END);
+  if (hb_syllabic_insert_dotted_circles (font, buffer,
+                                        indic_broken_cluster,
+                                        I_Cat(DOTTEDCIRCLE),
+                                        I_Cat(Repha),
+                                        POS_END))
+    ret = true;
 
   foreach_syllable (buffer, start, end)
     initial_reordering_syllable_indic (plan, font->face, buffer, start, end);
 
   (void) buffer->message (font, "end reordering indic initial");
+
+  return ret;
 }
 
 static void
@@ -980,10 +1021,10 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
    * 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_H is desired but has been lost. */
+   * class of I_Cat(H) is desired but has been lost. */
   /* 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 ();
+  hb_codepoint_t virama_glyph = indic_plan->virama_glyph;
   if (virama_glyph)
   {
     for (unsigned int i = start; i < end; i++)
@@ -992,7 +1033,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
          _hb_glyph_info_multiplied (&info[i]))
       {
        /* This will make sure that this glyph passes is_halant() test. */
-       info[i].indic_category() = OT_H;
+       info[i].indic_category() = I_Cat(H);
        _hb_glyph_info_clear_ligated_and_multiplied (&info[i]);
       }
   }
@@ -1026,12 +1067,15 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
              base = i;
              while (base < end && is_halant (info[base]))
                base++;
-             info[base].indic_position() = POS_BASE_C;
+             if (base < end)
+               info[base].indic_position() = POS_BASE_C;
 
              try_pref = false;
            }
            break;
          }
+       if (base == end)
+         break;
       }
       /* For Malayalam, skip over unformed below- (but NOT post-) forms. */
       if (buffer->props.script == HB_SCRIPT_MALAYALAM)
@@ -1058,11 +1102,11 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
       break;
     }
   if (base == end && start < base &&
-      is_one_of (info[base - 1], FLAG (OT_ZWJ)))
+      is_one_of (info[base - 1], FLAG (I_Cat(ZWJ))))
     base--;
   if (base < end)
     while (start < base &&
-          is_one_of (info[base], (FLAG (OT_N) | FLAG (OT_H))))
+          is_one_of (info[base], (FLAG (I_Cat(N)) | FLAG (I_Cat(H)))))
       base--;
 
 
@@ -1107,7 +1151,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
     {
     search:
       while (new_pos > start &&
-            !(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H)))))
+            !(is_one_of (info[new_pos], (FLAG (I_Cat(M)) | FLAG (I_Cat(MPst)) | FLAG (I_Cat(H))))))
        new_pos--;
 
       /* If we found no Halant we are done.
@@ -1124,7 +1168,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
        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)
+         if (info[new_pos + 1].indic_category() == I_Cat(ZWJ))
          {
            /* Keep searching. */
            if (new_pos > start)
@@ -1197,7 +1241,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
    */
   if (start + 1 < end &&
       info[start].indic_position() == POS_RA_TO_BECOME_REPH &&
-      ((info[start].indic_category() == OT_Repha) ^
+      ((info[start].indic_category() == I_Cat(Repha)) ^
        _hb_glyph_info_ligated_and_didnt_multiply (&info[start])))
   {
     unsigned int new_reph_pos;
@@ -1307,7 +1351,8 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
          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) {
+         if (FLAG_UNSAFE (info[i].indic_category()) & (FLAG (I_Cat(M)) | FLAG (I_Cat(MPst))))
+         {
            /* Ok, got it. */
            new_reph_pos--;
          }
@@ -1367,7 +1412,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
          if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL)
          {
            while (new_pos > start &&
-                  !(is_one_of (info[new_pos - 1], FLAG(OT_M) | FLAG (OT_H))))
+                  !(is_one_of (info[new_pos - 1], FLAG (I_Cat(M)) | FLAG (I_Cat(MPst)) | FLAG (I_Cat(H)))))
              new_pos--;
          }
 
@@ -1416,11 +1461,10 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
     switch ((hb_tag_t) plan->props.script)
     {
       case HB_SCRIPT_TAMIL:
-      case HB_SCRIPT_SINHALA:
        break;
 
       default:
-       /* Uniscribe merges the entire syllable into a single cluster... Except for Tamil & Sinhala.
+       /* Uniscribe merges the entire syllable into a single cluster... Except for Tamil.
         * 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. */
@@ -1431,13 +1475,13 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
 }
 
 
-static void
+static bool
 final_reordering_indic (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;
+  if (unlikely (!count)) return false;
 
   if (buffer->message (font, "start reordering indic final")) {
     foreach_syllable (buffer, start, end)
@@ -1447,6 +1491,8 @@ final_reordering_indic (const hb_ot_shape_plan_t *plan,
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category);
   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position);
+
+  return false;
 }
 
 
@@ -1455,7 +1501,9 @@ 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);
+  const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
+  if (!indic_plan->uniscribe_bug_compatible)
+    _hb_preprocess_text_vowel_constraints (plan, buffer, font);
 }
 
 static bool
@@ -1488,48 +1536,6 @@ decompose_indic (const hb_ot_shape_normalize_context_t *c,
 #endif
   }
 
-  if ((ab == 0x0DDAu || hb_in_range<hb_codepoint_t> (ab, 0x0DDCu, 0x0DDEu)))
-  {
-    /*
-     * Sinhala split matras...  Let the fun begin.
-     *
-     * These four characters have Unicode decompositions.  However, Uniscribe
-     * decomposes them "Khmer-style", that is, it uses the character itself to
-     * get the second half.  The first half of all four decompositions is always
-     * U+0DD9.
-     *
-     * Now, there are buggy fonts, namely, the widely used lklug.ttf, that are
-     * broken with Uniscribe.  But we need to support them.  As such, we only
-     * do the Uniscribe-style decomposition if the character is transformed into
-     * its "sec.half" form by the 'pstf' feature.  Otherwise, we fall back to
-     * Unicode decomposition.
-     *
-     * Note that we can't unconditionally use Unicode decomposition.  That would
-     * break some other fonts, that are designed to work with Uniscribe, and
-     * don't have positioning features for the Unicode-style decomposition.
-     *
-     * Argh...
-     *
-     * The Uniscribe behavior is now documented in the newly published Sinhala
-     * spec in 2012:
-     *
-     *   https://docs.microsoft.com/en-us/typography/script-development/sinhala#shaping
-     */
-
-
-    const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data;
-    hb_codepoint_t glyph;
-    if (indic_plan->uniscribe_bug_compatible ||
-       (c->font->get_nominal_glyph (ab, &glyph) &&
-        indic_plan->pstf.would_substitute (&glyph, 1, c->font->face)))
-    {
-      /* Ok, safe to use Uniscribe-style decomposition. */
-      *a = 0x0DD9u;
-      *b = ab;
-      return true;
-    }
-  }
-
   return (bool) c->unicode->decompose (ab, a, b);
 }
 
@@ -1550,7 +1556,7 @@ compose_indic (const hb_ot_shape_normalize_context_t *c,
 }
 
 
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
+const hb_ot_shaper_t _hb_ot_shaper_indic =
 {
   collect_features_indic,
   override_features_indic,
@@ -1558,12 +1564,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
   data_destroy_indic,
   preprocess_text_indic,
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   decompose_indic,
   compose_indic,
   setup_masks_indic,
-  HB_TAG_NONE, /* gpos_tag */
   nullptr, /* reorder_marks */
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
diff --git a/src/hb-ot-shaper-indic.hh b/src/hb-ot-shaper-indic.hh
new file mode 100644 (file)
index 0000000..4f822c2
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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_OT_SHAPER_INDIC_HH
+#define HB_OT_SHAPER_INDIC_HH
+
+#include "hb.hh"
+
+#include "hb-ot-shaper-syllabic.hh"
+
+
+/* Visual positions in a syllable from left to right. */
+enum ot_position_t {
+  POS_START = 0,
+
+  POS_RA_TO_BECOME_REPH = 1,
+  POS_PRE_M = 2,
+  POS_PRE_C = 3,
+
+  POS_BASE_C = 4,
+  POS_AFTER_MAIN = 5,
+
+  POS_ABOVE_C = 6,
+
+  POS_BEFORE_SUB = 7,
+  POS_BELOW_C = 8,
+  POS_AFTER_SUB = 9,
+
+  POS_BEFORE_POST = 10,
+  POS_POST_C = 11,
+  POS_AFTER_POST = 12,
+
+  POS_SMVD = 13,
+
+  POS_END = 14
+};
+
+
+HB_INTERNAL uint16_t
+hb_indic_get_categories (hb_codepoint_t u);
+
+
+#endif /* HB_OT_SHAPER_INDIC_HH */
diff --git a/src/hb-ot-shaper-khmer-machine.hh b/src/hb-ot-shaper-khmer-machine.hh
new file mode 100644 (file)
index 0000000..f1e7a91
--- /dev/null
@@ -0,0 +1,428 @@
+
+#line 1 "hb-ot-shaper-khmer-machine.rl"
+/*
+ * Copyright © 2011,2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPER_KHMER_MACHINE_HH
+#define HB_OT_SHAPER_KHMER_MACHINE_HH
+
+#include "hb.hh"
+
+#include "hb-ot-layout.hh"
+#include "hb-ot-shaper-indic.hh"
+
+/* buffer var allocations */
+#define khmer_category() ot_shaper_var_u8_category() /* khmer_category_t */
+
+using khmer_category_t = unsigned;
+
+#define K_Cat(Cat) khmer_syllable_machine_ex_##Cat
+
+enum khmer_syllable_type_t {
+  khmer_consonant_syllable,
+  khmer_broken_cluster,
+  khmer_non_khmer_cluster,
+};
+
+
+#line 52 "hb-ot-shaper-khmer-machine.hh"
+#define khmer_syllable_machine_ex_C 1u
+#define khmer_syllable_machine_ex_DOTTEDCIRCLE 11u
+#define khmer_syllable_machine_ex_H 4u
+#define khmer_syllable_machine_ex_PLACEHOLDER 10u
+#define khmer_syllable_machine_ex_Ra 15u
+#define khmer_syllable_machine_ex_Robatic 25u
+#define khmer_syllable_machine_ex_V 2u
+#define khmer_syllable_machine_ex_VAbv 20u
+#define khmer_syllable_machine_ex_VBlw 21u
+#define khmer_syllable_machine_ex_VPre 22u
+#define khmer_syllable_machine_ex_VPst 23u
+#define khmer_syllable_machine_ex_Xgroup 26u
+#define khmer_syllable_machine_ex_Ygroup 27u
+#define khmer_syllable_machine_ex_ZWJ 6u
+#define khmer_syllable_machine_ex_ZWNJ 5u
+
+
+#line 70 "hb-ot-shaper-khmer-machine.hh"
+static const unsigned char _khmer_syllable_machine_trans_keys[] = {
+       5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 
+       5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, 
+       5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 1u, 27u, 4u, 27u, 1u, 15u, 
+       4u, 27u, 4u, 27u, 27u, 27u, 4u, 27u, 4u, 27u, 4u, 27u, 4u, 27u, 4u, 27u, 
+       4u, 27u, 1u, 15u, 4u, 27u, 4u, 27u, 27u, 27u, 4u, 27u, 4u, 27u, 4u, 27u, 
+       4u, 27u, 4u, 27u, 5u, 26u, 0
+};
+
+static const char _khmer_syllable_machine_key_spans[] = {
+       22, 22, 15, 22, 22, 22, 22, 22, 
+       22, 22, 22, 22, 22, 15, 22, 22, 
+       22, 22, 22, 22, 22, 27, 24, 15, 
+       24, 24, 1, 24, 24, 24, 24, 24, 
+       24, 15, 24, 24, 1, 24, 24, 24, 
+       24, 24, 22
+};
+
+static const short _khmer_syllable_machine_index_offsets[] = {
+       0, 23, 46, 62, 85, 108, 131, 154, 
+       177, 200, 223, 246, 269, 292, 308, 331, 
+       354, 377, 400, 423, 446, 469, 497, 522, 
+       538, 563, 588, 590, 615, 640, 665, 690, 
+       715, 740, 756, 781, 806, 808, 833, 858, 
+       883, 908, 933
+};
+
+static const char _khmer_syllable_machine_indicies[] = {
+       1, 1, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 2, 
+       0, 0, 0, 0, 3, 4, 0, 1, 
+       1, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 4, 0, 5, 5, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 5, 0, 1, 1, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 2, 0, 0, 
+       0, 0, 0, 4, 0, 6, 6, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 2, 0, 7, 7, 0, 0, 
+       0, 0, 0, 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, 2, 0, 0, 0, 0, 0, 
+       10, 0, 9, 9, 0, 0, 0, 0, 
+       0, 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, 
+       2, 0, 0, 0, 0, 0, 12, 0, 
+       11, 11, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 12, 0, 1, 
+       1, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 2, 0, 
+       0, 0, 0, 13, 4, 0, 15, 15, 
+       14, 14, 14, 14, 14, 14, 14, 14, 
+       14, 14, 14, 14, 14, 16, 14, 14, 
+       14, 14, 17, 18, 14, 15, 15, 19, 
+       19, 19, 19, 19, 19, 19, 19, 19, 
+       19, 19, 19, 19, 19, 19, 19, 19, 
+       19, 19, 18, 19, 20, 20, 14, 14, 
+       14, 14, 14, 14, 14, 14, 14, 14, 
+       14, 14, 20, 14, 15, 15, 14, 14, 
+       14, 14, 14, 14, 14, 14, 14, 14, 
+       14, 14, 14, 16, 14, 14, 14, 14, 
+       14, 18, 14, 21, 21, 14, 14, 14, 
+       14, 14, 14, 14, 14, 14, 14, 14, 
+       14, 14, 14, 14, 14, 14, 14, 14, 
+       16, 14, 22, 22, 14, 14, 14, 14, 
+       14, 14, 14, 14, 14, 14, 14, 14, 
+       14, 14, 14, 14, 14, 14, 14, 23, 
+       14, 24, 24, 14, 14, 14, 14, 14, 
+       14, 14, 14, 14, 14, 14, 14, 14, 
+       16, 14, 14, 14, 14, 14, 25, 14, 
+       24, 24, 14, 14, 14, 14, 14, 14, 
+       14, 14, 14, 14, 14, 14, 14, 14, 
+       14, 14, 14, 14, 14, 25, 14, 26, 
+       26, 14, 14, 14, 14, 14, 14, 14, 
+       14, 14, 14, 14, 14, 14, 16, 14, 
+       14, 14, 14, 14, 27, 14, 26, 26, 
+       14, 14, 14, 14, 14, 14, 14, 14, 
+       14, 14, 14, 14, 14, 14, 14, 14, 
+       14, 14, 14, 27, 14, 29, 29, 28, 
+       30, 31, 31, 28, 28, 28, 13, 13, 
+       28, 28, 28, 29, 28, 28, 28, 28, 
+       16, 25, 27, 23, 28, 17, 18, 20, 
+       28, 33, 34, 34, 32, 32, 32, 32, 
+       32, 32, 32, 32, 32, 32, 32, 32, 
+       32, 2, 10, 12, 8, 32, 13, 4, 
+       5, 32, 35, 35, 32, 32, 32, 32, 
+       32, 32, 32, 32, 32, 32, 32, 32, 
+       35, 32, 33, 36, 36, 32, 32, 32, 
+       32, 32, 32, 32, 32, 32, 32, 32, 
+       32, 32, 2, 10, 12, 8, 32, 3, 
+       4, 5, 32, 37, 38, 38, 32, 32, 
+       32, 32, 32, 32, 32, 32, 32, 32, 
+       32, 32, 32, 2, 10, 12, 8, 32, 
+       32, 4, 5, 32, 5, 32, 37, 6, 
+       6, 32, 32, 32, 32, 32, 32, 32, 
+       32, 32, 32, 32, 32, 32, 32, 32, 
+       32, 8, 32, 32, 2, 5, 32, 37, 
+       7, 7, 32, 32, 32, 32, 32, 32, 
+       32, 32, 32, 32, 32, 32, 32, 32, 
+       32, 32, 32, 32, 32, 8, 5, 32, 
+       37, 39, 39, 32, 32, 32, 32, 32, 
+       32, 32, 32, 32, 32, 32, 32, 32, 
+       2, 32, 32, 8, 32, 32, 10, 5, 
+       32, 37, 40, 40, 32, 32, 32, 32, 
+       32, 32, 32, 32, 32, 32, 32, 32, 
+       32, 2, 10, 32, 8, 32, 32, 12, 
+       5, 32, 33, 38, 38, 32, 32, 32, 
+       32, 32, 32, 32, 32, 32, 32, 32, 
+       32, 32, 2, 10, 12, 8, 32, 32, 
+       4, 5, 32, 33, 38, 38, 32, 32, 
+       32, 32, 32, 32, 32, 32, 32, 32, 
+       32, 32, 32, 2, 10, 12, 8, 32, 
+       3, 4, 5, 32, 42, 42, 41, 41, 
+       41, 41, 41, 41, 41, 41, 41, 41, 
+       41, 41, 42, 41, 30, 43, 43, 41, 
+       41, 41, 41, 41, 41, 41, 41, 41, 
+       41, 41, 41, 41, 16, 25, 27, 23, 
+       41, 17, 18, 20, 41, 44, 45, 45, 
+       41, 41, 41, 41, 41, 41, 41, 41, 
+       41, 41, 41, 41, 41, 16, 25, 27, 
+       23, 41, 41, 18, 20, 41, 20, 41, 
+       44, 21, 21, 41, 41, 41, 41, 41, 
+       41, 41, 41, 41, 41, 41, 41, 41, 
+       41, 41, 41, 23, 41, 41, 16, 20, 
+       41, 44, 22, 22, 41, 41, 41, 41, 
+       41, 41, 41, 41, 41, 41, 41, 41, 
+       41, 41, 41, 41, 41, 41, 41, 23, 
+       20, 41, 44, 46, 46, 41, 41, 41, 
+       41, 41, 41, 41, 41, 41, 41, 41, 
+       41, 41, 16, 41, 41, 23, 41, 41, 
+       25, 20, 41, 44, 47, 47, 41, 41, 
+       41, 41, 41, 41, 41, 41, 41, 41, 
+       41, 41, 41, 16, 25, 41, 23, 41, 
+       41, 27, 20, 41, 30, 45, 45, 41, 
+       41, 41, 41, 41, 41, 41, 41, 41, 
+       41, 41, 41, 41, 16, 25, 27, 23, 
+       41, 41, 18, 20, 41, 15, 15, 48, 
+       48, 48, 48, 48, 48, 48, 48, 48, 
+       48, 48, 48, 48, 16, 48, 48, 48, 
+       48, 48, 18, 48, 0
+};
+
+static const char _khmer_syllable_machine_trans_targs[] = {
+       21, 1, 27, 31, 25, 26, 4, 5, 
+       28, 7, 29, 9, 30, 32, 21, 12, 
+       37, 41, 35, 21, 36, 15, 16, 38, 
+       18, 39, 20, 40, 21, 22, 33, 42, 
+       21, 23, 10, 24, 0, 2, 3, 6, 
+       8, 21, 34, 11, 13, 14, 17, 19, 
+       21
+};
+
+static const char _khmer_syllable_machine_trans_actions[] = {
+       1, 0, 2, 2, 2, 0, 0, 0, 
+       2, 0, 2, 0, 2, 2, 3, 0, 
+       2, 4, 4, 5, 0, 0, 0, 2, 
+       0, 2, 0, 2, 8, 2, 0, 9, 
+       10, 0, 0, 2, 0, 0, 0, 0, 
+       0, 11, 4, 0, 0, 0, 0, 0, 
+       12
+};
+
+static const char _khmer_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, 6, 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, 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
+};
+
+static const short _khmer_syllable_machine_eof_trans[] = {
+       1, 1, 1, 1, 1, 1, 1, 1, 
+       1, 1, 1, 15, 20, 15, 15, 15, 
+       15, 15, 15, 15, 15, 0, 33, 33, 
+       33, 33, 33, 33, 33, 33, 33, 33, 
+       33, 42, 42, 42, 42, 42, 42, 42, 
+       42, 42, 49
+};
+
+static const int khmer_syllable_machine_start = 21;
+static const int khmer_syllable_machine_first_final = 21;
+static const int khmer_syllable_machine_error = -1;
+
+static const int khmer_syllable_machine_en_main = 21;
+
+
+#line 53 "hb-ot-shaper-khmer-machine.rl"
+
+
+
+#line 102 "hb-ot-shaper-khmer-machine.rl"
+
+
+#define found_syllable(syllable_type) \
+  HB_STMT_START { \
+    if (0) fprintf (stderr, "syllable %u..%u %s\n", ts, te, #syllable_type); \
+    for (unsigned int i = ts; i < te; i++) \
+      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+    syllable_serial++; \
+    if (syllable_serial == 16) syllable_serial = 1; \
+  } HB_STMT_END
+
+inline void
+find_syllables_khmer (hb_buffer_t *buffer)
+{
+  unsigned int p, pe, eof, ts, te, act HB_UNUSED;
+  int cs;
+  hb_glyph_info_t *info = buffer->info;
+  
+#line 298 "hb-ot-shaper-khmer-machine.hh"
+       {
+       cs = khmer_syllable_machine_start;
+       ts = 0;
+       te = 0;
+       act = 0;
+       }
+
+#line 122 "hb-ot-shaper-khmer-machine.rl"
+
+
+  p = 0;
+  pe = eof = buffer->len;
+
+  unsigned int syllable_serial = 1;
+  
+#line 314 "hb-ot-shaper-khmer-machine.hh"
+       {
+       int _slen;
+       int _trans;
+       const unsigned char *_keys;
+       const char *_inds;
+       if ( p == pe )
+               goto _test_eof;
+_resume:
+       switch ( _khmer_syllable_machine_from_state_actions[cs] ) {
+       case 7:
+#line 1 "NONE"
+       {ts = p;}
+       break;
+#line 328 "hb-ot-shaper-khmer-machine.hh"
+       }
+
+       _keys = _khmer_syllable_machine_trans_keys + (cs<<1);
+       _inds = _khmer_syllable_machine_indicies + _khmer_syllable_machine_index_offsets[cs];
+
+       _slen = _khmer_syllable_machine_key_spans[cs];
+       _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].khmer_category()) &&
+               ( info[p].khmer_category()) <= _keys[1] ?
+               ( info[p].khmer_category()) - _keys[0] : _slen ];
+
+_eof_trans:
+       cs = _khmer_syllable_machine_trans_targs[_trans];
+
+       if ( _khmer_syllable_machine_trans_actions[_trans] == 0 )
+               goto _again;
+
+       switch ( _khmer_syllable_machine_trans_actions[_trans] ) {
+       case 2:
+#line 1 "NONE"
+       {te = p+1;}
+       break;
+       case 8:
+#line 98 "hb-ot-shaper-khmer-machine.rl"
+       {te = p+1;{ found_syllable (khmer_non_khmer_cluster); }}
+       break;
+       case 10:
+#line 96 "hb-ot-shaper-khmer-machine.rl"
+       {te = p;p--;{ found_syllable (khmer_consonant_syllable); }}
+       break;
+       case 11:
+#line 97 "hb-ot-shaper-khmer-machine.rl"
+       {te = p;p--;{ found_syllable (khmer_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
+       break;
+       case 12:
+#line 98 "hb-ot-shaper-khmer-machine.rl"
+       {te = p;p--;{ found_syllable (khmer_non_khmer_cluster); }}
+       break;
+       case 1:
+#line 96 "hb-ot-shaper-khmer-machine.rl"
+       {{p = ((te))-1;}{ found_syllable (khmer_consonant_syllable); }}
+       break;
+       case 3:
+#line 97 "hb-ot-shaper-khmer-machine.rl"
+       {{p = ((te))-1;}{ found_syllable (khmer_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
+       break;
+       case 5:
+#line 1 "NONE"
+       {       switch( act ) {
+       case 2:
+       {{p = ((te))-1;} found_syllable (khmer_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }
+       break;
+       case 3:
+       {{p = ((te))-1;} found_syllable (khmer_non_khmer_cluster); }
+       break;
+       }
+       }
+       break;
+       case 4:
+#line 1 "NONE"
+       {te = p+1;}
+#line 97 "hb-ot-shaper-khmer-machine.rl"
+       {act = 2;}
+       break;
+       case 9:
+#line 1 "NONE"
+       {te = p+1;}
+#line 98 "hb-ot-shaper-khmer-machine.rl"
+       {act = 3;}
+       break;
+#line 398 "hb-ot-shaper-khmer-machine.hh"
+       }
+
+_again:
+       switch ( _khmer_syllable_machine_to_state_actions[cs] ) {
+       case 6:
+#line 1 "NONE"
+       {ts = 0;}
+       break;
+#line 407 "hb-ot-shaper-khmer-machine.hh"
+       }
+
+       if ( ++p != pe )
+               goto _resume;
+       _test_eof: {}
+       if ( p == eof )
+       {
+       if ( _khmer_syllable_machine_eof_trans[cs] > 0 ) {
+               _trans = _khmer_syllable_machine_eof_trans[cs] - 1;
+               goto _eof_trans;
+       }
+       }
+
+       }
+
+#line 130 "hb-ot-shaper-khmer-machine.rl"
+
+}
+
+#undef found_syllable
+
+#endif /* HB_OT_SHAPER_KHMER_MACHINE_HH */
similarity index 70%
rename from src/hb-ot-shape-complex-khmer-machine.rl
rename to src/hb-ot-shaper-khmer-machine.rl
index c9cf33f..c226e77 100644 (file)
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
+#ifndef HB_OT_SHAPER_KHMER_MACHINE_HH
+#define HB_OT_SHAPER_KHMER_MACHINE_HH
 
 #include "hb.hh"
 
+#include "hb-ot-layout.hh"
+#include "hb-ot-shaper-indic.hh"
+
+/* buffer var allocations */
+#define khmer_category() ot_shaper_var_u8_category() /* khmer_category_t */
+
+using khmer_category_t = unsigned;
+
+#define K_Cat(Cat) khmer_syllable_machine_ex_##Cat
+
 enum khmer_syllable_type_t {
   khmer_consonant_syllable,
   khmer_broken_cluster,
@@ -44,21 +54,27 @@ enum khmer_syllable_type_t {
 
 %%{
 
+
+# We use category H for spec category Coeng
+
 export C    = 1;
 export V    = 2;
+export H    = 4;
 export ZWNJ = 5;
 export ZWJ  = 6;
-export PLACEHOLDER = 11;
-export DOTTEDCIRCLE = 12;
-export Coeng= 14;
-export Ra   = 16;
-export Robatic = 20;
-export Xgroup  = 21;
-export Ygroup  = 22;
-export VAbv = 26;
-export VBlw = 27;
-export VPre = 28;
-export VPst = 29;
+export PLACEHOLDER = 10;
+export DOTTEDCIRCLE = 11;
+export Ra   = 15;
+
+export VAbv = 20;
+export VBlw = 21;
+export VPre = 22;
+export VPst = 23;
+
+export Robatic = 25;
+export Xgroup  = 26;
+export Ygroup  = 27;
+
 
 c = (C | Ra | V);
 cn = c.((ZWJ|ZWNJ)?.Robatic)?;
@@ -69,16 +85,16 @@ 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;
+syllable_tail = xgroup matra_group xgroup (H.c)? ygroup;
 
 
-broken_cluster =       (Coeng.cn)* (Coeng | syllable_tail);
+broken_cluster =       Robatic? (H.cn)* (H | syllable_tail);
 consonant_syllable =   (cn|PLACEHOLDER|DOTTEDCIRCLE) broken_cluster;
 other =                        any;
 
 main := |*
        consonant_syllable      => { found_syllable (khmer_consonant_syllable); };
-       broken_cluster          => { found_syllable (khmer_broken_cluster); };
+       broken_cluster          => { found_syllable (khmer_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; };
        other                   => { found_syllable (khmer_non_khmer_cluster); };
 *|;
 
@@ -87,14 +103,14 @@ main := |*
 
 #define found_syllable(syllable_type) \
   HB_STMT_START { \
-    if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
+    if (0) fprintf (stderr, "syllable %u..%u %s\n", ts, te, #syllable_type); \
     for (unsigned int i = ts; i < te; i++) \
       info[i].syllable() = (syllable_serial << 4) | syllable_type; \
     syllable_serial++; \
-    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+    if (syllable_serial == 16) syllable_serial = 1; \
   } HB_STMT_END
 
-static void
+inline void
 find_syllables_khmer (hb_buffer_t *buffer)
 {
   unsigned int p, pe, eof, ts, te, act HB_UNUSED;
@@ -116,4 +132,4 @@ find_syllables_khmer (hb_buffer_t *buffer)
 
 #undef found_syllable
 
-#endif /* HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH */
+#endif /* HB_OT_SHAPER_KHMER_MACHINE_HH */
similarity index 87%
rename from src/hb-ot-shape-complex-khmer.cc
rename to src/hb-ot-shaper-khmer.cc
index 7787886..019a285 100644 (file)
@@ -28,8 +28,8 @@
 
 #ifndef HB_NO_OT_SHAPE
 
-#include "hb-ot-shape-complex-khmer.hh"
-#include "hb-ot-shape-complex-khmer-machine.hh"
+#include "hb-ot-shaper-khmer-machine.hh"
+#include "hb-ot-shaper-indic.hh"
 #include "hb-ot-layout.hh"
 
 
@@ -37,6 +37,7 @@
  * Khmer shaper.
  */
 
+
 static const hb_ot_map_feature_t
 khmer_features[] =
 {
@@ -45,11 +46,11 @@ khmer_features[] =
    * These features are applied all at once, before reordering, constrained
    * to the syllable.
    */
-  {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},
+  {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('c','f','a','r'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
   /*
    * Other features.
    * These features are applied all at once after clearing syllables.
@@ -79,11 +80,20 @@ enum {
   KHMER_BASIC_FEATURES = _KHMER_PRES, /* Don't forget to update this! */
 };
 
-static void
+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);
+
+  info.khmer_category() = (khmer_category_t) (type & 0xFFu);
+}
+
+static bool
 setup_syllables_khmer (const hb_ot_shape_plan_t *plan,
                       hb_font_t *font,
                       hb_buffer_t *buffer);
-static void
+static bool
 reorder_khmer (const hb_ot_shape_plan_t *plan,
               hb_font_t *font,
               hb_buffer_t *buffer);
@@ -107,14 +117,15 @@ collect_features_khmer (hb_ot_shape_planner_t *plan)
    *
    * 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'));
+  map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
+  map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
 
   unsigned int i = 0;
   for (; i < KHMER_BASIC_FEATURES; i++)
     map->add_feature (khmer_features[i]);
 
-  map->add_gsub_pause (_hb_clear_syllables);
+  /* https://github.com/harfbuzz/harfbuzz/issues/3531 */
+  map->add_gsub_pause (hb_syllabic_clear_var); // Don't need syllables anymore, use stop to free buffer var
 
   for (; i < KHMER_NUM_FEATURES; i++)
     map->add_feature (khmer_features[i]);
@@ -181,14 +192,16 @@ setup_masks_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED,
     set_khmer_properties (info[i]);
 }
 
-static void
+static bool
 setup_syllables_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED,
                       hb_font_t *font HB_UNUSED,
                       hb_buffer_t *buffer)
 {
+  HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
   find_syllables_khmer (buffer);
   foreach_syllable (buffer, start, end)
     buffer->unsafe_to_break (start, end);
+  return false;
 }
 
 
@@ -229,11 +242,11 @@ reorder_consonant_syllable (const hb_ot_shape_plan_t *plan,
      * the 'pref' OpenType feature applied to them.
      * """
      */
-    if (info[i].khmer_category() == OT_Coeng && num_coengs <= 2 && i + 1 < end)
+    if (info[i].khmer_category() == K_Cat(H) && num_coengs <= 2 && i + 1 < end)
     {
       num_coengs++;
 
-      if (info[i + 1].khmer_category() == OT_Ra)
+      if (info[i + 1].khmer_category() == K_Cat(Ra))
       {
        for (unsigned int j = 0; j < 2; j++)
          info[i + j].mask |= khmer_plan->mask_array[KHMER_PREF];
@@ -261,7 +274,7 @@ reorder_consonant_syllable (const hb_ot_shape_plan_t *plan,
     }
 
     /* Reorder left matra piece. */
-    else if (info[i].khmer_category() == OT_VPre)
+    else if (info[i].khmer_category() == K_Cat(VPre))
     {
       /* Move to the start. */
       buffer->merge_clusters (start, i + 1);
@@ -291,23 +304,27 @@ reorder_syllable_khmer (const hb_ot_shape_plan_t *plan,
   }
 }
 
-static void
+static bool
 reorder_khmer (const hb_ot_shape_plan_t *plan,
               hb_font_t *font,
               hb_buffer_t *buffer)
 {
+  bool ret = false;
   if (buffer->message (font, "start reordering khmer"))
   {
-    hb_syllabic_insert_dotted_circles (font, buffer,
-                                      khmer_broken_cluster,
-                                      OT_DOTTEDCIRCLE,
-                                      OT_Repha);
+    if (hb_syllabic_insert_dotted_circles (font, buffer,
+                                          khmer_broken_cluster,
+                                          K_Cat(DOTTEDCIRCLE),
+                                          (unsigned) -1))
+      ret = true;
 
     foreach_syllable (buffer, start, end)
       reorder_syllable_khmer (plan, font->face, buffer, start, end);
     (void) buffer->message (font, "end reordering khmer");
   }
   HB_BUFFER_DEALLOCATE_VAR (buffer, khmer_category);
+
+  return ret;
 }
 
 
@@ -348,7 +365,7 @@ compose_khmer (const hb_ot_shape_normalize_context_t *c,
 }
 
 
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_khmer =
+const hb_ot_shaper_t _hb_ot_shaper_khmer =
 {
   collect_features_khmer,
   override_features_khmer,
@@ -356,12 +373,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_khmer =
   data_destroy_khmer,
   nullptr, /* preprocess_text */
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   decompose_khmer,
   compose_khmer,
   setup_masks_khmer,
-  HB_TAG_NONE, /* gpos_tag */
   nullptr, /* reorder_marks */
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
diff --git a/src/hb-ot-shaper-myanmar-machine.hh b/src/hb-ot-shaper-myanmar-machine.hh
new file mode 100644 (file)
index 0000000..f7b456b
--- /dev/null
@@ -0,0 +1,553 @@
+
+#line 1 "hb-ot-shaper-myanmar-machine.rl"
+/*
+ * Copyright © 2011,2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPER_MYANMAR_MACHINE_HH
+#define HB_OT_SHAPER_MYANMAR_MACHINE_HH
+
+#include "hb.hh"
+
+#include "hb-ot-layout.hh"
+#include "hb-ot-shaper-indic.hh"
+
+/* buffer var allocations */
+#define myanmar_category() ot_shaper_var_u8_category() /* myanmar_category_t */
+#define myanmar_position() ot_shaper_var_u8_auxiliary() /* myanmar_position_t */
+
+using myanmar_category_t = unsigned;
+using myanmar_position_t = ot_position_t;
+
+#define M_Cat(Cat) myanmar_syllable_machine_ex_##Cat
+
+enum myanmar_syllable_type_t {
+  myanmar_consonant_syllable,
+  myanmar_broken_cluster,
+  myanmar_non_myanmar_cluster,
+};
+
+
+#line 54 "hb-ot-shaper-myanmar-machine.hh"
+#define myanmar_syllable_machine_ex_A 9u
+#define myanmar_syllable_machine_ex_As 32u
+#define myanmar_syllable_machine_ex_C 1u
+#define myanmar_syllable_machine_ex_CS 18u
+#define myanmar_syllable_machine_ex_DB 3u
+#define myanmar_syllable_machine_ex_DOTTEDCIRCLE 11u
+#define myanmar_syllable_machine_ex_GB 10u
+#define myanmar_syllable_machine_ex_H 4u
+#define myanmar_syllable_machine_ex_IV 2u
+#define myanmar_syllable_machine_ex_MH 35u
+#define myanmar_syllable_machine_ex_ML 41u
+#define myanmar_syllable_machine_ex_MR 36u
+#define myanmar_syllable_machine_ex_MW 37u
+#define myanmar_syllable_machine_ex_MY 38u
+#define myanmar_syllable_machine_ex_PT 39u
+#define myanmar_syllable_machine_ex_Ra 15u
+#define myanmar_syllable_machine_ex_SM 8u
+#define myanmar_syllable_machine_ex_VAbv 20u
+#define myanmar_syllable_machine_ex_VBlw 21u
+#define myanmar_syllable_machine_ex_VPre 22u
+#define myanmar_syllable_machine_ex_VPst 23u
+#define myanmar_syllable_machine_ex_VS 40u
+#define myanmar_syllable_machine_ex_ZWJ 6u
+#define myanmar_syllable_machine_ex_ZWNJ 5u
+
+
+#line 81 "hb-ot-shaper-myanmar-machine.hh"
+static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
+       1u, 41u, 3u, 41u, 5u, 39u, 5u, 8u, 3u, 41u, 3u, 39u, 3u, 39u, 5u, 39u, 
+       5u, 39u, 3u, 39u, 3u, 39u, 3u, 41u, 5u, 39u, 1u, 15u, 3u, 39u, 3u, 39u, 
+       3u, 40u, 3u, 39u, 3u, 41u, 3u, 41u, 3u, 39u, 3u, 41u, 3u, 41u, 3u, 41u, 
+       3u, 41u, 3u, 41u, 5u, 39u, 5u, 8u, 3u, 41u, 3u, 39u, 3u, 39u, 5u, 39u, 
+       5u, 39u, 3u, 39u, 3u, 39u, 3u, 41u, 5u, 39u, 1u, 15u, 3u, 41u, 3u, 39u, 
+       3u, 39u, 3u, 40u, 3u, 39u, 3u, 41u, 3u, 41u, 3u, 39u, 3u, 41u, 3u, 41u, 
+       3u, 41u, 3u, 41u, 3u, 41u, 3u, 41u, 3u, 41u, 1u, 41u, 1u, 15u, 0
+};
+
+static const char _myanmar_syllable_machine_key_spans[] = {
+       41, 39, 35, 4, 39, 37, 37, 35, 
+       35, 37, 37, 39, 35, 15, 37, 37, 
+       38, 37, 39, 39, 37, 39, 39, 39, 
+       39, 39, 35, 4, 39, 37, 37, 35, 
+       35, 37, 37, 39, 35, 15, 39, 37, 
+       37, 38, 37, 39, 39, 37, 39, 39, 
+       39, 39, 39, 39, 39, 41, 15
+};
+
+static const short _myanmar_syllable_machine_index_offsets[] = {
+       0, 42, 82, 118, 123, 163, 201, 239, 
+       275, 311, 349, 387, 427, 463, 479, 517, 
+       555, 594, 632, 672, 712, 750, 790, 830, 
+       870, 910, 950, 986, 991, 1031, 1069, 1107, 
+       1143, 1179, 1217, 1255, 1295, 1331, 1347, 1387, 
+       1425, 1463, 1502, 1540, 1580, 1620, 1658, 1698, 
+       1738, 1778, 1818, 1858, 1898, 1938, 1980
+};
+
+static const char _myanmar_syllable_machine_indicies[] = {
+       1, 1, 2, 3, 4, 4, 0, 5, 
+       6, 1, 1, 0, 0, 0, 7, 0, 
+       0, 8, 0, 9, 10, 11, 12, 0, 
+       0, 0, 0, 0, 0, 0, 0, 13, 
+       0, 0, 14, 15, 16, 17, 18, 19, 
+       20, 0, 22, 23, 24, 24, 21, 25, 
+       26, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 27, 28, 29, 30, 21, 
+       21, 21, 21, 21, 21, 21, 21, 31, 
+       21, 21, 32, 33, 34, 35, 36, 37, 
+       38, 21, 24, 24, 21, 25, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 30, 21, 21, 21, 
+       21, 21, 21, 21, 21, 39, 21, 21, 
+       21, 21, 21, 21, 36, 21, 24, 24, 
+       21, 25, 21, 22, 21, 24, 24, 21, 
+       25, 26, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 40, 21, 21, 30, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       41, 21, 21, 42, 21, 21, 21, 36, 
+       21, 41, 21, 22, 21, 24, 24, 21, 
+       25, 26, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 30, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 36, 
+       21, 43, 21, 24, 24, 21, 25, 36, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 44, 21, 
+       21, 21, 21, 21, 21, 36, 21, 24, 
+       24, 21, 25, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 44, 21, 21, 21, 21, 21, 
+       21, 36, 21, 24, 24, 21, 25, 21, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 36, 21, 22, 
+       21, 24, 24, 21, 25, 26, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       40, 21, 21, 30, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 36, 21, 22, 21, 24, 
+       24, 21, 25, 26, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 40, 21, 
+       21, 30, 21, 21, 21, 21, 21, 21, 
+       21, 21, 41, 21, 21, 21, 21, 21, 
+       21, 36, 21, 22, 21, 24, 24, 21, 
+       25, 26, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 40, 21, 21, 30, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       41, 21, 21, 21, 21, 21, 21, 36, 
+       21, 41, 21, 24, 24, 21, 25, 21, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 30, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 36, 21, 1, 
+       1, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 1, 21, 22, 
+       21, 24, 24, 21, 25, 26, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       27, 28, 21, 30, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 36, 21, 22, 21, 24, 
+       24, 21, 25, 26, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 28, 
+       21, 30, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 36, 21, 22, 21, 24, 24, 21, 
+       25, 26, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 27, 28, 29, 30, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 36, 
+       45, 21, 22, 21, 24, 24, 21, 25, 
+       26, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 27, 28, 29, 30, 21, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 36, 21, 
+       22, 21, 24, 24, 21, 25, 26, 21, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 27, 28, 29, 30, 21, 21, 21, 
+       21, 21, 21, 21, 21, 31, 21, 21, 
+       32, 33, 34, 35, 36, 21, 38, 21, 
+       22, 21, 24, 24, 21, 25, 26, 21, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 27, 28, 29, 30, 21, 21, 21, 
+       21, 21, 21, 21, 21, 45, 21, 21, 
+       21, 21, 21, 21, 36, 21, 38, 21, 
+       22, 21, 24, 24, 21, 25, 26, 21, 
+       21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 27, 28, 29, 30, 21, 21, 21, 
+       21, 21, 21, 21, 21, 45, 21, 21, 
+       21, 21, 21, 21, 36, 21, 22, 21, 
+       24, 24, 21, 25, 26, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 27, 
+       28, 29, 30, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 32, 21, 
+       34, 21, 36, 21, 38, 21, 22, 21, 
+       24, 24, 21, 25, 26, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 27, 
+       28, 29, 30, 21, 21, 21, 21, 21, 
+       21, 21, 21, 45, 21, 21, 32, 21, 
+       21, 21, 36, 21, 38, 21, 22, 21, 
+       24, 24, 21, 25, 26, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 27, 
+       28, 29, 30, 21, 21, 21, 21, 21, 
+       21, 21, 21, 46, 21, 21, 32, 33, 
+       34, 21, 36, 21, 38, 21, 22, 21, 
+       24, 24, 21, 25, 26, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 27, 
+       28, 29, 30, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 32, 33, 
+       34, 21, 36, 21, 38, 21, 22, 23, 
+       24, 24, 21, 25, 26, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 27, 
+       28, 29, 30, 21, 21, 21, 21, 21, 
+       21, 21, 21, 31, 21, 21, 32, 33, 
+       34, 35, 36, 21, 38, 21, 48, 48, 
+       47, 5, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       12, 47, 47, 47, 47, 47, 47, 47, 
+       47, 49, 47, 47, 47, 47, 47, 47, 
+       18, 47, 48, 48, 47, 5, 47, 2, 
+       47, 48, 48, 47, 5, 6, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       50, 47, 47, 12, 47, 47, 47, 47, 
+       47, 47, 47, 47, 51, 47, 47, 52, 
+       47, 47, 47, 18, 47, 51, 47, 2, 
+       47, 48, 48, 47, 5, 6, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 12, 47, 47, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 18, 47, 53, 47, 48, 
+       48, 47, 5, 18, 47, 47, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 54, 47, 47, 47, 47, 47, 
+       47, 18, 47, 48, 48, 47, 5, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 47, 47, 47, 54, 47, 
+       47, 47, 47, 47, 47, 18, 47, 48, 
+       48, 47, 5, 47, 47, 47, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 18, 47, 2, 47, 48, 48, 47, 
+       5, 6, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 47, 50, 47, 47, 12, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 18, 
+       47, 2, 47, 48, 48, 47, 5, 6, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 50, 47, 47, 12, 47, 47, 
+       47, 47, 47, 47, 47, 47, 51, 47, 
+       47, 47, 47, 47, 47, 18, 47, 2, 
+       47, 48, 48, 47, 5, 6, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       50, 47, 47, 12, 47, 47, 47, 47, 
+       47, 47, 47, 47, 51, 47, 47, 47, 
+       47, 47, 47, 18, 47, 51, 47, 48, 
+       48, 47, 5, 47, 47, 47, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 12, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 18, 47, 55, 55, 47, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 55, 47, 2, 3, 48, 48, 47, 
+       5, 6, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 47, 9, 10, 11, 12, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       13, 47, 47, 14, 15, 16, 17, 18, 
+       19, 20, 47, 2, 47, 48, 48, 47, 
+       5, 6, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 47, 9, 10, 47, 12, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 18, 
+       47, 2, 47, 48, 48, 47, 5, 6, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 10, 47, 12, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 47, 47, 18, 47, 2, 
+       47, 48, 48, 47, 5, 6, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       9, 10, 11, 12, 47, 47, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 18, 56, 47, 2, 47, 
+       48, 48, 47, 5, 6, 47, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 9, 
+       10, 11, 12, 47, 47, 47, 47, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 18, 47, 2, 47, 48, 48, 
+       47, 5, 6, 47, 47, 47, 47, 47, 
+       47, 47, 47, 47, 47, 9, 10, 11, 
+       12, 47, 47, 47, 47, 47, 47, 47, 
+       47, 13, 47, 47, 14, 15, 16, 17, 
+       18, 47, 20, 47, 2, 47, 48, 48, 
+       47, 5, 6, 47, 47, 47, 47, 47, 
+       47, 47, 47, 47, 47, 9, 10, 11, 
+       12, 47, 47, 47, 47, 47, 47, 47, 
+       47, 56, 47, 47, 47, 47, 47, 47, 
+       18, 47, 20, 47, 2, 47, 48, 48, 
+       47, 5, 6, 47, 47, 47, 47, 47, 
+       47, 47, 47, 47, 47, 9, 10, 11, 
+       12, 47, 47, 47, 47, 47, 47, 47, 
+       47, 56, 47, 47, 47, 47, 47, 47, 
+       18, 47, 2, 47, 48, 48, 47, 5, 
+       6, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 9, 10, 11, 12, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 14, 47, 16, 47, 18, 47, 
+       20, 47, 2, 47, 48, 48, 47, 5, 
+       6, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 9, 10, 11, 12, 47, 
+       47, 47, 47, 47, 47, 47, 47, 56, 
+       47, 47, 14, 47, 47, 47, 18, 47, 
+       20, 47, 2, 47, 48, 48, 47, 5, 
+       6, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 9, 10, 11, 12, 47, 
+       47, 47, 47, 47, 47, 47, 47, 57, 
+       47, 47, 14, 15, 16, 47, 18, 47, 
+       20, 47, 2, 47, 48, 48, 47, 5, 
+       6, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 9, 10, 11, 12, 47, 
+       47, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 14, 15, 16, 47, 18, 47, 
+       20, 47, 2, 3, 48, 48, 47, 5, 
+       6, 47, 47, 47, 47, 47, 47, 47, 
+       47, 47, 47, 9, 10, 11, 12, 47, 
+       47, 47, 47, 47, 47, 47, 47, 13, 
+       47, 47, 14, 15, 16, 17, 18, 47, 
+       20, 47, 22, 23, 24, 24, 21, 25, 
+       26, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 27, 28, 29, 30, 21, 
+       21, 21, 21, 21, 21, 21, 21, 58, 
+       21, 21, 32, 33, 34, 35, 36, 37, 
+       38, 21, 22, 59, 24, 24, 21, 25, 
+       26, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 27, 28, 29, 30, 21, 
+       21, 21, 21, 21, 21, 21, 21, 31, 
+       21, 21, 32, 33, 34, 35, 36, 21, 
+       38, 21, 1, 1, 2, 3, 48, 48, 
+       47, 5, 6, 1, 1, 47, 47, 47, 
+       1, 47, 47, 47, 47, 9, 10, 11, 
+       12, 47, 47, 47, 47, 47, 47, 47, 
+       47, 13, 47, 47, 14, 15, 16, 17, 
+       18, 19, 20, 47, 1, 1, 60, 60, 
+       60, 60, 60, 60, 60, 1, 1, 60, 
+       60, 60, 1, 60, 0
+};
+
+static const char _myanmar_syllable_machine_trans_targs[] = {
+       0, 1, 26, 37, 0, 27, 29, 51, 
+       54, 39, 40, 41, 28, 43, 44, 46, 
+       47, 48, 30, 50, 45, 0, 2, 13, 
+       0, 3, 5, 14, 15, 16, 4, 18, 
+       19, 21, 22, 23, 6, 25, 20, 12, 
+       9, 10, 11, 7, 8, 17, 24, 0, 
+       0, 36, 33, 34, 35, 31, 32, 38, 
+       42, 49, 52, 53, 0
+};
+
+static const char _myanmar_syllable_machine_trans_actions[] = {
+       3, 0, 0, 0, 4, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 5, 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, 7, 
+       8, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 9
+};
+
+static const char _myanmar_syllable_machine_to_state_actions[] = {
+       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, 
+       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 _myanmar_syllable_machine_from_state_actions[] = {
+       2, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 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 _myanmar_syllable_machine_eof_trans[] = {
+       0, 22, 22, 22, 22, 22, 22, 22, 
+       22, 22, 22, 22, 22, 22, 22, 22, 
+       22, 22, 22, 22, 22, 22, 22, 22, 
+       22, 22, 48, 48, 48, 48, 48, 48, 
+       48, 48, 48, 48, 48, 48, 48, 48, 
+       48, 48, 48, 48, 48, 48, 48, 48, 
+       48, 48, 48, 22, 22, 48, 61
+};
+
+static const int myanmar_syllable_machine_start = 0;
+static const int myanmar_syllable_machine_first_final = 0;
+static const int myanmar_syllable_machine_error = -1;
+
+static const int myanmar_syllable_machine_en_main = 0;
+
+
+#line 55 "hb-ot-shaper-myanmar-machine.rl"
+
+
+
+#line 117 "hb-ot-shaper-myanmar-machine.rl"
+
+
+#define found_syllable(syllable_type) \
+  HB_STMT_START { \
+    if (0) fprintf (stderr, "syllable %u..%u %s\n", ts, te, #syllable_type); \
+    for (unsigned int i = ts; i < te; i++) \
+      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+    syllable_serial++; \
+    if (syllable_serial == 16) syllable_serial = 1; \
+  } HB_STMT_END
+
+inline void
+find_syllables_myanmar (hb_buffer_t *buffer)
+{
+  unsigned int p, pe, eof, ts, te, act HB_UNUSED;
+  int cs;
+  hb_glyph_info_t *info = buffer->info;
+  
+#line 447 "hb-ot-shaper-myanmar-machine.hh"
+       {
+       cs = myanmar_syllable_machine_start;
+       ts = 0;
+       te = 0;
+       act = 0;
+       }
+
+#line 137 "hb-ot-shaper-myanmar-machine.rl"
+
+
+  p = 0;
+  pe = eof = buffer->len;
+
+  unsigned int syllable_serial = 1;
+  
+#line 463 "hb-ot-shaper-myanmar-machine.hh"
+       {
+       int _slen;
+       int _trans;
+       const unsigned char *_keys;
+       const char *_inds;
+       if ( p == pe )
+               goto _test_eof;
+_resume:
+       switch ( _myanmar_syllable_machine_from_state_actions[cs] ) {
+       case 2:
+#line 1 "NONE"
+       {ts = p;}
+       break;
+#line 477 "hb-ot-shaper-myanmar-machine.hh"
+       }
+
+       _keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
+       _inds = _myanmar_syllable_machine_indicies + _myanmar_syllable_machine_index_offsets[cs];
+
+       _slen = _myanmar_syllable_machine_key_spans[cs];
+       _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].myanmar_category()) &&
+               ( info[p].myanmar_category()) <= _keys[1] ?
+               ( info[p].myanmar_category()) - _keys[0] : _slen ];
+
+_eof_trans:
+       cs = _myanmar_syllable_machine_trans_targs[_trans];
+
+       if ( _myanmar_syllable_machine_trans_actions[_trans] == 0 )
+               goto _again;
+
+       switch ( _myanmar_syllable_machine_trans_actions[_trans] ) {
+       case 6:
+#line 110 "hb-ot-shaper-myanmar-machine.rl"
+       {te = p+1;{ found_syllable (myanmar_consonant_syllable); }}
+       break;
+       case 4:
+#line 111 "hb-ot-shaper-myanmar-machine.rl"
+       {te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }}
+       break;
+       case 8:
+#line 112 "hb-ot-shaper-myanmar-machine.rl"
+       {te = p+1;{ found_syllable (myanmar_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
+       break;
+       case 3:
+#line 113 "hb-ot-shaper-myanmar-machine.rl"
+       {te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }}
+       break;
+       case 5:
+#line 110 "hb-ot-shaper-myanmar-machine.rl"
+       {te = p;p--;{ found_syllable (myanmar_consonant_syllable); }}
+       break;
+       case 7:
+#line 112 "hb-ot-shaper-myanmar-machine.rl"
+       {te = p;p--;{ found_syllable (myanmar_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
+       break;
+       case 9:
+#line 113 "hb-ot-shaper-myanmar-machine.rl"
+       {te = p;p--;{ found_syllable (myanmar_non_myanmar_cluster); }}
+       break;
+#line 523 "hb-ot-shaper-myanmar-machine.hh"
+       }
+
+_again:
+       switch ( _myanmar_syllable_machine_to_state_actions[cs] ) {
+       case 1:
+#line 1 "NONE"
+       {ts = 0;}
+       break;
+#line 532 "hb-ot-shaper-myanmar-machine.hh"
+       }
+
+       if ( ++p != pe )
+               goto _resume;
+       _test_eof: {}
+       if ( p == eof )
+       {
+       if ( _myanmar_syllable_machine_eof_trans[cs] > 0 ) {
+               _trans = _myanmar_syllable_machine_eof_trans[cs] - 1;
+               goto _eof_trans;
+       }
+       }
+
+       }
+
+#line 145 "hb-ot-shaper-myanmar-machine.rl"
+
+}
+
+#undef found_syllable
+
+#endif /* HB_OT_SHAPER_MYANMAR_MACHINE_HH */
similarity index 62%
rename from src/hb-ot-shape-complex-myanmar-machine.rl
rename to src/hb-ot-shaper-myanmar-machine.rl
index 2e6ac78..e8d1e78 100644 (file)
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH
+#ifndef HB_OT_SHAPER_MYANMAR_MACHINE_HH
+#define HB_OT_SHAPER_MYANMAR_MACHINE_HH
 
 #include "hb.hh"
 
+#include "hb-ot-layout.hh"
+#include "hb-ot-shaper-indic.hh"
+
+/* buffer var allocations */
+#define myanmar_category() ot_shaper_var_u8_category() /* myanmar_category_t */
+#define myanmar_position() ot_shaper_var_u8_auxiliary() /* myanmar_position_t */
+
+using myanmar_category_t = unsigned;
+using myanmar_position_t = ot_position_t;
+
+#define M_Cat(Cat) myanmar_syllable_machine_ex_##Cat
+
 enum myanmar_syllable_type_t {
   myanmar_consonant_syllable,
-  myanmar_punctuation_cluster,
   myanmar_broken_cluster,
   myanmar_non_myanmar_cluster,
 };
@@ -45,32 +56,38 @@ enum myanmar_syllable_type_t {
 
 %%{
 
-export A    = 10;
-export As   = 18;
+
+# Spec category D is folded into GB; D0 is not implemented by Uniscribe and as such folded into D
+# Spec category P is folded into GB
+
 export C    = 1;
-export D    = 32;
-export D0   = 20;
-export DB   = 3;
-export GB   = 11;
-export H    = 4;
 export IV   = 2;
-export MH   = 21;
-export ML   = 33;
-export MR   = 22;
-export MW   = 23;
-export MY   = 24;
-export PT   = 25;
-export V    = 8;
-export VAbv = 26;
-export VBlw = 27;
-export VPre = 28;
-export VPst = 29;
-export VS   = 30;
-export ZWJ  = 6;
+export DB   = 3;       # Dot below          = OT_N
+export H    = 4;
 export ZWNJ = 5;
-export Ra   = 16;
-export P    = 31;
-export CS   = 19;
+export ZWJ  = 6;
+export SM    = 8;      # Visarga and Shan tones
+export GB   = 10;      #                    = OT_PLACEHOLDER
+export DOTTEDCIRCLE = 11;
+export A    = 9;
+export Ra   = 15;
+export CS   = 18;
+
+export VAbv = 20;
+export VBlw = 21;
+export VPre = 22;
+export VPst = 23;
+
+# 32+ are for Myanmar-specific values
+export As   = 32;      # Asat
+export MH   = 35;      # Medial Ha
+export MR   = 36;      # Medial Ra
+export MW   = 37;      # Medial Wa, Shan Wa
+export MY   = 38;      # Medial Ya, Mon Na, Mon Ma
+export PT   = 39;      # Pwo and other tones
+export VS   = 40;      # Variation selectors
+export ML   = 41;      # Medial Mon La
+
 
 j = ZWJ|ZWNJ;                  # Joiners
 k = (Ra As H);                 # Kinzi
@@ -82,19 +99,17 @@ main_vowel_group = (VPre.VS?)* VAbv* VBlw* A* (DB As?)?;
 post_vowel_group = VPst MH? ML? As* VAbv* A* (DB As?)?;
 pwo_tone_group = PT A* DB? As?;
 
-complex_syllable_tail = As* medial_group main_vowel_group post_vowel_group* pwo_tone_group* V* j?;
+complex_syllable_tail = As* medial_group main_vowel_group post_vowel_group* pwo_tone_group* SM* j?;
 syllable_tail = (H (c|IV).VS?)* (H | complex_syllable_tail);
 
-consonant_syllable =   (k|CS)? (c|IV|D|GB).VS? syllable_tail;
-punctuation_cluster =  P V;
+consonant_syllable =   (k|CS)? (c|IV|GB|DOTTEDCIRCLE).VS? syllable_tail;
 broken_cluster =       k? VS? syllable_tail;
 other =                        any;
 
 main := |*
        consonant_syllable      => { found_syllable (myanmar_consonant_syllable); };
        j                       => { found_syllable (myanmar_non_myanmar_cluster); };
-       punctuation_cluster     => { found_syllable (myanmar_punctuation_cluster); };
-       broken_cluster          => { found_syllable (myanmar_broken_cluster); };
+       broken_cluster          => { found_syllable (myanmar_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; };
        other                   => { found_syllable (myanmar_non_myanmar_cluster); };
 *|;
 
@@ -103,14 +118,14 @@ main := |*
 
 #define found_syllable(syllable_type) \
   HB_STMT_START { \
-    if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
+    if (0) fprintf (stderr, "syllable %u..%u %s\n", ts, te, #syllable_type); \
     for (unsigned int i = ts; i < te; i++) \
       info[i].syllable() = (syllable_serial << 4) | syllable_type; \
     syllable_serial++; \
-    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+    if (syllable_serial == 16) syllable_serial = 1; \
   } HB_STMT_END
 
-static void
+inline void
 find_syllables_myanmar (hb_buffer_t *buffer)
 {
   unsigned int p, pe, eof, ts, te, act HB_UNUSED;
@@ -132,4 +147,4 @@ find_syllables_myanmar (hb_buffer_t *buffer)
 
 #undef found_syllable
 
-#endif /* HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH */
+#endif /* HB_OT_SHAPER_MYANMAR_MACHINE_HH */
similarity index 68%
rename from src/hb-ot-shape-complex-myanmar.cc
rename to src/hb-ot-shaper-myanmar.cc
index e6ae75e..1b2a085 100644 (file)
 
 #ifndef HB_NO_OT_SHAPE
 
-#include "hb-ot-shape-complex-myanmar.hh"
-#include "hb-ot-shape-complex-myanmar-machine.hh"
+#include "hb-ot-shaper-myanmar-machine.hh"
+#include "hb-ot-shaper-indic.hh"
+#include "hb-ot-layout.hh"
 
 
 /*
  * Myanmar shaper.
  */
 
+
 static const hb_tag_t
 myanmar_basic_features[] =
 {
@@ -62,11 +64,45 @@ myanmar_other_features[] =
   HB_TAG('p','s','t','s'),
 };
 
-static void
+static inline void
+set_myanmar_properties (hb_glyph_info_t &info)
+{
+  hb_codepoint_t u = info.codepoint;
+  unsigned int type = hb_indic_get_categories (u);
+
+  info.myanmar_category() = (myanmar_category_t) (type & 0xFFu);
+}
+
+
+static inline bool
+is_one_of_myanmar (const hb_glyph_info_t &info, unsigned int flags)
+{
+  /* If it ligated, all bets are off. */
+  if (_hb_glyph_info_ligated (&info)) return false;
+  return !!(FLAG_UNSAFE (info.myanmar_category()) & flags);
+}
+
+/* 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!
+ *
+ * Keep in sync with consonant_categories in the generator. */
+#define CONSONANT_FLAGS_MYANMAR (FLAG (M_Cat(C)) | FLAG (M_Cat(CS)) | FLAG (M_Cat(Ra)) | /* FLAG (M_Cat(CM)) | */ FLAG (M_Cat(IV)) | FLAG (M_Cat(GB)) | FLAG (M_Cat(DOTTEDCIRCLE)))
+
+static inline bool
+is_consonant_myanmar (const hb_glyph_info_t &info)
+{
+  return is_one_of_myanmar (info, CONSONANT_FLAGS_MYANMAR);
+}
+
+
+static bool
 setup_syllables_myanmar (const hb_ot_shape_plan_t *plan,
                         hb_font_t *font,
                         hb_buffer_t *buffer);
-static void
+static bool
 reorder_myanmar (const hb_ot_shape_plan_t *plan,
                 hb_font_t *font,
                 hb_buffer_t *buffer);
@@ -79,21 +115,20 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan)
   /* Do this before any lookups have been applied. */
   map->add_gsub_pause (setup_syllables_myanmar);
 
-  map->enable_feature (HB_TAG('l','o','c','l'));
+  map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
   /* 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->enable_feature (HB_TAG('c','c','m','p'));
+  map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
 
 
   map->add_gsub_pause (reorder_myanmar);
 
   for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_basic_features); i++)
   {
-    map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ);
+    map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ | F_PER_SYLLABLE);
     map->add_gsub_pause (nullptr);
   }
-
-  map->add_gsub_pause (_hb_clear_syllables);
+  map->add_gsub_pause (hb_syllabic_clear_var); // Don't need syllables anymore, use stop to free buffer var
 
   for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_other_features); i++)
     map->enable_feature (myanmar_other_features[i], F_MANUAL_ZWJ);
@@ -107,8 +142,7 @@ setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
   HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_category);
   HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_position);
 
-  /* We cannot setup masks here.  We save information about characters
-   * and setup masks later on in a pause-callback. */
+  /* No masks, we just save information about characters. */
 
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
@@ -116,14 +150,16 @@ setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
     set_myanmar_properties (info[i]);
 }
 
-static void
+static bool
 setup_syllables_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
                         hb_font_t *font HB_UNUSED,
                         hb_buffer_t *buffer)
 {
+  HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
   find_syllables_myanmar (buffer);
   foreach_syllable (buffer, start, end)
     buffer->unsafe_to_break (start, end);
+  return false;
 }
 
 static int
@@ -132,7 +168,7 @@ compare_myanmar_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
   int a = pa->myanmar_position();
   int b = pb->myanmar_position();
 
-  return a < b ? -1 : a == b ? 0 : +1;
+  return (int) a - (int) b;
 }
 
 
@@ -151,9 +187,9 @@ initial_reordering_consonant_syllable (hb_buffer_t *buffer,
   {
     unsigned int limit = start;
     if (start + 3 <= end &&
-       info[start  ].myanmar_category() == OT_Ra &&
-       info[start+1].myanmar_category() == OT_As &&
-       info[start+2].myanmar_category() == OT_H)
+       info[start  ].myanmar_category() == M_Cat(Ra) &&
+       info[start+1].myanmar_category() == M_Cat(As) &&
+       info[start+2].myanmar_category() == M_Cat(H))
     {
       limit += 3;
       base = start;
@@ -165,7 +201,7 @@ initial_reordering_consonant_syllable (hb_buffer_t *buffer,
        base = limit;
 
       for (unsigned int i = limit; i < end; i++)
-       if (is_consonant (info[i]))
+       if (is_consonant_myanmar (info[i]))
        {
          base = i;
          break;
@@ -190,39 +226,40 @@ initial_reordering_consonant_syllable (hb_buffer_t *buffer,
      * Myanmar reordering! */
     for (; i < end; i++)
     {
-      if (info[i].myanmar_category() == OT_MR) /* Pre-base reordering */
+      if (info[i].myanmar_category() == M_Cat(MR)) /* Pre-base reordering */
       {
        info[i].myanmar_position() = POS_PRE_C;
        continue;
       }
-      if (info[i].myanmar_position() < POS_BASE_C) /* Left matra */
+      if (info[i].myanmar_category() == M_Cat(VPre)) /* Left matra */
       {
+       info[i].myanmar_position() = POS_PRE_M;
        continue;
       }
-      if (info[i].myanmar_category() == OT_VS)
+      if (info[i].myanmar_category() == M_Cat(VS))
       {
        info[i].myanmar_position() = info[i - 1].myanmar_position();
        continue;
       }
 
-      if (pos == POS_AFTER_MAIN && info[i].myanmar_category() == OT_VBlw)
+      if (pos == POS_AFTER_MAIN && info[i].myanmar_category() == M_Cat(VBlw))
       {
        pos = POS_BELOW_C;
        info[i].myanmar_position() = pos;
        continue;
       }
 
-      if (pos == POS_BELOW_C && info[i].myanmar_category() == OT_A)
+      if (pos == POS_BELOW_C && info[i].myanmar_category() == M_Cat(A))
       {
        info[i].myanmar_position() = POS_BEFORE_SUB;
        continue;
       }
-      if (pos == POS_BELOW_C && info[i].myanmar_category() == OT_VBlw)
+      if (pos == POS_BELOW_C && info[i].myanmar_category() == M_Cat(VBlw))
       {
        info[i].myanmar_position() = pos;
        continue;
       }
-      if (pos == POS_BELOW_C && info[i].myanmar_category() != OT_A)
+      if (pos == POS_BELOW_C && info[i].myanmar_category() != M_Cat(A))
       {
        pos = POS_AFTER_SUB;
        info[i].myanmar_position() = pos;
@@ -234,6 +271,33 @@ initial_reordering_consonant_syllable (hb_buffer_t *buffer,
 
   /* Sit tight, rock 'n roll! */
   buffer->sort (start, end, compare_myanmar_order);
+
+  /* Flip left-matra sequence. */
+  unsigned first_left_matra = end;
+  unsigned last_left_matra = end;
+  for (unsigned int i = start; i < end; i++)
+  {
+    if (info[i].myanmar_position() == POS_PRE_M)
+    {
+      if (first_left_matra == end)
+       first_left_matra = i;
+      last_left_matra = i;
+    }
+  }
+  /* https://github.com/harfbuzz/harfbuzz/issues/3863 */
+  if (first_left_matra < last_left_matra)
+  {
+    /* No need to merge clusters, done already? */
+    buffer->reverse_range (first_left_matra, last_left_matra + 1);
+    /* Reverse back VS, etc. */
+    unsigned i = first_left_matra;
+    for (unsigned j = i; j <= last_left_matra; j++)
+      if (info[j].myanmar_category() == M_Cat(VPre))
+      {
+       buffer->reverse_range (i, j + 1);
+       i = j + 1;
+      }
+  }
 }
 
 static void
@@ -250,22 +314,23 @@ reorder_syllable_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
       initial_reordering_consonant_syllable  (buffer, start, end);
       break;
 
-    case myanmar_punctuation_cluster:
     case myanmar_non_myanmar_cluster:
       break;
   }
 }
 
-static void
+static bool
 reorder_myanmar (const hb_ot_shape_plan_t *plan,
                 hb_font_t *font,
                 hb_buffer_t *buffer)
 {
+  bool ret = false;
   if (buffer->message (font, "start reordering myanmar"))
   {
-    hb_syllabic_insert_dotted_circles (font, buffer,
-                                      myanmar_broken_cluster,
-                                      OT_GB);
+    if (hb_syllabic_insert_dotted_circles (font, buffer,
+                                          myanmar_broken_cluster,
+                                          M_Cat(DOTTEDCIRCLE)))
+      ret = true;
 
     foreach_syllable (buffer, start, end)
       reorder_syllable_myanmar (plan, font->face, buffer, start, end);
@@ -274,10 +339,12 @@ reorder_myanmar (const hb_ot_shape_plan_t *plan,
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_category);
   HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_position);
+
+  return ret;
 }
 
 
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
+const hb_ot_shaper_t _hb_ot_shaper_myanmar =
 {
   collect_features_myanmar,
   nullptr, /* override_features */
@@ -285,21 +352,22 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
   nullptr, /* data_destroy */
   nullptr, /* preprocess_text */
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   nullptr, /* decompose */
   nullptr, /* compose */
   setup_masks_myanmar,
-  HB_TAG_NONE, /* gpos_tag */
   nullptr, /* reorder_marks */
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
   false, /* fallback_position */
 };
 
 
+#ifndef HB_NO_OT_SHAPER_MYANMAR_ZAWGYI
 /* 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 =
+const hb_ot_shaper_t _hb_ot_shaper_myanmar_zawgyi =
 {
   nullptr, /* collect_features */
   nullptr, /* override_features */
@@ -307,15 +375,16 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_zawgyi =
   nullptr, /* data_destroy */
   nullptr, /* preprocess_text */
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
   nullptr, /* decompose */
   nullptr, /* compose */
   nullptr, /* setup_masks */
-  HB_TAG_NONE, /* gpos_tag */
   nullptr, /* reorder_marks */
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
+#endif
 
 
 #endif
similarity index 72%
rename from src/hb-ot-shape-complex-syllabic.cc
rename to src/hb-ot-shaper-syllabic.cc
index 76092c7..97f6203 100644 (file)
 
 #ifndef HB_NO_OT_SHAPE
 
-#include "hb-ot-shape-complex-syllabic.hh"
+#include "hb-ot-shaper-syllabic.hh"
 
 
-void
+bool
 hb_syllabic_insert_dotted_circles (hb_font_t *font,
                                   hb_buffer_t *buffer,
                                   unsigned int broken_syllable_type,
@@ -38,32 +38,27 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
                                   int dottedcircle_position)
 {
   if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
-    return;
-
-  /* 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;
-  for (unsigned int i = 0; i < count; i++)
-    if ((info[i].syllable() & 0x0F) == broken_syllable_type)
-    {
-      has_broken_syllables = true;
-      break;
-    }
-  if (likely (!has_broken_syllables))
-    return;
+    return false;
+  if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE)))
+  {
+    if (buffer->messaging ())
+      (void) buffer->message (font, "skipped inserting dotted-circles because there is no broken syllables");
+    return false;
+  }
 
+  if (buffer->messaging () &&
+      !buffer->message (font, "start inserting dotted-circles"))
+    return false;
 
   hb_codepoint_t dottedcircle_glyph;
   if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
-    return;
+    return false;
 
   hb_glyph_info_t dottedcircle = {0};
   dottedcircle.codepoint = 0x25CCu;
-  dottedcircle.complex_var_u8_category() = dottedcircle_category;
+  dottedcircle.ot_shaper_var_u8_category() = dottedcircle_category;
   if (dottedcircle_position != -1)
-    dottedcircle.complex_var_u8_auxiliary() = dottedcircle_position;
+    dottedcircle.ot_shaper_var_u8_auxiliary() = dottedcircle_position;
   dottedcircle.codepoint = dottedcircle_glyph;
 
   buffer->clear_output ();
@@ -87,7 +82,7 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
       {
        while (buffer->idx < buffer->len && buffer->successful &&
               last_syllable == buffer->cur().syllable() &&
-              buffer->cur().complex_var_u8_category() == (unsigned) repha_category)
+              buffer->cur().ot_shaper_var_u8_category() == (unsigned) repha_category)
          (void) buffer->next_glyph ();
       }
 
@@ -97,6 +92,20 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
       (void) buffer->next_glyph ();
   }
   buffer->sync ();
+
+  if (buffer->messaging ())
+    (void) buffer->message (font, "end inserting dotted-circles");
+
+  return true;
+}
+
+HB_INTERNAL bool
+hb_syllabic_clear_var (const hb_ot_shape_plan_t *plan,
+                      hb_font_t *font,
+                      hb_buffer_t *buffer)
+{
+  HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
+  return false;
 }
 
 
similarity index 82%
rename from src/hb-ot-shape-complex-syllabic.hh
rename to src/hb-ot-shaper-syllabic.hh
index b901a66..f240ad1 100644 (file)
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  */
 
-#ifndef HB_OT_SHAPE_COMPLEX_SYLLABIC_HH
-#define HB_OT_SHAPE_COMPLEX_SYLLABIC_HH
+#ifndef HB_OT_SHAPER_SYLLABIC_HH
+#define HB_OT_SHAPER_SYLLABIC_HH
 
 #include "hb.hh"
 
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shaper.hh"
 
 
-HB_INTERNAL void
+HB_INTERNAL bool
 hb_syllabic_insert_dotted_circles (hb_font_t *font,
                                   hb_buffer_t *buffer,
                                   unsigned int broken_syllable_type,
@@ -38,5 +38,10 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
                                   int repha_category = -1,
                                   int dottedcircle_position = -1);
 
+HB_INTERNAL bool
+hb_syllabic_clear_var (const hb_ot_shape_plan_t *plan,
+                      hb_font_t *font,
+                      hb_buffer_t *buffer);
 
-#endif /* HB_OT_SHAPE_COMPLEX_SYLLABIC_HH */
+
+#endif /* HB_OT_SHAPER_SYLLABIC_HH */
similarity index 95%
rename from src/hb-ot-shape-complex-thai.cc
rename to src/hb-ot-shaper-thai.cc
index a1e27a8..6cd67cd 100644 (file)
@@ -28,7 +28,7 @@
 
 #ifndef HB_NO_OT_SHAPE
 
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shaper.hh"
 
 
 /* Thai / Lao shaper */
@@ -98,9 +98,9 @@ static hb_codepoint_t
 thai_pua_shape (hb_codepoint_t u, thai_action_t action, hb_font_t *font)
 {
   struct thai_pua_mapping_t {
-    hb_codepoint_t u;
-    hb_codepoint_t win_pua;
-    hb_codepoint_t mac_pua;
+    uint16_t u;
+    uint16_t win_pua;
+    uint16_t mac_pua;
   } const *pua_mappings = nullptr;
   static const thai_pua_mapping_t SD_mappings[] = {
     {0x0E48u, 0xF70Au, 0xF88Bu}, /* MAI EK */
@@ -222,7 +222,7 @@ do_thai_pua_shaping (const hb_ot_shape_plan_t *plan HB_UNUSED,
                     hb_buffer_t              *buffer,
                     hb_font_t                *font)
 {
-#ifdef HB_NO_OT_SHAPE_COMPLEX_THAI_FALLBACK
+#ifdef HB_NO_OT_SHAPER_THAI_FALLBACK
   return;
 #endif
 
@@ -279,7 +279,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
    * to be what Uniscribe and other engines implement.  According to Eric Muller:
    *
    * When you have a SARA AM, decompose it in NIKHAHIT + SARA AA, *and* move the
-   * NIKHAHIT backwards over any tone mark (0E48-0E4B).
+   * NIKHAHIT backwards over any above-base marks.
    *
    * <0E14, 0E4B, 0E33> -> <0E14, 0E4D, 0E4B, 0E32>
    *
@@ -308,8 +308,8 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
    * Nikhahit:         U+0E4D  U+0ECD
    *
    * Testing shows that Uniscribe reorder the following marks:
-   * Thai:     <0E31,0E34..0E37,0E47..0E4E>
-   * Lao:      <0EB1,0EB4..0EB7,0EC7..0ECE>
+   * Thai:     <0E31,0E34..0E37,     0E47..0E4E>
+   * Lao:      <0EB1,0EB4..0EB7,0EBB,0EC8..0ECD>
    *
    * Note how the Lao versions are the same as Thai + 0x80.
    */
@@ -319,7 +319,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
 #define IS_SARA_AM(x) (((x) & ~0x0080u) == 0x0E33u)
 #define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0x0E33u + 0x0E4Du)
 #define SARA_AA_FROM_SARA_AM(x) ((x) - 1)
-#define IS_TONE_MARK(x) (hb_in_ranges<hb_codepoint_t> ((x) & ~0x0080u, 0x0E34u, 0x0E37u, 0x0E47u, 0x0E4Eu, 0x0E31u, 0x0E31u))
+#define IS_ABOVE_BASE_MARK(x) (hb_in_ranges<hb_codepoint_t> ((x) & ~0x0080u, 0x0E34u, 0x0E37u, 0x0E47u, 0x0E4Eu, 0x0E31u, 0x0E31u, 0x0E3Bu, 0x0E3Bu))
 
   buffer->clear_output ();
   unsigned int count = buffer->len;
@@ -343,7 +343,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
 
     /* Ok, let's see... */
     unsigned int start = end - 2;
-    while (start > 0 && IS_TONE_MARK (buffer->out_info[start - 1].codepoint))
+    while (start > 0 && IS_ABOVE_BASE_MARK (buffer->out_info[start - 1].codepoint))
       start--;
 
     if (start + 2 < end)
@@ -371,7 +371,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
     do_thai_pua_shaping (plan, buffer, font);
 }
 
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai =
+const hb_ot_shaper_t _hb_ot_shaper_thai =
 {
   nullptr, /* collect_features */
   nullptr, /* override_features */
@@ -379,12 +379,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai =
   nullptr, /* data_destroy */
   preprocess_text_thai,
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   nullptr, /* decompose */
   nullptr, /* compose */
   nullptr, /* setup_masks */
-  HB_TAG_NONE, /* gpos_tag */
   nullptr, /* reorder_marks */
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   false,/* fallback_position */
 };
diff --git a/src/hb-ot-shaper-use-machine.hh b/src/hb-ot-shaper-use-machine.hh
new file mode 100644 (file)
index 0000000..be0a253
--- /dev/null
@@ -0,0 +1,1079 @@
+
+#line 1 "hb-ot-shaper-use-machine.rl"
+/*
+ * Copyright © 2015  Mozilla Foundation.
+ * Copyright © 2015  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.
+ *
+ * Mozilla Author(s): Jonathan Kew
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPER_USE_MACHINE_HH
+#define HB_OT_SHAPER_USE_MACHINE_HH
+
+#include "hb.hh"
+
+#include "hb-ot-shaper-syllabic.hh"
+
+/* buffer var allocations */
+#define use_category() ot_shaper_var_u8_category()
+
+#define USE(Cat) use_syllable_machine_ex_##Cat
+
+enum use_syllable_type_t {
+  use_virama_terminated_cluster,
+  use_sakot_terminated_cluster,
+  use_standard_cluster,
+  use_number_joiner_terminated_cluster,
+  use_numeral_cluster,
+  use_symbol_cluster,
+  use_hieroglyph_cluster,
+  use_broken_cluster,
+  use_non_cluster,
+};
+
+
+#line 57 "hb-ot-shaper-use-machine.hh"
+#define use_syllable_machine_ex_B 1u
+#define use_syllable_machine_ex_CGJ 6u
+#define use_syllable_machine_ex_CMAbv 31u
+#define use_syllable_machine_ex_CMBlw 32u
+#define use_syllable_machine_ex_CS 43u
+#define use_syllable_machine_ex_FAbv 24u
+#define use_syllable_machine_ex_FBlw 25u
+#define use_syllable_machine_ex_FMAbv 45u
+#define use_syllable_machine_ex_FMBlw 46u
+#define use_syllable_machine_ex_FMPst 47u
+#define use_syllable_machine_ex_FPst 26u
+#define use_syllable_machine_ex_G 49u
+#define use_syllable_machine_ex_GB 5u
+#define use_syllable_machine_ex_H 12u
+#define use_syllable_machine_ex_HM 54u
+#define use_syllable_machine_ex_HN 13u
+#define use_syllable_machine_ex_HR 55u
+#define use_syllable_machine_ex_HVM 53u
+#define use_syllable_machine_ex_IS 44u
+#define use_syllable_machine_ex_J 50u
+#define use_syllable_machine_ex_MAbv 27u
+#define use_syllable_machine_ex_MBlw 28u
+#define use_syllable_machine_ex_MPre 30u
+#define use_syllable_machine_ex_MPst 29u
+#define use_syllable_machine_ex_N 4u
+#define use_syllable_machine_ex_O 0u
+#define use_syllable_machine_ex_R 18u
+#define use_syllable_machine_ex_SB 51u
+#define use_syllable_machine_ex_SE 52u
+#define use_syllable_machine_ex_SMAbv 41u
+#define use_syllable_machine_ex_SMBlw 42u
+#define use_syllable_machine_ex_SUB 11u
+#define use_syllable_machine_ex_Sk 48u
+#define use_syllable_machine_ex_VAbv 33u
+#define use_syllable_machine_ex_VBlw 34u
+#define use_syllable_machine_ex_VMAbv 37u
+#define use_syllable_machine_ex_VMBlw 38u
+#define use_syllable_machine_ex_VMPre 23u
+#define use_syllable_machine_ex_VMPst 39u
+#define use_syllable_machine_ex_VPre 22u
+#define use_syllable_machine_ex_VPst 35u
+#define use_syllable_machine_ex_WJ 16u
+#define use_syllable_machine_ex_ZWNJ 14u
+
+
+#line 103 "hb-ot-shaper-use-machine.hh"
+static const unsigned char _use_syllable_machine_trans_keys[] = {
+       49u, 51u, 0u, 53u, 11u, 53u, 11u, 53u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 
+       14u, 47u, 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 
+       14u, 48u, 14u, 53u, 14u, 53u, 14u, 53u, 14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u, 
+       12u, 53u, 12u, 53u, 11u, 53u, 1u, 14u, 1u, 48u, 14u, 42u, 14u, 42u, 11u, 53u, 
+       1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, 14u, 46u, 14u, 46u, 14u, 14u, 
+       14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u, 14u, 53u, 14u, 53u, 14u, 53u, 
+       14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, 1u, 14u, 
+       1u, 14u, 1u, 48u, 13u, 14u, 4u, 14u, 11u, 53u, 11u, 53u, 1u, 53u, 14u, 48u, 
+       14u, 47u, 14u, 47u, 14u, 47u, 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 
+       14u, 48u, 1u, 14u, 14u, 48u, 14u, 53u, 14u, 53u, 14u, 53u, 14u, 53u, 12u, 53u, 
+       14u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, 1u, 14u, 1u, 14u, 1u, 48u, 
+       11u, 53u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, 14u, 46u, 14u, 46u, 
+       14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u, 14u, 53u, 14u, 53u, 
+       14u, 53u, 14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, 
+       1u, 14u, 1u, 48u, 4u, 14u, 13u, 14u, 1u, 53u, 14u, 42u, 14u, 42u, 1u, 5u, 
+       14u, 55u, 14u, 51u, 14u, 52u, 14u, 54u, 11u, 53u, 0
+};
+
+static const char _use_syllable_machine_key_spans[] = {
+       3, 54, 43, 43, 53, 35, 34, 34, 
+       34, 33, 33, 1, 35, 35, 35, 14, 
+       35, 40, 40, 40, 40, 42, 40, 42, 
+       42, 42, 43, 14, 48, 29, 29, 43, 
+       53, 35, 34, 34, 34, 33, 33, 1, 
+       35, 35, 35, 14, 35, 40, 40, 40, 
+       40, 42, 40, 42, 42, 42, 43, 14, 
+       14, 48, 2, 11, 43, 43, 53, 35, 
+       34, 34, 34, 33, 33, 1, 35, 35, 
+       35, 14, 35, 40, 40, 40, 40, 42, 
+       40, 42, 42, 42, 43, 14, 14, 48, 
+       43, 53, 35, 34, 34, 34, 33, 33, 
+       1, 35, 35, 35, 14, 35, 40, 40, 
+       40, 40, 42, 40, 42, 42, 42, 43, 
+       14, 48, 11, 2, 53, 29, 29, 5, 
+       42, 38, 39, 41, 43
+};
+
+static const short _use_syllable_machine_index_offsets[] = {
+       0, 4, 59, 103, 147, 201, 237, 272, 
+       307, 342, 376, 410, 412, 448, 484, 520, 
+       535, 571, 612, 653, 694, 735, 778, 819, 
+       862, 905, 948, 992, 1007, 1056, 1086, 1116, 
+       1160, 1214, 1250, 1285, 1320, 1355, 1389, 1423, 
+       1425, 1461, 1497, 1533, 1548, 1584, 1625, 1666, 
+       1707, 1748, 1791, 1832, 1875, 1918, 1961, 2005, 
+       2020, 2035, 2084, 2087, 2099, 2143, 2187, 2241, 
+       2277, 2312, 2347, 2382, 2416, 2450, 2452, 2488, 
+       2524, 2560, 2575, 2611, 2652, 2693, 2734, 2775, 
+       2818, 2859, 2902, 2945, 2988, 3032, 3047, 3062, 
+       3111, 3155, 3209, 3245, 3280, 3315, 3350, 3384, 
+       3418, 3420, 3456, 3492, 3528, 3543, 3579, 3620, 
+       3661, 3702, 3743, 3786, 3827, 3870, 3913, 3956, 
+       4000, 4015, 4064, 4076, 4079, 4133, 4163, 4193, 
+       4199, 4242, 4281, 4321, 4363
+};
+
+static const unsigned char _use_syllable_machine_indicies[] = {
+       1, 0, 2, 0, 3, 4, 5, 5, 
+       6, 7, 5, 5, 5, 5, 5, 8, 
+       9, 10, 11, 5, 5, 5, 12, 5, 
+       5, 5, 13, 14, 15, 16, 17, 18, 
+       19, 20, 21, 8, 22, 23, 24, 25, 
+       5, 26, 27, 28, 5, 29, 30, 31, 
+       32, 33, 34, 35, 32, 1, 5, 36, 
+       5, 37, 5, 39, 40, 38, 41, 38, 
+       38, 38, 38, 38, 38, 38, 42, 43, 
+       44, 45, 46, 47, 48, 49, 50, 39, 
+       51, 52, 53, 54, 38, 55, 56, 57, 
+       38, 58, 59, 38, 60, 61, 62, 63, 
+       60, 38, 38, 38, 38, 64, 38, 39, 
+       40, 38, 41, 38, 38, 38, 38, 38, 
+       38, 38, 42, 43, 44, 45, 46, 47, 
+       48, 49, 50, 39, 51, 52, 53, 54, 
+       38, 55, 56, 57, 38, 38, 38, 38, 
+       60, 61, 62, 63, 60, 38, 38, 38, 
+       38, 64, 38, 39, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       41, 38, 38, 38, 38, 38, 38, 38, 
+       38, 43, 44, 45, 46, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 55, 
+       56, 57, 38, 38, 38, 38, 38, 61, 
+       62, 63, 65, 38, 38, 38, 38, 43, 
+       38, 41, 38, 38, 38, 38, 38, 38, 
+       38, 38, 43, 44, 45, 46, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       55, 56, 57, 38, 38, 38, 38, 38, 
+       61, 62, 63, 65, 38, 41, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 44, 
+       45, 46, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 38, 61, 62, 63, 38, 
+       41, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 45, 46, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 61, 
+       62, 63, 38, 41, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 46, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 61, 62, 63, 38, 41, 38, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 61, 62, 38, 
+       41, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       62, 38, 41, 38, 41, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 44, 45, 
+       46, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 55, 56, 57, 38, 38, 
+       38, 38, 38, 61, 62, 63, 65, 38, 
+       41, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 44, 45, 46, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       56, 57, 38, 38, 38, 38, 38, 61, 
+       62, 63, 65, 38, 41, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 44, 45, 
+       46, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 57, 38, 38, 
+       38, 38, 38, 61, 62, 63, 65, 38, 
+       66, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 41, 38, 41, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       38, 44, 45, 46, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 61, 62, 
+       63, 65, 38, 41, 38, 38, 38, 38, 
+       38, 38, 38, 42, 43, 44, 45, 46, 
+       38, 38, 38, 38, 38, 38, 52, 53, 
+       54, 38, 55, 56, 57, 38, 38, 38, 
+       38, 38, 61, 62, 63, 65, 38, 38, 
+       38, 38, 43, 38, 41, 38, 38, 38, 
+       38, 38, 38, 38, 38, 43, 44, 45, 
+       46, 38, 38, 38, 38, 38, 38, 52, 
+       53, 54, 38, 55, 56, 57, 38, 38, 
+       38, 38, 38, 61, 62, 63, 65, 38, 
+       38, 38, 38, 43, 38, 41, 38, 38, 
+       38, 38, 38, 38, 38, 38, 43, 44, 
+       45, 46, 38, 38, 38, 38, 38, 38, 
+       38, 53, 54, 38, 55, 56, 57, 38, 
+       38, 38, 38, 38, 61, 62, 63, 65, 
+       38, 38, 38, 38, 43, 38, 41, 38, 
+       38, 38, 38, 38, 38, 38, 38, 43, 
+       44, 45, 46, 38, 38, 38, 38, 38, 
+       38, 38, 38, 54, 38, 55, 56, 57, 
+       38, 38, 38, 38, 38, 61, 62, 63, 
+       65, 38, 38, 38, 38, 43, 38, 67, 
+       38, 41, 38, 38, 38, 38, 38, 38, 
+       38, 42, 43, 44, 45, 46, 38, 48, 
+       49, 38, 38, 38, 52, 53, 54, 38, 
+       55, 56, 57, 38, 38, 38, 38, 38, 
+       61, 62, 63, 65, 38, 38, 38, 38, 
+       43, 38, 41, 38, 38, 38, 38, 38, 
+       38, 38, 38, 43, 44, 45, 46, 38, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       38, 55, 56, 57, 38, 38, 38, 38, 
+       38, 61, 62, 63, 65, 38, 38, 38, 
+       38, 43, 38, 67, 38, 41, 38, 38, 
+       38, 38, 38, 38, 38, 42, 43, 44, 
+       45, 46, 38, 38, 49, 38, 38, 38, 
+       52, 53, 54, 38, 55, 56, 57, 38, 
+       38, 38, 38, 38, 61, 62, 63, 65, 
+       38, 38, 38, 38, 43, 38, 67, 38, 
+       41, 38, 38, 38, 38, 38, 38, 38, 
+       42, 43, 44, 45, 46, 38, 38, 38, 
+       38, 38, 38, 52, 53, 54, 38, 55, 
+       56, 57, 38, 38, 38, 38, 38, 61, 
+       62, 63, 65, 38, 38, 38, 38, 43, 
+       38, 67, 38, 41, 38, 38, 38, 38, 
+       38, 38, 38, 42, 43, 44, 45, 46, 
+       47, 48, 49, 38, 38, 38, 52, 53, 
+       54, 38, 55, 56, 57, 38, 38, 38, 
+       38, 38, 61, 62, 63, 65, 38, 38, 
+       38, 38, 43, 38, 39, 40, 38, 41, 
+       38, 38, 38, 38, 38, 38, 38, 42, 
+       43, 44, 45, 46, 47, 48, 49, 50, 
+       38, 51, 52, 53, 54, 38, 55, 56, 
+       57, 38, 38, 38, 38, 60, 61, 62, 
+       63, 60, 38, 38, 38, 38, 64, 38, 
+       39, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 41, 38, 39, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 38, 41, 38, 38, 38, 
+       38, 38, 38, 38, 38, 43, 44, 45, 
+       46, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 55, 56, 57, 38, 38, 
+       38, 38, 38, 61, 62, 63, 65, 38, 
+       41, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 58, 59, 38, 41, 38, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 38, 38, 38, 38, 38, 38, 
+       38, 38, 59, 38, 4, 69, 68, 70, 
+       68, 68, 68, 68, 68, 68, 68, 71, 
+       72, 73, 74, 75, 76, 77, 78, 79, 
+       4, 80, 81, 82, 83, 68, 84, 85, 
+       86, 68, 68, 68, 68, 87, 88, 89, 
+       90, 91, 68, 68, 68, 68, 92, 68, 
+       4, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 70, 68, 68, 
+       68, 68, 68, 68, 68, 68, 72, 73, 
+       74, 75, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 84, 85, 86, 68, 
+       68, 68, 68, 68, 88, 89, 90, 93, 
+       68, 68, 68, 68, 72, 68, 70, 68, 
+       68, 68, 68, 68, 68, 68, 68, 72, 
+       73, 74, 75, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 84, 85, 86, 
+       68, 68, 68, 68, 68, 88, 89, 90, 
+       93, 68, 70, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 73, 74, 75, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 88, 89, 90, 68, 70, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       74, 75, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 88, 89, 90, 68, 
+       70, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 75, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 88, 
+       89, 90, 68, 70, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 88, 89, 68, 70, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 89, 68, 70, 
+       68, 70, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 73, 74, 75, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       84, 85, 86, 68, 68, 68, 68, 68, 
+       88, 89, 90, 93, 68, 70, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 73, 
+       74, 75, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 85, 86, 68, 
+       68, 68, 68, 68, 88, 89, 90, 93, 
+       68, 70, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 73, 74, 75, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 86, 68, 68, 68, 68, 68, 
+       88, 89, 90, 93, 68, 95, 94, 94, 
+       94, 94, 94, 94, 94, 94, 94, 94, 
+       94, 94, 96, 94, 70, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 73, 74, 
+       75, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 88, 89, 90, 93, 68, 
+       70, 68, 68, 68, 68, 68, 68, 68, 
+       71, 72, 73, 74, 75, 68, 68, 68, 
+       68, 68, 68, 81, 82, 83, 68, 84, 
+       85, 86, 68, 68, 68, 68, 68, 88, 
+       89, 90, 93, 68, 68, 68, 68, 72, 
+       68, 70, 68, 68, 68, 68, 68, 68, 
+       68, 68, 72, 73, 74, 75, 68, 68, 
+       68, 68, 68, 68, 81, 82, 83, 68, 
+       84, 85, 86, 68, 68, 68, 68, 68, 
+       88, 89, 90, 93, 68, 68, 68, 68, 
+       72, 68, 70, 68, 68, 68, 68, 68, 
+       68, 68, 68, 72, 73, 74, 75, 68, 
+       68, 68, 68, 68, 68, 68, 82, 83, 
+       68, 84, 85, 86, 68, 68, 68, 68, 
+       68, 88, 89, 90, 93, 68, 68, 68, 
+       68, 72, 68, 70, 68, 68, 68, 68, 
+       68, 68, 68, 68, 72, 73, 74, 75, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       83, 68, 84, 85, 86, 68, 68, 68, 
+       68, 68, 88, 89, 90, 93, 68, 68, 
+       68, 68, 72, 68, 97, 68, 70, 68, 
+       68, 68, 68, 68, 68, 68, 71, 72, 
+       73, 74, 75, 68, 77, 78, 68, 68, 
+       68, 81, 82, 83, 68, 84, 85, 86, 
+       68, 68, 68, 68, 68, 88, 89, 90, 
+       93, 68, 68, 68, 68, 72, 68, 70, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       72, 73, 74, 75, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 84, 85, 
+       86, 68, 68, 68, 68, 68, 88, 89, 
+       90, 93, 68, 68, 68, 68, 72, 68, 
+       97, 68, 70, 68, 68, 68, 68, 68, 
+       68, 68, 71, 72, 73, 74, 75, 68, 
+       68, 78, 68, 68, 68, 81, 82, 83, 
+       68, 84, 85, 86, 68, 68, 68, 68, 
+       68, 88, 89, 90, 93, 68, 68, 68, 
+       68, 72, 68, 97, 68, 70, 68, 68, 
+       68, 68, 68, 68, 68, 71, 72, 73, 
+       74, 75, 68, 68, 68, 68, 68, 68, 
+       81, 82, 83, 68, 84, 85, 86, 68, 
+       68, 68, 68, 68, 88, 89, 90, 93, 
+       68, 68, 68, 68, 72, 68, 97, 68, 
+       70, 68, 68, 68, 68, 68, 68, 68, 
+       71, 72, 73, 74, 75, 76, 77, 78, 
+       68, 68, 68, 81, 82, 83, 68, 84, 
+       85, 86, 68, 68, 68, 68, 68, 88, 
+       89, 90, 93, 68, 68, 68, 68, 72, 
+       68, 4, 69, 68, 70, 68, 68, 68, 
+       68, 68, 68, 68, 71, 72, 73, 74, 
+       75, 76, 77, 78, 79, 68, 80, 81, 
+       82, 83, 68, 84, 85, 86, 68, 68, 
+       68, 68, 87, 88, 89, 90, 91, 68, 
+       68, 68, 68, 92, 68, 4, 98, 98, 
+       98, 98, 98, 98, 98, 98, 98, 98, 
+       98, 98, 99, 98, 4, 94, 94, 94, 
+       94, 94, 94, 94, 94, 94, 94, 94, 
+       94, 96, 94, 4, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       70, 68, 68, 68, 68, 68, 68, 68, 
+       68, 72, 73, 74, 75, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 84, 
+       85, 86, 68, 68, 68, 68, 68, 88, 
+       89, 90, 93, 68, 101, 102, 100, 6, 
+       103, 103, 103, 103, 103, 103, 103, 103, 
+       103, 104, 103, 105, 106, 68, 70, 68, 
+       68, 68, 68, 68, 68, 68, 107, 108, 
+       109, 110, 111, 112, 113, 114, 115, 105, 
+       116, 117, 118, 119, 68, 120, 121, 122, 
+       68, 58, 59, 68, 123, 124, 125, 126, 
+       127, 68, 68, 68, 68, 128, 68, 105, 
+       106, 68, 70, 68, 68, 68, 68, 68, 
+       68, 68, 107, 108, 109, 110, 111, 112, 
+       113, 114, 115, 105, 116, 117, 118, 119, 
+       68, 120, 121, 122, 68, 68, 68, 68, 
+       123, 124, 125, 126, 127, 68, 68, 68, 
+       68, 128, 68, 105, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       70, 68, 68, 68, 68, 68, 68, 68, 
+       68, 108, 109, 110, 111, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 120, 
+       121, 122, 68, 68, 68, 68, 68, 124, 
+       125, 126, 129, 68, 68, 68, 68, 108, 
+       68, 70, 68, 68, 68, 68, 68, 68, 
+       68, 68, 108, 109, 110, 111, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       120, 121, 122, 68, 68, 68, 68, 68, 
+       124, 125, 126, 129, 68, 70, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 109, 
+       110, 111, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 124, 125, 126, 68, 
+       70, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 110, 111, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 124, 
+       125, 126, 68, 70, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 111, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 124, 125, 126, 68, 70, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 124, 125, 68, 
+       70, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       125, 68, 70, 68, 70, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 109, 110, 
+       111, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 120, 121, 122, 68, 68, 
+       68, 68, 68, 124, 125, 126, 129, 68, 
+       70, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 109, 110, 111, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       121, 122, 68, 68, 68, 68, 68, 124, 
+       125, 126, 129, 68, 70, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 109, 110, 
+       111, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 122, 68, 68, 
+       68, 68, 68, 124, 125, 126, 129, 68, 
+       130, 94, 94, 94, 94, 94, 94, 94, 
+       94, 94, 94, 94, 94, 96, 94, 70, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 109, 110, 111, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 68, 68, 68, 124, 125, 
+       126, 129, 68, 70, 68, 68, 68, 68, 
+       68, 68, 68, 107, 108, 109, 110, 111, 
+       68, 68, 68, 68, 68, 68, 117, 118, 
+       119, 68, 120, 121, 122, 68, 68, 68, 
+       68, 68, 124, 125, 126, 129, 68, 68, 
+       68, 68, 108, 68, 70, 68, 68, 68, 
+       68, 68, 68, 68, 68, 108, 109, 110, 
+       111, 68, 68, 68, 68, 68, 68, 117, 
+       118, 119, 68, 120, 121, 122, 68, 68, 
+       68, 68, 68, 124, 125, 126, 129, 68, 
+       68, 68, 68, 108, 68, 70, 68, 68, 
+       68, 68, 68, 68, 68, 68, 108, 109, 
+       110, 111, 68, 68, 68, 68, 68, 68, 
+       68, 118, 119, 68, 120, 121, 122, 68, 
+       68, 68, 68, 68, 124, 125, 126, 129, 
+       68, 68, 68, 68, 108, 68, 70, 68, 
+       68, 68, 68, 68, 68, 68, 68, 108, 
+       109, 110, 111, 68, 68, 68, 68, 68, 
+       68, 68, 68, 119, 68, 120, 121, 122, 
+       68, 68, 68, 68, 68, 124, 125, 126, 
+       129, 68, 68, 68, 68, 108, 68, 131, 
+       68, 70, 68, 68, 68, 68, 68, 68, 
+       68, 107, 108, 109, 110, 111, 68, 113, 
+       114, 68, 68, 68, 117, 118, 119, 68, 
+       120, 121, 122, 68, 68, 68, 68, 68, 
+       124, 125, 126, 129, 68, 68, 68, 68, 
+       108, 68, 70, 68, 68, 68, 68, 68, 
+       68, 68, 68, 108, 109, 110, 111, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 120, 121, 122, 68, 68, 68, 68, 
+       68, 124, 125, 126, 129, 68, 68, 68, 
+       68, 108, 68, 131, 68, 70, 68, 68, 
+       68, 68, 68, 68, 68, 107, 108, 109, 
+       110, 111, 68, 68, 114, 68, 68, 68, 
+       117, 118, 119, 68, 120, 121, 122, 68, 
+       68, 68, 68, 68, 124, 125, 126, 129, 
+       68, 68, 68, 68, 108, 68, 131, 68, 
+       70, 68, 68, 68, 68, 68, 68, 68, 
+       107, 108, 109, 110, 111, 68, 68, 68, 
+       68, 68, 68, 117, 118, 119, 68, 120, 
+       121, 122, 68, 68, 68, 68, 68, 124, 
+       125, 126, 129, 68, 68, 68, 68, 108, 
+       68, 131, 68, 70, 68, 68, 68, 68, 
+       68, 68, 68, 107, 108, 109, 110, 111, 
+       112, 113, 114, 68, 68, 68, 117, 118, 
+       119, 68, 120, 121, 122, 68, 68, 68, 
+       68, 68, 124, 125, 126, 129, 68, 68, 
+       68, 68, 108, 68, 105, 106, 68, 70, 
+       68, 68, 68, 68, 68, 68, 68, 107, 
+       108, 109, 110, 111, 112, 113, 114, 115, 
+       68, 116, 117, 118, 119, 68, 120, 121, 
+       122, 68, 68, 68, 68, 123, 124, 125, 
+       126, 127, 68, 68, 68, 68, 128, 68, 
+       105, 98, 98, 98, 98, 98, 98, 98, 
+       98, 98, 98, 98, 98, 99, 98, 105, 
+       94, 94, 94, 94, 94, 94, 94, 94, 
+       94, 94, 94, 94, 96, 94, 105, 68, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 68, 70, 68, 68, 68, 68, 
+       68, 68, 68, 68, 108, 109, 110, 111, 
+       68, 68, 68, 68, 68, 68, 68, 68, 
+       68, 68, 120, 121, 122, 68, 68, 68, 
+       68, 68, 124, 125, 126, 129, 68, 8, 
+       9, 132, 11, 132, 132, 132, 132, 132, 
+       132, 132, 13, 14, 15, 16, 17, 18, 
+       19, 20, 21, 8, 22, 23, 24, 25, 
+       132, 26, 27, 28, 132, 132, 132, 132, 
+       32, 33, 34, 35, 32, 132, 132, 132, 
+       132, 37, 132, 8, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       11, 132, 132, 132, 132, 132, 132, 132, 
+       132, 14, 15, 16, 17, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 26, 
+       27, 28, 132, 132, 132, 132, 132, 33, 
+       34, 35, 133, 132, 132, 132, 132, 14, 
+       132, 11, 132, 132, 132, 132, 132, 132, 
+       132, 132, 14, 15, 16, 17, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       26, 27, 28, 132, 132, 132, 132, 132, 
+       33, 34, 35, 133, 132, 11, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 15, 
+       16, 17, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 132, 33, 34, 35, 132, 
+       11, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 16, 17, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 33, 
+       34, 35, 132, 11, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 17, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 33, 34, 35, 132, 11, 132, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 33, 34, 132, 
+       11, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       34, 132, 11, 132, 11, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 15, 16, 
+       17, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 26, 27, 28, 132, 132, 
+       132, 132, 132, 33, 34, 35, 133, 132, 
+       11, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 15, 16, 17, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       27, 28, 132, 132, 132, 132, 132, 33, 
+       34, 35, 133, 132, 11, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 15, 16, 
+       17, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 28, 132, 132, 
+       132, 132, 132, 33, 34, 35, 133, 132, 
+       134, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 11, 132, 11, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       132, 15, 16, 17, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 33, 34, 
+       35, 133, 132, 11, 132, 132, 132, 132, 
+       132, 132, 132, 13, 14, 15, 16, 17, 
+       132, 132, 132, 132, 132, 132, 23, 24, 
+       25, 132, 26, 27, 28, 132, 132, 132, 
+       132, 132, 33, 34, 35, 133, 132, 132, 
+       132, 132, 14, 132, 11, 132, 132, 132, 
+       132, 132, 132, 132, 132, 14, 15, 16, 
+       17, 132, 132, 132, 132, 132, 132, 23, 
+       24, 25, 132, 26, 27, 28, 132, 132, 
+       132, 132, 132, 33, 34, 35, 133, 132, 
+       132, 132, 132, 14, 132, 11, 132, 132, 
+       132, 132, 132, 132, 132, 132, 14, 15, 
+       16, 17, 132, 132, 132, 132, 132, 132, 
+       132, 24, 25, 132, 26, 27, 28, 132, 
+       132, 132, 132, 132, 33, 34, 35, 133, 
+       132, 132, 132, 132, 14, 132, 11, 132, 
+       132, 132, 132, 132, 132, 132, 132, 14, 
+       15, 16, 17, 132, 132, 132, 132, 132, 
+       132, 132, 132, 25, 132, 26, 27, 28, 
+       132, 132, 132, 132, 132, 33, 34, 35, 
+       133, 132, 132, 132, 132, 14, 132, 135, 
+       132, 11, 132, 132, 132, 132, 132, 132, 
+       132, 13, 14, 15, 16, 17, 132, 19, 
+       20, 132, 132, 132, 23, 24, 25, 132, 
+       26, 27, 28, 132, 132, 132, 132, 132, 
+       33, 34, 35, 133, 132, 132, 132, 132, 
+       14, 132, 11, 132, 132, 132, 132, 132, 
+       132, 132, 132, 14, 15, 16, 17, 132, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       132, 26, 27, 28, 132, 132, 132, 132, 
+       132, 33, 34, 35, 133, 132, 132, 132, 
+       132, 14, 132, 135, 132, 11, 132, 132, 
+       132, 132, 132, 132, 132, 13, 14, 15, 
+       16, 17, 132, 132, 20, 132, 132, 132, 
+       23, 24, 25, 132, 26, 27, 28, 132, 
+       132, 132, 132, 132, 33, 34, 35, 133, 
+       132, 132, 132, 132, 14, 132, 135, 132, 
+       11, 132, 132, 132, 132, 132, 132, 132, 
+       13, 14, 15, 16, 17, 132, 132, 132, 
+       132, 132, 132, 23, 24, 25, 132, 26, 
+       27, 28, 132, 132, 132, 132, 132, 33, 
+       34, 35, 133, 132, 132, 132, 132, 14, 
+       132, 135, 132, 11, 132, 132, 132, 132, 
+       132, 132, 132, 13, 14, 15, 16, 17, 
+       18, 19, 20, 132, 132, 132, 23, 24, 
+       25, 132, 26, 27, 28, 132, 132, 132, 
+       132, 132, 33, 34, 35, 133, 132, 132, 
+       132, 132, 14, 132, 8, 9, 132, 11, 
+       132, 132, 132, 132, 132, 132, 132, 13, 
+       14, 15, 16, 17, 18, 19, 20, 21, 
+       132, 22, 23, 24, 25, 132, 26, 27, 
+       28, 132, 132, 132, 132, 32, 33, 34, 
+       35, 32, 132, 132, 132, 132, 37, 132, 
+       8, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 11, 132, 8, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 132, 11, 132, 132, 132, 
+       132, 132, 132, 132, 132, 14, 15, 16, 
+       17, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 26, 27, 28, 132, 132, 
+       132, 132, 132, 33, 34, 35, 133, 132, 
+       136, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 11, 132, 10, 11, 132, 4, 
+       132, 132, 132, 4, 132, 132, 132, 132, 
+       132, 8, 9, 10, 11, 132, 132, 132, 
+       132, 132, 132, 132, 13, 14, 15, 16, 
+       17, 18, 19, 20, 21, 8, 22, 23, 
+       24, 25, 132, 26, 27, 28, 132, 29, 
+       30, 132, 32, 33, 34, 35, 32, 132, 
+       132, 132, 132, 37, 132, 11, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       29, 30, 132, 11, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 132, 
+       132, 132, 132, 132, 132, 132, 132, 30, 
+       132, 4, 137, 137, 137, 4, 137, 139, 
+       138, 138, 138, 138, 138, 138, 138, 138, 
+       138, 138, 138, 138, 138, 138, 138, 138, 
+       138, 138, 138, 138, 138, 138, 138, 138, 
+       138, 138, 138, 138, 138, 138, 138, 138, 
+       138, 138, 138, 140, 138, 141, 138, 141, 
+       142, 138, 139, 138, 138, 138, 138, 138, 
+       138, 138, 138, 138, 138, 138, 138, 138, 
+       138, 138, 138, 138, 138, 138, 138, 138, 
+       138, 138, 138, 138, 138, 138, 138, 138, 
+       138, 138, 138, 138, 138, 1, 140, 140, 
+       138, 139, 138, 138, 138, 138, 138, 138, 
+       138, 138, 138, 138, 138, 138, 138, 138, 
+       138, 138, 138, 138, 138, 138, 138, 138, 
+       138, 138, 138, 138, 138, 138, 138, 138, 
+       138, 138, 138, 138, 138, 140, 138, 141, 
+       138, 139, 138, 138, 138, 138, 138, 138, 
+       138, 138, 138, 138, 138, 138, 138, 138, 
+       138, 138, 138, 138, 138, 138, 138, 138, 
+       138, 138, 138, 138, 138, 138, 138, 138, 
+       138, 138, 138, 138, 138, 140, 138, 141, 
+       138, 141, 138, 39, 40, 38, 41, 38, 
+       38, 38, 38, 38, 38, 38, 42, 43, 
+       44, 45, 46, 47, 48, 49, 50, 39, 
+       51, 52, 53, 54, 38, 55, 56, 57, 
+       38, 58, 59, 38, 60, 61, 62, 63, 
+       60, 1, 38, 2, 38, 64, 38, 0
+};
+
+static const char _use_syllable_machine_trans_targs[] = {
+       1, 120, 0, 2, 31, 1, 58, 60, 
+       88, 89, 114, 1, 116, 102, 90, 91, 
+       92, 93, 106, 108, 109, 110, 111, 103, 
+       104, 105, 97, 98, 99, 117, 118, 119, 
+       112, 94, 95, 96, 124, 113, 1, 3, 
+       4, 1, 17, 5, 6, 7, 8, 21, 
+       23, 24, 25, 26, 18, 19, 20, 12, 
+       13, 14, 29, 30, 27, 9, 10, 11, 
+       28, 15, 16, 22, 1, 32, 1, 45, 
+       33, 34, 35, 36, 49, 51, 52, 53, 
+       54, 46, 47, 48, 40, 41, 42, 55, 
+       37, 38, 39, 56, 57, 43, 1, 44, 
+       1, 50, 1, 1, 1, 59, 1, 1, 
+       1, 61, 62, 75, 63, 64, 65, 66, 
+       79, 81, 82, 83, 84, 76, 77, 78, 
+       70, 71, 72, 85, 67, 68, 69, 86, 
+       87, 73, 74, 80, 1, 100, 101, 107, 
+       115, 1, 1, 1, 121, 122, 123
+};
+
+static const char _use_syllable_machine_trans_actions[] = {
+       1, 0, 0, 0, 0, 4, 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, 0, 
+       0, 0, 0, 0, 6, 0, 7, 0, 
+       0, 8, 0, 0, 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, 10, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 11, 0, 
+       12, 0, 13, 14, 15, 0, 16, 17, 
+       18, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 19, 0, 0, 0, 
+       0, 20, 21, 22, 0, 0, 0
+};
+
+static const char _use_syllable_machine_to_state_actions[] = {
+       0, 2, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 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[] = {
+       0, 3, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 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, 0, 39, 39, 39, 39, 39, 39, 
+       39, 39, 39, 39, 39, 39, 39, 39, 
+       39, 39, 39, 39, 39, 39, 39, 39, 
+       39, 39, 39, 39, 39, 39, 39, 69, 
+       69, 69, 69, 69, 69, 69, 69, 69, 
+       69, 69, 69, 95, 69, 69, 69, 69, 
+       69, 69, 69, 69, 69, 69, 69, 99, 
+       95, 69, 101, 104, 69, 69, 69, 69, 
+       69, 69, 69, 69, 69, 69, 69, 69, 
+       69, 95, 69, 69, 69, 69, 69, 69, 
+       69, 69, 69, 69, 69, 99, 95, 69, 
+       133, 133, 133, 133, 133, 133, 133, 133, 
+       133, 133, 133, 133, 133, 133, 133, 133, 
+       133, 133, 133, 133, 133, 133, 133, 133, 
+       133, 133, 133, 133, 133, 133, 133, 138, 
+       139, 139, 139, 139, 39
+};
+
+static const int use_syllable_machine_start = 1;
+static const int use_syllable_machine_first_final = 1;
+static const int use_syllable_machine_error = -1;
+
+static const int use_syllable_machine_en_main = 1;
+
+
+#line 58 "hb-ot-shaper-use-machine.rl"
+
+
+
+#line 184 "hb-ot-shaper-use-machine.rl"
+
+
+#define found_syllable(syllable_type) \
+  HB_STMT_START { \
+    if (0) fprintf (stderr, "syllable %u..%u %s\n", (*ts).second.first, (*te).second.first, #syllable_type); \
+    for (unsigned i = (*ts).second.first; i < (*te).second.first; ++i) \
+      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+    syllable_serial++; \
+    if (syllable_serial == 16) syllable_serial = 1; \
+  } HB_STMT_END
+
+
+template <typename Iter>
+struct machine_index_t :
+  hb_iter_with_fallback_t<machine_index_t<Iter>,
+                         typename Iter::item_t>
+{
+  machine_index_t (const Iter& it) : it (it) {}
+  machine_index_t (const machine_index_t& o) : hb_iter_with_fallback_t<machine_index_t<Iter>,
+                                                                      typename Iter::item_t> (),
+                                              it (o.it), is_null (o.is_null) {}
+
+  static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
+  static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
+
+  typename Iter::item_t __item__ () const { return *it; }
+  typename Iter::item_t __item_at__ (unsigned i) const { return it[i]; }
+  unsigned __len__ () const { return it.len (); }
+  void __next__ () { ++it; }
+  void __forward__ (unsigned n) { it += n; }
+  void __prev__ () { --it; }
+  void __rewind__ (unsigned n) { it -= n; }
+
+  void operator = (unsigned n)
+  {
+    assert (n == 0);
+    is_null = true;
+  }
+  explicit operator bool () { return !is_null; }
+
+  void operator = (const machine_index_t& o)
+  {
+    is_null = o.is_null;
+    unsigned index = (*it).first;
+    unsigned n = (*o.it).first;
+    if (index < n) it += n - index; else if (index > n) it -= index - n;
+  }
+  bool operator == (const machine_index_t& o) const
+  { return is_null ? o.is_null : !o.is_null && (*it).first == (*o.it).first; }
+  bool operator != (const machine_index_t& o) const { return !(*this == o); }
+
+  private:
+  Iter it;
+  bool is_null = false;
+};
+struct
+{
+  template <typename Iter,
+           hb_requires (hb_is_iterable (Iter))>
+  machine_index_t<hb_iter_type<Iter>>
+  operator () (Iter&& it) const
+  { return machine_index_t<hb_iter_type<Iter>> (hb_iter (it)); }
+}
+HB_FUNCOBJ (machine_index);
+
+
+
+static bool
+not_ccs_default_ignorable (const hb_glyph_info_t &i)
+{ return i.use_category() != USE(CGJ); }
+
+static inline void
+find_syllables_use (hb_buffer_t *buffer)
+{
+  hb_glyph_info_t *info = buffer->info;
+  auto p =
+    + hb_iter (info, buffer->len)
+    | hb_enumerate
+    | hb_filter ([] (const hb_glyph_info_t &i) { return not_ccs_default_ignorable (i); },
+                hb_second)
+    | hb_filter ([&] (const hb_pair_t<unsigned, const hb_glyph_info_t &> p)
+                {
+                  if (p.second.use_category() == USE(ZWNJ))
+                    for (unsigned i = p.first + 1; i < buffer->len; ++i)
+                      if (not_ccs_default_ignorable (info[i]))
+                        return !_hb_glyph_info_is_unicode_mark (&info[i]);
+                  return true;
+                })
+    | hb_enumerate
+    | machine_index
+    ;
+  auto pe = p + p.len ();
+  auto eof = +pe;
+  auto ts = +p;
+  auto te = +p;
+  unsigned int act HB_UNUSED;
+  int cs;
+  
+#line 924 "hb-ot-shaper-use-machine.hh"
+       {
+       cs = use_syllable_machine_start;
+       ts = 0;
+       te = 0;
+       act = 0;
+       }
+
+#line 284 "hb-ot-shaper-use-machine.rl"
+
+
+  unsigned int syllable_serial = 1;
+  
+#line 937 "hb-ot-shaper-use-machine.hh"
+       {
+       int _slen;
+       int _trans;
+       const unsigned char *_keys;
+       const unsigned char *_inds;
+       if ( p == pe )
+               goto _test_eof;
+_resume:
+       switch ( _use_syllable_machine_from_state_actions[cs] ) {
+       case 3:
+#line 1 "NONE"
+       {ts = p;}
+       break;
+#line 951 "hb-ot-shaper-use-machine.hh"
+       }
+
+       _keys = _use_syllable_machine_trans_keys + (cs<<1);
+       _inds = _use_syllable_machine_indicies + _use_syllable_machine_index_offsets[cs];
+
+       _slen = _use_syllable_machine_key_spans[cs];
+       _trans = _inds[ _slen > 0 && _keys[0] <=( (*p).second.second.use_category()) &&
+               ( (*p).second.second.use_category()) <= _keys[1] ?
+               ( (*p).second.second.use_category()) - _keys[0] : _slen ];
+
+_eof_trans:
+       cs = _use_syllable_machine_trans_targs[_trans];
+
+       if ( _use_syllable_machine_trans_actions[_trans] == 0 )
+               goto _again;
+
+       switch ( _use_syllable_machine_trans_actions[_trans] ) {
+       case 6:
+#line 1 "NONE"
+       {te = p+1;}
+       break;
+       case 14:
+#line 172 "hb-ot-shaper-use-machine.rl"
+       {te = p+1;{ found_syllable (use_virama_terminated_cluster); }}
+       break;
+       case 12:
+#line 173 "hb-ot-shaper-use-machine.rl"
+       {te = p+1;{ found_syllable (use_sakot_terminated_cluster); }}
+       break;
+       case 10:
+#line 174 "hb-ot-shaper-use-machine.rl"
+       {te = p+1;{ found_syllable (use_standard_cluster); }}
+       break;
+       case 18:
+#line 175 "hb-ot-shaper-use-machine.rl"
+       {te = p+1;{ found_syllable (use_number_joiner_terminated_cluster); }}
+       break;
+       case 16:
+#line 176 "hb-ot-shaper-use-machine.rl"
+       {te = p+1;{ found_syllable (use_numeral_cluster); }}
+       break;
+       case 8:
+#line 177 "hb-ot-shaper-use-machine.rl"
+       {te = p+1;{ found_syllable (use_symbol_cluster); }}
+       break;
+       case 22:
+#line 178 "hb-ot-shaper-use-machine.rl"
+       {te = p+1;{ found_syllable (use_hieroglyph_cluster); }}
+       break;
+       case 5:
+#line 179 "hb-ot-shaper-use-machine.rl"
+       {te = p+1;{ found_syllable (use_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
+       break;
+       case 4:
+#line 180 "hb-ot-shaper-use-machine.rl"
+       {te = p+1;{ found_syllable (use_non_cluster); }}
+       break;
+       case 13:
+#line 172 "hb-ot-shaper-use-machine.rl"
+       {te = p;p--;{ found_syllable (use_virama_terminated_cluster); }}
+       break;
+       case 11:
+#line 173 "hb-ot-shaper-use-machine.rl"
+       {te = p;p--;{ found_syllable (use_sakot_terminated_cluster); }}
+       break;
+       case 9:
+#line 174 "hb-ot-shaper-use-machine.rl"
+       {te = p;p--;{ found_syllable (use_standard_cluster); }}
+       break;
+       case 17:
+#line 175 "hb-ot-shaper-use-machine.rl"
+       {te = p;p--;{ found_syllable (use_number_joiner_terminated_cluster); }}
+       break;
+       case 15:
+#line 176 "hb-ot-shaper-use-machine.rl"
+       {te = p;p--;{ found_syllable (use_numeral_cluster); }}
+       break;
+       case 7:
+#line 177 "hb-ot-shaper-use-machine.rl"
+       {te = p;p--;{ found_syllable (use_symbol_cluster); }}
+       break;
+       case 21:
+#line 178 "hb-ot-shaper-use-machine.rl"
+       {te = p;p--;{ found_syllable (use_hieroglyph_cluster); }}
+       break;
+       case 19:
+#line 179 "hb-ot-shaper-use-machine.rl"
+       {te = p;p--;{ found_syllable (use_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
+       break;
+       case 20:
+#line 180 "hb-ot-shaper-use-machine.rl"
+       {te = p;p--;{ found_syllable (use_non_cluster); }}
+       break;
+       case 1:
+#line 177 "hb-ot-shaper-use-machine.rl"
+       {{p = ((te))-1;}{ found_syllable (use_symbol_cluster); }}
+       break;
+#line 1049 "hb-ot-shaper-use-machine.hh"
+       }
+
+_again:
+       switch ( _use_syllable_machine_to_state_actions[cs] ) {
+       case 2:
+#line 1 "NONE"
+       {ts = 0;}
+       break;
+#line 1058 "hb-ot-shaper-use-machine.hh"
+       }
+
+       if ( ++p != pe )
+               goto _resume;
+       _test_eof: {}
+       if ( p == eof )
+       {
+       if ( _use_syllable_machine_eof_trans[cs] > 0 ) {
+               _trans = _use_syllable_machine_eof_trans[cs] - 1;
+               goto _eof_trans;
+       }
+       }
+
+       }
+
+#line 289 "hb-ot-shaper-use-machine.rl"
+
+}
+
+#undef found_syllable
+
+#endif /* HB_OT_SHAPER_USE_MACHINE_HH */
similarity index 74%
rename from src/hb-ot-shape-complex-use-machine.rl
rename to src/hb-ot-shaper-use-machine.rl
index 9e0d98d..374fcad 100644 (file)
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
+#ifndef HB_OT_SHAPER_USE_MACHINE_HH
+#define HB_OT_SHAPER_USE_MACHINE_HH
 
 #include "hb.hh"
 
-#include "hb-ot-shape-complex-syllabic.hh"
+#include "hb-ot-shaper-syllabic.hh"
 
 /* buffer var allocations */
-#define use_category() complex_var_u8_category()
+#define use_category() ot_shaper_var_u8_category()
 
 #define USE(Cat) use_syllable_machine_ex_##Cat
 
@@ -73,14 +73,18 @@ export H    = 12; # HALANT
 
 export HN      = 13; # HALANT_NUM
 export ZWNJ    = 14; # Zero width non-joiner
+export WJ      = 16; # Word joiner
 export R       = 18; # REPHA
 export CS      = 43; # CONS_WITH_STACKER
-export HVM     = 44; # HALANT_OR_VOWEL_MODIFIER
+export IS      = 44; # INVISIBLE_STACKER
 export Sk      = 48; # SAKOT
 export G       = 49; # HIEROGLYPH
 export J       = 50; # HIEROGLYPH_JOINER
 export SB      = 51; # HIEROGLYPH_SEGMENT_BEGIN
 export SE      = 52; # HIEROGLYPH_SEGMENT_END
+export HVM     = 53; # HALANT_OR_VOWEL_MODIFIER
+export HM      = 54; # HIEROGLYPH_MOD
+export HR      = 55; # HIEROGLYPH_MIRROR
 
 export FAbv    = 24; # CONS_FINAL_ABOVE
 export FBlw    = 25; # CONS_FINAL_BELOW
@@ -106,11 +110,11 @@ export FMBlw      = 46; # CONS_FINAL_MOD  UIPC = Bottom
 export FMPst   = 47; # CONS_FINAL_MOD  UIPC = Not_Applicable
 
 
-h = H | HVM | Sk;
+h = H | HVM | IS | Sk;
 
-consonant_modifiers = CMAbv* CMBlw* ((h B | SUB) CMAbv? CMBlw*)*;
+consonant_modifiers = CMAbv* CMBlw* ((h B | SUB) CMAbv* CMBlw*)*;
 medial_consonants = MPre? MAbv? MBlw? MPst?;
-dependent_vowels = VPre* VAbv* VBlw* VPst*;
+dependent_vowels = VPre* VAbv* VBlw* VPst* | H;
 vowel_modifiers = HVM? VMPre* VMAbv* VMBlw* VMPst*;
 final_consonants = FAbv* FBlw* FPst*;
 final_modifiers = FMAbv* FMBlw* | FMPst?;
@@ -134,7 +138,7 @@ symbol_cluster_tail = SMAbv+ SMBlw* | SMBlw+;
 
 virama_terminated_cluster_tail =
        consonant_modifiers
-       h
+       IS
 ;
 virama_terminated_cluster =
        complex_syllable_start
@@ -152,26 +156,27 @@ standard_cluster =
        complex_syllable_start
        complex_syllable_tail
 ;
+tail = complex_syllable_tail | sakot_terminated_cluster_tail | symbol_cluster_tail | virama_terminated_cluster_tail;
 broken_cluster =
        R?
-       (complex_syllable_tail | number_joiner_terminated_cluster_tail | numeral_cluster_tail | symbol_cluster_tail | virama_terminated_cluster_tail | sakot_terminated_cluster_tail)
+       (tail | number_joiner_terminated_cluster_tail | numeral_cluster_tail)
 ;
 
 number_joiner_terminated_cluster = N number_joiner_terminated_cluster_tail;
 numeral_cluster = N numeral_cluster_tail?;
-symbol_cluster = (O | GB) symbol_cluster_tail?;
-hieroglyph_cluster = SB+ | SB* G SE* (J SE* (G SE*)?)*;
+symbol_cluster = (O | GB | SB) tail?;
+hieroglyph_cluster = SB* G HR? HM? SE* (J SB* (G HR? HM? SE*)?)*;
 other = any;
 
 main := |*
-       virama_terminated_cluster               => { found_syllable (use_virama_terminated_cluster); };
-       sakot_terminated_cluster                => { found_syllable (use_sakot_terminated_cluster); };
-       standard_cluster                        => { found_syllable (use_standard_cluster); };
-       number_joiner_terminated_cluster        => { found_syllable (use_number_joiner_terminated_cluster); };
-       numeral_cluster                         => { found_syllable (use_numeral_cluster); };
-       symbol_cluster                          => { found_syllable (use_symbol_cluster); };
-       hieroglyph_cluster                      => { found_syllable (use_hieroglyph_cluster); };
-       broken_cluster                          => { found_syllable (use_broken_cluster); };
+       virama_terminated_cluster ZWNJ?         => { found_syllable (use_virama_terminated_cluster); };
+       sakot_terminated_cluster ZWNJ?          => { found_syllable (use_sakot_terminated_cluster); };
+       standard_cluster ZWNJ?                  => { found_syllable (use_standard_cluster); };
+       number_joiner_terminated_cluster ZWNJ?  => { found_syllable (use_number_joiner_terminated_cluster); };
+       numeral_cluster ZWNJ?                   => { found_syllable (use_numeral_cluster); };
+       symbol_cluster ZWNJ?                    => { found_syllable (use_symbol_cluster); };
+       hieroglyph_cluster ZWNJ?                => { found_syllable (use_hieroglyph_cluster); };
+       broken_cluster ZWNJ?                    => { found_syllable (use_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; };
        other                                   => { found_syllable (use_non_cluster); };
 *|;
 
@@ -180,11 +185,11 @@ main := |*
 
 #define found_syllable(syllable_type) \
   HB_STMT_START { \
-    if (0) fprintf (stderr, "syllable %d..%d %s\n", (*ts).second.first, (*te).second.first, #syllable_type); \
+    if (0) fprintf (stderr, "syllable %u..%u %s\n", (*ts).second.first, (*te).second.first, #syllable_type); \
     for (unsigned i = (*ts).second.first; i < (*te).second.first; ++i) \
       info[i].syllable() = (syllable_serial << 4) | syllable_type; \
     syllable_serial++; \
-    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+    if (syllable_serial == 16) syllable_serial = 1; \
   } HB_STMT_END
 
 
@@ -194,7 +199,9 @@ struct machine_index_t :
                          typename Iter::item_t>
 {
   machine_index_t (const Iter& it) : it (it) {}
-  machine_index_t (const machine_index_t& o) : it (o.it) {}
+  machine_index_t (const machine_index_t& o) : hb_iter_with_fallback_t<machine_index_t<Iter>,
+                                                                      typename Iter::item_t> (),
+                                              it (o.it), is_null (o.is_null) {}
 
   static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
   static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
@@ -206,14 +213,28 @@ struct machine_index_t :
   void __forward__ (unsigned n) { it += n; }
   void __prev__ () { --it; }
   void __rewind__ (unsigned n) { it -= n; }
+
   void operator = (unsigned n)
-  { unsigned index = (*it).first; if (index < n) it += n - index; else if (index > n) it -= index - n; }
-  void operator = (const machine_index_t& o) { *this = (*o.it).first; }
-  bool operator == (const machine_index_t& o) const { return (*it).first == (*o.it).first; }
+  {
+    assert (n == 0);
+    is_null = true;
+  }
+  explicit operator bool () { return !is_null; }
+
+  void operator = (const machine_index_t& o)
+  {
+    is_null = o.is_null;
+    unsigned index = (*it).first;
+    unsigned n = (*o.it).first;
+    if (index < n) it += n - index; else if (index > n) it -= index - n;
+  }
+  bool operator == (const machine_index_t& o) const
+  { return is_null ? o.is_null : !o.is_null && (*it).first == (*o.it).first; }
   bool operator != (const machine_index_t& o) const { return !(*this == o); }
 
   private:
   Iter it;
+  bool is_null = false;
 };
 struct
 {
@@ -229,7 +250,7 @@ HB_FUNCOBJ (machine_index);
 
 static bool
 not_ccs_default_ignorable (const hb_glyph_info_t &i)
-{ return !(i.use_category() == USE(CGJ) && _hb_glyph_info_is_default_ignorable (&i)); }
+{ return i.use_category() != USE(CGJ); }
 
 static inline void
 find_syllables_use (hb_buffer_t *buffer)
@@ -270,4 +291,4 @@ find_syllables_use (hb_buffer_t *buffer)
 
 #undef found_syllable
 
-#endif /* HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH */
+#endif /* HB_OT_SHAPER_USE_MACHINE_HH */
diff --git a/src/hb-ot-shaper-use-table.hh b/src/hb-ot-shaper-use-table.hh
new file mode 100644 (file)
index 0000000..d581b65
--- /dev/null
@@ -0,0 +1,690 @@
+/* == Start of generated table == */
+/*
+ * The following table is generated by running:
+ *
+ *   ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt ArabicShaping.txt DerivedCoreProperties.txt UnicodeData.txt Blocks.txt Scripts.txt IndicSyllabicCategory-Additional.txt IndicPositionalCategory-Additional.txt
+ *
+ * on files with these headers:
+ *
+ * # IndicSyllabicCategory-15.1.0.txt
+ * # Date: 2023-01-05
+ * # IndicPositionalCategory-15.1.0.txt
+ * # Date: 2023-01-05
+ * # ArabicShaping-15.1.0.txt
+ * # Date: 2023-01-05
+ * # DerivedCoreProperties-15.1.0.txt
+ * # Date: 2023-08-07, 15:21:24 GMT
+ * # Blocks-15.1.0.txt
+ * # Date: 2023-07-28, 15:47:20 GMT
+ * # Scripts-15.1.0.txt
+ * # Date: 2023-07-28, 16:01:07 GMT
+ * # Override values For Indic_Syllabic_Category
+ * # Not derivable
+ * # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
+ * # Updated for Unicode 10.0 by Andrew Glass 2017-07-25
+ * # Updated for Unicode 12.1 by Andrew Glass 2019-05-24
+ * # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
+ * # Updated for Unicode 14.0 by Andrew Glass 2021-09-25
+ * # Updated for Unicode 15.0 by Andrew Glass 2022-09-16
+ * # Updated for Unicode 15.1 by Andrew Glass 2023-09-14
+ * # Override values For Indic_Positional_Category
+ * # Not derivable
+ * # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
+ * # Updated for Unicode 10.0 by Andrew Glass 2017-07-25
+ * # Ammended for Unicode 10.0 by Andrew Glass 2018-09-21
+ * # Updated for L2/19-083    by Andrew Glass 2019-05-06
+ * # Updated for Unicode 12.1 by Andrew Glass 2019-05-30
+ * # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
+ * # Updated for Unicode 14.0 by Andrew Glass 2021-09-28
+ * # Updated for Unicode 15.0 by Andrew Glass 2022-09-16
+ * # Updated for Unicode 15.1 by Andrew Glass 2023-09-14
+ * UnicodeData.txt does not have a header.
+ */
+
+#ifndef HB_OT_SHAPER_USE_TABLE_HH
+#define HB_OT_SHAPER_USE_TABLE_HH
+
+#include "hb.hh"
+
+#include "hb-ot-shaper-use-machine.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 */
+#define G      USE(G)  /* HIEROGLYPH */
+#define GB     USE(GB) /* BASE_OTHER */
+#define H      USE(H)  /* HALANT */
+#define HM     USE(HM) /* HIEROGLYPH_MOD */
+#define HN     USE(HN) /* HALANT_NUM */
+#define HR     USE(HR) /* HIEROGLYPH_MIRROR */
+#define HVM    USE(HVM)        /* HALANT_OR_VOWEL_MODIFIER */
+#define IS     USE(IS) /* INVISIBLE_STACKER */
+#define J      USE(J)  /* HIEROGLYPH_JOINER */
+#define N      USE(N)  /* BASE_NUM */
+#define O      USE(O)  /* OTHER */
+#define R      USE(R)  /* REPHA */
+#define SB     USE(SB) /* HIEROGLYPH_SEGMENT_BEGIN */
+#define SE     USE(SE) /* HIEROGLYPH_SEGMENT_END */
+#define SUB    USE(SUB)        /* CONS_SUB */
+#define Sk     USE(Sk) /* SAKOT */
+#define WJ     USE(WJ) /* Word_Joiner */
+#define ZWNJ   USE(ZWNJ)       /* ZWNJ */
+#define CMAbv  USE(CMAbv)
+#define CMBlw  USE(CMBlw)
+#define FAbv   USE(FAbv)
+#define FBlw   USE(FBlw)
+#define FPst   USE(FPst)
+#define FMAbv  USE(FMAbv)
+#define FMBlw  USE(FMBlw)
+#define FMPst  USE(FMPst)
+#define MAbv   USE(MAbv)
+#define MBlw   USE(MBlw)
+#define MPst   USE(MPst)
+#define MPre   USE(MPre)
+#define SMAbv  USE(SMAbv)
+#define SMBlw  USE(SMBlw)
+#define VAbv   USE(VAbv)
+#define VBlw   USE(VBlw)
+#define VPst   USE(VPst)
+#define VPre   USE(VPre)
+#define VMAbv  USE(VMAbv)
+#define VMBlw  USE(VMBlw)
+#define VMPst  USE(VMPst)
+#define VMPre  USE(VMPre)
+#pragma GCC diagnostic pop
+
+
+#ifndef HB_OPTIMIZE_SIZE
+
+static const uint8_t
+hb_use_u8[3187] =
+{
+     16,   50,   51,   51,   51,   52,   51,   83,  118,  131,   51,   57,   58,  179,  195,   61,
+     51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
+     51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
+     51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
+     51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
+     51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
+     51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
+     14,    0,    1,    2,    2,    2,    2,    3,    2,    2,    2,    2,    2,    4,    2,    2,
+      5,    6,    2,    7,    8,    9,   10,   11,   12,   13,   14,   15,   16,    2,    2,   17,
+     18,   19,   20,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   21,
+     22,   23,   24,   25,   26,   27,   28,   29,   30,   31,   32,    2,   33,    2,    2,    2,
+      2,   34,   35,    2,    2,    2,    2,    2,    2,    2,    2,    2,   36,    2,    2,    2,
+     37,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   38,    2,   39,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,   40,   41,   42,   43,   44,   45,    2,   46,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   47,   48,    2,
+     49,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   50,   51,    2,    2,    2,
+      2,    2,    2,    2,    2,   52,   53,    2,   54,    2,    2,   55,    2,    2,   56,   57,
+     58,   59,   60,   61,   62,   63,   64,   65,    2,   66,   67,    2,   68,   69,   70,   71,
+      2,   72,    2,   73,   74,   75,   76,    2,    2,   77,   78,   79,   80,    2,   81,   82,
+      2,   83,   83,   83,   83,   83,   83,   83,   83,   84,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,   85,   86,    2,    2,    2,    2,    2,    2,    2,   87,
+     88,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,   89,   89,   89,   90,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,   91,   92,    2,    2,    2,    2,    2,
+      2,    2,    2,   93,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,   94,    2,    2,   95,    2,    2,    2,   96,    2,    2,    2,    2,    2,
+      2,    2,    2,   97,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,   98,   98,   99,  100,   98,   98,   98,   98,   98,   98,   98,   98,   98,   98,   98,
+     98,   98,   98,   98,   98,   98,   98,   98,   98,   98,   98,   98,   98,   98,   98,   98,
+     98,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,
+      0,    2,    2,    2,    2,    2,    0,    0,    0,    0,    0,    0,    0,    0,    3,    4,
+      0,    5,    0,    0,    0,    0,    0,    6,    0,    0,    7,    0,    0,    0,    0,    0,
+      0,    0,    0,    0,    1,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+      8,    9,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   10,   11,
+     11,   11,   11,    0,    0,    0,    9,   12,    0,    2,    2,    2,    2,   13,   14,    0,
+      0,   11,   15,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   16,   17,
+     18,   19,   20,   21,   22,   16,   23,   24,   25,   12,   26,   27,   20,    2,    2,    2,
+      2,    2,   20,    0,    2,    2,    2,    2,    2,    0,    2,    2,    2,    2,    2,    2,
+      2,   28,   29,   30,    2,    2,    2,    9,   30,    9,   30,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    9,    2,    2,    2,    9,    9,    0,    2,    2,    0,   17,
+     18,   19,   20,   31,   32,   33,   32,   34,    0,    0,    0,    0,   35,    0,    0,    2,
+     30,    2,    0,    0,    0,    0,    0,    9,   36,   12,   15,   30,    2,    2,    9,    0,
+     30,    9,    2,   30,    9,    2,    0,   37,   18,   19,   31,    0,   27,   38,   27,   39,
+      0,   40,    0,    0,    0,   30,    2,    9,    9,    0,    0,    0,    2,    2,    2,    2,
+      2,   41,   42,   43,    0,    0,    0,    0,    0,   12,   15,   30,    2,    2,    2,    2,
+     30,    2,   30,    2,    2,    2,    2,    2,    2,    9,    2,   30,    2,    2,    0,   17,
+     18,   19,   20,   21,   27,   22,   35,   24,    0,    0,    0,    0,    0,   30,   41,   41,
+     44,   12,   29,   30,    2,    2,    2,    9,   30,    9,    2,   30,    2,    2,    0,   17,
+     45,    0,    0,   27,   22,    0,    0,    2,   30,   30,    0,    0,    0,    0,    0,    0,
+      0,    0,   46,   30,    2,    2,    9,    0,    2,    9,    2,    2,    0,   30,    9,    9,
+      2,    0,   30,    9,    0,    2,    9,    0,    2,    2,    2,    2,    2,    2,    0,    0,
+     23,   16,   47,    0,   48,   33,   48,   34,    0,    0,    0,    0,   35,    0,    0,    0,
+      0,   15,   29,   49,    2,    2,    2,    9,    2,    9,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    0,   17,   22,   16,   23,   47,   22,   38,   22,   39,
+      0,    0,    0,   27,   31,    2,    9,    0,    0,   10,   29,   30,    2,    2,    2,    9,
+      2,    2,    2,   30,    2,    2,    0,   17,   45,    0,    0,   35,   47,    0,    0,    0,
+      9,   50,   51,    0,    0,    0,    0,    0,    0,   11,   29,    2,    2,    2,    2,    9,
+      2,    2,    2,    2,    2,    2,   52,   53,   23,   23,   19,   31,   48,   33,   48,   34,
+     54,    0,    0,    0,   35,    0,    0,    0,   30,   12,   29,   30,    2,    2,    2,    2,
+      2,    2,    2,    2,    9,    0,    2,    2,    2,    2,   30,    2,    2,    2,    2,   30,
+      0,    2,    2,    2,    9,    0,   55,    0,   35,   23,   22,   31,   31,   18,   48,   48,
+     25,    0,   23,    0,    0,    0,    0,    0,    0,    2,    0,    2,    9,    0,    0,    0,
+      0,    0,    0,    0,    0,   20,    0,    0,    0,    2,    2,   56,   56,   57,    0,    0,
+     18,    2,    2,    2,    2,   30,    2,    2,    2,    2,    2,    2,    2,    2,    2,    9,
+      0,   58,   21,   59,   22,   22,   20,   20,   46,   21,   11,   31,   11,    2,    2,   60,
+     61,   61,   61,   61,   61,   62,   61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+     61,   61,   61,   61,   61,   61,   61,   63,    0,    0,    0,    0,   64,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,   65,   45,   59,   66,   22,   22,   67,   68,   69,   70,
+     71,    2,    2,    2,    2,    2,    1,    0,    5,    2,    2,    2,   23,   20,    2,    2,
+     72,   71,   73,   74,   65,   73,   29,   29,    2,   52,   22,   53,    2,    2,    2,    2,
+      2,    2,   75,   76,   77,   29,   29,   78,   79,    2,    2,    2,    2,    2,   29,   45,
+      0,    2,   59,   80,    0,    0,    0,    0,   30,    2,   59,   47,    0,    0,    0,    0,
+      0,    2,   59,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,    9,
+      2,    9,   59,    0,    0,    0,    0,    0,    0,    2,    2,   81,   45,   22,   59,   20,
+     48,   48,   48,   48,   15,   82,   83,   84,   85,   86,   87,    0,    0,    0,    0,   88,
+      0,    9,    0,    0,   30,    0,   89,   81,   90,    2,    2,    2,    2,    9,    0,    0,
+      0,   42,   42,   91,   92,    2,    2,    2,    2,    2,    2,    2,    2,   13,    9,    0,
+      0,   93,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      9,   22,   80,   45,   22,   94,   61,    0,    0,   95,   96,   95,   95,   97,   98,    0,
+      0,    2,    2,    2,    2,    2,    2,    2,    0,    2,    2,    9,    0,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    2,    0,    0,    2,    2,    2,    2,   29,    0,    0,
+      0,    2,    2,    2,    2,    2,    9,    0,    0,    2,    2,    2,   52,   99,   45,    0,
+      0,    2,    2,  100,  101,  102,  103,   61,   63,  104,   16,   45,   22,   59,   21,   80,
+     48,   48,   76,   11,   11,   11,  105,   46,   40,   11,  106,   74,    2,    2,    2,    2,
+      2,    2,    2,  107,   22,   20,   20,   22,   48,   48,   22,  108,    2,    2,    2,    9,
+      0,    0,    0,    0,    0,    0,  109,  110,  111,  111,  111,    0,    0,    0,    0,    0,
+      0,  106,   74,    2,    2,    2,    2,    2,    2,   60,   61,   59,   25,   22,  112,   61,
+      2,    2,    2,    2,  107,   22,   23,   45,   45,  102,   14,    0,    0,    0,    0,    0,
+      0,    2,    2,   61,   18,   48,   23,  113,  102,  102,  102,  114,  115,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    0,   30,    2,   11,   46,  116,  116,  116,   11,  116,
+    116,   15,  116,  116,  116,   26,    0,   40,    0,    0,    0,  117,   51,   11,    5,    0,
+      0,    0,    0,    0,    0,    0,  118,    0,    0,    0,    0,    0,    0,    0,    6,  119,
+    120,   42,   42,    5,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,  120,  120,
+    121,  120,  120,  120,  120,  120,  120,  120,  120,    0,    0,  122,    0,    0,    0,    0,
+      0,    0,    7,  122,    0,    0,    0,    0,    0,   46,    0,    0,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,    0,    0,    9,    0,    0,    0,    0,  123,  123,    0,    0,
+      0,    2,    2,    2,    2,    0,    0,    0,   30,    0,    0,    0,    0,    0,    0,    0,
+    124,    0,  123,  123,    0,    0,    0,    0,    0,    2,   53,    2,  108,    2,   10,    2,
+      2,    2,   65,   19,   16,    0,    0,   31,    0,    2,    2,    0,    0,    0,    0,    0,
+      0,   29,    2,    2,    2,    2,    2,    2,    2,    2,    2,  125,   23,   23,   23,   23,
+     23,   23,   23,  126,    0,    0,    0,    0,    0,   11,   11,   11,   11,   11,   11,   11,
+     11,   11,    2,    0,    0,    0,    0,    0,   52,    2,    2,    2,   22,   22,  127,  116,
+      0,    2,    2,    2,  128,   20,   59,   20,  113,  102,  129,    0,    0,    0,    0,    0,
+      0,   11,  130,    2,    2,    2,    2,    2,    2,    2,  131,   23,   22,   20,   48,  132,
+    133,  134,    0,    0,    0,    0,    0,    0,    0,    2,    2,   52,   30,    2,    2,    2,
+      2,    2,    2,    2,    2,   10,   22,   59,   99,   76,  135,  136,  137,    0,    0,    0,
+      0,    2,  138,    2,    2,    2,    2,  139,    0,   30,    2,   42,    5,    0,   79,   15,
+      2,   53,   22,  140,   52,   53,    2,    2,  105,   10,    9,    0,    0,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,  141,   21,   25,    0,    0,  142,  143,    0,    0,    0,
+      0,    2,   65,   45,   23,   80,   47,  144,    0,   81,   81,   81,   81,   81,   81,   81,
+     81,    0,    0,    0,    0,    0,    0,    0,    6,  120,  120,  120,  120,  121,    0,    0,
+      0,    2,    2,    2,    2,    2,    9,    2,    2,    2,    9,    2,   30,    2,    2,    2,
+      2,    2,   30,    2,    2,    2,   30,    9,    0,  128,   20,   27,   31,    0,    0,  145,
+    146,    2,    2,   30,    2,   30,    2,    2,    2,    2,    2,    2,    0,   14,   37,    0,
+    147,    2,    2,   13,   37,    0,   30,    2,    2,    2,    0,    0,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,   30,    2,    2,    9,    2,    2,   11,   41,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,   27,   38,    0,    2,    2,    2,  116,  116,  116,  116,
+    116,  148,    2,    9,    0,    0,    0,    0,    0,    2,   14,   14,    0,    0,    0,    0,
+      0,    9,    2,    2,    9,    2,    2,    2,    2,   30,    2,    9,    0,   30,    2,    0,
+      0,  149,  150,  151,    2,    2,    2,    2,    2,    2,    2,    2,    2,   22,   22,   20,
+     20,   20,   22,   22,  134,    0,    0,    0,    0,    0,  152,  152,  152,  152,  152,  152,
+    152,  152,  152,  152,    2,    2,    2,    2,    2,   53,   52,   53,    0,    0,    0,    0,
+    153,   11,   74,    2,    2,    2,    2,    2,    2,   18,   19,   21,   16,   24,   37,    0,
+      0,    0,   31,    0,    0,    0,    0,    0,    0,   11,   49,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,  128,   20,   22,  154,   22,   21,  155,  156,    2,    2,    2,    2,
+      2,    0,    0,   65,  157,    0,    0,    0,    0,    2,   13,    0,    0,    0,    0,    0,
+      0,    2,   65,   25,   20,   20,   20,   22,   22,  108,  158,    0,    0,   56,  159,   31,
+    160,   30,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   23,
+     19,   22,   22,  161,   44,    0,    0,    0,   49,  128,    0,    0,    0,    0,    0,    0,
+      0,    2,    2,    2,    9,    9,    2,    2,   30,    2,    2,    2,    2,    2,    2,    2,
+     30,    2,    2,    2,    2,    2,    2,    2,   10,   18,   19,   21,   22,  162,   31,    0,
+      0,   11,   11,   30,    2,    2,    2,    9,   30,    9,    2,   30,    2,    2,   58,   17,
+     23,   16,   23,   47,   32,   33,   32,   34,    0,    0,    0,    0,   35,    0,    0,    0,
+      2,    2,   23,    0,   11,   11,   11,   46,    0,   11,   11,   46,    0,    0,    0,    0,
+      0,    2,    2,   65,   25,   20,   20,   20,   22,   23,  126,   15,   17,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    0,    0,  163,  164,    0,    0,    0,    0,    0,    0,
+      0,   18,   19,   20,   20,   66,   99,   25,  160,   11,  165,    9,    0,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    2,    2,   65,   25,   20,   20,    0,   48,   48,   11,
+    166,   37,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    2,    2,   20,
+      0,   23,   19,   20,   20,   21,   16,   82,  166,   38,    0,    0,    0,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,   10,  167,   25,   20,   22,   22,  165,    9,    0,    0,
+      0,    2,    2,    2,    2,    2,    9,   43,  136,   23,   22,   20,   76,   21,   22,    0,
+      0,    2,    2,    2,    9,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,   18,
+     19,   20,   21,   22,  105,  166,   37,    0,    0,    2,    2,    2,    9,   30,    0,    2,
+      2,    2,    2,   30,    9,    2,    2,    2,    2,   23,   23,   18,   32,   33,   12,  168,
+    169,  170,  171,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    0,    2,    2,
+      2,   65,   25,   20,   20,    0,   22,   23,   29,  108,    0,   33,    0,    0,    0,    0,
+      0,   52,   20,   22,   22,   22,  140,    2,    2,    2,  172,  173,   11,   15,  174,   72,
+    175,    0,    0,    1,  147,    0,    0,    0,    0,   52,   20,   22,   16,   19,   20,    2,
+      2,    2,    2,  158,  158,  158,  176,  176,  176,  176,  176,  176,   15,  177,    0,   30,
+      0,   22,   20,   20,   31,   22,   22,   11,  166,    0,   61,   61,   61,   61,   61,   61,
+     61,   66,   21,   82,   46,    0,    0,    0,    0,    2,    2,    2,    9,    2,   30,    2,
+      2,   52,   22,   22,   31,    0,   38,   22,   27,   11,  159,  178,  174,    0,    0,    0,
+      0,    2,    2,    2,   30,    9,    2,    2,    2,    2,    2,    2,    2,    2,   23,   23,
+     47,   22,   35,   82,   68,    0,    0,    0,    0,    2,  179,   66,   47,    0,    0,    0,
+      0,   11,  180,    2,    2,    2,    2,    2,    2,    2,    2,   23,   22,   20,   31,    0,
+     48,   16,  143,    0,    0,    0,    0,    0,    0,  181,  181,  181,  181,  181,  181,  181,
+    181,  182,  182,  182,  183,  184,  182,  181,  181,  185,  181,  181,  186,  187,  187,  187,
+    187,  187,  187,  187,    0,    0,    0,    0,    0,   11,   11,   11,   46,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    9,    0,   58,  188,   20,   20,   20,   20,   20,   20,
+     20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,    0,    0,    0,
+     40,  116,   26,    0,    0,    0,    0,    0,    0,    0,    0,    9,    0,    0,    0,    0,
+      0,    2,    2,    2,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    0,   58,
+     37,    0,    6,  120,  120,  120,  121,    0,    0,   11,   11,   11,   49,    2,    2,    2,
+      0,    2,    2,    2,    2,    2,    0,    0,    2,    2,    2,    2,    2,    2,    2,    2,
+     46,    2,    2,    2,    2,    2,    2,   11,   11,    2,    2,    2,    2,    2,    2,   22,
+     22,    2,    2,   44,   44,   44,   92,    0,    0,    O,    O,    O,   GB,    B,    B,    O,
+     SB,    O,   SE,   GB,    O,    O,   WJ,FMPst,FMPst,    O,  CGJ,    B,    O,    B,VMAbv,VMAbv,
+  VMAbv,    O,VMAbv,    B,CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw,    B, VPst, VPre, VPst,
+   VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst, VPst, VPst,    H, VPre, VPst,VMBlw,    O,    O,
+   VAbv,   GB,VMAbv,VMPst,VMPst,    O,    B, VBlw,    O,    O, VPre, VPre,    O, VPre,    H,    O,
+   VPst,FMAbv,    O,CMBlw,    O, VAbv,    O, VAbv,    H,    O,VMBlw,VMAbv,CMAbv,   GB,   GB,    O,
+   MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv,    O, VPst,    O, VPre, VPre,VMAbv,    B,    O,   CS,   CS,
+  VMPst,    B, VAbv, VAbv,    B,    R,    O,  HVM,    O,    O,FMBlw,    O,CMAbv,    O,CMBlw, VAbv,
+   VBlw,    B,  SUB,  SUB,  SUB,    O,  SUB,  SUB,    O,FMBlw,    O,    B, VPst, VBlw, VPre,VMAbv,
+  VMBlw,VMPst,   IS, VAbv, MPst, MPre, MBlw, MBlw,    B, MBlw, MBlw, VPst,VMPst,VMPst,    B, MBlw,
+   VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw,    B,VMPst, VBlw, VPst,  CGJ,  CGJ, VPst,VMAbv,VMAbv,
+  FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv,   IS,FMAbv,    B,FMAbv,    B,  CGJ,   WJ,  CGJ,   GB,
+  CMAbv,CMAbv,    B,   GB,    B, VAbv,  SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv,
+   VPre,    B, MPre, MBlw,  SUB, FAbv, FAbv, MAbv,  SUB,   Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv,
+   VPst,    H,    B,    O,SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst,   IS, VBlw, FAbv,VMPre,VMPre,FMAbv,
+  CMBlw,VMBlw,VMBlw,VMAbv,   CS,    O,FMAbv, ZWNJ,  CGJ,   WJ,   WJ,   WJ,    O,FMPst,    O,   SB,
+     SE,    O,    H, MPst, VPst,    H,VMAbv, VAbv,VMBlw,    B, VBlw, FPst, VPst, FAbv,VMPst,    B,
+  CMAbv, VAbv, MBlw, MPst, MBlw,    H,    O, VBlw, MPst, MPre, MAbv, MBlw,    O,    B, FAbv, FAbv,
+   FPst, VBlw,    B,    B, VPre,    O,VMPst,   IS,    O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv,    O,
+     IS,VMBlw,    B,VMPst,VMAbv,VMPst,   CS,   CS,    B,    N,    N,    O,   HN, VPre, VBlw, VAbv,
+     IS,CMAbv,    O, VPst,    B,    R,    R,CMBlw, VAbv, VPre,VMAbv,VMAbv,    H, VAbv,CMBlw,FMAbv,
+      B,   CS,   CS,    H,CMBlw,VMPst,    H,VMPst, VAbv,VMAbv, VPst,   IS,    R, MPst,    R, MPst,
+  CMBlw,    B,FMBlw, VBlw,VMAbv,    R, MBlw, MBlw,   GB, FBlw, FBlw,CMAbv,   IS, VBlw,   IS,   GB,
+   VAbv,    R,VMPst,    G,    G,    J,    J,    J,   SB,   SE,    J,   HR,    G,    G,   HM,   HM,
+     HM,    O, VBlw,
+};
+static const uint16_t
+hb_use_u16[808] =
+{
+    0,  0,  1,  2,  0,  3,  0,  3,  0,  0,  4,  5,  0,  6,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  7,  0,  0,  0,
+    0,  0,  0,  0,  8,  0,  0,  0,  0,  0,  0,  0,  9, 10, 11, 12,
+    0,  0,  0,  0, 10, 13,  0,  0, 14, 10, 10, 15, 16, 17, 18, 19,
+   20, 21, 22, 23, 24, 25, 18, 26, 27, 21, 22, 28, 29, 30, 31, 32,
+   33, 34, 22, 35, 36,  0, 18, 37, 38, 21, 22, 39, 24, 40, 18, 41,
+   42, 43, 44, 45, 46, 47, 31,  0, 48, 49, 22, 50, 51, 52, 18,  0,
+   53, 49, 22, 54, 51, 55, 18, 56, 57, 49, 10, 58, 59, 60, 18,  0,
+   61, 62, 10, 63, 64, 65, 31, 66, 67, 68, 10, 69, 70, 10, 71, 72,
+   73, 74, 75, 76, 77,  0,  0,  0, 10, 10, 78, 79, 80, 81, 82, 83,
+   84, 85,  0,  0,  0,  0,  0,  0, 10, 86, 10, 87, 10, 88, 89, 90,
+   10, 10, 10, 91, 92, 93,  2,  0, 94,  0, 10, 10, 10, 10, 10, 95,
+   96, 10, 97,  0,  0,  0,  0,  0, 98, 99,100,101, 31, 10,102,103,
+   10, 10,104, 10,105,106,  0,  0, 10,107, 10, 10, 10,108,109,110,
+    2,  2,  0,  0,  0,  0,  0,  0,111, 10, 10,112,113,  2,114,115,
+  116, 10,117, 10, 10, 10,118,119, 10, 10,120,121,122,  0,  0,  0,
+    0,  0,  0,  0,  0,123,124,125,  0,  0,  0,  0,  0,  0,  0,126,
+  127,128,129,  0,  0,  0,130,131,132,  0,  0,  0,  0,  0,  0,133,
+    0,  0,  0,  0,134,  0,  0,  0,  0,  0,  0,  0,  0,  0,135,  0,
+    0,  0,  0, 10, 10, 10,136,137,  0,  0,138,  0,  0,  0,  0,  0,
+  139, 10,140,  0, 10, 10, 10,141,142, 10, 10,143,144,  2,145,146,
+   10, 10,147, 10,148,149,  0,  0,150, 10, 10,151,152,  2,153, 99,
+   10, 10,154,155,156,  2, 10,157, 10, 10, 10,158,159,  0,160,161,
+    0,  0,  0,  0, 10, 10,162,  2,163,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,164,  0,  0,  0,  0,  0,  0,  0,165,
+    0,  0,  0,  0,  0,  0,  0,166,166,167, 34,168,  0,  0,  0,  0,
+  169,170, 10,171, 95,  0,  0,  0,  0,  0,  0,  0, 70, 10,172,  0,
+   10,173,174,  0,  0,  0,  0,  0, 10, 10,175,  2,  0,  0,  0,  0,
+   10, 10,176,173,  0,  0,  0,  0,  0,  0,  0, 10,177,178,  0, 10,
+  179,  0,  0,180,181,  0,  0,  0,182, 10, 10,183,184,185,186,187,
+  188, 10, 10,189,190,  0,  0,  0,191, 10,192,193,194, 10, 10,195,
+  188, 10, 10,196,197,106,198,103, 10, 34,199,200,201,  0,  0,  0,
+  202,203, 95, 10, 10,204,205,  2,206, 21, 22,207,208,209,210,211,
+   10, 10, 10,212,213,214,215,  0,198, 10, 10,216,217,  2,  0,  0,
+   10, 10,218,219,220,221,  0,  0, 10, 10, 10,222,223,  2,  0,  0,
+   10, 10,224,225,  2,  0,  0,  0, 10,226,227,104,228,  0,  0,  0,
+   10, 10,229,230,  0,  0,  0,  0,231,232, 10,233,234,  2,  0,  0,
+    0,  0,235, 10, 10,236,237,  0,238, 10, 10,239,240,241, 10, 10,
+  242,243,  0,  0,  0,  0,  0,  0, 22, 10,218,244,  8, 10, 71, 19,
+   10,245, 74,246,  0,  0,  0,  0,247, 10, 10,248,249,  2,250, 10,
+  251,252,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 10,253,
+  254, 49, 10,255,256,  2,  0,  0,257,257,257,257,257,257,257,257,
+  257,257,257,258,259,260,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,
+   10, 10, 10,261,  0,  0,  0,  0, 10, 10, 10, 10,262,263,264,264,
+  265,266,  0,  0,  0,  0,267,  0, 10, 10, 10, 10, 10, 10, 10, 10,
+   10, 10, 10, 10, 10,268,  0,  0, 10, 10, 10, 10, 10, 10,106, 71,
+   95,269,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,270,
+   10, 10, 71,271,272,  0,  0,  0,  0, 10,273,  0, 10, 10,274,  2,
+    0,  0,  0,  0,  0, 10,275,  2, 10, 10, 10, 10,276,  2,  0,  0,
+  130,130,130,130,130,130,130,130,163,163,163,163,163,163,163,163,
+  163,163,163,163,163,163,163,130,
+};
+
+static inline unsigned
+hb_use_b4 (const uint8_t* a, unsigned i)
+{
+  return (a[i>>1]>>((i&1u)<<2))&15u;
+}
+static inline uint_fast8_t
+hb_use_get_category (unsigned u)
+{
+  return u<921600u?hb_use_u8[2809+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
+}
+
+
+#else
+
+static const uint8_t
+hb_use_u8[3483] =
+{
+     16,   50,   51,   51,   51,   52,   51,   83,  118,  131,   51,   57,   58,  179,  195,   61,
+     51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
+     51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
+     51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
+     51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
+     51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
+     51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
+     14,    0,    1,    1,    2,    1,    1,    3,    4,    5,    6,    7,    8,    9,   10,    1,
+     11,   12,    1,    1,    1,    1,    1,    1,   13,   14,   15,   16,   17,   18,   19,    1,
+      1,   20,    1,    1,    1,    1,   21,    1,   22,    1,    1,    1,    1,    1,   23,   24,
+      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,   25,   26,   27,   28,    1,    1,    1,
+      1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   29,
+     30,    1,    1,    1,    1,    1,   31,    1,    1,    1,    1,   32,   33,    1,   34,   35,
+     36,   37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,    1,   48,   49,   50,
+     51,   52,   52,   52,   52,   53,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+      1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   54,   55,    1,    1,    1,
+     56,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   57,   58,    1,    1,
+      1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   59,    1,    1,
+      1,    1,   60,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+      1,    1,   61,   62,    1,   63,    1,    1,    1,    1,   64,    1,    1,    1,    1,    1,
+      1,   65,   66,   65,   65,   65,   65,   65,   65,   65,   65,   65,   65,   65,   65,   65,
+     65,    0,    1,    2,    2,    0,    3,    4,    0,    0,    0,    0,    0,    0,    0,    0,
+      0,    0,    0,    5,    0,    0,    0,    0,    0,    0,    0,    6,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,    0,    0,    7,    8,    0,    0,    9,    0,    0,    0,    0,
+      0,   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,   37,   45,   46,   47,   48,   49,   50,   51,   52,   53,   54,   55,
+      0,   56,   57,   58,   59,   60,    0,    0,    0,   61,   62,   63,   64,   56,   65,   66,
+     67,   68,   56,   56,   69,   70,   71,    0,    0,   72,   73,   74,   75,   56,   76,   77,
+      0,   78,   56,   79,   80,   81,    0,    0,    0,   82,   83,   84,   85,   86,   87,   56,
+     88,   56,   89,   90,    0,    0,    0,   91,   92,    0,    0,    0,    0,    0,    0,    0,
+     93,   94,   95,    0,   96,   97,    0,    0,   98,    0,    0,    0,    0,    0,    0,   99,
+      0,    0,    0,    0,    0,    0,    0,    0,  100,    0,  101,   56,  102,    0,    0,    0,
+      0,    0,  103,    0,    0,    0,    0,    0,    0,  104,  105,   56,  106,  107,  108,  109,
+    110,   56,  111,  112,    0,  113,  114,  115,  116,   56,  117,  118,  119,   56,  120,  121,
+    122,    0,    0,    0,    0,    0,    0,   56,  123,  124,    0,    0,    0,    0,    0,    0,
+    125,    0,    0,    0,    0,    0,    0,    0,  126,    0,    0,    0,  127,  128,  129,    0,
+      0,  130,  131,  132,    0,    0,    0,   51,  133,    0,    0,    0,    0,  134,  135,    0,
+      0,   56,  136,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   56,  137,    0,
+      0,    0,  101,  138,  101,  139,  140,  141,    0,  142,  143,  144,  145,  146,  147,  148,
+      0,  149,  150,  151,  152,  146,  153,  154,  155,  156,  157,  158,    0,  159,  160,  161,
+    162,  163,  164,  165,  166,    0,    0,    0,    0,   56,  167,  168,  169,  170,  171,  172,
+      0,    0,    0,    0,    0,   56,  173,  174,    0,   56,  175,  176,    0,   56,  177,   67,
+      0,  178,  179,  180,    0,    0,    0,    0,    0,   56,  181,    0,    0,    0,    0,    0,
+      0,  182,  183,  184,    0,    0,  185,  186,  187,  188,  189,  190,   56,  191,    0,    0,
+      0,  192,  193,  194,  195,  196,  197,    0,    0,  198,  199,  200,  201,  202,   67,    0,
+      0,    0,    0,    0,    0,    0,    0,    0,  203,  204,  205,  206,    0,    0,    0,    0,
+      0,  207,  207,  207,  207,  207,  207,  207,  207,  207,  208,  209,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,    0,    0,   67,    0,   56,  210,    0,    0,    0,    0,    0,
+      0,   56,   56,  211,  212,  213,    0,    0,  214,   56,   56,   56,   56,   56,   56,   56,
+     56,   56,   56,   56,   56,   56,   56,  215,    0,   56,   56,   56,  216,  217,    0,    0,
+      0,    0,    0,    0,  218,    0,    0,    0,    0,   56,  219,  220,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,  101,  221,   56,  222,    0,    0,    0,    0,    0,    0,  101,
+    223,   56,   56,  224,    0,    0,    0,    0,    0,  225,  225,  225,  225,  225,  225,  225,
+    225,  226,  226,  226,  226,  226,  226,  226,  227,    0,    0,    0,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,    0,    0,    1,    0,    2,    2,    2,    2,    2,    0,    0,
+      0,    0,    0,    0,    0,    0,    3,    4,    0,    5,    0,    0,    0,    0,    0,    6,
+      0,    0,    7,    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,    0,    0,    0,
+      0,    0,    0,    0,    0,    0,    0,    0,    8,    9,    0,    0,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,   10,   11,   11,   11,   11,    0,    0,    0,    9,   12,
+      0,    2,    2,    2,    2,   13,   14,    0,    0,   11,   15,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,   16,   17,   18,   19,   20,   21,   22,   16,   23,   24,
+     25,   12,   26,   27,   20,    2,    2,    2,    2,    2,   20,    0,    2,    2,    2,    2,
+      2,    0,    2,    2,    2,    2,    2,    2,    2,   28,   29,   30,    2,    2,    2,    9,
+     30,    9,   30,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    9,    2,    2,
+      2,    9,    9,    0,    2,    2,    0,   17,   18,   19,   20,   31,   32,   33,   32,   34,
+      0,    0,    0,    0,   35,    0,    0,    2,   30,    2,    0,    0,    0,    0,    0,    9,
+     36,   12,   15,   30,    2,    2,    9,    0,   30,    9,    2,   30,    9,    2,    0,   37,
+     18,   19,   31,    0,   27,   38,   27,   39,    0,   40,    0,    0,    0,   30,    2,    9,
+      9,    0,    0,    0,    2,    2,    2,    2,    2,   41,   42,   43,    0,    0,    0,    0,
+      0,   12,   15,   30,    2,    2,    2,    2,   30,    2,   30,    2,    2,    2,    2,    2,
+      2,    9,    2,   30,    2,    2,    0,   17,   18,   19,   20,   21,   27,   22,   35,   24,
+      0,    0,    0,    0,    0,   30,   41,   41,   44,   12,   29,   30,    2,    2,    2,    9,
+     30,    9,    2,   30,    2,    2,    0,   17,   45,    0,    0,   27,   22,    0,    0,    2,
+     30,   30,    0,    0,    0,    0,    0,    0,    0,    0,   46,   30,    2,    2,    9,    0,
+      2,    9,    2,    2,    0,   30,    9,    9,    2,    0,   30,    9,    0,    2,    9,    0,
+      2,    2,    2,    2,    2,    2,    0,    0,   23,   16,   47,    0,   48,   33,   48,   34,
+      0,    0,    0,    0,   35,    0,    0,    0,    0,   15,   29,   49,    2,    2,    2,    9,
+      2,    9,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    0,   17,
+     22,   16,   23,   47,   22,   38,   22,   39,    0,    0,    0,   27,   31,    2,    9,    0,
+      0,   10,   29,   30,    2,    2,    2,    9,    2,    2,    2,   30,    2,    2,    0,   17,
+     45,    0,    0,   35,   47,    0,    0,    0,    9,   50,   51,    0,    0,    0,    0,    0,
+      0,   11,   29,    2,    2,    2,    2,    9,    2,    2,    2,    2,    2,    2,   52,   53,
+     23,   23,   19,   31,   48,   33,   48,   34,   54,    0,    0,    0,   35,    0,    0,    0,
+     30,   12,   29,   30,    2,    2,    2,    2,    2,    2,    2,    2,    9,    0,    2,    2,
+      2,    2,   30,    2,    2,    2,    2,   30,    0,    2,    2,    2,    9,    0,   55,    0,
+     35,   23,   22,   31,   31,   18,   48,   48,   25,    0,   23,    0,    0,    0,    0,    0,
+      0,    2,    0,    2,    9,    0,    0,    0,    0,    0,    0,    0,    0,   20,    0,    0,
+      0,    2,    2,   56,   56,   57,    0,    0,   18,    2,    2,    2,    2,   30,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    9,    0,   58,   21,   59,   22,   22,   20,   20,
+     46,   21,   11,   31,   11,    2,    2,   60,   61,   61,   61,   61,   61,   62,   61,   61,
+     61,   61,   61,   61,   61,   61,   61,   61,   61,   61,   61,   61,   61,   61,   61,   63,
+      0,    0,    0,    0,   64,    0,    0,    0,    0,    2,    2,    2,    2,    2,   65,   45,
+     59,   66,   22,   22,   67,   68,   69,   70,   71,    2,    2,    2,    2,    2,    1,    0,
+      5,    2,    2,    2,   23,   20,    2,    2,   72,   71,   73,   74,   65,   73,   29,   29,
+      2,   52,   22,   53,    2,    2,    2,    2,    2,    2,   75,   76,   77,   29,   29,   78,
+     79,    2,    2,    2,    2,    2,   29,   45,    0,    2,   59,   80,    0,    0,    0,    0,
+     30,    2,   59,   47,    0,    0,    0,    0,    0,    2,   59,    0,    0,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    2,    9,    2,    9,   59,    0,    0,    0,    0,    0,
+      0,    2,    2,   81,   45,   22,   59,   20,   48,   48,   48,   48,   15,   82,   83,   84,
+     85,   86,   87,    0,    0,    0,    0,   88,    0,    9,    0,    0,   30,    0,   89,   81,
+     90,    2,    2,    2,    2,    9,    0,    0,    0,   42,   42,   91,   92,    2,    2,    2,
+      2,    2,    2,    2,    2,   13,    9,    0,    0,   93,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    9,   22,   80,   45,   22,   94,   61,    0,
+      0,   95,   96,   95,   95,   97,   98,    0,    0,    2,    2,    2,    2,    2,    2,    2,
+      0,    2,    2,    9,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,    0,
+      0,    2,    2,    2,    2,   29,    0,    0,    0,    2,    2,    2,    2,    2,    9,    0,
+      0,    2,    2,    2,   52,   99,   45,    0,    0,    2,    2,  100,  101,  102,  103,   61,
+     63,  104,   16,   45,   22,   59,   21,   80,   48,   48,   76,   11,   11,   11,  105,   46,
+     40,   11,  106,   74,    2,    2,    2,    2,    2,    2,    2,  107,   22,   20,   20,   22,
+     48,   48,   22,  108,    2,    2,    2,    9,    0,    0,    0,    0,    0,    0,  109,  110,
+    111,  111,  111,    0,    0,    0,    0,    0,    0,  106,   74,    2,    2,    2,    2,    2,
+      2,   60,   61,   59,   25,   22,  112,   61,    2,    2,    2,    2,  107,   22,   23,   45,
+     45,  102,   14,    0,    0,    0,    0,    0,    0,    2,    2,   61,   18,   48,   23,  113,
+    102,  102,  102,  114,  115,    0,    0,    0,    0,    2,    2,    2,    2,    2,    0,   30,
+      2,   11,   46,  116,  116,  116,   11,  116,  116,   15,  116,  116,  116,   26,    0,   40,
+      0,    0,    0,  117,   51,   11,    5,    0,    0,    0,    0,    0,    0,    0,  118,    0,
+      0,    0,    0,    0,    0,    0,    6,  119,  120,   42,   42,    5,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,    0,  120,  120,  121,  120,  120,  120,  120,  120,  120,  120,
+    120,    0,    0,  122,    0,    0,    0,    0,    0,    0,    7,  122,    0,    0,    0,    0,
+      0,   46,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    9,
+      0,    0,    0,    0,  123,  123,    0,    0,    0,    2,    2,    2,    2,    0,    0,    0,
+     30,    0,    0,    0,    0,    0,    0,    0,  124,    0,  123,  123,    0,    0,    0,    0,
+      0,    2,   53,    2,  108,    2,   10,    2,    2,    2,   65,   19,   16,    0,    0,   31,
+      0,    2,    2,    0,    0,    0,    0,    0,    0,   29,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,  125,   23,   23,   23,   23,   23,   23,   23,  126,    0,    0,    0,    0,
+      0,   11,   11,   11,   11,   11,   11,   11,   11,   11,    2,    0,    0,    0,    0,    0,
+     52,    2,    2,    2,   22,   22,  127,  116,    0,    2,    2,    2,  128,   20,   59,   20,
+    113,  102,  129,    0,    0,    0,    0,    0,    0,   11,  130,    2,    2,    2,    2,    2,
+      2,    2,  131,   23,   22,   20,   48,  132,  133,  134,    0,    0,    0,    0,    0,    0,
+      0,    2,    2,   52,   30,    2,    2,    2,    2,    2,    2,    2,    2,   10,   22,   59,
+     99,   76,  135,  136,  137,    0,    0,    0,    0,    2,  138,    2,    2,    2,    2,  139,
+      0,   30,    2,   42,    5,    0,   79,   15,    2,   53,   22,  140,   52,   53,    2,    2,
+    105,   10,    9,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,  141,   21,
+     25,    0,    0,  142,  143,    0,    0,    0,    0,    2,   65,   45,   23,   80,   47,  144,
+      0,   81,   81,   81,   81,   81,   81,   81,   81,    0,    0,    0,    0,    0,    0,    0,
+      6,  120,  120,  120,  120,  121,    0,    0,    0,    2,    2,    2,    2,    2,    9,    2,
+      2,    2,    9,    2,   30,    2,    2,    2,    2,    2,   30,    2,    2,    2,   30,    9,
+      0,  128,   20,   27,   31,    0,    0,  145,  146,    2,    2,   30,    2,   30,    2,    2,
+      2,    2,    2,    2,    0,   14,   37,    0,  147,    2,    2,   13,   37,    0,   30,    2,
+      2,    2,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   30,    2,    2,
+      9,    2,    2,   11,   41,    0,    0,    0,    0,    2,    2,    2,    2,    2,   27,   38,
+      0,    2,    2,    2,  116,  116,  116,  116,  116,  148,    2,    9,    0,    0,    0,    0,
+      0,    2,   14,   14,    0,    0,    0,    0,    0,    9,    2,    2,    9,    2,    2,    2,
+      2,   30,    2,    9,    0,   30,    2,    0,    0,  149,  150,  151,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,   22,   22,   20,   20,   20,   22,   22,  134,    0,    0,    0,
+      0,    0,  152,  152,  152,  152,  152,  152,  152,  152,  152,  152,    2,    2,    2,    2,
+      2,   53,   52,   53,    0,    0,    0,    0,  153,   11,   74,    2,    2,    2,    2,    2,
+      2,   18,   19,   21,   16,   24,   37,    0,    0,    0,   31,    0,    0,    0,    0,    0,
+      0,   11,   49,    2,    2,    2,    2,    2,    2,    2,    2,    2,  128,   20,   22,  154,
+     22,   21,  155,  156,    2,    2,    2,    2,    2,    0,    0,   65,  157,    0,    0,    0,
+      0,    2,   13,    0,    0,    0,    0,    0,    0,    2,   65,   25,   20,   20,   20,   22,
+     22,  108,  158,    0,    0,   56,  159,   31,  160,   30,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,   23,   19,   22,   22,  161,   44,    0,    0,    0,
+     49,  128,    0,    0,    0,    0,    0,    0,    0,    2,    2,    2,    9,    9,    2,    2,
+     30,    2,    2,    2,    2,    2,    2,    2,   30,    2,    2,    2,    2,    2,    2,    2,
+     10,   18,   19,   21,   22,  162,   31,    0,    0,   11,   11,   30,    2,    2,    2,    9,
+     30,    9,    2,   30,    2,    2,   58,   17,   23,   16,   23,   47,   32,   33,   32,   34,
+      0,    0,    0,    0,   35,    0,    0,    0,    2,    2,   23,    0,   11,   11,   11,   46,
+      0,   11,   11,   46,    0,    0,    0,    0,    0,    2,    2,   65,   25,   20,   20,   20,
+     22,   23,  126,   15,   17,    0,    0,    0,    0,    2,    2,    2,    2,    2,    0,    0,
+    163,  164,    0,    0,    0,    0,    0,    0,    0,   18,   19,   20,   20,   66,   99,   25,
+    160,   11,  165,    9,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,    2,
+     65,   25,   20,   20,    0,   48,   48,   11,  166,   37,    0,    0,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,    2,    2,   20,    0,   23,   19,   20,   20,   21,   16,   82,
+    166,   38,    0,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,   10,  167,
+     25,   20,   22,   22,  165,    9,    0,    0,    0,    2,    2,    2,    2,    2,    9,   43,
+    136,   23,   22,   20,   76,   21,   22,    0,    0,    2,    2,    2,    9,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    2,   18,   19,   20,   21,   22,  105,  166,   37,    0,
+      0,    2,    2,    2,    9,   30,    0,    2,    2,    2,    2,   30,    9,    2,    2,    2,
+      2,   23,   23,   18,   32,   33,   12,  168,  169,  170,  171,    0,    0,    0,    0,    0,
+      0,    2,    2,    2,    2,    0,    2,    2,    2,   65,   25,   20,   20,    0,   22,   23,
+     29,  108,    0,   33,    0,    0,    0,    0,    0,   52,   20,   22,   22,   22,  140,    2,
+      2,    2,  172,  173,   11,   15,  174,   72,  175,    0,    0,    1,  147,    0,    0,    0,
+      0,   52,   20,   22,   16,   19,   20,    2,    2,    2,    2,  158,  158,  158,  176,  176,
+    176,  176,  176,  176,   15,  177,    0,   30,    0,   22,   20,   20,   31,   22,   22,   11,
+    166,    0,   61,   61,   61,   61,   61,   61,   61,   66,   21,   82,   46,    0,    0,    0,
+      0,    2,    2,    2,    9,    2,   30,    2,    2,   52,   22,   22,   31,    0,   38,   22,
+     27,   11,  159,  178,  174,    0,    0,    0,    0,    2,    2,    2,   30,    9,    2,    2,
+      2,    2,    2,    2,    2,    2,   23,   23,   47,   22,   35,   82,   68,    0,    0,    0,
+      0,    2,  179,   66,   47,    0,    0,    0,    0,   11,  180,    2,    2,    2,    2,    2,
+      2,    2,    2,   23,   22,   20,   31,    0,   48,   16,  143,    0,    0,    0,    0,    0,
+      0,  181,  181,  181,  181,  181,  181,  181,  181,  182,  182,  182,  183,  184,  182,  181,
+    181,  185,  181,  181,  186,  187,  187,  187,  187,  187,  187,  187,    0,    0,    0,    0,
+      0,   11,   11,   11,   46,    0,    0,    0,    0,    2,    2,    2,    2,    2,    9,    0,
+     58,  188,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,
+     20,   20,   20,   20,   20,    0,    0,    0,   40,  116,   26,    0,    0,    0,    0,    0,
+      0,    0,    0,    9,    0,    0,    0,    0,    0,    2,    2,    2,    0,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    0,   58,   37,    0,    6,  120,  120,  120,  121,    0,
+      0,   11,   11,   11,   49,    2,    2,    2,    0,    2,    2,    2,    2,    2,    0,    0,
+      2,    2,    2,    2,    2,    2,    2,    2,   46,    2,    2,    2,    2,    2,    2,   11,
+     11,    2,    2,    2,    2,    2,    2,   22,   22,    2,    2,   44,   44,   44,   92,    0,
+      0,    O,    O,    O,   GB,    B,    B,    O,   SB,    O,   SE,   GB,    O,    O,   WJ,FMPst,
+  FMPst,    O,  CGJ,    B,    O,    B,VMAbv,VMAbv,VMAbv,    O,VMAbv,    B,CMBlw,CMBlw,CMBlw,VMAbv,
+  VMPst, VAbv, VPst,CMBlw,    B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst,
+   VPst, VPst,    H, VPre, VPst,VMBlw,    O,    O, VAbv,   GB,VMAbv,VMPst,VMPst,    O,    B, VBlw,
+      O,    O, VPre, VPre,    O, VPre,    H,    O, VPst,FMAbv,    O,CMBlw,    O, VAbv,    O, VAbv,
+      H,    O,VMBlw,VMAbv,CMAbv,   GB,   GB,    O, MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv,    O, VPst,
+      O, VPre, VPre,VMAbv,    B,    O,   CS,   CS,VMPst,    B, VAbv, VAbv,    B,    R,    O,  HVM,
+      O,    O,FMBlw,    O,CMAbv,    O,CMBlw, VAbv, VBlw,    B,  SUB,  SUB,  SUB,    O,  SUB,  SUB,
+      O,FMBlw,    O,    B, VPst, VBlw, VPre,VMAbv,VMBlw,VMPst,   IS, VAbv, MPst, MPre, MBlw, MBlw,
+      B, MBlw, MBlw, VPst,VMPst,VMPst,    B, MBlw, VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw,    B,
+  VMPst, VBlw, VPst,  CGJ,  CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv,   IS,
+  FMAbv,    B,FMAbv,    B,  CGJ,   WJ,  CGJ,   GB,CMAbv,CMAbv,    B,   GB,    B, VAbv,  SUB, FPst,
+   FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre,    B, MPre, MBlw,  SUB, FAbv, FAbv, MAbv,
+    SUB,   Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst,    H,    B,    O,SMAbv,SMBlw,SMAbv,SMAbv,
+  SMAbv, VPst,   IS, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv,   CS,    O,FMAbv, ZWNJ,
+    CGJ,   WJ,   WJ,   WJ,    O,FMPst,    O,   SB,   SE,    O,    H, MPst, VPst,    H,VMAbv, VAbv,
+  VMBlw,    B, VBlw, FPst, VPst, FAbv,VMPst,    B,CMAbv, VAbv, MBlw, MPst, MBlw,    H,    O, VBlw,
+   MPst, MPre, MAbv, MBlw,    O,    B, FAbv, FAbv, FPst, VBlw,    B,    B, VPre,    O,VMPst,   IS,
+      O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv,    O,   IS,VMBlw,    B,VMPst,VMAbv,VMPst,   CS,   CS,
+      B,    N,    N,    O,   HN, VPre, VBlw, VAbv,   IS,CMAbv,    O, VPst,    B,    R,    R,CMBlw,
+   VAbv, VPre,VMAbv,VMAbv,    H, VAbv,CMBlw,FMAbv,    B,   CS,   CS,    H,CMBlw,VMPst,    H,VMPst,
+   VAbv,VMAbv, VPst,   IS,    R, MPst,    R, MPst,CMBlw,    B,FMBlw, VBlw,VMAbv,    R, MBlw, MBlw,
+     GB, FBlw, FBlw,CMAbv,   IS, VBlw,   IS,   GB, VAbv,    R,VMPst,    G,    G,    J,    J,    J,
+     SB,   SE,    J,   HR,    G,    G,   HM,   HM,   HM,    O, VBlw,
+};
+static const uint16_t
+hb_use_u16[456] =
+{
+    0,  0,  1,  2,  0,  3,  4,  5,  0,  6,  7,  0,  8,  0,  9, 10,
+   11, 12, 10, 13, 14, 10, 10, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+   24, 25, 18, 26, 27, 21, 22, 28, 29, 30, 31, 32, 33, 34, 22, 35,
+   36,  0, 18, 37, 38, 21, 22, 39, 24, 40, 18, 41, 42, 43, 44, 45,
+   46, 47, 31,  0, 48, 49, 22, 50, 51, 52, 18,  0, 53, 49, 22, 54,
+   51, 55, 18, 56, 57, 49, 10, 58, 59, 60, 61, 62, 10, 63, 64, 65,
+   31, 66, 67, 68, 10, 69, 70, 10, 71, 72, 73, 74, 75, 76, 77,  0,
+   10, 10, 78, 79, 80, 81, 82, 83, 84, 85, 10, 86, 10, 87, 10, 88,
+   89, 90, 10, 91, 92, 93,  2,  0, 94,  0, 10, 95, 96, 10, 97,  0,
+   98, 99,100,101, 31, 10,102,103,104, 10,105,106, 10,107, 10,108,
+  109,110,  2,  2,111, 10, 10,112,113,  2,114,115,116, 10,117, 10,
+  118,119,120,121,122,  0,  0,123,124,125,  0,126,127,128,129,  0,
+  130,131,132,  0,  0,133,134,  0,135,  0,  0, 10,136,137,138,  0,
+  139, 10,140,  0, 10,141,142, 10, 10,143,144,  2,145,146,147, 10,
+  148,149,150, 10, 10,151,152,  2,153, 99,154,155,156,  2, 10,157,
+   10,158,159,  0,160,161,162,  2,163,  0,  0,164,  0,165,  0,166,
+  166,167, 34,168,169,170, 10,171, 95,  0,172,  0, 10,173,174,  0,
+  175,  2,176,173,177,178,179,  0,  0,180,181,  0,182, 10, 10,183,
+  184,185,186,187,188, 10, 10,189,190,  0,191, 10,192,193,194, 10,
+   10,195, 10,196,197,106,198,103, 10, 34,199,200,201,  0,202,203,
+   95, 10, 10,204,205,  2,206, 21, 22,207,208,209,210,211, 10,212,
+  213,214,215,  0,198, 10, 10,216,217,  2,218,219,220,221, 10,222,
+  223,  2,224,225, 10,226,227,104,228,  0,229,230,231,232, 10,233,
+  234,  2,235, 10, 10,236,237,  0,238, 10, 10,239,240,241,242,243,
+   22, 10,218,244,  8, 10, 71, 19, 10,245, 74,246,247, 10, 10,248,
+  249,  2,250, 10,251,252, 10,253,254, 49, 10,255,256,  2,257,257,
+  257,258,259,260, 10,261,262,263,264,264,265,266,267,  0, 10,268,
+  106, 71, 95,269,  0,270, 71,271,272,  0,273,  0,274,  2,275,  2,
+  276,  2,130,130,163,163,163,130,
+};
+
+static inline unsigned
+hb_use_b4 (const uint8_t* a, unsigned i)
+{
+  return (a[i>>1]>>((i&1u)<<2))&15u;
+}
+static inline uint_fast8_t
+hb_use_get_category (unsigned u)
+{
+  return u<921600u?hb_use_u8[3105+(((hb_use_u8[889+(((hb_use_u16[((hb_use_u8[353+(((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>1>>3>>4))<<4)+((u>>1>>3>>1>>3)&15u))])<<3)+((u>>1>>3>>1)&7u))])<<1)+((u>>1>>3)&1u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
+}
+
+#endif
+
+#undef B
+#undef CGJ
+#undef CS
+#undef G
+#undef GB
+#undef H
+#undef HM
+#undef HN
+#undef HR
+#undef HVM
+#undef IS
+#undef J
+#undef N
+#undef O
+#undef R
+#undef SB
+#undef SE
+#undef SUB
+#undef Sk
+#undef WJ
+#undef ZWNJ
+#undef CMAbv
+#undef CMBlw
+#undef FAbv
+#undef FBlw
+#undef FPst
+#undef FMAbv
+#undef FMBlw
+#undef FMPst
+#undef MAbv
+#undef MBlw
+#undef MPst
+#undef MPre
+#undef SMAbv
+#undef SMBlw
+#undef VAbv
+#undef VBlw
+#undef VPst
+#undef VPre
+#undef VMAbv
+#undef VMBlw
+#undef VMPst
+#undef VMPre
+
+
+#endif /* HB_OT_SHAPER_USE_TABLE_HH */
+/* == End of generated table == */
similarity index 90%
rename from src/hb-ot-shape-complex-use.cc
rename to src/hb-ot-shaper-use.cc
index 70b6379..c35765a 100644 (file)
 
 #ifndef HB_NO_OT_SHAPE
 
-#include "hb-ot-shape-complex-use-machine.hh"
-#include "hb-ot-shape-complex-use-table.hh"
-#include "hb-ot-shape-complex-arabic.hh"
-#include "hb-ot-shape-complex-arabic-joining-list.hh"
-#include "hb-ot-shape-complex-vowel-constraints.hh"
+#include "hb-ot-shaper-use-machine.hh"
+#include "hb-ot-shaper-use-table.hh"
+#include "hb-ot-shaper-arabic.hh"
+#include "hb-ot-shaper-arabic-joining-list.hh"
+#include "hb-ot-shaper-vowel-constraints.hh"
 
 
 /*
@@ -89,19 +89,19 @@ use_other_features[] =
   HB_TAG('p','s','t','s'),
 };
 
-static void
+static bool
 setup_syllables_use (const hb_ot_shape_plan_t *plan,
                     hb_font_t *font,
                     hb_buffer_t *buffer);
-static void
+static bool
 record_rphf_use (const hb_ot_shape_plan_t *plan,
                 hb_font_t *font,
                 hb_buffer_t *buffer);
-static void
+static bool
 record_pref_use (const hb_ot_shape_plan_t *plan,
                 hb_font_t *font,
                 hb_buffer_t *buffer);
-static void
+static bool
 reorder_use (const hb_ot_shape_plan_t *plan,
             hb_font_t *font,
             hb_buffer_t *buffer);
@@ -115,25 +115,25 @@ collect_features_use (hb_ot_shape_planner_t *plan)
   map->add_gsub_pause (setup_syllables_use);
 
   /* "Default glyph pre-processing group" */
-  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);
+  map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
+  map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
+  map->enable_feature (HB_TAG('n','u','k','t'), F_PER_SYLLABLE);
+  map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ | F_PER_SYLLABLE);
 
   /* "Reordering group" */
   map->add_gsub_pause (_hb_clear_substitution_flags);
-  map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ);
+  map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ | F_PER_SYLLABLE);
   map->add_gsub_pause (record_rphf_use);
   map->add_gsub_pause (_hb_clear_substitution_flags);
-  map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ);
+  map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ | F_PER_SYLLABLE);
   map->add_gsub_pause (record_pref_use);
 
   /* "Orthographic unit shaping group" */
   for (unsigned int i = 0; i < ARRAY_LENGTH (use_basic_features); i++)
-    map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ);
+    map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ | F_PER_SYLLABLE);
 
   map->add_gsub_pause (reorder_use);
-  map->add_gsub_pause (_hb_clear_syllables);
+  map->add_gsub_pause (hb_syllabic_clear_var); // Don't need syllables anymore, use stop to free buffer var
 
   /* "Topographical features" */
   for (unsigned int i = 0; i < ARRAY_LENGTH (use_topographical_features); i++)
@@ -257,7 +257,6 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan,
     use_syllable_type_t syllable_type = (use_syllable_type_t) (info[start].syllable() & 0x0F);
     switch (syllable_type)
     {
-      case use_symbol_cluster:
       case use_hieroglyph_cluster:
       case use_non_cluster:
        /* These don't join.  Nothing to do. */
@@ -269,6 +268,7 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan,
       case use_standard_cluster:
       case use_number_joiner_terminated_cluster:
       case use_numeral_cluster:
+      case use_symbol_cluster:
       case use_broken_cluster:
 
        bool join = last_form == JOINING_FORM_FINA || last_form == JOINING_FORM_ISOL;
@@ -293,19 +293,21 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan,
   }
 }
 
-static void
+static bool
 setup_syllables_use (const hb_ot_shape_plan_t *plan,
                     hb_font_t *font HB_UNUSED,
                     hb_buffer_t *buffer)
 {
+  HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
   find_syllables_use (buffer);
   foreach_syllable (buffer, start, end)
     buffer->unsafe_to_break (start, end);
   setup_rphf_mask (plan, buffer);
   setup_topographical_masks (plan, buffer);
+  return false;
 }
 
-static void
+static bool
 record_rphf_use (const hb_ot_shape_plan_t *plan,
                 hb_font_t *font HB_UNUSED,
                 hb_buffer_t *buffer)
@@ -313,7 +315,7 @@ record_rphf_use (const hb_ot_shape_plan_t *plan,
   const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
 
   hb_mask_t mask = use_plan->rphf_mask;
-  if (!mask) return;
+  if (!mask) return false;
   hb_glyph_info_t *info = buffer->info;
 
   foreach_syllable (buffer, start, end)
@@ -326,9 +328,10 @@ record_rphf_use (const hb_ot_shape_plan_t *plan,
        break;
       }
   }
+  return false;
 }
 
-static void
+static bool
 record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
                 hb_font_t *font HB_UNUSED,
                 hb_buffer_t *buffer)
@@ -345,12 +348,13 @@ record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
        break;
       }
   }
+  return false;
 }
 
 static inline bool
 is_halant_use (const hb_glyph_info_t &info)
 {
-  return (info.use_category() == USE(H) || info.use_category() == USE(HVM)) &&
+  return (info.use_category() == USE(H) || info.use_category() == USE(HVM) || info.use_category() == USE(IS)) &&
         !_hb_glyph_info_ligated (&info);
 }
 
@@ -363,6 +367,7 @@ reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end)
                  (FLAG (use_virama_terminated_cluster) |
                   FLAG (use_sakot_terminated_cluster) |
                   FLAG (use_standard_cluster) |
+                  FLAG (use_symbol_cluster) |
                   FLAG (use_broken_cluster) |
                   0))))
     return;
@@ -372,6 +377,9 @@ reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end)
 #define POST_BASE_FLAGS64 (FLAG64 (USE(FAbv)) | \
                           FLAG64 (USE(FBlw)) | \
                           FLAG64 (USE(FPst)) | \
+                          FLAG64 (USE(FMAbv)) | \
+                          FLAG64 (USE(FMBlw)) | \
+                          FLAG64 (USE(FMPst)) | \
                           FLAG64 (USE(MAbv)) | \
                           FLAG64 (USE(MBlw)) | \
                           FLAG64 (USE(MPst)) | \
@@ -436,17 +444,19 @@ reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end)
   }
 }
 
-static void
+static bool
 reorder_use (const hb_ot_shape_plan_t *plan,
             hb_font_t *font,
             hb_buffer_t *buffer)
 {
+  bool ret = false;
   if (buffer->message (font, "start reordering USE"))
   {
-    hb_syllabic_insert_dotted_circles (font, buffer,
-                                      use_broken_cluster,
-                                      USE(B),
-                                      USE(R));
+    if (hb_syllabic_insert_dotted_circles (font, buffer,
+                                          use_broken_cluster,
+                                          USE(B),
+                                          USE(R)))
+      ret = true;
 
     foreach_syllable (buffer, start, end)
       reorder_syllable_use (buffer, start, end);
@@ -455,6 +465,8 @@ reorder_use (const hb_ot_shape_plan_t *plan,
   }
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, use_category);
+
+  return ret;
 }
 
 
@@ -480,7 +492,7 @@ compose_use (const hb_ot_shape_normalize_context_t *c,
 }
 
 
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use =
+const hb_ot_shaper_t _hb_ot_shaper_use =
 {
   collect_features_use,
   nullptr, /* override_features */
@@ -488,12 +500,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use =
   data_destroy_use,
   preprocess_text_use,
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   nullptr, /* decompose */
   compose_use,
   setup_masks_use,
-  HB_TAG_NONE, /* gpos_tag */
   nullptr, /* reorder_marks */
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
   false, /* fallback_position */
 };
similarity index 91%
rename from src/hb-ot-shape-complex-vowel-constraints.cc
rename to src/hb-ot-shaper-vowel-constraints.cc
index d2cca10..d1ed894 100644 (file)
  * # Date: 2015-03-12, 21:17:00 GMT [AG]
  * # Date: 2019-11-08, 23:22:00 GMT [AG]
  *
- * # Scripts-14.0.0.txt
- * # Date: 2021-07-10, 00:35:31 GMT
+ * # Scripts-15.1.0.txt
+ * # Date: 2023-07-28, 16:01:07 GMT
  */
 
 #include "hb.hh"
 
 #ifndef HB_NO_OT_SHAPE
 
-#include "hb-ot-shape-complex-vowel-constraints.hh"
+#include "hb-ot-shaper-vowel-constraints.hh"
 
 static void
 _output_dotted_circle (hb_buffer_t *buffer)
@@ -39,7 +39,7 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
                                       hb_buffer_t              *buffer,
                                       hb_font_t                *font HB_UNUSED)
 {
-#ifdef HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS
+#ifdef HB_NO_OT_SHAPER_VOWEL_CONSTRAINTS
   return;
 #endif
   if (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)
@@ -342,6 +342,40 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
       }
       break;
 
+    case HB_SCRIPT_KHOJKI:
+      for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
+      {
+       bool matched = false;
+       switch (buffer->cur ().codepoint)
+       {
+         case 0x11200u:
+           switch (buffer->cur (1).codepoint)
+           {
+             case 0x1122Cu: case 0x11231u: case 0x11233u:
+               matched = true;
+               break;
+           }
+           break;
+         case 0x11206u:
+           matched = 0x1122Cu == buffer->cur (1).codepoint;
+           break;
+         case 0x1122Cu:
+           switch (buffer->cur (1).codepoint)
+           {
+             case 0x11230u: case 0x11231u:
+               matched = true;
+               break;
+           }
+           break;
+         case 0x11240u:
+           matched = 0x1122Eu == buffer->cur (1).codepoint;
+           break;
+       }
+       (void) buffer->next_glyph ();
+       if (matched) _output_with_dotted_circle (buffer);
+      }
+      break;
+
     case HB_SCRIPT_KHUDAWADI:
       for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
       {
similarity index 87%
rename from src/hb-ot-shape-complex-vowel-constraints.hh
rename to src/hb-ot-shaper-vowel-constraints.hh
index d9082d4..5a7ee1b 100644 (file)
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS_HH
-#define HB_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS_HH
+#ifndef HB_OT_SHAPER_VOWEL_CONSTRAINTS_HH
+#define HB_OT_SHAPER_VOWEL_CONSTRAINTS_HH
 
 #include "hb.hh"
 
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shaper.hh"
 
 HB_INTERNAL void
 _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan,
                                       hb_buffer_t              *buffer,
                                       hb_font_t                *font);
 
-#endif /* HB_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS_HH */
+#endif /* HB_OT_SHAPER_VOWEL_CONSTRAINTS_HH */
similarity index 84%
rename from src/hb-ot-shape-complex.hh
rename to src/hb-ot-shaper.hh
index 8012a9a..0207b2b 100644 (file)
@@ -24,8 +24,8 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_OT_SHAPE_COMPLEX_HH
-#define HB_OT_SHAPE_COMPLEX_HH
+#ifndef HB_OT_SHAPER_HH
+#define HB_OT_SHAPER_HH
 
 #include "hb.hh"
 
 #include "hb-ot-shape-normalize.hh"
 
 
-/* buffer var allocations, used by complex shapers */
-#define complex_var_u8_category()      var2.u8[2]
-#define complex_var_u8_auxiliary()     var2.u8[3]
+/* buffer var allocations, used by all OT shapers */
+#define ot_shaper_var_u8_category()    var2.u8[2]
+#define ot_shaper_var_u8_auxiliary()   var2.u8[3]
 
 
-#define HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS 32
+#define HB_OT_SHAPE_MAX_COMBINING_MARKS 32
 
 enum hb_ot_shape_zero_width_marks_type_t {
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
@@ -49,22 +49,22 @@ enum hb_ot_shape_zero_width_marks_type_t {
 
 
 /* Master OT shaper list */
-#define HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS \
-  HB_COMPLEX_SHAPER_IMPLEMENT (arabic) \
-  HB_COMPLEX_SHAPER_IMPLEMENT (default) \
-  HB_COMPLEX_SHAPER_IMPLEMENT (dumber) \
-  HB_COMPLEX_SHAPER_IMPLEMENT (hangul) \
-  HB_COMPLEX_SHAPER_IMPLEMENT (hebrew) \
-  HB_COMPLEX_SHAPER_IMPLEMENT (indic) \
-  HB_COMPLEX_SHAPER_IMPLEMENT (khmer) \
-  HB_COMPLEX_SHAPER_IMPLEMENT (myanmar) \
-  HB_COMPLEX_SHAPER_IMPLEMENT (myanmar_zawgyi) \
-  HB_COMPLEX_SHAPER_IMPLEMENT (thai) \
-  HB_COMPLEX_SHAPER_IMPLEMENT (use) \
+#define HB_OT_SHAPERS_IMPLEMENT_SHAPERS \
+  HB_OT_SHAPER_IMPLEMENT (arabic) \
+  HB_OT_SHAPER_IMPLEMENT (default) \
+  HB_OT_SHAPER_IMPLEMENT (dumber) \
+  HB_OT_SHAPER_IMPLEMENT (hangul) \
+  HB_OT_SHAPER_IMPLEMENT (hebrew) \
+  HB_OT_SHAPER_IMPLEMENT (indic) \
+  HB_OT_SHAPER_IMPLEMENT (khmer) \
+  HB_OT_SHAPER_IMPLEMENT (myanmar) \
+  HB_OT_SHAPER_IMPLEMENT (myanmar_zawgyi) \
+  HB_OT_SHAPER_IMPLEMENT (thai) \
+  HB_OT_SHAPER_IMPLEMENT (use) \
   /* ^--- Add new shapers here; keep sorted. */
 
 
-struct hb_ot_complex_shaper_t
+struct hb_ot_shaper_t
 {
   /* collect_features()
    * Called during shape_plan().
@@ -117,8 +117,6 @@ struct hb_ot_complex_shaper_t
                              hb_font_t                *font);
 
 
-  hb_ot_shape_normalization_mode_t normalization_preference;
-
   /* decompose()
    * Called during shape()'s normalization.
    * May be NULL.
@@ -147,12 +145,6 @@ struct hb_ot_complex_shaper_t
                       hb_buffer_t              *buffer,
                       hb_font_t                *font);
 
-  /* 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.
-   */
-  hb_tag_t gpos_tag;
-
   /* reorder_marks()
    * Called during shape().
    * Shapers can use to modify ordering of combining marks.
@@ -163,23 +155,31 @@ struct hb_ot_complex_shaper_t
                         unsigned int              start,
                         unsigned int              end);
 
+  /* 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.
+   */
+  hb_tag_t gpos_tag;
+
+  hb_ot_shape_normalization_mode_t normalization_preference;
+
   hb_ot_shape_zero_width_marks_type_t zero_width_marks;
 
   bool fallback_position;
 };
 
-#define HB_COMPLEX_SHAPER_IMPLEMENT(name) extern HB_INTERNAL const hb_ot_complex_shaper_t _hb_ot_complex_shaper_##name;
-HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
-#undef HB_COMPLEX_SHAPER_IMPLEMENT
+#define HB_OT_SHAPER_IMPLEMENT(name) extern HB_INTERNAL const hb_ot_shaper_t _hb_ot_shaper_##name;
+HB_OT_SHAPERS_IMPLEMENT_SHAPERS
+#undef HB_OT_SHAPER_IMPLEMENT
 
 
-static inline const hb_ot_complex_shaper_t *
-hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
+static inline const hb_ot_shaper_t *
+hb_ot_shaper_categorize (const hb_ot_shape_planner_t *planner)
 {
   switch ((hb_tag_t) planner->props.script)
   {
     default:
-      return &_hb_ot_complex_shaper_default;
+      return &_hb_ot_shaper_default;
 
 
     /* Unicode-1.1 additions */
@@ -195,28 +195,28 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
       if ((planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT ||
           planner->props.script == HB_SCRIPT_ARABIC) &&
          HB_DIRECTION_IS_HORIZONTAL(planner->props.direction))
-       return &_hb_ot_complex_shaper_arabic;
+       return &_hb_ot_shaper_arabic;
       else
-       return &_hb_ot_complex_shaper_default;
+       return &_hb_ot_shaper_default;
 
 
     /* Unicode-1.1 additions */
     case HB_SCRIPT_THAI:
     case HB_SCRIPT_LAO:
 
-      return &_hb_ot_complex_shaper_thai;
+      return &_hb_ot_shaper_thai;
 
 
     /* Unicode-1.1 additions */
     case HB_SCRIPT_HANGUL:
 
-      return &_hb_ot_complex_shaper_hangul;
+      return &_hb_ot_shaper_hangul;
 
 
     /* Unicode-1.1 additions */
     case HB_SCRIPT_HEBREW:
 
-      return &_hb_ot_complex_shaper_hebrew;
+      return &_hb_ot_shaper_hebrew;
 
 
     /* Unicode-1.1 additions */
@@ -230,9 +230,6 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
     case HB_SCRIPT_TAMIL:
     case HB_SCRIPT_TELUGU:
 
-    /* Unicode-3.0 additions */
-    case HB_SCRIPT_SINHALA:
-
       /* 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.
@@ -240,14 +237,14 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
        * 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;
+       return &_hb_ot_shaper_default;
       else if ((planner->map.chosen_script[0] & 0x000000FF) == '3')
-       return &_hb_ot_complex_shaper_use;
+       return &_hb_ot_shaper_use;
       else
-       return &_hb_ot_complex_shaper_indic;
+       return &_hb_ot_shaper_indic;
 
     case HB_SCRIPT_KHMER:
-       return &_hb_ot_complex_shaper_khmer;
+       return &_hb_ot_shaper_khmer;
 
     case HB_SCRIPT_MYANMAR:
       /* If the designer designed the font for the 'DFLT' script,
@@ -260,16 +257,18 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
       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;
+       return &_hb_ot_shaper_default;
       else
-       return &_hb_ot_complex_shaper_myanmar;
+       return &_hb_ot_shaper_myanmar;
 
 
+#ifndef HB_NO_OT_SHAPER_MYANMAR_ZAWGYI
 #define HB_SCRIPT_MYANMAR_ZAWGYI       ((hb_script_t) HB_TAG ('Q','a','a','g'))
     case HB_SCRIPT_MYANMAR_ZAWGYI:
     /* https://github.com/harfbuzz/harfbuzz/issues/1162 */
 
-      return &_hb_ot_complex_shaper_myanmar_zawgyi;
+      return &_hb_ot_shaper_myanmar_zawgyi;
+#endif
 
 
     /* Unicode-2.0 additions */
@@ -277,7 +276,7 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
 
     /* Unicode-3.0 additions */
     case HB_SCRIPT_MONGOLIAN:
-    //case HB_SCRIPT_SINHALA:
+    case HB_SCRIPT_SINHALA:
 
     /* Unicode-3.2 additions */
     case HB_SCRIPT_BUHID:
@@ -383,6 +382,10 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
     case HB_SCRIPT_TOTO:
     case HB_SCRIPT_VITHKUQI:
 
+    /* Unicode-15.0 additions */
+    case HB_SCRIPT_KAWI:
+    case HB_SCRIPT_NAG_MUNDARI:
+
       /* 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.
@@ -390,11 +393,11 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
        * GSUB/GPOS needed, so there may be no scripts found! */
       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;
+       return &_hb_ot_shaper_default;
       else
-       return &_hb_ot_complex_shaper_use;
+       return &_hb_ot_shaper_use;
   }
 }
 
 
-#endif /* HB_OT_SHAPE_COMPLEX_HH */
+#endif /* HB_OT_SHAPER_HH */
index 41d1734..f7bb379 100644 (file)
@@ -57,6 +57,41 @@ enum
   // Reserved = 0xFFFC                         /* Reserved for future use — set to zero. */
 };
 
+static bool axis_value_is_outside_axis_range (hb_tag_t axis_tag, float axis_value,
+                                              const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location)
+{
+  if (!user_axes_location->has (axis_tag))
+    return false;
+
+  Triple axis_range = user_axes_location->get (axis_tag);
+  return (axis_value < axis_range.minimum || axis_value > axis_range.maximum);
+}
+
+struct StatAxisRecord
+{
+  int cmp (hb_tag_t key) const { return tag.cmp (key); }
+
+  hb_ot_name_id_t get_name_id () const { return nameID; }
+
+  hb_tag_t get_axis_tag () const { return tag; }
+
+  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 AxisValueFormat1
 {
   unsigned int get_axis_index () const { return axisIndex; }
@@ -64,10 +99,37 @@ struct AxisValueFormat1
 
   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
 
+  hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    unsigned axis_idx = get_axis_index ();
+    return axis_records[axis_idx].get_axis_tag ();
+  }
+
+  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+                        const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
+  {
+    hb_tag_t axis_tag = get_axis_tag (axis_records);
+    float axis_value = get_value ();
+
+    return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    TRACE_SUBSET (this);
+    const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
+
+    if (keep_axis_value (axis_records, user_axes_location))
+      return_trace (c->serializer->embed (this));
+
+    return_trace (false);
+  }
+
   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:
@@ -80,7 +142,7 @@ struct AxisValueFormat1
   NameID       valueNameID;    /* The name ID for entries in the 'name' table
                                 * that provide a display string for this
                                 * attribute value. */
-  HBFixed      value;          /* A numeric value for this attribute value. */
+  F16DOT16     value;          /* A numeric value for this attribute value. */
   public:
   DEFINE_SIZE_STATIC (12);
 };
@@ -92,10 +154,37 @@ struct AxisValueFormat2
 
   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
 
+  hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    unsigned axis_idx = get_axis_index ();
+    return axis_records[axis_idx].get_axis_tag ();
+  }
+
+  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+                        const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
+  {
+    hb_tag_t axis_tag = get_axis_tag (axis_records);
+    float axis_value = get_value ();
+
+    return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    TRACE_SUBSET (this);
+    const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
+
+    if (keep_axis_value (axis_records, user_axes_location))
+      return_trace (c->serializer->embed (this));
+
+    return_trace (false);
+  }
+
   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:
@@ -108,10 +197,10 @@ struct AxisValueFormat2
   NameID       valueNameID;    /* The name ID for entries in the 'name' table
                                 * that provide a display string for this
                                 * attribute value. */
-  HBFixed      nominalValue;   /* A numeric value for this attribute value. */
-  HBFixed      rangeMinValue;  /* The minimum value for a range associated
+  F16DOT16     nominalValue;   /* A numeric value for this attribute value. */
+  F16DOT16     rangeMinValue;  /* The minimum value for a range associated
                                 * with the specified name ID. */
-  HBFixed      rangeMaxValue;  /* The maximum value for a range associated
+  F16DOT16     rangeMaxValue;  /* The maximum value for a range associated
                                 * with the specified name ID. */
   public:
   DEFINE_SIZE_STATIC (20);
@@ -124,10 +213,37 @@ struct AxisValueFormat3
 
   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
 
+  hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    unsigned axis_idx = get_axis_index ();
+    return axis_records[axis_idx].get_axis_tag ();
+  }
+
+  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+                        const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
+  {
+    hb_tag_t axis_tag = get_axis_tag (axis_records);
+    float axis_value = get_value ();
+
+    return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    TRACE_SUBSET (this);
+    const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
+
+    if (keep_axis_value (axis_records, user_axes_location))
+      return_trace (c->serializer->embed (this));
+
+    return_trace (false);
+  }
+
   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:
@@ -140,8 +256,8 @@ struct AxisValueFormat3
   NameID       valueNameID;    /* The name ID for entries in the 'name' table
                                 * that provide a display string for this
                                 * attribute value. */
-  HBFixed      value;          /* A numeric value for this attribute value. */
-  HBFixed      linkedValue;    /* The numeric value for a style-linked mapping
+  F16DOT16     value;          /* A numeric value for this attribute value. */
+  F16DOT16     linkedValue;    /* The numeric value for a style-linked mapping
                                 * from this value. */
   public:
   DEFINE_SIZE_STATIC (16);
@@ -155,14 +271,14 @@ struct AxisValueRecord
   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:
   HBUINT16     axisIndex;      /* Zero-base index into the axis record array
                                 * identifying the axis to which this value
                                 * applies. Must be less than designAxisCount. */
-  HBFixed      value;          /* A numeric value for this attribute value. */
+  F16DOT16     value;          /* A numeric value for this attribute value. */
   public:
   DEFINE_SIZE_STATIC (6);
 };
@@ -172,12 +288,46 @@ struct AxisValueFormat4
   const AxisValueRecord &get_axis_record (unsigned int axis_index) const
   { return axisValues.as_array (axisCount)[axis_index]; }
 
+  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+                        const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
+  {
+    hb_array_t<const AxisValueRecord> axis_value_records = axisValues.as_array (axisCount);
+
+    for (const auto& rec : axis_value_records)
+    {
+      unsigned axis_idx = rec.get_axis_index ();
+      float axis_value = rec.get_value ();
+      hb_tag_t axis_tag = axis_records[axis_idx].get_axis_tag ();
+
+      if (axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location))
+        return false;
+    }
+
+    return true;
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    TRACE_SUBSET (this);
+    const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location = &c->plan->user_axes_location;
+    if (!keep_axis_value (axis_records, user_axes_location))
+      return_trace (false);
+
+    unsigned total_size = min_size + axisCount * AxisValueRecord::static_size;
+    auto *out = c->serializer->allocate_size<AxisValueFormat4> (total_size);
+    if (unlikely (!out)) return_trace (false);
+    hb_memcpy (out, this, total_size);
+    return_trace (true);
+  }
+
   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (likely (c->check_struct (this) &&
+                          axisValues.sanitize (c, axisCount)));
   }
 
   protected:
@@ -234,6 +384,33 @@ struct AxisValue
     }
   }
 
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format);
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+    case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+                        hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
+  {
+    switch (u.format)
+    {
+    case 1: return u.format1.keep_axis_value (axis_records, user_axes_location);
+    case 2: return u.format2.keep_axis_value (axis_records, user_axes_location);
+    case 3: return u.format3.keep_axis_value (axis_records, user_axes_location);
+    case 4: return u.format4.keep_axis_value (axis_records, user_axes_location);
+    default:return false;
+    }
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -263,27 +440,33 @@ struct AxisValue
   DEFINE_SIZE_UNION (2, format);
 };
 
-struct StatAxisRecord
+struct AxisValueOffsetArray: UnsizedArrayOf<Offset16To<AxisValue>>
 {
-  int cmp (hb_tag_t key) const { return tag.cmp (key); }
+  bool subset (hb_subset_context_t *c,
+               unsigned axisValueCount,
+               unsigned& count,
+               const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    TRACE_SUBSET (this);
 
-  hb_ot_name_id_t get_name_id () const { return nameID; }
+    auto axisValueOffsets = as_array (axisValueCount);
+    count = 0;
+    for (const auto& offset : axisValueOffsets)
+    {
+      if (!offset) continue;
+      auto o_snap = c->serializer->snapshot ();
+      auto *o = c->serializer->embed (offset);
+      if (!o) return_trace (false);
+      if (!o->serialize_subset (c, offset, this, axis_records))
+      {
+        c->serializer->revert (o_snap);
+        continue;
+      }
+      count++;
+    }
 
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (count);
   }
-
-  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
@@ -329,7 +512,8 @@ struct STAT
     return axis_value.get_value_name_id ();
   }
 
-  void collect_name_ids (hb_set_t *nameids_to_retain) const
+  void collect_name_ids (hb_hashmap_t<hb_tag_t, Triple> *user_axes_location,
+                         hb_set_t *nameids_to_retain /* OUT */) const
   {
     if (!has_data ()) return;
 
@@ -338,11 +522,38 @@ struct STAT
     | hb_sink (nameids_to_retain)
     ;
 
+    auto designAxes = get_design_axes ();
+
     + get_axis_value_offsets ()
     | hb_map (hb_add (&(this + offsetToAxisValueOffsets)))
+    | hb_filter ([&] (const AxisValue& _)
+                 { return _.keep_axis_value (designAxes, user_axes_location); })
     | hb_map (&AxisValue::get_value_name_id)
     | hb_sink (nameids_to_retain)
     ;
+
+    nameids_to_retain->add (elidedFallbackNameID);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    STAT *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+
+    auto designAxes = get_design_axes ();
+    for (unsigned i = 0; i < (unsigned)designAxisCount; i++)
+      if (unlikely (!c->serializer->embed (designAxes[i])))
+          return_trace (false);
+
+    if (designAxisCount)
+      c->serializer->check_assign (out->designAxesOffset, this->get_size (),
+                                   HB_SERIALIZE_ERROR_INT_OVERFLOW);
+
+    unsigned count = 0;
+    out->offsetToAxisValueOffsets.serialize_subset (c, offsetToAxisValueOffsets, this,
+                                                    axisValueCount, count, designAxes);
+    return_trace (c->serializer->check_assign (out->axisValueCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -381,7 +592,7 @@ struct STAT
                                 * set to zero; if designAxisCount is greater
                                 * than zero, must be greater than zero. */
   HBUINT16     axisValueCount; /* The number of axis value tables. */
-  NNOffset32To<UnsizedArrayOf<Offset16To<AxisValue>>>
+  NNOffset32To<AxisValueOffsetArray>
                offsetToAxisValueOffsets;
                                /* Offset in bytes from the beginning of
                                 * the STAT table to the start of the design
index 61d2814..032a7c8 100644 (file)
  *
  * on files with these headers:
  *
- * <meta name="updated_at" content="2022-01-28 10:00 PM" />
- * File-Date: 2021-12-29
+ * <meta name="updated_at" content="2022-09-30 11:47 PM" />
+ * File-Date: 2023-08-02
  */
 
 #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 */
-  {"aba",      HB_TAG_NONE            },       /* Abé != Abaza */
-  {"abh",      HB_TAG('A','R','A',' ')},       /* Tajiki Arabic -> Arabic */
-  {"abq",      HB_TAG('A','B','A',' ')},       /* Abaza */
-  {"abs",      HB_TAG('C','P','P',' ')},       /* Ambonese Malay -> Creoles */
-  {"abv",      HB_TAG('A','R','A',' ')},       /* Baharna Arabic -> Arabic */
-  {"acf",      HB_TAG('F','A','N',' ')},       /* Saint Lucian Creole French -> French Antillean */
-  {"acf",      HB_TAG('C','P','P',' ')},       /* Saint Lucian Creole French -> Creoles */
-/*{"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 */
-  {"acr",      HB_TAG('M','Y','N',' ')},       /* Achi -> Mayan */
-  {"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 */
-  {"afk",      HB_TAG_NONE            },       /* Nanubae != Afrikaans */
-  {"afs",      HB_TAG('C','P','P',' ')},       /* Afro-Seminole Creole -> Creoles */
-  {"agu",      HB_TAG('M','Y','N',' ')},       /* Aguacateco -> Mayan */
-  {"agw",      HB_TAG_NONE            },       /* Kahua != Agaw */
-  {"ahg",      HB_TAG('A','G','W',' ')},       /* Qimant -> Agaw */
-  {"aht",      HB_TAG('A','T','H',' ')},       /* Ahtena -> Athapaskan */
-  {"aig",      HB_TAG('C','P','P',' ')},       /* Antigua and Barbuda Creole English -> Creoles */
-  {"aii",      HB_TAG('S','W','A',' ')},       /* Assyrian Neo-Aramaic -> Swadaya Aramaic */
-  {"aii",      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] */
-  {"akb",      HB_TAG('A','K','B',' ')},       /* Batak Angkola */
-  {"akb",      HB_TAG('B','T','K',' ')},       /* Batak Angkola -> Batak */
-  {"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 */
-  {"aoa",      HB_TAG('C','P','P',' ')},       /* Angolar -> Creoles */
-  {"apa",      HB_TAG('A','T','H',' ')},       /* Apache [collection] -> Athapaskan */
-  {"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 */
-  {"ari",      HB_TAG_NONE            },       /* Arikara != Aari */
-  {"ark",      HB_TAG_NONE            },       /* Arikapú != Rakhine */
-  {"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 */
-  {"ary",      HB_TAG('A','R','A',' ')},       /* Moroccan Arabic -> Arabic */
-  {"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 [collection] -> Athapaskan */
-  {"atj",      HB_TAG('R','C','R',' ')},       /* Atikamekw -> R-Cree */
-  {"atv",      HB_TAG('A','L','T',' ')},       /* Northern Altai -> Altai */
-  {"auj",      HB_TAG('B','B','R',' ')},       /* Awjilah -> Berber */
-  {"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 */
-/*{"avn",      HB_TAG('A','V','N',' ')},*/     /* Avatime */
-/*{"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 */
-  {"azb",      HB_TAG('A','Z','E',' ')},       /* South Azerbaijani -> Azerbaijani */
-  {"azd",      HB_TAG('N','A','H',' ')},       /* Eastern Durango Nahuatl -> Nahuatl */
-  {"azj",      HB_TAG('A','Z','E',' ')},       /* North Azerbaijani -> Azerbaijani */
-  {"azn",      HB_TAG('N','A','H',' ')},       /* Western Durango Nahuatl -> Nahuatl */
-  {"azz",      HB_TAG('N','A','H',' ')},       /* Highland Puebla Nahuatl -> Nahuatl */
-  {"ba",       HB_TAG('B','S','H',' ')},       /* Bashkir */
-  {"bad",      HB_TAG('B','A','D','0')},       /* Banda [collection] */
-  {"bag",      HB_TAG_NONE            },       /* Tuki != Baghelkhandi */
-  {"bah",      HB_TAG('C','P','P',' ')},       /* Bahamas Creole English -> Creoles */
-  {"bai",      HB_TAG('B','M','L',' ')},       /* Bamileke [collection] */
-  {"bal",      HB_TAG('B','L','I',' ')},       /* Baluchi [macrolanguage] */
-/*{"ban",      HB_TAG('B','A','N',' ')},*/     /* Balinese */
-/*{"bar",      HB_TAG('B','A','R',' ')},*/     /* Bavarian */
-  {"bau",      HB_TAG_NONE            },       /* Bada (Nigeria) != Baulé */
-  {"bbc",      HB_TAG('B','B','C',' ')},       /* Batak Toba */
-  {"bbc",      HB_TAG('B','T','K',' ')},       /* Batak Toba -> Batak */
-  {"bbj",      HB_TAG('B','M','L',' ')},       /* Ghomálá' -> Bamileke */
-  {"bbp",      HB_TAG('B','A','D','0')},       /* West Central Banda -> Banda */
-  {"bbr",      HB_TAG_NONE            },       /* Girawa != Berber */
-  {"bbz",      HB_TAG('A','R','A',' ')},       /* Babalia Creole Arabic (retired code) -> Arabic */
-  {"bcc",      HB_TAG('B','L','I',' ')},       /* Southern Balochi -> Baluchi */
-  {"bch",      HB_TAG_NONE            },       /* Bariai != Bench */
-  {"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 [collection] */
-  {"bew",      HB_TAG('C','P','P',' ')},       /* Betawi -> Creoles */
-  {"bfl",      HB_TAG('B','A','D','0')},       /* Banda-Ndélé -> Banda */
-  {"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 */
-  {"bgq",      HB_TAG('R','A','J',' ')},       /* Bagri -> Rajasthani */
-  {"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 */
-  {"bi",       HB_TAG('C','P','P',' ')},       /* Bislama -> Creoles */
-/*{"bik",      HB_TAG('B','I','K',' ')},*/     /* Bikol [macrolanguage] */
-  {"bil",      HB_TAG_NONE            },       /* Bile != Bilen */
-  {"bin",      HB_TAG('E','D','O',' ')},       /* Edo */
-  {"biu",      HB_TAG('Q','I','N',' ')},       /* Biete -> Chin */
-/*{"bjj",      HB_TAG('B','J','J',' ')},*/     /* Kanauji */
-  {"bjn",      HB_TAG('M','L','Y',' ')},       /* Banjar -> Malay */
-  {"bjo",      HB_TAG('B','A','D','0')},       /* Mid-Southern Banda -> Banda */
-  {"bjq",      HB_TAG('M','L','G',' ')},       /* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */
-  {"bjs",      HB_TAG('C','P','P',' ')},       /* Bajan -> Creoles */
-  {"bjt",      HB_TAG('B','L','N',' ')},       /* Balanta-Ganja -> Balante */
-  {"bkf",      HB_TAG_NONE            },       /* Beeke != Blackfoot */
-  {"bko",      HB_TAG('B','M','L',' ')},       /* Kwa' -> Bamileke */
-  {"bla",      HB_TAG('B','K','F',' ')},       /* Siksika -> Blackfoot */
-  {"ble",      HB_TAG('B','L','N',' ')},       /* Balanta-Kentohe -> Balante */
-  {"blg",      HB_TAG('I','B','A',' ')},       /* Balau (retired code) -> Iban */
-  {"bli",      HB_TAG_NONE            },       /* Bolia != Baluchi */
-  {"blk",      HB_TAG('B','L','K',' ')},       /* Pa’o Karen */
-  {"blk",      HB_TAG('K','R','N',' ')},       /* Pa'o Karen -> Karen */
-  {"bln",      HB_TAG('B','I','K',' ')},       /* Southern Catanduanes Bikol -> Bikol */
-  {"blt",      HB_TAG_NONE            },       /* Tai Dam != Balti */
-  {"bm",       HB_TAG('B','M','B',' ')},       /* Bambara (Bamanankan) */
-  {"bmb",      HB_TAG_NONE            },       /* Bembe != Bambara (Bamanankan) */
-  {"bml",      HB_TAG_NONE            },       /* Bomboli != Bamileke */
-  {"bmm",      HB_TAG('M','L','G',' ')},       /* Northern Betsimisaraka Malagasy -> Malagasy */
-  {"bn",       HB_TAG('B','E','N',' ')},       /* Bengali */
-  {"bo",       HB_TAG('T','I','B',' ')},       /* Tibetan */
-  {"bpd",      HB_TAG('B','A','D','0')},       /* Banda-Banda -> Banda */
-  {"bpl",      HB_TAG('C','P','P',' ')},       /* Broome Pearling Lugger Pidgin -> Creoles */
-  {"bpq",      HB_TAG('C','P','P',' ')},       /* Banda Malay -> Creoles */
-/*{"bpy",      HB_TAG('B','P','Y',' ')},*/     /* Bishnupriya -> Bishnupriya Manipuri */
-  {"bqi",      HB_TAG('L','R','C',' ')},       /* Bakhtiari -> Luri */
-  {"bqk",      HB_TAG('B','A','D','0')},       /* Banda-Mbrès -> Banda */
-  {"br",       HB_TAG('B','R','E',' ')},       /* Breton */
-  {"bra",      HB_TAG('B','R','I',' ')},       /* Braj -> Braj Bhasha */
-  {"brc",      HB_TAG('C','P','P',' ')},       /* Berbice Creole Dutch -> Creoles */
-/*{"brh",      HB_TAG('B','R','H',' ')},*/     /* Brahui */
-  {"bri",      HB_TAG_NONE            },       /* Mokpwe != Braj Bhasha */
-  {"brm",      HB_TAG_NONE            },       /* Barambu != Burmese */
-/*{"brx",      HB_TAG('B','R','X',' ')},*/     /* Bodo (India) */
-  {"bs",       HB_TAG('B','O','S',' ')},       /* Bosnian */
-  {"bsh",      HB_TAG_NONE            },       /* Kati != Bashkir */
-/*{"bsk",      HB_TAG('B','S','K',' ')},*/     /* Burushaski */
-  {"btb",      HB_TAG('B','T','I',' ')},       /* Beti (Cameroon) (retired code) */
-  {"btd",      HB_TAG('B','T','D',' ')},       /* Batak Dairi (Pakpak) */
-  {"btd",      HB_TAG('B','T','K',' ')},       /* Batak Dairi -> Batak */
-  {"bti",      HB_TAG_NONE            },       /* Burate != Beti */
-  {"btj",      HB_TAG('M','L','Y',' ')},       /* Bacanese Malay -> Malay */
-/*{"btk",      HB_TAG('B','T','K',' ')},*/     /* Batak [collection] */
-  {"btm",      HB_TAG('B','T','M',' ')},       /* Batak Mandailing */
-  {"btm",      HB_TAG('B','T','K',' ')},       /* Batak Mandailing -> Batak */
-  {"bto",      HB_TAG('B','I','K',' ')},       /* Rinconada Bikol -> Bikol */
-  {"bts",      HB_TAG('B','T','S',' ')},       /* Batak Simalungun */
-  {"bts",      HB_TAG('B','T','K',' ')},       /* Batak Simalungun -> Batak */
-  {"btx",      HB_TAG('B','T','X',' ')},       /* Batak Karo */
-  {"btx",      HB_TAG('B','T','K',' ')},       /* Batak Karo -> Batak */
-  {"btz",      HB_TAG('B','T','Z',' ')},       /* Batak Alas-Kluet */
-  {"btz",      HB_TAG('B','T','K',' ')},       /* Batak Alas-Kluet -> Batak */
-/*{"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 */
-  {"bwe",      HB_TAG('K','R','N',' ')},       /* Bwe Karen -> Karen */
-  {"bxk",      HB_TAG('L','U','H',' ')},       /* Bukusu -> Luyia */
-  {"bxo",      HB_TAG('C','P','P',' ')},       /* Barikanchi -> Creoles */
-  {"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 */
-  {"byv",      HB_TAG('B','M','L',' ')},       /* Medumba -> Bamileke */
-  {"bzc",      HB_TAG('M','L','G',' ')},       /* Southern Betsimisaraka Malagasy -> Malagasy */
-  {"bzj",      HB_TAG('C','P','P',' ')},       /* Belize Kriol English -> Creoles */
-  {"bzk",      HB_TAG('C','P','P',' ')},       /* Nicaragua Creole English -> Creoles */
-  {"ca",       HB_TAG('C','A','T',' ')},       /* Catalan */
-  {"caa",      HB_TAG('M','Y','N',' ')},       /* Chortí -> Mayan */
-  {"cac",      HB_TAG('M','Y','N',' ')},       /* Chuj -> Mayan */
-  {"caf",      HB_TAG('C','R','R',' ')},       /* Southern Carrier -> Carrier */
-  {"caf",      HB_TAG('A','T','H',' ')},       /* Southern Carrier -> Athapaskan */
-  {"cak",      HB_TAG('C','A','K',' ')},       /* Kaqchikel */
-  {"cak",      HB_TAG('M','Y','N',' ')},       /* Kaqchikel -> Mayan */
-  {"cbk",      HB_TAG('C','B','K',' ')},       /* Chavacano -> Zamboanga Chavacano */
-  {"cbk",      HB_TAG('C','P','P',' ')},       /* Chavacano -> Creoles */
-  {"cbl",      HB_TAG('Q','I','N',' ')},       /* Bualkhaw Chin -> Chin */
-  {"ccl",      HB_TAG('C','P','P',' ')},       /* Cutchi-Swahili -> Creoles */
-  {"ccm",      HB_TAG('C','P','P',' ')},       /* Malaccan Creole Malay -> Creoles */
-  {"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 */
-  {"cek",      HB_TAG('Q','I','N',' ')},       /* Eastern Khumi Chin -> Chin */
-  {"cey",      HB_TAG('Q','I','N',' ')},       /* Ekai Chin -> Chin */
-  {"cfm",      HB_TAG('H','A','L',' ')},       /* Halam (Falam Chin) */
-  {"cfm",      HB_TAG('Q','I','N',' ')},       /* Falam Chin -> Chin */
-/*{"cgg",      HB_TAG('C','G','G',' ')},*/     /* Chiga */
-  {"ch",       HB_TAG('C','H','A',' ')},       /* Chamorro */
-  {"chf",      HB_TAG('M','Y','N',' ')},       /* Tabasco Chontal -> Mayan */
-  {"chg",      HB_TAG_NONE            },       /* Chagatai != Chaha Gurage */
-  {"chh",      HB_TAG_NONE            },       /* Chinook != Chattisgarhi */
-  {"chj",      HB_TAG('C','C','H','N')},       /* Ojitlán Chinantec -> Chinantec */
-  {"chk",      HB_TAG('C','H','K','0')},       /* Chuukese */
-  {"chm",      HB_TAG('H','M','A',' ')},       /* Mari (Russia) [macrolanguage] -> High Mari */
-  {"chm",      HB_TAG('L','M','A',' ')},       /* Mari (Russia) [macrolanguage] -> Low Mari */
-  {"chn",      HB_TAG('C','P','P',' ')},       /* Chinook jargon -> Creoles */
-/*{"cho",      HB_TAG('C','H','O',' ')},*/     /* Choctaw */
-  {"chp",      HB_TAG('C','H','P',' ')},       /* Chipewyan */
-  {"chp",      HB_TAG('S','A','Y',' ')},       /* Chipewyan -> Sayisi */
-  {"chp",      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 */
-  {"ckn",      HB_TAG('Q','I','N',' ')},       /* Kaang Chin -> Chin */
-  {"cks",      HB_TAG('C','P','P',' ')},       /* Tayo -> Creoles */
-  {"ckt",      HB_TAG('C','H','K',' ')},       /* Chukot -> Chukchi */
-  {"ckz",      HB_TAG('M','Y','N',' ')},       /* Cakchiquel-Quiché Mixed Language -> Mayan */
-  {"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 */
-  {"clj",      HB_TAG('Q','I','N',' ')},       /* Laitu Chin -> Chin */
-  {"clt",      HB_TAG('Q','I','N',' ')},       /* Lautu Chin -> Chin */
-  {"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 */
-  {"cnp",      HB_TAG('Z','H','S',' ')},       /* Northern Ping Chinese -> Chinese, Simplified */
-  {"cnr",      HB_TAG('S','R','B',' ')},       /* Montenegrin -> Serbian */
-  {"cnt",      HB_TAG('C','C','H','N')},       /* Tepetotutla Chinantec -> Chinantec */
-  {"cnu",      HB_TAG('B','B','R',' ')},       /* Chenoua -> Berber */
-  {"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 */
-  {"cob",      HB_TAG('M','Y','N',' ')},       /* Chicomuceltec -> Mayan */
-/*{"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 [collection] -> Creoles */
-  {"cpf",      HB_TAG('C','P','P',' ')},       /* French-based creoles and pidgins [collection] -> Creoles */
-  {"cpi",      HB_TAG('C','P','P',' ')},       /* Chinese Pidgin English -> Creoles */
-/*{"cpp",      HB_TAG('C','P','P',' ')},*/     /* Portuguese-based creoles and pidgins [collection] -> 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) */
-  {"cqu",      HB_TAG('Q','U','Z',' ')},       /* Chilean Quechua (retired code) -> Quechua */
-  {"cr",       HB_TAG('C','R','E',' ')},       /* Cree [macrolanguage] */
-  {"crh",      HB_TAG('C','R','T',' ')},       /* Crimean Tatar */
-  {"cri",      HB_TAG('C','P','P',' ')},       /* Sãotomense -> Creoles */
-  {"crj",      HB_TAG('E','C','R',' ')},       /* Southern East Cree -> Eastern Cree */
-  {"crj",      HB_TAG('Y','C','R',' ')},       /* Southern East Cree -> Y-Cree */
-  {"crj",      HB_TAG('C','R','E',' ')},       /* Southern East Cree -> Cree */
-  {"crk",      HB_TAG('W','C','R',' ')},       /* Plains Cree -> West-Cree */
-  {"crk",      HB_TAG('Y','C','R',' ')},       /* Plains Cree -> Y-Cree */
-  {"crk",      HB_TAG('C','R','E',' ')},       /* Plains Cree -> Cree */
-  {"crl",      HB_TAG('E','C','R',' ')},       /* Northern East Cree -> Eastern Cree */
-  {"crl",      HB_TAG('Y','C','R',' ')},       /* Northern East Cree -> Y-Cree */
-  {"crl",      HB_TAG('C','R','E',' ')},       /* Northern East Cree -> Cree */
-  {"crm",      HB_TAG('M','C','R',' ')},       /* Moose Cree */
-  {"crm",      HB_TAG('L','C','R',' ')},       /* Moose Cree -> L-Cree */
-  {"crm",      HB_TAG('C','R','E',' ')},       /* Moose Cree -> Cree */
-  {"crp",      HB_TAG('C','P','P',' ')},       /* Creoles and pidgins [collection] -> Creoles */
-  {"crr",      HB_TAG_NONE            },       /* Carolina Algonquian != Carrier */
-  {"crs",      HB_TAG('C','P','P',' ')},       /* Seselwa Creole French -> Creoles */
-  {"crt",      HB_TAG_NONE            },       /* Iyojwa'ja Chorote != Crimean Tatar */
-  {"crx",      HB_TAG('C','R','R',' ')},       /* Carrier */
-  {"crx",      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 */
-  {"csj",      HB_TAG('Q','I','N',' ')},       /* Songlai Chin -> Chin */
-  {"csl",      HB_TAG_NONE            },       /* Chinese Sign Language != Church Slavonic */
-  {"cso",      HB_TAG('C','C','H','N')},       /* Sochiapam Chinantec -> Chinantec */
-  {"csp",      HB_TAG('Z','H','S',' ')},       /* Southern Ping Chinese -> Chinese, Simplified */
-  {"csv",      HB_TAG('Q','I','N',' ')},       /* Sumtu Chin -> Chin */
-  {"csw",      HB_TAG('N','C','R',' ')},       /* Swampy Cree -> N-Cree */
-  {"csw",      HB_TAG('N','H','C',' ')},       /* Swampy Cree -> Norway House Cree */
-  {"csw",      HB_TAG('C','R','E',' ')},       /* Swampy Cree -> 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 */
-  {"cth",      HB_TAG('Q','I','N',' ')},       /* Thaiphum Chin -> Chin */
-  {"ctl",      HB_TAG('C','C','H','N')},       /* Tlacoatzintepec Chinantec -> Chinantec */
-  {"cts",      HB_TAG('B','I','K',' ')},       /* Northern Catanduanes Bikol -> Bikol */
-/*{"ctt",      HB_TAG('C','T','T',' ')},*/     /* Wayanad Chetti */
-  {"ctu",      HB_TAG('M','Y','N',' ')},       /* Chol -> Mayan */
-  {"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 */
-  {"cwd",      HB_TAG('T','C','R',' ')},       /* Woods Cree -> TH-Cree */
-  {"cwd",      HB_TAG('C','R','E',' ')},       /* Woods Cree -> 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 */
-/*{"dag",      HB_TAG('D','A','G',' ')},*/     /* Dagbani */
-  {"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 */
-  {"dcr",      HB_TAG('C','P','P',' ')},       /* Negerhollands -> Creoles */
-  {"de",       HB_TAG('D','E','U',' ')},       /* German */
-  {"den",      HB_TAG('S','L','A',' ')},       /* Slave (Athapascan) [macrolanguage] -> Slavey */
-  {"den",      HB_TAG('A','T','H',' ')},       /* Slave (Athapascan) [macrolanguage] -> Athapaskan */
-  {"dep",      HB_TAG('C','P','P',' ')},       /* Pidgin Delaware -> Creoles */
-  {"dgo",      HB_TAG('D','G','O',' ')},       /* Dogri (individual language) */
-  {"dgo",      HB_TAG('D','G','R',' ')},       /* Dogri (macrolanguage) */
-  {"dgr",      HB_TAG('A','T','H',' ')},       /* Dogrib -> Athapaskan */
-  {"dhd",      HB_TAG('M','A','W',' ')},       /* Dhundari -> Marwari */
-/*{"dhg",      HB_TAG('D','H','G',' ')},*/     /* Dhangu */
-  {"dhv",      HB_TAG_NONE            },       /* Dehu != Divehi (Dhivehi, Maldivian) (deprecated) */
-  {"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 */
-  {"diq",      HB_TAG('Z','Z','A',' ')},       /* Dimli -> Zazaki */
-  {"diw",      HB_TAG('D','N','K',' ')},       /* Northwestern Dinka -> Dinka */
-  {"dje",      HB_TAG('D','J','R',' ')},       /* Zarma */
-  {"djk",      HB_TAG('C','P','P',' ')},       /* Eastern Maroon Creole -> Creoles */
-  {"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 */
-  {"dnk",      HB_TAG_NONE            },       /* Dengka != Dinka */
-  {"doi",      HB_TAG('D','G','R',' ')},       /* Dogri (macrolanguage) [macrolanguage] */
-  {"drh",      HB_TAG('M','N','G',' ')},       /* Darkhat (retired code) -> Mongolian */
-  {"dri",      HB_TAG_NONE            },       /* C'Lela != Dari */
-  {"drw",      HB_TAG('D','R','I',' ')},       /* Darwazi (retired code) -> Dari */
-  {"drw",      HB_TAG('F','A','R',' ')},       /* Darwazi (retired code) -> Persian */
-  {"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) */
-  {"dun",      HB_TAG_NONE            },       /* Dusun Deyah != Dungan */
-  {"dup",      HB_TAG('M','L','Y',' ')},       /* Duano -> Malay */
-  {"dv",       HB_TAG('D','I','V',' ')},       /* Divehi (Dhivehi, Maldivian) */
-  {"dv",       HB_TAG('D','H','V',' ')},       /* Divehi (Dhivehi, Maldivian) (deprecated) */
-  {"dwk",      HB_TAG('K','U','I',' ')},       /* Dawik Kui -> Kui */
-  {"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 */
-  {"dzn",      HB_TAG_NONE            },       /* Dzando != Dzongkha */
-  {"ecr",      HB_TAG_NONE            },       /* Eteocretan != Eastern Cree */
-  {"ee",       HB_TAG('E','W','E',' ')},       /* Ewe */
-/*{"efi",      HB_TAG('E','F','I',' ')},*/     /* Efik */
-  {"ekk",      HB_TAG('E','T','I',' ')},       /* Standard Estonian -> Estonian */
-  {"eky",      HB_TAG('K','R','N',' ')},       /* Eastern Kayah -> Karen */
-  {"el",       HB_TAG('E','L','L',' ')},       /* Modern Greek (1453-) -> Greek */
-  {"emk",      HB_TAG('E','M','K',' ')},       /* Eastern Maninkakan */
-  {"emk",      HB_TAG('M','N','K',' ')},       /* Eastern Maninkakan -> Maninka */
-  {"emy",      HB_TAG('M','Y','N',' ')},       /* Epigraphic Mayan -> Mayan */
-  {"en",       HB_TAG('E','N','G',' ')},       /* English */
-  {"enb",      HB_TAG('K','A','L',' ')},       /* Markweeta -> Kalenjin */
-  {"enf",      HB_TAG('F','N','E',' ')},       /* Forest Enets */
-  {"enh",      HB_TAG('T','N','E',' ')},       /* Tundra Enets */
-  {"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 */
-  {"euq",      HB_TAG_NONE            },       /* Basque [collection] != 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] */
-  {"fab",      HB_TAG('C','P','P',' ')},       /* Fa d'Ambu -> Creoles */
-  {"fan",      HB_TAG('F','A','N','0')},       /* Fang (Equatorial Guinea) */
-  {"fan",      HB_TAG('B','T','I',' ')},       /* Fang (Equatorial Guinea) -> Beti */
-  {"far",      HB_TAG_NONE            },       /* Fataleka != Persian */
-  {"fat",      HB_TAG('F','A','T',' ')},       /* Fanti */
-  {"fat",      HB_TAG('A','K','A',' ')},       /* Fanti -> Akan */
-  {"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) */
-  {"flm",      HB_TAG('Q','I','N',' ')},       /* Falam Chin (retired code) -> Chin */
-  {"fmp",      HB_TAG('F','M','P',' ')},       /* Fe’fe’ */
-  {"fmp",      HB_TAG('B','M','L',' ')},       /* Fe'fe' -> Bamileke */
-  {"fng",      HB_TAG('C','P','P',' ')},       /* Fanagalo -> Creoles */
-  {"fo",       HB_TAG('F','O','S',' ')},       /* Faroese */
-/*{"fon",      HB_TAG('F','O','N',' ')},*/     /* Fon */
-  {"fos",      HB_TAG_NONE            },       /* Siraya != Faroese */
-  {"fpe",      HB_TAG('C','P','P',' ')},       /* Fernando Po Creole English -> Creoles */
-  {"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 */
-  {"fuf",      HB_TAG('F','U','L',' ')},       /* Pular -> Fulah */
-  {"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 */
-  {"fuv",      HB_TAG('F','U','L',' ')},       /* Nigerian Fulfulde -> Fulah */
-  {"fy",       HB_TAG('F','R','I',' ')},       /* Western Frisian -> Frisian */
-  {"ga",       HB_TAG('I','R','I',' ')},       /* Irish */
-  {"gaa",      HB_TAG('G','A','D',' ')},       /* Ga */
-  {"gac",      HB_TAG('C','P','P',' ')},       /* Mixed Great Andamanese -> Creoles */
-  {"gad",      HB_TAG_NONE            },       /* Gaddang != Ga */
-  {"gae",      HB_TAG_NONE            },       /* Guarequena != Scottish Gaelic (Gaelic) */
-/*{"gag",      HB_TAG('G','A','G',' ')},*/     /* Gagauz */
-  {"gal",      HB_TAG_NONE            },       /* Galolen != Galician */
-  {"gan",      HB_TAG('Z','H','S',' ')},       /* Gan Chinese -> Chinese, Simplified */
-  {"gar",      HB_TAG_NONE            },       /* Galeya != Garshuni */
-  {"gaw",      HB_TAG_NONE            },       /* Nobonob != Garhwali */
-  {"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 */
-  {"gcf",      HB_TAG('C','P','P',' ')},       /* Guadeloupean Creole French -> Creoles */
-  {"gcl",      HB_TAG('C','P','P',' ')},       /* Grenadian Creole English -> Creoles */
-  {"gcr",      HB_TAG('C','P','P',' ')},       /* Guianese Creole French -> Creoles */
-  {"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 */
-  {"gha",      HB_TAG('B','B','R',' ')},       /* Ghadamès -> Berber */
-  {"ghk",      HB_TAG('K','R','N',' ')},       /* Geko Karen -> Karen */
-  {"gho",      HB_TAG('B','B','R',' ')},       /* Ghomara -> Berber */
-  {"gib",      HB_TAG('C','P','P',' ')},       /* Gibanawa -> Creoles */
-/*{"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) */
-  {"gkp",      HB_TAG('K','P','L',' ')},       /* Guinea Kpelle -> Kpelle */
-  {"gl",       HB_TAG('G','A','L',' ')},       /* Galician */
-  {"gld",      HB_TAG('N','A','N',' ')},       /* Nanai */
-/*{"glk",      HB_TAG('G','L','K',' ')},*/     /* Gilaki */
-  {"gmz",      HB_TAG_NONE            },       /* Mgbolizhia != Gumuz */
-  {"gn",       HB_TAG('G','U','A',' ')},       /* Guarani [macrolanguage] */
-  {"gnb",      HB_TAG('Q','I','N',' ')},       /* Gangte -> Chin */
-/*{"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] */
-  {"goq",      HB_TAG('C','P','P',' ')},       /* Gorap -> Creoles */
-  {"gox",      HB_TAG('B','A','D','0')},       /* Gobu -> Banda */
-  {"gpe",      HB_TAG('C','P','P',' ')},       /* Ghanaian Pidgin English -> Creoles */
-  {"gro",      HB_TAG_NONE            },       /* Groma != Garo */
-  {"grr",      HB_TAG('B','B','R',' ')},       /* Taznatit -> Berber */
-  {"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 */
-  {"gua",      HB_TAG_NONE            },       /* Shiki != Guarani */
-/*{"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 */
-  {"gul",      HB_TAG('C','P','P',' ')},       /* Sea Island Creole English -> Creoles */
-  {"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 */
-  {"gyn",      HB_TAG('C','P','P',' ')},       /* Guyanese Creole English -> Creoles */
-  {"ha",       HB_TAG('H','A','U',' ')},       /* Hausa */
-  {"haa",      HB_TAG('A','T','H',' ')},       /* Han -> Athapaskan */
-  {"hae",      HB_TAG('O','R','O',' ')},       /* Eastern Oromo -> Oromo */
-  {"hai",      HB_TAG('H','A','I','0')},       /* Haida [macrolanguage] */
-  {"hak",      HB_TAG('Z','H','S',' ')},       /* Hakka Chinese -> Chinese, Simplified */
-  {"hal",      HB_TAG_NONE            },       /* Halang != Halam (Falam Chin) */
-  {"har",      HB_TAG('H','R','I',' ')},       /* Harari */
-/*{"haw",      HB_TAG('H','A','W',' ')},*/     /* Hawaiian */
-  {"hax",      HB_TAG('H','A','I','0')},       /* Southern Haida -> Haida */
-/*{"hay",      HB_TAG('H','A','Y',' ')},*/     /* Haya */
-/*{"haz",      HB_TAG('H','A','Z',' ')},*/     /* Hazaragi */
-  {"hbn",      HB_TAG_NONE            },       /* Heiban != Hammer-Banna */
-  {"hca",      HB_TAG('C','P','P',' ')},       /* Andaman Creole Hindi -> Creoles */
-  {"hdn",      HB_TAG('H','A','I','0')},       /* Northern Haida -> Haida */
-  {"he",       HB_TAG('I','W','R',' ')},       /* Hebrew */
-  {"hea",      HB_TAG('H','M','N',' ')},       /* Northern Qiandong Miao -> Hmong */
-/*{"hei",      HB_TAG('H','E','I',' ')},*/     /* Heiltsuk */
-  {"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','D',' ')},       /* Large Flowery Miao -> A-Hmao */
-  {"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 */
-  {"hmr",      HB_TAG('Q','I','N',' ')},       /* Hmar -> Chin */
-  {"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','Z',' ')},       /* Hmong Shua -> Hmong Shuat */
-  {"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 */
-  {"ho",       HB_TAG('C','P','P',' ')},       /* Hiri Motu -> Creoles */
-  {"hoc",      HB_TAG('H','O',' ',' ')},       /* Ho */
-  {"hoi",      HB_TAG('A','T','H',' ')},       /* Holikachuk -> Athapaskan */
-  {"hoj",      HB_TAG('H','A','R',' ')},       /* Hadothi -> Harauti */
-  {"hoj",      HB_TAG('R','A','J',' ')},       /* Hadothi -> Rajasthani */
-  {"hr",       HB_TAG('H','R','V',' ')},       /* Croatian */
-  {"hra",      HB_TAG('Q','I','N',' ')},       /* Hrangkhol -> Chin */
-  {"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) */
-  {"ht",       HB_TAG('C','P','P',' ')},       /* Haitian -> Creoles */
-  {"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 */
-  {"hus",      HB_TAG('M','Y','N',' ')},       /* Huastec -> Mayan */
-  {"hwc",      HB_TAG('C','P','P',' ')},       /* Hawai'i Creole English -> Creoles */
-  {"hy",       HB_TAG('H','Y','E','0')},       /* Armenian -> Armenian East */
-  {"hy",       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 */
-  {"iby",      HB_TAG('I','J','O',' ')},       /* Ibani -> Ijo */
-  {"icr",      HB_TAG('C','P','P',' ')},       /* Islander Creole English -> Creoles */
-  {"id",       HB_TAG('I','N','D',' ')},       /* Indonesian */
-  {"id",       HB_TAG('M','L','Y',' ')},       /* Indonesian -> Malay */
-  {"ida",      HB_TAG('L','U','H',' ')},       /* Idakho-Isukha-Tiriki -> Luyia */
-  {"idb",      HB_TAG('C','P','P',' ')},       /* Indo-Portuguese -> Creoles */
-  {"ie",       HB_TAG('I','L','E',' ')},       /* Interlingue */
-  {"ig",       HB_TAG('I','B','O',' ')},       /* Igbo */
-  {"igb",      HB_TAG('E','B','I',' ')},       /* Ebira */
-  {"ihb",      HB_TAG('C','P','P',' ')},       /* Iha Based Pidgin -> Creoles */
-  {"ii",       HB_TAG('Y','I','M',' ')},       /* Sichuan Yi -> Yi Modern */
-  {"ijc",      HB_TAG('I','J','O',' ')},       /* Izon -> Ijo */
-  {"ije",      HB_TAG('I','J','O',' ')},       /* Biseni -> Ijo */
-  {"ijn",      HB_TAG('I','J','O',' ')},       /* Kalabari -> Ijo */
-/*{"ijo",      HB_TAG('I','J','O',' ')},*/     /* Ijo [collection] */
-  {"ijs",      HB_TAG('I','J','O',' ')},       /* Southeast Ijo -> Ijo */
-  {"ik",       HB_TAG('I','P','K',' ')},       /* Inupiaq [macrolanguage] -> Inupiat */
-  {"ike",      HB_TAG('I','N','U',' ')},       /* Eastern Canadian Inuktitut -> Inuktitut */
-  {"ike",      HB_TAG('I','N','U','K')},       /* Eastern Canadian Inuktitut -> Nunavik 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) */
-  {"in",       HB_TAG('M','L','Y',' ')},       /* Indonesian (retired code) -> Malay */
-  {"ing",      HB_TAG('A','T','H',' ')},       /* Degexit'an -> Athapaskan */
-  {"inh",      HB_TAG('I','N','G',' ')},       /* Ingush */
-  {"io",       HB_TAG('I','D','O',' ')},       /* Ido */
-  {"iri",      HB_TAG_NONE            },       /* Rigwe != Irish */
-/*{"iru",      HB_TAG('I','R','U',' ')},*/     /* Irula */
-  {"is",       HB_TAG('I','S','L',' ')},       /* Icelandic */
-  {"ism",      HB_TAG_NONE            },       /* Masimasi != Inari Sami */
-  {"it",       HB_TAG('I','T','A',' ')},       /* Italian */
-  {"itz",      HB_TAG('M','Y','N',' ')},       /* Itzá -> Mayan */
-  {"iu",       HB_TAG('I','N','U',' ')},       /* Inuktitut [macrolanguage] */
-  {"iu",       HB_TAG('I','N','U','K')},       /* Inuktitut [macrolanguage] -> Nunavik Inuktitut */
-  {"iw",       HB_TAG('I','W','R',' ')},       /* Hebrew (retired code) */
-  {"ixl",      HB_TAG('M','Y','N',' ')},       /* Ixil -> Mayan */
-  {"ja",       HB_TAG('J','A','N',' ')},       /* Japanese */
-  {"jac",      HB_TAG('M','Y','N',' ')},       /* Popti' -> Mayan */
-  {"jak",      HB_TAG('M','L','Y',' ')},       /* Jakun -> Malay */
-  {"jam",      HB_TAG('J','A','M',' ')},       /* Jamaican Creole English -> Jamaican Creole */
-  {"jam",      HB_TAG('C','P','P',' ')},       /* Jamaican Creole English -> Creoles */
-  {"jan",      HB_TAG_NONE            },       /* Jandai != Japanese */
-  {"jax",      HB_TAG('M','L','Y',' ')},       /* Jambi Malay -> Malay */
-  {"jbe",      HB_TAG('B','B','R',' ')},       /* Judeo-Berber -> Berber */
-  {"jbn",      HB_TAG('B','B','R',' ')},       /* Nafusi -> Berber */
-/*{"jbo",      HB_TAG('J','B','O',' ')},*/     /* Lojban */
-/*{"jct",      HB_TAG('J','C','T',' ')},*/     /* Krymchak */
-  {"jgo",      HB_TAG('B','M','L',' ')},       /* Ngomba -> Bamileke */
-  {"ji",       HB_TAG('J','I','I',' ')},       /* Yiddish (retired code) */
-  {"jii",      HB_TAG_NONE            },       /* Jiiddu != Yiddish */
-  {"jkm",      HB_TAG('K','R','N',' ')},       /* Mobwa Karen -> Karen */
-  {"jkp",      HB_TAG('K','R','N',' ')},       /* Paku Karen -> Karen */
-  {"jud",      HB_TAG_NONE            },       /* Worodougou != Ladino */
-  {"jul",      HB_TAG_NONE            },       /* Jirel != Jula */
-  {"jv",       HB_TAG('J','A','V',' ')},       /* Javanese */
-  {"jvd",      HB_TAG('C','P','P',' ')},       /* Javindo -> Creoles */
-  {"jw",       HB_TAG('J','A','V',' ')},       /* Javanese (retired code) */
-  {"ka",       HB_TAG('K','A','T',' ')},       /* Georgian */
-  {"kaa",      HB_TAG('K','R','K',' ')},       /* Karakalpak */
-  {"kab",      HB_TAG('K','A','B','0')},       /* Kabyle */
-  {"kab",      HB_TAG('B','B','R',' ')},       /* Kabyle -> Berber */
-  {"kac",      HB_TAG_NONE            },       /* Kachin != Kachchi */
-  {"kam",      HB_TAG('K','M','B',' ')},       /* Kamba (Kenya) */
-  {"kar",      HB_TAG('K','R','N',' ')},       /* Karen [collection] */
-/*{"kaw",      HB_TAG('K','A','W',' ')},*/     /* Kawi (Old Javanese) */
-  {"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 */
-  {"kca",      HB_TAG('K','H','S',' ')},       /* Khanty -> Khanty-Shurishkar */
-  {"kca",      HB_TAG('K','H','V',' ')},       /* Khanty -> Khanty-Vakhi */
-  {"kcn",      HB_TAG('C','P','P',' ')},       /* Nubi -> Creoles */
-/*{"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) */
-  {"kea",      HB_TAG('C','P','P',' ')},       /* Kabuverdianu -> Creoles */
-  {"keb",      HB_TAG_NONE            },       /* Kélé != Kebena */
-  {"kek",      HB_TAG('K','E','K',' ')},       /* Kekchi */
-  {"kek",      HB_TAG('M','Y','N',' ')},       /* Kekchí -> Mayan */
-  {"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] */
-  {"kge",      HB_TAG_NONE            },       /* Komering != Khutsuri Georgian */
-  {"kha",      HB_TAG('K','S','I',' ')},       /* Khasi */
-  {"khb",      HB_TAG('X','B','D',' ')},       /* Lü */
-  {"khk",      HB_TAG('M','N','G',' ')},       /* Halh Mongolian -> Mongolian */
-  {"khn",      HB_TAG_NONE            },       /* Khandesi != Khamti Shan (Microsoft fonts) */
-  {"khs",      HB_TAG_NONE            },       /* Kasua != Khanty-Shurishkar */
-  {"kht",      HB_TAG('K','H','T',' ')},       /* Khamti -> Khamti Shan */
-  {"kht",      HB_TAG('K','H','N',' ')},       /* Khamti -> Khamti Shan (Microsoft fonts) */
-  {"khv",      HB_TAG_NONE            },       /* Khvarshi != Khanty-Vakhi */
-/*{"khw",      HB_TAG('K','H','W',' ')},*/     /* Khowar */
-  {"ki",       HB_TAG('K','I','K',' ')},       /* Kikuyu (Gikuyu) */
-  {"kis",      HB_TAG_NONE            },       /* Kis != Kisii */
-  {"kiu",      HB_TAG('K','I','U',' ')},       /* Kirmanjki */
-  {"kiu",      HB_TAG('Z','Z','A',' ')},       /* Kirmanjki -> Zazaki */
-  {"kj",       HB_TAG('K','U','A',' ')},       /* Kuanyama */
-  {"kjb",      HB_TAG('M','Y','N',' ')},       /* Q'anjob'al -> Mayan */
-/*{"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 */
-  {"kjp",      HB_TAG('K','R','N',' ')},       /* Pwo Eastern Karen -> Karen */
-  {"kjt",      HB_TAG('K','R','N',' ')},       /* Phrae Pwo Karen -> Karen */
-/*{"kjz",      HB_TAG('K','J','Z',' ')},*/     /* Bumthangkha */
-  {"kk",       HB_TAG('K','A','Z',' ')},       /* Kazakh */
-  {"kkn",      HB_TAG_NONE            },       /* Kon Keu != Kokni */
-  {"kkz",      HB_TAG('A','T','H',' ')},       /* Kaska -> Athapaskan */
-  {"kl",       HB_TAG('G','R','N',' ')},       /* Greenlandic */
-  {"klm",      HB_TAG_NONE            },       /* Migum != Kalmyk */
-  {"kln",      HB_TAG('K','A','L',' ')},       /* Kalenjin [macrolanguage] */
-  {"km",       HB_TAG('K','H','M',' ')},       /* Khmer */
-  {"kmb",      HB_TAG('M','B','N',' ')},       /* Kimbundu -> Mbundu */
-  {"kmn",      HB_TAG_NONE            },       /* Awtuw != Kumaoni */
-  {"kmo",      HB_TAG_NONE            },       /* Kwoma != Komo */
-  {"kmr",      HB_TAG('K','U','R',' ')},       /* Northern Kurdish -> Kurdish */
-  {"kms",      HB_TAG_NONE            },       /* Kamasau != Komso */
-  {"kmv",      HB_TAG('C','P','P',' ')},       /* Karipúna Creole French -> Creoles */
-  {"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 */
-  {"knj",      HB_TAG('M','Y','N',' ')},       /* Western Kanjobal -> Mayan */
-  {"knn",      HB_TAG('K','O','K',' ')},       /* Konkani */
-  {"knr",      HB_TAG_NONE            },       /* Kaningra != Kanuri */
-  {"ko",       HB_TAG('K','O','R',' ')},       /* Korean */
-  {"ko",       HB_TAG('K','O','H',' ')},       /* Korean -> Korean Old Hangul */
-  {"kod",      HB_TAG_NONE            },       /* Kodi != Kodagu */
-  {"koh",      HB_TAG_NONE            },       /* Koyo != Korean Old Hangul */
-  {"koi",      HB_TAG('K','O','P',' ')},       /* Komi-Permyak */
-  {"koi",      HB_TAG('K','O','M',' ')},       /* Komi-Permyak -> Komi */
-/*{"kok",      HB_TAG('K','O','K',' ')},*/     /* Konkani [macrolanguage] */
-  {"kop",      HB_TAG_NONE            },       /* Waube != Komi-Permyak */
-/*{"kos",      HB_TAG('K','O','S',' ')},*/     /* Kosraean */
-  {"koy",      HB_TAG('A','T','H',' ')},       /* Koyukon -> Athapaskan */
-  {"koz",      HB_TAG_NONE            },       /* Korak != Komi-Zyrian */
-  {"kpe",      HB_TAG('K','P','L',' ')},       /* Kpelle [macrolanguage] */
-  {"kpl",      HB_TAG_NONE            },       /* Kpala != Kpelle */
-  {"kpp",      HB_TAG('K','R','N',' ')},       /* Paku Karen (retired code) -> Karen */
-  {"kpv",      HB_TAG('K','O','Z',' ')},       /* Komi-Zyrian */
-  {"kpv",      HB_TAG('K','O','M',' ')},       /* Komi-Zyrian -> Komi */
-  {"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 */
-  {"krc",      HB_TAG('B','A','L',' ')},       /* Karachay-Balkar -> Balkar */
-  {"kri",      HB_TAG('K','R','I',' ')},       /* Krio */
-  {"kri",      HB_TAG('C','P','P',' ')},       /* Krio -> Creoles */
-  {"krk",      HB_TAG_NONE            },       /* Kerek != Karakalpak */
-/*{"krl",      HB_TAG('K','R','L',' ')},*/     /* Karelian */
-  {"krm",      HB_TAG_NONE            },       /* Krim (retired code) != Karaim */
-  {"krn",      HB_TAG_NONE            },       /* Sapo != Karen */
-  {"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 */
-  {"ksi",      HB_TAG_NONE            },       /* Krisa != Khasi */
-  {"ksm",      HB_TAG_NONE            },       /* Kumba != Kildin Sami */
-  {"kss",      HB_TAG('K','I','S',' ')},       /* Southern Kisi -> Kisii */
-  {"ksw",      HB_TAG('K','S','W',' ')},       /* S’gaw Karen */
-  {"ksw",      HB_TAG('K','R','N',' ')},       /* S'gaw Karen -> 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] */
-  {"kui",      HB_TAG_NONE            },       /* Kuikúro-Kalapálo != Kui */
-  {"kul",      HB_TAG_NONE            },       /* Kulere != Kulvi */
-/*{"kum",      HB_TAG('K','U','M',' ')},*/     /* Kumyk */
-  {"kuu",      HB_TAG('A','T','H',' ')},       /* Upper Kuskokwim -> Athapaskan */
-  {"kuw",      HB_TAG('B','A','D','0')},       /* Kpagua -> Banda */
-  {"kuy",      HB_TAG_NONE            },       /* Kuuku-Ya'u != Kuy */
-  {"kv",       HB_TAG('K','O','M',' ')},       /* Komi [macrolanguage] */
-  {"kvb",      HB_TAG('M','L','Y',' ')},       /* Kubu -> Malay */
-  {"kvl",      HB_TAG('K','R','N',' ')},       /* Kayaw -> Karen */
-  {"kvq",      HB_TAG('K','R','N',' ')},       /* Geba Karen -> Karen */
-  {"kvr",      HB_TAG('M','L','Y',' ')},       /* Kerinci -> Malay */
-  {"kvt",      HB_TAG('K','R','N',' ')},       /* Lahta Karen -> Karen */
-  {"kvu",      HB_TAG('K','R','N',' ')},       /* Yinbaw Karen -> Karen */
-  {"kvy",      HB_TAG('K','R','N',' ')},       /* Yintale Karen -> Karen */
-  {"kw",       HB_TAG('C','O','R',' ')},       /* Cornish */
-/*{"kwk",      HB_TAG('K','W','K',' ')},*/     /* Kwakiutl -> Kwakʼwala */
-  {"kww",      HB_TAG('C','P','P',' ')},       /* Kwinti -> Creoles */
-  {"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 */
-  {"kxf",      HB_TAG('K','R','N',' ')},       /* Manumanaw Karen -> Karen */
-  {"kxk",      HB_TAG('K','R','N',' ')},       /* Zayein Karen -> Karen */
-  {"kxl",      HB_TAG('K','U','U',' ')},       /* Nepali Kurux (retired code) -> Kurukh */
-  {"kxu",      HB_TAG('K','U','I',' ')},       /* Kui (India) (retired code) */
-  {"ky",       HB_TAG('K','I','R',' ')},       /* Kirghiz (Kyrgyz) */
-  {"kyk",      HB_TAG_NONE            },       /* Kamayo != Koryak */
-  {"kyu",      HB_TAG('K','Y','U',' ')},       /* Western Kayah */
-  {"kyu",      HB_TAG('K','R','N',' ')},       /* Western Kayah -> Karen */
-  {"la",       HB_TAG('L','A','T',' ')},       /* Latin */
-  {"lac",      HB_TAG('M','Y','N',' ')},       /* Lacandon -> Mayan */
-  {"lad",      HB_TAG('J','U','D',' ')},       /* Ladino */
-  {"lah",      HB_TAG_NONE            },       /* Lahnda [macrolanguage] != Lahuli */
-  {"lak",      HB_TAG_NONE            },       /* Laka (Nigeria) != Lak */
-  {"lam",      HB_TAG_NONE            },       /* Lamba != Lambani */
-  {"laz",      HB_TAG_NONE            },       /* Aribwatsa != Laz */
-  {"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 */
-  {"ldk",      HB_TAG_NONE            },       /* Leelau != Ladakhi */
-/*{"lef",      HB_TAG('L','E','F',' ')},*/     /* Lelemi */
-/*{"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 */
-  {"lir",      HB_TAG('C','P','P',' ')},       /* Liberian English -> Creoles */
-/*{"lis",      HB_TAG('L','I','S',' ')},*/     /* Lisu */
-  {"liw",      HB_TAG('M','L','Y',' ')},       /* Col -> Malay */
-  {"liy",      HB_TAG('B','A','D','0')},       /* Banda-Bambari -> Banda */
-/*{"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 */
-  {"lma",      HB_TAG_NONE            },       /* East Limba != Low Mari */
-  {"lmb",      HB_TAG_NONE            },       /* Merei != Limbu */
-  {"lmn",      HB_TAG('L','A','M',' ')},       /* Lambadi -> Lambani */
-/*{"lmo",      HB_TAG('L','M','O',' ')},*/     /* Lombard */
-  {"lmw",      HB_TAG_NONE            },       /* Lake Miwok != Lomwe */
-  {"ln",       HB_TAG('L','I','N',' ')},       /* Lingala */
-  {"lna",      HB_TAG('B','A','D','0')},       /* Langbashe -> Banda */
-  {"lnl",      HB_TAG('B','A','D','0')},       /* South Central Banda -> Banda */
-  {"lo",       HB_TAG('L','A','O',' ')},       /* Lao */
-/*{"lom",      HB_TAG('L','O','M',' ')},*/     /* Loma (Liberia) */
-  {"lou",      HB_TAG('C','P','P',' ')},       /* Louisiana Creole -> Creoles */
-/*{"lpo",      HB_TAG('L','P','O',' ')},*/     /* Lipo */
-/*{"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 */
-  {"lrt",      HB_TAG('C','P','P',' ')},       /* Larantuka Malay -> Creoles */
-  {"lsb",      HB_TAG_NONE            },       /* Burundian Sign Language != Lower Sorbian */
-  {"lsm",      HB_TAG('L','U','H',' ')},       /* Saamia -> Luyia */
-  {"lt",       HB_TAG('L','T','H',' ')},       /* Lithuanian */
-  {"ltg",      HB_TAG('L','V','I',' ')},       /* Latgalian -> Latvian */
-  {"lth",      HB_TAG_NONE            },       /* Thur != Lithuanian */
-  {"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 */
-  {"lus",      HB_TAG('Q','I','N',' ')},       /* Lushai -> Chin */
-  {"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] */
-  {"lvi",      HB_TAG_NONE            },       /* Lavi != Latvian */
-  {"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 */
-  {"maj",      HB_TAG_NONE            },       /* Jalapa De Díaz Mazatec != Majang */
-  {"mak",      HB_TAG('M','K','R',' ')},       /* Makasar */
-  {"mam",      HB_TAG('M','A','M',' ')},       /* Mam */
-  {"mam",      HB_TAG('M','Y','N',' ')},       /* Mam -> Mayan */
-  {"man",      HB_TAG('M','N','K',' ')},       /* Mandingo [macrolanguage] -> Maninka */
-  {"map",      HB_TAG_NONE            },       /* Austronesian [collection] != Mapudungun */
-  {"maw",      HB_TAG_NONE            },       /* Mampruli != Marwari */
-  {"max",      HB_TAG('M','L','Y',' ')},       /* North Moluccan Malay -> Malay */
-  {"max",      HB_TAG('C','P','P',' ')},       /* North Moluccan Malay -> Creoles */
-  {"mbf",      HB_TAG('C','P','P',' ')},       /* Baba Malay -> Creoles */
-  {"mbn",      HB_TAG_NONE            },       /* Macaguán != Mbundu */
-/*{"mbo",      HB_TAG('M','B','O',' ')},*/     /* Mbo (Cameroon) */
-  {"mch",      HB_TAG_NONE            },       /* Maquiritari != Manchu */
-  {"mcm",      HB_TAG('C','P','P',' ')},       /* Malaccan Creole Portuguese -> Creoles */
-  {"mcr",      HB_TAG_NONE            },       /* Menya != Moose Cree */
-  {"mct",      HB_TAG('B','T','I',' ')},       /* Mengisa -> Beti */
-  {"mde",      HB_TAG_NONE            },       /* Maba (Chad) != Mende */
-  {"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 */
-  {"mfa",      HB_TAG('M','L','Y',' ')},       /* Pattani Malay -> Malay */
-  {"mfb",      HB_TAG('M','L','Y',' ')},       /* Bangka -> Malay */
-  {"mfe",      HB_TAG('M','F','E',' ')},       /* Morisyen */
-  {"mfe",      HB_TAG('C','P','P',' ')},       /* Morisyen -> Creoles */
-  {"mfp",      HB_TAG('C','P','P',' ')},       /* Makassar Malay -> Creoles */
-  {"mg",       HB_TAG('M','L','G',' ')},       /* Malagasy [macrolanguage] */
-  {"mh",       HB_TAG('M','A','H',' ')},       /* Marshallese */
-  {"mhc",      HB_TAG('M','Y','N',' ')},       /* Mocho -> Mayan */
-  {"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 */
-  {"min",      HB_TAG('M','L','Y',' ')},       /* Minangkabau -> Malay */
-  {"miz",      HB_TAG_NONE            },       /* Coatzospan Mixtec != Mizo */
-  {"mk",       HB_TAG('M','K','D',' ')},       /* Macedonian */
-  {"mkn",      HB_TAG('C','P','P',' ')},       /* Kupang Malay -> Creoles */
-  {"mkr",      HB_TAG_NONE            },       /* Malas != Makasar */
-  {"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 */
-  {"ml",       HB_TAG('M','L','R',' ')},       /* Malayalam -> Malayalam Reformed */
-  {"mle",      HB_TAG_NONE            },       /* Manambu != Male */
-  {"mln",      HB_TAG_NONE            },       /* Malango != Malinke */
-  {"mlq",      HB_TAG('M','L','N',' ')},       /* Western Maninkakan -> Malinke */
-  {"mlq",      HB_TAG('M','N','K',' ')},       /* Western Maninkakan -> Maninka */
-  {"mlr",      HB_TAG_NONE            },       /* Vame != Malayalam Reformed */
-  {"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 */
-  {"mnd",      HB_TAG_NONE            },       /* Mondé != Mandinka */
-  {"mng",      HB_TAG_NONE            },       /* Eastern Mnong != Mongolian */
-  {"mnh",      HB_TAG('B','A','D','0')},       /* Mono (Democratic Republic of Congo) -> Banda */
-/*{"mni",      HB_TAG('M','N','I',' ')},*/     /* Manipuri */
-  {"mnk",      HB_TAG('M','N','D',' ')},       /* Mandinka */
-  {"mnk",      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 */
-  {"mnw",      HB_TAG('M','O','N','T')},       /* Mon -> Thailand Mon */
-  {"mnx",      HB_TAG_NONE            },       /* Manikion != Manx */
-  {"mo",       HB_TAG('M','O','L',' ')},       /* Moldavian (retired code) */
-  {"mo",       HB_TAG('R','O','M',' ')},       /* Moldavian (retired code) -> Romanian */
-  {"mod",      HB_TAG('C','P','P',' ')},       /* Mobilian -> Creoles */
-/*{"moh",      HB_TAG('M','O','H',' ')},*/     /* Mohawk */
-  {"mok",      HB_TAG_NONE            },       /* Morori != Moksha */
-  {"mop",      HB_TAG('M','Y','N',' ')},       /* Mopán Maya -> Mayan */
-  {"mor",      HB_TAG_NONE            },       /* Moro != Moroccan */
-/*{"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 */
-  {"msi",      HB_TAG('C','P','P',' ')},       /* Sabah Malay -> Creoles */
-  {"mt",       HB_TAG('M','T','S',' ')},       /* Maltese */
-  {"mth",      HB_TAG_NONE            },       /* Munggui != Maithili */
-  {"mtr",      HB_TAG('M','A','W',' ')},       /* Mewari -> Marwari */
-  {"mts",      HB_TAG_NONE            },       /* Yora != Maltese */
-  {"mud",      HB_TAG('C','P','P',' ')},       /* Mednyj Aleut -> Creoles */
-  {"mui",      HB_TAG('M','L','Y',' ')},       /* Musi -> Malay */
-  {"mun",      HB_TAG_NONE            },       /* Munda [collection] != Mundari */
-  {"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 */
-  {"mwq",      HB_TAG('Q','I','N',' ')},       /* Mün Chin -> Chin */
-  {"mwr",      HB_TAG('M','A','W',' ')},       /* Marwari [macrolanguage] */
-  {"mww",      HB_TAG('M','W','W',' ')},       /* Hmong Daw */
-  {"mww",      HB_TAG('H','M','N',' ')},       /* Hmong Daw -> Hmong */
-  {"my",       HB_TAG('B','R','M',' ')},       /* Burmese */
-  {"mym",      HB_TAG('M','E','N',' ')},       /* Me’en */
-/*{"myn",      HB_TAG('M','Y','N',' ')},*/     /* Mayan [collection] */
-  {"myq",      HB_TAG('M','N','K',' ')},       /* Forest Maninka (retired code) -> Maninka */
-  {"myv",      HB_TAG('E','R','Z',' ')},       /* Erzya */
-  {"mzb",      HB_TAG('B','B','R',' ')},       /* Tumzabt -> Berber */
-/*{"mzn",      HB_TAG('M','Z','N',' ')},*/     /* Mazanderani */
-  {"mzs",      HB_TAG('C','P','P',' ')},       /* Macanese -> Creoles */
-  {"na",       HB_TAG('N','A','U',' ')},       /* Nauru -> Nauruan */
-  {"nag",      HB_TAG('N','A','G',' ')},       /* Naga Pidgin -> Naga-Assamese */
-  {"nag",      HB_TAG('C','P','P',' ')},       /* Naga Pidgin -> Creoles */
-/*{"nah",      HB_TAG('N','A','H',' ')},*/     /* Nahuatl [collection] */
-  {"nan",      HB_TAG('Z','H','S',' ')},       /* Min Nan Chinese -> Chinese, Simplified */
-/*{"nap",      HB_TAG('N','A','P',' ')},*/     /* Neapolitan */
-  {"nas",      HB_TAG_NONE            },       /* Naasioi != Naskapi */
-  {"naz",      HB_TAG('N','A','H',' ')},       /* Coatepec Nahuatl -> Nahuatl */
-  {"nb",       HB_TAG('N','O','R',' ')},       /* Norwegian Bokmål -> Norwegian */
-  {"nch",      HB_TAG('N','A','H',' ')},       /* Central Huasteca Nahuatl -> Nahuatl */
-  {"nci",      HB_TAG('N','A','H',' ')},       /* Classical Nahuatl -> Nahuatl */
-  {"ncj",      HB_TAG('N','A','H',' ')},       /* Northern Puebla Nahuatl -> Nahuatl */
-  {"ncl",      HB_TAG('N','A','H',' ')},       /* Michoacán Nahuatl -> Nahuatl */
-  {"ncr",      HB_TAG_NONE            },       /* Ncane != N-Cree */
-  {"ncx",      HB_TAG('N','A','H',' ')},       /* Central Puebla Nahuatl -> Nahuatl */
-  {"nd",       HB_TAG('N','D','B',' ')},       /* North Ndebele -> Ndebele */
-  {"ndb",      HB_TAG_NONE            },       /* Kenswei Nsei != Ndebele */
-/*{"ndc",      HB_TAG('N','D','C',' ')},*/     /* Ndau */
-  {"ndg",      HB_TAG_NONE            },       /* Ndengereko != Ndonga */
-/*{"nds",      HB_TAG('N','D','S',' ')},*/     /* Low Saxon */
-  {"ne",       HB_TAG('N','E','P',' ')},       /* Nepali [macrolanguage] */
-  {"nef",      HB_TAG('C','P','P',' ')},       /* Nefamese -> Creoles */
-/*{"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 */
-  {"ngm",      HB_TAG('C','P','P',' ')},       /* Ngatik Men's Creole -> Creoles */
-  {"ngo",      HB_TAG('S','X','T',' ')},       /* Ngoni (retired code) -> Sutu */
-  {"ngr",      HB_TAG_NONE            },       /* Engdewu != Nagari */
-  {"ngu",      HB_TAG('N','A','H',' ')},       /* Guerrero Nahuatl -> Nahuatl */
-  {"nhc",      HB_TAG('N','A','H',' ')},       /* Tabasco Nahuatl -> Nahuatl */
-  {"nhd",      HB_TAG('G','U','A',' ')},       /* Chiripá -> Guarani */
-  {"nhe",      HB_TAG('N','A','H',' ')},       /* Eastern Huasteca Nahuatl -> Nahuatl */
-  {"nhg",      HB_TAG('N','A','H',' ')},       /* Tetelcingo Nahuatl -> Nahuatl */
-  {"nhi",      HB_TAG('N','A','H',' ')},       /* Zacatlán-Ahuacatlán-Tepetzintla Nahuatl -> Nahuatl */
-  {"nhk",      HB_TAG('N','A','H',' ')},       /* Isthmus-Cosoleacaque Nahuatl -> Nahuatl */
-  {"nhm",      HB_TAG('N','A','H',' ')},       /* Morelos Nahuatl -> Nahuatl */
-  {"nhn",      HB_TAG('N','A','H',' ')},       /* Central Nahuatl -> Nahuatl */
-  {"nhp",      HB_TAG('N','A','H',' ')},       /* Isthmus-Pajapan Nahuatl -> Nahuatl */
-  {"nhq",      HB_TAG('N','A','H',' ')},       /* Huaxcaleca Nahuatl -> Nahuatl */
-  {"nht",      HB_TAG('N','A','H',' ')},       /* Ometepec Nahuatl -> Nahuatl */
-  {"nhv",      HB_TAG('N','A','H',' ')},       /* Temascaltepec Nahuatl -> Nahuatl */
-  {"nhw",      HB_TAG('N','A','H',' ')},       /* Western Huasteca Nahuatl -> Nahuatl */
-  {"nhx",      HB_TAG('N','A','H',' ')},       /* Isthmus-Mecayapan Nahuatl -> Nahuatl */
-  {"nhy",      HB_TAG('N','A','H',' ')},       /* Northern Oaxaca Nahuatl -> Nahuatl */
-  {"nhz",      HB_TAG('N','A','H',' ')},       /* Santa María La Alta Nahuatl -> Nahuatl */
-  {"niq",      HB_TAG('K','A','L',' ')},       /* Nandi -> Kalenjin */
-  {"nis",      HB_TAG_NONE            },       /* Nimi != Nisi */
-/*{"niu",      HB_TAG('N','I','U',' ')},*/     /* Niuean */
-  {"niv",      HB_TAG('G','I','L',' ')},       /* Gilyak */
-  {"njt",      HB_TAG('C','P','P',' ')},       /* Ndyuka-Trio Pidgin -> Creoles */
-  {"njz",      HB_TAG('N','I','S',' ')},       /* Nyishi -> Nisi */
-  {"nko",      HB_TAG_NONE            },       /* Nkonya != N’Ko */
-  {"nkx",      HB_TAG('I','J','O',' ')},       /* Nkoroo -> Ijo */
-  {"nl",       HB_TAG('N','L','D',' ')},       /* Dutch */
-  {"nla",      HB_TAG('B','M','L',' ')},       /* Ngombale -> Bamileke */
-  {"nle",      HB_TAG('L','U','H',' ')},       /* East Nyala -> Luyia */
-  {"nln",      HB_TAG('N','A','H',' ')},       /* Durango Nahuatl (retired code) -> Nahuatl */
-  {"nlv",      HB_TAG('N','A','H',' ')},       /* Orizaba Nahuatl -> Nahuatl */
-  {"nn",       HB_TAG('N','Y','N',' ')},       /* Norwegian Nynorsk (Nynorsk, Norwegian) */
-  {"nnh",      HB_TAG('B','M','L',' ')},       /* Ngiemboon -> Bamileke */
-  {"nnz",      HB_TAG('B','M','L',' ')},       /* Nda'nda' -> Bamileke */
-  {"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 */
-  {"npl",      HB_TAG('N','A','H',' ')},       /* Southeastern Puebla Nahuatl -> Nahuatl */
-  {"nqo",      HB_TAG('N','K','O',' ')},       /* N’Ko */
-  {"nr",       HB_TAG('N','D','B',' ')},       /* South Ndebele -> Ndebele */
-  {"nsk",      HB_TAG('N','A','S',' ')},       /* Naskapi */
-  {"nsm",      HB_TAG_NONE            },       /* Sumi Naga != Northern Sami */
-/*{"nso",      HB_TAG('N','S','O',' ')},*/     /* Northern Sotho */
-  {"nsu",      HB_TAG('N','A','H',' ')},       /* Sierra Negra Nahuatl -> Nahuatl */
-  {"nto",      HB_TAG_NONE            },       /* Ntomba != Esperanto */
-  {"nue",      HB_TAG('B','A','D','0')},       /* Ngundu -> Banda */
-  {"nuu",      HB_TAG('B','A','D','0')},       /* Ngbundu -> Banda */
-  {"nuz",      HB_TAG('N','A','H',' ')},       /* Tlamacazapa Nahuatl -> Nahuatl */
-  {"nv",       HB_TAG('N','A','V',' ')},       /* Navajo */
-  {"nv",       HB_TAG('A','T','H',' ')},       /* Navajo -> Athapaskan */
-  {"nwe",      HB_TAG('B','M','L',' ')},       /* Ngwe -> Bamileke */
-  {"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 */
-  {"ojs",      HB_TAG('O','J','B',' ')},       /* Severn Ojibwa -> Ojibway */
-  {"ojw",      HB_TAG('O','J','B',' ')},       /* Western Ojibwa -> Ojibway */
-  {"okd",      HB_TAG('I','J','O',' ')},       /* Okodia -> Ijo */
-  {"oki",      HB_TAG('K','A','L',' ')},       /* Okiek -> Kalenjin */
-  {"okm",      HB_TAG('K','O','H',' ')},       /* Middle Korean (10th-16th cent.) -> Korean Old Hangul */
-  {"okr",      HB_TAG('I','J','O',' ')},       /* Kirike -> Ijo */
-  {"om",       HB_TAG('O','R','O',' ')},       /* Oromo [macrolanguage] */
-  {"onx",      HB_TAG('C','P','P',' ')},       /* Onin Based Pidgin -> Creoles */
-  {"oor",      HB_TAG('C','P','P',' ')},       /* Oorlams -> Creoles */
-  {"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 */
-  {"oro",      HB_TAG_NONE            },       /* Orokolo != Oromo */
-  {"orr",      HB_TAG('I','J','O',' ')},       /* Oruma -> Ijo */
-  {"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 */
-  {"oua",      HB_TAG('B','B','R',' ')},       /* Tagargrent -> Berber */
-  {"pa",       HB_TAG('P','A','N',' ')},       /* Punjabi */
-  {"paa",      HB_TAG_NONE            },       /* Papuan [collection] != Palestinian Aramaic */
-/*{"pag",      HB_TAG('P','A','G',' ')},*/     /* Pangasinan */
-  {"pal",      HB_TAG_NONE            },       /* Pahlavi != Pali */
-/*{"pam",      HB_TAG('P','A','M',' ')},*/     /* Pampanga -> Pampangan */
-  {"pap",      HB_TAG('P','A','P','0')},       /* Papiamento -> Papiamentu */
-  {"pap",      HB_TAG('C','P','P',' ')},       /* Papiamento -> Creoles */
-  {"pas",      HB_TAG_NONE            },       /* Papasena != Pashto */
-/*{"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 */
-  {"pcm",      HB_TAG('C','P','P',' ')},       /* Nigerian Pidgin -> Creoles */
-/*{"pdc",      HB_TAG('P','D','C',' ')},*/     /* Pennsylvania German */
-  {"pdu",      HB_TAG('K','R','N',' ')},       /* Kayan -> Karen */
-  {"pea",      HB_TAG('C','P','P',' ')},       /* Peranakan Indonesian -> Creoles */
-  {"pel",      HB_TAG('M','L','Y',' ')},       /* Pekal -> Malay */
-  {"pes",      HB_TAG('F','A','R',' ')},       /* Iranian Persian -> Persian */
-  {"pey",      HB_TAG('C','P','P',' ')},       /* Petjo -> Creoles */
-  {"pga",      HB_TAG('A','R','A',' ')},       /* Sudanese Creole Arabic -> Arabic */
-  {"pga",      HB_TAG('C','P','P',' ')},       /* Sudanese Creole Arabic -> Creoles */
-/*{"phk",      HB_TAG('P','H','K',' ')},*/     /* Phake */
-  {"pi",       HB_TAG('P','A','L',' ')},       /* Pali */
-  {"pih",      HB_TAG('P','I','H',' ')},       /* Pitcairn-Norfolk -> Norfolk */
-  {"pih",      HB_TAG('C','P','P',' ')},       /* Pitcairn-Norfolk -> Creoles */
-  {"pil",      HB_TAG_NONE            },       /* Yom != Filipino */
-  {"pis",      HB_TAG('C','P','P',' ')},       /* Pijin -> Creoles */
-  {"pkh",      HB_TAG('Q','I','N',' ')},       /* Pankhu -> Chin */
-  {"pko",      HB_TAG('K','A','L',' ')},       /* Pökoot -> Kalenjin */
-  {"pl",       HB_TAG('P','L','K',' ')},       /* Polish */
-  {"plg",      HB_TAG_NONE            },       /* Pilagá != Palaung */
-  {"plk",      HB_TAG_NONE            },       /* Kohistani Shina != Polish */
-  {"pll",      HB_TAG('P','L','G',' ')},       /* Shwe Palaung -> Palaung */
-  {"pln",      HB_TAG('C','P','P',' ')},       /* Palenquero -> Creoles */
-  {"plp",      HB_TAG('P','A','P',' ')},       /* Palpa (retired code) */
-  {"plt",      HB_TAG('M','L','G',' ')},       /* Plateau Malagasy -> Malagasy */
-  {"pml",      HB_TAG('C','P','P',' ')},       /* Lingua Franca -> Creoles */
-/*{"pms",      HB_TAG('P','M','S',' ')},*/     /* Piemontese */
-  {"pmy",      HB_TAG('C','P','P',' ')},       /* Papuan Malay -> Creoles */
-/*{"pnb",      HB_TAG('P','N','B',' ')},*/     /* Western Panjabi */
-  {"poc",      HB_TAG('M','Y','N',' ')},       /* Poqomam -> Mayan */
-  {"poh",      HB_TAG('P','O','H',' ')},       /* Poqomchi' -> Pocomchi */
-  {"poh",      HB_TAG('M','Y','N',' ')},       /* Poqomchi' -> Mayan */
-/*{"pon",      HB_TAG('P','O','N',' ')},*/     /* Pohnpeian */
-  {"pov",      HB_TAG('C','P','P',' ')},       /* Upper Guinea Crioulo -> Creoles */
-  {"ppa",      HB_TAG('B','A','G',' ')},       /* Pao (retired code) -> Baghelkhandi */
-  {"pre",      HB_TAG('C','P','P',' ')},       /* Principense -> Creoles */
-/*{"pro",      HB_TAG('P','R','O',' ')},*/     /* Old Provençal (to 1500) -> Provençal / Old Provençal */
-  {"prs",      HB_TAG('D','R','I',' ')},       /* Dari */
-  {"prs",      HB_TAG('F','A','R',' ')},       /* Dari -> Persian */
-  {"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 */
-  {"pub",      HB_TAG('Q','I','N',' ')},       /* Purum -> Chin */
-  {"puz",      HB_TAG('Q','I','N',' ')},       /* Purum Naga (retired code) -> Chin */
-  {"pwo",      HB_TAG('P','W','O',' ')},       /* Pwo Western Karen -> Western Pwo Karen */
-  {"pwo",      HB_TAG('K','R','N',' ')},       /* Pwo Western Karen -> Karen */
-  {"pww",      HB_TAG('K','R','N',' ')},       /* Pwo Northern Karen -> Karen */
-  {"qu",       HB_TAG('Q','U','Z',' ')},       /* Quechua [macrolanguage] */
-  {"qub",      HB_TAG('Q','W','H',' ')},       /* Huallaga Huánuco Quechua -> Quechua (Peru) */
-  {"qub",      HB_TAG('Q','U','Z',' ')},       /* Huallaga Huánuco Quechua -> Quechua */
-  {"quc",      HB_TAG('Q','U','C',' ')},       /* K’iche’ */
-  {"quc",      HB_TAG('M','Y','N',' ')},       /* K'iche' -> Mayan */
-  {"qud",      HB_TAG('Q','V','I',' ')},       /* Calderón Highland Quichua -> Quechua (Ecuador) */
-  {"qud",      HB_TAG('Q','U','Z',' ')},       /* Calderón Highland Quichua -> Quechua */
-  {"quf",      HB_TAG('Q','U','Z',' ')},       /* Lambayeque Quechua -> Quechua */
-  {"qug",      HB_TAG('Q','V','I',' ')},       /* Chimborazo Highland Quichua -> Quechua (Ecuador) */
-  {"qug",      HB_TAG('Q','U','Z',' ')},       /* Chimborazo Highland Quichua -> Quechua */
-  {"quh",      HB_TAG('Q','U','H',' ')},       /* South Bolivian Quechua -> Quechua (Bolivia) */
-  {"quh",      HB_TAG('Q','U','Z',' ')},       /* South Bolivian Quechua -> Quechua */
-  {"quk",      HB_TAG('Q','U','Z',' ')},       /* Chachapoyas Quechua -> Quechua */
-  {"qul",      HB_TAG('Q','U','H',' ')},       /* North Bolivian Quechua -> Quechua (Bolivia) */
-  {"qul",      HB_TAG('Q','U','Z',' ')},       /* North Bolivian Quechua -> Quechua */
-  {"qum",      HB_TAG('M','Y','N',' ')},       /* Sipacapense -> Mayan */
-  {"qup",      HB_TAG('Q','V','I',' ')},       /* Southern Pastaza Quechua -> Quechua (Ecuador) */
-  {"qup",      HB_TAG('Q','U','Z',' ')},       /* Southern Pastaza Quechua -> Quechua */
-  {"qur",      HB_TAG('Q','W','H',' ')},       /* Yanahuanca Pasco Quechua -> Quechua (Peru) */
-  {"qur",      HB_TAG('Q','U','Z',' ')},       /* Yanahuanca Pasco Quechua -> Quechua */
-  {"qus",      HB_TAG('Q','U','H',' ')},       /* Santiago del Estero Quichua -> Quechua (Bolivia) */
-  {"qus",      HB_TAG('Q','U','Z',' ')},       /* Santiago del Estero Quichua -> Quechua */
-  {"quv",      HB_TAG('M','Y','N',' ')},       /* Sacapulteco -> Mayan */
-  {"quw",      HB_TAG('Q','V','I',' ')},       /* Tena Lowland Quichua -> Quechua (Ecuador) */
-  {"quw",      HB_TAG('Q','U','Z',' ')},       /* Tena Lowland Quichua -> Quechua */
-  {"qux",      HB_TAG('Q','W','H',' ')},       /* Yauyos Quechua -> Quechua (Peru) */
-  {"qux",      HB_TAG('Q','U','Z',' ')},       /* Yauyos Quechua -> Quechua */
-  {"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) */
-  {"qva",      HB_TAG('Q','U','Z',' ')},       /* Ambo-Pasco Quechua -> Quechua */
-  {"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) */
-  {"qvh",      HB_TAG('Q','U','Z',' ')},       /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua */
-  {"qvi",      HB_TAG('Q','V','I',' ')},       /* Imbabura Highland Quichua -> Quechua (Ecuador) */
-  {"qvi",      HB_TAG('Q','U','Z',' ')},       /* Imbabura Highland Quichua -> Quechua */
-  {"qvj",      HB_TAG('Q','V','I',' ')},       /* Loja Highland Quichua -> Quechua (Ecuador) */
-  {"qvj",      HB_TAG('Q','U','Z',' ')},       /* Loja Highland Quichua -> Quechua */
-  {"qvl",      HB_TAG('Q','W','H',' ')},       /* Cajatambo North Lima Quechua -> Quechua (Peru) */
-  {"qvl",      HB_TAG('Q','U','Z',' ')},       /* Cajatambo North Lima Quechua -> Quechua */
-  {"qvm",      HB_TAG('Q','W','H',' ')},       /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */
-  {"qvm",      HB_TAG('Q','U','Z',' ')},       /* Margos-Yarowilca-Lauricocha Quechua -> Quechua */
-  {"qvn",      HB_TAG('Q','W','H',' ')},       /* North Junín Quechua -> Quechua (Peru) */
-  {"qvn",      HB_TAG('Q','U','Z',' ')},       /* North Junín Quechua -> Quechua */
-  {"qvo",      HB_TAG('Q','V','I',' ')},       /* Napo Lowland Quechua -> Quechua (Ecuador) */
-  {"qvo",      HB_TAG('Q','U','Z',' ')},       /* Napo Lowland Quechua -> Quechua */
-  {"qvp",      HB_TAG('Q','W','H',' ')},       /* Pacaraos Quechua -> Quechua (Peru) */
-  {"qvp",      HB_TAG('Q','U','Z',' ')},       /* Pacaraos Quechua -> Quechua */
-  {"qvs",      HB_TAG('Q','U','Z',' ')},       /* San Martín Quechua -> Quechua */
-  {"qvw",      HB_TAG('Q','W','H',' ')},       /* Huaylla Wanca Quechua -> Quechua (Peru) */
-  {"qvw",      HB_TAG('Q','U','Z',' ')},       /* Huaylla Wanca Quechua -> Quechua */
-  {"qvz",      HB_TAG('Q','V','I',' ')},       /* Northern Pastaza Quichua -> Quechua (Ecuador) */
-  {"qvz",      HB_TAG('Q','U','Z',' ')},       /* Northern Pastaza Quichua -> Quechua */
-  {"qwa",      HB_TAG('Q','W','H',' ')},       /* Corongo Ancash Quechua -> Quechua (Peru) */
-  {"qwa",      HB_TAG('Q','U','Z',' ')},       /* Corongo Ancash Quechua -> Quechua */
-  {"qwc",      HB_TAG('Q','U','Z',' ')},       /* Classical Quechua -> Quechua */
-  {"qwh",      HB_TAG('Q','W','H',' ')},       /* Huaylas Ancash Quechua -> Quechua (Peru) */
-  {"qwh",      HB_TAG('Q','U','Z',' ')},       /* Huaylas Ancash Quechua -> Quechua */
-  {"qws",      HB_TAG('Q','W','H',' ')},       /* Sihuas Ancash Quechua -> Quechua (Peru) */
-  {"qws",      HB_TAG('Q','U','Z',' ')},       /* Sihuas Ancash Quechua -> Quechua */
-  {"qwt",      HB_TAG('A','T','H',' ')},       /* Kwalhioqua-Tlatskanai -> Athapaskan */
-  {"qxa",      HB_TAG('Q','W','H',' ')},       /* Chiquián Ancash Quechua -> Quechua (Peru) */
-  {"qxa",      HB_TAG('Q','U','Z',' ')},       /* Chiquián Ancash Quechua -> Quechua */
-  {"qxc",      HB_TAG('Q','W','H',' ')},       /* Chincha Quechua -> Quechua (Peru) */
-  {"qxc",      HB_TAG('Q','U','Z',' ')},       /* Chincha Quechua -> Quechua */
-  {"qxh",      HB_TAG('Q','W','H',' ')},       /* Panao Huánuco Quechua -> Quechua (Peru) */
-  {"qxh",      HB_TAG('Q','U','Z',' ')},       /* Panao Huánuco Quechua -> Quechua */
-  {"qxl",      HB_TAG('Q','V','I',' ')},       /* Salasaca Highland Quichua -> Quechua (Ecuador) */
-  {"qxl",      HB_TAG('Q','U','Z',' ')},       /* Salasaca Highland Quichua -> Quechua */
-  {"qxn",      HB_TAG('Q','W','H',' ')},       /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */
-  {"qxn",      HB_TAG('Q','U','Z',' ')},       /* Northern Conchucos Ancash Quechua -> Quechua */
-  {"qxo",      HB_TAG('Q','W','H',' ')},       /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */
-  {"qxo",      HB_TAG('Q','U','Z',' ')},       /* Southern Conchucos Ancash Quechua -> Quechua */
-  {"qxp",      HB_TAG('Q','U','Z',' ')},       /* Puno Quechua -> Quechua */
-  {"qxr",      HB_TAG('Q','V','I',' ')},       /* Cañar Highland Quichua -> Quechua (Ecuador) */
-  {"qxr",      HB_TAG('Q','U','Z',' ')},       /* Cañar Highland Quichua -> Quechua */
-  {"qxt",      HB_TAG('Q','W','H',' ')},       /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */
-  {"qxt",      HB_TAG('Q','U','Z',' ')},       /* Santa Ana de Tusi Pasco Quechua -> Quechua */
-  {"qxu",      HB_TAG('Q','U','Z',' ')},       /* Arequipa-La Unión Quechua -> Quechua */
-  {"qxw",      HB_TAG('Q','W','H',' ')},       /* Jauja Wanca Quechua -> Quechua (Peru) */
-  {"qxw",      HB_TAG('Q','U','Z',' ')},       /* Jauja Wanca Quechua -> Quechua */
-  {"rag",      HB_TAG('L','U','H',' ')},       /* Logooli -> Luyia */
-/*{"raj",      HB_TAG('R','A','J',' ')},*/     /* Rajasthani [macrolanguage] */
-  {"ral",      HB_TAG('Q','I','N',' ')},       /* Ralte -> Chin */
-/*{"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 */
-  {"rcf",      HB_TAG('C','P','P',' ')},       /* Réunion Creole French -> Creoles */
-/*{"rej",      HB_TAG('R','E','J',' ')},*/     /* Rejang */
-/*{"rhg",      HB_TAG('R','H','G',' ')},*/     /* Rohingya */
-/*{"ria",      HB_TAG('R','I','A',' ')},*/     /* Riang (India) */
-  {"rif",      HB_TAG('R','I','F',' ')},       /* Tarifit */
-  {"rif",      HB_TAG('B','B','R',' ')},       /* Tarifit -> Berber */
-/*{"rit",      HB_TAG('R','I','T',' ')},*/     /* Ritharrngu -> 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 */
-  {"rms",      HB_TAG_NONE            },       /* Romanian Sign Language != Romansh */
-  {"rmw",      HB_TAG('R','O','Y',' ')},       /* Welsh Romani -> Romany */
-  {"rmy",      HB_TAG('R','M','Y',' ')},       /* Vlax Romani */
-  {"rmy",      HB_TAG('R','O','Y',' ')},       /* Vlax Romani -> Romany */
-  {"rmz",      HB_TAG('A','R','K',' ')},       /* Marma -> Rakhine */
-  {"rn",       HB_TAG('R','U','N',' ')},       /* Rundi */
-  {"ro",       HB_TAG('R','O','M',' ')},       /* Romanian */
-  {"rom",      HB_TAG('R','O','Y',' ')},       /* Romany [macrolanguage] */
-  {"rop",      HB_TAG('C','P','P',' ')},       /* Kriol -> Creoles */
-  {"rtc",      HB_TAG('Q','I','N',' ')},       /* Rungtu Chin -> Chin */
-/*{"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 */
-  {"sad",      HB_TAG_NONE            },       /* Sandawe != Sadri */
-  {"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 */
-  {"say",      HB_TAG_NONE            },       /* Saya != Sayisi */
-  {"sc",       HB_TAG('S','R','D',' ')},       /* Sardinian [macrolanguage] */
-  {"scf",      HB_TAG('C','P','P',' ')},       /* San Miguel Creole French -> Creoles */
-  {"sch",      HB_TAG('Q','I','N',' ')},       /* Sakachep -> Chin */
-  {"sci",      HB_TAG('C','P','P',' ')},       /* Sri Lankan Creole Malay -> Creoles */
-  {"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 */
-  {"scs",      HB_TAG('S','L','A',' ')},       /* North Slavey -> Slavey */
-  {"scs",      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 */
-  {"sds",      HB_TAG('B','B','R',' ')},       /* Sened -> Berber */
-  {"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('S','F','M',' ')},       /* Small Flowery Miao */
-  {"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 */
-  {"sgo",      HB_TAG_NONE            },       /* Songa (retired code) != Sango */
-/*{"sgs",      HB_TAG('S','G','S',' ')},*/     /* Samogitian */
-  {"sgw",      HB_TAG('C','H','G',' ')},       /* Sebat Bet Gurage -> Chaha Gurage */
-  {"sh",       HB_TAG('B','O','S',' ')},       /* Serbo-Croatian [macrolanguage] -> Bosnian */
-  {"sh",       HB_TAG('H','R','V',' ')},       /* Serbo-Croatian [macrolanguage] -> Croatian */
-  {"sh",       HB_TAG('S','R','B',' ')},       /* Serbo-Croatian [macrolanguage] -> Serbian */
-  {"shi",      HB_TAG('S','H','I',' ')},       /* Tachelhit */
-  {"shi",      HB_TAG('B','B','R',' ')},       /* Tachelhit -> Berber */
-  {"shl",      HB_TAG('Q','I','N',' ')},       /* Shendu -> Chin */
-/*{"shn",      HB_TAG('S','H','N',' ')},*/     /* Shan */
-  {"shu",      HB_TAG('A','R','A',' ')},       /* Chadian Arabic -> Arabic */
-  {"shy",      HB_TAG('B','B','R',' ')},       /* Tachawit -> Berber */
-  {"si",       HB_TAG('S','N','H',' ')},       /* Sinhala (Sinhalese) */
-  {"sib",      HB_TAG_NONE            },       /* Sebop != Sibe */
-/*{"sid",      HB_TAG('S','I','D',' ')},*/     /* Sidamo */
-  {"sig",      HB_TAG_NONE            },       /* Paasaal != Silte Gurage */
-  {"siz",      HB_TAG('B','B','R',' ')},       /* Siwi -> Berber */
-  {"sjd",      HB_TAG('K','S','M',' ')},       /* Kildin Sami */
-  {"sjo",      HB_TAG('S','I','B',' ')},       /* Xibe -> Sibe */
-  {"sjs",      HB_TAG('B','B','R',' ')},       /* Senhaja De Srair -> Berber */
-  {"sk",       HB_TAG('S','K','Y',' ')},       /* Slovak */
-  {"skg",      HB_TAG('M','L','G',' ')},       /* Sakalava Malagasy -> Malagasy */
-  {"skr",      HB_TAG('S','R','K',' ')},       /* Saraiki */
-  {"sks",      HB_TAG_NONE            },       /* Maia != Skolt Sami */
-  {"skw",      HB_TAG('C','P','P',' ')},       /* Skepi Creole Dutch -> Creoles */
-  {"sky",      HB_TAG_NONE            },       /* Sikaiana != Slovak */
-  {"sl",       HB_TAG('S','L','V',' ')},       /* Slovenian */
-  {"sla",      HB_TAG_NONE            },       /* Slavic [collection] != Slavey */
-  {"sm",       HB_TAG('S','M','O',' ')},       /* Samoan */
-  {"sma",      HB_TAG('S','S','M',' ')},       /* Southern Sami */
-  {"smj",      HB_TAG('L','S','M',' ')},       /* Lule Sami */
-  {"sml",      HB_TAG_NONE            },       /* Central Sama != Somali */
-  {"smn",      HB_TAG('I','S','M',' ')},       /* Inari Sami */
-  {"sms",      HB_TAG('S','K','S',' ')},       /* Skolt Sami */
-  {"smt",      HB_TAG('Q','I','N',' ')},       /* Simte -> Chin */
-  {"sn",       HB_TAG('S','N','A','0')},       /* Shona */
-  {"snh",      HB_TAG_NONE            },       /* Shinabo (retired code) != Sinhala (Sinhalese) */
-/*{"snk",      HB_TAG('S','N','K',' ')},*/     /* Soninke */
-  {"so",       HB_TAG('S','M','L',' ')},       /* Somali */
-  {"sog",      HB_TAG_NONE            },       /* Sogdian != Sodo Gurage */
-/*{"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 */
-  {"srb",      HB_TAG_NONE            },       /* Sora != Serbian */
-  {"src",      HB_TAG('S','R','D',' ')},       /* Logudorese Sardinian -> Sardinian */
-  {"srk",      HB_TAG_NONE            },       /* Serudung Murut != Saraiki */
-  {"srm",      HB_TAG('C','P','P',' ')},       /* Saramaccan -> Creoles */
-  {"srn",      HB_TAG('C','P','P',' ')},       /* Sranan Tongo -> Creoles */
-  {"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 */
-  {"ssl",      HB_TAG_NONE            },       /* Western Sisaala != South Slavey */
-  {"ssm",      HB_TAG_NONE            },       /* Semnam != Southern Sami */
-  {"st",       HB_TAG('S','O','T',' ')},       /* Southern Sotho */
-  {"sta",      HB_TAG('C','P','P',' ')},       /* Settla -> Creoles */
-/*{"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 */
-  {"sur",      HB_TAG_NONE            },       /* Mwaghavul != Suri */
-  {"sv",       HB_TAG('S','V','E',' ')},       /* Swedish */
-/*{"sva",      HB_TAG('S','V','A',' ')},*/     /* Svan */
-  {"svc",      HB_TAG('C','P','P',' ')},       /* Vincentian Creole English -> Creoles */
-  {"sve",      HB_TAG_NONE            },       /* Serili != Swedish */
-  {"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 */
-  {"swk",      HB_TAG_NONE            },       /* Malawi Sena != Swahili */
-  {"swn",      HB_TAG('B','B','R',' ')},       /* Sawknah -> Berber */
-  {"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 */
-  {"taj",      HB_TAG_NONE            },       /* Eastern Tamang != Tajiki */
-  {"taq",      HB_TAG('T','M','H',' ')},       /* Tamasheq -> Tamashek */
-  {"taq",      HB_TAG('B','B','R',' ')},       /* Tamasheq -> Berber */
-  {"tas",      HB_TAG('C','P','P',' ')},       /* Tay Boi -> Creoles */
-  {"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 */
-  {"tch",      HB_TAG('C','P','P',' ')},       /* Turks And Caicos Creole English -> Creoles */
-  {"tcp",      HB_TAG('Q','I','N',' ')},       /* Tawr Chin -> Chin */
-  {"tcs",      HB_TAG('C','P','P',' ')},       /* Torres Strait Creole -> Creoles */
-  {"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 */
-  {"tez",      HB_TAG('B','B','R',' ')},       /* Tetserret -> Berber */
-  {"tfn",      HB_TAG('A','T','H',' ')},       /* Tanaina -> Athapaskan */
-  {"tg",       HB_TAG('T','A','J',' ')},       /* Tajik -> Tajiki */
-  {"tgh",      HB_TAG('C','P','P',' ')},       /* Tobagonian Creole English -> Creoles */
-  {"tgj",      HB_TAG('N','I','S',' ')},       /* Tagin -> Nisi */
-  {"tgn",      HB_TAG_NONE            },       /* Tandaganon != Tongan */
-  {"tgr",      HB_TAG_NONE            },       /* Tareng != Tigre */
-  {"tgx",      HB_TAG('A','T','H',' ')},       /* Tagish -> Athapaskan */
-  {"tgy",      HB_TAG_NONE            },       /* Togoyo != Tigrinya */
-  {"th",       HB_TAG('T','H','A',' ')},       /* Thai */
-  {"tht",      HB_TAG('A','T','H',' ')},       /* Tahltan -> Athapaskan */
-  {"thv",      HB_TAG('T','M','H',' ')},       /* Tahaggart Tamahaq -> Tamashek */
-  {"thv",      HB_TAG('B','B','R',' ')},       /* Tahaggart Tamahaq -> Berber */
-  {"thz",      HB_TAG('T','M','H',' ')},       /* Tayart Tamajeq -> Tamashek */
-  {"thz",      HB_TAG('B','B','R',' ')},       /* Tayart Tamajeq -> Berber */
-  {"ti",       HB_TAG('T','G','Y',' ')},       /* Tigrinya */
-  {"tia",      HB_TAG('B','B','R',' ')},       /* Tidikelt Tamazight -> Berber */
-  {"tig",      HB_TAG('T','G','R',' ')},       /* Tigre */
-/*{"tiv",      HB_TAG('T','I','V',' ')},*/     /* Tiv */
-/*{"tjl",      HB_TAG('T','J','L',' ')},*/     /* Tai Laing */
-  {"tjo",      HB_TAG('B','B','R',' ')},       /* Temacine Tamazight -> Berber */
-  {"tk",       HB_TAG('T','K','M',' ')},       /* Turkmen */
-  {"tkg",      HB_TAG('M','L','G',' ')},       /* Tesaka Malagasy -> Malagasy */
-  {"tkm",      HB_TAG_NONE            },       /* Takelma != Turkmen */
-  {"tl",       HB_TAG('T','G','L',' ')},       /* Tagalog */
-/*{"tli",      HB_TAG('T','L','I',' ')},*/     /* Tlingit */
-  {"tmg",      HB_TAG('C','P','P',' ')},       /* Ternateño -> Creoles */
-  {"tmh",      HB_TAG('T','M','H',' ')},       /* Tamashek [macrolanguage] */
-  {"tmh",      HB_TAG('B','B','R',' ')},       /* Tamashek [macrolanguage] -> Berber */
-  {"tmn",      HB_TAG_NONE            },       /* Taman (Indonesia) != Temne */
-  {"tmw",      HB_TAG('M','L','Y',' ')},       /* Temuan -> Malay */
-  {"tn",       HB_TAG('T','N','A',' ')},       /* Tswana */
-  {"tna",      HB_TAG_NONE            },       /* Tacana != Tswana */
-  {"tne",      HB_TAG_NONE            },       /* Tinoc Kallahan (retired code) != Tundra Enets */
-  {"tnf",      HB_TAG('D','R','I',' ')},       /* Tangshewi (retired code) -> Dari */
-  {"tnf",      HB_TAG('F','A','R',' ')},       /* Tangshewi (retired code) -> Persian */
-  {"tng",      HB_TAG_NONE            },       /* Tobanga != Tonga */
-  {"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) */
-  {"toj",      HB_TAG('M','Y','N',' ')},       /* Tojolabal -> Mayan */
-  {"tol",      HB_TAG('A','T','H',' ')},       /* Tolowa -> Athapaskan */
-  {"tor",      HB_TAG('B','A','D','0')},       /* Togbo-Vara Banda -> Banda */
-  {"tpi",      HB_TAG('T','P','I',' ')},       /* Tok Pisin */
-  {"tpi",      HB_TAG('C','P','P',' ')},       /* Tok Pisin -> Creoles */
-  {"tr",       HB_TAG('T','R','K',' ')},       /* Turkish */
-  {"trf",      HB_TAG('C','P','P',' ')},       /* Trinidadian Creole English -> Creoles */
-  {"trk",      HB_TAG_NONE            },       /* Turkic [collection] != Turkish */
-  {"tru",      HB_TAG('T','U','A',' ')},       /* Turoyo -> Turoyo Aramaic */
-  {"tru",      HB_TAG('S','Y','R',' ')},       /* Turoyo -> Syriac */
-  {"ts",       HB_TAG('T','S','G',' ')},       /* Tsonga */
-  {"tsg",      HB_TAG_NONE            },       /* Tausug != Tsonga */
-/*{"tsj",      HB_TAG('T','S','J',' ')},*/     /* Tshangla */
-  {"tt",       HB_TAG('T','A','T',' ')},       /* Tatar */
-  {"ttc",      HB_TAG('M','Y','N',' ')},       /* Tektiteko -> Mayan */
-  {"ttm",      HB_TAG('A','T','H',' ')},       /* Northern Tutchone -> Athapaskan */
-  {"ttq",      HB_TAG('T','M','H',' ')},       /* Tawallammat Tamajaq -> Tamashek */
-  {"ttq",      HB_TAG('B','B','R',' ')},       /* Tawallammat Tamajaq -> Berber */
-  {"tua",      HB_TAG_NONE            },       /* Wiarumus != Turoyo Aramaic */
-  {"tul",      HB_TAG_NONE            },       /* Tula != Tumbuka */
-/*{"tum",      HB_TAG('T','U','M',' ')},*/     /* Tumbuka -> Tulu */
-  {"tuu",      HB_TAG('A','T','H',' ')},       /* Tututni -> Athapaskan */
-  {"tuv",      HB_TAG_NONE            },       /* Turkana != Tuvin */
-  {"tuy",      HB_TAG('K','A','L',' ')},       /* Tugen -> Kalenjin */
-/*{"tvl",      HB_TAG('T','V','L',' ')},*/     /* Tuvalu */
-  {"tvy",      HB_TAG('C','P','P',' ')},       /* Timor Pidgin -> Creoles */
-  {"tw",       HB_TAG('T','W','I',' ')},       /* Twi */
-  {"tw",       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 */
-  {"tzh",      HB_TAG('M','Y','N',' ')},       /* Tzeltal -> Mayan */
-  {"tzj",      HB_TAG('M','Y','N',' ')},       /* Tz'utujil -> Mayan */
-  {"tzm",      HB_TAG('T','Z','M',' ')},       /* Central Atlas Tamazight -> Tamazight */
-  {"tzm",      HB_TAG('B','B','R',' ')},       /* Central Atlas Tamazight -> Berber */
-  {"tzo",      HB_TAG('T','Z','O',' ')},       /* Tzotzil */
-  {"tzo",      HB_TAG('M','Y','N',' ')},       /* Tzotzil -> Mayan */
-  {"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 */
-  {"uki",      HB_TAG('K','U','I',' ')},       /* Kui (India) */
-  {"uln",      HB_TAG('C','P','P',' ')},       /* Unserdeutsch -> Creoles */
-/*{"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 */
-  {"usp",      HB_TAG('M','Y','N',' ')},       /* Uspanteco -> Mayan */
-  {"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 */
-  {"vap",      HB_TAG('Q','I','N',' ')},       /* Vaiphei -> Chin */
-  {"ve",       HB_TAG('V','E','N',' ')},       /* Venda */
-/*{"vec",      HB_TAG('V','E','C',' ')},*/     /* Venetian */
-  {"vi",       HB_TAG('V','I','T',' ')},       /* Vietnamese */
-  {"vic",      HB_TAG('C','P','P',' ')},       /* Virgin Islands Creole English -> Creoles */
-  {"vit",      HB_TAG_NONE            },       /* Viti != Vietnamese */
-  {"vkk",      HB_TAG('M','L','Y',' ')},       /* Kaur -> Malay */
-  {"vkp",      HB_TAG('C','P','P',' ')},       /* Korlai Creole Portuguese -> Creoles */
-  {"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 */
-  {"wag",      HB_TAG_NONE            },       /* Wa'ema != Wagdi */
-/*{"war",      HB_TAG('W','A','R',' ')},*/     /* Waray (Philippines) -> Waray-Waray */
-  {"wbm",      HB_TAG('W','A',' ',' ')},       /* Wa */
-  {"wbr",      HB_TAG('W','A','G',' ')},       /* Wagdi */
-  {"wbr",      HB_TAG('R','A','J',' ')},       /* Wagdi -> Rajasthani */
-/*{"wci",      HB_TAG('W','C','I',' ')},*/     /* Waci Gbe */
-  {"wea",      HB_TAG('K','R','N',' ')},       /* Wewaw -> Karen */
-  {"wes",      HB_TAG('C','P','P',' ')},       /* Cameroon Pidgin -> Creoles */
-  {"weu",      HB_TAG('Q','I','N',' ')},       /* Rawngtu Chin -> Chin */
-  {"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 */
-  {"xal",      HB_TAG('T','O','D',' ')},       /* Kalmyk -> Todo */
-  {"xan",      HB_TAG('S','E','K',' ')},       /* Xamtanga -> Sekota */
-  {"xbd",      HB_TAG_NONE            },       /* Bindal != Lü */
-  {"xh",       HB_TAG('X','H','S',' ')},       /* Xhosa */
-/*{"xjb",      HB_TAG('X','J','B',' ')},*/     /* Minjungbal -> Minjangbal */
-/*{"xkf",      HB_TAG('X','K','F',' ')},*/     /* Khengkha */
-  {"xmg",      HB_TAG('B','M','L',' ')},       /* Mengaka -> Bamileke */
-  {"xmm",      HB_TAG('M','L','Y',' ')},       /* Manado Malay -> Malay */
-  {"xmm",      HB_TAG('C','P','P',' ')},       /* Manado Malay -> Creoles */
-  {"xmv",      HB_TAG('M','L','G',' ')},       /* Antankarana Malagasy -> Malagasy */
-  {"xmw",      HB_TAG('M','L','G',' ')},       /* Tsimihety Malagasy -> Malagasy */
-  {"xnj",      HB_TAG('S','X','T',' ')},       /* Ngoni (Tanzania) -> Sutu */
-  {"xnq",      HB_TAG('S','X','T',' ')},       /* Ngoni (Mozambique) -> Sutu */
-  {"xnr",      HB_TAG('D','G','R',' ')},       /* Kangri -> Dogri (macrolanguage) */
-/*{"xog",      HB_TAG('X','O','G',' ')},*/     /* Soga */
-  {"xpe",      HB_TAG('X','P','E',' ')},       /* Liberia Kpelle -> Kpelle (Liberia) */
-  {"xpe",      HB_TAG('K','P','L',' ')},       /* Liberia Kpelle -> Kpelle */
-  {"xsl",      HB_TAG('S','S','L',' ')},       /* South Slavey */
-  {"xsl",      HB_TAG('S','L','A',' ')},       /* South Slavey -> Slavey */
-  {"xsl",      HB_TAG('A','T','H',' ')},       /* South Slavey -> Athapaskan */
-  {"xst",      HB_TAG('S','I','G',' ')},       /* Silt'e (retired code) -> Silte Gurage */
-/*{"xub",      HB_TAG('X','U','B',' ')},*/     /* Betta Kurumba -> Bette Kuruma */
-/*{"xuj",      HB_TAG('X','U','J',' ')},*/     /* Jennu Kurumba -> Jennu Kuruma */
-  {"xup",      HB_TAG('A','T','H',' ')},       /* Upper Umpqua -> Athapaskan */
-  {"xwo",      HB_TAG('T','O','D',' ')},       /* Written Oirat -> Todo */
-  {"yaj",      HB_TAG('B','A','D','0')},       /* Banda-Yangere -> Banda */
-  {"yak",      HB_TAG_NONE            },       /* Yakama != Sakha */
-/*{"yao",      HB_TAG('Y','A','O',' ')},*/     /* Yao */
-/*{"yap",      HB_TAG('Y','A','P',' ')},*/     /* Yapese */
-  {"yba",      HB_TAG_NONE            },       /* Yala != Yoruba */
-  {"ybb",      HB_TAG('B','M','L',' ')},       /* Yemba -> Bamileke */
-  {"ybd",      HB_TAG('A','R','K',' ')},       /* Yangbye (retired code) -> Rakhine */
-  {"ydd",      HB_TAG('J','I','I',' ')},       /* Eastern Yiddish -> Yiddish */
-/*{"ygp",      HB_TAG('Y','G','P',' ')},*/     /* Gepo */
-  {"yi",       HB_TAG('J','I','I',' ')},       /* Yiddish [macrolanguage] */
-  {"yih",      HB_TAG('J','I','I',' ')},       /* Western Yiddish -> Yiddish */
-  {"yim",      HB_TAG_NONE            },       /* Yimchungru Naga != Yi Modern */
-/*{"yna",      HB_TAG('Y','N','A',' ')},*/     /* Aluo */
-  {"yo",       HB_TAG('Y','B','A',' ')},       /* Yoruba */
-  {"yos",      HB_TAG('Q','I','N',' ')},       /* Yos (retired code) -> Chin */
-  {"yua",      HB_TAG('M','Y','N',' ')},       /* Yucateco -> Mayan */
-  {"yue",      HB_TAG('Z','H','H',' ')},       /* Yue Chinese -> Chinese, Traditional, Hong Kong SAR */
-/*{"ywq",      HB_TAG('Y','W','Q',' ')},*/     /* Wuding-Luquan Yi */
-  {"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 */
-  {"zen",      HB_TAG('B','B','R',' ')},       /* Zenaga -> Berber */
-  {"zgb",      HB_TAG('Z','H','A',' ')},       /* Guibei Zhuang -> Zhuang */
-  {"zgh",      HB_TAG('Z','G','H',' ')},       /* Standard Moroccan Tamazight */
-  {"zgh",      HB_TAG('B','B','R',' ')},       /* Standard Moroccan Tamazight -> Berber */
-  {"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, Simplified [macrolanguage] */
-  {"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 */
-  {"zmz",      HB_TAG('B','A','D','0')},       /* Mbandja -> Banda */
-  {"znd",      HB_TAG_NONE            },       /* Zande [collection] != Zande */
-  {"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 */
-  {"zyp",      HB_TAG('Q','I','N',' ')},       /* Zyphe Chin -> Chin */
-/*{"zza",      HB_TAG('Z','Z','A',' ')},*/     /* Zazaki [macrolanguage] */
-  {"zzj",      HB_TAG('Z','H','A',' ')},       /* Zuojiang Zhuang -> Zhuang */
+static const LangTag ot_languages2[] = {
+  {HB_TAG('a','a',' ',' '),    HB_TAG('A','F','R',' ')},       /* Afar */
+  {HB_TAG('a','b',' ',' '),    HB_TAG('A','B','K',' ')},       /* Abkhazian */
+  {HB_TAG('a','f',' ',' '),    HB_TAG('A','F','K',' ')},       /* Afrikaans */
+  {HB_TAG('a','k',' ',' '),    HB_TAG('A','K','A',' ')},       /* Akan [macrolanguage] */
+  {HB_TAG('a','m',' ',' '),    HB_TAG('A','M','H',' ')},       /* Amharic */
+  {HB_TAG('a','n',' ',' '),    HB_TAG('A','R','G',' ')},       /* Aragonese */
+  {HB_TAG('a','r',' ',' '),    HB_TAG('A','R','A',' ')},       /* Arabic [macrolanguage] */
+  {HB_TAG('a','s',' ',' '),    HB_TAG('A','S','M',' ')},       /* Assamese */
+  {HB_TAG('a','v',' ',' '),    HB_TAG('A','V','R',' ')},       /* Avaric -> Avar */
+  {HB_TAG('a','y',' ',' '),    HB_TAG('A','Y','M',' ')},       /* Aymara [macrolanguage] */
+  {HB_TAG('a','z',' ',' '),    HB_TAG('A','Z','E',' ')},       /* Azerbaijani [macrolanguage] */
+  {HB_TAG('b','a',' ',' '),    HB_TAG('B','S','H',' ')},       /* Bashkir */
+  {HB_TAG('b','e',' ',' '),    HB_TAG('B','E','L',' ')},       /* Belarusian -> Belarussian */
+  {HB_TAG('b','g',' ',' '),    HB_TAG('B','G','R',' ')},       /* Bulgarian */
+  {HB_TAG('b','i',' ',' '),    HB_TAG('B','I','S',' ')},       /* Bislama */
+  {HB_TAG('b','i',' ',' '),    HB_TAG('C','P','P',' ')},       /* Bislama -> Creoles */
+  {HB_TAG('b','m',' ',' '),    HB_TAG('B','M','B',' ')},       /* Bambara (Bamanankan) */
+  {HB_TAG('b','n',' ',' '),    HB_TAG('B','E','N',' ')},       /* Bengali */
+  {HB_TAG('b','o',' ',' '),    HB_TAG('T','I','B',' ')},       /* Tibetan */
+  {HB_TAG('b','r',' ',' '),    HB_TAG('B','R','E',' ')},       /* Breton */
+  {HB_TAG('b','s',' ',' '),    HB_TAG('B','O','S',' ')},       /* Bosnian */
+  {HB_TAG('c','a',' ',' '),    HB_TAG('C','A','T',' ')},       /* Catalan */
+  {HB_TAG('c','e',' ',' '),    HB_TAG('C','H','E',' ')},       /* Chechen */
+  {HB_TAG('c','h',' ',' '),    HB_TAG('C','H','A',' ')},       /* Chamorro */
+  {HB_TAG('c','o',' ',' '),    HB_TAG('C','O','S',' ')},       /* Corsican */
+  {HB_TAG('c','r',' ',' '),    HB_TAG('C','R','E',' ')},       /* Cree [macrolanguage] */
+  {HB_TAG('c','s',' ',' '),    HB_TAG('C','S','Y',' ')},       /* Czech */
+  {HB_TAG('c','u',' ',' '),    HB_TAG('C','S','L',' ')},       /* Church Slavonic */
+  {HB_TAG('c','v',' ',' '),    HB_TAG('C','H','U',' ')},       /* Chuvash */
+  {HB_TAG('c','y',' ',' '),    HB_TAG('W','E','L',' ')},       /* Welsh */
+  {HB_TAG('d','a',' ',' '),    HB_TAG('D','A','N',' ')},       /* Danish */
+  {HB_TAG('d','e',' ',' '),    HB_TAG('D','E','U',' ')},       /* German */
+  {HB_TAG('d','v',' ',' '),    HB_TAG('D','I','V',' ')},       /* Divehi (Dhivehi, Maldivian) */
+  {HB_TAG('d','v',' ',' '),    HB_TAG('D','H','V',' ')},       /* Divehi (Dhivehi, Maldivian) (deprecated) */
+  {HB_TAG('d','z',' ',' '),    HB_TAG('D','Z','N',' ')},       /* Dzongkha */
+  {HB_TAG('e','e',' ',' '),    HB_TAG('E','W','E',' ')},       /* Ewe */
+  {HB_TAG('e','l',' ',' '),    HB_TAG('E','L','L',' ')},       /* Modern Greek (1453-) -> Greek */
+  {HB_TAG('e','n',' ',' '),    HB_TAG('E','N','G',' ')},       /* English */
+  {HB_TAG('e','o',' ',' '),    HB_TAG('N','T','O',' ')},       /* Esperanto */
+  {HB_TAG('e','s',' ',' '),    HB_TAG('E','S','P',' ')},       /* Spanish */
+  {HB_TAG('e','t',' ',' '),    HB_TAG('E','T','I',' ')},       /* Estonian [macrolanguage] */
+  {HB_TAG('e','u',' ',' '),    HB_TAG('E','U','Q',' ')},       /* Basque */
+  {HB_TAG('f','a',' ',' '),    HB_TAG('F','A','R',' ')},       /* Persian [macrolanguage] */
+  {HB_TAG('f','f',' ',' '),    HB_TAG('F','U','L',' ')},       /* Fulah [macrolanguage] */
+  {HB_TAG('f','i',' ',' '),    HB_TAG('F','I','N',' ')},       /* Finnish */
+  {HB_TAG('f','j',' ',' '),    HB_TAG('F','J','I',' ')},       /* Fijian */
+  {HB_TAG('f','o',' ',' '),    HB_TAG('F','O','S',' ')},       /* Faroese */
+  {HB_TAG('f','r',' ',' '),    HB_TAG('F','R','A',' ')},       /* French */
+  {HB_TAG('f','y',' ',' '),    HB_TAG('F','R','I',' ')},       /* Western Frisian -> Frisian */
+  {HB_TAG('g','a',' ',' '),    HB_TAG('I','R','I',' ')},       /* Irish */
+  {HB_TAG('g','d',' ',' '),    HB_TAG('G','A','E',' ')},       /* Scottish Gaelic (Gaelic) */
+  {HB_TAG('g','l',' ',' '),    HB_TAG('G','A','L',' ')},       /* Galician */
+  {HB_TAG('g','n',' ',' '),    HB_TAG('G','U','A',' ')},       /* Guarani [macrolanguage] */
+  {HB_TAG('g','u',' ',' '),    HB_TAG('G','U','J',' ')},       /* Gujarati */
+  {HB_TAG('g','v',' ',' '),    HB_TAG('M','N','X',' ')},       /* Manx */
+  {HB_TAG('h','a',' ',' '),    HB_TAG('H','A','U',' ')},       /* Hausa */
+  {HB_TAG('h','e',' ',' '),    HB_TAG('I','W','R',' ')},       /* Hebrew */
+  {HB_TAG('h','i',' ',' '),    HB_TAG('H','I','N',' ')},       /* Hindi */
+  {HB_TAG('h','o',' ',' '),    HB_TAG('H','M','O',' ')},       /* Hiri Motu */
+  {HB_TAG('h','o',' ',' '),    HB_TAG('C','P','P',' ')},       /* Hiri Motu -> Creoles */
+  {HB_TAG('h','r',' ',' '),    HB_TAG('H','R','V',' ')},       /* Croatian */
+  {HB_TAG('h','t',' ',' '),    HB_TAG('H','A','I',' ')},       /* Haitian (Haitian Creole) */
+  {HB_TAG('h','t',' ',' '),    HB_TAG('C','P','P',' ')},       /* Haitian -> Creoles */
+  {HB_TAG('h','u',' ',' '),    HB_TAG('H','U','N',' ')},       /* Hungarian */
+  {HB_TAG('h','y',' ',' '),    HB_TAG('H','Y','E','0')},       /* Armenian -> Armenian East */
+  {HB_TAG('h','y',' ',' '),    HB_TAG('H','Y','E',' ')},       /* Armenian */
+  {HB_TAG('h','z',' ',' '),    HB_TAG('H','E','R',' ')},       /* Herero */
+  {HB_TAG('i','a',' ',' '),    HB_TAG('I','N','A',' ')},       /* Interlingua (International Auxiliary Language Association) */
+  {HB_TAG('i','d',' ',' '),    HB_TAG('I','N','D',' ')},       /* Indonesian */
+  {HB_TAG('i','d',' ',' '),    HB_TAG('M','L','Y',' ')},       /* Indonesian -> Malay */
+  {HB_TAG('i','e',' ',' '),    HB_TAG('I','L','E',' ')},       /* Interlingue */
+  {HB_TAG('i','g',' ',' '),    HB_TAG('I','B','O',' ')},       /* Igbo */
+  {HB_TAG('i','i',' ',' '),    HB_TAG('Y','I','M',' ')},       /* Sichuan Yi -> Yi Modern */
+  {HB_TAG('i','k',' ',' '),    HB_TAG('I','P','K',' ')},       /* Inupiaq [macrolanguage] -> Inupiat */
+  {HB_TAG('i','n',' ',' '),    HB_TAG('I','N','D',' ')},       /* Indonesian (retired code) */
+  {HB_TAG('i','n',' ',' '),    HB_TAG('M','L','Y',' ')},       /* Indonesian (retired code) -> Malay */
+  {HB_TAG('i','o',' ',' '),    HB_TAG('I','D','O',' ')},       /* Ido */
+  {HB_TAG('i','s',' ',' '),    HB_TAG('I','S','L',' ')},       /* Icelandic */
+  {HB_TAG('i','t',' ',' '),    HB_TAG('I','T','A',' ')},       /* Italian */
+  {HB_TAG('i','u',' ',' '),    HB_TAG('I','N','U',' ')},       /* Inuktitut [macrolanguage] */
+  {HB_TAG('i','u',' ',' '),    HB_TAG('I','N','U','K')},       /* Inuktitut [macrolanguage] -> Nunavik Inuktitut */
+  {HB_TAG('i','w',' ',' '),    HB_TAG('I','W','R',' ')},       /* Hebrew (retired code) */
+  {HB_TAG('j','a',' ',' '),    HB_TAG('J','A','N',' ')},       /* Japanese */
+  {HB_TAG('j','i',' ',' '),    HB_TAG('J','I','I',' ')},       /* Yiddish (retired code) */
+  {HB_TAG('j','v',' ',' '),    HB_TAG('J','A','V',' ')},       /* Javanese */
+  {HB_TAG('j','w',' ',' '),    HB_TAG('J','A','V',' ')},       /* Javanese (retired code) */
+  {HB_TAG('k','a',' ',' '),    HB_TAG('K','A','T',' ')},       /* Georgian */
+  {HB_TAG('k','g',' ',' '),    HB_TAG('K','O','N','0')},       /* Kongo [macrolanguage] */
+  {HB_TAG('k','i',' ',' '),    HB_TAG('K','I','K',' ')},       /* Kikuyu (Gikuyu) */
+  {HB_TAG('k','j',' ',' '),    HB_TAG('K','U','A',' ')},       /* Kuanyama */
+  {HB_TAG('k','k',' ',' '),    HB_TAG('K','A','Z',' ')},       /* Kazakh */
+  {HB_TAG('k','l',' ',' '),    HB_TAG('G','R','N',' ')},       /* Greenlandic */
+  {HB_TAG('k','m',' ',' '),    HB_TAG('K','H','M',' ')},       /* Khmer */
+  {HB_TAG('k','n',' ',' '),    HB_TAG('K','A','N',' ')},       /* Kannada */
+  {HB_TAG('k','o',' ',' '),    HB_TAG('K','O','R',' ')},       /* Korean */
+  {HB_TAG('k','o',' ',' '),    HB_TAG('K','O','H',' ')},       /* Korean -> Korean Old Hangul */
+  {HB_TAG('k','r',' ',' '),    HB_TAG('K','N','R',' ')},       /* Kanuri [macrolanguage] */
+  {HB_TAG('k','s',' ',' '),    HB_TAG('K','S','H',' ')},       /* Kashmiri */
+  {HB_TAG('k','u',' ',' '),    HB_TAG('K','U','R',' ')},       /* Kurdish [macrolanguage] */
+  {HB_TAG('k','v',' ',' '),    HB_TAG('K','O','M',' ')},       /* Komi [macrolanguage] */
+  {HB_TAG('k','w',' ',' '),    HB_TAG('C','O','R',' ')},       /* Cornish */
+  {HB_TAG('k','y',' ',' '),    HB_TAG('K','I','R',' ')},       /* Kirghiz (Kyrgyz) */
+  {HB_TAG('l','a',' ',' '),    HB_TAG('L','A','T',' ')},       /* Latin */
+  {HB_TAG('l','b',' ',' '),    HB_TAG('L','T','Z',' ')},       /* Luxembourgish */
+  {HB_TAG('l','g',' ',' '),    HB_TAG('L','U','G',' ')},       /* Ganda */
+  {HB_TAG('l','i',' ',' '),    HB_TAG('L','I','M',' ')},       /* Limburgish */
+  {HB_TAG('l','n',' ',' '),    HB_TAG('L','I','N',' ')},       /* Lingala */
+  {HB_TAG('l','o',' ',' '),    HB_TAG('L','A','O',' ')},       /* Lao */
+  {HB_TAG('l','t',' ',' '),    HB_TAG('L','T','H',' ')},       /* Lithuanian */
+  {HB_TAG('l','u',' ',' '),    HB_TAG('L','U','B',' ')},       /* Luba-Katanga */
+  {HB_TAG('l','v',' ',' '),    HB_TAG('L','V','I',' ')},       /* Latvian [macrolanguage] */
+  {HB_TAG('m','g',' ',' '),    HB_TAG('M','L','G',' ')},       /* Malagasy [macrolanguage] */
+  {HB_TAG('m','h',' ',' '),    HB_TAG('M','A','H',' ')},       /* Marshallese */
+  {HB_TAG('m','i',' ',' '),    HB_TAG('M','R','I',' ')},       /* Maori */
+  {HB_TAG('m','k',' ',' '),    HB_TAG('M','K','D',' ')},       /* Macedonian */
+  {HB_TAG('m','l',' ',' '),    HB_TAG('M','A','L',' ')},       /* Malayalam -> Malayalam Traditional */
+  {HB_TAG('m','l',' ',' '),    HB_TAG('M','L','R',' ')},       /* Malayalam -> Malayalam Reformed */
+  {HB_TAG('m','n',' ',' '),    HB_TAG('M','N','G',' ')},       /* Mongolian [macrolanguage] */
+  {HB_TAG('m','o',' ',' '),    HB_TAG('M','O','L',' ')},       /* Moldavian (retired code) */
+  {HB_TAG('m','o',' ',' '),    HB_TAG('R','O','M',' ')},       /* Moldavian (retired code) -> Romanian */
+  {HB_TAG('m','r',' ',' '),    HB_TAG('M','A','R',' ')},       /* Marathi */
+  {HB_TAG('m','s',' ',' '),    HB_TAG('M','L','Y',' ')},       /* Malay [macrolanguage] */
+  {HB_TAG('m','t',' ',' '),    HB_TAG('M','T','S',' ')},       /* Maltese */
+  {HB_TAG('m','y',' ',' '),    HB_TAG('B','R','M',' ')},       /* Burmese */
+  {HB_TAG('n','a',' ',' '),    HB_TAG('N','A','U',' ')},       /* Nauru -> Nauruan */
+  {HB_TAG('n','b',' ',' '),    HB_TAG('N','O','R',' ')},       /* Norwegian Bokmål -> Norwegian */
+  {HB_TAG('n','d',' ',' '),    HB_TAG('N','D','B',' ')},       /* North Ndebele -> Ndebele */
+  {HB_TAG('n','e',' ',' '),    HB_TAG('N','E','P',' ')},       /* Nepali [macrolanguage] */
+  {HB_TAG('n','g',' ',' '),    HB_TAG('N','D','G',' ')},       /* Ndonga */
+  {HB_TAG('n','l',' ',' '),    HB_TAG('N','L','D',' ')},       /* Dutch */
+  {HB_TAG('n','n',' ',' '),    HB_TAG('N','Y','N',' ')},       /* Norwegian Nynorsk (Nynorsk, Norwegian) */
+  {HB_TAG('n','o',' ',' '),    HB_TAG('N','O','R',' ')},       /* Norwegian [macrolanguage] */
+  {HB_TAG('n','r',' ',' '),    HB_TAG('N','D','B',' ')},       /* South Ndebele -> Ndebele */
+  {HB_TAG('n','v',' ',' '),    HB_TAG('N','A','V',' ')},       /* Navajo */
+  {HB_TAG('n','v',' ',' '),    HB_TAG('A','T','H',' ')},       /* Navajo -> Athapaskan */
+  {HB_TAG('n','y',' ',' '),    HB_TAG('C','H','I',' ')},       /* Chichewa (Chewa, Nyanja) */
+  {HB_TAG('o','c',' ',' '),    HB_TAG('O','C','I',' ')},       /* Occitan (post 1500) */
+  {HB_TAG('o','j',' ',' '),    HB_TAG('O','J','B',' ')},       /* Ojibwa [macrolanguage] -> Ojibway */
+  {HB_TAG('o','m',' ',' '),    HB_TAG('O','R','O',' ')},       /* Oromo [macrolanguage] */
+  {HB_TAG('o','r',' ',' '),    HB_TAG('O','R','I',' ')},       /* Odia (formerly Oriya) [macrolanguage] */
+  {HB_TAG('o','s',' ',' '),    HB_TAG('O','S','S',' ')},       /* Ossetian */
+  {HB_TAG('p','a',' ',' '),    HB_TAG('P','A','N',' ')},       /* Punjabi */
+  {HB_TAG('p','i',' ',' '),    HB_TAG('P','A','L',' ')},       /* Pali */
+  {HB_TAG('p','l',' ',' '),    HB_TAG('P','L','K',' ')},       /* Polish */
+  {HB_TAG('p','s',' ',' '),    HB_TAG('P','A','S',' ')},       /* Pashto [macrolanguage] */
+  {HB_TAG('p','t',' ',' '),    HB_TAG('P','T','G',' ')},       /* Portuguese */
+  {HB_TAG('q','u',' ',' '),    HB_TAG('Q','U','Z',' ')},       /* Quechua [macrolanguage] */
+  {HB_TAG('r','m',' ',' '),    HB_TAG('R','M','S',' ')},       /* Romansh */
+  {HB_TAG('r','n',' ',' '),    HB_TAG('R','U','N',' ')},       /* Rundi */
+  {HB_TAG('r','o',' ',' '),    HB_TAG('R','O','M',' ')},       /* Romanian */
+  {HB_TAG('r','u',' ',' '),    HB_TAG('R','U','S',' ')},       /* Russian */
+  {HB_TAG('r','w',' ',' '),    HB_TAG('R','U','A',' ')},       /* Kinyarwanda */
+  {HB_TAG('s','a',' ',' '),    HB_TAG('S','A','N',' ')},       /* Sanskrit */
+  {HB_TAG('s','c',' ',' '),    HB_TAG('S','R','D',' ')},       /* Sardinian [macrolanguage] */
+  {HB_TAG('s','d',' ',' '),    HB_TAG('S','N','D',' ')},       /* Sindhi */
+  {HB_TAG('s','e',' ',' '),    HB_TAG('N','S','M',' ')},       /* Northern Sami */
+  {HB_TAG('s','g',' ',' '),    HB_TAG('S','G','O',' ')},       /* Sango */
+  {HB_TAG('s','h',' ',' '),    HB_TAG('B','O','S',' ')},       /* Serbo-Croatian [macrolanguage] -> Bosnian */
+  {HB_TAG('s','h',' ',' '),    HB_TAG('H','R','V',' ')},       /* Serbo-Croatian [macrolanguage] -> Croatian */
+  {HB_TAG('s','h',' ',' '),    HB_TAG('S','R','B',' ')},       /* Serbo-Croatian [macrolanguage] -> Serbian */
+  {HB_TAG('s','i',' ',' '),    HB_TAG('S','N','H',' ')},       /* Sinhala (Sinhalese) */
+  {HB_TAG('s','k',' ',' '),    HB_TAG('S','K','Y',' ')},       /* Slovak */
+  {HB_TAG('s','l',' ',' '),    HB_TAG('S','L','V',' ')},       /* Slovenian */
+  {HB_TAG('s','m',' ',' '),    HB_TAG('S','M','O',' ')},       /* Samoan */
+  {HB_TAG('s','n',' ',' '),    HB_TAG('S','N','A','0')},       /* Shona */
+  {HB_TAG('s','o',' ',' '),    HB_TAG('S','M','L',' ')},       /* Somali */
+  {HB_TAG('s','q',' ',' '),    HB_TAG('S','Q','I',' ')},       /* Albanian [macrolanguage] */
+  {HB_TAG('s','r',' ',' '),    HB_TAG('S','R','B',' ')},       /* Serbian */
+  {HB_TAG('s','s',' ',' '),    HB_TAG('S','W','Z',' ')},       /* Swati */
+  {HB_TAG('s','t',' ',' '),    HB_TAG('S','O','T',' ')},       /* Southern Sotho */
+  {HB_TAG('s','u',' ',' '),    HB_TAG('S','U','N',' ')},       /* Sundanese */
+  {HB_TAG('s','v',' ',' '),    HB_TAG('S','V','E',' ')},       /* Swedish */
+  {HB_TAG('s','w',' ',' '),    HB_TAG('S','W','K',' ')},       /* Swahili [macrolanguage] */
+  {HB_TAG('t','a',' ',' '),    HB_TAG('T','A','M',' ')},       /* Tamil */
+  {HB_TAG('t','e',' ',' '),    HB_TAG('T','E','L',' ')},       /* Telugu */
+  {HB_TAG('t','g',' ',' '),    HB_TAG('T','A','J',' ')},       /* Tajik -> Tajiki */
+  {HB_TAG('t','h',' ',' '),    HB_TAG('T','H','A',' ')},       /* Thai */
+  {HB_TAG('t','i',' ',' '),    HB_TAG('T','G','Y',' ')},       /* Tigrinya */
+  {HB_TAG('t','k',' ',' '),    HB_TAG('T','K','M',' ')},       /* Turkmen */
+  {HB_TAG('t','l',' ',' '),    HB_TAG('T','G','L',' ')},       /* Tagalog */
+  {HB_TAG('t','n',' ',' '),    HB_TAG('T','N','A',' ')},       /* Tswana */
+  {HB_TAG('t','o',' ',' '),    HB_TAG('T','G','N',' ')},       /* Tonga (Tonga Islands) -> Tongan */
+  {HB_TAG('t','r',' ',' '),    HB_TAG('T','R','K',' ')},       /* Turkish */
+  {HB_TAG('t','s',' ',' '),    HB_TAG('T','S','G',' ')},       /* Tsonga */
+  {HB_TAG('t','t',' ',' '),    HB_TAG('T','A','T',' ')},       /* Tatar */
+  {HB_TAG('t','w',' ',' '),    HB_TAG('T','W','I',' ')},       /* Twi */
+  {HB_TAG('t','w',' ',' '),    HB_TAG('A','K','A',' ')},       /* Twi -> Akan */
+  {HB_TAG('t','y',' ',' '),    HB_TAG('T','H','T',' ')},       /* Tahitian */
+  {HB_TAG('u','g',' ',' '),    HB_TAG('U','Y','G',' ')},       /* Uyghur */
+  {HB_TAG('u','k',' ',' '),    HB_TAG('U','K','R',' ')},       /* Ukrainian */
+  {HB_TAG('u','r',' ',' '),    HB_TAG('U','R','D',' ')},       /* Urdu */
+  {HB_TAG('u','z',' ',' '),    HB_TAG('U','Z','B',' ')},       /* Uzbek [macrolanguage] */
+  {HB_TAG('v','e',' ',' '),    HB_TAG('V','E','N',' ')},       /* Venda */
+  {HB_TAG('v','i',' ',' '),    HB_TAG('V','I','T',' ')},       /* Vietnamese */
+  {HB_TAG('v','o',' ',' '),    HB_TAG('V','O','L',' ')},       /* Volapük */
+  {HB_TAG('w','a',' ',' '),    HB_TAG('W','L','N',' ')},       /* Walloon */
+  {HB_TAG('w','o',' ',' '),    HB_TAG('W','L','F',' ')},       /* Wolof */
+  {HB_TAG('x','h',' ',' '),    HB_TAG('X','H','S',' ')},       /* Xhosa */
+  {HB_TAG('y','i',' ',' '),    HB_TAG('J','I','I',' ')},       /* Yiddish [macrolanguage] */
+  {HB_TAG('y','o',' ',' '),    HB_TAG('Y','B','A',' ')},       /* Yoruba */
+  {HB_TAG('z','a',' ',' '),    HB_TAG('Z','H','A',' ')},       /* Zhuang [macrolanguage] */
+  {HB_TAG('z','h',' ',' '),    HB_TAG('Z','H','S',' ')},       /* Chinese, Simplified [macrolanguage] */
+  {HB_TAG('z','u',' ',' '),    HB_TAG('Z','U','L',' ')},       /* Zulu */
 };
 
+#ifndef HB_NO_LANGUAGE_LONG
+static const LangTag ot_languages3[] = {
+  {HB_TAG('a','a','e',' '),    HB_TAG('S','Q','I',' ')},       /* Arbëreshë Albanian -> Albanian */
+  {HB_TAG('a','a','o',' '),    HB_TAG('A','R','A',' ')},       /* Algerian Saharan Arabic -> Arabic */
+  {HB_TAG('a','a','t',' '),    HB_TAG('S','Q','I',' ')},       /* Arvanitika Albanian -> Albanian */
+  {HB_TAG('a','b','a',' '),    HB_TAG_NONE            },       /* Abé != Abaza */
+  {HB_TAG('a','b','h',' '),    HB_TAG('A','R','A',' ')},       /* Tajiki Arabic -> Arabic */
+  {HB_TAG('a','b','q',' '),    HB_TAG('A','B','A',' ')},       /* Abaza */
+  {HB_TAG('a','b','s',' '),    HB_TAG('C','P','P',' ')},       /* Ambonese Malay -> Creoles */
+  {HB_TAG('a','b','v',' '),    HB_TAG('A','R','A',' ')},       /* Baharna Arabic -> Arabic */
+  {HB_TAG('a','c','f',' '),    HB_TAG('F','A','N',' ')},       /* Saint Lucian Creole French -> French Antillean */
+  {HB_TAG('a','c','f',' '),    HB_TAG('C','P','P',' ')},       /* Saint Lucian Creole French -> Creoles */
+/*{HB_TAG('a','c','h',' '),    HB_TAG('A','C','H',' ')},*/     /* Acoli -> Acholi */
+  {HB_TAG('a','c','m',' '),    HB_TAG('A','R','A',' ')},       /* Mesopotamian Arabic -> Arabic */
+  {HB_TAG('a','c','q',' '),    HB_TAG('A','R','A',' ')},       /* Ta'izzi-Adeni Arabic -> Arabic */
+  {HB_TAG('a','c','r',' '),    HB_TAG('A','C','R',' ')},       /* Achi */
+  {HB_TAG('a','c','r',' '),    HB_TAG('M','Y','N',' ')},       /* Achi -> Mayan */
+  {HB_TAG('a','c','w',' '),    HB_TAG('A','R','A',' ')},       /* Hijazi Arabic -> Arabic */
+  {HB_TAG('a','c','x',' '),    HB_TAG('A','R','A',' ')},       /* Omani Arabic -> Arabic */
+  {HB_TAG('a','c','y',' '),    HB_TAG('A','R','A',' ')},       /* Cypriot Arabic -> Arabic */
+  {HB_TAG('a','d','a',' '),    HB_TAG('D','N','G',' ')},       /* Adangme -> Dangme */
+  {HB_TAG('a','d','f',' '),    HB_TAG('A','R','A',' ')},       /* Dhofari Arabic -> Arabic */
+  {HB_TAG('a','d','p',' '),    HB_TAG('D','Z','N',' ')},       /* Adap (retired code) -> Dzongkha */
+/*{HB_TAG('a','d','y',' '),    HB_TAG('A','D','Y',' ')},*/     /* Adyghe */
+  {HB_TAG('a','e','b',' '),    HB_TAG('A','R','A',' ')},       /* Tunisian Arabic -> Arabic */
+  {HB_TAG('a','e','c',' '),    HB_TAG('A','R','A',' ')},       /* Saidi Arabic -> Arabic */
+  {HB_TAG('a','f','b',' '),    HB_TAG('A','R','A',' ')},       /* Gulf Arabic -> Arabic */
+  {HB_TAG('a','f','k',' '),    HB_TAG_NONE            },       /* Nanubae != Afrikaans */
+  {HB_TAG('a','f','s',' '),    HB_TAG('C','P','P',' ')},       /* Afro-Seminole Creole -> Creoles */
+  {HB_TAG('a','g','u',' '),    HB_TAG('M','Y','N',' ')},       /* Aguacateco -> Mayan */
+  {HB_TAG('a','g','w',' '),    HB_TAG_NONE            },       /* Kahua != Agaw */
+  {HB_TAG('a','h','g',' '),    HB_TAG('A','G','W',' ')},       /* Qimant -> Agaw */
+  {HB_TAG('a','h','t',' '),    HB_TAG('A','T','H',' ')},       /* Ahtena -> Athapaskan */
+  {HB_TAG('a','i','g',' '),    HB_TAG('C','P','P',' ')},       /* Antigua and Barbuda Creole English -> Creoles */
+  {HB_TAG('a','i','i',' '),    HB_TAG('S','W','A',' ')},       /* Assyrian Neo-Aramaic -> Swadaya Aramaic */
+  {HB_TAG('a','i','i',' '),    HB_TAG('S','Y','R',' ')},       /* Assyrian Neo-Aramaic -> Syriac */
+/*{HB_TAG('a','i','o',' '),    HB_TAG('A','I','O',' ')},*/     /* Aiton */
+  {HB_TAG('a','i','w',' '),    HB_TAG('A','R','I',' ')},       /* Aari */
+  {HB_TAG('a','j','p',' '),    HB_TAG('A','R','A',' ')},       /* South Levantine Arabic (retired code) -> Arabic */
+  {HB_TAG('a','j','t',' '),    HB_TAG('A','R','A',' ')},       /* Judeo-Tunisian Arabic (retired code) -> Arabic */
+  {HB_TAG('a','k','b',' '),    HB_TAG('A','K','B',' ')},       /* Batak Angkola */
+  {HB_TAG('a','k','b',' '),    HB_TAG('B','T','K',' ')},       /* Batak Angkola -> Batak */
+  {HB_TAG('a','l','n',' '),    HB_TAG('S','Q','I',' ')},       /* Gheg Albanian -> Albanian */
+  {HB_TAG('a','l','s',' '),    HB_TAG('S','Q','I',' ')},       /* Tosk Albanian -> Albanian */
+/*{HB_TAG('a','l','t',' '),    HB_TAG('A','L','T',' ')},*/     /* Southern Altai -> Altai */
+  {HB_TAG('a','m','f',' '),    HB_TAG('H','B','N',' ')},       /* Hamer-Banna -> Hammer-Banna */
+  {HB_TAG('a','m','w',' '),    HB_TAG('S','Y','R',' ')},       /* Western Neo-Aramaic -> Syriac */
+/*{HB_TAG('a','n','g',' '),    HB_TAG('A','N','G',' ')},*/     /* Old English (ca. 450-1100) -> Anglo-Saxon */
+  {HB_TAG('a','o','a',' '),    HB_TAG('C','P','P',' ')},       /* Angolar -> Creoles */
+  {HB_TAG('a','p','a',' '),    HB_TAG('A','T','H',' ')},       /* Apache [collection] -> Athapaskan */
+  {HB_TAG('a','p','c',' '),    HB_TAG('A','R','A',' ')},       /* Levantine Arabic -> Arabic */
+  {HB_TAG('a','p','d',' '),    HB_TAG('A','R','A',' ')},       /* Sudanese Arabic -> Arabic */
+  {HB_TAG('a','p','j',' '),    HB_TAG('A','T','H',' ')},       /* Jicarilla Apache -> Athapaskan */
+  {HB_TAG('a','p','k',' '),    HB_TAG('A','T','H',' ')},       /* Kiowa Apache -> Athapaskan */
+  {HB_TAG('a','p','l',' '),    HB_TAG('A','T','H',' ')},       /* Lipan Apache -> Athapaskan */
+  {HB_TAG('a','p','m',' '),    HB_TAG('A','T','H',' ')},       /* Mescalero-Chiricahua Apache -> Athapaskan */
+  {HB_TAG('a','p','w',' '),    HB_TAG('A','T','H',' ')},       /* Western Apache -> Athapaskan */
+  {HB_TAG('a','r','b',' '),    HB_TAG('A','R','A',' ')},       /* Standard Arabic -> Arabic */
+  {HB_TAG('a','r','i',' '),    HB_TAG_NONE            },       /* Arikara != Aari */
+  {HB_TAG('a','r','k',' '),    HB_TAG_NONE            },       /* Arikapú != Rakhine */
+  {HB_TAG('a','r','n',' '),    HB_TAG('M','A','P',' ')},       /* Mapudungun */
+  {HB_TAG('a','r','q',' '),    HB_TAG('A','R','A',' ')},       /* Algerian Arabic -> Arabic */
+  {HB_TAG('a','r','s',' '),    HB_TAG('A','R','A',' ')},       /* Najdi Arabic -> Arabic */
+  {HB_TAG('a','r','y',' '),    HB_TAG('M','O','R',' ')},       /* Moroccan Arabic -> Moroccan */
+  {HB_TAG('a','r','y',' '),    HB_TAG('A','R','A',' ')},       /* Moroccan Arabic -> Arabic */
+  {HB_TAG('a','r','z',' '),    HB_TAG('A','R','A',' ')},       /* Egyptian Arabic -> Arabic */
+/*{HB_TAG('a','s','t',' '),    HB_TAG('A','S','T',' ')},*/     /* Asturian */
+/*{HB_TAG('a','t','h',' '),    HB_TAG('A','T','H',' ')},*/     /* Athapascan [collection] -> Athapaskan */
+  {HB_TAG('a','t','j',' '),    HB_TAG('R','C','R',' ')},       /* Atikamekw -> R-Cree */
+  {HB_TAG('a','t','v',' '),    HB_TAG('A','L','T',' ')},       /* Northern Altai -> Altai */
+  {HB_TAG('a','u','j',' '),    HB_TAG('B','B','R',' ')},       /* Awjilah -> Berber */
+  {HB_TAG('a','u','z',' '),    HB_TAG('A','R','A',' ')},       /* Uzbeki Arabic -> Arabic */
+  {HB_TAG('a','v','l',' '),    HB_TAG('A','R','A',' ')},       /* Eastern Egyptian Bedawi Arabic -> Arabic */
+/*{HB_TAG('a','v','n',' '),    HB_TAG('A','V','N',' ')},*/     /* Avatime */
+/*{HB_TAG('a','w','a',' '),    HB_TAG('A','W','A',' ')},*/     /* Awadhi */
+  {HB_TAG('a','y','c',' '),    HB_TAG('A','Y','M',' ')},       /* Southern Aymara -> Aymara */
+  {HB_TAG('a','y','h',' '),    HB_TAG('A','R','A',' ')},       /* Hadrami Arabic -> Arabic */
+  {HB_TAG('a','y','l',' '),    HB_TAG('A','R','A',' ')},       /* Libyan Arabic -> Arabic */
+  {HB_TAG('a','y','n',' '),    HB_TAG('A','R','A',' ')},       /* Sanaani Arabic -> Arabic */
+  {HB_TAG('a','y','p',' '),    HB_TAG('A','R','A',' ')},       /* North Mesopotamian Arabic -> Arabic */
+  {HB_TAG('a','y','r',' '),    HB_TAG('A','Y','M',' ')},       /* Central Aymara -> Aymara */
+  {HB_TAG('a','z','b',' '),    HB_TAG('A','Z','B',' ')},       /* South Azerbaijani -> Torki */
+  {HB_TAG('a','z','b',' '),    HB_TAG('A','Z','E',' ')},       /* South Azerbaijani -> Azerbaijani */
+  {HB_TAG('a','z','d',' '),    HB_TAG('N','A','H',' ')},       /* Eastern Durango Nahuatl -> Nahuatl */
+  {HB_TAG('a','z','j',' '),    HB_TAG('A','Z','E',' ')},       /* North Azerbaijani -> Azerbaijani */
+  {HB_TAG('a','z','n',' '),    HB_TAG('N','A','H',' ')},       /* Western Durango Nahuatl -> Nahuatl */
+  {HB_TAG('a','z','z',' '),    HB_TAG('N','A','H',' ')},       /* Highland Puebla Nahuatl -> Nahuatl */
+  {HB_TAG('b','a','d',' '),    HB_TAG('B','A','D','0')},       /* Banda [collection] */
+  {HB_TAG('b','a','g',' '),    HB_TAG_NONE            },       /* Tuki != Baghelkhandi */
+  {HB_TAG('b','a','h',' '),    HB_TAG('C','P','P',' ')},       /* Bahamas Creole English -> Creoles */
+  {HB_TAG('b','a','i',' '),    HB_TAG('B','M','L',' ')},       /* Bamileke [collection] */
+  {HB_TAG('b','a','l',' '),    HB_TAG('B','L','I',' ')},       /* Baluchi [macrolanguage] */
+/*{HB_TAG('b','a','n',' '),    HB_TAG('B','A','N',' ')},*/     /* Balinese */
+/*{HB_TAG('b','a','r',' '),    HB_TAG('B','A','R',' ')},*/     /* Bavarian */
+  {HB_TAG('b','a','u',' '),    HB_TAG_NONE            },       /* Bada (Nigeria) != Baulé */
+  {HB_TAG('b','b','c',' '),    HB_TAG('B','B','C',' ')},       /* Batak Toba */
+  {HB_TAG('b','b','c',' '),    HB_TAG('B','T','K',' ')},       /* Batak Toba -> Batak */
+  {HB_TAG('b','b','j',' '),    HB_TAG('B','M','L',' ')},       /* Ghomálá' -> Bamileke */
+  {HB_TAG('b','b','p',' '),    HB_TAG('B','A','D','0')},       /* West Central Banda -> Banda */
+  {HB_TAG('b','b','r',' '),    HB_TAG_NONE            },       /* Girawa != Berber */
+  {HB_TAG('b','b','z',' '),    HB_TAG('A','R','A',' ')},       /* Babalia Creole Arabic (retired code) -> Arabic */
+  {HB_TAG('b','c','c',' '),    HB_TAG('B','L','I',' ')},       /* Southern Balochi -> Baluchi */
+  {HB_TAG('b','c','h',' '),    HB_TAG_NONE            },       /* Bariai != Bench */
+  {HB_TAG('b','c','i',' '),    HB_TAG('B','A','U',' ')},       /* Baoulé -> Baulé */
+  {HB_TAG('b','c','l',' '),    HB_TAG('B','I','K',' ')},       /* Central Bikol -> Bikol */
+  {HB_TAG('b','c','q',' '),    HB_TAG('B','C','H',' ')},       /* Bench */
+  {HB_TAG('b','c','r',' '),    HB_TAG('A','T','H',' ')},       /* Babine -> Athapaskan */
+/*{HB_TAG('b','d','y',' '),    HB_TAG('B','D','Y',' ')},*/     /* Bandjalang */
+  {HB_TAG('b','e','a',' '),    HB_TAG('A','T','H',' ')},       /* Beaver -> Athapaskan */
+  {HB_TAG('b','e','b',' '),    HB_TAG('B','T','I',' ')},       /* Bebele -> Beti */
+/*{HB_TAG('b','e','m',' '),    HB_TAG('B','E','M',' ')},*/     /* Bemba (Zambia) */
+  {HB_TAG('b','e','r',' '),    HB_TAG('B','B','R',' ')},       /* Berber [collection] */
+  {HB_TAG('b','e','w',' '),    HB_TAG('C','P','P',' ')},       /* Betawi -> Creoles */
+  {HB_TAG('b','f','l',' '),    HB_TAG('B','A','D','0')},       /* Banda-Ndélé -> Banda */
+  {HB_TAG('b','f','q',' '),    HB_TAG('B','A','D',' ')},       /* Badaga */
+  {HB_TAG('b','f','t',' '),    HB_TAG('B','L','T',' ')},       /* Balti */
+  {HB_TAG('b','f','u',' '),    HB_TAG('L','A','H',' ')},       /* Gahri -> Lahuli */
+  {HB_TAG('b','f','y',' '),    HB_TAG('B','A','G',' ')},       /* Bagheli -> Baghelkhandi */
+/*{HB_TAG('b','g','c',' '),    HB_TAG('B','G','C',' ')},*/     /* Haryanvi */
+  {HB_TAG('b','g','n',' '),    HB_TAG('B','L','I',' ')},       /* Western Balochi -> Baluchi */
+  {HB_TAG('b','g','p',' '),    HB_TAG('B','L','I',' ')},       /* Eastern Balochi -> Baluchi */
+  {HB_TAG('b','g','q',' '),    HB_TAG('B','G','Q',' ')},       /* Bagri */
+  {HB_TAG('b','g','q',' '),    HB_TAG('R','A','J',' ')},       /* Bagri -> Rajasthani */
+  {HB_TAG('b','g','r',' '),    HB_TAG('Q','I','N',' ')},       /* Bawm Chin -> Chin */
+  {HB_TAG('b','h','b',' '),    HB_TAG('B','H','I',' ')},       /* Bhili */
+/*{HB_TAG('b','h','i',' '),    HB_TAG('B','H','I',' ')},*/     /* Bhilali -> Bhili */
+  {HB_TAG('b','h','k',' '),    HB_TAG('B','I','K',' ')},       /* Albay Bicolano (retired code) -> Bikol */
+/*{HB_TAG('b','h','o',' '),    HB_TAG('B','H','O',' ')},*/     /* Bhojpuri */
+  {HB_TAG('b','h','r',' '),    HB_TAG('M','L','G',' ')},       /* Bara Malagasy -> Malagasy */
+/*{HB_TAG('b','i','k',' '),    HB_TAG('B','I','K',' ')},*/     /* Bikol [macrolanguage] */
+  {HB_TAG('b','i','l',' '),    HB_TAG_NONE            },       /* Bile != Bilen */
+  {HB_TAG('b','i','n',' '),    HB_TAG('E','D','O',' ')},       /* Edo */
+  {HB_TAG('b','i','u',' '),    HB_TAG('Q','I','N',' ')},       /* Biete -> Chin */
+/*{HB_TAG('b','j','j',' '),    HB_TAG('B','J','J',' ')},*/     /* Kanauji */
+  {HB_TAG('b','j','n',' '),    HB_TAG('M','L','Y',' ')},       /* Banjar -> Malay */
+  {HB_TAG('b','j','o',' '),    HB_TAG('B','A','D','0')},       /* Mid-Southern Banda -> Banda */
+  {HB_TAG('b','j','q',' '),    HB_TAG('M','L','G',' ')},       /* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */
+  {HB_TAG('b','j','s',' '),    HB_TAG('C','P','P',' ')},       /* Bajan -> Creoles */
+  {HB_TAG('b','j','t',' '),    HB_TAG('B','L','N',' ')},       /* Balanta-Ganja -> Balante */
+  {HB_TAG('b','k','f',' '),    HB_TAG_NONE            },       /* Beeke != Blackfoot */
+  {HB_TAG('b','k','o',' '),    HB_TAG('B','M','L',' ')},       /* Kwa' -> Bamileke */
+  {HB_TAG('b','l','a',' '),    HB_TAG('B','K','F',' ')},       /* Siksika -> Blackfoot */
+  {HB_TAG('b','l','e',' '),    HB_TAG('B','L','N',' ')},       /* Balanta-Kentohe -> Balante */
+  {HB_TAG('b','l','g',' '),    HB_TAG('I','B','A',' ')},       /* Balau (retired code) -> Iban */
+  {HB_TAG('b','l','i',' '),    HB_TAG_NONE            },       /* Bolia != Baluchi */
+  {HB_TAG('b','l','k',' '),    HB_TAG('B','L','K',' ')},       /* Pa’o Karen */
+  {HB_TAG('b','l','k',' '),    HB_TAG('K','R','N',' ')},       /* Pa'o Karen -> Karen */
+  {HB_TAG('b','l','n',' '),    HB_TAG('B','I','K',' ')},       /* Southern Catanduanes Bikol -> Bikol */
+  {HB_TAG('b','l','t',' '),    HB_TAG_NONE            },       /* Tai Dam != Balti */
+  {HB_TAG('b','m','b',' '),    HB_TAG_NONE            },       /* Bembe != Bambara (Bamanankan) */
+  {HB_TAG('b','m','l',' '),    HB_TAG_NONE            },       /* Bomboli != Bamileke */
+  {HB_TAG('b','m','m',' '),    HB_TAG('M','L','G',' ')},       /* Northern Betsimisaraka Malagasy -> Malagasy */
+  {HB_TAG('b','p','d',' '),    HB_TAG('B','A','D','0')},       /* Banda-Banda -> Banda */
+  {HB_TAG('b','p','l',' '),    HB_TAG('C','P','P',' ')},       /* Broome Pearling Lugger Pidgin -> Creoles */
+  {HB_TAG('b','p','q',' '),    HB_TAG('C','P','P',' ')},       /* Banda Malay -> Creoles */
+/*{HB_TAG('b','p','y',' '),    HB_TAG('B','P','Y',' ')},*/     /* Bishnupriya -> Bishnupriya Manipuri */
+  {HB_TAG('b','q','i',' '),    HB_TAG('L','R','C',' ')},       /* Bakhtiari -> Luri */
+  {HB_TAG('b','q','k',' '),    HB_TAG('B','A','D','0')},       /* Banda-Mbrès -> Banda */
+  {HB_TAG('b','r','a',' '),    HB_TAG('B','R','I',' ')},       /* Braj -> Braj Bhasha */
+  {HB_TAG('b','r','c',' '),    HB_TAG('C','P','P',' ')},       /* Berbice Creole Dutch -> Creoles */
+/*{HB_TAG('b','r','h',' '),    HB_TAG('B','R','H',' ')},*/     /* Brahui */
+  {HB_TAG('b','r','i',' '),    HB_TAG_NONE            },       /* Mokpwe != Braj Bhasha */
+  {HB_TAG('b','r','m',' '),    HB_TAG_NONE            },       /* Barambu != Burmese */
+/*{HB_TAG('b','r','x',' '),    HB_TAG('B','R','X',' ')},*/     /* Bodo (India) */
+  {HB_TAG('b','s','h',' '),    HB_TAG_NONE            },       /* Kati != Bashkir */
+/*{HB_TAG('b','s','k',' '),    HB_TAG('B','S','K',' ')},*/     /* Burushaski */
+  {HB_TAG('b','t','b',' '),    HB_TAG('B','T','I',' ')},       /* Beti (Cameroon) (retired code) */
+  {HB_TAG('b','t','d',' '),    HB_TAG('B','T','D',' ')},       /* Batak Dairi (Pakpak) */
+  {HB_TAG('b','t','d',' '),    HB_TAG('B','T','K',' ')},       /* Batak Dairi -> Batak */
+  {HB_TAG('b','t','i',' '),    HB_TAG_NONE            },       /* Burate != Beti */
+  {HB_TAG('b','t','j',' '),    HB_TAG('M','L','Y',' ')},       /* Bacanese Malay -> Malay */
+/*{HB_TAG('b','t','k',' '),    HB_TAG('B','T','K',' ')},*/     /* Batak [collection] */
+  {HB_TAG('b','t','m',' '),    HB_TAG('B','T','M',' ')},       /* Batak Mandailing */
+  {HB_TAG('b','t','m',' '),    HB_TAG('B','T','K',' ')},       /* Batak Mandailing -> Batak */
+  {HB_TAG('b','t','o',' '),    HB_TAG('B','I','K',' ')},       /* Rinconada Bikol -> Bikol */
+  {HB_TAG('b','t','s',' '),    HB_TAG('B','T','S',' ')},       /* Batak Simalungun */
+  {HB_TAG('b','t','s',' '),    HB_TAG('B','T','K',' ')},       /* Batak Simalungun -> Batak */
+  {HB_TAG('b','t','x',' '),    HB_TAG('B','T','X',' ')},       /* Batak Karo */
+  {HB_TAG('b','t','x',' '),    HB_TAG('B','T','K',' ')},       /* Batak Karo -> Batak */
+  {HB_TAG('b','t','z',' '),    HB_TAG('B','T','Z',' ')},       /* Batak Alas-Kluet */
+  {HB_TAG('b','t','z',' '),    HB_TAG('B','T','K',' ')},       /* Batak Alas-Kluet -> Batak */
+/*{HB_TAG('b','u','g',' '),    HB_TAG('B','U','G',' ')},*/     /* Buginese -> Bugis */
+  {HB_TAG('b','u','m',' '),    HB_TAG('B','T','I',' ')},       /* Bulu (Cameroon) -> Beti */
+  {HB_TAG('b','v','e',' '),    HB_TAG('M','L','Y',' ')},       /* Berau Malay -> Malay */
+  {HB_TAG('b','v','u',' '),    HB_TAG('M','L','Y',' ')},       /* Bukit Malay -> Malay */
+  {HB_TAG('b','w','e',' '),    HB_TAG('K','R','N',' ')},       /* Bwe Karen -> Karen */
+  {HB_TAG('b','x','k',' '),    HB_TAG('L','U','H',' ')},       /* Bukusu -> Luyia */
+  {HB_TAG('b','x','o',' '),    HB_TAG('C','P','P',' ')},       /* Barikanchi -> Creoles */
+  {HB_TAG('b','x','p',' '),    HB_TAG('B','T','I',' ')},       /* Bebil -> Beti */
+  {HB_TAG('b','x','r',' '),    HB_TAG('R','B','U',' ')},       /* Russia Buriat -> Russian Buriat */
+  {HB_TAG('b','y','n',' '),    HB_TAG('B','I','L',' ')},       /* Bilin -> Bilen */
+  {HB_TAG('b','y','v',' '),    HB_TAG('B','Y','V',' ')},       /* Medumba */
+  {HB_TAG('b','y','v',' '),    HB_TAG('B','M','L',' ')},       /* Medumba -> Bamileke */
+  {HB_TAG('b','z','c',' '),    HB_TAG('M','L','G',' ')},       /* Southern Betsimisaraka Malagasy -> Malagasy */
+  {HB_TAG('b','z','j',' '),    HB_TAG('C','P','P',' ')},       /* Belize Kriol English -> Creoles */
+  {HB_TAG('b','z','k',' '),    HB_TAG('C','P','P',' ')},       /* Nicaragua Creole English -> Creoles */
+  {HB_TAG('c','a','a',' '),    HB_TAG('M','Y','N',' ')},       /* Chortí -> Mayan */
+  {HB_TAG('c','a','c',' '),    HB_TAG('M','Y','N',' ')},       /* Chuj -> Mayan */
+  {HB_TAG('c','a','f',' '),    HB_TAG('C','R','R',' ')},       /* Southern Carrier -> Carrier */
+  {HB_TAG('c','a','f',' '),    HB_TAG('A','T','H',' ')},       /* Southern Carrier -> Athapaskan */
+  {HB_TAG('c','a','k',' '),    HB_TAG('C','A','K',' ')},       /* Kaqchikel */
+  {HB_TAG('c','a','k',' '),    HB_TAG('M','Y','N',' ')},       /* Kaqchikel -> Mayan */
+  {HB_TAG('c','b','k',' '),    HB_TAG('C','B','K',' ')},       /* Chavacano -> Zamboanga Chavacano */
+  {HB_TAG('c','b','k',' '),    HB_TAG('C','P','P',' ')},       /* Chavacano -> Creoles */
+  {HB_TAG('c','b','l',' '),    HB_TAG('Q','I','N',' ')},       /* Bualkhaw Chin -> Chin */
+  {HB_TAG('c','c','l',' '),    HB_TAG('C','P','P',' ')},       /* Cutchi-Swahili -> Creoles */
+  {HB_TAG('c','c','m',' '),    HB_TAG('C','P','P',' ')},       /* Malaccan Creole Malay -> Creoles */
+  {HB_TAG('c','c','o',' '),    HB_TAG('C','C','H','N')},       /* Comaltepec Chinantec -> Chinantec */
+  {HB_TAG('c','c','q',' '),    HB_TAG('A','R','K',' ')},       /* Chaungtha (retired code) -> Rakhine */
+  {HB_TAG('c','d','o',' '),    HB_TAG('Z','H','S',' ')},       /* Min Dong Chinese -> Chinese, Simplified */
+/*{HB_TAG('c','e','b',' '),    HB_TAG('C','E','B',' ')},*/     /* Cebuano */
+  {HB_TAG('c','e','k',' '),    HB_TAG('Q','I','N',' ')},       /* Eastern Khumi Chin -> Chin */
+  {HB_TAG('c','e','y',' '),    HB_TAG('Q','I','N',' ')},       /* Ekai Chin -> Chin */
+  {HB_TAG('c','f','m',' '),    HB_TAG('H','A','L',' ')},       /* Halam (Falam Chin) */
+  {HB_TAG('c','f','m',' '),    HB_TAG('Q','I','N',' ')},       /* Falam Chin -> Chin */
+/*{HB_TAG('c','g','g',' '),    HB_TAG('C','G','G',' ')},*/     /* Chiga */
+  {HB_TAG('c','h','f',' '),    HB_TAG('M','Y','N',' ')},       /* Tabasco Chontal -> Mayan */
+  {HB_TAG('c','h','g',' '),    HB_TAG_NONE            },       /* Chagatai != Chaha Gurage */
+  {HB_TAG('c','h','h',' '),    HB_TAG_NONE            },       /* Chinook != Chattisgarhi */
+  {HB_TAG('c','h','j',' '),    HB_TAG('C','C','H','N')},       /* Ojitlán Chinantec -> Chinantec */
+  {HB_TAG('c','h','k',' '),    HB_TAG('C','H','K','0')},       /* Chuukese */
+  {HB_TAG('c','h','m',' '),    HB_TAG('H','M','A',' ')},       /* Mari (Russia) [macrolanguage] -> High Mari */
+  {HB_TAG('c','h','m',' '),    HB_TAG('L','M','A',' ')},       /* Mari (Russia) [macrolanguage] -> Low Mari */
+  {HB_TAG('c','h','n',' '),    HB_TAG('C','P','P',' ')},       /* Chinook jargon -> Creoles */
+/*{HB_TAG('c','h','o',' '),    HB_TAG('C','H','O',' ')},*/     /* Choctaw */
+  {HB_TAG('c','h','p',' '),    HB_TAG('C','H','P',' ')},       /* Chipewyan */
+  {HB_TAG('c','h','p',' '),    HB_TAG('S','A','Y',' ')},       /* Chipewyan -> Sayisi */
+  {HB_TAG('c','h','p',' '),    HB_TAG('A','T','H',' ')},       /* Chipewyan -> Athapaskan */
+  {HB_TAG('c','h','q',' '),    HB_TAG('C','C','H','N')},       /* Quiotepec Chinantec -> Chinantec */
+/*{HB_TAG('c','h','r',' '),    HB_TAG('C','H','R',' ')},*/     /* Cherokee */
+/*{HB_TAG('c','h','y',' '),    HB_TAG('C','H','Y',' ')},*/     /* Cheyenne */
+  {HB_TAG('c','h','z',' '),    HB_TAG('C','C','H','N')},       /* Ozumacín Chinantec -> Chinantec */
+  {HB_TAG('c','i','w',' '),    HB_TAG('O','J','B',' ')},       /* Chippewa -> Ojibway */
+/*{HB_TAG('c','j','a',' '),    HB_TAG('C','J','A',' ')},*/     /* Western Cham */
+/*{HB_TAG('c','j','m',' '),    HB_TAG('C','J','M',' ')},*/     /* Eastern Cham */
+  {HB_TAG('c','j','y',' '),    HB_TAG('Z','H','S',' ')},       /* Jinyu Chinese -> Chinese, Simplified */
+  {HB_TAG('c','k','a',' '),    HB_TAG('Q','I','N',' ')},       /* Khumi Awa Chin (retired code) -> Chin */
+  {HB_TAG('c','k','b',' '),    HB_TAG('K','U','R',' ')},       /* Central Kurdish -> Kurdish */
+  {HB_TAG('c','k','n',' '),    HB_TAG('Q','I','N',' ')},       /* Kaang Chin -> Chin */
+  {HB_TAG('c','k','s',' '),    HB_TAG('C','P','P',' ')},       /* Tayo -> Creoles */
+  {HB_TAG('c','k','t',' '),    HB_TAG('C','H','K',' ')},       /* Chukot -> Chukchi */
+  {HB_TAG('c','k','z',' '),    HB_TAG('M','Y','N',' ')},       /* Cakchiquel-Quiché Mixed Language -> Mayan */
+  {HB_TAG('c','l','c',' '),    HB_TAG('A','T','H',' ')},       /* Chilcotin -> Athapaskan */
+  {HB_TAG('c','l','d',' '),    HB_TAG('S','Y','R',' ')},       /* Chaldean Neo-Aramaic -> Syriac */
+  {HB_TAG('c','l','e',' '),    HB_TAG('C','C','H','N')},       /* Lealao Chinantec -> Chinantec */
+  {HB_TAG('c','l','j',' '),    HB_TAG('Q','I','N',' ')},       /* Laitu Chin -> Chin */
+  {HB_TAG('c','l','t',' '),    HB_TAG('Q','I','N',' ')},       /* Lautu Chin -> Chin */
+  {HB_TAG('c','m','n',' '),    HB_TAG('Z','H','S',' ')},       /* Mandarin Chinese -> Chinese, Simplified */
+  {HB_TAG('c','m','r',' '),    HB_TAG('Q','I','N',' ')},       /* Mro-Khimi Chin -> Chin */
+  {HB_TAG('c','n','b',' '),    HB_TAG('Q','I','N',' ')},       /* Chinbon Chin -> Chin */
+  {HB_TAG('c','n','h',' '),    HB_TAG('Q','I','N',' ')},       /* Hakha Chin -> Chin */
+  {HB_TAG('c','n','k',' '),    HB_TAG('Q','I','N',' ')},       /* Khumi Chin -> Chin */
+  {HB_TAG('c','n','l',' '),    HB_TAG('C','C','H','N')},       /* Lalana Chinantec -> Chinantec */
+  {HB_TAG('c','n','p',' '),    HB_TAG('Z','H','S',' ')},       /* Northern Ping Chinese -> Chinese, Simplified */
+  {HB_TAG('c','n','r',' '),    HB_TAG('S','R','B',' ')},       /* Montenegrin -> Serbian */
+  {HB_TAG('c','n','t',' '),    HB_TAG('C','C','H','N')},       /* Tepetotutla Chinantec -> Chinantec */
+  {HB_TAG('c','n','u',' '),    HB_TAG('B','B','R',' ')},       /* Chenoua -> Berber */
+  {HB_TAG('c','n','w',' '),    HB_TAG('Q','I','N',' ')},       /* Ngawn Chin -> Chin */
+  {HB_TAG('c','o','a',' '),    HB_TAG('M','L','Y',' ')},       /* Cocos Islands Malay -> Malay */
+  {HB_TAG('c','o','b',' '),    HB_TAG('M','Y','N',' ')},       /* Chicomuceltec -> Mayan */
+/*{HB_TAG('c','o','p',' '),    HB_TAG('C','O','P',' ')},*/     /* Coptic */
+  {HB_TAG('c','o','q',' '),    HB_TAG('A','T','H',' ')},       /* Coquille -> Athapaskan */
+  {HB_TAG('c','p','a',' '),    HB_TAG('C','C','H','N')},       /* Palantla Chinantec -> Chinantec */
+  {HB_TAG('c','p','e',' '),    HB_TAG('C','P','P',' ')},       /* English-based creoles and pidgins [collection] -> Creoles */
+  {HB_TAG('c','p','f',' '),    HB_TAG('C','P','P',' ')},       /* French-based creoles and pidgins [collection] -> Creoles */
+  {HB_TAG('c','p','i',' '),    HB_TAG('C','P','P',' ')},       /* Chinese Pidgin English -> Creoles */
+/*{HB_TAG('c','p','p',' '),    HB_TAG('C','P','P',' ')},*/     /* Portuguese-based creoles and pidgins [collection] -> Creoles */
+  {HB_TAG('c','p','x',' '),    HB_TAG('Z','H','S',' ')},       /* Pu-Xian Chinese -> Chinese, Simplified */
+  {HB_TAG('c','q','d',' '),    HB_TAG('H','M','N',' ')},       /* Chuanqiandian Cluster Miao -> Hmong */
+  {HB_TAG('c','q','u',' '),    HB_TAG('Q','U','H',' ')},       /* Chilean Quechua (retired code) -> Quechua (Bolivia) */
+  {HB_TAG('c','q','u',' '),    HB_TAG('Q','U','Z',' ')},       /* Chilean Quechua (retired code) -> Quechua */
+  {HB_TAG('c','r','h',' '),    HB_TAG('C','R','T',' ')},       /* Crimean Tatar */
+  {HB_TAG('c','r','i',' '),    HB_TAG('C','P','P',' ')},       /* Sãotomense -> Creoles */
+  {HB_TAG('c','r','j',' '),    HB_TAG('E','C','R',' ')},       /* Southern East Cree -> Eastern Cree */
+  {HB_TAG('c','r','j',' '),    HB_TAG('Y','C','R',' ')},       /* Southern East Cree -> Y-Cree */
+  {HB_TAG('c','r','j',' '),    HB_TAG('C','R','E',' ')},       /* Southern East Cree -> Cree */
+  {HB_TAG('c','r','k',' '),    HB_TAG('W','C','R',' ')},       /* Plains Cree -> West-Cree */
+  {HB_TAG('c','r','k',' '),    HB_TAG('Y','C','R',' ')},       /* Plains Cree -> Y-Cree */
+  {HB_TAG('c','r','k',' '),    HB_TAG('C','R','E',' ')},       /* Plains Cree -> Cree */
+  {HB_TAG('c','r','l',' '),    HB_TAG('E','C','R',' ')},       /* Northern East Cree -> Eastern Cree */
+  {HB_TAG('c','r','l',' '),    HB_TAG('Y','C','R',' ')},       /* Northern East Cree -> Y-Cree */
+  {HB_TAG('c','r','l',' '),    HB_TAG('C','R','E',' ')},       /* Northern East Cree -> Cree */
+  {HB_TAG('c','r','m',' '),    HB_TAG('M','C','R',' ')},       /* Moose Cree */
+  {HB_TAG('c','r','m',' '),    HB_TAG('L','C','R',' ')},       /* Moose Cree -> L-Cree */
+  {HB_TAG('c','r','m',' '),    HB_TAG('C','R','E',' ')},       /* Moose Cree -> Cree */
+  {HB_TAG('c','r','p',' '),    HB_TAG('C','P','P',' ')},       /* Creoles and pidgins [collection] -> Creoles */
+  {HB_TAG('c','r','r',' '),    HB_TAG_NONE            },       /* Carolina Algonquian != Carrier */
+  {HB_TAG('c','r','s',' '),    HB_TAG('C','P','P',' ')},       /* Seselwa Creole French -> Creoles */
+  {HB_TAG('c','r','t',' '),    HB_TAG_NONE            },       /* Iyojwa'ja Chorote != Crimean Tatar */
+  {HB_TAG('c','r','x',' '),    HB_TAG('C','R','R',' ')},       /* Carrier */
+  {HB_TAG('c','r','x',' '),    HB_TAG('A','T','H',' ')},       /* Carrier -> Athapaskan */
+  {HB_TAG('c','s','a',' '),    HB_TAG('C','C','H','N')},       /* Chiltepec Chinantec -> Chinantec */
+/*{HB_TAG('c','s','b',' '),    HB_TAG('C','S','B',' ')},*/     /* Kashubian */
+  {HB_TAG('c','s','h',' '),    HB_TAG('Q','I','N',' ')},       /* Asho Chin -> Chin */
+  {HB_TAG('c','s','j',' '),    HB_TAG('Q','I','N',' ')},       /* Songlai Chin -> Chin */
+  {HB_TAG('c','s','l',' '),    HB_TAG_NONE            },       /* Chinese Sign Language != Church Slavonic */
+  {HB_TAG('c','s','o',' '),    HB_TAG('C','C','H','N')},       /* Sochiapam Chinantec -> Chinantec */
+  {HB_TAG('c','s','p',' '),    HB_TAG('Z','H','S',' ')},       /* Southern Ping Chinese -> Chinese, Simplified */
+  {HB_TAG('c','s','v',' '),    HB_TAG('Q','I','N',' ')},       /* Sumtu Chin -> Chin */
+  {HB_TAG('c','s','w',' '),    HB_TAG('N','C','R',' ')},       /* Swampy Cree -> N-Cree */
+  {HB_TAG('c','s','w',' '),    HB_TAG('N','H','C',' ')},       /* Swampy Cree -> Norway House Cree */
+  {HB_TAG('c','s','w',' '),    HB_TAG('C','R','E',' ')},       /* Swampy Cree -> Cree */
+  {HB_TAG('c','s','y',' '),    HB_TAG('Q','I','N',' ')},       /* Siyin Chin -> Chin */
+  {HB_TAG('c','t','c',' '),    HB_TAG('A','T','H',' ')},       /* Chetco -> Athapaskan */
+  {HB_TAG('c','t','d',' '),    HB_TAG('Q','I','N',' ')},       /* Tedim Chin -> Chin */
+  {HB_TAG('c','t','e',' '),    HB_TAG('C','C','H','N')},       /* Tepinapa Chinantec -> Chinantec */
+/*{HB_TAG('c','t','g',' '),    HB_TAG('C','T','G',' ')},*/     /* Chittagonian */
+  {HB_TAG('c','t','h',' '),    HB_TAG('Q','I','N',' ')},       /* Thaiphum Chin -> Chin */
+  {HB_TAG('c','t','l',' '),    HB_TAG('C','C','H','N')},       /* Tlacoatzintepec Chinantec -> Chinantec */
+  {HB_TAG('c','t','s',' '),    HB_TAG('B','I','K',' ')},       /* Northern Catanduanes Bikol -> Bikol */
+/*{HB_TAG('c','t','t',' '),    HB_TAG('C','T','T',' ')},*/     /* Wayanad Chetti */
+  {HB_TAG('c','t','u',' '),    HB_TAG('M','Y','N',' ')},       /* Chol -> Mayan */
+  {HB_TAG('c','u','c',' '),    HB_TAG('C','C','H','N')},       /* Usila Chinantec -> Chinantec */
+/*{HB_TAG('c','u','k',' '),    HB_TAG('C','U','K',' ')},*/     /* San Blas Kuna */
+  {HB_TAG('c','v','n',' '),    HB_TAG('C','C','H','N')},       /* Valle Nacional Chinantec -> Chinantec */
+  {HB_TAG('c','w','d',' '),    HB_TAG('D','C','R',' ')},       /* Woods Cree */
+  {HB_TAG('c','w','d',' '),    HB_TAG('T','C','R',' ')},       /* Woods Cree -> TH-Cree */
+  {HB_TAG('c','w','d',' '),    HB_TAG('C','R','E',' ')},       /* Woods Cree -> Cree */
+  {HB_TAG('c','z','h',' '),    HB_TAG('Z','H','S',' ')},       /* Huizhou Chinese -> Chinese, Simplified */
+  {HB_TAG('c','z','o',' '),    HB_TAG('Z','H','S',' ')},       /* Min Zhong Chinese -> Chinese, Simplified */
+  {HB_TAG('c','z','t',' '),    HB_TAG('Q','I','N',' ')},       /* Zotung Chin -> Chin */
+/*{HB_TAG('d','a','g',' '),    HB_TAG('D','A','G',' ')},*/     /* Dagbani */
+  {HB_TAG('d','a','o',' '),    HB_TAG('Q','I','N',' ')},       /* Daai Chin -> Chin */
+  {HB_TAG('d','a','p',' '),    HB_TAG('N','I','S',' ')},       /* Nisi (India) (retired code) */
+/*{HB_TAG('d','a','r',' '),    HB_TAG('D','A','R',' ')},*/     /* Dargwa */
+/*{HB_TAG('d','a','x',' '),    HB_TAG('D','A','X',' ')},*/     /* Dayi */
+  {HB_TAG('d','c','r',' '),    HB_TAG('C','P','P',' ')},       /* Negerhollands -> Creoles */
+  {HB_TAG('d','e','n',' '),    HB_TAG('S','L','A',' ')},       /* Slave (Athapascan) [macrolanguage] -> Slavey */
+  {HB_TAG('d','e','n',' '),    HB_TAG('A','T','H',' ')},       /* Slave (Athapascan) [macrolanguage] -> Athapaskan */
+  {HB_TAG('d','e','p',' '),    HB_TAG('C','P','P',' ')},       /* Pidgin Delaware -> Creoles */
+  {HB_TAG('d','g','o',' '),    HB_TAG('D','G','O',' ')},       /* Dogri (individual language) */
+  {HB_TAG('d','g','o',' '),    HB_TAG('D','G','R',' ')},       /* Dogri (macrolanguage) */
+  {HB_TAG('d','g','r',' '),    HB_TAG('A','T','H',' ')},       /* Dogrib -> Athapaskan */
+  {HB_TAG('d','h','d',' '),    HB_TAG('M','A','W',' ')},       /* Dhundari -> Marwari */
+/*{HB_TAG('d','h','g',' '),    HB_TAG('D','H','G',' ')},*/     /* Dhangu */
+  {HB_TAG('d','h','v',' '),    HB_TAG_NONE            },       /* Dehu != Divehi (Dhivehi, Maldivian) (deprecated) */
+  {HB_TAG('d','i','b',' '),    HB_TAG('D','N','K',' ')},       /* South Central Dinka -> Dinka */
+  {HB_TAG('d','i','k',' '),    HB_TAG('D','N','K',' ')},       /* Southwestern Dinka -> Dinka */
+  {HB_TAG('d','i','n',' '),    HB_TAG('D','N','K',' ')},       /* Dinka [macrolanguage] */
+  {HB_TAG('d','i','p',' '),    HB_TAG('D','N','K',' ')},       /* Northeastern Dinka -> Dinka */
+  {HB_TAG('d','i','q',' '),    HB_TAG('D','I','Q',' ')},       /* Dimli */
+  {HB_TAG('d','i','q',' '),    HB_TAG('Z','Z','A',' ')},       /* Dimli -> Zazaki */
+  {HB_TAG('d','i','w',' '),    HB_TAG('D','N','K',' ')},       /* Northwestern Dinka -> Dinka */
+  {HB_TAG('d','j','e',' '),    HB_TAG('D','J','R',' ')},       /* Zarma */
+  {HB_TAG('d','j','k',' '),    HB_TAG('C','P','P',' ')},       /* Eastern Maroon Creole -> Creoles */
+  {HB_TAG('d','j','r',' '),    HB_TAG('D','J','R','0')},       /* Djambarrpuyngu */
+  {HB_TAG('d','k','s',' '),    HB_TAG('D','N','K',' ')},       /* Southeastern Dinka -> Dinka */
+  {HB_TAG('d','n','g',' '),    HB_TAG('D','U','N',' ')},       /* Dungan */
+/*{HB_TAG('d','n','j',' '),    HB_TAG('D','N','J',' ')},*/     /* Dan */
+  {HB_TAG('d','n','k',' '),    HB_TAG_NONE            },       /* Dengka != Dinka */
+  {HB_TAG('d','o','i',' '),    HB_TAG('D','G','R',' ')},       /* Dogri (macrolanguage) [macrolanguage] */
+  {HB_TAG('d','r','h',' '),    HB_TAG('M','N','G',' ')},       /* Darkhat (retired code) -> Mongolian */
+  {HB_TAG('d','r','i',' '),    HB_TAG_NONE            },       /* C'Lela != Dari */
+  {HB_TAG('d','r','w',' '),    HB_TAG('D','R','I',' ')},       /* Darwazi (retired code) -> Dari */
+  {HB_TAG('d','r','w',' '),    HB_TAG('F','A','R',' ')},       /* Darwazi (retired code) -> Persian */
+  {HB_TAG('d','s','b',' '),    HB_TAG('L','S','B',' ')},       /* Lower Sorbian */
+  {HB_TAG('d','t','y',' '),    HB_TAG('N','E','P',' ')},       /* Dotyali -> Nepali */
+/*{HB_TAG('d','u','j',' '),    HB_TAG('D','U','J',' ')},*/     /* Dhuwal (retired code) */
+  {HB_TAG('d','u','n',' '),    HB_TAG_NONE            },       /* Dusun Deyah != Dungan */
+  {HB_TAG('d','u','p',' '),    HB_TAG('M','L','Y',' ')},       /* Duano -> Malay */
+  {HB_TAG('d','w','k',' '),    HB_TAG('K','U','I',' ')},       /* Dawik Kui -> Kui */
+  {HB_TAG('d','w','u',' '),    HB_TAG('D','U','J',' ')},       /* Dhuwal */
+  {HB_TAG('d','w','y',' '),    HB_TAG('D','U','J',' ')},       /* Dhuwaya -> Dhuwal */
+  {HB_TAG('d','y','u',' '),    HB_TAG('J','U','L',' ')},       /* Dyula -> Jula */
+  {HB_TAG('d','z','n',' '),    HB_TAG_NONE            },       /* Dzando != Dzongkha */
+  {HB_TAG('e','c','r',' '),    HB_TAG_NONE            },       /* Eteocretan != Eastern Cree */
+/*{HB_TAG('e','f','i',' '),    HB_TAG('E','F','I',' ')},*/     /* Efik */
+  {HB_TAG('e','k','k',' '),    HB_TAG('E','T','I',' ')},       /* Standard Estonian -> Estonian */
+  {HB_TAG('e','k','y',' '),    HB_TAG('K','R','N',' ')},       /* Eastern Kayah -> Karen */
+  {HB_TAG('e','m','k',' '),    HB_TAG('E','M','K',' ')},       /* Eastern Maninkakan */
+  {HB_TAG('e','m','k',' '),    HB_TAG('M','N','K',' ')},       /* Eastern Maninkakan -> Maninka */
+  {HB_TAG('e','m','y',' '),    HB_TAG('M','Y','N',' ')},       /* Epigraphic Mayan -> Mayan */
+  {HB_TAG('e','n','b',' '),    HB_TAG('K','A','L',' ')},       /* Markweeta -> Kalenjin */
+  {HB_TAG('e','n','f',' '),    HB_TAG('F','N','E',' ')},       /* Forest Enets */
+  {HB_TAG('e','n','h',' '),    HB_TAG('T','N','E',' ')},       /* Tundra Enets */
+  {HB_TAG('e','s','g',' '),    HB_TAG('G','O','N',' ')},       /* Aheri Gondi -> Gondi */
+  {HB_TAG('e','s','i',' '),    HB_TAG('I','P','K',' ')},       /* North Alaskan Inupiatun -> Inupiat */
+  {HB_TAG('e','s','k',' '),    HB_TAG('I','P','K',' ')},       /* Northwest Alaska Inupiatun -> Inupiat */
+/*{HB_TAG('e','s','u',' '),    HB_TAG('E','S','U',' ')},*/     /* Central Yupik */
+  {HB_TAG('e','t','o',' '),    HB_TAG('B','T','I',' ')},       /* Eton (Cameroon) -> Beti */
+  {HB_TAG('e','u','q',' '),    HB_TAG_NONE            },       /* Basque [collection] != Basque */
+  {HB_TAG('e','v','e',' '),    HB_TAG('E','V','N',' ')},       /* Even */
+  {HB_TAG('e','v','n',' '),    HB_TAG('E','V','K',' ')},       /* Evenki */
+  {HB_TAG('e','w','o',' '),    HB_TAG('B','T','I',' ')},       /* Ewondo -> Beti */
+  {HB_TAG('e','y','o',' '),    HB_TAG('K','A','L',' ')},       /* Keiyo -> Kalenjin */
+  {HB_TAG('f','a','b',' '),    HB_TAG('C','P','P',' ')},       /* Fa d'Ambu -> Creoles */
+  {HB_TAG('f','a','n',' '),    HB_TAG('F','A','N','0')},       /* Fang (Equatorial Guinea) */
+  {HB_TAG('f','a','n',' '),    HB_TAG('B','T','I',' ')},       /* Fang (Equatorial Guinea) -> Beti */
+  {HB_TAG('f','a','r',' '),    HB_TAG_NONE            },       /* Fataleka != Persian */
+  {HB_TAG('f','a','t',' '),    HB_TAG('F','A','T',' ')},       /* Fanti */
+  {HB_TAG('f','a','t',' '),    HB_TAG('A','K','A',' ')},       /* Fanti -> Akan */
+  {HB_TAG('f','b','l',' '),    HB_TAG('B','I','K',' ')},       /* West Albay Bikol -> Bikol */
+  {HB_TAG('f','f','m',' '),    HB_TAG('F','U','L',' ')},       /* Maasina Fulfulde -> Fulah */
+  {HB_TAG('f','i','l',' '),    HB_TAG('P','I','L',' ')},       /* Filipino */
+  {HB_TAG('f','l','m',' '),    HB_TAG('H','A','L',' ')},       /* Halam (Falam Chin) (retired code) */
+  {HB_TAG('f','l','m',' '),    HB_TAG('Q','I','N',' ')},       /* Falam Chin (retired code) -> Chin */
+  {HB_TAG('f','m','p',' '),    HB_TAG('F','M','P',' ')},       /* Fe’fe’ */
+  {HB_TAG('f','m','p',' '),    HB_TAG('B','M','L',' ')},       /* Fe'fe' -> Bamileke */
+  {HB_TAG('f','n','g',' '),    HB_TAG('C','P','P',' ')},       /* Fanagalo -> Creoles */
+/*{HB_TAG('f','o','n',' '),    HB_TAG('F','O','N',' ')},*/     /* Fon */
+  {HB_TAG('f','o','s',' '),    HB_TAG_NONE            },       /* Siraya != Faroese */
+  {HB_TAG('f','p','e',' '),    HB_TAG('C','P','P',' ')},       /* Fernando Po Creole English -> Creoles */
+/*{HB_TAG('f','r','c',' '),    HB_TAG('F','R','C',' ')},*/     /* Cajun French */
+/*{HB_TAG('f','r','p',' '),    HB_TAG('F','R','P',' ')},*/     /* Arpitan */
+  {HB_TAG('f','u','b',' '),    HB_TAG('F','U','L',' ')},       /* Adamawa Fulfulde -> Fulah */
+  {HB_TAG('f','u','c',' '),    HB_TAG('F','U','L',' ')},       /* Pulaar -> Fulah */
+  {HB_TAG('f','u','e',' '),    HB_TAG('F','U','L',' ')},       /* Borgu Fulfulde -> Fulah */
+  {HB_TAG('f','u','f',' '),    HB_TAG('F','T','A',' ')},       /* Pular -> Futa */
+  {HB_TAG('f','u','f',' '),    HB_TAG('F','U','L',' ')},       /* Pular -> Fulah */
+  {HB_TAG('f','u','h',' '),    HB_TAG('F','U','L',' ')},       /* Western Niger Fulfulde -> Fulah */
+  {HB_TAG('f','u','i',' '),    HB_TAG('F','U','L',' ')},       /* Bagirmi Fulfulde -> Fulah */
+  {HB_TAG('f','u','q',' '),    HB_TAG('F','U','L',' ')},       /* Central-Eastern Niger Fulfulde -> Fulah */
+  {HB_TAG('f','u','r',' '),    HB_TAG('F','R','L',' ')},       /* Friulian */
+  {HB_TAG('f','u','v',' '),    HB_TAG('F','U','V',' ')},       /* Nigerian Fulfulde */
+  {HB_TAG('f','u','v',' '),    HB_TAG('F','U','L',' ')},       /* Nigerian Fulfulde -> Fulah */
+  {HB_TAG('g','a','a',' '),    HB_TAG('G','A','D',' ')},       /* Ga */
+  {HB_TAG('g','a','c',' '),    HB_TAG('C','P','P',' ')},       /* Mixed Great Andamanese -> Creoles */
+  {HB_TAG('g','a','d',' '),    HB_TAG_NONE            },       /* Gaddang != Ga */
+  {HB_TAG('g','a','e',' '),    HB_TAG_NONE            },       /* Guarequena != Scottish Gaelic (Gaelic) */
+/*{HB_TAG('g','a','g',' '),    HB_TAG('G','A','G',' ')},*/     /* Gagauz */
+  {HB_TAG('g','a','l',' '),    HB_TAG_NONE            },       /* Galolen != Galician */
+  {HB_TAG('g','a','n',' '),    HB_TAG('Z','H','S',' ')},       /* Gan Chinese -> Chinese, Simplified */
+  {HB_TAG('g','a','r',' '),    HB_TAG_NONE            },       /* Galeya != Garshuni */
+  {HB_TAG('g','a','w',' '),    HB_TAG_NONE            },       /* Nobonob != Garhwali */
+  {HB_TAG('g','a','x',' '),    HB_TAG('O','R','O',' ')},       /* Borana-Arsi-Guji Oromo -> Oromo */
+  {HB_TAG('g','a','z',' '),    HB_TAG('O','R','O',' ')},       /* West Central Oromo -> Oromo */
+  {HB_TAG('g','b','m',' '),    HB_TAG('G','A','W',' ')},       /* Garhwali */
+  {HB_TAG('g','c','e',' '),    HB_TAG('A','T','H',' ')},       /* Galice -> Athapaskan */
+  {HB_TAG('g','c','f',' '),    HB_TAG('C','P','P',' ')},       /* Guadeloupean Creole French -> Creoles */
+  {HB_TAG('g','c','l',' '),    HB_TAG('C','P','P',' ')},       /* Grenadian Creole English -> Creoles */
+  {HB_TAG('g','c','r',' '),    HB_TAG('C','P','P',' ')},       /* Guianese Creole French -> Creoles */
+  {HB_TAG('g','d','a',' '),    HB_TAG('R','A','J',' ')},       /* Gade Lohar -> Rajasthani */
+/*{HB_TAG('g','e','z',' '),    HB_TAG('G','E','Z',' ')},*/     /* Geez */
+  {HB_TAG('g','g','o',' '),    HB_TAG('G','O','N',' ')},       /* Southern Gondi (retired code) -> Gondi */
+  {HB_TAG('g','h','a',' '),    HB_TAG('B','B','R',' ')},       /* Ghadamès -> Berber */
+  {HB_TAG('g','h','k',' '),    HB_TAG('K','R','N',' ')},       /* Geko Karen -> Karen */
+  {HB_TAG('g','h','o',' '),    HB_TAG('B','B','R',' ')},       /* Ghomara -> Berber */
+  {HB_TAG('g','i','b',' '),    HB_TAG('C','P','P',' ')},       /* Gibanawa -> Creoles */
+/*{HB_TAG('g','i','h',' '),    HB_TAG('G','I','H',' ')},*/     /* Githabul */
+  {HB_TAG('g','i','l',' '),    HB_TAG('G','I','L','0')},       /* Kiribati (Gilbertese) */
+  {HB_TAG('g','j','u',' '),    HB_TAG('R','A','J',' ')},       /* Gujari -> Rajasthani */
+  {HB_TAG('g','k','p',' '),    HB_TAG('G','K','P',' ')},       /* Guinea Kpelle -> Kpelle (Guinea) */
+  {HB_TAG('g','k','p',' '),    HB_TAG('K','P','L',' ')},       /* Guinea Kpelle -> Kpelle */
+  {HB_TAG('g','l','d',' '),    HB_TAG('N','A','N',' ')},       /* Nanai */
+/*{HB_TAG('g','l','k',' '),    HB_TAG('G','L','K',' ')},*/     /* Gilaki */
+  {HB_TAG('g','m','z',' '),    HB_TAG_NONE            },       /* Mgbolizhia != Gumuz */
+  {HB_TAG('g','n','b',' '),    HB_TAG('Q','I','N',' ')},       /* Gangte -> Chin */
+/*{HB_TAG('g','n','n',' '),    HB_TAG('G','N','N',' ')},*/     /* Gumatj */
+  {HB_TAG('g','n','o',' '),    HB_TAG('G','O','N',' ')},       /* Northern Gondi -> Gondi */
+  {HB_TAG('g','n','w',' '),    HB_TAG('G','U','A',' ')},       /* Western Bolivian Guaraní -> Guarani */
+/*{HB_TAG('g','o','g',' '),    HB_TAG('G','O','G',' ')},*/     /* Gogo */
+  {HB_TAG('g','o','m',' '),    HB_TAG('K','O','K',' ')},       /* Goan Konkani -> Konkani */
+/*{HB_TAG('g','o','n',' '),    HB_TAG('G','O','N',' ')},*/     /* Gondi [macrolanguage] */
+  {HB_TAG('g','o','q',' '),    HB_TAG('C','P','P',' ')},       /* Gorap -> Creoles */
+  {HB_TAG('g','o','x',' '),    HB_TAG('B','A','D','0')},       /* Gobu -> Banda */
+  {HB_TAG('g','p','e',' '),    HB_TAG('C','P','P',' ')},       /* Ghanaian Pidgin English -> Creoles */
+  {HB_TAG('g','r','o',' '),    HB_TAG_NONE            },       /* Groma != Garo */
+  {HB_TAG('g','r','r',' '),    HB_TAG('B','B','R',' ')},       /* Taznatit -> Berber */
+  {HB_TAG('g','r','t',' '),    HB_TAG('G','R','O',' ')},       /* Garo */
+  {HB_TAG('g','r','u',' '),    HB_TAG('S','O','G',' ')},       /* Kistane -> Sodo Gurage */
+  {HB_TAG('g','s','w',' '),    HB_TAG('A','L','S',' ')},       /* Alsatian */
+  {HB_TAG('g','u','a',' '),    HB_TAG_NONE            },       /* Shiki != Guarani */
+/*{HB_TAG('g','u','c',' '),    HB_TAG('G','U','C',' ')},*/     /* Wayuu */
+/*{HB_TAG('g','u','f',' '),    HB_TAG('G','U','F',' ')},*/     /* Gupapuyngu */
+  {HB_TAG('g','u','g',' '),    HB_TAG('G','U','A',' ')},       /* Paraguayan Guaraní -> Guarani */
+  {HB_TAG('g','u','i',' '),    HB_TAG('G','U','A',' ')},       /* Eastern Bolivian Guaraní -> Guarani */
+  {HB_TAG('g','u','k',' '),    HB_TAG('G','M','Z',' ')},       /* Gumuz */
+  {HB_TAG('g','u','l',' '),    HB_TAG('C','P','P',' ')},       /* Sea Island Creole English -> Creoles */
+  {HB_TAG('g','u','n',' '),    HB_TAG('G','U','A',' ')},       /* Mbyá Guaraní -> Guarani */
+/*{HB_TAG('g','u','z',' '),    HB_TAG('G','U','Z',' ')},*/     /* Gusii */
+  {HB_TAG('g','w','i',' '),    HB_TAG('A','T','H',' ')},       /* Gwichʼin -> Athapaskan */
+  {HB_TAG('g','y','n',' '),    HB_TAG('C','P','P',' ')},       /* Guyanese Creole English -> Creoles */
+  {HB_TAG('h','a','a',' '),    HB_TAG('A','T','H',' ')},       /* Han -> Athapaskan */
+  {HB_TAG('h','a','e',' '),    HB_TAG('O','R','O',' ')},       /* Eastern Oromo -> Oromo */
+  {HB_TAG('h','a','i',' '),    HB_TAG('H','A','I','0')},       /* Haida [macrolanguage] */
+  {HB_TAG('h','a','k',' '),    HB_TAG('Z','H','S',' ')},       /* Hakka Chinese -> Chinese, Simplified */
+  {HB_TAG('h','a','l',' '),    HB_TAG_NONE            },       /* Halang != Halam (Falam Chin) */
+  {HB_TAG('h','a','r',' '),    HB_TAG('H','R','I',' ')},       /* Harari */
+/*{HB_TAG('h','a','w',' '),    HB_TAG('H','A','W',' ')},*/     /* Hawaiian */
+  {HB_TAG('h','a','x',' '),    HB_TAG('H','A','I','0')},       /* Southern Haida -> Haida */
+/*{HB_TAG('h','a','y',' '),    HB_TAG('H','A','Y',' ')},*/     /* Haya */
+/*{HB_TAG('h','a','z',' '),    HB_TAG('H','A','Z',' ')},*/     /* Hazaragi */
+  {HB_TAG('h','b','n',' '),    HB_TAG_NONE            },       /* Heiban != Hammer-Banna */
+  {HB_TAG('h','c','a',' '),    HB_TAG('C','P','P',' ')},       /* Andaman Creole Hindi -> Creoles */
+  {HB_TAG('h','d','n',' '),    HB_TAG('H','A','I','0')},       /* Northern Haida -> Haida */
+  {HB_TAG('h','e','a',' '),    HB_TAG('H','M','N',' ')},       /* Northern Qiandong Miao -> Hmong */
+/*{HB_TAG('h','e','i',' '),    HB_TAG('H','E','I',' ')},*/     /* Heiltsuk */
+/*{HB_TAG('h','i','l',' '),    HB_TAG('H','I','L',' ')},*/     /* Hiligaynon */
+  {HB_TAG('h','j','i',' '),    HB_TAG('M','L','Y',' ')},       /* Haji -> Malay */
+  {HB_TAG('h','l','t',' '),    HB_TAG('Q','I','N',' ')},       /* Matu Chin -> Chin */
+  {HB_TAG('h','m','a',' '),    HB_TAG('H','M','N',' ')},       /* Southern Mashan Hmong -> Hmong */
+  {HB_TAG('h','m','c',' '),    HB_TAG('H','M','N',' ')},       /* Central Huishui Hmong -> Hmong */
+  {HB_TAG('h','m','d',' '),    HB_TAG('H','M','D',' ')},       /* Large Flowery Miao -> A-Hmao */
+  {HB_TAG('h','m','d',' '),    HB_TAG('H','M','N',' ')},       /* Large Flowery Miao -> Hmong */
+  {HB_TAG('h','m','e',' '),    HB_TAG('H','M','N',' ')},       /* Eastern Huishui Hmong -> Hmong */
+  {HB_TAG('h','m','g',' '),    HB_TAG('H','M','N',' ')},       /* Southwestern Guiyang Hmong -> Hmong */
+  {HB_TAG('h','m','h',' '),    HB_TAG('H','M','N',' ')},       /* Southwestern Huishui Hmong -> Hmong */
+  {HB_TAG('h','m','i',' '),    HB_TAG('H','M','N',' ')},       /* Northern Huishui Hmong -> Hmong */
+  {HB_TAG('h','m','j',' '),    HB_TAG('H','M','N',' ')},       /* Ge -> Hmong */
+  {HB_TAG('h','m','l',' '),    HB_TAG('H','M','N',' ')},       /* Luopohe Hmong -> Hmong */
+  {HB_TAG('h','m','m',' '),    HB_TAG('H','M','N',' ')},       /* Central Mashan Hmong -> Hmong */
+/*{HB_TAG('h','m','n',' '),    HB_TAG('H','M','N',' ')},*/     /* Hmong [macrolanguage] */
+  {HB_TAG('h','m','p',' '),    HB_TAG('H','M','N',' ')},       /* Northern Mashan Hmong -> Hmong */
+  {HB_TAG('h','m','q',' '),    HB_TAG('H','M','N',' ')},       /* Eastern Qiandong Miao -> Hmong */
+  {HB_TAG('h','m','r',' '),    HB_TAG('Q','I','N',' ')},       /* Hmar -> Chin */
+  {HB_TAG('h','m','s',' '),    HB_TAG('H','M','N',' ')},       /* Southern Qiandong Miao -> Hmong */
+  {HB_TAG('h','m','w',' '),    HB_TAG('H','M','N',' ')},       /* Western Mashan Hmong -> Hmong */
+  {HB_TAG('h','m','y',' '),    HB_TAG('H','M','N',' ')},       /* Southern Guiyang Hmong -> Hmong */
+  {HB_TAG('h','m','z',' '),    HB_TAG('H','M','Z',' ')},       /* Hmong Shua -> Hmong Shuat */
+  {HB_TAG('h','m','z',' '),    HB_TAG('H','M','N',' ')},       /* Hmong Shua -> Hmong */
+/*{HB_TAG('h','n','d',' '),    HB_TAG('H','N','D',' ')},*/     /* Southern Hindko -> Hindko */
+  {HB_TAG('h','n','e',' '),    HB_TAG('C','H','H',' ')},       /* Chhattisgarhi -> Chattisgarhi */
+  {HB_TAG('h','n','j',' '),    HB_TAG('H','M','N',' ')},       /* Hmong Njua -> Hmong */
+  {HB_TAG('h','n','o',' '),    HB_TAG('H','N','D',' ')},       /* Northern Hindko -> Hindko */
+  {HB_TAG('h','o','c',' '),    HB_TAG('H','O',' ',' ')},       /* Ho */
+  {HB_TAG('h','o','i',' '),    HB_TAG('A','T','H',' ')},       /* Holikachuk -> Athapaskan */
+  {HB_TAG('h','o','j',' '),    HB_TAG('H','A','R',' ')},       /* Hadothi -> Harauti */
+  {HB_TAG('h','o','j',' '),    HB_TAG('R','A','J',' ')},       /* Hadothi -> Rajasthani */
+  {HB_TAG('h','r','a',' '),    HB_TAG('Q','I','N',' ')},       /* Hrangkhol -> Chin */
+  {HB_TAG('h','r','m',' '),    HB_TAG('H','M','N',' ')},       /* Horned Miao -> Hmong */
+  {HB_TAG('h','s','b',' '),    HB_TAG('U','S','B',' ')},       /* Upper Sorbian */
+  {HB_TAG('h','s','n',' '),    HB_TAG('Z','H','S',' ')},       /* Xiang Chinese -> Chinese, Simplified */
+  {HB_TAG('h','u','j',' '),    HB_TAG('H','M','N',' ')},       /* Northern Guiyang Hmong -> Hmong */
+  {HB_TAG('h','u','p',' '),    HB_TAG('A','T','H',' ')},       /* Hupa -> Athapaskan */
+  {HB_TAG('h','u','s',' '),    HB_TAG('M','Y','N',' ')},       /* Huastec -> Mayan */
+  {HB_TAG('h','w','c',' '),    HB_TAG('C','P','P',' ')},       /* Hawai'i Creole English -> Creoles */
+  {HB_TAG('h','y','w',' '),    HB_TAG('H','Y','E',' ')},       /* Western Armenian -> Armenian */
+/*{HB_TAG('i','b','a',' '),    HB_TAG('I','B','A',' ')},*/     /* Iban */
+/*{HB_TAG('i','b','b',' '),    HB_TAG('I','B','B',' ')},*/     /* Ibibio */
+  {HB_TAG('i','b','y',' '),    HB_TAG('I','J','O',' ')},       /* Ibani -> Ijo */
+  {HB_TAG('i','c','r',' '),    HB_TAG('C','P','P',' ')},       /* Islander Creole English -> Creoles */
+  {HB_TAG('i','d','a',' '),    HB_TAG('L','U','H',' ')},       /* Idakho-Isukha-Tiriki -> Luyia */
+  {HB_TAG('i','d','b',' '),    HB_TAG('C','P','P',' ')},       /* Indo-Portuguese -> Creoles */
+  {HB_TAG('i','g','b',' '),    HB_TAG('E','B','I',' ')},       /* Ebira */
+  {HB_TAG('i','h','b',' '),    HB_TAG('C','P','P',' ')},       /* Iha Based Pidgin -> Creoles */
+  {HB_TAG('i','j','c',' '),    HB_TAG('I','J','O',' ')},       /* Izon -> Ijo */
+  {HB_TAG('i','j','e',' '),    HB_TAG('I','J','O',' ')},       /* Biseni -> Ijo */
+  {HB_TAG('i','j','n',' '),    HB_TAG('I','J','O',' ')},       /* Kalabari -> Ijo */
+/*{HB_TAG('i','j','o',' '),    HB_TAG('I','J','O',' ')},*/     /* Ijo [collection] */
+  {HB_TAG('i','j','s',' '),    HB_TAG('I','J','O',' ')},       /* Southeast Ijo -> Ijo */
+  {HB_TAG('i','k','e',' '),    HB_TAG('I','N','U',' ')},       /* Eastern Canadian Inuktitut -> Inuktitut */
+  {HB_TAG('i','k','e',' '),    HB_TAG('I','N','U','K')},       /* Eastern Canadian Inuktitut -> Nunavik Inuktitut */
+  {HB_TAG('i','k','t',' '),    HB_TAG('I','N','U',' ')},       /* Inuinnaqtun -> Inuktitut */
+/*{HB_TAG('i','l','o',' '),    HB_TAG('I','L','O',' ')},*/     /* Iloko -> Ilokano */
+  {HB_TAG('i','n','g',' '),    HB_TAG('A','T','H',' ')},       /* Degexit'an -> Athapaskan */
+  {HB_TAG('i','n','h',' '),    HB_TAG('I','N','G',' ')},       /* Ingush */
+  {HB_TAG('i','r','i',' '),    HB_TAG_NONE            },       /* Rigwe != Irish */
+/*{HB_TAG('i','r','u',' '),    HB_TAG('I','R','U',' ')},*/     /* Irula */
+  {HB_TAG('i','s','m',' '),    HB_TAG_NONE            },       /* Masimasi != Inari Sami */
+  {HB_TAG('i','t','z',' '),    HB_TAG('M','Y','N',' ')},       /* Itzá -> Mayan */
+  {HB_TAG('i','x','l',' '),    HB_TAG('M','Y','N',' ')},       /* Ixil -> Mayan */
+  {HB_TAG('j','a','c',' '),    HB_TAG('M','Y','N',' ')},       /* Popti' -> Mayan */
+  {HB_TAG('j','a','k',' '),    HB_TAG('M','L','Y',' ')},       /* Jakun -> Malay */
+  {HB_TAG('j','a','m',' '),    HB_TAG('J','A','M',' ')},       /* Jamaican Creole English -> Jamaican Creole */
+  {HB_TAG('j','a','m',' '),    HB_TAG('C','P','P',' ')},       /* Jamaican Creole English -> Creoles */
+  {HB_TAG('j','a','n',' '),    HB_TAG_NONE            },       /* Jandai != Japanese */
+  {HB_TAG('j','a','x',' '),    HB_TAG('M','L','Y',' ')},       /* Jambi Malay -> Malay */
+  {HB_TAG('j','b','e',' '),    HB_TAG('B','B','R',' ')},       /* Judeo-Berber -> Berber */
+  {HB_TAG('j','b','n',' '),    HB_TAG('B','B','R',' ')},       /* Nafusi -> Berber */
+/*{HB_TAG('j','b','o',' '),    HB_TAG('J','B','O',' ')},*/     /* Lojban */
+/*{HB_TAG('j','c','t',' '),    HB_TAG('J','C','T',' ')},*/     /* Krymchak */
+  {HB_TAG('j','g','o',' '),    HB_TAG('B','M','L',' ')},       /* Ngomba -> Bamileke */
+  {HB_TAG('j','i','i',' '),    HB_TAG_NONE            },       /* Jiiddu != Yiddish */
+  {HB_TAG('j','k','m',' '),    HB_TAG('K','R','N',' ')},       /* Mobwa Karen -> Karen */
+  {HB_TAG('j','k','p',' '),    HB_TAG('K','R','N',' ')},       /* Paku Karen -> Karen */
+  {HB_TAG('j','u','d',' '),    HB_TAG_NONE            },       /* Worodougou != Ladino */
+  {HB_TAG('j','u','l',' '),    HB_TAG_NONE            },       /* Jirel != Jula */
+  {HB_TAG('j','v','d',' '),    HB_TAG('C','P','P',' ')},       /* Javindo -> Creoles */
+  {HB_TAG('k','a','a',' '),    HB_TAG('K','R','K',' ')},       /* Karakalpak */
+  {HB_TAG('k','a','b',' '),    HB_TAG('K','A','B','0')},       /* Kabyle */
+  {HB_TAG('k','a','b',' '),    HB_TAG('B','B','R',' ')},       /* Kabyle -> Berber */
+  {HB_TAG('k','a','c',' '),    HB_TAG_NONE            },       /* Kachin != Kachchi */
+  {HB_TAG('k','a','m',' '),    HB_TAG('K','M','B',' ')},       /* Kamba (Kenya) */
+  {HB_TAG('k','a','r',' '),    HB_TAG('K','R','N',' ')},       /* Karen [collection] */
+/*{HB_TAG('k','a','w',' '),    HB_TAG('K','A','W',' ')},*/     /* Kawi (Old Javanese) */
+  {HB_TAG('k','b','d',' '),    HB_TAG('K','A','B',' ')},       /* Kabardian */
+  {HB_TAG('k','b','y',' '),    HB_TAG('K','N','R',' ')},       /* Manga Kanuri -> Kanuri */
+  {HB_TAG('k','c','a',' '),    HB_TAG('K','H','K',' ')},       /* Khanty -> Khanty-Kazim */
+  {HB_TAG('k','c','a',' '),    HB_TAG('K','H','S',' ')},       /* Khanty -> Khanty-Shurishkar */
+  {HB_TAG('k','c','a',' '),    HB_TAG('K','H','V',' ')},       /* Khanty -> Khanty-Vakhi */
+  {HB_TAG('k','c','n',' '),    HB_TAG('C','P','P',' ')},       /* Nubi -> Creoles */
+/*{HB_TAG('k','d','e',' '),    HB_TAG('K','D','E',' ')},*/     /* Makonde */
+  {HB_TAG('k','d','r',' '),    HB_TAG('K','R','M',' ')},       /* Karaim */
+  {HB_TAG('k','d','t',' '),    HB_TAG('K','U','Y',' ')},       /* Kuy */
+  {HB_TAG('k','e','a',' '),    HB_TAG('K','E','A',' ')},       /* Kabuverdianu (Crioulo) */
+  {HB_TAG('k','e','a',' '),    HB_TAG('C','P','P',' ')},       /* Kabuverdianu -> Creoles */
+  {HB_TAG('k','e','b',' '),    HB_TAG_NONE            },       /* Kélé != Kebena */
+  {HB_TAG('k','e','k',' '),    HB_TAG('K','E','K',' ')},       /* Kekchi */
+  {HB_TAG('k','e','k',' '),    HB_TAG('M','Y','N',' ')},       /* Kekchí -> Mayan */
+  {HB_TAG('k','e','x',' '),    HB_TAG('K','K','N',' ')},       /* Kukna -> Kokni */
+  {HB_TAG('k','f','a',' '),    HB_TAG('K','O','D',' ')},       /* Kodava -> Kodagu */
+  {HB_TAG('k','f','r',' '),    HB_TAG('K','A','C',' ')},       /* Kachhi -> Kachchi */
+  {HB_TAG('k','f','x',' '),    HB_TAG('K','U','L',' ')},       /* Kullu Pahari -> Kulvi */
+  {HB_TAG('k','f','y',' '),    HB_TAG('K','M','N',' ')},       /* Kumaoni */
+  {HB_TAG('k','g','e',' '),    HB_TAG_NONE            },       /* Komering != Khutsuri Georgian */
+  {HB_TAG('k','h','a',' '),    HB_TAG('K','S','I',' ')},       /* Khasi */
+  {HB_TAG('k','h','b',' '),    HB_TAG('X','B','D',' ')},       /* Lü */
+  {HB_TAG('k','h','k',' '),    HB_TAG('M','N','G',' ')},       /* Halh Mongolian -> Mongolian */
+  {HB_TAG('k','h','n',' '),    HB_TAG_NONE            },       /* Khandesi != Khamti Shan (Microsoft fonts) */
+  {HB_TAG('k','h','s',' '),    HB_TAG_NONE            },       /* Kasua != Khanty-Shurishkar */
+  {HB_TAG('k','h','t',' '),    HB_TAG('K','H','T',' ')},       /* Khamti -> Khamti Shan */
+  {HB_TAG('k','h','t',' '),    HB_TAG('K','H','N',' ')},       /* Khamti -> Khamti Shan (Microsoft fonts) */
+  {HB_TAG('k','h','v',' '),    HB_TAG_NONE            },       /* Khvarshi != Khanty-Vakhi */
+/*{HB_TAG('k','h','w',' '),    HB_TAG('K','H','W',' ')},*/     /* Khowar */
+  {HB_TAG('k','i','s',' '),    HB_TAG_NONE            },       /* Kis != Kisii */
+  {HB_TAG('k','i','u',' '),    HB_TAG('K','I','U',' ')},       /* Kirmanjki */
+  {HB_TAG('k','i','u',' '),    HB_TAG('Z','Z','A',' ')},       /* Kirmanjki -> Zazaki */
+  {HB_TAG('k','j','b',' '),    HB_TAG('M','Y','N',' ')},       /* Q'anjob'al -> Mayan */
+/*{HB_TAG('k','j','d',' '),    HB_TAG('K','J','D',' ')},*/     /* Southern Kiwai */
+  {HB_TAG('k','j','h',' '),    HB_TAG('K','H','A',' ')},       /* Khakas -> Khakass */
+  {HB_TAG('k','j','p',' '),    HB_TAG('K','J','P',' ')},       /* Pwo Eastern Karen -> Eastern Pwo Karen */
+  {HB_TAG('k','j','p',' '),    HB_TAG('K','R','N',' ')},       /* Pwo Eastern Karen -> Karen */
+  {HB_TAG('k','j','t',' '),    HB_TAG('K','R','N',' ')},       /* Phrae Pwo Karen -> Karen */
+/*{HB_TAG('k','j','z',' '),    HB_TAG('K','J','Z',' ')},*/     /* Bumthangkha */
+  {HB_TAG('k','k','n',' '),    HB_TAG_NONE            },       /* Kon Keu != Kokni */
+  {HB_TAG('k','k','z',' '),    HB_TAG('A','T','H',' ')},       /* Kaska -> Athapaskan */
+  {HB_TAG('k','l','m',' '),    HB_TAG_NONE            },       /* Migum != Kalmyk */
+  {HB_TAG('k','l','n',' '),    HB_TAG('K','A','L',' ')},       /* Kalenjin [macrolanguage] */
+  {HB_TAG('k','m','b',' '),    HB_TAG('M','B','N',' ')},       /* Kimbundu -> Mbundu */
+  {HB_TAG('k','m','n',' '),    HB_TAG_NONE            },       /* Awtuw != Kumaoni */
+  {HB_TAG('k','m','o',' '),    HB_TAG_NONE            },       /* Kwoma != Komo */
+  {HB_TAG('k','m','r',' '),    HB_TAG('K','U','R',' ')},       /* Northern Kurdish -> Kurdish */
+  {HB_TAG('k','m','s',' '),    HB_TAG_NONE            },       /* Kamasau != Komso */
+  {HB_TAG('k','m','v',' '),    HB_TAG('C','P','P',' ')},       /* Karipúna Creole French -> Creoles */
+  {HB_TAG('k','m','w',' '),    HB_TAG('K','M','O',' ')},       /* Komo (Democratic Republic of Congo) */
+/*{HB_TAG('k','m','z',' '),    HB_TAG('K','M','Z',' ')},*/     /* Khorasani Turkish -> Khorasani Turkic */
+  {HB_TAG('k','n','c',' '),    HB_TAG('K','N','R',' ')},       /* Central Kanuri -> Kanuri */
+  {HB_TAG('k','n','g',' '),    HB_TAG('K','O','N','0')},       /* Koongo -> Kongo */
+  {HB_TAG('k','n','j',' '),    HB_TAG('M','Y','N',' ')},       /* Western Kanjobal -> Mayan */
+  {HB_TAG('k','n','n',' '),    HB_TAG('K','O','K',' ')},       /* Konkani */
+  {HB_TAG('k','n','r',' '),    HB_TAG_NONE            },       /* Kaningra != Kanuri */
+  {HB_TAG('k','o','d',' '),    HB_TAG_NONE            },       /* Kodi != Kodagu */
+  {HB_TAG('k','o','h',' '),    HB_TAG_NONE            },       /* Koyo != Korean Old Hangul */
+  {HB_TAG('k','o','i',' '),    HB_TAG('K','O','P',' ')},       /* Komi-Permyak */
+  {HB_TAG('k','o','i',' '),    HB_TAG('K','O','M',' ')},       /* Komi-Permyak -> Komi */
+/*{HB_TAG('k','o','k',' '),    HB_TAG('K','O','K',' ')},*/     /* Konkani [macrolanguage] */
+  {HB_TAG('k','o','p',' '),    HB_TAG_NONE            },       /* Waube != Komi-Permyak */
+/*{HB_TAG('k','o','s',' '),    HB_TAG('K','O','S',' ')},*/     /* Kosraean */
+  {HB_TAG('k','o','y',' '),    HB_TAG('A','T','H',' ')},       /* Koyukon -> Athapaskan */
+  {HB_TAG('k','o','z',' '),    HB_TAG_NONE            },       /* Korak != Komi-Zyrian */
+  {HB_TAG('k','p','e',' '),    HB_TAG('K','P','L',' ')},       /* Kpelle [macrolanguage] */
+  {HB_TAG('k','p','l',' '),    HB_TAG_NONE            },       /* Kpala != Kpelle */
+  {HB_TAG('k','p','p',' '),    HB_TAG('K','R','N',' ')},       /* Paku Karen (retired code) -> Karen */
+  {HB_TAG('k','p','v',' '),    HB_TAG('K','O','Z',' ')},       /* Komi-Zyrian */
+  {HB_TAG('k','p','v',' '),    HB_TAG('K','O','M',' ')},       /* Komi-Zyrian -> Komi */
+  {HB_TAG('k','p','y',' '),    HB_TAG('K','Y','K',' ')},       /* Koryak */
+  {HB_TAG('k','q','s',' '),    HB_TAG('K','I','S',' ')},       /* Northern Kissi -> Kisii */
+  {HB_TAG('k','q','y',' '),    HB_TAG('K','R','T',' ')},       /* Koorete */
+  {HB_TAG('k','r','c',' '),    HB_TAG('K','A','R',' ')},       /* Karachay-Balkar -> Karachay */
+  {HB_TAG('k','r','c',' '),    HB_TAG('B','A','L',' ')},       /* Karachay-Balkar -> Balkar */
+  {HB_TAG('k','r','i',' '),    HB_TAG('K','R','I',' ')},       /* Krio */
+  {HB_TAG('k','r','i',' '),    HB_TAG('C','P','P',' ')},       /* Krio -> Creoles */
+  {HB_TAG('k','r','k',' '),    HB_TAG_NONE            },       /* Kerek != Karakalpak */
+/*{HB_TAG('k','r','l',' '),    HB_TAG('K','R','L',' ')},*/     /* Karelian */
+  {HB_TAG('k','r','m',' '),    HB_TAG_NONE            },       /* Krim (retired code) != Karaim */
+  {HB_TAG('k','r','n',' '),    HB_TAG_NONE            },       /* Sapo != Karen */
+  {HB_TAG('k','r','t',' '),    HB_TAG('K','N','R',' ')},       /* Tumari Kanuri -> Kanuri */
+  {HB_TAG('k','r','u',' '),    HB_TAG('K','U','U',' ')},       /* Kurukh */
+  {HB_TAG('k','s','h',' '),    HB_TAG('K','S','H','0')},       /* Kölsch -> Ripuarian */
+  {HB_TAG('k','s','i',' '),    HB_TAG_NONE            },       /* Krisa != Khasi */
+  {HB_TAG('k','s','m',' '),    HB_TAG_NONE            },       /* Kumba != Kildin Sami */
+  {HB_TAG('k','s','s',' '),    HB_TAG('K','I','S',' ')},       /* Southern Kisi -> Kisii */
+  {HB_TAG('k','s','w',' '),    HB_TAG('K','S','W',' ')},       /* S’gaw Karen */
+  {HB_TAG('k','s','w',' '),    HB_TAG('K','R','N',' ')},       /* S'gaw Karen -> Karen */
+  {HB_TAG('k','t','b',' '),    HB_TAG('K','E','B',' ')},       /* Kambaata -> Kebena */
+  {HB_TAG('k','t','u',' '),    HB_TAG('K','O','N',' ')},       /* Kituba (Democratic Republic of Congo) -> Kikongo */
+  {HB_TAG('k','t','w',' '),    HB_TAG('A','T','H',' ')},       /* Kato -> Athapaskan */
+  {HB_TAG('k','u','i',' '),    HB_TAG_NONE            },       /* Kuikúro-Kalapálo != Kui */
+  {HB_TAG('k','u','l',' '),    HB_TAG_NONE            },       /* Kulere != Kulvi */
+/*{HB_TAG('k','u','m',' '),    HB_TAG('K','U','M',' ')},*/     /* Kumyk */
+  {HB_TAG('k','u','u',' '),    HB_TAG('A','T','H',' ')},       /* Upper Kuskokwim -> Athapaskan */
+  {HB_TAG('k','u','w',' '),    HB_TAG('B','A','D','0')},       /* Kpagua -> Banda */
+  {HB_TAG('k','u','y',' '),    HB_TAG_NONE            },       /* Kuuku-Ya'u != Kuy */
+  {HB_TAG('k','v','b',' '),    HB_TAG('M','L','Y',' ')},       /* Kubu -> Malay */
+  {HB_TAG('k','v','l',' '),    HB_TAG('K','R','N',' ')},       /* Kayaw -> Karen */
+  {HB_TAG('k','v','q',' '),    HB_TAG('K','R','N',' ')},       /* Geba Karen -> Karen */
+  {HB_TAG('k','v','r',' '),    HB_TAG('M','L','Y',' ')},       /* Kerinci -> Malay */
+  {HB_TAG('k','v','t',' '),    HB_TAG('K','R','N',' ')},       /* Lahta Karen -> Karen */
+  {HB_TAG('k','v','u',' '),    HB_TAG('K','R','N',' ')},       /* Yinbaw Karen -> Karen */
+  {HB_TAG('k','v','y',' '),    HB_TAG('K','R','N',' ')},       /* Yintale Karen -> Karen */
+/*{HB_TAG('k','w','k',' '),    HB_TAG('K','W','K',' ')},*/     /* Kwakiutl -> Kwakʼwala */
+  {HB_TAG('k','w','w',' '),    HB_TAG('C','P','P',' ')},       /* Kwinti -> Creoles */
+  {HB_TAG('k','w','y',' '),    HB_TAG('K','O','N','0')},       /* San Salvador Kongo -> Kongo */
+  {HB_TAG('k','x','c',' '),    HB_TAG('K','M','S',' ')},       /* Konso -> Komso */
+  {HB_TAG('k','x','d',' '),    HB_TAG('M','L','Y',' ')},       /* Brunei -> Malay */
+  {HB_TAG('k','x','f',' '),    HB_TAG('K','R','N',' ')},       /* Manumanaw Karen -> Karen */
+  {HB_TAG('k','x','k',' '),    HB_TAG('K','R','N',' ')},       /* Zayein Karen -> Karen */
+  {HB_TAG('k','x','l',' '),    HB_TAG('K','U','U',' ')},       /* Nepali Kurux (retired code) -> Kurukh */
+  {HB_TAG('k','x','u',' '),    HB_TAG('K','U','I',' ')},       /* Kui (India) (retired code) */
+  {HB_TAG('k','y','k',' '),    HB_TAG_NONE            },       /* Kamayo != Koryak */
+  {HB_TAG('k','y','u',' '),    HB_TAG('K','Y','U',' ')},       /* Western Kayah */
+  {HB_TAG('k','y','u',' '),    HB_TAG('K','R','N',' ')},       /* Western Kayah -> Karen */
+  {HB_TAG('l','a','c',' '),    HB_TAG('M','Y','N',' ')},       /* Lacandon -> Mayan */
+  {HB_TAG('l','a','d',' '),    HB_TAG('J','U','D',' ')},       /* Ladino */
+  {HB_TAG('l','a','h',' '),    HB_TAG_NONE            },       /* Lahnda [macrolanguage] != Lahuli */
+  {HB_TAG('l','a','k',' '),    HB_TAG_NONE            },       /* Laka (Nigeria) (retired code) != Lak */
+  {HB_TAG('l','a','m',' '),    HB_TAG_NONE            },       /* Lamba != Lambani */
+  {HB_TAG('l','a','z',' '),    HB_TAG_NONE            },       /* Aribwatsa != Laz */
+  {HB_TAG('l','b','e',' '),    HB_TAG('L','A','K',' ')},       /* Lak */
+  {HB_TAG('l','b','j',' '),    HB_TAG('L','D','K',' ')},       /* Ladakhi */
+  {HB_TAG('l','b','l',' '),    HB_TAG('B','I','K',' ')},       /* Libon Bikol -> Bikol */
+  {HB_TAG('l','c','e',' '),    HB_TAG('M','L','Y',' ')},       /* Loncong -> Malay */
+  {HB_TAG('l','c','f',' '),    HB_TAG('M','L','Y',' ')},       /* Lubu -> Malay */
+  {HB_TAG('l','d','i',' '),    HB_TAG('K','O','N','0')},       /* Laari -> Kongo */
+  {HB_TAG('l','d','k',' '),    HB_TAG_NONE            },       /* Leelau != Ladakhi */
+/*{HB_TAG('l','e','f',' '),    HB_TAG('L','E','F',' ')},*/     /* Lelemi */
+/*{HB_TAG('l','e','z',' '),    HB_TAG('L','E','Z',' ')},*/     /* Lezghian -> Lezgi */
+  {HB_TAG('l','i','f',' '),    HB_TAG('L','M','B',' ')},       /* Limbu */
+/*{HB_TAG('l','i','j',' '),    HB_TAG('L','I','J',' ')},*/     /* Ligurian */
+  {HB_TAG('l','i','r',' '),    HB_TAG('C','P','P',' ')},       /* Liberian English -> Creoles */
+/*{HB_TAG('l','i','s',' '),    HB_TAG('L','I','S',' ')},*/     /* Lisu */
+  {HB_TAG('l','i','w',' '),    HB_TAG('M','L','Y',' ')},       /* Col -> Malay */
+  {HB_TAG('l','i','y',' '),    HB_TAG('B','A','D','0')},       /* Banda-Bambari -> Banda */
+/*{HB_TAG('l','j','p',' '),    HB_TAG('L','J','P',' ')},*/     /* Lampung Api -> Lampung */
+  {HB_TAG('l','k','b',' '),    HB_TAG('L','U','H',' ')},       /* Kabras -> Luyia */
+/*{HB_TAG('l','k','i',' '),    HB_TAG('L','K','I',' ')},*/     /* Laki */
+  {HB_TAG('l','k','o',' '),    HB_TAG('L','U','H',' ')},       /* Khayo -> Luyia */
+  {HB_TAG('l','k','s',' '),    HB_TAG('L','U','H',' ')},       /* Kisa -> Luyia */
+  {HB_TAG('l','l','d',' '),    HB_TAG('L','A','D',' ')},       /* Ladin */
+  {HB_TAG('l','m','a',' '),    HB_TAG_NONE            },       /* East Limba != Low Mari */
+  {HB_TAG('l','m','b',' '),    HB_TAG_NONE            },       /* Merei != Limbu */
+  {HB_TAG('l','m','n',' '),    HB_TAG('L','A','M',' ')},       /* Lambadi -> Lambani */
+/*{HB_TAG('l','m','o',' '),    HB_TAG('L','M','O',' ')},*/     /* Lombard */
+  {HB_TAG('l','m','w',' '),    HB_TAG_NONE            },       /* Lake Miwok != Lomwe */
+  {HB_TAG('l','n','a',' '),    HB_TAG('B','A','D','0')},       /* Langbashe -> Banda */
+  {HB_TAG('l','n','l',' '),    HB_TAG('B','A','D','0')},       /* South Central Banda -> Banda */
+/*{HB_TAG('l','o','m',' '),    HB_TAG('L','O','M',' ')},*/     /* Loma (Liberia) */
+  {HB_TAG('l','o','u',' '),    HB_TAG('C','P','P',' ')},       /* Louisiana Creole -> Creoles */
+/*{HB_TAG('l','p','o',' '),    HB_TAG('L','P','O',' ')},*/     /* Lipo */
+/*{HB_TAG('l','r','c',' '),    HB_TAG('L','R','C',' ')},*/     /* Northern Luri -> Luri */
+  {HB_TAG('l','r','i',' '),    HB_TAG('L','U','H',' ')},       /* Marachi -> Luyia */
+  {HB_TAG('l','r','m',' '),    HB_TAG('L','U','H',' ')},       /* Marama -> Luyia */
+  {HB_TAG('l','r','t',' '),    HB_TAG('C','P','P',' ')},       /* Larantuka Malay -> Creoles */
+  {HB_TAG('l','s','b',' '),    HB_TAG_NONE            },       /* Burundian Sign Language != Lower Sorbian */
+  {HB_TAG('l','s','m',' '),    HB_TAG('L','U','H',' ')},       /* Saamia -> Luyia */
+  {HB_TAG('l','t','g',' '),    HB_TAG('L','V','I',' ')},       /* Latgalian -> Latvian */
+  {HB_TAG('l','t','h',' '),    HB_TAG_NONE            },       /* Thur != Lithuanian */
+  {HB_TAG('l','t','o',' '),    HB_TAG('L','U','H',' ')},       /* Tsotso -> Luyia */
+  {HB_TAG('l','t','s',' '),    HB_TAG('L','U','H',' ')},       /* Tachoni -> Luyia */
+/*{HB_TAG('l','u','a',' '),    HB_TAG('L','U','A',' ')},*/     /* Luba-Lulua */
+/*{HB_TAG('l','u','o',' '),    HB_TAG('L','U','O',' ')},*/     /* Luo (Kenya and Tanzania) */
+  {HB_TAG('l','u','s',' '),    HB_TAG('M','I','Z',' ')},       /* Lushai -> Mizo */
+  {HB_TAG('l','u','s',' '),    HB_TAG('Q','I','N',' ')},       /* Lushai -> Chin */
+  {HB_TAG('l','u','y',' '),    HB_TAG('L','U','H',' ')},       /* Luyia [macrolanguage] */
+  {HB_TAG('l','u','z',' '),    HB_TAG('L','R','C',' ')},       /* Southern Luri -> Luri */
+  {HB_TAG('l','v','i',' '),    HB_TAG_NONE            },       /* Lavi != Latvian */
+  {HB_TAG('l','v','s',' '),    HB_TAG('L','V','I',' ')},       /* Standard Latvian -> Latvian */
+  {HB_TAG('l','w','g',' '),    HB_TAG('L','U','H',' ')},       /* Wanga -> Luyia */
+  {HB_TAG('l','z','h',' '),    HB_TAG('Z','H','T',' ')},       /* Literary Chinese -> Chinese, Traditional */
+  {HB_TAG('l','z','z',' '),    HB_TAG('L','A','Z',' ')},       /* Laz */
+/*{HB_TAG('m','a','d',' '),    HB_TAG('M','A','D',' ')},*/     /* Madurese -> Madura */
+/*{HB_TAG('m','a','g',' '),    HB_TAG('M','A','G',' ')},*/     /* Magahi */
+  {HB_TAG('m','a','i',' '),    HB_TAG('M','T','H',' ')},       /* Maithili */
+  {HB_TAG('m','a','j',' '),    HB_TAG_NONE            },       /* Jalapa De Díaz Mazatec != Majang */
+  {HB_TAG('m','a','k',' '),    HB_TAG('M','K','R',' ')},       /* Makasar */
+  {HB_TAG('m','a','m',' '),    HB_TAG('M','A','M',' ')},       /* Mam */
+  {HB_TAG('m','a','m',' '),    HB_TAG('M','Y','N',' ')},       /* Mam -> Mayan */
+  {HB_TAG('m','a','n',' '),    HB_TAG('M','N','K',' ')},       /* Mandingo [macrolanguage] -> Maninka */
+  {HB_TAG('m','a','p',' '),    HB_TAG_NONE            },       /* Austronesian [collection] != Mapudungun */
+  {HB_TAG('m','a','w',' '),    HB_TAG_NONE            },       /* Mampruli != Marwari */
+  {HB_TAG('m','a','x',' '),    HB_TAG('M','L','Y',' ')},       /* North Moluccan Malay -> Malay */
+  {HB_TAG('m','a','x',' '),    HB_TAG('C','P','P',' ')},       /* North Moluccan Malay -> Creoles */
+  {HB_TAG('m','b','f',' '),    HB_TAG('C','P','P',' ')},       /* Baba Malay -> Creoles */
+  {HB_TAG('m','b','n',' '),    HB_TAG_NONE            },       /* Macaguán != Mbundu */
+/*{HB_TAG('m','b','o',' '),    HB_TAG('M','B','O',' ')},*/     /* Mbo (Cameroon) */
+  {HB_TAG('m','c','h',' '),    HB_TAG_NONE            },       /* Maquiritari != Manchu */
+  {HB_TAG('m','c','m',' '),    HB_TAG('C','P','P',' ')},       /* Malaccan Creole Portuguese -> Creoles */
+  {HB_TAG('m','c','r',' '),    HB_TAG_NONE            },       /* Menya != Moose Cree */
+  {HB_TAG('m','c','t',' '),    HB_TAG('B','T','I',' ')},       /* Mengisa -> Beti */
+  {HB_TAG('m','d','e',' '),    HB_TAG_NONE            },       /* Maba (Chad) != Mende */
+  {HB_TAG('m','d','f',' '),    HB_TAG('M','O','K',' ')},       /* Moksha */
+/*{HB_TAG('m','d','r',' '),    HB_TAG('M','D','R',' ')},*/     /* Mandar */
+  {HB_TAG('m','d','y',' '),    HB_TAG('M','L','E',' ')},       /* Male (Ethiopia) */
+  {HB_TAG('m','e','n',' '),    HB_TAG('M','D','E',' ')},       /* Mende (Sierra Leone) */
+  {HB_TAG('m','e','o',' '),    HB_TAG('M','L','Y',' ')},       /* Kedah Malay -> Malay */
+/*{HB_TAG('m','e','r',' '),    HB_TAG('M','E','R',' ')},*/     /* Meru */
+  {HB_TAG('m','f','a',' '),    HB_TAG('M','F','A',' ')},       /* Pattani Malay */
+  {HB_TAG('m','f','a',' '),    HB_TAG('M','L','Y',' ')},       /* Pattani Malay -> Malay */
+  {HB_TAG('m','f','b',' '),    HB_TAG('M','L','Y',' ')},       /* Bangka -> Malay */
+  {HB_TAG('m','f','e',' '),    HB_TAG('M','F','E',' ')},       /* Morisyen */
+  {HB_TAG('m','f','e',' '),    HB_TAG('C','P','P',' ')},       /* Morisyen -> Creoles */
+  {HB_TAG('m','f','p',' '),    HB_TAG('C','P','P',' ')},       /* Makassar Malay -> Creoles */
+  {HB_TAG('m','h','c',' '),    HB_TAG('M','Y','N',' ')},       /* Mocho -> Mayan */
+  {HB_TAG('m','h','r',' '),    HB_TAG('L','M','A',' ')},       /* Eastern Mari -> Low Mari */
+  {HB_TAG('m','h','v',' '),    HB_TAG('A','R','K',' ')},       /* Arakanese (retired code) -> Rakhine */
+  {HB_TAG('m','i','n',' '),    HB_TAG('M','I','N',' ')},       /* Minangkabau */
+  {HB_TAG('m','i','n',' '),    HB_TAG('M','L','Y',' ')},       /* Minangkabau -> Malay */
+  {HB_TAG('m','i','z',' '),    HB_TAG_NONE            },       /* Coatzospan Mixtec != Mizo */
+  {HB_TAG('m','k','n',' '),    HB_TAG('C','P','P',' ')},       /* Kupang Malay -> Creoles */
+  {HB_TAG('m','k','r',' '),    HB_TAG_NONE            },       /* Malas != Makasar */
+  {HB_TAG('m','k','u',' '),    HB_TAG('M','N','K',' ')},       /* Konyanka Maninka -> Maninka */
+/*{HB_TAG('m','k','w',' '),    HB_TAG('M','K','W',' ')},*/     /* Kituba (Congo) */
+  {HB_TAG('m','l','e',' '),    HB_TAG_NONE            },       /* Manambu != Male */
+  {HB_TAG('m','l','n',' '),    HB_TAG_NONE            },       /* Malango != Malinke */
+  {HB_TAG('m','l','q',' '),    HB_TAG('M','L','N',' ')},       /* Western Maninkakan -> Malinke */
+  {HB_TAG('m','l','q',' '),    HB_TAG('M','N','K',' ')},       /* Western Maninkakan -> Maninka */
+  {HB_TAG('m','l','r',' '),    HB_TAG_NONE            },       /* Vame != Malayalam Reformed */
+  {HB_TAG('m','m','r',' '),    HB_TAG('H','M','N',' ')},       /* Western Xiangxi Miao -> Hmong */
+  {HB_TAG('m','n','c',' '),    HB_TAG('M','C','H',' ')},       /* Manchu */
+  {HB_TAG('m','n','d',' '),    HB_TAG_NONE            },       /* Mondé != Mandinka */
+  {HB_TAG('m','n','g',' '),    HB_TAG_NONE            },       /* Eastern Mnong != Mongolian */
+  {HB_TAG('m','n','h',' '),    HB_TAG('B','A','D','0')},       /* Mono (Democratic Republic of Congo) -> Banda */
+/*{HB_TAG('m','n','i',' '),    HB_TAG('M','N','I',' ')},*/     /* Manipuri */
+  {HB_TAG('m','n','k',' '),    HB_TAG('M','N','D',' ')},       /* Mandinka */
+  {HB_TAG('m','n','k',' '),    HB_TAG('M','N','K',' ')},       /* Mandinka -> Maninka */
+  {HB_TAG('m','n','p',' '),    HB_TAG('Z','H','S',' ')},       /* Min Bei Chinese -> Chinese, Simplified */
+  {HB_TAG('m','n','s',' '),    HB_TAG('M','A','N',' ')},       /* Mansi */
+  {HB_TAG('m','n','w',' '),    HB_TAG('M','O','N',' ')},       /* Mon */
+  {HB_TAG('m','n','w',' '),    HB_TAG('M','O','N','T')},       /* Mon -> Thailand Mon */
+  {HB_TAG('m','n','x',' '),    HB_TAG_NONE            },       /* Manikion != Manx */
+  {HB_TAG('m','o','d',' '),    HB_TAG('C','P','P',' ')},       /* Mobilian -> Creoles */
+/*{HB_TAG('m','o','h',' '),    HB_TAG('M','O','H',' ')},*/     /* Mohawk */
+  {HB_TAG('m','o','k',' '),    HB_TAG_NONE            },       /* Morori != Moksha */
+  {HB_TAG('m','o','p',' '),    HB_TAG('M','Y','N',' ')},       /* Mopán Maya -> Mayan */
+  {HB_TAG('m','o','r',' '),    HB_TAG_NONE            },       /* Moro != Moroccan */
+/*{HB_TAG('m','o','s',' '),    HB_TAG('M','O','S',' ')},*/     /* Mossi */
+  {HB_TAG('m','p','e',' '),    HB_TAG('M','A','J',' ')},       /* Majang */
+  {HB_TAG('m','q','g',' '),    HB_TAG('M','L','Y',' ')},       /* Kota Bangun Kutai Malay -> Malay */
+  {HB_TAG('m','r','h',' '),    HB_TAG('Q','I','N',' ')},       /* Mara Chin -> Chin */
+  {HB_TAG('m','r','j',' '),    HB_TAG('H','M','A',' ')},       /* Western Mari -> High Mari */
+  {HB_TAG('m','s','c',' '),    HB_TAG('M','N','K',' ')},       /* Sankaran Maninka -> Maninka */
+  {HB_TAG('m','s','h',' '),    HB_TAG('M','L','G',' ')},       /* Masikoro Malagasy -> Malagasy */
+  {HB_TAG('m','s','i',' '),    HB_TAG('M','L','Y',' ')},       /* Sabah Malay -> Malay */
+  {HB_TAG('m','s','i',' '),    HB_TAG('C','P','P',' ')},       /* Sabah Malay -> Creoles */
+  {HB_TAG('m','t','h',' '),    HB_TAG_NONE            },       /* Munggui != Maithili */
+  {HB_TAG('m','t','r',' '),    HB_TAG('M','A','W',' ')},       /* Mewari -> Marwari */
+  {HB_TAG('m','t','s',' '),    HB_TAG_NONE            },       /* Yora != Maltese */
+  {HB_TAG('m','u','d',' '),    HB_TAG('C','P','P',' ')},       /* Mednyj Aleut -> Creoles */
+  {HB_TAG('m','u','i',' '),    HB_TAG('M','L','Y',' ')},       /* Musi -> Malay */
+  {HB_TAG('m','u','n',' '),    HB_TAG_NONE            },       /* Munda [collection] != Mundari */
+  {HB_TAG('m','u','p',' '),    HB_TAG('R','A','J',' ')},       /* Malvi -> Rajasthani */
+  {HB_TAG('m','u','q',' '),    HB_TAG('H','M','N',' ')},       /* Eastern Xiangxi Miao -> Hmong */
+/*{HB_TAG('m','u','s',' '),    HB_TAG('M','U','S',' ')},*/     /* Creek -> Muscogee */
+  {HB_TAG('m','v','b',' '),    HB_TAG('A','T','H',' ')},       /* Mattole -> Athapaskan */
+  {HB_TAG('m','v','e',' '),    HB_TAG('M','A','W',' ')},       /* Marwari (Pakistan) */
+  {HB_TAG('m','v','f',' '),    HB_TAG('M','N','G',' ')},       /* Peripheral Mongolian -> Mongolian */
+  {HB_TAG('m','w','k',' '),    HB_TAG('M','N','K',' ')},       /* Kita Maninkakan -> Maninka */
+/*{HB_TAG('m','w','l',' '),    HB_TAG('M','W','L',' ')},*/     /* Mirandese */
+  {HB_TAG('m','w','q',' '),    HB_TAG('Q','I','N',' ')},       /* Mün Chin -> Chin */
+  {HB_TAG('m','w','r',' '),    HB_TAG('M','A','W',' ')},       /* Marwari [macrolanguage] */
+  {HB_TAG('m','w','w',' '),    HB_TAG('M','W','W',' ')},       /* Hmong Daw */
+  {HB_TAG('m','w','w',' '),    HB_TAG('H','M','N',' ')},       /* Hmong Daw -> Hmong */
+  {HB_TAG('m','y','m',' '),    HB_TAG('M','E','N',' ')},       /* Me’en */
+/*{HB_TAG('m','y','n',' '),    HB_TAG('M','Y','N',' ')},*/     /* Mayan [collection] */
+  {HB_TAG('m','y','q',' '),    HB_TAG('M','N','K',' ')},       /* Forest Maninka (retired code) -> Maninka */
+  {HB_TAG('m','y','v',' '),    HB_TAG('E','R','Z',' ')},       /* Erzya */
+  {HB_TAG('m','z','b',' '),    HB_TAG('B','B','R',' ')},       /* Tumzabt -> Berber */
+/*{HB_TAG('m','z','n',' '),    HB_TAG('M','Z','N',' ')},*/     /* Mazanderani */
+  {HB_TAG('m','z','s',' '),    HB_TAG('C','P','P',' ')},       /* Macanese -> Creoles */
+  {HB_TAG('n','a','g',' '),    HB_TAG('N','A','G',' ')},       /* Naga Pidgin -> Naga-Assamese */
+  {HB_TAG('n','a','g',' '),    HB_TAG('C','P','P',' ')},       /* Naga Pidgin -> Creoles */
+/*{HB_TAG('n','a','h',' '),    HB_TAG('N','A','H',' ')},*/     /* Nahuatl [collection] */
+  {HB_TAG('n','a','n',' '),    HB_TAG('Z','H','S',' ')},       /* Min Nan Chinese -> Chinese, Simplified */
+/*{HB_TAG('n','a','p',' '),    HB_TAG('N','A','P',' ')},*/     /* Neapolitan */
+  {HB_TAG('n','a','s',' '),    HB_TAG_NONE            },       /* Naasioi != Naskapi */
+  {HB_TAG('n','a','z',' '),    HB_TAG('N','A','H',' ')},       /* Coatepec Nahuatl -> Nahuatl */
+  {HB_TAG('n','c','h',' '),    HB_TAG('N','A','H',' ')},       /* Central Huasteca Nahuatl -> Nahuatl */
+  {HB_TAG('n','c','i',' '),    HB_TAG('N','A','H',' ')},       /* Classical Nahuatl -> Nahuatl */
+  {HB_TAG('n','c','j',' '),    HB_TAG('N','A','H',' ')},       /* Northern Puebla Nahuatl -> Nahuatl */
+  {HB_TAG('n','c','l',' '),    HB_TAG('N','A','H',' ')},       /* Michoacán Nahuatl -> Nahuatl */
+  {HB_TAG('n','c','r',' '),    HB_TAG_NONE            },       /* Ncane != N-Cree */
+  {HB_TAG('n','c','x',' '),    HB_TAG('N','A','H',' ')},       /* Central Puebla Nahuatl -> Nahuatl */
+  {HB_TAG('n','d','b',' '),    HB_TAG_NONE            },       /* Kenswei Nsei != Ndebele */
+/*{HB_TAG('n','d','c',' '),    HB_TAG('N','D','C',' ')},*/     /* Ndau */
+  {HB_TAG('n','d','g',' '),    HB_TAG_NONE            },       /* Ndengereko != Ndonga */
+/*{HB_TAG('n','d','s',' '),    HB_TAG('N','D','S',' ')},*/     /* Low Saxon */
+  {HB_TAG('n','e','f',' '),    HB_TAG('C','P','P',' ')},       /* Nefamese -> Creoles */
+/*{HB_TAG('n','e','w',' '),    HB_TAG('N','E','W',' ')},*/     /* Newari */
+/*{HB_TAG('n','g','a',' '),    HB_TAG('N','G','A',' ')},*/     /* Ngbaka */
+  {HB_TAG('n','g','l',' '),    HB_TAG('L','M','W',' ')},       /* Lomwe */
+  {HB_TAG('n','g','m',' '),    HB_TAG('C','P','P',' ')},       /* Ngatik Men's Creole -> Creoles */
+  {HB_TAG('n','g','o',' '),    HB_TAG('S','X','T',' ')},       /* Ngoni (retired code) -> Sutu */
+  {HB_TAG('n','g','r',' '),    HB_TAG_NONE            },       /* Engdewu != Nagari */
+  {HB_TAG('n','g','u',' '),    HB_TAG('N','A','H',' ')},       /* Guerrero Nahuatl -> Nahuatl */
+  {HB_TAG('n','h','c',' '),    HB_TAG('N','A','H',' ')},       /* Tabasco Nahuatl -> Nahuatl */
+  {HB_TAG('n','h','d',' '),    HB_TAG('G','U','A',' ')},       /* Chiripá -> Guarani */
+  {HB_TAG('n','h','e',' '),    HB_TAG('N','A','H',' ')},       /* Eastern Huasteca Nahuatl -> Nahuatl */
+  {HB_TAG('n','h','g',' '),    HB_TAG('N','A','H',' ')},       /* Tetelcingo Nahuatl -> Nahuatl */
+  {HB_TAG('n','h','i',' '),    HB_TAG('N','A','H',' ')},       /* Zacatlán-Ahuacatlán-Tepetzintla Nahuatl -> Nahuatl */
+  {HB_TAG('n','h','k',' '),    HB_TAG('N','A','H',' ')},       /* Isthmus-Cosoleacaque Nahuatl -> Nahuatl */
+  {HB_TAG('n','h','m',' '),    HB_TAG('N','A','H',' ')},       /* Morelos Nahuatl -> Nahuatl */
+  {HB_TAG('n','h','n',' '),    HB_TAG('N','A','H',' ')},       /* Central Nahuatl -> Nahuatl */
+  {HB_TAG('n','h','p',' '),    HB_TAG('N','A','H',' ')},       /* Isthmus-Pajapan Nahuatl -> Nahuatl */
+  {HB_TAG('n','h','q',' '),    HB_TAG('N','A','H',' ')},       /* Huaxcaleca Nahuatl -> Nahuatl */
+  {HB_TAG('n','h','t',' '),    HB_TAG('N','A','H',' ')},       /* Ometepec Nahuatl -> Nahuatl */
+  {HB_TAG('n','h','v',' '),    HB_TAG('N','A','H',' ')},       /* Temascaltepec Nahuatl -> Nahuatl */
+  {HB_TAG('n','h','w',' '),    HB_TAG('N','A','H',' ')},       /* Western Huasteca Nahuatl -> Nahuatl */
+  {HB_TAG('n','h','x',' '),    HB_TAG('N','A','H',' ')},       /* Isthmus-Mecayapan Nahuatl -> Nahuatl */
+  {HB_TAG('n','h','y',' '),    HB_TAG('N','A','H',' ')},       /* Northern Oaxaca Nahuatl -> Nahuatl */
+  {HB_TAG('n','h','z',' '),    HB_TAG('N','A','H',' ')},       /* Santa María La Alta Nahuatl -> Nahuatl */
+  {HB_TAG('n','i','q',' '),    HB_TAG('K','A','L',' ')},       /* Nandi -> Kalenjin */
+  {HB_TAG('n','i','s',' '),    HB_TAG_NONE            },       /* Nimi != Nisi */
+/*{HB_TAG('n','i','u',' '),    HB_TAG('N','I','U',' ')},*/     /* Niuean */
+  {HB_TAG('n','i','v',' '),    HB_TAG('G','I','L',' ')},       /* Gilyak */
+  {HB_TAG('n','j','t',' '),    HB_TAG('C','P','P',' ')},       /* Ndyuka-Trio Pidgin -> Creoles */
+  {HB_TAG('n','j','z',' '),    HB_TAG('N','I','S',' ')},       /* Nyishi -> Nisi */
+  {HB_TAG('n','k','o',' '),    HB_TAG_NONE            },       /* Nkonya != N’Ko */
+  {HB_TAG('n','k','x',' '),    HB_TAG('I','J','O',' ')},       /* Nkoroo -> Ijo */
+  {HB_TAG('n','l','a',' '),    HB_TAG('B','M','L',' ')},       /* Ngombale -> Bamileke */
+  {HB_TAG('n','l','e',' '),    HB_TAG('L','U','H',' ')},       /* East Nyala -> Luyia */
+  {HB_TAG('n','l','n',' '),    HB_TAG('N','A','H',' ')},       /* Durango Nahuatl (retired code) -> Nahuatl */
+  {HB_TAG('n','l','v',' '),    HB_TAG('N','A','H',' ')},       /* Orizaba Nahuatl -> Nahuatl */
+  {HB_TAG('n','n','h',' '),    HB_TAG('B','M','L',' ')},       /* Ngiemboon -> Bamileke */
+  {HB_TAG('n','n','z',' '),    HB_TAG('B','M','L',' ')},       /* Nda'nda' -> Bamileke */
+  {HB_TAG('n','o','d',' '),    HB_TAG('N','T','A',' ')},       /* Northern Thai -> Northern Tai */
+/*{HB_TAG('n','o','e',' '),    HB_TAG('N','O','E',' ')},*/     /* Nimadi */
+/*{HB_TAG('n','o','g',' '),    HB_TAG('N','O','G',' ')},*/     /* Nogai */
+/*{HB_TAG('n','o','v',' '),    HB_TAG('N','O','V',' ')},*/     /* Novial */
+  {HB_TAG('n','p','i',' '),    HB_TAG('N','E','P',' ')},       /* Nepali */
+  {HB_TAG('n','p','l',' '),    HB_TAG('N','A','H',' ')},       /* Southeastern Puebla Nahuatl -> Nahuatl */
+  {HB_TAG('n','q','o',' '),    HB_TAG('N','K','O',' ')},       /* N’Ko */
+  {HB_TAG('n','s','k',' '),    HB_TAG('N','A','S',' ')},       /* Naskapi */
+  {HB_TAG('n','s','m',' '),    HB_TAG_NONE            },       /* Sumi Naga != Northern Sami */
+/*{HB_TAG('n','s','o',' '),    HB_TAG('N','S','O',' ')},*/     /* Northern Sotho */
+  {HB_TAG('n','s','u',' '),    HB_TAG('N','A','H',' ')},       /* Sierra Negra Nahuatl -> Nahuatl */
+  {HB_TAG('n','t','o',' '),    HB_TAG_NONE            },       /* Ntomba != Esperanto */
+  {HB_TAG('n','u','e',' '),    HB_TAG('B','A','D','0')},       /* Ngundu -> Banda */
+  {HB_TAG('n','u','u',' '),    HB_TAG('B','A','D','0')},       /* Ngbundu -> Banda */
+  {HB_TAG('n','u','z',' '),    HB_TAG('N','A','H',' ')},       /* Tlamacazapa Nahuatl -> Nahuatl */
+  {HB_TAG('n','w','e',' '),    HB_TAG('B','M','L',' ')},       /* Ngwe -> Bamileke */
+  {HB_TAG('n','y','d',' '),    HB_TAG('L','U','H',' ')},       /* Nyore -> Luyia */
+/*{HB_TAG('n','y','m',' '),    HB_TAG('N','Y','M',' ')},*/     /* Nyamwezi */
+  {HB_TAG('n','y','n',' '),    HB_TAG('N','K','L',' ')},       /* Nyankole */
+/*{HB_TAG('n','z','a',' '),    HB_TAG('N','Z','A',' ')},*/     /* Tigon Mbembe -> Mbembe Tigon */
+/*{HB_TAG('o','j','b',' '),    HB_TAG('O','J','B',' ')},*/     /* Northwestern Ojibwa -> Ojibway */
+  {HB_TAG('o','j','c',' '),    HB_TAG('O','J','B',' ')},       /* Central Ojibwa -> Ojibway */
+  {HB_TAG('o','j','g',' '),    HB_TAG('O','J','B',' ')},       /* Eastern Ojibwa -> Ojibway */
+  {HB_TAG('o','j','s',' '),    HB_TAG('O','C','R',' ')},       /* Severn Ojibwa -> Oji-Cree */
+  {HB_TAG('o','j','s',' '),    HB_TAG('O','J','B',' ')},       /* Severn Ojibwa -> Ojibway */
+  {HB_TAG('o','j','w',' '),    HB_TAG('O','J','B',' ')},       /* Western Ojibwa -> Ojibway */
+  {HB_TAG('o','k','d',' '),    HB_TAG('I','J','O',' ')},       /* Okodia -> Ijo */
+  {HB_TAG('o','k','i',' '),    HB_TAG('K','A','L',' ')},       /* Okiek -> Kalenjin */
+  {HB_TAG('o','k','m',' '),    HB_TAG('K','O','H',' ')},       /* Middle Korean (10th-16th cent.) -> Korean Old Hangul */
+  {HB_TAG('o','k','r',' '),    HB_TAG('I','J','O',' ')},       /* Kirike -> Ijo */
+  {HB_TAG('o','n','x',' '),    HB_TAG('C','P','P',' ')},       /* Onin Based Pidgin -> Creoles */
+  {HB_TAG('o','o','r',' '),    HB_TAG('C','P','P',' ')},       /* Oorlams -> Creoles */
+  {HB_TAG('o','r','c',' '),    HB_TAG('O','R','O',' ')},       /* Orma -> Oromo */
+  {HB_TAG('o','r','n',' '),    HB_TAG('M','L','Y',' ')},       /* Orang Kanaq -> Malay */
+  {HB_TAG('o','r','o',' '),    HB_TAG_NONE            },       /* Orokolo != Oromo */
+  {HB_TAG('o','r','r',' '),    HB_TAG('I','J','O',' ')},       /* Oruma -> Ijo */
+  {HB_TAG('o','r','s',' '),    HB_TAG('M','L','Y',' ')},       /* Orang Seletar -> Malay */
+  {HB_TAG('o','r','y',' '),    HB_TAG('O','R','I',' ')},       /* Odia (formerly Oriya) */
+  {HB_TAG('o','t','w',' '),    HB_TAG('O','J','B',' ')},       /* Ottawa -> Ojibway */
+  {HB_TAG('o','u','a',' '),    HB_TAG('B','B','R',' ')},       /* Tagargrent -> Berber */
+  {HB_TAG('p','a','a',' '),    HB_TAG_NONE            },       /* Papuan [collection] != Palestinian Aramaic */
+/*{HB_TAG('p','a','g',' '),    HB_TAG('P','A','G',' ')},*/     /* Pangasinan */
+  {HB_TAG('p','a','l',' '),    HB_TAG_NONE            },       /* Pahlavi != Pali */
+/*{HB_TAG('p','a','m',' '),    HB_TAG('P','A','M',' ')},*/     /* Pampanga -> Pampangan */
+  {HB_TAG('p','a','p',' '),    HB_TAG('P','A','P','0')},       /* Papiamento -> Papiamentu */
+  {HB_TAG('p','a','p',' '),    HB_TAG('C','P','P',' ')},       /* Papiamento -> Creoles */
+  {HB_TAG('p','a','s',' '),    HB_TAG_NONE            },       /* Papasena != Pashto */
+/*{HB_TAG('p','a','u',' '),    HB_TAG('P','A','U',' ')},*/     /* Palauan */
+  {HB_TAG('p','b','t',' '),    HB_TAG('P','A','S',' ')},       /* Southern Pashto -> Pashto */
+  {HB_TAG('p','b','u',' '),    HB_TAG('P','A','S',' ')},       /* Northern Pashto -> Pashto */
+/*{HB_TAG('p','c','c',' '),    HB_TAG('P','C','C',' ')},*/     /* Bouyei */
+/*{HB_TAG('p','c','d',' '),    HB_TAG('P','C','D',' ')},*/     /* Picard */
+  {HB_TAG('p','c','e',' '),    HB_TAG('P','L','G',' ')},       /* Ruching Palaung -> Palaung */
+  {HB_TAG('p','c','k',' '),    HB_TAG('Q','I','N',' ')},       /* Paite Chin -> Chin */
+  {HB_TAG('p','c','m',' '),    HB_TAG('C','P','P',' ')},       /* Nigerian Pidgin -> Creoles */
+/*{HB_TAG('p','d','c',' '),    HB_TAG('P','D','C',' ')},*/     /* Pennsylvania German */
+  {HB_TAG('p','d','u',' '),    HB_TAG('K','R','N',' ')},       /* Kayan -> Karen */
+  {HB_TAG('p','e','a',' '),    HB_TAG('C','P','P',' ')},       /* Peranakan Indonesian -> Creoles */
+  {HB_TAG('p','e','l',' '),    HB_TAG('M','L','Y',' ')},       /* Pekal -> Malay */
+  {HB_TAG('p','e','s',' '),    HB_TAG('F','A','R',' ')},       /* Iranian Persian -> Persian */
+  {HB_TAG('p','e','y',' '),    HB_TAG('C','P','P',' ')},       /* Petjo -> Creoles */
+  {HB_TAG('p','g','a',' '),    HB_TAG('A','R','A',' ')},       /* Sudanese Creole Arabic -> Arabic */
+  {HB_TAG('p','g','a',' '),    HB_TAG('C','P','P',' ')},       /* Sudanese Creole Arabic -> Creoles */
+/*{HB_TAG('p','h','k',' '),    HB_TAG('P','H','K',' ')},*/     /* Phake */
+  {HB_TAG('p','i','h',' '),    HB_TAG('P','I','H',' ')},       /* Pitcairn-Norfolk -> Norfolk */
+  {HB_TAG('p','i','h',' '),    HB_TAG('C','P','P',' ')},       /* Pitcairn-Norfolk -> Creoles */
+  {HB_TAG('p','i','l',' '),    HB_TAG_NONE            },       /* Yom != Filipino */
+  {HB_TAG('p','i','s',' '),    HB_TAG('C','P','P',' ')},       /* Pijin -> Creoles */
+  {HB_TAG('p','k','h',' '),    HB_TAG('Q','I','N',' ')},       /* Pankhu -> Chin */
+  {HB_TAG('p','k','o',' '),    HB_TAG('K','A','L',' ')},       /* Pökoot -> Kalenjin */
+  {HB_TAG('p','l','g',' '),    HB_TAG_NONE            },       /* Pilagá != Palaung */
+  {HB_TAG('p','l','k',' '),    HB_TAG_NONE            },       /* Kohistani Shina != Polish */
+  {HB_TAG('p','l','l',' '),    HB_TAG('P','L','G',' ')},       /* Shwe Palaung -> Palaung */
+  {HB_TAG('p','l','n',' '),    HB_TAG('C','P','P',' ')},       /* Palenquero -> Creoles */
+  {HB_TAG('p','l','p',' '),    HB_TAG('P','A','P',' ')},       /* Palpa (retired code) */
+  {HB_TAG('p','l','t',' '),    HB_TAG('M','L','G',' ')},       /* Plateau Malagasy -> Malagasy */
+  {HB_TAG('p','m','l',' '),    HB_TAG('C','P','P',' ')},       /* Lingua Franca -> Creoles */
+/*{HB_TAG('p','m','s',' '),    HB_TAG('P','M','S',' ')},*/     /* Piemontese */
+  {HB_TAG('p','m','y',' '),    HB_TAG('C','P','P',' ')},       /* Papuan Malay -> Creoles */
+/*{HB_TAG('p','n','b',' '),    HB_TAG('P','N','B',' ')},*/     /* Western Panjabi */
+  {HB_TAG('p','o','c',' '),    HB_TAG('M','Y','N',' ')},       /* Poqomam -> Mayan */
+  {HB_TAG('p','o','h',' '),    HB_TAG('P','O','H',' ')},       /* Poqomchi' -> Pocomchi */
+  {HB_TAG('p','o','h',' '),    HB_TAG('M','Y','N',' ')},       /* Poqomchi' -> Mayan */
+/*{HB_TAG('p','o','n',' '),    HB_TAG('P','O','N',' ')},*/     /* Pohnpeian */
+  {HB_TAG('p','o','v',' '),    HB_TAG('C','P','P',' ')},       /* Upper Guinea Crioulo -> Creoles */
+  {HB_TAG('p','p','a',' '),    HB_TAG('B','A','G',' ')},       /* Pao (retired code) -> Baghelkhandi */
+  {HB_TAG('p','r','e',' '),    HB_TAG('C','P','P',' ')},       /* Principense -> Creoles */
+/*{HB_TAG('p','r','o',' '),    HB_TAG('P','R','O',' ')},*/     /* Old Provençal (to 1500) -> Provençal / Old Provençal */
+  {HB_TAG('p','r','p',' '),    HB_TAG('G','U','J',' ')},       /* Parsi (retired code) -> Gujarati */
+  {HB_TAG('p','r','s',' '),    HB_TAG('D','R','I',' ')},       /* Dari */
+  {HB_TAG('p','r','s',' '),    HB_TAG('F','A','R',' ')},       /* Dari -> Persian */
+  {HB_TAG('p','s','e',' '),    HB_TAG('M','L','Y',' ')},       /* Central Malay -> Malay */
+  {HB_TAG('p','s','t',' '),    HB_TAG('P','A','S',' ')},       /* Central Pashto -> Pashto */
+  {HB_TAG('p','u','b',' '),    HB_TAG('Q','I','N',' ')},       /* Purum -> Chin */
+  {HB_TAG('p','u','z',' '),    HB_TAG('Q','I','N',' ')},       /* Purum Naga (retired code) -> Chin */
+  {HB_TAG('p','w','o',' '),    HB_TAG('P','W','O',' ')},       /* Pwo Western Karen -> Western Pwo Karen */
+  {HB_TAG('p','w','o',' '),    HB_TAG('K','R','N',' ')},       /* Pwo Western Karen -> Karen */
+  {HB_TAG('p','w','w',' '),    HB_TAG('K','R','N',' ')},       /* Pwo Northern Karen -> Karen */
+  {HB_TAG('q','u','b',' '),    HB_TAG('Q','W','H',' ')},       /* Huallaga Huánuco Quechua -> Quechua (Peru) */
+  {HB_TAG('q','u','b',' '),    HB_TAG('Q','U','Z',' ')},       /* Huallaga Huánuco Quechua -> Quechua */
+  {HB_TAG('q','u','c',' '),    HB_TAG('Q','U','C',' ')},       /* K’iche’ */
+  {HB_TAG('q','u','c',' '),    HB_TAG('M','Y','N',' ')},       /* K'iche' -> Mayan */
+  {HB_TAG('q','u','d',' '),    HB_TAG('Q','V','I',' ')},       /* Calderón Highland Quichua -> Quechua (Ecuador) */
+  {HB_TAG('q','u','d',' '),    HB_TAG('Q','U','Z',' ')},       /* Calderón Highland Quichua -> Quechua */
+  {HB_TAG('q','u','f',' '),    HB_TAG('Q','U','Z',' ')},       /* Lambayeque Quechua -> Quechua */
+  {HB_TAG('q','u','g',' '),    HB_TAG('Q','V','I',' ')},       /* Chimborazo Highland Quichua -> Quechua (Ecuador) */
+  {HB_TAG('q','u','g',' '),    HB_TAG('Q','U','Z',' ')},       /* Chimborazo Highland Quichua -> Quechua */
+  {HB_TAG('q','u','h',' '),    HB_TAG('Q','U','H',' ')},       /* South Bolivian Quechua -> Quechua (Bolivia) */
+  {HB_TAG('q','u','h',' '),    HB_TAG('Q','U','Z',' ')},       /* South Bolivian Quechua -> Quechua */
+  {HB_TAG('q','u','k',' '),    HB_TAG('Q','U','Z',' ')},       /* Chachapoyas Quechua -> Quechua */
+  {HB_TAG('q','u','l',' '),    HB_TAG('Q','U','H',' ')},       /* North Bolivian Quechua -> Quechua (Bolivia) */
+  {HB_TAG('q','u','l',' '),    HB_TAG('Q','U','Z',' ')},       /* North Bolivian Quechua -> Quechua */
+  {HB_TAG('q','u','m',' '),    HB_TAG('M','Y','N',' ')},       /* Sipacapense -> Mayan */
+  {HB_TAG('q','u','p',' '),    HB_TAG('Q','V','I',' ')},       /* Southern Pastaza Quechua -> Quechua (Ecuador) */
+  {HB_TAG('q','u','p',' '),    HB_TAG('Q','U','Z',' ')},       /* Southern Pastaza Quechua -> Quechua */
+  {HB_TAG('q','u','r',' '),    HB_TAG('Q','W','H',' ')},       /* Yanahuanca Pasco Quechua -> Quechua (Peru) */
+  {HB_TAG('q','u','r',' '),    HB_TAG('Q','U','Z',' ')},       /* Yanahuanca Pasco Quechua -> Quechua */
+  {HB_TAG('q','u','s',' '),    HB_TAG('Q','U','H',' ')},       /* Santiago del Estero Quichua -> Quechua (Bolivia) */
+  {HB_TAG('q','u','s',' '),    HB_TAG('Q','U','Z',' ')},       /* Santiago del Estero Quichua -> Quechua */
+  {HB_TAG('q','u','v',' '),    HB_TAG('M','Y','N',' ')},       /* Sacapulteco -> Mayan */
+  {HB_TAG('q','u','w',' '),    HB_TAG('Q','V','I',' ')},       /* Tena Lowland Quichua -> Quechua (Ecuador) */
+  {HB_TAG('q','u','w',' '),    HB_TAG('Q','U','Z',' ')},       /* Tena Lowland Quichua -> Quechua */
+  {HB_TAG('q','u','x',' '),    HB_TAG('Q','W','H',' ')},       /* Yauyos Quechua -> Quechua (Peru) */
+  {HB_TAG('q','u','x',' '),    HB_TAG('Q','U','Z',' ')},       /* Yauyos Quechua -> Quechua */
+  {HB_TAG('q','u','y',' '),    HB_TAG('Q','U','Z',' ')},       /* Ayacucho Quechua -> Quechua */
+/*{HB_TAG('q','u','z',' '),    HB_TAG('Q','U','Z',' ')},*/     /* Cusco Quechua -> Quechua */
+  {HB_TAG('q','v','a',' '),    HB_TAG('Q','W','H',' ')},       /* Ambo-Pasco Quechua -> Quechua (Peru) */
+  {HB_TAG('q','v','a',' '),    HB_TAG('Q','U','Z',' ')},       /* Ambo-Pasco Quechua -> Quechua */
+  {HB_TAG('q','v','c',' '),    HB_TAG('Q','U','Z',' ')},       /* Cajamarca Quechua -> Quechua */
+  {HB_TAG('q','v','e',' '),    HB_TAG('Q','U','Z',' ')},       /* Eastern Apurímac Quechua -> Quechua */
+  {HB_TAG('q','v','h',' '),    HB_TAG('Q','W','H',' ')},       /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */
+  {HB_TAG('q','v','h',' '),    HB_TAG('Q','U','Z',' ')},       /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua */
+  {HB_TAG('q','v','i',' '),    HB_TAG('Q','V','I',' ')},       /* Imbabura Highland Quichua -> Quechua (Ecuador) */
+  {HB_TAG('q','v','i',' '),    HB_TAG('Q','U','Z',' ')},       /* Imbabura Highland Quichua -> Quechua */
+  {HB_TAG('q','v','j',' '),    HB_TAG('Q','V','I',' ')},       /* Loja Highland Quichua -> Quechua (Ecuador) */
+  {HB_TAG('q','v','j',' '),    HB_TAG('Q','U','Z',' ')},       /* Loja Highland Quichua -> Quechua */
+  {HB_TAG('q','v','l',' '),    HB_TAG('Q','W','H',' ')},       /* Cajatambo North Lima Quechua -> Quechua (Peru) */
+  {HB_TAG('q','v','l',' '),    HB_TAG('Q','U','Z',' ')},       /* Cajatambo North Lima Quechua -> Quechua */
+  {HB_TAG('q','v','m',' '),    HB_TAG('Q','W','H',' ')},       /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */
+  {HB_TAG('q','v','m',' '),    HB_TAG('Q','U','Z',' ')},       /* Margos-Yarowilca-Lauricocha Quechua -> Quechua */
+  {HB_TAG('q','v','n',' '),    HB_TAG('Q','W','H',' ')},       /* North Junín Quechua -> Quechua (Peru) */
+  {HB_TAG('q','v','n',' '),    HB_TAG('Q','U','Z',' ')},       /* North Junín Quechua -> Quechua */
+  {HB_TAG('q','v','o',' '),    HB_TAG('Q','V','I',' ')},       /* Napo Lowland Quechua -> Quechua (Ecuador) */
+  {HB_TAG('q','v','o',' '),    HB_TAG('Q','U','Z',' ')},       /* Napo Lowland Quechua -> Quechua */
+  {HB_TAG('q','v','p',' '),    HB_TAG('Q','W','H',' ')},       /* Pacaraos Quechua -> Quechua (Peru) */
+  {HB_TAG('q','v','p',' '),    HB_TAG('Q','U','Z',' ')},       /* Pacaraos Quechua -> Quechua */
+  {HB_TAG('q','v','s',' '),    HB_TAG('Q','U','Z',' ')},       /* San Martín Quechua -> Quechua */
+  {HB_TAG('q','v','w',' '),    HB_TAG('Q','W','H',' ')},       /* Huaylla Wanca Quechua -> Quechua (Peru) */
+  {HB_TAG('q','v','w',' '),    HB_TAG('Q','U','Z',' ')},       /* Huaylla Wanca Quechua -> Quechua */
+  {HB_TAG('q','v','z',' '),    HB_TAG('Q','V','I',' ')},       /* Northern Pastaza Quichua -> Quechua (Ecuador) */
+  {HB_TAG('q','v','z',' '),    HB_TAG('Q','U','Z',' ')},       /* Northern Pastaza Quichua -> Quechua */
+  {HB_TAG('q','w','a',' '),    HB_TAG('Q','W','H',' ')},       /* Corongo Ancash Quechua -> Quechua (Peru) */
+  {HB_TAG('q','w','a',' '),    HB_TAG('Q','U','Z',' ')},       /* Corongo Ancash Quechua -> Quechua */
+  {HB_TAG('q','w','c',' '),    HB_TAG('Q','U','Z',' ')},       /* Classical Quechua -> Quechua */
+  {HB_TAG('q','w','h',' '),    HB_TAG('Q','W','H',' ')},       /* Huaylas Ancash Quechua -> Quechua (Peru) */
+  {HB_TAG('q','w','h',' '),    HB_TAG('Q','U','Z',' ')},       /* Huaylas Ancash Quechua -> Quechua */
+  {HB_TAG('q','w','s',' '),    HB_TAG('Q','W','H',' ')},       /* Sihuas Ancash Quechua -> Quechua (Peru) */
+  {HB_TAG('q','w','s',' '),    HB_TAG('Q','U','Z',' ')},       /* Sihuas Ancash Quechua -> Quechua */
+  {HB_TAG('q','w','t',' '),    HB_TAG('A','T','H',' ')},       /* Kwalhioqua-Tlatskanai -> Athapaskan */
+  {HB_TAG('q','x','a',' '),    HB_TAG('Q','W','H',' ')},       /* Chiquián Ancash Quechua -> Quechua (Peru) */
+  {HB_TAG('q','x','a',' '),    HB_TAG('Q','U','Z',' ')},       /* Chiquián Ancash Quechua -> Quechua */
+  {HB_TAG('q','x','c',' '),    HB_TAG('Q','W','H',' ')},       /* Chincha Quechua -> Quechua (Peru) */
+  {HB_TAG('q','x','c',' '),    HB_TAG('Q','U','Z',' ')},       /* Chincha Quechua -> Quechua */
+  {HB_TAG('q','x','h',' '),    HB_TAG('Q','W','H',' ')},       /* Panao Huánuco Quechua -> Quechua (Peru) */
+  {HB_TAG('q','x','h',' '),    HB_TAG('Q','U','Z',' ')},       /* Panao Huánuco Quechua -> Quechua */
+  {HB_TAG('q','x','l',' '),    HB_TAG('Q','V','I',' ')},       /* Salasaca Highland Quichua -> Quechua (Ecuador) */
+  {HB_TAG('q','x','l',' '),    HB_TAG('Q','U','Z',' ')},       /* Salasaca Highland Quichua -> Quechua */
+  {HB_TAG('q','x','n',' '),    HB_TAG('Q','W','H',' ')},       /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */
+  {HB_TAG('q','x','n',' '),    HB_TAG('Q','U','Z',' ')},       /* Northern Conchucos Ancash Quechua -> Quechua */
+  {HB_TAG('q','x','o',' '),    HB_TAG('Q','W','H',' ')},       /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */
+  {HB_TAG('q','x','o',' '),    HB_TAG('Q','U','Z',' ')},       /* Southern Conchucos Ancash Quechua -> Quechua */
+  {HB_TAG('q','x','p',' '),    HB_TAG('Q','U','Z',' ')},       /* Puno Quechua -> Quechua */
+  {HB_TAG('q','x','r',' '),    HB_TAG('Q','V','I',' ')},       /* Cañar Highland Quichua -> Quechua (Ecuador) */
+  {HB_TAG('q','x','r',' '),    HB_TAG('Q','U','Z',' ')},       /* Cañar Highland Quichua -> Quechua */
+  {HB_TAG('q','x','t',' '),    HB_TAG('Q','W','H',' ')},       /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */
+  {HB_TAG('q','x','t',' '),    HB_TAG('Q','U','Z',' ')},       /* Santa Ana de Tusi Pasco Quechua -> Quechua */
+  {HB_TAG('q','x','u',' '),    HB_TAG('Q','U','Z',' ')},       /* Arequipa-La Unión Quechua -> Quechua */
+  {HB_TAG('q','x','w',' '),    HB_TAG('Q','W','H',' ')},       /* Jauja Wanca Quechua -> Quechua (Peru) */
+  {HB_TAG('q','x','w',' '),    HB_TAG('Q','U','Z',' ')},       /* Jauja Wanca Quechua -> Quechua */
+  {HB_TAG('r','a','g',' '),    HB_TAG('L','U','H',' ')},       /* Logooli -> Luyia */
+/*{HB_TAG('r','a','j',' '),    HB_TAG('R','A','J',' ')},*/     /* Rajasthani [macrolanguage] */
+  {HB_TAG('r','a','l',' '),    HB_TAG('Q','I','N',' ')},       /* Ralte -> Chin */
+/*{HB_TAG('r','a','r',' '),    HB_TAG('R','A','R',' ')},*/     /* Rarotongan */
+  {HB_TAG('r','b','b',' '),    HB_TAG('P','L','G',' ')},       /* Rumai Palaung -> Palaung */
+  {HB_TAG('r','b','l',' '),    HB_TAG('B','I','K',' ')},       /* Miraya Bikol -> Bikol */
+  {HB_TAG('r','c','f',' '),    HB_TAG('C','P','P',' ')},       /* Réunion Creole French -> Creoles */
+/*{HB_TAG('r','e','j',' '),    HB_TAG('R','E','J',' ')},*/     /* Rejang */
+/*{HB_TAG('r','h','g',' '),    HB_TAG('R','H','G',' ')},*/     /* Rohingya */
+/*{HB_TAG('r','i','a',' '),    HB_TAG('R','I','A',' ')},*/     /* Riang (India) */
+  {HB_TAG('r','i','f',' '),    HB_TAG('R','I','F',' ')},       /* Tarifit */
+  {HB_TAG('r','i','f',' '),    HB_TAG('B','B','R',' ')},       /* Tarifit -> Berber */
+/*{HB_TAG('r','i','t',' '),    HB_TAG('R','I','T',' ')},*/     /* Ritharrngu -> Ritarungo */
+  {HB_TAG('r','k','i',' '),    HB_TAG('A','R','K',' ')},       /* Rakhine */
+/*{HB_TAG('r','k','w',' '),    HB_TAG('R','K','W',' ')},*/     /* Arakwal */
+  {HB_TAG('r','m','c',' '),    HB_TAG('R','O','Y',' ')},       /* Carpathian Romani -> Romany */
+  {HB_TAG('r','m','f',' '),    HB_TAG('R','O','Y',' ')},       /* Kalo Finnish Romani -> Romany */
+  {HB_TAG('r','m','l',' '),    HB_TAG('R','O','Y',' ')},       /* Baltic Romani -> Romany */
+  {HB_TAG('r','m','n',' '),    HB_TAG('R','O','Y',' ')},       /* Balkan Romani -> Romany */
+  {HB_TAG('r','m','o',' '),    HB_TAG('R','O','Y',' ')},       /* Sinte Romani -> Romany */
+  {HB_TAG('r','m','s',' '),    HB_TAG_NONE            },       /* Romanian Sign Language != Romansh */
+  {HB_TAG('r','m','w',' '),    HB_TAG('R','O','Y',' ')},       /* Welsh Romani -> Romany */
+  {HB_TAG('r','m','y',' '),    HB_TAG('R','M','Y',' ')},       /* Vlax Romani */
+  {HB_TAG('r','m','y',' '),    HB_TAG('R','O','Y',' ')},       /* Vlax Romani -> Romany */
+  {HB_TAG('r','m','z',' '),    HB_TAG('A','R','K',' ')},       /* Marma -> Rakhine */
+  {HB_TAG('r','o','m',' '),    HB_TAG('R','O','Y',' ')},       /* Romany [macrolanguage] */
+  {HB_TAG('r','o','p',' '),    HB_TAG('C','P','P',' ')},       /* Kriol -> Creoles */
+  {HB_TAG('r','t','c',' '),    HB_TAG('Q','I','N',' ')},       /* Rungtu Chin -> Chin */
+/*{HB_TAG('r','t','m',' '),    HB_TAG('R','T','M',' ')},*/     /* Rotuman */
+  {HB_TAG('r','u','e',' '),    HB_TAG('R','S','Y',' ')},       /* Rusyn */
+/*{HB_TAG('r','u','p',' '),    HB_TAG('R','U','P',' ')},*/     /* Aromanian */
+  {HB_TAG('r','w','r',' '),    HB_TAG('M','A','W',' ')},       /* Marwari (India) */
+  {HB_TAG('s','a','d',' '),    HB_TAG_NONE            },       /* Sandawe != Sadri */
+  {HB_TAG('s','a','h',' '),    HB_TAG('Y','A','K',' ')},       /* Yakut -> Sakha */
+  {HB_TAG('s','a','m',' '),    HB_TAG('P','A','A',' ')},       /* Samaritan Aramaic -> Palestinian Aramaic */
+/*{HB_TAG('s','a','s',' '),    HB_TAG('S','A','S',' ')},*/     /* Sasak */
+/*{HB_TAG('s','a','t',' '),    HB_TAG('S','A','T',' ')},*/     /* Santali */
+  {HB_TAG('s','a','y',' '),    HB_TAG_NONE            },       /* Saya != Sayisi */
+  {HB_TAG('s','c','f',' '),    HB_TAG('C','P','P',' ')},       /* San Miguel Creole French -> Creoles */
+  {HB_TAG('s','c','h',' '),    HB_TAG('Q','I','N',' ')},       /* Sakachep -> Chin */
+  {HB_TAG('s','c','i',' '),    HB_TAG('C','P','P',' ')},       /* Sri Lankan Creole Malay -> Creoles */
+  {HB_TAG('s','c','k',' '),    HB_TAG('S','A','D',' ')},       /* Sadri */
+/*{HB_TAG('s','c','n',' '),    HB_TAG('S','C','N',' ')},*/     /* Sicilian */
+/*{HB_TAG('s','c','o',' '),    HB_TAG('S','C','O',' ')},*/     /* Scots */
+  {HB_TAG('s','c','s',' '),    HB_TAG('S','C','S',' ')},       /* North Slavey */
+  {HB_TAG('s','c','s',' '),    HB_TAG('S','L','A',' ')},       /* North Slavey -> Slavey */
+  {HB_TAG('s','c','s',' '),    HB_TAG('A','T','H',' ')},       /* North Slavey -> Athapaskan */
+  {HB_TAG('s','d','c',' '),    HB_TAG('S','R','D',' ')},       /* Sassarese Sardinian -> Sardinian */
+  {HB_TAG('s','d','h',' '),    HB_TAG('K','U','R',' ')},       /* Southern Kurdish -> Kurdish */
+  {HB_TAG('s','d','n',' '),    HB_TAG('S','R','D',' ')},       /* Gallurese Sardinian -> Sardinian */
+  {HB_TAG('s','d','s',' '),    HB_TAG('B','B','R',' ')},       /* Sened -> Berber */
+  {HB_TAG('s','e','h',' '),    HB_TAG('S','N','A',' ')},       /* Sena */
+  {HB_TAG('s','e','k',' '),    HB_TAG('A','T','H',' ')},       /* Sekani -> Athapaskan */
+/*{HB_TAG('s','e','l',' '),    HB_TAG('S','E','L',' ')},*/     /* Selkup */
+  {HB_TAG('s','e','z',' '),    HB_TAG('Q','I','N',' ')},       /* Senthang Chin -> Chin */
+  {HB_TAG('s','f','m',' '),    HB_TAG('S','F','M',' ')},       /* Small Flowery Miao */
+  {HB_TAG('s','f','m',' '),    HB_TAG('H','M','N',' ')},       /* Small Flowery Miao -> Hmong */
+/*{HB_TAG('s','g','a',' '),    HB_TAG('S','G','A',' ')},*/     /* Old Irish (to 900) */
+  {HB_TAG('s','g','c',' '),    HB_TAG('K','A','L',' ')},       /* Kipsigis -> Kalenjin */
+  {HB_TAG('s','g','o',' '),    HB_TAG_NONE            },       /* Songa (retired code) != Sango */
+/*{HB_TAG('s','g','s',' '),    HB_TAG('S','G','S',' ')},*/     /* Samogitian */
+  {HB_TAG('s','g','w',' '),    HB_TAG('C','H','G',' ')},       /* Sebat Bet Gurage -> Chaha Gurage */
+  {HB_TAG('s','h','i',' '),    HB_TAG('S','H','I',' ')},       /* Tachelhit */
+  {HB_TAG('s','h','i',' '),    HB_TAG('B','B','R',' ')},       /* Tachelhit -> Berber */
+  {HB_TAG('s','h','l',' '),    HB_TAG('Q','I','N',' ')},       /* Shendu -> Chin */
+/*{HB_TAG('s','h','n',' '),    HB_TAG('S','H','N',' ')},*/     /* Shan */
+  {HB_TAG('s','h','u',' '),    HB_TAG('A','R','A',' ')},       /* Chadian Arabic -> Arabic */
+  {HB_TAG('s','h','y',' '),    HB_TAG('B','B','R',' ')},       /* Tachawit -> Berber */
+  {HB_TAG('s','i','b',' '),    HB_TAG_NONE            },       /* Sebop != Sibe */
+/*{HB_TAG('s','i','d',' '),    HB_TAG('S','I','D',' ')},*/     /* Sidamo */
+  {HB_TAG('s','i','g',' '),    HB_TAG_NONE            },       /* Paasaal != Silte Gurage */
+  {HB_TAG('s','i','z',' '),    HB_TAG('B','B','R',' ')},       /* Siwi -> Berber */
+  {HB_TAG('s','j','d',' '),    HB_TAG('K','S','M',' ')},       /* Kildin Sami */
+  {HB_TAG('s','j','o',' '),    HB_TAG('S','I','B',' ')},       /* Xibe -> Sibe */
+  {HB_TAG('s','j','s',' '),    HB_TAG('B','B','R',' ')},       /* Senhaja De Srair -> Berber */
+  {HB_TAG('s','k','g',' '),    HB_TAG('M','L','G',' ')},       /* Sakalava Malagasy -> Malagasy */
+  {HB_TAG('s','k','r',' '),    HB_TAG('S','R','K',' ')},       /* Saraiki */
+  {HB_TAG('s','k','s',' '),    HB_TAG_NONE            },       /* Maia != Skolt Sami */
+  {HB_TAG('s','k','w',' '),    HB_TAG('C','P','P',' ')},       /* Skepi Creole Dutch -> Creoles */
+  {HB_TAG('s','k','y',' '),    HB_TAG_NONE            },       /* Sikaiana != Slovak */
+  {HB_TAG('s','l','a',' '),    HB_TAG_NONE            },       /* Slavic [collection] != Slavey */
+  {HB_TAG('s','m','a',' '),    HB_TAG('S','S','M',' ')},       /* Southern Sami */
+  {HB_TAG('s','m','d',' '),    HB_TAG('M','B','N',' ')},       /* Sama (retired code) -> Mbundu */
+  {HB_TAG('s','m','j',' '),    HB_TAG('L','S','M',' ')},       /* Lule Sami */
+  {HB_TAG('s','m','l',' '),    HB_TAG_NONE            },       /* Central Sama != Somali */
+  {HB_TAG('s','m','n',' '),    HB_TAG('I','S','M',' ')},       /* Inari Sami */
+  {HB_TAG('s','m','s',' '),    HB_TAG('S','K','S',' ')},       /* Skolt Sami */
+  {HB_TAG('s','m','t',' '),    HB_TAG('Q','I','N',' ')},       /* Simte -> Chin */
+  {HB_TAG('s','n','b',' '),    HB_TAG('I','B','A',' ')},       /* Sebuyau (retired code) -> Iban */
+  {HB_TAG('s','n','h',' '),    HB_TAG_NONE            },       /* Shinabo (retired code) != Sinhala (Sinhalese) */
+/*{HB_TAG('s','n','k',' '),    HB_TAG('S','N','K',' ')},*/     /* Soninke */
+  {HB_TAG('s','o','g',' '),    HB_TAG_NONE            },       /* Sogdian != Sodo Gurage */
+/*{HB_TAG('s','o','p',' '),    HB_TAG('S','O','P',' ')},*/     /* Songe */
+  {HB_TAG('s','p','v',' '),    HB_TAG('O','R','I',' ')},       /* Sambalpuri -> Odia (formerly Oriya) */
+  {HB_TAG('s','p','y',' '),    HB_TAG('K','A','L',' ')},       /* Sabaot -> Kalenjin */
+  {HB_TAG('s','r','b',' '),    HB_TAG_NONE            },       /* Sora != Serbian */
+  {HB_TAG('s','r','c',' '),    HB_TAG('S','R','D',' ')},       /* Logudorese Sardinian -> Sardinian */
+  {HB_TAG('s','r','k',' '),    HB_TAG_NONE            },       /* Serudung Murut != Saraiki */
+  {HB_TAG('s','r','m',' '),    HB_TAG('C','P','P',' ')},       /* Saramaccan -> Creoles */
+  {HB_TAG('s','r','n',' '),    HB_TAG('C','P','P',' ')},       /* Sranan Tongo -> Creoles */
+  {HB_TAG('s','r','o',' '),    HB_TAG('S','R','D',' ')},       /* Campidanese Sardinian -> Sardinian */
+/*{HB_TAG('s','r','r',' '),    HB_TAG('S','R','R',' ')},*/     /* Serer */
+  {HB_TAG('s','r','s',' '),    HB_TAG('A','T','H',' ')},       /* Sarsi -> Athapaskan */
+  {HB_TAG('s','s','h',' '),    HB_TAG('A','R','A',' ')},       /* Shihhi Arabic -> Arabic */
+  {HB_TAG('s','s','l',' '),    HB_TAG_NONE            },       /* Western Sisaala != South Slavey */
+  {HB_TAG('s','s','m',' '),    HB_TAG_NONE            },       /* Semnam != Southern Sami */
+  {HB_TAG('s','t','a',' '),    HB_TAG('C','P','P',' ')},       /* Settla -> Creoles */
+/*{HB_TAG('s','t','q',' '),    HB_TAG('S','T','Q',' ')},*/     /* Saterfriesisch -> Saterland Frisian */
+  {HB_TAG('s','t','v',' '),    HB_TAG('S','I','G',' ')},       /* Silt'e -> Silte Gurage */
+/*{HB_TAG('s','u','k',' '),    HB_TAG('S','U','K',' ')},*/     /* Sukuma */
+  {HB_TAG('s','u','q',' '),    HB_TAG('S','U','R',' ')},       /* Suri */
+  {HB_TAG('s','u','r',' '),    HB_TAG_NONE            },       /* Mwaghavul != Suri */
+/*{HB_TAG('s','v','a',' '),    HB_TAG('S','V','A',' ')},*/     /* Svan */
+  {HB_TAG('s','v','c',' '),    HB_TAG('C','P','P',' ')},       /* Vincentian Creole English -> Creoles */
+  {HB_TAG('s','v','e',' '),    HB_TAG_NONE            },       /* Serili != Swedish */
+  {HB_TAG('s','w','b',' '),    HB_TAG('C','M','R',' ')},       /* Maore Comorian -> Comorian */
+  {HB_TAG('s','w','c',' '),    HB_TAG('S','W','K',' ')},       /* Congo Swahili -> Swahili */
+  {HB_TAG('s','w','h',' '),    HB_TAG('S','W','K',' ')},       /* Swahili */
+  {HB_TAG('s','w','k',' '),    HB_TAG_NONE            },       /* Malawi Sena != Swahili */
+  {HB_TAG('s','w','n',' '),    HB_TAG('B','B','R',' ')},       /* Sawknah -> Berber */
+  {HB_TAG('s','w','v',' '),    HB_TAG('M','A','W',' ')},       /* Shekhawati -> Marwari */
+/*{HB_TAG('s','x','u',' '),    HB_TAG('S','X','U',' ')},*/     /* Upper Saxon */
+  {HB_TAG('s','y','c',' '),    HB_TAG('S','Y','R',' ')},       /* Classical Syriac -> Syriac */
+/*{HB_TAG('s','y','l',' '),    HB_TAG('S','Y','L',' ')},*/     /* Sylheti */
+/*{HB_TAG('s','y','r',' '),    HB_TAG('S','Y','R',' ')},*/     /* Syriac [macrolanguage] */
+/*{HB_TAG('s','z','l',' '),    HB_TAG('S','Z','L',' ')},*/     /* Silesian */
+  {HB_TAG('t','a','a',' '),    HB_TAG('A','T','H',' ')},       /* Lower Tanana -> Athapaskan */
+/*{HB_TAG('t','a','b',' '),    HB_TAG('T','A','B',' ')},*/     /* Tabassaran -> Tabasaran */
+  {HB_TAG('t','a','j',' '),    HB_TAG_NONE            },       /* Eastern Tamang != Tajiki */
+  {HB_TAG('t','a','q',' '),    HB_TAG('T','M','H',' ')},       /* Tamasheq -> Tamashek */
+  {HB_TAG('t','a','q',' '),    HB_TAG('B','B','R',' ')},       /* Tamasheq -> Berber */
+  {HB_TAG('t','a','s',' '),    HB_TAG('C','P','P',' ')},       /* Tay Boi -> Creoles */
+  {HB_TAG('t','a','u',' '),    HB_TAG('A','T','H',' ')},       /* Upper Tanana -> Athapaskan */
+  {HB_TAG('t','c','b',' '),    HB_TAG('A','T','H',' ')},       /* Tanacross -> Athapaskan */
+  {HB_TAG('t','c','e',' '),    HB_TAG('A','T','H',' ')},       /* Southern Tutchone -> Athapaskan */
+  {HB_TAG('t','c','h',' '),    HB_TAG('C','P','P',' ')},       /* Turks And Caicos Creole English -> Creoles */
+  {HB_TAG('t','c','p',' '),    HB_TAG('Q','I','N',' ')},       /* Tawr Chin -> Chin */
+  {HB_TAG('t','c','s',' '),    HB_TAG('C','P','P',' ')},       /* Torres Strait Creole -> Creoles */
+  {HB_TAG('t','c','y',' '),    HB_TAG('T','U','L',' ')},       /* Tulu */
+  {HB_TAG('t','c','z',' '),    HB_TAG('Q','I','N',' ')},       /* Thado Chin -> Chin */
+/*{HB_TAG('t','d','d',' '),    HB_TAG('T','D','D',' ')},*/     /* Tai Nüa -> Dehong Dai */
+  {HB_TAG('t','d','x',' '),    HB_TAG('M','L','G',' ')},       /* Tandroy-Mahafaly Malagasy -> Malagasy */
+  {HB_TAG('t','e','c',' '),    HB_TAG('K','A','L',' ')},       /* Terik -> Kalenjin */
+  {HB_TAG('t','e','m',' '),    HB_TAG('T','M','N',' ')},       /* Timne -> Temne */
+/*{HB_TAG('t','e','t',' '),    HB_TAG('T','E','T',' ')},*/     /* Tetum */
+  {HB_TAG('t','e','z',' '),    HB_TAG('B','B','R',' ')},       /* Tetserret -> Berber */
+  {HB_TAG('t','f','n',' '),    HB_TAG('A','T','H',' ')},       /* Tanaina -> Athapaskan */
+  {HB_TAG('t','g','h',' '),    HB_TAG('C','P','P',' ')},       /* Tobagonian Creole English -> Creoles */
+  {HB_TAG('t','g','j',' '),    HB_TAG('N','I','S',' ')},       /* Tagin -> Nisi */
+  {HB_TAG('t','g','n',' '),    HB_TAG_NONE            },       /* Tandaganon != Tongan */
+  {HB_TAG('t','g','r',' '),    HB_TAG_NONE            },       /* Tareng != Tigre */
+  {HB_TAG('t','g','x',' '),    HB_TAG('A','T','H',' ')},       /* Tagish -> Athapaskan */
+  {HB_TAG('t','g','y',' '),    HB_TAG_NONE            },       /* Togoyo != Tigrinya */
+  {HB_TAG('t','h','t',' '),    HB_TAG('A','T','H',' ')},       /* Tahltan -> Athapaskan */
+  {HB_TAG('t','h','v',' '),    HB_TAG('T','M','H',' ')},       /* Tahaggart Tamahaq -> Tamashek */
+  {HB_TAG('t','h','v',' '),    HB_TAG('B','B','R',' ')},       /* Tahaggart Tamahaq -> Berber */
+  {HB_TAG('t','h','z',' '),    HB_TAG('T','M','H',' ')},       /* Tayart Tamajeq -> Tamashek */
+  {HB_TAG('t','h','z',' '),    HB_TAG('B','B','R',' ')},       /* Tayart Tamajeq -> Berber */
+  {HB_TAG('t','i','a',' '),    HB_TAG('B','B','R',' ')},       /* Tidikelt Tamazight -> Berber */
+  {HB_TAG('t','i','g',' '),    HB_TAG('T','G','R',' ')},       /* Tigre */
+/*{HB_TAG('t','i','v',' '),    HB_TAG('T','I','V',' ')},*/     /* Tiv */
+/*{HB_TAG('t','j','l',' '),    HB_TAG('T','J','L',' ')},*/     /* Tai Laing */
+  {HB_TAG('t','j','o',' '),    HB_TAG('B','B','R',' ')},       /* Temacine Tamazight -> Berber */
+  {HB_TAG('t','k','g',' '),    HB_TAG('M','L','G',' ')},       /* Tesaka Malagasy -> Malagasy */
+  {HB_TAG('t','k','m',' '),    HB_TAG_NONE            },       /* Takelma != Turkmen */
+/*{HB_TAG('t','l','i',' '),    HB_TAG('T','L','I',' ')},*/     /* Tlingit */
+  {HB_TAG('t','m','g',' '),    HB_TAG('C','P','P',' ')},       /* Ternateño -> Creoles */
+  {HB_TAG('t','m','h',' '),    HB_TAG('T','M','H',' ')},       /* Tamashek [macrolanguage] */
+  {HB_TAG('t','m','h',' '),    HB_TAG('B','B','R',' ')},       /* Tamashek [macrolanguage] -> Berber */
+  {HB_TAG('t','m','n',' '),    HB_TAG_NONE            },       /* Taman (Indonesia) != Temne */
+  {HB_TAG('t','m','w',' '),    HB_TAG('M','L','Y',' ')},       /* Temuan -> Malay */
+  {HB_TAG('t','n','a',' '),    HB_TAG_NONE            },       /* Tacana != Tswana */
+  {HB_TAG('t','n','e',' '),    HB_TAG_NONE            },       /* Tinoc Kallahan (retired code) != Tundra Enets */
+  {HB_TAG('t','n','f',' '),    HB_TAG('D','R','I',' ')},       /* Tangshewi (retired code) -> Dari */
+  {HB_TAG('t','n','f',' '),    HB_TAG('F','A','R',' ')},       /* Tangshewi (retired code) -> Persian */
+  {HB_TAG('t','n','g',' '),    HB_TAG_NONE            },       /* Tobanga != Tonga */
+  {HB_TAG('t','o','d',' '),    HB_TAG('T','O','D','0')},       /* Toma */
+  {HB_TAG('t','o','i',' '),    HB_TAG('T','N','G',' ')},       /* Tonga (Zambia) */
+  {HB_TAG('t','o','j',' '),    HB_TAG('M','Y','N',' ')},       /* Tojolabal -> Mayan */
+  {HB_TAG('t','o','l',' '),    HB_TAG('A','T','H',' ')},       /* Tolowa -> Athapaskan */
+  {HB_TAG('t','o','r',' '),    HB_TAG('B','A','D','0')},       /* Togbo-Vara Banda -> Banda */
+  {HB_TAG('t','p','i',' '),    HB_TAG('T','P','I',' ')},       /* Tok Pisin */
+  {HB_TAG('t','p','i',' '),    HB_TAG('C','P','P',' ')},       /* Tok Pisin -> Creoles */
+  {HB_TAG('t','r','f',' '),    HB_TAG('C','P','P',' ')},       /* Trinidadian Creole English -> Creoles */
+  {HB_TAG('t','r','k',' '),    HB_TAG_NONE            },       /* Turkic [collection] != Turkish */
+  {HB_TAG('t','r','u',' '),    HB_TAG('T','U','A',' ')},       /* Turoyo -> Turoyo Aramaic */
+  {HB_TAG('t','r','u',' '),    HB_TAG('S','Y','R',' ')},       /* Turoyo -> Syriac */
+  {HB_TAG('t','s','g',' '),    HB_TAG_NONE            },       /* Tausug != Tsonga */
+/*{HB_TAG('t','s','j',' '),    HB_TAG('T','S','J',' ')},*/     /* Tshangla */
+  {HB_TAG('t','t','c',' '),    HB_TAG('M','Y','N',' ')},       /* Tektiteko -> Mayan */
+  {HB_TAG('t','t','m',' '),    HB_TAG('A','T','H',' ')},       /* Northern Tutchone -> Athapaskan */
+  {HB_TAG('t','t','q',' '),    HB_TAG('T','M','H',' ')},       /* Tawallammat Tamajaq -> Tamashek */
+  {HB_TAG('t','t','q',' '),    HB_TAG('B','B','R',' ')},       /* Tawallammat Tamajaq -> Berber */
+  {HB_TAG('t','u','a',' '),    HB_TAG_NONE            },       /* Wiarumus != Turoyo Aramaic */
+  {HB_TAG('t','u','l',' '),    HB_TAG_NONE            },       /* Tula != Tulu */
+/*{HB_TAG('t','u','m',' '),    HB_TAG('T','U','M',' ')},*/     /* Tumbuka */
+  {HB_TAG('t','u','u',' '),    HB_TAG('A','T','H',' ')},       /* Tututni -> Athapaskan */
+  {HB_TAG('t','u','v',' '),    HB_TAG_NONE            },       /* Turkana != Tuvin */
+  {HB_TAG('t','u','y',' '),    HB_TAG('K','A','L',' ')},       /* Tugen -> Kalenjin */
+/*{HB_TAG('t','v','l',' '),    HB_TAG('T','V','L',' ')},*/     /* Tuvalu */
+  {HB_TAG('t','v','y',' '),    HB_TAG('C','P','P',' ')},       /* Timor Pidgin -> Creoles */
+  {HB_TAG('t','x','c',' '),    HB_TAG('A','T','H',' ')},       /* Tsetsaut -> Athapaskan */
+  {HB_TAG('t','x','y',' '),    HB_TAG('M','L','G',' ')},       /* Tanosy Malagasy -> Malagasy */
+  {HB_TAG('t','y','v',' '),    HB_TAG('T','U','V',' ')},       /* Tuvinian -> Tuvin */
+/*{HB_TAG('t','y','z',' '),    HB_TAG('T','Y','Z',' ')},*/     /* Tày */
+  {HB_TAG('t','z','h',' '),    HB_TAG('M','Y','N',' ')},       /* Tzeltal -> Mayan */
+  {HB_TAG('t','z','j',' '),    HB_TAG('M','Y','N',' ')},       /* Tz'utujil -> Mayan */
+  {HB_TAG('t','z','m',' '),    HB_TAG('T','Z','M',' ')},       /* Central Atlas Tamazight -> Tamazight */
+  {HB_TAG('t','z','m',' '),    HB_TAG('B','B','R',' ')},       /* Central Atlas Tamazight -> Berber */
+  {HB_TAG('t','z','o',' '),    HB_TAG('T','Z','O',' ')},       /* Tzotzil */
+  {HB_TAG('t','z','o',' '),    HB_TAG('M','Y','N',' ')},       /* Tzotzil -> Mayan */
+  {HB_TAG('u','b','l',' '),    HB_TAG('B','I','K',' ')},       /* Buhi'non Bikol -> Bikol */
+/*{HB_TAG('u','d','m',' '),    HB_TAG('U','D','M',' ')},*/     /* Udmurt */
+  {HB_TAG('u','k','i',' '),    HB_TAG('K','U','I',' ')},       /* Kui (India) */
+  {HB_TAG('u','l','n',' '),    HB_TAG('C','P','P',' ')},       /* Unserdeutsch -> Creoles */
+/*{HB_TAG('u','m','b',' '),    HB_TAG('U','M','B',' ')},*/     /* Umbundu */
+  {HB_TAG('u','n','r',' '),    HB_TAG('M','U','N',' ')},       /* Mundari */
+  {HB_TAG('u','r','k',' '),    HB_TAG('M','L','Y',' ')},       /* Urak Lawoi' -> Malay */
+  {HB_TAG('u','s','p',' '),    HB_TAG('M','Y','N',' ')},       /* Uspanteco -> Mayan */
+  {HB_TAG('u','z','n',' '),    HB_TAG('U','Z','B',' ')},       /* Northern Uzbek -> Uzbek */
+  {HB_TAG('u','z','s',' '),    HB_TAG('U','Z','B',' ')},       /* Southern Uzbek -> Uzbek */
+  {HB_TAG('v','a','p',' '),    HB_TAG('Q','I','N',' ')},       /* Vaiphei -> Chin */
+/*{HB_TAG('v','e','c',' '),    HB_TAG('V','E','C',' ')},*/     /* Venetian */
+  {HB_TAG('v','i','c',' '),    HB_TAG('C','P','P',' ')},       /* Virgin Islands Creole English -> Creoles */
+  {HB_TAG('v','i','t',' '),    HB_TAG_NONE            },       /* Viti != Vietnamese */
+  {HB_TAG('v','k','k',' '),    HB_TAG('M','L','Y',' ')},       /* Kaur -> Malay */
+  {HB_TAG('v','k','p',' '),    HB_TAG('C','P','P',' ')},       /* Korlai Creole Portuguese -> Creoles */
+  {HB_TAG('v','k','t',' '),    HB_TAG('M','L','Y',' ')},       /* Tenggarong Kutai Malay -> Malay */
+  {HB_TAG('v','l','s',' '),    HB_TAG('F','L','E',' ')},       /* Vlaams -> Dutch (Flemish) */
+  {HB_TAG('v','m','w',' '),    HB_TAG('M','A','K',' ')},       /* Makhuwa */
+/*{HB_TAG('v','r','o',' '),    HB_TAG('V','R','O',' ')},*/     /* Võro */
+  {HB_TAG('w','a','g',' '),    HB_TAG_NONE            },       /* Wa'ema != Wagdi */
+/*{HB_TAG('w','a','r',' '),    HB_TAG('W','A','R',' ')},*/     /* Waray (Philippines) -> Waray-Waray */
+  {HB_TAG('w','b','m',' '),    HB_TAG('W','A',' ',' ')},       /* Wa */
+  {HB_TAG('w','b','r',' '),    HB_TAG('W','A','G',' ')},       /* Wagdi */
+  {HB_TAG('w','b','r',' '),    HB_TAG('R','A','J',' ')},       /* Wagdi -> Rajasthani */
+/*{HB_TAG('w','c','i',' '),    HB_TAG('W','C','I',' ')},*/     /* Waci Gbe */
+  {HB_TAG('w','e','a',' '),    HB_TAG('K','R','N',' ')},       /* Wewaw -> Karen */
+  {HB_TAG('w','e','s',' '),    HB_TAG('C','P','P',' ')},       /* Cameroon Pidgin -> Creoles */
+  {HB_TAG('w','e','u',' '),    HB_TAG('Q','I','N',' ')},       /* Rawngtu Chin -> Chin */
+  {HB_TAG('w','l','c',' '),    HB_TAG('C','M','R',' ')},       /* Mwali Comorian -> Comorian */
+  {HB_TAG('w','l','e',' '),    HB_TAG('S','I','G',' ')},       /* Wolane -> Silte Gurage */
+  {HB_TAG('w','l','k',' '),    HB_TAG('A','T','H',' ')},       /* Wailaki -> Athapaskan */
+  {HB_TAG('w','n','i',' '),    HB_TAG('C','M','R',' ')},       /* Ndzwani Comorian -> Comorian */
+  {HB_TAG('w','r','y',' '),    HB_TAG('M','A','W',' ')},       /* Merwari -> Marwari */
+  {HB_TAG('w','s','g',' '),    HB_TAG('G','O','N',' ')},       /* Adilabad Gondi -> Gondi */
+/*{HB_TAG('w','t','m',' '),    HB_TAG('W','T','M',' ')},*/     /* Mewati */
+  {HB_TAG('w','u','u',' '),    HB_TAG('Z','H','S',' ')},       /* Wu Chinese -> Chinese, Simplified */
+  {HB_TAG('x','a','l',' '),    HB_TAG('K','L','M',' ')},       /* Kalmyk */
+  {HB_TAG('x','a','l',' '),    HB_TAG('T','O','D',' ')},       /* Kalmyk -> Todo */
+  {HB_TAG('x','a','n',' '),    HB_TAG('S','E','K',' ')},       /* Xamtanga -> Sekota */
+  {HB_TAG('x','b','d',' '),    HB_TAG_NONE            },       /* Bindal != Lü */
+/*{HB_TAG('x','j','b',' '),    HB_TAG('X','J','B',' ')},*/     /* Minjungbal -> Minjangbal */
+/*{HB_TAG('x','k','f',' '),    HB_TAG('X','K','F',' ')},*/     /* Khengkha */
+  {HB_TAG('x','m','g',' '),    HB_TAG('B','M','L',' ')},       /* Mengaka -> Bamileke */
+  {HB_TAG('x','m','m',' '),    HB_TAG('M','L','Y',' ')},       /* Manado Malay -> Malay */
+  {HB_TAG('x','m','m',' '),    HB_TAG('C','P','P',' ')},       /* Manado Malay -> Creoles */
+  {HB_TAG('x','m','v',' '),    HB_TAG('M','L','G',' ')},       /* Antankarana Malagasy -> Malagasy */
+  {HB_TAG('x','m','w',' '),    HB_TAG('M','L','G',' ')},       /* Tsimihety Malagasy -> Malagasy */
+  {HB_TAG('x','n','j',' '),    HB_TAG('S','X','T',' ')},       /* Ngoni (Tanzania) -> Sutu */
+  {HB_TAG('x','n','q',' '),    HB_TAG('S','X','T',' ')},       /* Ngoni (Mozambique) -> Sutu */
+  {HB_TAG('x','n','r',' '),    HB_TAG('D','G','R',' ')},       /* Kangri -> Dogri (macrolanguage) */
+/*{HB_TAG('x','o','g',' '),    HB_TAG('X','O','G',' ')},*/     /* Soga */
+  {HB_TAG('x','p','e',' '),    HB_TAG('X','P','E',' ')},       /* Liberia Kpelle -> Kpelle (Liberia) */
+  {HB_TAG('x','p','e',' '),    HB_TAG('K','P','L',' ')},       /* Liberia Kpelle -> Kpelle */
+  {HB_TAG('x','s','l',' '),    HB_TAG('S','S','L',' ')},       /* South Slavey */
+  {HB_TAG('x','s','l',' '),    HB_TAG('S','L','A',' ')},       /* South Slavey -> Slavey */
+  {HB_TAG('x','s','l',' '),    HB_TAG('A','T','H',' ')},       /* South Slavey -> Athapaskan */
+  {HB_TAG('x','s','t',' '),    HB_TAG('S','I','G',' ')},       /* Silt'e (retired code) -> Silte Gurage */
+/*{HB_TAG('x','u','b',' '),    HB_TAG('X','U','B',' ')},*/     /* Betta Kurumba -> Bette Kuruma */
+/*{HB_TAG('x','u','j',' '),    HB_TAG('X','U','J',' ')},*/     /* Jennu Kurumba -> Jennu Kuruma */
+  {HB_TAG('x','u','p',' '),    HB_TAG('A','T','H',' ')},       /* Upper Umpqua -> Athapaskan */
+  {HB_TAG('x','w','o',' '),    HB_TAG('T','O','D',' ')},       /* Written Oirat -> Todo */
+  {HB_TAG('y','a','j',' '),    HB_TAG('B','A','D','0')},       /* Banda-Yangere -> Banda */
+  {HB_TAG('y','a','k',' '),    HB_TAG_NONE            },       /* Yakama != Sakha */
+/*{HB_TAG('y','a','o',' '),    HB_TAG('Y','A','O',' ')},*/     /* Yao */
+/*{HB_TAG('y','a','p',' '),    HB_TAG('Y','A','P',' ')},*/     /* Yapese */
+  {HB_TAG('y','b','a',' '),    HB_TAG_NONE            },       /* Yala != Yoruba */
+  {HB_TAG('y','b','b',' '),    HB_TAG('B','M','L',' ')},       /* Yemba -> Bamileke */
+  {HB_TAG('y','b','d',' '),    HB_TAG('A','R','K',' ')},       /* Yangbye (retired code) -> Rakhine */
+  {HB_TAG('y','c','r',' '),    HB_TAG_NONE            },       /* Yilan Creole != Y-Cree */
+  {HB_TAG('y','d','d',' '),    HB_TAG('J','I','I',' ')},       /* Eastern Yiddish -> Yiddish */
+/*{HB_TAG('y','g','p',' '),    HB_TAG('Y','G','P',' ')},*/     /* Gepo */
+  {HB_TAG('y','i','h',' '),    HB_TAG('J','I','I',' ')},       /* Western Yiddish -> Yiddish */
+  {HB_TAG('y','i','m',' '),    HB_TAG_NONE            },       /* Yimchungru Naga != Yi Modern */
+/*{HB_TAG('y','n','a',' '),    HB_TAG('Y','N','A',' ')},*/     /* Aluo */
+  {HB_TAG('y','o','s',' '),    HB_TAG('Q','I','N',' ')},       /* Yos (retired code) -> Chin */
+  {HB_TAG('y','u','a',' '),    HB_TAG('M','Y','N',' ')},       /* Yucateco -> Mayan */
+  {HB_TAG('y','u','e',' '),    HB_TAG('Z','H','H',' ')},       /* Yue Chinese -> Chinese, Traditional, Hong Kong SAR */
+/*{HB_TAG('y','w','q',' '),    HB_TAG('Y','W','Q',' ')},*/     /* Wuding-Luquan Yi */
+  {HB_TAG('z','c','h',' '),    HB_TAG('Z','H','A',' ')},       /* Central Hongshuihe Zhuang -> Zhuang */
+  {HB_TAG('z','d','j',' '),    HB_TAG('C','M','R',' ')},       /* Ngazidja Comorian -> Comorian */
+/*{HB_TAG('z','e','a',' '),    HB_TAG('Z','E','A',' ')},*/     /* Zeeuws -> Zealandic */
+  {HB_TAG('z','e','h',' '),    HB_TAG('Z','H','A',' ')},       /* Eastern Hongshuihe Zhuang -> Zhuang */
+  {HB_TAG('z','e','n',' '),    HB_TAG('B','B','R',' ')},       /* Zenaga -> Berber */
+  {HB_TAG('z','g','b',' '),    HB_TAG('Z','H','A',' ')},       /* Guibei Zhuang -> Zhuang */
+  {HB_TAG('z','g','h',' '),    HB_TAG('Z','G','H',' ')},       /* Standard Moroccan Tamazight */
+  {HB_TAG('z','g','h',' '),    HB_TAG('B','B','R',' ')},       /* Standard Moroccan Tamazight -> Berber */
+  {HB_TAG('z','g','m',' '),    HB_TAG('Z','H','A',' ')},       /* Minz Zhuang -> Zhuang */
+  {HB_TAG('z','g','n',' '),    HB_TAG('Z','H','A',' ')},       /* Guibian Zhuang -> Zhuang */
+  {HB_TAG('z','h','d',' '),    HB_TAG('Z','H','A',' ')},       /* Dai Zhuang -> Zhuang */
+  {HB_TAG('z','h','n',' '),    HB_TAG('Z','H','A',' ')},       /* Nong Zhuang -> Zhuang */
+  {HB_TAG('z','k','b',' '),    HB_TAG('K','H','A',' ')},       /* Koibal (retired code) -> Khakass */
+  {HB_TAG('z','l','j',' '),    HB_TAG('Z','H','A',' ')},       /* Liujiang Zhuang -> Zhuang */
+  {HB_TAG('z','l','m',' '),    HB_TAG('M','L','Y',' ')},       /* Malay */
+  {HB_TAG('z','l','n',' '),    HB_TAG('Z','H','A',' ')},       /* Lianshan Zhuang -> Zhuang */
+  {HB_TAG('z','l','q',' '),    HB_TAG('Z','H','A',' ')},       /* Liuqian Zhuang -> Zhuang */
+  {HB_TAG('z','m','i',' '),    HB_TAG('M','L','Y',' ')},       /* Negeri Sembilan Malay -> Malay */
+  {HB_TAG('z','m','z',' '),    HB_TAG('B','A','D','0')},       /* Mbandja -> Banda */
+  {HB_TAG('z','n','d',' '),    HB_TAG_NONE            },       /* Zande [collection] != Zande */
+  {HB_TAG('z','n','e',' '),    HB_TAG('Z','N','D',' ')},       /* Zande */
+  {HB_TAG('z','o','m',' '),    HB_TAG('Q','I','N',' ')},       /* Zou -> Chin */
+  {HB_TAG('z','q','e',' '),    HB_TAG('Z','H','A',' ')},       /* Qiubei Zhuang -> Zhuang */
+  {HB_TAG('z','s','m',' '),    HB_TAG('M','L','Y',' ')},       /* Standard Malay -> Malay */
+  {HB_TAG('z','u','m',' '),    HB_TAG('L','R','C',' ')},       /* Kumzari -> Luri */
+  {HB_TAG('z','y','b',' '),    HB_TAG('Z','H','A',' ')},       /* Yongbei Zhuang -> Zhuang */
+  {HB_TAG('z','y','g',' '),    HB_TAG('Z','H','A',' ')},       /* Yang Zhuang -> Zhuang */
+  {HB_TAG('z','y','j',' '),    HB_TAG('Z','H','A',' ')},       /* Youjiang Zhuang -> Zhuang */
+  {HB_TAG('z','y','n',' '),    HB_TAG('Z','H','A',' ')},       /* Yongnan Zhuang -> Zhuang */
+  {HB_TAG('z','y','p',' '),    HB_TAG('Q','I','N',' ')},       /* Zyphe Chin -> Chin */
+/*{HB_TAG('z','z','a',' '),    HB_TAG('Z','Z','A',' ')},*/     /* Zazaki [macrolanguage] */
+  {HB_TAG('z','z','j',' '),    HB_TAG('Z','H','A',' ')},       /* Zuojiang Zhuang -> Zhuang */
+};
+#endif
+
 /**
  * hb_ot_tags_from_complex_language:
  * @lang_str: a BCP 47 language tag to convert.
@@ -1630,75 +1641,81 @@ static const LangTag ot_languages[] = {
  *
  * Return value: Whether any language systems were retrieved.
  **/
-static bool
+static inline 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, "-arevmda"))
-  {
-    /* Armenian; Western Armenian (retired code) */
-    tags[0] = HB_TAG('H','Y','E',' ');  /* Armenian */
-    *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"))
+  if (limit - lang_str >= 7)
   {
-    /* 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;
+    const char *p = strchr (lang_str, '-');
+    if (!p || p >= limit || limit - p < 5) goto out;
+    if (subtag_matches (p, limit, "-fonnapa", 8))
+    {
+      /* Undetermined; North American Phonetic Alphabet */
+      tags[0] = HB_TAG('A','P','P','H');  /* Phonetic transcription—Americanist conventions */
+      *count = 1;
+      return true;
+    }
+    if (subtag_matches (p, limit, "-polyton", 8))
+    {
+      /* Modern Greek (1453-); Polytonic Greek */
+      tags[0] = HB_TAG('P','G','R',' ');  /* Polytonic Greek */
+      *count = 1;
+      return true;
+    }
+    if (subtag_matches (p, limit, "-arevmda", 8))
+    {
+      /* Armenian; Western Armenian (retired code) */
+      tags[0] = HB_TAG('H','Y','E',' ');  /* Armenian */
+      *count = 1;
+      return true;
+    }
+    if (subtag_matches (p, limit, "-provenc", 8))
+    {
+      /* Occitan (post 1500); Provençal */
+      tags[0] = HB_TAG('P','R','O',' ');  /* Provençal / Old Provençal */
+      *count = 1;
+      return true;
+    }
+    if (subtag_matches (p, limit, "-fonipa", 7))
+    {
+      /* Undetermined; International Phonetic Alphabet */
+      tags[0] = HB_TAG('I','P','P','H');  /* Phonetic transcription—IPA conventions */
+      *count = 1;
+      return true;
+    }
+    if (subtag_matches (p, limit, "-geok", 5))
+    {
+      /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */
+      tags[0] = HB_TAG('K','G','E',' ');  /* Khutsuri Georgian */
+      *count = 1;
+      return true;
+    }
+    if (subtag_matches (p, limit, "-syre", 5))
+    {
+      /* 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 (p, limit, "-syrj", 5))
+    {
+      /* 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 (p, limit, "-syrn", 5))
+    {
+      /* 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;
+    }
   }
+out:
   switch (lang_str[0])
   {
   case 'a':
@@ -1711,14 +1728,14 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
     }
     break;
   case 'c':
-    if (lang_matches (&lang_str[1], "do-hant-hk"))
+    if (lang_matches (&lang_str[1], limit, "do-hant-hk", 10))
     {
       /* Min Dong Chinese; Han (Traditional variant); Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "do-hant-mo"))
+    if (lang_matches (&lang_str[1], limit, "do-hant-mo", 10))
     {
       /* Min Dong Chinese; Han (Traditional variant); Macao */
       unsigned int i;
@@ -1731,14 +1748,14 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       *count = i;
       return true;
     }
-    if (lang_matches (&lang_str[1], "jy-hant-hk"))
+    if (lang_matches (&lang_str[1], limit, "jy-hant-hk", 10))
     {
       /* Jinyu Chinese; Han (Traditional variant); Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "jy-hant-mo"))
+    if (lang_matches (&lang_str[1], limit, "jy-hant-mo", 10))
     {
       /* Jinyu Chinese; Han (Traditional variant); Macao */
       unsigned int i;
@@ -1751,14 +1768,14 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       *count = i;
       return true;
     }
-    if (lang_matches (&lang_str[1], "mn-hant-hk"))
+    if (lang_matches (&lang_str[1], limit, "mn-hant-hk", 10))
     {
       /* Mandarin Chinese; Han (Traditional variant); Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "mn-hant-mo"))
+    if (lang_matches (&lang_str[1], limit, "mn-hant-mo", 10))
     {
       /* Mandarin Chinese; Han (Traditional variant); Macao */
       unsigned int i;
@@ -1771,14 +1788,14 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       *count = i;
       return true;
     }
-    if (lang_matches (&lang_str[1], "np-hant-hk"))
+    if (lang_matches (&lang_str[1], limit, "np-hant-hk", 10))
     {
       /* Northern Ping Chinese; Han (Traditional variant); Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "np-hant-mo"))
+    if (lang_matches (&lang_str[1], limit, "np-hant-mo", 10))
     {
       /* Northern Ping Chinese; Han (Traditional variant); Macao */
       unsigned int i;
@@ -1791,14 +1808,14 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       *count = i;
       return true;
     }
-    if (lang_matches (&lang_str[1], "px-hant-hk"))
+    if (lang_matches (&lang_str[1], limit, "px-hant-hk", 10))
     {
       /* Pu-Xian Chinese; Han (Traditional variant); Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "px-hant-mo"))
+    if (lang_matches (&lang_str[1], limit, "px-hant-mo", 10))
     {
       /* Pu-Xian Chinese; Han (Traditional variant); Macao */
       unsigned int i;
@@ -1811,14 +1828,14 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       *count = i;
       return true;
     }
-    if (lang_matches (&lang_str[1], "sp-hant-hk"))
+    if (lang_matches (&lang_str[1], limit, "sp-hant-hk", 10))
     {
       /* Southern Ping Chinese; Han (Traditional variant); Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "sp-hant-mo"))
+    if (lang_matches (&lang_str[1], limit, "sp-hant-mo", 10))
     {
       /* Southern Ping Chinese; Han (Traditional variant); Macao */
       unsigned int i;
@@ -1831,14 +1848,14 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       *count = i;
       return true;
     }
-    if (lang_matches (&lang_str[1], "zh-hant-hk"))
+    if (lang_matches (&lang_str[1], limit, "zh-hant-hk", 10))
     {
       /* Huizhou Chinese; Han (Traditional variant); Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "zh-hant-mo"))
+    if (lang_matches (&lang_str[1], limit, "zh-hant-mo", 10))
     {
       /* Huizhou Chinese; Han (Traditional variant); Macao */
       unsigned int i;
@@ -1851,14 +1868,14 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       *count = i;
       return true;
     }
-    if (lang_matches (&lang_str[1], "zo-hant-hk"))
+    if (lang_matches (&lang_str[1], limit, "zo-hant-hk", 10))
     {
       /* Min Zhong Chinese; Han (Traditional variant); Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "zo-hant-mo"))
+    if (lang_matches (&lang_str[1], limit, "zo-hant-mo", 10))
     {
       /* Min Zhong Chinese; Han (Traditional variant); Macao */
       unsigned int i;
@@ -1871,112 +1888,112 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       *count = i;
       return true;
     }
-    if (lang_matches (&lang_str[1], "do-hans"))
+    if (lang_matches (&lang_str[1], limit, "do-hans", 7))
     {
       /* Min Dong Chinese; Han (Simplified variant) */
       tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "do-hant"))
+    if (lang_matches (&lang_str[1], limit, "do-hant", 7))
     {
       /* Min Dong Chinese; Han (Traditional variant) */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "jy-hans"))
+    if (lang_matches (&lang_str[1], limit, "jy-hans", 7))
     {
       /* Jinyu Chinese; Han (Simplified variant) */
       tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "jy-hant"))
+    if (lang_matches (&lang_str[1], limit, "jy-hant", 7))
     {
       /* Jinyu Chinese; Han (Traditional variant) */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "mn-hans"))
+    if (lang_matches (&lang_str[1], limit, "mn-hans", 7))
     {
       /* Mandarin Chinese; Han (Simplified variant) */
       tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "mn-hant"))
+    if (lang_matches (&lang_str[1], limit, "mn-hant", 7))
     {
       /* Mandarin Chinese; Han (Traditional variant) */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "np-hans"))
+    if (lang_matches (&lang_str[1], limit, "np-hans", 7))
     {
       /* Northern Ping Chinese; Han (Simplified variant) */
       tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "np-hant"))
+    if (lang_matches (&lang_str[1], limit, "np-hant", 7))
     {
       /* Northern Ping Chinese; Han (Traditional variant) */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "px-hans"))
+    if (lang_matches (&lang_str[1], limit, "px-hans", 7))
     {
       /* Pu-Xian Chinese; Han (Simplified variant) */
       tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "px-hant"))
+    if (lang_matches (&lang_str[1], limit, "px-hant", 7))
     {
       /* Pu-Xian Chinese; Han (Traditional variant) */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "sp-hans"))
+    if (lang_matches (&lang_str[1], limit, "sp-hans", 7))
     {
       /* Southern Ping Chinese; Han (Simplified variant) */
       tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "sp-hant"))
+    if (lang_matches (&lang_str[1], limit, "sp-hant", 7))
     {
       /* Southern Ping Chinese; Han (Traditional variant) */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "zh-hans"))
+    if (lang_matches (&lang_str[1], limit, "zh-hans", 7))
     {
       /* Huizhou Chinese; Han (Simplified variant) */
       tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "zh-hant"))
+    if (lang_matches (&lang_str[1], limit, "zh-hant", 7))
     {
       /* Huizhou Chinese; Han (Traditional variant) */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "zo-hans"))
+    if (lang_matches (&lang_str[1], limit, "zo-hans", 7))
     {
       /* Min Zhong Chinese; Han (Simplified variant) */
       tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "zo-hant"))
+    if (lang_matches (&lang_str[1], limit, "zo-hant", 7))
     {
       /* Min Zhong Chinese; Han (Traditional variant) */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -1984,7 +2001,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "do-", 3)
-       && subtag_matches (lang_str, limit, "-hk"))
+       && subtag_matches (lang_str, limit, "-hk", 3))
     {
       /* Min Dong Chinese; Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
@@ -1992,7 +2009,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "do-", 3)
-       && subtag_matches (lang_str, limit, "-mo"))
+       && subtag_matches (lang_str, limit, "-mo", 3))
     {
       /* Min Dong Chinese; Macao */
       unsigned int i;
@@ -2006,7 +2023,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "do-", 3)
-       && subtag_matches (lang_str, limit, "-tw"))
+       && subtag_matches (lang_str, limit, "-tw", 3))
     {
       /* Min Dong Chinese; Taiwan, Province of China */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2014,7 +2031,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "jy-", 3)
-       && subtag_matches (lang_str, limit, "-hk"))
+       && subtag_matches (lang_str, limit, "-hk", 3))
     {
       /* Jinyu Chinese; Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
@@ -2022,7 +2039,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "jy-", 3)
-       && subtag_matches (lang_str, limit, "-mo"))
+       && subtag_matches (lang_str, limit, "-mo", 3))
     {
       /* Jinyu Chinese; Macao */
       unsigned int i;
@@ -2036,7 +2053,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "jy-", 3)
-       && subtag_matches (lang_str, limit, "-tw"))
+       && subtag_matches (lang_str, limit, "-tw", 3))
     {
       /* Jinyu Chinese; Taiwan, Province of China */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2044,7 +2061,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "mn-", 3)
-       && subtag_matches (lang_str, limit, "-hk"))
+       && subtag_matches (lang_str, limit, "-hk", 3))
     {
       /* Mandarin Chinese; Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
@@ -2052,7 +2069,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "mn-", 3)
-       && subtag_matches (lang_str, limit, "-mo"))
+       && subtag_matches (lang_str, limit, "-mo", 3))
     {
       /* Mandarin Chinese; Macao */
       unsigned int i;
@@ -2066,7 +2083,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "mn-", 3)
-       && subtag_matches (lang_str, limit, "-tw"))
+       && subtag_matches (lang_str, limit, "-tw", 3))
     {
       /* Mandarin Chinese; Taiwan, Province of China */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2074,7 +2091,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "np-", 3)
-       && subtag_matches (lang_str, limit, "-hk"))
+       && subtag_matches (lang_str, limit, "-hk", 3))
     {
       /* Northern Ping Chinese; Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
@@ -2082,7 +2099,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "np-", 3)
-       && subtag_matches (lang_str, limit, "-mo"))
+       && subtag_matches (lang_str, limit, "-mo", 3))
     {
       /* Northern Ping Chinese; Macao */
       unsigned int i;
@@ -2096,7 +2113,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "np-", 3)
-       && subtag_matches (lang_str, limit, "-tw"))
+       && subtag_matches (lang_str, limit, "-tw", 3))
     {
       /* Northern Ping Chinese; Taiwan, Province of China */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2104,7 +2121,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "px-", 3)
-       && subtag_matches (lang_str, limit, "-hk"))
+       && subtag_matches (lang_str, limit, "-hk", 3))
     {
       /* Pu-Xian Chinese; Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
@@ -2112,7 +2129,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "px-", 3)
-       && subtag_matches (lang_str, limit, "-mo"))
+       && subtag_matches (lang_str, limit, "-mo", 3))
     {
       /* Pu-Xian Chinese; Macao */
       unsigned int i;
@@ -2126,7 +2143,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "px-", 3)
-       && subtag_matches (lang_str, limit, "-tw"))
+       && subtag_matches (lang_str, limit, "-tw", 3))
     {
       /* Pu-Xian Chinese; Taiwan, Province of China */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2134,7 +2151,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "sp-", 3)
-       && subtag_matches (lang_str, limit, "-hk"))
+       && subtag_matches (lang_str, limit, "-hk", 3))
     {
       /* Southern Ping Chinese; Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
@@ -2142,7 +2159,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "sp-", 3)
-       && subtag_matches (lang_str, limit, "-mo"))
+       && subtag_matches (lang_str, limit, "-mo", 3))
     {
       /* Southern Ping Chinese; Macao */
       unsigned int i;
@@ -2156,7 +2173,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "sp-", 3)
-       && subtag_matches (lang_str, limit, "-tw"))
+       && subtag_matches (lang_str, limit, "-tw", 3))
     {
       /* Southern Ping Chinese; Taiwan, Province of China */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2164,7 +2181,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "zh-", 3)
-       && subtag_matches (lang_str, limit, "-hk"))
+       && subtag_matches (lang_str, limit, "-hk", 3))
     {
       /* Huizhou Chinese; Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
@@ -2172,7 +2189,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "zh-", 3)
-       && subtag_matches (lang_str, limit, "-mo"))
+       && subtag_matches (lang_str, limit, "-mo", 3))
     {
       /* Huizhou Chinese; Macao */
       unsigned int i;
@@ -2186,7 +2203,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "zh-", 3)
-       && subtag_matches (lang_str, limit, "-tw"))
+       && subtag_matches (lang_str, limit, "-tw", 3))
     {
       /* Huizhou Chinese; Taiwan, Province of China */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2194,7 +2211,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "zo-", 3)
-       && subtag_matches (lang_str, limit, "-hk"))
+       && subtag_matches (lang_str, limit, "-hk", 3))
     {
       /* Min Zhong Chinese; Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
@@ -2202,7 +2219,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "zo-", 3)
-       && subtag_matches (lang_str, limit, "-mo"))
+       && subtag_matches (lang_str, limit, "-mo", 3))
     {
       /* Min Zhong Chinese; Macao */
       unsigned int i;
@@ -2216,7 +2233,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "zo-", 3)
-       && subtag_matches (lang_str, limit, "-tw"))
+       && subtag_matches (lang_str, limit, "-tw", 3))
     {
       /* Min Zhong Chinese; Taiwan, Province of China */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2225,14 +2242,14 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
     }
     break;
   case 'g':
-    if (lang_matches (&lang_str[1], "an-hant-hk"))
+    if (lang_matches (&lang_str[1], limit, "an-hant-hk", 10))
     {
       /* Gan Chinese; Han (Traditional variant); Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "an-hant-mo"))
+    if (lang_matches (&lang_str[1], limit, "an-hant-mo", 10))
     {
       /* Gan Chinese; Han (Traditional variant); Macao */
       unsigned int i;
@@ -2245,21 +2262,21 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       *count = i;
       return true;
     }
-    if (lang_matches (&lang_str[1], "an-hans"))
+    if (lang_matches (&lang_str[1], limit, "an-hans", 7))
     {
       /* Gan Chinese; Han (Simplified variant) */
       tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "an-hant"))
+    if (lang_matches (&lang_str[1], limit, "an-hant", 7))
     {
       /* Gan Chinese; Han (Traditional variant) */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "a-latg"))
+    if (lang_matches (&lang_str[1], limit, "a-latg", 6))
     {
       /* Irish; Latin (Gaelic variant) */
       tags[0] = HB_TAG('I','R','T',' ');  /* Irish Traditional */
@@ -2267,7 +2284,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "an-", 3)
-       && subtag_matches (lang_str, limit, "-hk"))
+       && subtag_matches (lang_str, limit, "-hk", 3))
     {
       /* Gan Chinese; Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
@@ -2275,7 +2292,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "an-", 3)
-       && subtag_matches (lang_str, limit, "-mo"))
+       && subtag_matches (lang_str, limit, "-mo", 3))
     {
       /* Gan Chinese; Macao */
       unsigned int i;
@@ -2289,7 +2306,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "an-", 3)
-       && subtag_matches (lang_str, limit, "-tw"))
+       && subtag_matches (lang_str, limit, "-tw", 3))
     {
       /* Gan Chinese; Taiwan, Province of China */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2298,14 +2315,14 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
     }
     break;
   case 'h':
-    if (lang_matches (&lang_str[1], "ak-hant-hk"))
+    if (lang_matches (&lang_str[1], limit, "ak-hant-hk", 10))
     {
       /* Hakka Chinese; Han (Traditional variant); Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "ak-hant-mo"))
+    if (lang_matches (&lang_str[1], limit, "ak-hant-mo", 10))
     {
       /* Hakka Chinese; Han (Traditional variant); Macao */
       unsigned int i;
@@ -2318,14 +2335,14 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       *count = i;
       return true;
     }
-    if (lang_matches (&lang_str[1], "sn-hant-hk"))
+    if (lang_matches (&lang_str[1], limit, "sn-hant-hk", 10))
     {
       /* Xiang Chinese; Han (Traditional variant); Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "sn-hant-mo"))
+    if (lang_matches (&lang_str[1], limit, "sn-hant-mo", 10))
     {
       /* Xiang Chinese; Han (Traditional variant); Macao */
       unsigned int i;
@@ -2338,28 +2355,28 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       *count = i;
       return true;
     }
-    if (lang_matches (&lang_str[1], "ak-hans"))
+    if (lang_matches (&lang_str[1], limit, "ak-hans", 7))
     {
       /* Hakka Chinese; Han (Simplified variant) */
       tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "ak-hant"))
+    if (lang_matches (&lang_str[1], limit, "ak-hant", 7))
     {
       /* Hakka Chinese; Han (Traditional variant) */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "sn-hans"))
+    if (lang_matches (&lang_str[1], limit, "sn-hans", 7))
     {
       /* Xiang Chinese; Han (Simplified variant) */
       tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "sn-hant"))
+    if (lang_matches (&lang_str[1], limit, "sn-hant", 7))
     {
       /* Xiang Chinese; Han (Traditional variant) */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2367,7 +2384,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "ak-", 3)
-       && subtag_matches (lang_str, limit, "-hk"))
+       && subtag_matches (lang_str, limit, "-hk", 3))
     {
       /* Hakka Chinese; Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
@@ -2375,7 +2392,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "ak-", 3)
-       && subtag_matches (lang_str, limit, "-mo"))
+       && subtag_matches (lang_str, limit, "-mo", 3))
     {
       /* Hakka Chinese; Macao */
       unsigned int i;
@@ -2389,7 +2406,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "ak-", 3)
-       && subtag_matches (lang_str, limit, "-tw"))
+       && subtag_matches (lang_str, limit, "-tw", 3))
     {
       /* Hakka Chinese; Taiwan, Province of China */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2397,7 +2414,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "sn-", 3)
-       && subtag_matches (lang_str, limit, "-hk"))
+       && subtag_matches (lang_str, limit, "-hk", 3))
     {
       /* Xiang Chinese; Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
@@ -2405,7 +2422,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "sn-", 3)
-       && subtag_matches (lang_str, limit, "-mo"))
+       && subtag_matches (lang_str, limit, "-mo", 3))
     {
       /* Xiang Chinese; Macao */
       unsigned int i;
@@ -2419,7 +2436,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "sn-", 3)
-       && subtag_matches (lang_str, limit, "-tw"))
+       && subtag_matches (lang_str, limit, "-tw", 3))
     {
       /* Xiang Chinese; Taiwan, Province of China */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2457,7 +2474,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
     }
     break;
   case 'l':
-    if (lang_matches (&lang_str[1], "zh-hans"))
+    if (lang_matches (&lang_str[1], limit, "zh-hans", 7))
     {
       /* Literary Chinese; Han (Simplified variant) */
       tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
@@ -2466,14 +2483,14 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
     }
     break;
   case 'm':
-    if (lang_matches (&lang_str[1], "np-hant-hk"))
+    if (lang_matches (&lang_str[1], limit, "np-hant-hk", 10))
     {
       /* Min Bei Chinese; Han (Traditional variant); Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "np-hant-mo"))
+    if (lang_matches (&lang_str[1], limit, "np-hant-mo", 10))
     {
       /* Min Bei Chinese; Han (Traditional variant); Macao */
       unsigned int i;
@@ -2486,14 +2503,14 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       *count = i;
       return true;
     }
-    if (lang_matches (&lang_str[1], "np-hans"))
+    if (lang_matches (&lang_str[1], limit, "np-hans", 7))
     {
       /* Min Bei Chinese; Han (Simplified variant) */
       tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "np-hant"))
+    if (lang_matches (&lang_str[1], limit, "np-hant", 7))
     {
       /* Min Bei Chinese; Han (Traditional variant) */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2501,7 +2518,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "np-", 3)
-       && subtag_matches (lang_str, limit, "-hk"))
+       && subtag_matches (lang_str, limit, "-hk", 3))
     {
       /* Min Bei Chinese; Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
@@ -2509,7 +2526,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "np-", 3)
-       && subtag_matches (lang_str, limit, "-mo"))
+       && subtag_matches (lang_str, limit, "-mo", 3))
     {
       /* Min Bei Chinese; Macao */
       unsigned int i;
@@ -2523,7 +2540,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "np-", 3)
-       && subtag_matches (lang_str, limit, "-tw"))
+       && subtag_matches (lang_str, limit, "-tw", 3))
     {
       /* Min Bei Chinese; Taiwan, Province of China */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2531,7 +2548,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "nw-", 3)
-       && subtag_matches (lang_str, limit, "-th"))
+       && subtag_matches (lang_str, limit, "-th", 3))
     {
       /* Mon; Thailand */
       tags[0] = HB_TAG('M','O','N','T');  /* Thailand Mon */
@@ -2540,14 +2557,14 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
     }
     break;
   case 'n':
-    if (lang_matches (&lang_str[1], "an-hant-hk"))
+    if (lang_matches (&lang_str[1], limit, "an-hant-hk", 10))
     {
       /* Min Nan Chinese; Han (Traditional variant); Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "an-hant-mo"))
+    if (lang_matches (&lang_str[1], limit, "an-hant-mo", 10))
     {
       /* Min Nan Chinese; Han (Traditional variant); Macao */
       unsigned int i;
@@ -2560,14 +2577,14 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       *count = i;
       return true;
     }
-    if (lang_matches (&lang_str[1], "an-hans"))
+    if (lang_matches (&lang_str[1], limit, "an-hans", 7))
     {
       /* Min Nan Chinese; Han (Simplified variant) */
       tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "an-hant"))
+    if (lang_matches (&lang_str[1], limit, "an-hant", 7))
     {
       /* Min Nan Chinese; Han (Traditional variant) */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2575,7 +2592,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "an-", 3)
-       && subtag_matches (lang_str, limit, "-hk"))
+       && subtag_matches (lang_str, limit, "-hk", 3))
     {
       /* Min Nan Chinese; Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
@@ -2583,7 +2600,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "an-", 3)
-       && subtag_matches (lang_str, limit, "-mo"))
+       && subtag_matches (lang_str, limit, "-mo", 3))
     {
       /* Min Nan Chinese; Macao */
       unsigned int i;
@@ -2597,7 +2614,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "an-", 3)
-       && subtag_matches (lang_str, limit, "-tw"))
+       && subtag_matches (lang_str, limit, "-tw", 3))
     {
       /* Min Nan Chinese; Taiwan, Province of China */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2621,7 +2638,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
     break;
   case 'r':
     if (0 == strncmp (&lang_str[1], "o-", 2)
-       && subtag_matches (lang_str, limit, "-md"))
+       && subtag_matches (lang_str, limit, "-md", 3))
     {
       /* Romanian; Moldova */
       unsigned int i;
@@ -2636,14 +2653,14 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
     }
     break;
   case 'w':
-    if (lang_matches (&lang_str[1], "uu-hant-hk"))
+    if (lang_matches (&lang_str[1], limit, "uu-hant-hk", 10))
     {
       /* Wu Chinese; Han (Traditional variant); Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "uu-hant-mo"))
+    if (lang_matches (&lang_str[1], limit, "uu-hant-mo", 10))
     {
       /* Wu Chinese; Han (Traditional variant); Macao */
       unsigned int i;
@@ -2656,14 +2673,14 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       *count = i;
       return true;
     }
-    if (lang_matches (&lang_str[1], "uu-hans"))
+    if (lang_matches (&lang_str[1], limit, "uu-hans", 7))
     {
       /* Wu Chinese; Han (Simplified variant) */
       tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "uu-hant"))
+    if (lang_matches (&lang_str[1], limit, "uu-hant", 7))
     {
       /* Wu Chinese; Han (Traditional variant) */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2671,7 +2688,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "uu-", 3)
-       && subtag_matches (lang_str, limit, "-hk"))
+       && subtag_matches (lang_str, limit, "-hk", 3))
     {
       /* Wu Chinese; Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
@@ -2679,7 +2696,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "uu-", 3)
-       && subtag_matches (lang_str, limit, "-mo"))
+       && subtag_matches (lang_str, limit, "-mo", 3))
     {
       /* Wu Chinese; Macao */
       unsigned int i;
@@ -2693,7 +2710,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "uu-", 3)
-       && subtag_matches (lang_str, limit, "-tw"))
+       && subtag_matches (lang_str, limit, "-tw", 3))
     {
       /* Wu Chinese; Taiwan, Province of China */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2702,7 +2719,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
     }
     break;
   case 'y':
-    if (lang_matches (&lang_str[1], "ue-hans"))
+    if (lang_matches (&lang_str[1], limit, "ue-hans", 7))
     {
       /* Yue Chinese; Han (Simplified variant) */
       tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
@@ -2711,14 +2728,14 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
     }
     break;
   case 'z':
-    if (lang_matches (&lang_str[1], "h-hant-hk"))
+    if (lang_matches (&lang_str[1], limit, "h-hant-hk", 9))
     {
       /* Chinese [macrolanguage]; Han (Traditional variant); Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "h-hant-mo"))
+    if (lang_matches (&lang_str[1], limit, "h-hant-mo", 9))
     {
       /* Chinese [macrolanguage]; Han (Traditional variant); Macao */
       unsigned int i;
@@ -2738,14 +2755,14 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "h-hans"))
+    if (lang_matches (&lang_str[1], limit, "h-hans", 6))
     {
       /* Chinese [macrolanguage]; Han (Simplified variant) */
       tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
-    if (lang_matches (&lang_str[1], "h-hant"))
+    if (lang_matches (&lang_str[1], limit, "h-hant", 6))
     {
       /* Chinese [macrolanguage]; Han (Traditional variant) */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2760,7 +2777,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "h-", 2)
-       && subtag_matches (lang_str, limit, "-hk"))
+       && subtag_matches (lang_str, limit, "-hk", 3))
     {
       /* Chinese [macrolanguage]; Hong Kong */
       tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
@@ -2768,7 +2785,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "h-", 2)
-       && subtag_matches (lang_str, limit, "-mo"))
+       && subtag_matches (lang_str, limit, "-mo", 3))
     {
       /* Chinese [macrolanguage]; Macao */
       unsigned int i;
@@ -2782,7 +2799,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
       return true;
     }
     if (0 == strncmp (&lang_str[1], "h-", 2)
-       && subtag_matches (lang_str, limit, "-tw"))
+       && subtag_matches (lang_str, limit, "-tw", 3))
     {
       /* Chinese [macrolanguage]; Taiwan, Province of China */
       tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
@@ -2806,7 +2823,7 @@ hb_ot_tags_from_complex_language (const char   *lang_str,
  * 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
+static inline hb_language_t
 hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
 {
   switch (tag)
index f50be97..53b6b38 100644 (file)
@@ -119,6 +119,17 @@ hb_ot_new_tag_to_script (hb_tag_t tag)
 }
 
 #ifndef HB_DISABLE_DEPRECATED
+/**
+ * hb_ot_tags_from_script:
+ * @script: an #hb_script_t to convert.
+ * @script_tag_1: (out): output #hb_tag_t.
+ * @script_tag_2: (out): output #hb_tag_t.
+ *
+ * Converts an #hb_script_t to script tags.
+ *
+ * Since: 0.6.0
+ * Deprecated: 2.0.0: use hb_ot_tags_from_script_and_language() instead
+ **/
 void
 hb_ot_tags_from_script (hb_script_t  script,
                        hb_tag_t    *script_tag_1,
@@ -189,48 +200,48 @@ hb_ot_tag_to_script (hb_tag_t tag)
 
 /* hb_language_t */
 
-static bool
+static inline bool
 subtag_matches (const char *lang_str,
                const char *limit,
-               const char *subtag)
+               const char *subtag,
+               unsigned    subtag_len)
 {
+  if (likely ((unsigned) (limit - lang_str) < subtag_len))
+    return false;
+
   do {
     const char *s = strstr (lang_str, subtag);
     if (!s || s >= limit)
       return false;
-    if (!ISALNUM (s[strlen (subtag)]))
+    if (!ISALNUM (s[subtag_len]))
       return true;
-    lang_str = s + strlen (subtag);
+    lang_str = s + subtag_len;
   } while (true);
 }
 
-static hb_bool_t
-lang_matches (const char *lang_str, const char *spec)
+static bool
+lang_matches (const char *lang_str,
+             const char *limit,
+             const char *spec,
+             unsigned    spec_len)
 {
-  unsigned int len = strlen (spec);
+  /* Same as hb_language_matches(); duplicated. */
+
+  if (likely ((unsigned) (limit - lang_str) < spec_len))
+    return false;
 
-  return strncmp (lang_str, spec, len) == 0 &&
-        (lang_str[len] == '\0' || lang_str[len] == '-');
+  return strncmp (lang_str, spec, spec_len) == 0 &&
+        (lang_str[spec_len] == '\0' || lang_str[spec_len] == '-');
 }
 
 struct LangTag
 {
-  char language[4];
+  hb_tag_t language;
   hb_tag_t tag;
 
-  int cmp (const char *a) const
+  int cmp (hb_tag_t a) const
   {
-    const char *b = this->language;
-    unsigned int da, db;
-    const char *p;
-
-    p = strchr (a, '-');
-    da = p ? (unsigned int) (p - a) : strlen (a);
-
-    p = strchr (b, '-');
-    db = p ? (unsigned int) (p - b) : strlen (b);
-
-    return strncmp (a, b, hb_max (da, db));
+    return a < this->language ? -1 : a > this->language ? +1 : 0;
   }
   int cmp (const LangTag *that) const
   { return cmp (that->language); }
@@ -249,6 +260,15 @@ struct LangTag
 /*{"zh?",      {HB_TAG('Z','H','P',' ')}},*/   /* Chinese Phonetic */
 
 #ifndef HB_DISABLE_DEPRECATED
+/**
+ * hb_ot_tag_from_language:
+ * @language: an #hb_language_t to convert.
+ *
+ * Converts an #hb_language_t to an #hb_tag_t.
+ *
+ * Since: 0.6.0
+ * Deprecated: 2.0.0: use hb_ot_tags_from_script_and_language() instead
+ **/
 hb_tag_t
 hb_ot_tag_from_language (hb_language_t language)
 {
@@ -265,16 +285,19 @@ hb_ot_tags_from_language (const char   *lang_str,
                          unsigned int *count,
                          hb_tag_t     *tags)
 {
-  const char *s;
-  unsigned int tag_idx;
 
+#ifndef HB_NO_LANGUAGE_LONG
   /* Check for matches of multiple subtags. */
   if (hb_ot_tags_from_complex_language (lang_str, limit, count, tags))
     return;
+#endif
 
   /* Find a language matching in the first component. */
-  s = strchr (lang_str, '-');
+#ifndef HB_NO_LANGUAGE_LONG
+  const char *s; s = strchr (lang_str, '-');
+#endif
   {
+#ifndef HB_NO_LANGUAGE_LONG
     if (s && limit - lang_str >= 6)
     {
       const char *extlang_end = strchr (s + 1, '-');
@@ -283,17 +306,42 @@ hb_ot_tags_from_language (const char   *lang_str,
          ISALPHA (s[1]))
        lang_str = s + 1;
     }
-    if (hb_sorted_array (ot_languages).bfind (lang_str, &tag_idx))
+#endif
+    const LangTag *ot_languages = nullptr;
+    unsigned ot_languages_len = 0;
+    const char *dash = strchr (lang_str, '-');
+    unsigned first_len = dash ? dash - lang_str : limit - lang_str;
+    if (first_len == 2)
+    {
+      ot_languages = ot_languages2;
+      ot_languages_len = ARRAY_LENGTH (ot_languages2);
+    }
+#ifndef HB_NO_LANGUAGE_LONG
+    else if (first_len == 3)
     {
+      ot_languages = ot_languages3;
+      ot_languages_len = ARRAY_LENGTH (ot_languages3);
+    }
+#endif
+
+    hb_tag_t lang_tag = hb_tag_from_string (lang_str, first_len);
+
+    static hb_atomic_int_t last_tag_idx; /* Poor man's cache. */
+    unsigned tag_idx = last_tag_idx;
+
+    if (likely (tag_idx < ot_languages_len && ot_languages[tag_idx].language == lang_tag) ||
+       hb_sorted_array (ot_languages, ot_languages_len).bfind (lang_tag, &tag_idx))
+    {
+      last_tag_idx = tag_idx;
       unsigned int i;
       while (tag_idx != 0 &&
-            0 == strcmp (ot_languages[tag_idx].language, ot_languages[tag_idx - 1].language))
+            ot_languages[tag_idx].language == ot_languages[tag_idx - 1].language)
        tag_idx--;
       for (i = 0;
           i < *count &&
-          tag_idx + i < ARRAY_LENGTH (ot_languages) &&
+          tag_idx + i < ot_languages_len &&
           ot_languages[tag_idx + i].tag != HB_TAG_NONE &&
-          0 == strcmp (ot_languages[tag_idx + i].language, ot_languages[tag_idx].language);
+          ot_languages[tag_idx + i].language == ot_languages[tag_idx].language;
           i++)
        tags[i] = ot_languages[tag_idx + i].tag;
       *count = i;
@@ -301,6 +349,7 @@ hb_ot_tags_from_language (const char   *lang_str,
     }
   }
 
+#ifndef HB_NO_LANGUAGE_LONG
   if (!s)
     s = lang_str + strlen (lang_str);
   if (s - lang_str == 3) {
@@ -309,6 +358,7 @@ hb_ot_tags_from_language (const char   *lang_str,
     *count = 1;
     return;
   }
+#endif
 
   *count = 0;
 }
@@ -362,7 +412,7 @@ parse_private_use_subtag (const char     *private_use_subtag,
 /**
  * hb_ot_tags_from_script_and_language:
  * @script: an #hb_script_t to convert.
- * @language: an #hb_language_t to convert.
+ * @language: (nullable): an #hb_language_t to convert.
  * @script_count: (inout) (optional): maximum number of script tags to retrieve (IN)
  * and actual number of script tags retrieved (OUT)
  * @script_tags: (out) (optional): array of size at least @script_count to store the
@@ -453,15 +503,29 @@ hb_ot_tag_to_language (hb_tag_t tag)
   if (tag == HB_OT_TAG_DEFAULT_LANGUAGE)
     return nullptr;
 
+#ifndef HB_NO_LANGUAGE_LONG
   {
     hb_language_t disambiguated_tag = hb_ot_ambiguous_tag_to_language (tag);
     if (disambiguated_tag != HB_LANGUAGE_INVALID)
       return disambiguated_tag;
   }
+#endif
 
-  for (i = 0; i < ARRAY_LENGTH (ot_languages); i++)
-    if (ot_languages[i].tag == tag)
-      return hb_language_from_string (ot_languages[i].language, -1);
+  char buf[4];
+  for (i = 0; i < ARRAY_LENGTH (ot_languages2); i++)
+    if (ot_languages2[i].tag == tag)
+    {
+      hb_tag_to_string (ot_languages2[i].language, buf);
+      return hb_language_from_string (buf, 2);
+    }
+#ifndef HB_NO_LANGUAGE_LONG
+  for (i = 0; i < ARRAY_LENGTH (ot_languages3); i++)
+    if (ot_languages3[i].tag == tag)
+    {
+      hb_tag_to_string (ot_languages3[i].language, buf);
+      return hb_language_from_string (buf, 3);
+    }
+#endif
 
   /* Return a custom language in the form of "x-hbot-AABBCCDD".
    * If it's three letters long, also guess it's ISO 639-3 and lower-case and
@@ -533,7 +597,7 @@ hb_ot_tags_to_script_and_language (hb_tag_t       script_tag,
       else
       {
        int shift;
-       memcpy (buf, lang_str, len);
+       hb_memcpy (buf, lang_str, len);
        if (lang_str[0] != 'x' || lang_str[1] != '-') {
          buf[len++] = '-';
          buf[len++] = 'x';
@@ -557,16 +621,28 @@ hb_ot_tags_to_script_and_language (hb_tag_t       script_tag,
 static inline void
 test_langs_sorted ()
 {
-  for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages); i++)
+  for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages2); i++)
+  {
+    int c = ot_languages2[i].cmp (&ot_languages2[i - 1]);
+    if (c > 0)
+    {
+      fprintf (stderr, "ot_languages2 not sorted at index %u: %08x %d %08x\n",
+              i, ot_languages2[i-1].language, c, ot_languages2[i].language);
+      abort();
+    }
+  }
+#ifndef HB_NO_LANGUAGE_LONG
+  for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages3); i++)
   {
-    int c = ot_languages[i].cmp (&ot_languages[i - 1]);
+    int c = ot_languages3[i].cmp (&ot_languages3[i - 1]);
     if (c > 0)
     {
-      fprintf (stderr, "ot_languages not sorted at index %d: %s %d %s\n",
-              i, ot_languages[i-1].language, c, ot_languages[i].language);
+      fprintf (stderr, "ot_languages3 not sorted at index %u: %08x %d %08x\n",
+              i, ot_languages3[i-1].language, c, ot_languages3[i].language);
       abort();
     }
   }
+#endif
 }
 
 int
index 65f26c1..f3754aa 100644 (file)
@@ -28,6 +28,8 @@
 #define HB_OT_VAR_AVAR_TABLE_HH
 
 #include "hb-open-type.hh"
+#include "hb-ot-var-common.hh"
+
 
 /*
  * avar -- Axis Variations
 namespace OT {
 
 
+/* "Spec": https://github.com/be-fonts/boring-expansion-spec/issues/14 */
+struct avarV2Tail
+{
+  friend struct avar;
+
+  bool sanitize (hb_sanitize_context_t *c,
+                const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (varIdxMap.sanitize (c, base) &&
+                 varStore.sanitize (c, base));
+  }
+
+  protected:
+  Offset32To<DeltaSetIndexMap> varIdxMap;      /* Offset from the beginning of 'avar' table. */
+  Offset32To<VariationStore>   varStore;       /* Offset from the beginning of 'avar' table. */
+
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+
 struct AxisValueMap
 {
   bool sanitize (hb_sanitize_context_t *c) const
@@ -48,6 +72,65 @@ struct AxisValueMap
     return_trace (c->check_struct (this));
   }
 
+  void set_mapping (float from_coord, float to_coord)
+  {
+    coords[0].set_float (from_coord);
+    coords[1].set_float (to_coord);
+  }
+
+  bool is_outside_axis_range (const Triple& axis_range) const
+  {
+    float from_coord = coords[0].to_float ();
+    return !axis_range.contains (from_coord);
+  }
+
+  bool must_include () const
+  {
+    float from_coord = coords[0].to_float ();
+    float to_coord = coords[1].to_float ();
+    return (from_coord == -1.f && to_coord == -1.f) ||
+           (from_coord == 0.f && to_coord == 0.f) ||
+           (from_coord == 1.f && to_coord == 1.f);
+  }
+
+  void instantiate (const Triple& axis_range,
+                    const Triple& unmapped_range,
+                    const TripleDistances& triple_distances)
+  {
+    float from_coord = coords[0].to_float ();
+    float to_coord = coords[1].to_float ();
+
+    from_coord = renormalizeValue (from_coord, unmapped_range, triple_distances);
+    to_coord = renormalizeValue (to_coord, axis_range, triple_distances);
+
+    coords[0].set_float (from_coord);
+    coords[1].set_float (to_coord);
+  }
+
+  HB_INTERNAL static int cmp (const void *pa, const void *pb)
+  {
+    const AxisValueMap *a = (const AxisValueMap *) pa;
+    const AxisValueMap *b = (const AxisValueMap *) pb;
+
+    int a_from = a->coords[0].to_int ();
+    int b_from = b->coords[0].to_int ();
+    if (a_from != b_from)
+      return a_from - b_from;
+
+    /* this should never be reached. according to the spec, all of the axis
+     * value map records for a given axis must have different fromCoord values
+     * */
+    int a_to = a->coords[1].to_int ();
+    int b_to = b->coords[1].to_int ();
+    return a_to - b_to;
+  }
+
+  bool serialize (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (c->embed (this));
+  }
+
   public:
   F2DOT14      coords[2];
 //   F2DOT14   fromCoord;      /* A normalized coordinate value obtained using
@@ -62,8 +145,8 @@ struct SegmentMaps : Array16Of<AxisValueMap>
 {
   int map (int value, unsigned int from_offset = 0, unsigned int to_offset = 1) const
   {
-#define fromCoord coords[from_offset]
-#define toCoord coords[to_offset]
+#define fromCoord coords[from_offset].to_int ()
+#define toCoord coords[to_offset].to_int ()
     /* 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
      * part of a better error recovery scheme. */
@@ -98,6 +181,78 @@ struct SegmentMaps : Array16Of<AxisValueMap>
 
   int unmap (int value) const { return map (value, 1, 0); }
 
+  Triple unmap_axis_range (const Triple& axis_range) const
+  {
+    F2DOT14 val, unmapped_val;
+
+    val.set_float (axis_range.minimum);
+    unmapped_val.set_int (unmap (val.to_int ()));
+    float unmapped_min = unmapped_val.to_float ();
+
+    val.set_float (axis_range.middle);
+    unmapped_val.set_int (unmap (val.to_int ()));
+    float unmapped_middle = unmapped_val.to_float ();
+
+    val.set_float (axis_range.maximum);
+    unmapped_val.set_int (unmap (val.to_int ()));
+    float unmapped_max = unmapped_val.to_float ();
+
+    return Triple{unmapped_min, unmapped_middle, unmapped_max};
+  }
+
+  bool subset (hb_subset_context_t *c, hb_tag_t axis_tag) const
+  {
+    TRACE_SUBSET (this);
+    /* avar mapped normalized axis range*/
+    Triple *axis_range;
+    if (!c->plan->axes_location.has (axis_tag, &axis_range))
+      return c->serializer->embed (*this);
+
+    TripleDistances *axis_triple_distances;
+    if (!c->plan->axes_triple_distances.has (axis_tag, &axis_triple_distances))
+      return_trace (false);
+
+    auto *out = c->serializer->start_embed (this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    Triple unmapped_range = unmap_axis_range (*axis_range);
+
+    /* create a vector of retained mappings and sort */
+    hb_vector_t<AxisValueMap> value_mappings;
+    for (const auto& _ : as_array ())
+    {
+      if (_.is_outside_axis_range (unmapped_range))
+        continue;
+      AxisValueMap mapping;
+      mapping = _;
+      mapping.instantiate (*axis_range, unmapped_range, *axis_triple_distances);
+      /* (-1, -1), (0, 0), (1, 1) mappings will be added later, so avoid
+       * duplicates here */
+      if (mapping.must_include ())
+        continue;
+      value_mappings.push (std::move (mapping));
+    }
+
+    AxisValueMap m;
+    m.set_mapping (-1.f, -1.f);
+    value_mappings.push (m);
+
+    m.set_mapping (0.f, 0.f);
+    value_mappings.push (m);
+
+    m.set_mapping (1.f, 1.f);
+    value_mappings.push (m);
+
+    value_mappings.qsort ();
+
+    for (const auto& _ : value_mappings)
+    {
+      if (!_.serialize (c->serializer))
+        return_trace (false);
+    }
+    return_trace (c->serializer->check_assign (out->len, value_mappings.length, HB_SERIALIZE_ERROR_INT_OVERFLOW));
+  }
+
   public:
   DEFINE_SIZE_ARRAY (2, *this);
 };
@@ -106,12 +261,24 @@ struct avar
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_avar;
 
+  bool has_data () const { return version.to_int (); }
+
+  const SegmentMaps* get_segment_maps () const
+  { return &firstAxisSegmentMaps; }
+
+  unsigned get_axis_count () const
+  { return axisCount; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (unlikely (!(version.sanitize (c) &&
-                   version.major == 1 &&
-                   c->check_struct (this))))
+    if (!(version.sanitize (c) &&
+         (version.major == 1
+#ifndef HB_NO_AVAR2
+          || version.major == 2
+#endif
+          ) &&
+         c->check_struct (this)))
       return_trace (false);
 
     const SegmentMaps *map = &firstAxisSegmentMaps;
@@ -123,6 +290,15 @@ struct avar
       map = &StructAfter<SegmentMaps> (*map);
     }
 
+#ifndef HB_NO_AVAR2
+    if (version.major < 2)
+      return_trace (true);
+
+    const auto &v2 = * (const avarV2Tail *) map;
+    if (unlikely (!v2.sanitize (c, this)))
+      return_trace (false);
+#endif
+
     return_trace (true);
   }
 
@@ -136,6 +312,36 @@ struct avar
       coords[i] = map->map (coords[i]);
       map = &StructAfter<SegmentMaps> (*map);
     }
+
+#ifndef HB_NO_AVAR2
+    if (version.major < 2)
+      return;
+
+    for (; count < axisCount; count++)
+      map = &StructAfter<SegmentMaps> (*map);
+
+    const auto &v2 = * (const avarV2Tail *) map;
+
+    const auto &varidx_map = this+v2.varIdxMap;
+    const auto &var_store = this+v2.varStore;
+    auto *var_store_cache = var_store.create_cache ();
+
+    hb_vector_t<int> out;
+    out.alloc (coords_length);
+    for (unsigned i = 0; i < coords_length; i++)
+    {
+      int v = coords[i];
+      uint32_t varidx = varidx_map.map (i);
+      float delta = var_store.get_delta (varidx, coords, coords_length, var_store_cache);
+      v += roundf (delta);
+      v = hb_clamp (v, -(1<<14), +(1<<14));
+      out.push (v);
+    }
+    for (unsigned i = 0; i < coords_length; i++)
+      coords[i] = out[i];
+
+    OT::VariationStore::destroy_cache (var_store_cache);
+#endif
   }
 
   void unmap_coords (int *coords, unsigned int coords_length) const
@@ -150,6 +356,39 @@ struct avar
     }
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    unsigned retained_axis_count = c->plan->axes_index_map.get_population ();
+    if (!retained_axis_count) //all axes are pinned/dropped
+      return_trace (false);
+
+    avar *out = c->serializer->allocate_min<avar> ();
+    if (unlikely (!out)) return_trace (false);
+
+    out->version.major = 1;
+    out->version.minor = 0;
+    if (!c->serializer->check_assign (out->axisCount, retained_axis_count, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+      return_trace (false);
+
+    const hb_map_t& axes_index_map = c->plan->axes_index_map;
+    const SegmentMaps *map = &firstAxisSegmentMaps;
+    unsigned count = axisCount;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      if (axes_index_map.has (i))
+      {
+        hb_tag_t *axis_tag;
+        if (!c->plan->axes_old_index_tag_map.has (i, &axis_tag))
+          return_trace (false);
+        if (!map->subset (c, *axis_tag))
+          return_trace (false);
+      }
+      map = &StructAfter<SegmentMaps> (*map);
+    }
+    return_trace (true);
+  }
+
   protected:
   FixedVersion<>version;       /* Version of the avar table
                                 * initially set to 0x00010000u */
index 0eafb94..b6fe13f 100644 (file)
 #define HB_OT_VAR_COMMON_HH
 
 #include "hb-ot-layout-common.hh"
+#include "hb-priority-queue.hh"
 
 
 namespace OT {
 
-struct DeltaSetIndexMapFormat0
+template <typename MapCountT>
+struct DeltaSetIndexMapFormat01
 {
   friend struct DeltaSetIndexMap;
 
+  unsigned get_size () const
+  { return min_size + mapCount * get_width (); }
+
   private:
-  DeltaSetIndexMapFormat0* copy (hb_serialize_context_t *c) const
+  DeltaSetIndexMapFormat01* copy (hb_serialize_context_t *c) const
   {
     TRACE_SERIALIZE (this);
-    auto *out = c->start_embed (this);
-    if (unlikely (!out)) return_trace (nullptr);
-
-    unsigned total_size = min_size + mapCount * get_width ();
-    HBUINT8 *p = c->allocate_size<HBUINT8> (total_size);
-    if (unlikely (!p)) return_trace (nullptr);
-
-    memcpy (p, this, HBUINT8::static_size * total_size);
-    return_trace (out);
+    return_trace (c->embed (this));
   }
 
   template <typename T>
@@ -68,14 +65,17 @@ struct DeltaSetIndexMapFormat0
     if (unlikely (!p)) return_trace (false);
     for (unsigned int i = 0; i < output_map.length; i++)
     {
-      unsigned int v = output_map[i];
-      unsigned int outer = v >> 16;
-      unsigned int inner = v & 0xFFFF;
-      unsigned int u = (outer << inner_bit_count) | inner;
-      for (unsigned int w = width; w > 0;)
+      unsigned int v = output_map.arrayZ[i];
+      if (v)
       {
-        p[--w] = u;
-        u >>= 8;
+       unsigned int outer = v >> 16;
+       unsigned int inner = v & 0xFFFF;
+       unsigned int u = (outer << inner_bit_count) | inner;
+       for (unsigned int w = width; w > 0;)
+       {
+         p[--w] = u;
+         u >>= 8;
+       }
       }
       p += width;
     }
@@ -128,56 +128,12 @@ struct DeltaSetIndexMapFormat0
   HBUINT8       format;         /* Format identifier--format = 0 */
   HBUINT8       entryFormat;    /* A packed field that describes the compressed
                                  * representation of delta-set indices. */
-  HBUINT16      mapCount;       /* The number of mapping entries. */
-  UnsizedArrayOf<HBUINT8>
-                mapDataZ;       /* The delta-set index mapping data. */
-
-  public:
-  DEFINE_SIZE_ARRAY (4, mapDataZ);
-};
-
-struct DeltaSetIndexMapFormat1
-{
-  friend struct DeltaSetIndexMap;
-
-  private:
-  DeltaSetIndexMapFormat1* copy (hb_serialize_context_t *c) const
-  {
-    TRACE_SERIALIZE (this);
-    auto *out = c->start_embed (this);
-    if (unlikely (!out)) return_trace (nullptr);
-
-    unsigned total_size = min_size + mapCount * get_width ();
-    HBUINT8 *p = c->allocate_size<HBUINT8> (total_size);
-    if (unlikely (!p)) return_trace (nullptr);
-
-    memcpy (p, this, HBUINT8::static_size * total_size);
-    return_trace (out);
-  }
-
-  unsigned get_map_count () const       { return mapCount; }
-  unsigned get_width () const           { return ((entryFormat >> 4) & 3) + 1; }
-  unsigned get_inner_bit_count () const { return (entryFormat & 0xF) + 1; }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-                  c->check_range (mapDataZ.arrayZ,
-                                  mapCount,
-                                  get_width ()));
-  }
-
-  protected:
-  HBUINT8       format;         /* Format identifier--format = 1 */
-  HBUINT8       entryFormat;    /* A packed field that describes the compressed
-                                 * representation of delta-set indices. */
-  HBUINT32      mapCount;       /* The number of mapping entries. */
+  MapCountT     mapCount;       /* The number of mapping entries. */
   UnsizedArrayOf<HBUINT8>
                 mapDataZ;       /* The delta-set index mapping data. */
 
   public:
-  DEFINE_SIZE_ARRAY (6, mapDataZ);
+  DEFINE_SIZE_ARRAY (2+MapCountT::static_size, mapDataZ);
 };
 
 struct DeltaSetIndexMap
@@ -186,8 +142,11 @@ struct DeltaSetIndexMap
   bool serialize (hb_serialize_context_t *c, const T &plan)
   {
     TRACE_SERIALIZE (this);
+    unsigned length = plan.get_output_map ().length;
+    u.format = length <= 0xFFFF ? 0 : 1;
     switch (u.format) {
     case 0: return_trace (u.format0.serialize (c, plan));
+    case 1: return_trace (u.format1.serialize (c, plan));
     default:return_trace (false);
     }
   }
@@ -196,6 +155,7 @@ struct DeltaSetIndexMap
   {
     switch (u.format) {
     case 0: return (u.format0.map (v));
+    case 1: return (u.format1.map (v));
     default:return v;
     }
   }
@@ -250,14 +210,2019 @@ struct DeltaSetIndexMap
 
   protected:
   union {
-  HBUINT8                       format;         /* Format identifier */
-  DeltaSetIndexMapFormat0       format0;
-  DeltaSetIndexMapFormat1       format1;
+  HBUINT8                            format;         /* Format identifier */
+  DeltaSetIndexMapFormat01<HBUINT16> format0;
+  DeltaSetIndexMapFormat01<HBUINT32> format1;
   } u;
   public:
   DEFINE_SIZE_UNION (1, format);
 };
 
+
+struct VarStoreInstancer
+{
+  VarStoreInstancer (const VariationStore *varStore,
+                    const DeltaSetIndexMap *varIdxMap,
+                    hb_array_t<int> coords) :
+    varStore (varStore), varIdxMap (varIdxMap), coords (coords) {}
+
+  operator bool () const { return varStore && bool (coords); }
+
+  /* according to the spec, if colr table has varStore but does not have
+   * varIdxMap, then an implicit identity mapping is used */
+  float operator() (uint32_t varIdx, unsigned short offset = 0) const
+  { return coords ? varStore->get_delta (varIdxMap ? varIdxMap->map (VarIdx::add (varIdx, offset)) : varIdx + offset, coords) : 0; }
+
+  const VariationStore *varStore;
+  const DeltaSetIndexMap *varIdxMap;
+  hb_array_t<int> coords;
+};
+
+/* https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader */
+struct TupleVariationHeader
+{
+  friend struct tuple_delta_t;
+  unsigned get_size (unsigned axis_count) const
+  { return min_size + get_all_tuples (axis_count).get_size (); }
+
+  unsigned get_data_size () const { return varDataSize; }
+
+  const TupleVariationHeader &get_next (unsigned axis_count) const
+  { return StructAtOffset<TupleVariationHeader> (this, get_size (axis_count)); }
+
+  bool unpack_axis_tuples (unsigned axis_count,
+                           const hb_array_t<const F2DOT14> shared_tuples,
+                           const hb_map_t *axes_old_index_tag_map,
+                           hb_hashmap_t<hb_tag_t, Triple>& axis_tuples /* OUT */) const
+  {
+    const F2DOT14 *peak_tuple = nullptr;
+    if (has_peak ())
+      peak_tuple = get_peak_tuple (axis_count).arrayZ;
+    else
+    {
+      unsigned int index = get_index ();
+      if (unlikely ((index + 1) * axis_count > shared_tuples.length))
+        return false;
+      peak_tuple = shared_tuples.sub_array (axis_count * index, axis_count).arrayZ;
+    }
+
+    const F2DOT14 *start_tuple = nullptr;
+    const F2DOT14 *end_tuple = nullptr;
+    bool has_interm = has_intermediate ();
+
+    if (has_interm)
+    {
+      start_tuple = get_start_tuple (axis_count).arrayZ;
+      end_tuple = get_end_tuple (axis_count).arrayZ;
+    }
+
+    for (unsigned i = 0; i < axis_count; i++)
+    {
+      float peak = peak_tuple[i].to_float ();
+      if (peak == 0.f) continue;
+
+      hb_tag_t *axis_tag;
+      if (!axes_old_index_tag_map->has (i, &axis_tag))
+        return false;
+
+      float start, end;
+      if (has_interm)
+      {
+        start = start_tuple[i].to_float ();
+        end = end_tuple[i].to_float ();
+      }
+      else
+      {
+        start = hb_min (peak, 0.f);
+        end = hb_max (peak, 0.f);
+      }
+      axis_tuples.set (*axis_tag, Triple (start, peak, end));
+    }
+
+    return true;
+  }
+
+  float calculate_scalar (hb_array_t<int> coords, unsigned int coord_count,
+                          const hb_array_t<const F2DOT14> shared_tuples,
+                         const hb_vector_t<hb_pair_t<int,int>> *shared_tuple_active_idx = nullptr) const
+  {
+    const F2DOT14 *peak_tuple;
+
+    unsigned start_idx = 0;
+    unsigned end_idx = coord_count;
+    unsigned step = 1;
+
+    if (has_peak ())
+      peak_tuple = get_peak_tuple (coord_count).arrayZ;
+    else
+    {
+      unsigned int index = get_index ();
+      if (unlikely ((index + 1) * coord_count > shared_tuples.length))
+        return 0.f;
+      peak_tuple = shared_tuples.sub_array (coord_count * index, coord_count).arrayZ;
+
+      if (shared_tuple_active_idx)
+      {
+       if (unlikely (index >= shared_tuple_active_idx->length))
+         return 0.f;
+       auto _ = (*shared_tuple_active_idx).arrayZ[index];
+       if (_.second != -1)
+       {
+         start_idx = _.first;
+         end_idx = _.second + 1;
+         step = _.second - _.first;
+       }
+       else if (_.first != -1)
+       {
+         start_idx = _.first;
+         end_idx = start_idx + 1;
+       }
+      }
+    }
+
+    const F2DOT14 *start_tuple = nullptr;
+    const F2DOT14 *end_tuple = nullptr;
+    bool has_interm = has_intermediate ();
+    if (has_interm)
+    {
+      start_tuple = get_start_tuple (coord_count).arrayZ;
+      end_tuple = get_end_tuple (coord_count).arrayZ;
+    }
+
+    float scalar = 1.f;
+    for (unsigned int i = start_idx; i < end_idx; i += step)
+    {
+      int peak = peak_tuple[i].to_int ();
+      if (!peak) continue;
+
+      int v = coords[i];
+      if (v == peak) continue;
+
+      if (has_interm)
+      {
+        int start = start_tuple[i].to_int ();
+        int end = end_tuple[i].to_int ();
+        if (unlikely (start > peak || peak > end ||
+                      (start < 0 && end > 0 && peak))) continue;
+        if (v < start || v > end) return 0.f;
+        if (v < peak)
+        { if (peak != start) scalar *= (float) (v - start) / (peak - start); }
+        else
+        { if (peak != end) scalar *= (float) (end - v) / (end - peak); }
+      }
+      else if (!v || v < hb_min (0, peak) || v > hb_max (0, peak)) return 0.f;
+      else
+        scalar *= (float) v / peak;
+    }
+    return scalar;
+  }
+
+  bool           has_peak () const { return tupleIndex & TuppleIndex::EmbeddedPeakTuple; }
+  bool   has_intermediate () const { return tupleIndex & TuppleIndex::IntermediateRegion; }
+  bool has_private_points () const { return tupleIndex & TuppleIndex::PrivatePointNumbers; }
+  unsigned      get_index () const { return tupleIndex & TuppleIndex::TupleIndexMask; }
+
+  protected:
+  struct TuppleIndex : HBUINT16
+  {
+    enum Flags {
+      EmbeddedPeakTuple   = 0x8000u,
+      IntermediateRegion  = 0x4000u,
+      PrivatePointNumbers = 0x2000u,
+      TupleIndexMask      = 0x0FFFu
+    };
+
+    TuppleIndex& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
+    DEFINE_SIZE_STATIC (2);
+  };
+
+  hb_array_t<const F2DOT14> get_all_tuples (unsigned axis_count) const
+  { return StructAfter<UnsizedArrayOf<F2DOT14>> (tupleIndex).as_array ((has_peak () + has_intermediate () * 2) * axis_count); }
+  hb_array_t<const F2DOT14> get_peak_tuple (unsigned axis_count) const
+  { return get_all_tuples (axis_count).sub_array (0, axis_count); }
+  hb_array_t<const F2DOT14> get_start_tuple (unsigned axis_count) const
+  { return get_all_tuples (axis_count).sub_array (has_peak () * axis_count, axis_count); }
+  hb_array_t<const F2DOT14> get_end_tuple (unsigned axis_count) const
+  { return get_all_tuples (axis_count).sub_array (has_peak () * axis_count + axis_count, axis_count); }
+
+  HBUINT16      varDataSize;    /* The size in bytes of the serialized
+                                 * data for this tuple variation table. */
+  TuppleIndex   tupleIndex;     /* A packed field. The high 4 bits are flags (see below).
+                                   The low 12 bits are an index into a shared tuple
+                                   records array. */
+  /* UnsizedArrayOf<F2DOT14> peakTuple - optional */
+                                /* Peak tuple record for this tuple variation table — optional,
+                                 * determined by flags in the tupleIndex value.
+                                 *
+                                 * Note that this must always be included in the 'cvar' table. */
+  /* UnsizedArrayOf<F2DOT14> intermediateStartTuple - optional */
+                                /* Intermediate start tuple record for this tuple variation table — optional,
+                                   determined by flags in the tupleIndex value. */
+  /* UnsizedArrayOf<F2DOT14> intermediateEndTuple - optional */
+                                /* Intermediate end tuple record for this tuple variation table — optional,
+                                 * determined by flags in the tupleIndex value. */
+  public:
+  DEFINE_SIZE_MIN (4);
+};
+
+enum packed_delta_flag_t
+{
+  DELTAS_ARE_ZERO      = 0x80,
+  DELTAS_ARE_WORDS     = 0x40,
+  DELTA_RUN_COUNT_MASK = 0x3F
+};
+
+struct tuple_delta_t
+{
+  public:
+  hb_hashmap_t<hb_tag_t, Triple> axis_tuples;
+
+  /* indices_length = point_count, indice[i] = 1 means point i is referenced */
+  hb_vector_t<bool> indices;
+  
+  hb_vector_t<float> deltas_x;
+  /* empty for cvar tuples */
+  hb_vector_t<float> deltas_y;
+
+  /* compiled data: header and deltas
+   * compiled point data is saved in a hashmap within tuple_variations_t cause
+   * some point sets might be reused by different tuple variations */
+  hb_vector_t<char> compiled_tuple_header;
+  hb_vector_t<char> compiled_deltas;
+
+  /* compiled peak coords, empty for non-gvar tuples */
+  hb_vector_t<char> compiled_peak_coords;
+
+  tuple_delta_t () = default;
+  tuple_delta_t (const tuple_delta_t& o) = default;
+
+  friend void swap (tuple_delta_t& a, tuple_delta_t& b)
+  {
+    hb_swap (a.axis_tuples, b.axis_tuples);
+    hb_swap (a.indices, b.indices);
+    hb_swap (a.deltas_x, b.deltas_x);
+    hb_swap (a.deltas_y, b.deltas_y);
+    hb_swap (a.compiled_tuple_header, b.compiled_tuple_header);
+    hb_swap (a.compiled_deltas, b.compiled_deltas);
+    hb_swap (a.compiled_peak_coords, b.compiled_peak_coords);
+  }
+
+  tuple_delta_t (tuple_delta_t&& o) : tuple_delta_t ()
+  { hb_swap (*this, o); }
+
+  tuple_delta_t& operator = (tuple_delta_t&& o)
+  {
+    hb_swap (*this, o);
+    return *this;
+  }
+
+  void remove_axis (hb_tag_t axis_tag)
+  { axis_tuples.del (axis_tag); }
+
+  bool set_tent (hb_tag_t axis_tag, Triple tent)
+  { return axis_tuples.set (axis_tag, tent); }
+
+  tuple_delta_t& operator += (const tuple_delta_t& o)
+  {
+    unsigned num = indices.length;
+    for (unsigned i = 0; i < num; i++)
+    {
+      if (indices.arrayZ[i])
+      {
+        if (o.indices.arrayZ[i])
+        {
+          deltas_x[i] += o.deltas_x[i];
+          if (deltas_y && o.deltas_y)
+            deltas_y[i] += o.deltas_y[i];
+        }
+      }
+      else
+      {
+        if (!o.indices.arrayZ[i]) continue;
+        indices.arrayZ[i] = true;
+        deltas_x[i] = o.deltas_x[i];
+        if (deltas_y && o.deltas_y)
+          deltas_y[i] = o.deltas_y[i];
+      }
+    }
+    return *this;
+  }
+
+  tuple_delta_t& operator *= (float scalar)
+  {
+    if (scalar == 1.0f)
+      return *this;
+
+    unsigned num = indices.length;
+    for (unsigned i = 0; i < num; i++)
+    {
+      if (!indices.arrayZ[i]) continue;
+
+      deltas_x[i] *= scalar;
+      if (deltas_y)
+        deltas_y[i] *= scalar;
+    }
+    return *this;
+  }
+
+  hb_vector_t<tuple_delta_t> change_tuple_var_axis_limit (hb_tag_t axis_tag, Triple axis_limit,
+                                                          TripleDistances axis_triple_distances) const
+  {
+    hb_vector_t<tuple_delta_t> out;
+    Triple *tent;
+    if (!axis_tuples.has (axis_tag, &tent))
+    {
+      out.push (*this);
+      return out;
+    }
+
+    if ((tent->minimum < 0.f && tent->maximum > 0.f) ||
+        !(tent->minimum <= tent->middle && tent->middle <= tent->maximum))
+      return out;
+
+    if (tent->middle == 0.f)
+    {
+      out.push (*this);
+      return out;
+    }
+
+    result_t solutions = rebase_tent (*tent, axis_limit, axis_triple_distances);
+    for (auto t : solutions)
+    {
+      tuple_delta_t new_var = *this;
+      if (t.second == Triple ())
+        new_var.remove_axis (axis_tag);
+      else
+        new_var.set_tent (axis_tag, t.second);
+
+      new_var *= t.first;
+      out.push (std::move (new_var));
+    }
+
+    return out;
+  }
+
+  bool compile_peak_coords (const hb_map_t& axes_index_map,
+                            const hb_map_t& axes_old_index_tag_map)
+  {
+    unsigned axis_count = axes_index_map.get_population ();
+    if (unlikely (!compiled_peak_coords.alloc (axis_count * F2DOT14::static_size)))
+      return false;
+
+    unsigned orig_axis_count = axes_old_index_tag_map.get_population ();
+    for (unsigned i = 0; i < orig_axis_count; i++)
+    {
+      if (!axes_index_map.has (i))
+        continue;
+
+      hb_tag_t axis_tag = axes_old_index_tag_map.get (i);
+      Triple *coords;
+      F2DOT14 peak_coord;
+      if (axis_tuples.has (axis_tag, &coords))
+        peak_coord.set_float (coords->middle);
+      else
+        peak_coord.set_int (0);
+
+      /* push F2DOT14 value into char vector */
+      int16_t val = peak_coord.to_int ();
+      compiled_peak_coords.push (static_cast<char> (val >> 8));
+      compiled_peak_coords.push (static_cast<char> (val & 0xFF));
+    }
+
+    return !compiled_peak_coords.in_error ();
+  }
+
+  /* deltas should be compiled already before we compile tuple
+   * variation header cause we need to fill in the size of the
+   * serialized data for this tuple variation */
+  bool compile_tuple_var_header (const hb_map_t& axes_index_map,
+                                 unsigned points_data_length,
+                                 const hb_map_t& axes_old_index_tag_map,
+                                 const hb_hashmap_t<const hb_vector_t<char>*, unsigned>* shared_tuples_idx_map)
+  {
+    if (!compiled_deltas) return false;
+
+    unsigned cur_axis_count = axes_index_map.get_population ();
+    /* allocate enough memory: 1 peak + 2 intermediate coords + fixed header size */
+    unsigned alloc_len = 3 * cur_axis_count * (F2DOT14::static_size) + 4;
+    if (unlikely (!compiled_tuple_header.resize (alloc_len))) return false;
+
+    unsigned flag = 0;
+    /* skip the first 4 header bytes: variationDataSize+tupleIndex */
+    F2DOT14* p = reinterpret_cast<F2DOT14 *> (compiled_tuple_header.begin () + 4);
+    F2DOT14* end = reinterpret_cast<F2DOT14 *> (compiled_tuple_header.end ());
+    hb_array_t<F2DOT14> coords (p, end - p);
+
+    /* encode peak coords */
+    unsigned peak_count = 0;
+    unsigned *shared_tuple_idx;
+    if (shared_tuples_idx_map &&
+        shared_tuples_idx_map->has (&compiled_peak_coords, &shared_tuple_idx))
+    {
+      flag = *shared_tuple_idx;
+    }
+    else
+    {
+      peak_count = encode_peak_coords(coords, flag, axes_index_map, axes_old_index_tag_map);
+      if (!peak_count) return false;
+    }
+
+    /* encode interim coords, it's optional so returned num could be 0 */
+    unsigned interim_count = encode_interm_coords (coords.sub_array (peak_count), flag, axes_index_map, axes_old_index_tag_map);
+
+    /* pointdata length = 0 implies "use shared points" */
+    if (points_data_length)
+      flag |= TupleVariationHeader::TuppleIndex::PrivatePointNumbers;
+
+    unsigned serialized_data_size = points_data_length + compiled_deltas.length;
+    TupleVariationHeader *o = reinterpret_cast<TupleVariationHeader *> (compiled_tuple_header.begin ());
+    o->varDataSize = serialized_data_size;
+    o->tupleIndex = flag;
+
+    unsigned total_header_len = 4 + (peak_count + interim_count) * (F2DOT14::static_size);
+    return compiled_tuple_header.resize (total_header_len);
+  }
+
+  unsigned encode_peak_coords (hb_array_t<F2DOT14> peak_coords,
+                               unsigned& flag,
+                               const hb_map_t& axes_index_map,
+                               const hb_map_t& axes_old_index_tag_map) const
+  {
+    unsigned orig_axis_count = axes_old_index_tag_map.get_population ();
+    auto it = peak_coords.iter ();
+    unsigned count = 0;
+    for (unsigned i = 0; i < orig_axis_count; i++)
+    {
+      if (!axes_index_map.has (i)) /* axis pinned */
+        continue;
+      hb_tag_t axis_tag = axes_old_index_tag_map.get (i);
+      Triple *coords;
+      if (!axis_tuples.has (axis_tag, &coords))
+        (*it).set_int (0);
+      else
+        (*it).set_float (coords->middle);
+      it++;
+      count++;
+    }
+    flag |= TupleVariationHeader::TuppleIndex::EmbeddedPeakTuple;
+    return count;
+  }
+
+  /* if no need to encode intermediate coords, then just return p */
+  unsigned encode_interm_coords (hb_array_t<F2DOT14> coords,
+                                 unsigned& flag,
+                                 const hb_map_t& axes_index_map,
+                                 const hb_map_t& axes_old_index_tag_map) const
+  {
+    unsigned orig_axis_count = axes_old_index_tag_map.get_population ();
+    unsigned cur_axis_count = axes_index_map.get_population ();
+
+    auto start_coords_iter = coords.sub_array (0, cur_axis_count).iter ();
+    auto end_coords_iter = coords.sub_array (cur_axis_count).iter ();
+    bool encode_needed = false;
+    unsigned count = 0;
+    for (unsigned i = 0; i < orig_axis_count; i++)
+    {
+      if (!axes_index_map.has (i)) /* axis pinned */
+        continue;
+      hb_tag_t axis_tag = axes_old_index_tag_map.get (i);
+      Triple *coords;
+      float min_val = 0.f, val = 0.f, max_val = 0.f;
+      if (axis_tuples.has (axis_tag, &coords))
+      {
+        min_val = coords->minimum;
+        val = coords->middle;
+        max_val = coords->maximum;
+      }
+
+      (*start_coords_iter).set_float (min_val);
+      (*end_coords_iter).set_float (max_val);
+
+      start_coords_iter++;
+      end_coords_iter++;
+      count += 2;
+      if (min_val != hb_min (val, 0.f) || max_val != hb_max (val, 0.f))
+        encode_needed = true;
+    }
+
+    if (encode_needed)
+    {
+      flag |= TupleVariationHeader::TuppleIndex::IntermediateRegion;
+      return count;
+    }
+    return 0;
+  }
+
+  bool compile_deltas ()
+  {
+    hb_vector_t<int> rounded_deltas;
+    if (unlikely (!rounded_deltas.alloc (indices.length)))
+      return false;
+
+    for (unsigned i = 0; i < indices.length; i++)
+    {
+      if (!indices[i]) continue;
+      int rounded_delta = (int) roundf (deltas_x[i]);
+      rounded_deltas.push (rounded_delta);
+    }
+
+    if (!rounded_deltas) return false;
+    /* allocate enough memories 3 * num_deltas */
+    unsigned alloc_len = 3 * rounded_deltas.length;
+    if (deltas_y)
+      alloc_len *= 2;
+
+    if (unlikely (!compiled_deltas.resize (alloc_len))) return false;
+
+    unsigned i = 0;
+    unsigned encoded_len = encode_delta_run (i, compiled_deltas.as_array (), rounded_deltas);
+
+    if (deltas_y)
+    {
+      /* reuse the rounded_deltas vector, check that deltas_y have the same num of deltas as deltas_x */
+      unsigned j = 0;
+      for (unsigned idx = 0; idx < indices.length; idx++)
+      {
+        if (!indices[idx]) continue;
+        int rounded_delta = (int) roundf (deltas_y[idx]);
+
+        if (j >= rounded_deltas.length) return false;
+
+        rounded_deltas[j++] = rounded_delta;
+      }
+
+      if (j != rounded_deltas.length) return false;
+      /* reset i because we reuse rounded_deltas for deltas_y */
+      i = 0;
+      encoded_len += encode_delta_run (i, compiled_deltas.as_array ().sub_array (encoded_len), rounded_deltas);
+    }
+    return compiled_deltas.resize (encoded_len);
+  }
+
+  unsigned encode_delta_run (unsigned& i,
+                             hb_array_t<char> encoded_bytes,
+                             const hb_vector_t<int>& deltas) const
+  {
+    unsigned num_deltas = deltas.length;
+    unsigned encoded_len = 0;
+    while (i < num_deltas)
+    {
+      int val = deltas[i];
+      if (val == 0)
+        encoded_len += encode_delta_run_as_zeroes (i, encoded_bytes.sub_array (encoded_len), deltas);
+      else if (val >= -128 && val <= 127)
+        encoded_len += encode_delta_run_as_bytes (i, encoded_bytes.sub_array (encoded_len), deltas);
+      else
+        encoded_len += encode_delta_run_as_words (i, encoded_bytes.sub_array (encoded_len), deltas);
+    }
+    return encoded_len;
+  }
+
+  unsigned encode_delta_run_as_zeroes (unsigned& i,
+                                       hb_array_t<char> encoded_bytes,
+                                       const hb_vector_t<int>& deltas) const
+  {
+    unsigned num_deltas = deltas.length;
+    unsigned run_length = 0;
+    auto it = encoded_bytes.iter ();
+    unsigned encoded_len = 0;
+    while (i < num_deltas && deltas[i] == 0)
+    {
+      i++;
+      run_length++;
+    }
+
+    while (run_length >= 64)
+    {
+      *it++ = char (DELTAS_ARE_ZERO | 63);
+      run_length -= 64;
+      encoded_len++;
+    }
+
+    if (run_length)
+    {
+      *it++ = char (DELTAS_ARE_ZERO | (run_length - 1));
+      encoded_len++;
+    }
+    return encoded_len;
+  }
+
+  unsigned encode_delta_run_as_bytes (unsigned &i,
+                                      hb_array_t<char> encoded_bytes,
+                                      const hb_vector_t<int>& deltas) const
+  {
+    unsigned start = i;
+    unsigned num_deltas = deltas.length;
+    while (i < num_deltas)
+    {
+      int val = deltas[i];
+      if (val > 127 || val < -128)
+        break;
+
+      /* from fonttools: if there're 2 or more zeros in a sequence,
+       * it is better to start a new run to save bytes. */
+      if (val == 0 && i + 1 < num_deltas && deltas[i+1] == 0)
+        break;
+
+      i++;
+    }
+    unsigned run_length = i - start;
+
+    unsigned encoded_len = 0;
+    auto it = encoded_bytes.iter ();
+
+    while (run_length >= 64)
+    {
+      *it++ = 63;
+      encoded_len++;
+
+      for (unsigned j = 0; j < 64; j++)
+      {
+        *it++ = static_cast<char> (deltas[start + j]);
+        encoded_len++;
+      }
+
+      start += 64;
+      run_length -= 64;
+    }
+
+    if (run_length)
+    {
+      *it++ = run_length - 1;
+      encoded_len++;
+
+      while (start < i)
+      {
+        *it++ = static_cast<char> (deltas[start++]);
+        encoded_len++;
+      }
+    }
+
+    return encoded_len;
+  }
+
+  unsigned encode_delta_run_as_words (unsigned &i,
+                                      hb_array_t<char> encoded_bytes,
+                                      const hb_vector_t<int>& deltas) const
+  {
+    unsigned start = i;
+    unsigned num_deltas = deltas.length;
+    while (i < num_deltas)
+    {
+      int val = deltas[i];
+      
+      /* start a new run for a single zero value*/
+      if (val == 0) break;
+
+      /* from fonttools: continue word-encoded run if there's only one
+       * single value in the range [-128, 127] because it is more compact.
+       * Only start a new run when there're 2 continuous such values. */
+      if (val >= -128 && val <= 127 &&
+          i + 1 < num_deltas &&
+          deltas[i+1] >= -128 && deltas[i+1] <= 127)
+        break;
+
+      i++;
+    }
+
+    unsigned run_length = i - start;
+    auto it = encoded_bytes.iter ();
+    unsigned encoded_len = 0;
+    while (run_length >= 64)
+    {
+      *it++ = (DELTAS_ARE_WORDS | 63);
+      encoded_len++;
+
+      for (unsigned j = 0; j < 64; j++)
+      {
+        int16_t delta_val = deltas[start + j];
+        *it++ = static_cast<char> (delta_val >> 8);
+        *it++ = static_cast<char> (delta_val & 0xFF);
+
+        encoded_len += 2;
+      }
+
+      start += 64;
+      run_length -= 64;
+    }
+
+    if (run_length)
+    {
+      *it++ = (DELTAS_ARE_WORDS | (run_length - 1));
+      encoded_len++;
+      while (start < i)
+      {
+        int16_t delta_val = deltas[start++];
+        *it++ = static_cast<char> (delta_val >> 8);
+        *it++ = static_cast<char> (delta_val & 0xFF);
+
+        encoded_len += 2;
+      }
+    }
+    return encoded_len;
+  }
+
+  bool calc_inferred_deltas (const contour_point_vector_t& orig_points)
+  {
+    unsigned point_count = orig_points.length;
+    if (point_count != indices.length)
+      return false;
+
+    unsigned ref_count = 0;
+    hb_vector_t<unsigned> end_points;
+
+    for (unsigned i = 0; i < point_count; i++)
+    {
+      if (indices.arrayZ[i])
+        ref_count++;
+      if (orig_points.arrayZ[i].is_end_point)
+        end_points.push (i);
+    }
+    /* all points are referenced, nothing to do */
+    if (ref_count == point_count)
+      return true;
+    if (unlikely (end_points.in_error ())) return false;
+
+    hb_set_t inferred_idxes;
+    unsigned start_point = 0;
+    for (unsigned end_point : end_points)
+    {
+      /* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */
+      unsigned unref_count = 0;
+      for (unsigned i = start_point; i < end_point + 1; i++)
+        unref_count += indices.arrayZ[i];
+      unref_count = (end_point - start_point + 1) - unref_count;
+
+      unsigned j = start_point;
+      if (unref_count == 0 || unref_count > end_point - start_point)
+        goto no_more_gaps;
+      for (;;)
+      {
+        /* Locate the next gap of unreferenced points between two referenced points prev and next.
+         * Note that a gap may wrap around at left (start_point) and/or at right (end_point).
+         */
+        unsigned int prev, next, i;
+        for (;;)
+        {
+          i = j;
+          j = next_index (i, start_point, end_point);
+          if (indices.arrayZ[i] && !indices.arrayZ[j]) break;
+        }
+        prev = j = i;
+        for (;;)
+        {
+          i = j;
+          j = next_index (i, start_point, end_point);
+          if (!indices.arrayZ[i] && indices.arrayZ[j]) break;
+        }
+        next = j;
+       /* Infer deltas for all unref points in the gap between prev and next */
+        i = prev;
+        for (;;)
+        {
+          i = next_index (i, start_point, end_point);
+          if (i == next) break;
+          deltas_x.arrayZ[i] = infer_delta (orig_points.arrayZ[i].x, orig_points.arrayZ[prev].x, orig_points.arrayZ[next].x,
+                                            deltas_x.arrayZ[prev], deltas_x.arrayZ[next]);
+          deltas_y.arrayZ[i] = infer_delta (orig_points.arrayZ[i].y, orig_points.arrayZ[prev].y, orig_points.arrayZ[next].y,
+                                            deltas_y.arrayZ[prev], deltas_y.arrayZ[next]);
+          inferred_idxes.add (i);
+          if (--unref_count == 0) goto no_more_gaps;
+        }
+      }
+    no_more_gaps:
+      start_point = end_point + 1;
+    }
+
+    for (unsigned i = 0; i < point_count; i++)
+    {
+      /* if points are not referenced and deltas are not inferred, set to 0.
+       * reference all points for gvar */
+      if ( !indices[i])
+      {
+        if (!inferred_idxes.has (i))
+        {
+          deltas_x.arrayZ[i] = 0.f;
+          deltas_y.arrayZ[i] = 0.f;
+        }
+        indices[i] = true;
+      }
+    }
+    return true;
+  }
+
+  static float infer_delta (float target_val, float prev_val, float next_val, float prev_delta, float next_delta)
+  {
+    if (prev_val == next_val)
+      return (prev_delta == next_delta) ? prev_delta : 0.f;
+    else if (target_val <= hb_min (prev_val, next_val))
+      return (prev_val < next_val) ? prev_delta : next_delta;
+    else if (target_val >= hb_max (prev_val, next_val))
+      return (prev_val > next_val) ? prev_delta : next_delta;
+
+    float r = (target_val - prev_val) / (next_val - prev_val);
+    return prev_delta + r * (next_delta - prev_delta);
+  }
+
+  static unsigned int next_index (unsigned int i, unsigned int start, unsigned int end)
+  { return (i >= end) ? start : (i + 1); }
+};
+
+struct TupleVariationData
+{
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    // here check on min_size only, TupleVariationHeader and var data will be
+    // checked while accessing through iterator.
+    return_trace (c->check_struct (this));
+  }
+
+  unsigned get_size (unsigned axis_count) const
+  {
+    unsigned total_size = min_size;
+    unsigned count = tupleVarCount.get_count ();
+    const TupleVariationHeader *tuple_var_header = &(get_tuple_var_header());
+    for (unsigned i = 0; i < count; i++)
+    {
+      total_size += tuple_var_header->get_size (axis_count) + tuple_var_header->get_data_size ();
+      tuple_var_header = &tuple_var_header->get_next (axis_count);
+    }
+
+    return total_size;
+  }
+
+  const TupleVariationHeader &get_tuple_var_header (void) const
+  { return StructAfter<TupleVariationHeader> (data); }
+
+  struct tuple_iterator_t;
+  struct tuple_variations_t
+  {
+    hb_vector_t<tuple_delta_t> tuple_vars;
+
+    private:
+    /* referenced point set->compiled point data map */
+    hb_hashmap_t<const hb_vector_t<bool>*, hb_bytes_t> point_data_map;
+    /* referenced point set-> count map, used in finding shared points */
+    hb_hashmap_t<const hb_vector_t<bool>*, unsigned> point_set_count_map;
+
+    /* empty for non-gvar tuples.
+     * shared_points_bytes is just a copy of some value in the point_data_map,
+     * which will be freed during map destruction. Save it for serialization, so
+     * no need to do find_shared_points () again */
+    hb_bytes_t shared_points_bytes;
+
+    /* total compiled byte size as TupleVariationData format, initialized to its
+     * min_size: 4 */
+    unsigned compiled_byte_size = 4;
+
+    public:
+    tuple_variations_t () = default;
+    tuple_variations_t (const tuple_variations_t&) = delete;
+    tuple_variations_t& operator=(const tuple_variations_t&) = delete;
+    tuple_variations_t (tuple_variations_t&&) = default;
+    tuple_variations_t& operator=(tuple_variations_t&&) = default;
+    ~tuple_variations_t () { fini (); }
+    void fini ()
+    {
+      for (auto _ : point_data_map.values ())
+        _.fini ();
+
+      point_set_count_map.fini ();
+      tuple_vars.fini ();
+    }
+
+    explicit operator bool () const { return bool (tuple_vars); }
+    unsigned get_var_count () const
+    {
+      unsigned count = tuple_vars.length;
+      if (shared_points_bytes.length)
+        count |= TupleVarCount::SharedPointNumbers;
+      return count;
+    }
+
+    unsigned get_compiled_byte_size () const
+    { return compiled_byte_size; }
+
+    bool create_from_tuple_var_data (tuple_iterator_t iterator,
+                                     unsigned tuple_var_count,
+                                     unsigned point_count,
+                                     bool is_gvar,
+                                     const hb_map_t *axes_old_index_tag_map,
+                                     const hb_vector_t<unsigned> &shared_indices,
+                                     const hb_array_t<const F2DOT14> shared_tuples)
+    {
+      do
+      {
+        const HBUINT8 *p = iterator.get_serialized_data ();
+        unsigned int length = iterator.current_tuple->get_data_size ();
+        if (unlikely (!iterator.var_data_bytes.check_range (p, length)))
+        { fini (); return false; }
+
+        hb_hashmap_t<hb_tag_t, Triple> axis_tuples;
+        if (!iterator.current_tuple->unpack_axis_tuples (iterator.get_axis_count (), shared_tuples, axes_old_index_tag_map, axis_tuples)
+            || axis_tuples.is_empty ())
+        { fini (); return false; }
+
+        hb_vector_t<unsigned> private_indices;
+        bool has_private_points = iterator.current_tuple->has_private_points ();
+        const HBUINT8 *end = p + length;
+        if (has_private_points &&
+            !TupleVariationData::unpack_points (p, private_indices, end))
+        { fini (); return false; }
+
+        const hb_vector_t<unsigned> &indices = has_private_points ? private_indices : shared_indices;
+        bool apply_to_all = (indices.length == 0);
+        unsigned num_deltas = apply_to_all ? point_count : indices.length;
+
+        hb_vector_t<int> deltas_x;
+
+        if (unlikely (!deltas_x.resize (num_deltas, false) ||
+                      !TupleVariationData::unpack_deltas (p, deltas_x, end)))
+        { fini (); return false; }
+
+        hb_vector_t<int> deltas_y;
+        if (is_gvar)
+        {
+          if (unlikely (!deltas_y.resize (num_deltas, false) ||
+                        !TupleVariationData::unpack_deltas (p, deltas_y, end)))
+          { fini (); return false; }
+        }
+
+        tuple_delta_t var;
+        var.axis_tuples = std::move (axis_tuples);
+        if (unlikely (!var.indices.resize (point_count) ||
+                      !var.deltas_x.resize (point_count, false)))
+        { fini (); return false; }
+
+        if (is_gvar && unlikely (!var.deltas_y.resize (point_count, false)))
+        { fini (); return false; }
+
+        for (unsigned i = 0; i < num_deltas; i++)
+        {
+          unsigned idx = apply_to_all ? i : indices[i];
+          if (idx >= point_count) continue;
+          var.indices[idx] = true;
+          var.deltas_x[idx] = static_cast<float> (deltas_x[i]);
+          if (is_gvar)
+            var.deltas_y[idx] = static_cast<float> (deltas_y[i]);
+        }
+        tuple_vars.push (std::move (var));
+      } while (iterator.move_to_next ());
+      return true;
+    }
+
+    bool create_from_item_var_data (const VarData &var_data,
+                                    const hb_vector_t<hb_hashmap_t<hb_tag_t, Triple>>& regions,
+                                    const hb_map_t& axes_old_index_tag_map,
+                                    const hb_inc_bimap_t* inner_map = nullptr)
+    {
+      /* NULL offset, to keep original varidx valid, just return */
+      if (&var_data == &Null (VarData))
+        return true;
+  
+      unsigned num_regions = var_data.get_region_index_count ();
+      if (!tuple_vars.alloc (num_regions)) return false;
+  
+      unsigned item_count = inner_map ? inner_map->get_population () : var_data.get_item_count ();
+      unsigned row_size = var_data.get_row_size ();
+      const HBUINT8 *delta_bytes = var_data.get_delta_bytes ();
+  
+      for (unsigned r = 0; r < num_regions; r++)
+      {
+        /* In VarData, deltas are organized in rows, convert them into
+         * column(region) based tuples, resize deltas_x first */
+        tuple_delta_t tuple;
+        if (!tuple.deltas_x.resize (item_count, false) ||
+            !tuple.indices.resize (item_count, false))
+          return false;
+  
+        for (unsigned i = 0; i < item_count; i++)
+        {
+          tuple.indices.arrayZ[i] = true;
+          tuple.deltas_x.arrayZ[i] = var_data.get_item_delta_fast (inner_map ? inner_map->backward (i) : i,
+                                                                   r, delta_bytes, row_size);
+        }
+  
+        unsigned region_index = var_data.get_region_index (r);
+        if (region_index >= regions.length) return false;
+        tuple.axis_tuples = regions.arrayZ[region_index];
+
+        tuple_vars.push (std::move (tuple));
+      }
+      return !tuple_vars.in_error ();
+    }
+
+    private:
+    static int _cmp_axis_tag (const void *pa, const void *pb)
+    {
+      const hb_tag_t *a = (const hb_tag_t*) pa;
+      const hb_tag_t *b = (const hb_tag_t*) pb;
+      return (int)(*a) - (int)(*b);
+    }
+
+    bool change_tuple_variations_axis_limits (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
+                                              const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances)
+    {
+      /* sort axis_tag/axis_limits, make result deterministic */
+      hb_vector_t<hb_tag_t> axis_tags;
+      if (!axis_tags.alloc (normalized_axes_location.get_population ()))
+        return false;
+      for (auto t : normalized_axes_location.keys ())
+        axis_tags.push (t);
+
+      axis_tags.qsort (_cmp_axis_tag);
+      for (auto axis_tag : axis_tags)
+      {
+        Triple *axis_limit;
+        if (!normalized_axes_location.has (axis_tag, &axis_limit))
+          return false;
+        TripleDistances axis_triple_distances{1.f, 1.f};
+        if (axes_triple_distances.has (axis_tag))
+          axis_triple_distances = axes_triple_distances.get (axis_tag);
+
+        hb_vector_t<tuple_delta_t> new_vars;
+        for (const tuple_delta_t& var : tuple_vars)
+        {
+          hb_vector_t<tuple_delta_t> out = var.change_tuple_var_axis_limit (axis_tag, *axis_limit, axis_triple_distances);
+          if (!out) continue;
+
+          unsigned new_len = new_vars.length + out.length;
+
+          if (unlikely (!new_vars.alloc (new_len, false)))
+          { fini (); return false;}
+
+          for (unsigned i = 0; i < out.length; i++)
+            new_vars.push (std::move (out[i]));
+        }
+        tuple_vars.fini ();
+        tuple_vars = std::move (new_vars);
+      }
+      return true;
+    }
+
+    /* merge tuple variations with overlapping tents */
+    void merge_tuple_variations ()
+    {
+      hb_vector_t<tuple_delta_t> new_vars;
+      hb_hashmap_t<const hb_hashmap_t<hb_tag_t, Triple>*, unsigned> m;
+      unsigned i = 0;
+      for (const tuple_delta_t& var : tuple_vars)
+      {
+        /* if all axes are pinned, drop the tuple variation */
+        if (var.axis_tuples.is_empty ()) continue;
+
+        unsigned *idx;
+        if (m.has (&(var.axis_tuples), &idx))
+        {
+          new_vars[*idx] += var;
+        }
+        else
+        {
+          new_vars.push (var);
+          m.set (&(var.axis_tuples), i);
+          i++;
+        }
+      }
+      tuple_vars.fini ();
+      tuple_vars = std::move (new_vars);
+    }
+
+    hb_bytes_t compile_point_set (const hb_vector_t<bool> &point_indices)
+    {
+      unsigned num_points = 0;
+      for (bool i : point_indices)
+        if (i) num_points++;
+
+      unsigned indices_length = point_indices.length;
+      /* If the points set consists of all points in the glyph, it's encoded with a
+       * single zero byte */
+      if (num_points == indices_length)
+      {
+        char *p = (char *) hb_calloc (1, sizeof (char));
+        if (unlikely (!p)) return hb_bytes_t ();
+
+        return hb_bytes_t (p, 1);
+      }
+
+      /* allocate enough memories: 2 bytes for count + 3 bytes for each point */
+      unsigned num_bytes = 2 + 3 *num_points;
+      char *p = (char *) hb_calloc (num_bytes, sizeof (char));
+      if (unlikely (!p)) return hb_bytes_t ();
+
+      unsigned pos = 0;
+      /* binary data starts with the total number of reference points */
+      if (num_points < 0x80)
+        p[pos++] = num_points;
+      else
+      {
+        p[pos++] = ((num_points >> 8) | 0x80);
+        p[pos++] = num_points & 0xFF;
+      }
+
+      const unsigned max_run_length = 0x7F;
+      unsigned i = 0;
+      unsigned last_value = 0;
+      unsigned num_encoded = 0;
+      while (i < indices_length && num_encoded < num_points)
+      {
+        unsigned run_length = 0;
+        unsigned header_pos = pos;
+        p[pos++] = 0;
+
+        bool use_byte_encoding = false;
+        bool new_run = true;
+        while (i < indices_length && num_encoded < num_points &&
+               run_length <= max_run_length)
+        {
+          // find out next referenced point index
+          while (i < indices_length && !point_indices[i])
+            i++;
+
+          if (i >= indices_length) break;
+
+          unsigned cur_value = i;
+          unsigned delta = cur_value - last_value;
+
+          if (new_run)
+          {
+            use_byte_encoding = (delta <= 0xFF);
+            new_run = false;
+          }
+
+          if (use_byte_encoding && delta > 0xFF)
+            break;
+
+          if (use_byte_encoding)
+            p[pos++] = delta;
+          else
+          {
+            p[pos++] = delta >> 8;
+            p[pos++] = delta & 0xFF;
+          }
+          i++;
+          last_value = cur_value;
+          run_length++;
+          num_encoded++;
+        }
+
+        if (use_byte_encoding)
+          p[header_pos] = run_length - 1;
+        else
+          p[header_pos] = (run_length - 1) | 0x80;
+      }
+      return hb_bytes_t (p, pos);
+    }
+
+    /* compile all point set and store byte data in a point_set->hb_bytes_t hashmap,
+     * also update point_set->count map, which will be used in finding shared
+     * point set*/
+    bool compile_all_point_sets ()
+    {
+      for (const auto& tuple: tuple_vars)
+      {
+        const hb_vector_t<bool>* points_set = &(tuple.indices);
+        if (point_data_map.has (points_set))
+        {
+          unsigned *count;
+          if (unlikely (!point_set_count_map.has (points_set, &count) ||
+                        !point_set_count_map.set (points_set, (*count) + 1)))
+            return false;
+          continue;
+        }
+        
+        hb_bytes_t compiled_data = compile_point_set (*points_set);
+        if (unlikely (compiled_data == hb_bytes_t ()))
+          return false;
+        
+        if (!point_data_map.set (points_set, compiled_data) ||
+            !point_set_count_map.set (points_set, 1))
+          return false;
+      }
+      return true;
+    }
+
+    /* find shared points set which saves most bytes */
+    hb_bytes_t find_shared_points ()
+    {
+      unsigned max_saved_bytes = 0;
+      hb_bytes_t res{};
+
+      for (const auto& _ : point_data_map.iter ())
+      {
+        const hb_vector_t<bool>* points_set = _.first;
+        unsigned data_length = _.second.length;
+        unsigned *count;
+        if (unlikely (!point_set_count_map.has (points_set, &count) ||
+                      *count <= 1))
+          return hb_bytes_t ();
+
+        unsigned saved_bytes = data_length * ((*count) -1);
+        if (saved_bytes > max_saved_bytes)
+        {
+          max_saved_bytes = saved_bytes;
+          res = _.second;
+        }
+      }
+      return res;
+    }
+
+    bool calc_inferred_deltas (contour_point_vector_t& contour_points)
+    {
+      for (tuple_delta_t& var : tuple_vars)
+        if (!var.calc_inferred_deltas (contour_points))
+          return false;
+      
+      return true;
+    }
+
+    public:
+    bool instantiate (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
+                      const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances,
+                      contour_point_vector_t* contour_points = nullptr)
+    {
+      if (!tuple_vars) return true;
+      if (!change_tuple_variations_axis_limits (normalized_axes_location, axes_triple_distances))
+        return false;
+      /* compute inferred deltas only for gvar */
+      if (contour_points)
+        if (!calc_inferred_deltas (*contour_points))
+          return false;
+
+      merge_tuple_variations ();
+      return !tuple_vars.in_error ();
+    }
+
+    bool compile_bytes (const hb_map_t& axes_index_map,
+                        const hb_map_t& axes_old_index_tag_map,
+                        bool use_shared_points,
+                        const hb_hashmap_t<const hb_vector_t<char>*, unsigned>* shared_tuples_idx_map = nullptr)
+    {
+      // compile points set and store data in hashmap
+      if (!compile_all_point_sets ())
+        return false;
+
+      if (use_shared_points)
+      {
+        shared_points_bytes = find_shared_points ();
+        compiled_byte_size += shared_points_bytes.length;
+      }
+      // compile delta and tuple var header for each tuple variation
+      for (auto& tuple: tuple_vars)
+      {
+        const hb_vector_t<bool>* points_set = &(tuple.indices);
+        hb_bytes_t *points_data;
+        if (unlikely (!point_data_map.has (points_set, &points_data)))
+          return false;
+
+        if (!tuple.compile_deltas ())
+          return false;
+
+        unsigned points_data_length = (*points_data != shared_points_bytes) ? points_data->length : 0;
+        if (!tuple.compile_tuple_var_header (axes_index_map, points_data_length, axes_old_index_tag_map,
+                                             shared_tuples_idx_map))
+          return false;
+        compiled_byte_size += tuple.compiled_tuple_header.length + points_data_length + tuple.compiled_deltas.length;
+      }
+      return true;
+    }
+
+    bool serialize_var_headers (hb_serialize_context_t *c, unsigned& total_header_len) const
+    {
+      TRACE_SERIALIZE (this);
+      for (const auto& tuple: tuple_vars)
+      {
+        tuple.compiled_tuple_header.as_array ().copy (c);
+        if (c->in_error ()) return_trace (false);
+        total_header_len += tuple.compiled_tuple_header.length;
+      }
+      return_trace (true);
+    }
+
+    bool serialize_var_data (hb_serialize_context_t *c, bool is_gvar) const
+    {
+      TRACE_SERIALIZE (this);
+      if (is_gvar)
+        shared_points_bytes.copy (c);
+
+      for (const auto& tuple: tuple_vars)
+      {
+        const hb_vector_t<bool>* points_set = &(tuple.indices);
+        hb_bytes_t *point_data;
+        if (!point_data_map.has (points_set, &point_data))
+          return_trace (false);
+
+        if (!is_gvar || *point_data != shared_points_bytes)
+          point_data->copy (c);
+
+        tuple.compiled_deltas.as_array ().copy (c);
+        if (c->in_error ()) return_trace (false);
+      }
+
+      /* padding for gvar */
+      if (is_gvar && (compiled_byte_size % 2))
+      {
+        HBUINT8 pad;
+        pad = 0;
+        if (!c->embed (pad)) return_trace (false);
+      }
+      return_trace (true);
+    }
+  };
+
+  struct tuple_iterator_t
+  {
+    unsigned get_axis_count () const { return axis_count; }
+
+    void init (hb_bytes_t var_data_bytes_, unsigned int axis_count_, const void *table_base_)
+    {
+      var_data_bytes = var_data_bytes_;
+      var_data = var_data_bytes_.as<TupleVariationData> ();
+      index = 0;
+      axis_count = axis_count_;
+      current_tuple = &var_data->get_tuple_var_header ();
+      data_offset = 0;
+      table_base = table_base_;
+    }
+
+    bool get_shared_indices (hb_vector_t<unsigned int> &shared_indices /* OUT */)
+    {
+      if (var_data->has_shared_point_numbers ())
+      {
+        const HBUINT8 *base = &(table_base+var_data->data);
+        const HBUINT8 *p = base;
+        if (!unpack_points (p, shared_indices, (const HBUINT8 *) (var_data_bytes.arrayZ + var_data_bytes.length))) return false;
+        data_offset = p - base;
+      }
+      return true;
+    }
+
+    bool is_valid () const
+    {
+      return (index < var_data->tupleVarCount.get_count ()) &&
+             var_data_bytes.check_range (current_tuple, TupleVariationHeader::min_size) &&
+             var_data_bytes.check_range (current_tuple, hb_max (current_tuple->get_data_size (),
+                                                                current_tuple->get_size (axis_count)));
+    }
+
+    bool move_to_next ()
+    {
+      data_offset += current_tuple->get_data_size ();
+      current_tuple = &current_tuple->get_next (axis_count);
+      index++;
+      return is_valid ();
+    }
+
+    const HBUINT8 *get_serialized_data () const
+    { return &(table_base+var_data->data) + data_offset; }
+
+    private:
+    const TupleVariationData *var_data;
+    unsigned int index;
+    unsigned int axis_count;
+    unsigned int data_offset;
+    const void *table_base;
+
+    public:
+    hb_bytes_t var_data_bytes;
+    const TupleVariationHeader *current_tuple;
+  };
+
+  static bool get_tuple_iterator (hb_bytes_t var_data_bytes, unsigned axis_count,
+                                  const void *table_base,
+                                  hb_vector_t<unsigned int> &shared_indices /* OUT */,
+                                  tuple_iterator_t *iterator /* OUT */)
+  {
+    iterator->init (var_data_bytes, axis_count, table_base);
+    if (!iterator->get_shared_indices (shared_indices))
+      return false;
+    return iterator->is_valid ();
+  }
+
+  bool has_shared_point_numbers () const { return tupleVarCount.has_shared_point_numbers (); }
+
+  static bool unpack_points (const HBUINT8 *&p /* IN/OUT */,
+                             hb_vector_t<unsigned int> &points /* OUT */,
+                             const HBUINT8 *end)
+  {
+    enum packed_point_flag_t
+    {
+      POINTS_ARE_WORDS     = 0x80,
+      POINT_RUN_COUNT_MASK = 0x7F
+    };
+
+    if (unlikely (p + 1 > end)) return false;
+
+    unsigned count = *p++;
+    if (count & POINTS_ARE_WORDS)
+    {
+      if (unlikely (p + 1 > end)) return false;
+      count = ((count & POINT_RUN_COUNT_MASK) << 8) | *p++;
+    }
+    if (unlikely (!points.resize (count, false))) return false;
+
+    unsigned n = 0;
+    unsigned i = 0;
+    while (i < count)
+    {
+      if (unlikely (p + 1 > end)) return false;
+      unsigned control = *p++;
+      unsigned run_count = (control & POINT_RUN_COUNT_MASK) + 1;
+      unsigned stop = i + run_count;
+      if (unlikely (stop > count)) return false;
+      if (control & POINTS_ARE_WORDS)
+      {
+        if (unlikely (p + run_count * HBUINT16::static_size > end)) return false;
+        for (; i < stop; i++)
+        {
+          n += *(const HBUINT16 *)p;
+          points.arrayZ[i] = n;
+          p += HBUINT16::static_size;
+        }
+      }
+      else
+      {
+        if (unlikely (p + run_count > end)) return false;
+        for (; i < stop; i++)
+        {
+          n += *p++;
+          points.arrayZ[i] = n;
+        }
+      }
+    }
+    return true;
+  }
+
+  static bool unpack_deltas (const HBUINT8 *&p /* IN/OUT */,
+                             hb_vector_t<int> &deltas /* IN/OUT */,
+                             const HBUINT8 *end)
+  {
+    unsigned i = 0;
+    unsigned count = deltas.length;
+    while (i < count)
+    {
+      if (unlikely (p + 1 > end)) return false;
+      unsigned control = *p++;
+      unsigned run_count = (control & DELTA_RUN_COUNT_MASK) + 1;
+      unsigned stop = i + run_count;
+      if (unlikely (stop > count)) return false;
+      if (control & DELTAS_ARE_ZERO)
+      {
+        for (; i < stop; i++)
+          deltas.arrayZ[i] = 0;
+      }
+      else if (control & DELTAS_ARE_WORDS)
+      {
+        if (unlikely (p + run_count * HBUINT16::static_size > end)) return false;
+        for (; i < stop; i++)
+        {
+          deltas.arrayZ[i] = * (const HBINT16 *) p;
+          p += HBUINT16::static_size;
+        }
+      }
+      else
+      {
+        if (unlikely (p + run_count > end)) return false;
+        for (; i < stop; i++)
+        {
+          deltas.arrayZ[i] = * (const HBINT8 *) p++;
+        }
+      }
+    }
+    return true;
+  }
+
+  bool has_data () const { return tupleVarCount; }
+
+  bool decompile_tuple_variations (unsigned point_count,
+                                   bool is_gvar,
+                                   tuple_iterator_t iterator,
+                                   const hb_map_t *axes_old_index_tag_map,
+                                   const hb_vector_t<unsigned> &shared_indices,
+                                   const hb_array_t<const F2DOT14> shared_tuples,
+                                   tuple_variations_t& tuple_variations /* OUT */) const
+  {
+    return tuple_variations.create_from_tuple_var_data (iterator, tupleVarCount,
+                                                        point_count, is_gvar,
+                                                        axes_old_index_tag_map,
+                                                        shared_indices,
+                                                        shared_tuples);
+  }
+
+  bool serialize (hb_serialize_context_t *c,
+                  bool is_gvar,
+                  const tuple_variations_t& tuple_variations) const
+  {
+    TRACE_SERIALIZE (this);
+    /* empty tuple variations, just return and skip serialization. */
+    if (!tuple_variations) return_trace (true);
+
+    auto *out = c->start_embed (this);
+    if (unlikely (!c->extend_min (out))) return_trace (false);
+
+    if (!c->check_assign (out->tupleVarCount, tuple_variations.get_var_count (),
+                          HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
+
+    unsigned total_header_len = 0;
+
+    if (!tuple_variations.serialize_var_headers (c, total_header_len))
+      return_trace (false);
+    
+    unsigned data_offset = min_size + total_header_len;
+    if (!is_gvar) data_offset += 4;
+    if (!c->check_assign (out->data, data_offset, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
+
+    return tuple_variations.serialize_var_data (c, is_gvar);
+  }
+
+  protected:
+  struct TupleVarCount : HBUINT16
+  {
+    friend struct tuple_variations_t;
+    bool has_shared_point_numbers () const { return ((*this) & SharedPointNumbers); }
+    unsigned int get_count () const { return (*this) & CountMask; }
+    TupleVarCount& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
+    explicit operator bool () const { return get_count (); }
+
+    protected:
+    enum Flags
+    {
+      SharedPointNumbers= 0x8000u,
+      CountMask         = 0x0FFFu
+    };
+    public:
+    DEFINE_SIZE_STATIC (2);
+  };
+
+  TupleVarCount tupleVarCount;  /* A packed field. The high 4 bits are flags, and the
+                                 * low 12 bits are the number of tuple variation tables
+                                 * for this glyph. The number of tuple variation tables
+                                 * can be any number between 1 and 4095. */
+  Offset16To<HBUINT8>
+                data;           /* Offset from the start of the base table
+                                 * to the serialized data. */
+  /* TupleVariationHeader tupleVariationHeaders[] *//* Array of tuple variation headers. */
+  public:
+  DEFINE_SIZE_MIN (4);
+};
+
+using tuple_variations_t = TupleVariationData::tuple_variations_t;
+struct item_variations_t
+{
+  using region_t = const hb_hashmap_t<hb_tag_t, Triple>*;
+  private:
+  /* each subtable is decompiled into a tuple_variations_t, in which all tuples
+   * have the same num of deltas (rows) */
+  hb_vector_t<tuple_variations_t> vars;
+
+  /* original region list, decompiled from item varstore, used when rebuilding
+   * region list after instantiation */
+  hb_vector_t<hb_hashmap_t<hb_tag_t, Triple>> orig_region_list;
+
+  /* region list: vector of Regions, maintain the original order for the regions
+   * that existed before instantiate (), append the new regions at the end.
+   * Regions are stored in each tuple already, save pointers only.
+   * When converting back to item varstore, unused regions will be pruned */
+  hb_vector_t<region_t> region_list;
+
+  /* region -> idx map after instantiation and pruning unused regions */
+  hb_hashmap_t<region_t, unsigned> region_map;
+
+  /* all delta rows after instantiation */
+  hb_vector_t<hb_vector_t<int>> delta_rows;
+  /* final optimized vector of encoding objects used to assemble the varstore */
+  hb_vector_t<delta_row_encoding_t> encodings;
+
+  /* old varidxes -> new var_idxes map */
+  hb_map_t varidx_map;
+
+  /* has long words */
+  bool has_long = false;
+
+  public:
+  bool has_long_word () const
+  { return has_long; }
+
+  const hb_vector_t<region_t>& get_region_list () const
+  { return region_list; }
+
+  const hb_vector_t<delta_row_encoding_t>& get_vardata_encodings () const
+  { return encodings; }
+
+  const hb_map_t& get_varidx_map () const
+  { return varidx_map; }
+
+  bool instantiate (const VariationStore& varStore,
+                    const hb_subset_plan_t *plan,
+                    bool optimize=true,
+                    bool use_no_variation_idx=true,
+                    const hb_array_t <const hb_inc_bimap_t> inner_maps = hb_array_t<const hb_inc_bimap_t> ())
+  {
+    if (!create_from_item_varstore (varStore, plan->axes_old_index_tag_map, inner_maps))
+      return false;
+    if (!instantiate_tuple_vars (plan->axes_location, plan->axes_triple_distances))
+      return false;
+    return as_item_varstore (optimize, use_no_variation_idx);
+  }
+
+  /* keep below APIs public only for unit test: test-item-varstore */
+  bool create_from_item_varstore (const VariationStore& varStore,
+                                  const hb_map_t& axes_old_index_tag_map,
+                                  const hb_array_t <const hb_inc_bimap_t> inner_maps = hb_array_t<const hb_inc_bimap_t> ())
+  {
+    const VarRegionList& regionList = varStore.get_region_list ();
+    if (!regionList.get_var_regions (axes_old_index_tag_map, orig_region_list))
+      return false;
+
+    unsigned num_var_data = varStore.get_sub_table_count ();
+    if (inner_maps && inner_maps.length != num_var_data) return false;
+    if (!vars.alloc (num_var_data)) return false;
+
+    for (unsigned i = 0; i < num_var_data; i++)
+    {
+      if (inner_maps && !inner_maps.arrayZ[i].get_population ())
+          continue;
+      tuple_variations_t var_data_tuples;
+      if (!var_data_tuples.create_from_item_var_data (varStore.get_sub_table (i),
+                                                      orig_region_list,
+                                                      axes_old_index_tag_map,
+                                                      inner_maps ? &(inner_maps.arrayZ[i]) : nullptr))
+        return false;
+
+      vars.push (std::move (var_data_tuples));
+    }
+    return !vars.in_error ();
+  }
+
+  bool instantiate_tuple_vars (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
+                               const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances)
+  {
+    for (tuple_variations_t& tuple_vars : vars)
+      if (!tuple_vars.instantiate (normalized_axes_location, axes_triple_distances))
+        return false;
+
+    if (!build_region_list ()) return false;
+    return true;
+  }
+
+  bool build_region_list ()
+  {
+    /* scan all tuples and collect all unique regions, prune unused regions */
+    hb_hashmap_t<region_t, unsigned> all_regions;
+    hb_hashmap_t<region_t, unsigned> used_regions;
+
+    /* use a vector when inserting new regions, make result deterministic */
+    hb_vector_t<region_t> all_unique_regions;
+    for (const tuple_variations_t& sub_table : vars)
+    {
+      for (const tuple_delta_t& tuple : sub_table.tuple_vars)
+      {
+        region_t r = &(tuple.axis_tuples);
+        if (!used_regions.has (r))
+        {
+          bool all_zeros = true;
+          for (float d : tuple.deltas_x)
+          {
+            int delta = (int) roundf (d);
+            if (delta != 0)
+            {
+              all_zeros = false;
+              break;
+            }
+          }
+          if (!all_zeros)
+          {
+            if (!used_regions.set (r, 1))
+              return false;
+          }
+        }
+        if (all_regions.has (r))
+          continue;
+        if (!all_regions.set (r, 1))
+          return false;
+        all_unique_regions.push (r);
+      }
+    }
+
+    if (!all_regions || !all_unique_regions) return false;
+    if (!region_list.alloc (all_regions.get_population ()))
+      return false;
+
+    unsigned idx = 0;
+    /* append the original regions that pre-existed */
+    for (const auto& r : orig_region_list)
+    {
+      if (!all_regions.has (&r) || !used_regions.has (&r))
+        continue;
+
+      region_list.push (&r);
+      if (!region_map.set (&r, idx))
+        return false;
+      all_regions.del (&r);
+      idx++;
+    }
+
+    /* append the new regions at the end */
+    for (const auto& r: all_unique_regions)
+    {
+      if (!all_regions.has (r) || !used_regions.has (r))
+        continue;
+      region_list.push (r);
+      if (!region_map.set (r, idx))
+        return false;
+      all_regions.del (r);
+      idx++;
+    }
+    return (!region_list.in_error ()) && (!region_map.in_error ());
+  }
+
+  /* main algorithm ported from fonttools VarStore_optimize() method, optimize
+   * varstore by default */
+
+  struct combined_gain_idx_tuple_t
+  {
+    int gain;
+    unsigned idx_1;
+    unsigned idx_2;
+
+    combined_gain_idx_tuple_t () = default;
+    combined_gain_idx_tuple_t (int gain_, unsigned i, unsigned j)
+        :gain (gain_), idx_1 (i), idx_2 (j) {}
+
+    bool operator < (const combined_gain_idx_tuple_t& o)
+    {
+      if (gain != o.gain)
+        return gain < o.gain;
+
+      if (idx_1 != o.idx_1)
+        return idx_1 < o.idx_1;
+
+      return idx_2 < o.idx_2;
+    }
+
+    bool operator <= (const combined_gain_idx_tuple_t& o)
+    {
+      if (*this < o) return true;
+      return gain == o.gain && idx_1 == o.idx_1 && idx_2 == o.idx_2;
+    }
+  };
+
+  bool as_item_varstore (bool optimize=true, bool use_no_variation_idx=true)
+  {
+    if (!region_list) return false;
+    unsigned num_cols = region_list.length;
+    /* pre-alloc a 2D vector for all sub_table's VarData rows */
+    unsigned total_rows = 0;
+    for (unsigned major = 0; major < vars.length; major++)
+    {
+      const tuple_variations_t& tuples = vars[major];
+      /* all tuples in each sub_table should have same num of deltas(num rows) */
+      total_rows += tuples.tuple_vars[0].deltas_x.length;
+    }
+
+    if (!delta_rows.resize (total_rows)) return false;
+    /* init all rows to [0]*num_cols */
+    for (unsigned i = 0; i < total_rows; i++)
+      if (!(delta_rows[i].resize (num_cols))) return false;
+
+    /* old VarIdxes -> full encoding_row mapping */
+    hb_hashmap_t<unsigned, const hb_vector_t<int>*> front_mapping;
+    unsigned start_row = 0;
+    hb_vector_t<delta_row_encoding_t> encoding_objs;
+    hb_hashmap_t<hb_vector_t<uint8_t>, unsigned> chars_idx_map;
+
+    /* delta_rows map, used for filtering out duplicate rows */
+    hb_hashmap_t<const hb_vector_t<int>*, unsigned> delta_rows_map;
+    for (unsigned major = 0; major < vars.length; major++)
+    {
+      /* deltas are stored in tuples(column based), convert them back into items
+       * (row based) delta */
+      const tuple_variations_t& tuples = vars[major];
+      unsigned num_rows = tuples.tuple_vars[0].deltas_x.length;
+      for (const tuple_delta_t& tuple: tuples.tuple_vars)
+      {
+        if (tuple.deltas_x.length != num_rows)
+          return false;
+
+        /* skip unused regions */
+        unsigned *col_idx;
+        if (!region_map.has (&(tuple.axis_tuples), &col_idx))
+          continue;
+
+        for (unsigned i = 0; i < num_rows; i++)
+        {
+          int rounded_delta = roundf (tuple.deltas_x[i]);
+          delta_rows[start_row + i][*col_idx] += rounded_delta;
+          if ((!has_long) && (rounded_delta < -65536 || rounded_delta > 65535))
+            has_long = true;
+        }
+      }
+
+      if (!optimize)
+      {
+        /* assemble a delta_row_encoding_t for this subtable, skip optimization so
+         * chars is not initialized, we only need delta rows for serialization */
+        delta_row_encoding_t obj;
+        for (unsigned r = start_row; r < start_row + num_rows; r++)
+          obj.add_row (&(delta_rows.arrayZ[r]));
+
+        encodings.push (std::move (obj));
+        start_row += num_rows;
+        continue;
+      }
+
+      for (unsigned minor = 0; minor < num_rows; minor++)
+      {
+        const hb_vector_t<int>& row = delta_rows[start_row + minor];
+        if (use_no_variation_idx)
+        {
+          bool all_zeros = true;
+          for (int delta : row)
+          {
+            if (delta != 0)
+            {
+              all_zeros = false;
+              break;
+            }
+          }
+          if (all_zeros)
+            continue;
+        }
+
+        if (!front_mapping.set ((major<<16) + minor, &row))
+          return false;
+
+        hb_vector_t<uint8_t> chars = delta_row_encoding_t::get_row_chars (row);
+        if (!chars) return false;
+
+        if (delta_rows_map.has (&row))
+          continue;
+
+        delta_rows_map.set (&row, 1);
+        unsigned *obj_idx;
+        if (chars_idx_map.has (chars, &obj_idx))
+        {
+          delta_row_encoding_t& obj = encoding_objs[*obj_idx];
+          if (!obj.add_row (&row))
+            return false;
+        }
+        else
+        {
+          if (!chars_idx_map.set (chars, encoding_objs.length))
+            return false;
+          delta_row_encoding_t obj (std::move (chars), &row);
+          encoding_objs.push (std::move (obj));
+        }
+      }
+
+      start_row += num_rows;
+    }
+
+    /* return directly if no optimization, maintain original VariationIndex so
+     * varidx_map would be empty */
+    if (!optimize) return !encodings.in_error ();
+
+    /* sort encoding_objs */
+    encoding_objs.qsort ();
+
+    /* main algorithm: repeatedly pick 2 best encodings to combine, and combine
+     * them */
+    hb_priority_queue_t<combined_gain_idx_tuple_t> queue;
+    unsigned num_todos = encoding_objs.length;
+    for (unsigned i = 0; i < num_todos; i++)
+    {
+      for (unsigned j = i + 1; j < num_todos; j++)
+      {
+        int combining_gain = encoding_objs.arrayZ[i].gain_from_merging (encoding_objs.arrayZ[j]);
+        if (combining_gain > 0)
+          queue.insert (combined_gain_idx_tuple_t (-combining_gain, i, j), 0);
+      }
+    }
+
+    hb_set_t removed_todo_idxes;
+    while (queue)
+    {
+      auto t = queue.pop_minimum ().first;
+      unsigned i = t.idx_1;
+      unsigned j = t.idx_2;
+
+      if (removed_todo_idxes.has (i) || removed_todo_idxes.has (j))
+        continue;
+
+      delta_row_encoding_t& encoding = encoding_objs.arrayZ[i];
+      delta_row_encoding_t& other_encoding = encoding_objs.arrayZ[j];
+
+      removed_todo_idxes.add (i);
+      removed_todo_idxes.add (j);
+
+      hb_vector_t<uint8_t> combined_chars;
+      if (!combined_chars.alloc (encoding.chars.length))
+        return false;
+
+      for (unsigned idx = 0; idx < encoding.chars.length; idx++)
+      {
+        uint8_t v = hb_max (encoding.chars.arrayZ[idx], other_encoding.chars.arrayZ[idx]);
+        combined_chars.push (v);
+      }
+
+      delta_row_encoding_t combined_encoding_obj (std::move (combined_chars));
+      for (const auto& row : hb_concat (encoding.items, other_encoding.items))
+        combined_encoding_obj.add_row (row);
+
+      for (unsigned idx = 0; idx < encoding_objs.length; idx++)
+      {
+        if (removed_todo_idxes.has (idx)) continue;
+
+        const delta_row_encoding_t& obj = encoding_objs.arrayZ[idx];
+        if (obj.chars == combined_chars)
+        {
+          for (const auto& row : obj.items)
+            combined_encoding_obj.add_row (row);
+
+          removed_todo_idxes.add (idx);
+          continue;
+        }
+
+        int combined_gain = combined_encoding_obj.gain_from_merging (obj);
+        if (combined_gain > 0)
+          queue.insert (combined_gain_idx_tuple_t (-combined_gain, idx, encoding_objs.length), 0);
+      }
+
+      encoding_objs.push (std::move (combined_encoding_obj));
+    }
+
+    int num_final_encodings = (int) encoding_objs.length - (int) removed_todo_idxes.get_population ();
+    if (num_final_encodings <= 0) return false;
+
+    if (!encodings.alloc (num_final_encodings)) return false;
+    for (unsigned i = 0; i < encoding_objs.length; i++)
+    {
+      if (removed_todo_idxes.has (i)) continue;
+      encodings.push (std::move (encoding_objs.arrayZ[i]));
+    }
+
+    /* sort again based on width, make result deterministic */
+    encodings.qsort (delta_row_encoding_t::cmp_width);
+
+    return compile_varidx_map (front_mapping);
+  }
+
+  private:
+  /* compile varidx_map for one VarData subtable (index specified by major) */
+  bool compile_varidx_map (const hb_hashmap_t<unsigned, const hb_vector_t<int>*>& front_mapping)
+  {
+    /* full encoding_row -> new VarIdxes mapping */
+    hb_hashmap_t<const hb_vector_t<int>*, unsigned> back_mapping;
+
+    for (unsigned major = 0; major < encodings.length; major++)
+    {
+      delta_row_encoding_t& encoding = encodings[major];
+      /* just sanity check, this shouldn't happen */
+      if (encoding.is_empty ())
+        return false;
+  
+      unsigned num_rows = encoding.items.length;
+  
+      /* sort rows, make result deterministic */
+      encoding.items.qsort (_cmp_row);
+  
+      /* compile old to new var_idxes mapping */
+      for (unsigned minor = 0; minor < num_rows; minor++)
+      {
+        unsigned new_varidx = (major << 16) + minor;
+        back_mapping.set (encoding.items.arrayZ[minor], new_varidx);
+      }
+    }
+
+    for (auto _ : front_mapping.iter ())
+    {
+      unsigned old_varidx = _.first;
+      unsigned *new_varidx;
+      if (back_mapping.has (_.second, &new_varidx))
+        varidx_map.set (old_varidx, *new_varidx);
+      else
+        varidx_map.set (old_varidx, HB_OT_LAYOUT_NO_VARIATIONS_INDEX);
+    }
+    return !varidx_map.in_error ();
+  }
+
+  static int _cmp_row (const void *pa, const void *pb)
+  {
+    /* compare pointers of vectors(const hb_vector_t<int>*) that represent a row */
+    const hb_vector_t<int>** a = (const hb_vector_t<int>**) pa;
+    const hb_vector_t<int>** b = (const hb_vector_t<int>**) pb;
+
+    for (unsigned i = 0; i < (*b)->length; i++)
+    {
+      int va = (*a)->arrayZ[i];
+      int vb = (*b)->arrayZ[i];
+      if (va != vb)
+        return va < vb ? -1 : 1;
+    }
+    return 0;
+  }
+};
+
 } /* namespace OT */
 
 
diff --git a/src/hb-ot-var-cvar-table.hh b/src/hb-ot-var-cvar-table.hh
new file mode 100644 (file)
index 0000000..381ae3c
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Copyright © 2023  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.
+ *
+ */
+
+#ifndef HB_OT_VAR_CVAR_TABLE_HH
+#define HB_OT_VAR_CVAR_TABLE_HH
+
+#include "hb-ot-var-common.hh"
+#include "hb-ot-var-fvar-table.hh"
+
+
+namespace OT {
+/*
+ * cvar -- control value table (CVT) Variations
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/cvar
+ */
+#define HB_OT_TAG_cvar HB_TAG('c','v','a','r')
+
+struct cvar
+{
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_cvar;
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                 version.sanitize (c) && likely (version.major == 1) &&
+                 tupleVariationData.sanitize (c));
+  }
+
+  const TupleVariationData* get_tuple_var_data (void) const
+  { return &tupleVariationData; }
+
+  bool decompile_tuple_variations (unsigned axis_count,
+                                   unsigned point_count,
+                                   hb_blob_t *blob,
+                                   bool is_gvar,
+                                   const hb_map_t *axes_old_index_tag_map,
+                                   TupleVariationData::tuple_variations_t& tuple_variations /* OUT */) const
+  {
+    hb_vector_t<unsigned> shared_indices;
+    TupleVariationData::tuple_iterator_t iterator;
+    hb_bytes_t var_data_bytes = blob->as_bytes ().sub_array (4);
+    if (!TupleVariationData::get_tuple_iterator (var_data_bytes, axis_count, this,
+                                                 shared_indices, &iterator))
+      return false;
+    
+    return tupleVariationData.decompile_tuple_variations (point_count, is_gvar, iterator,
+                                                          axes_old_index_tag_map,
+                                                          shared_indices,
+                                                          hb_array<const F2DOT14> (),
+                                                          tuple_variations);
+  }
+
+  static bool calculate_cvt_deltas (unsigned axis_count,
+                                    hb_array_t<int> coords,
+                                    unsigned num_cvt_item,
+                                    const TupleVariationData *tuple_var_data,
+                                    const void *base,
+                                    hb_vector_t<float>& cvt_deltas /* OUT */)
+  {
+    if (!coords) return true;
+    hb_vector_t<unsigned> shared_indices;
+    TupleVariationData::tuple_iterator_t iterator;
+    unsigned var_data_length = tuple_var_data->get_size (axis_count);
+    hb_bytes_t var_data_bytes = hb_bytes_t (reinterpret_cast<const char*> (tuple_var_data), var_data_length);
+    if (!TupleVariationData::get_tuple_iterator (var_data_bytes, axis_count, base,
+                                                 shared_indices, &iterator))
+      return true; /* isn't applied at all */
+
+    hb_array_t<const F2DOT14> shared_tuples = hb_array<F2DOT14> ();
+    hb_vector_t<unsigned> private_indices;
+    hb_vector_t<int> unpacked_deltas;
+
+    do
+    {
+      float scalar = iterator.current_tuple->calculate_scalar (coords, axis_count, shared_tuples);
+      if (scalar == 0.f) continue;
+      const HBUINT8 *p = iterator.get_serialized_data ();
+      unsigned int length = iterator.current_tuple->get_data_size ();
+      if (unlikely (!iterator.var_data_bytes.check_range (p, length)))
+        return false;
+
+      const HBUINT8 *end = p + length;
+
+      bool has_private_points = iterator.current_tuple->has_private_points ();
+      if (has_private_points &&
+          !TupleVariationData::unpack_points (p, private_indices, end))
+        return false;
+      const hb_vector_t<unsigned int> &indices = has_private_points ? private_indices : shared_indices;
+
+      bool apply_to_all = (indices.length == 0);
+      unsigned num_deltas = apply_to_all ? num_cvt_item : indices.length;
+      if (unlikely (!unpacked_deltas.resize (num_deltas, false))) return false;
+      if (unlikely (!TupleVariationData::unpack_deltas (p, unpacked_deltas, end))) return false;
+
+      for (unsigned int i = 0; i < num_deltas; i++)
+      {
+        unsigned int idx = apply_to_all ? i : indices[i];
+        if (unlikely (idx >= num_cvt_item)) continue;
+        if (scalar != 1.0f) cvt_deltas[idx] += unpacked_deltas[i] * scalar ;
+        else cvt_deltas[idx] += unpacked_deltas[i];
+      }
+    } while (iterator.move_to_next ());
+
+    return true;
+  }
+  
+  bool serialize (hb_serialize_context_t *c,
+                  TupleVariationData::tuple_variations_t& tuple_variations) const
+  {
+    TRACE_SERIALIZE (this);
+    if (!tuple_variations) return_trace (false);
+    if (unlikely (!c->embed (version))) return_trace (false);
+
+    return_trace (tupleVariationData.serialize (c, false, tuple_variations));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    if (c->plan->all_axes_pinned)
+      return_trace (false);
+
+    OT::TupleVariationData::tuple_variations_t tuple_variations;
+    unsigned axis_count = c->plan->axes_old_index_tag_map.get_population ();
+
+    const hb_tag_t cvt = HB_TAG('c','v','t',' ');
+    hb_blob_t *cvt_blob = hb_face_reference_table (c->plan->source, cvt);
+    unsigned point_count = hb_blob_get_length (cvt_blob) / FWORD::static_size;
+    hb_blob_destroy (cvt_blob);
+
+    if (!decompile_tuple_variations (axis_count, point_count,
+                                     c->source_blob, false,
+                                     &(c->plan->axes_old_index_tag_map),
+                                     tuple_variations))
+      return_trace (false);
+
+    if (!tuple_variations.instantiate (c->plan->axes_location, c->plan->axes_triple_distances))
+      return_trace (false);
+
+    if (!tuple_variations.compile_bytes (c->plan->axes_index_map, c->plan->axes_old_index_tag_map,
+                                         false /* do not use shared points */))
+      return_trace (false);
+
+    return_trace (serialize (c->serializer, tuple_variations));
+  }
+
+  static bool add_cvt_and_apply_deltas (hb_subset_plan_t *plan,
+                                        const TupleVariationData *tuple_var_data,
+                                        const void *base)
+  {
+    const hb_tag_t cvt = HB_TAG('c','v','t',' ');
+    hb_blob_t *cvt_blob = hb_face_reference_table (plan->source, cvt);
+    hb_blob_t *cvt_prime_blob = hb_blob_copy_writable_or_fail (cvt_blob);
+    hb_blob_destroy (cvt_blob);
+  
+    if (unlikely (!cvt_prime_blob))
+      return false;
+    unsigned cvt_blob_length = hb_blob_get_length (cvt_prime_blob);
+    unsigned num_cvt_item = cvt_blob_length / FWORD::static_size;
+
+    hb_vector_t<float> cvt_deltas;
+    if (unlikely (!cvt_deltas.resize (num_cvt_item)))
+    {
+      hb_blob_destroy (cvt_prime_blob);
+      return false;
+    }
+
+    if (!calculate_cvt_deltas (plan->normalized_coords.length, plan->normalized_coords.as_array (),
+                               num_cvt_item, tuple_var_data, base, cvt_deltas))
+    {
+      hb_blob_destroy (cvt_prime_blob);
+      return false;
+    }
+
+    FWORD *cvt_prime = (FWORD *) hb_blob_get_data_writable (cvt_prime_blob, nullptr);
+    for (unsigned i = 0; i < num_cvt_item; i++)
+      cvt_prime[i] += (int) roundf (cvt_deltas[i]);
+    
+    bool success = plan->add_table (cvt, cvt_prime_blob);
+    hb_blob_destroy (cvt_prime_blob);
+    return success;
+  }
+
+  protected:
+  FixedVersion<>version;               /* Version of the CVT variation table
+                                        * initially set to 0x00010000u */
+  TupleVariationData tupleVariationData; /* TupleVariationDate for cvar table */
+  public:
+  DEFINE_SIZE_MIN (8);
+};
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_VAR_CVAR_TABLE_HH */
index e066558..4c4957b 100644 (file)
 
 namespace OT {
 
+static bool axis_coord_pinned_or_within_axis_range (const hb_array_t<const F16DOT16> coords,
+                                                    unsigned axis_index,
+                                                    Triple axis_limit)
+{
+  float axis_coord = coords[axis_index].to_float ();
+  if (axis_limit.is_point ())
+  {
+    if (axis_limit.minimum != axis_coord)
+      return false;
+  }
+  else
+  {
+    if (axis_coord < axis_limit.minimum ||
+        axis_coord > axis_limit.maximum)
+      return false;
+  }
+  return true;
+}
 
 struct InstanceRecord
 {
   friend struct fvar;
 
-  hb_array_t<const HBFixed> get_coordinates (unsigned int axis_count) const
+  hb_array_t<const F16DOT16> get_coordinates (unsigned int axis_count) const
   { return coordinatesZ.as_array (axis_count); }
 
+  bool keep_instance (unsigned axis_count,
+                      const hb_map_t *axes_index_tag_map,
+                      const hb_hashmap_t<hb_tag_t, Triple> *axes_location) const
+  {
+    if (axes_location->is_empty ()) return true;
+    const hb_array_t<const F16DOT16> coords = get_coordinates (axis_count);
+    for (unsigned i = 0 ; i < axis_count; i++)
+    {
+      uint32_t *axis_tag;
+      if (!axes_index_tag_map->has (i, &axis_tag))
+        return false;
+      if (!axes_location->has (*axis_tag))
+        continue;
+      
+      Triple axis_limit = axes_location->get (*axis_tag);
+      if (!axis_coord_pinned_or_within_axis_range (coords, i, axis_limit))
+        return false;
+    }
+    return true;
+  }
+
+  bool subset (hb_subset_context_t *c,
+               unsigned axis_count,
+               bool has_postscript_nameid) const
+  {
+    TRACE_SUBSET (this);
+    if (unlikely (!c->serializer->embed (subfamilyNameID))) return_trace (false);
+    if (unlikely (!c->serializer->embed (flags))) return_trace (false);
+
+    const hb_array_t<const F16DOT16> coords = get_coordinates (axis_count);
+    const hb_hashmap_t<hb_tag_t, Triple> *axes_location = &c->plan->user_axes_location;
+    for (unsigned i = 0 ; i < axis_count; i++)
+    {
+      uint32_t *axis_tag;
+      Triple *axis_limit;
+      // only keep instances whose coordinates == pinned axis location
+      if (!c->plan->axes_old_index_tag_map.has (i, &axis_tag)) return_trace (false);
+      if (axes_location->has (*axis_tag, &axis_limit))
+      {
+        if (!axis_coord_pinned_or_within_axis_range (coords, i, *axis_limit))
+          return_trace (false);
+        
+        //skip pinned axis
+        if (axis_limit->is_point ())
+          continue;
+      }
+
+      if (!c->serializer->embed (coords[i]))
+        return_trace (false);
+    }
+
+    if (has_postscript_nameid)
+    {
+      NameID name_id;
+      name_id = StructAfter<NameID> (coords);
+      if (!c->serializer->embed (name_id))
+        return_trace (false);
+    }
+
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c, unsigned int axis_count) const
   {
     TRACE_SANITIZE (this);
@@ -58,7 +138,7 @@ struct InstanceRecord
   NameID       subfamilyNameID;/* The name ID for entries in the 'name' table
                                 * that provide subfamily names for this instance. */
   HBUINT16     flags;          /* Reserved for future use — set to 0. */
-  UnsizedArrayOf<HBFixed>
+  UnsizedArrayOf<F16DOT16>
                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
@@ -96,6 +176,8 @@ struct AxisRecord
     info->reserved = 0;
   }
 
+  hb_tag_t get_axis_tag () const { return axisTag; }
+
   int normalize_axis_value (float v) const
   {
     float min_value, default_value, max_value;
@@ -133,21 +215,49 @@ struct AxisRecord
     return_trace (c->check_struct (this));
   }
 
-  protected:
   void get_coordinates (float &min, float &default_, float &max) const
   {
-    default_ = defaultValue / 65536.f;
+    default_ = defaultValue.to_float ();
     /* Ensure order, to simplify client math. */
-    min = hb_min (default_, minValue / 65536.f);
-    max = hb_max (default_, maxValue / 65536.f);
+    min = hb_min (default_, minValue.to_float ());
+    max = hb_max (default_, maxValue.to_float ());
+  }
+
+  float get_default () const
+  {
+    return defaultValue.to_float ();
+  }
+
+  TripleDistances get_triple_distances () const
+  {
+    float min, default_, max;
+    get_coordinates (min, default_, max);
+    return TripleDistances (min, default_, max);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+
+    const hb_hashmap_t<hb_tag_t, Triple>& user_axes_location = c->plan->user_axes_location;
+    Triple *axis_limit;
+    if (user_axes_location.has (axisTag, &axis_limit))
+    {
+      out->minValue.set_float (axis_limit->minimum);
+      out->defaultValue.set_float (axis_limit->middle);
+      out->maxValue.set_float (axis_limit->maximum);
+    }
+    return_trace (true);
   }
 
   public:
   Tag          axisTag;        /* Tag identifying the design variation for the axis. */
   protected:
-  HBFixed      minValue;       /* The minimum coordinate value for the axis. */
-  HBFixed      defaultValue;   /* The default coordinate value for the axis. */
-  HBFixed      maxValue;       /* The maximum coordinate value for the axis. */
+  F16DOT16     minValue;       /* The minimum coordinate value for the axis. */
+  F16DOT16     defaultValue;   /* The default coordinate value for the axis. */
+  F16DOT16     maxValue;       /* The maximum coordinate value for the axis. */
   public:
   HBUINT16     flags;          /* Axis flags. */
   NameID       axisNameID;     /* The name ID for entries in the 'name' table that
@@ -172,7 +282,8 @@ struct fvar
                  axisSize == 20 && /* Assumed in our code. */
                  instanceSize >= axisCount * 4 + 4 &&
                  get_axes ().sanitize (c) &&
-                 c->check_range (get_instance (0), instanceCount, instanceSize));
+                 c->check_range (&StructAfter<InstanceRecord> (get_axes ()),
+                                 instanceCount, instanceSize));
   }
 
   unsigned int get_axis_count () const { return axisCount; }
@@ -213,7 +324,7 @@ struct fvar
     if (!axis_index) axis_index = &i;
     *axis_index = HB_OT_VAR_NO_AXIS_INDEX;
     auto axes = get_axes ();
-    return axes.lfind (tag, axis_index) && (axes[*axis_index].get_axis_deprecated (info), true);
+    return axes.lfind (tag, axis_index) && ((void) axes[*axis_index].get_axis_deprecated (info), true);
   }
 #endif
   bool
@@ -221,7 +332,7 @@ struct fvar
   {
     unsigned i;
     auto axes = get_axes ();
-    return axes.lfind (tag, &i) && (axes[i].get_axis_info (i, info), true);
+    return axes.lfind (tag, &i) && ((void) axes[i].get_axis_info (i, info), true);
   }
 
   int normalize_axis_value (unsigned int axis_index, float v) const
@@ -262,7 +373,7 @@ struct fvar
 
     if (coords_length && *coords_length)
     {
-      hb_array_t<const HBFixed> instanceCoords = instance->get_coordinates (axisCount)
+      hb_array_t<const F16DOT16> 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 ();
@@ -270,24 +381,84 @@ struct fvar
     return axisCount;
   }
 
-  void collect_name_ids (hb_set_t *nameids) const
+  void collect_name_ids (hb_hashmap_t<hb_tag_t, Triple> *user_axes_location,
+                        hb_map_t *axes_old_index_tag_map,
+                        hb_set_t *nameids  /* IN/OUT */) const
   {
     if (!has_data ()) return;
 
-    + get_axes ()
-    | hb_map (&AxisRecord::get_name_id)
-    | hb_sink (nameids)
-    ;
+    auto axis_records = get_axes ();
+    for (unsigned i = 0 ; i < (unsigned)axisCount; i++)
+    {
+      hb_tag_t axis_tag = axis_records[i].get_axis_tag ();
+      if (user_axes_location->has (axis_tag) &&
+          user_axes_location->get (axis_tag).is_point ())
+        continue;
+
+      nameids->add (axis_records[i].get_name_id ());
+    }
+
+    for (unsigned i = 0 ; i < (unsigned)instanceCount; i++)
+    {
+      const InstanceRecord *instance = get_instance (i);
+
+      if (!instance->keep_instance (axisCount, axes_old_index_tag_map, user_axes_location))
+        continue;
+
+      nameids->add (instance->subfamilyNameID);
+
+      if (instanceSize >= axisCount * 4 + 6)
+      {
+        unsigned post_script_name_id = StructAfter<NameID> (instance->get_coordinates (axisCount));
+        if (post_script_name_id != HB_OT_NAME_ID_INVALID) nameids->add (post_script_name_id);
+      }
+    }
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    unsigned retained_axis_count = c->plan->axes_index_map.get_population ();
+    if (!retained_axis_count) //all axes are pinned
+      return_trace (false);
+
+    fvar *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+
+    if (!c->serializer->check_assign (out->axisCount, retained_axis_count, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+      return_trace (false);
+
+    bool has_postscript_nameid = false;
+    if (instanceSize >= axisCount * 4 + 6)
+      has_postscript_nameid = true;
+
+    if (!c->serializer->check_assign (out->instanceSize, retained_axis_count * 4 + (has_postscript_nameid ? 6 : 4),
+                                      HB_SERIALIZE_ERROR_INT_OVERFLOW))
+      return_trace (false);
+
+    auto axes_records = get_axes ();
+    for (unsigned i = 0 ; i < (unsigned)axisCount; i++)
+    {
+      if (!c->plan->axes_index_map.has (i)) continue;
+      if (unlikely (!axes_records[i].subset (c)))
+        return_trace (false);
+    }
 
-    + hb_range ((unsigned) instanceCount)
-    | hb_map ([this] (const unsigned _) { return get_instance_subfamily_name_id (_); })
-    | hb_sink (nameids)
-    ;
+    if (!c->serializer->check_assign (out->firstAxis, get_size (), HB_SERIALIZE_ERROR_INT_OVERFLOW))
+      return_trace (false);
+
+    unsigned num_retained_instances = 0;
+    for (unsigned i = 0 ; i < (unsigned)instanceCount; i++)
+    {
+      const InstanceRecord *instance = get_instance (i);
+      auto snap = c->serializer->snapshot ();
+      if (!instance->subset (c, axisCount, has_postscript_nameid))
+        c->serializer->revert (snap);
+      else
+        num_retained_instances++;
+    }
 
-    + hb_range ((unsigned) instanceCount)
-    | hb_map ([this] (const unsigned _) { return get_instance_postscript_name_id (_); })
-    | hb_sink (nameids)
-    ;
+    return_trace (c->serializer->check_assign (out->instanceCount, num_retained_instances, HB_SERIALIZE_ERROR_INT_OVERFLOW));
   }
 
   public:
@@ -315,8 +486,8 @@ struct fvar
   HBUINT16     instanceCount;  /* The number of named instances defined in the font
                                 * (the number of records in the instances array). */
   HBUINT16     instanceSize;   /* The size in bytes of each InstanceRecord — set
-                                * to either axisCount * sizeof(HBFixed) + 4, or to
-                                * axisCount * sizeof(HBFixed) + 6. */
+                                * to either axisCount * sizeof(F16DOT16) + 4, or to
+                                * axisCount * sizeof(F16DOT16) + 6. */
 
   public:
   DEFINE_SIZE_STATIC (16);
index 539213c..8ef9f0e 100644 (file)
@@ -29,6 +29,7 @@
 #define HB_OT_VAR_GVAR_TABLE_HH
 
 #include "hb-open-type.hh"
+#include "hb-ot-var-common.hh"
 
 /*
  * gvar -- Glyph Variation Table
 
 namespace OT {
 
-struct contour_point_t
+struct GlyphVariationData : TupleVariationData
+{};
+
+struct glyph_variations_t
 {
-  void init (float x_ = 0.f, float y_ = 0.f, bool is_end_point_ = false)
-  { flag = 0; x = x_; y = y_; is_end_point = is_end_point_; }
+  using tuple_variations_t = TupleVariationData::tuple_variations_t;
+  hb_vector_t<tuple_variations_t> glyph_variations;
 
-  void translate (const contour_point_t &p) { x += p.x; y += p.y; }
+  hb_vector_t<char> compiled_shared_tuples;
+  private:
+  unsigned shared_tuples_count = 0;
 
-  uint8_t flag;
-  float x, y;
-  bool is_end_point;
-};
+  /* shared coords-> index map after instantiation */
+  hb_hashmap_t<const hb_vector_t<char>*, unsigned> shared_tuples_idx_map;
 
-struct contour_point_vector_t : hb_vector_t<contour_point_t>
-{
-  void extend (const hb_array_t<contour_point_t> &a)
-  {
-    unsigned int old_len = length;
-    resize (old_len + a.length);
-    for (unsigned int i = 0; i < a.length; i++)
-      (*this)[old_len + i] = a[i];
-  }
+  public:
+  unsigned compiled_shared_tuples_count () const
+  { return shared_tuples_count; }
 
-  void transform (const float (&matrix)[4])
+  unsigned compiled_byte_size () const
   {
-    for (unsigned int i = 0; i < length; i++)
-    {
-      contour_point_t &p = (*this)[i];
-      float x_ = p.x * matrix[0] + p.y * matrix[2];
-          p.y = p.x * matrix[1] + p.y * matrix[3];
-      p.x = x_;
-    }
-  }
+    unsigned byte_size = 0;
+    for (const auto& _ : glyph_variations)
+      byte_size += _.get_compiled_byte_size ();
 
-  void translate (const contour_point_t& delta)
-  {
-    for (unsigned int i = 0; i < length; i++)
-      (*this)[i].translate (delta);
+    return byte_size;
   }
-};
-
-/* https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader */
-struct TupleVariationHeader
-{
-  unsigned get_size (unsigned axis_count) const
-  { return min_size + get_all_tuples (axis_count).get_size (); }
-
-  unsigned get_data_size () const { return varDataSize; }
 
-  const TupleVariationHeader &get_next (unsigned axis_count) const
-  { return StructAtOffset<TupleVariationHeader> (this, get_size (axis_count)); }
-
-  float calculate_scalar (const int *coords, unsigned int coord_count,
-                         const hb_array_t<const F2DOT14> shared_tuples) const
+  bool create_from_glyphs_var_data (unsigned axis_count,
+                                    const hb_array_t<const F2DOT14> shared_tuples,
+                                    const hb_subset_plan_t *plan,
+                                    const hb_hashmap_t<hb_codepoint_t, hb_bytes_t>& new_gid_var_data_map)
   {
-    hb_array_t<const F2DOT14> peak_tuple;
+    if (unlikely (!glyph_variations.alloc (plan->new_to_old_gid_list.length, true)))
+      return false;
 
-    if (has_peak ())
-      peak_tuple = get_peak_tuple (coord_count);
-    else
+    auto it = hb_iter (plan->new_to_old_gid_list);
+    for (auto &_ : it)
     {
-      unsigned int index = get_index ();
-      if (unlikely (index * coord_count >= shared_tuples.length))
-       return 0.f;
-      peak_tuple = shared_tuples.sub_array (coord_count * index, coord_count);
-    }
+      hb_codepoint_t new_gid = _.first;
+      contour_point_vector_t *all_contour_points;
+      if (!new_gid_var_data_map.has (new_gid) ||
+          !plan->new_gid_contour_points_map.has (new_gid, &all_contour_points))
+        return false;
+      hb_bytes_t var_data = new_gid_var_data_map.get (new_gid);
+
+      const GlyphVariationData* p = reinterpret_cast<const GlyphVariationData*> (var_data.arrayZ);
+      hb_vector_t<unsigned> shared_indices;
+      GlyphVariationData::tuple_iterator_t iterator;
+      tuple_variations_t tuple_vars;
+
+      /* in case variation data is empty, push an empty struct into the vector,
+       * keep the vector in sync with the new_to_old_gid_list */
+      if (!var_data || ! p->has_data () || !all_contour_points->length ||
+          !GlyphVariationData::get_tuple_iterator (var_data, axis_count,
+                                                   var_data.arrayZ,
+                                                   shared_indices, &iterator))
+      {
+        glyph_variations.push (std::move (tuple_vars));
+        continue;
+      }
 
-    hb_array_t<const F2DOT14> start_tuple;
-    hb_array_t<const F2DOT14> end_tuple;
-    if (has_intermediate ())
-    {
-      start_tuple = get_start_tuple (coord_count);
-      end_tuple = get_end_tuple (coord_count);
+      if (!p->decompile_tuple_variations (all_contour_points->length, true /* is_gvar */,
+                                          iterator, &(plan->axes_old_index_tag_map),
+                                          shared_indices, shared_tuples,
+                                          tuple_vars /* OUT */))
+        return false;
+      glyph_variations.push (std::move (tuple_vars));
     }
+    return !glyph_variations.in_error () && glyph_variations.length == plan->new_to_old_gid_list.length;
+  }
 
-    float scalar = 1.f;
-    for (unsigned int i = 0; i < coord_count; i++)
+  bool instantiate (const hb_subset_plan_t *plan)
+  {
+    unsigned count = plan->new_to_old_gid_list.length;
+    for (unsigned i = 0; i < count; i++)
     {
-      int v = coords[i];
-      int peak = peak_tuple[i];
-      if (!peak || v == peak) continue;
-
-      if (has_intermediate ())
-      {
-       int start = start_tuple[i];
-       int end = end_tuple[i];
-       if (unlikely (start > peak || peak > end ||
-                     (start < 0 && end > 0 && peak))) continue;
-       if (v < start || v > end) return 0.f;
-       if (v < peak)
-       { if (peak != start) scalar *= (float) (v - start) / (peak - start); }
-       else
-       { if (peak != end) scalar *= (float) (end - v) / (end - peak); }
-      }
-      else if (!v || v < hb_min (0, peak) || v > hb_max (0, peak)) return 0.f;
-      else
-       scalar *= (float) v / peak;
+      hb_codepoint_t new_gid = plan->new_to_old_gid_list[i].first;
+      contour_point_vector_t *all_points;
+      if (!plan->new_gid_contour_points_map.has (new_gid, &all_points))
+        return false;
+      if (!glyph_variations[i].instantiate (plan->axes_location, plan->axes_triple_distances, all_points))
+        return false;
     }
-    return scalar;
+    return true;
   }
 
-  bool           has_peak () const { return tupleIndex & TuppleIndex::EmbeddedPeakTuple; }
-  bool   has_intermediate () const { return tupleIndex & TuppleIndex::IntermediateRegion; }
-  bool has_private_points () const { return tupleIndex & TuppleIndex::PrivatePointNumbers; }
-  unsigned      get_index () const { return tupleIndex & TuppleIndex::TupleIndexMask; }
-
-  protected:
-  struct TuppleIndex : HBUINT16
+  bool compile_bytes (const hb_map_t& axes_index_map,
+                      const hb_map_t& axes_old_index_tag_map)
   {
-    enum Flags {
-      EmbeddedPeakTuple   = 0x8000u,
-      IntermediateRegion  = 0x4000u,
-      PrivatePointNumbers = 0x2000u,
-      TupleIndexMask      = 0x0FFFu
-    };
-
-    DEFINE_SIZE_STATIC (2);
-  };
-
-  hb_array_t<const F2DOT14> get_all_tuples (unsigned axis_count) const
-  { return StructAfter<UnsizedArrayOf<F2DOT14>> (tupleIndex).as_array ((has_peak () + has_intermediate () * 2) * axis_count); }
-  hb_array_t<const F2DOT14> get_peak_tuple (unsigned axis_count) const
-  { return get_all_tuples (axis_count).sub_array (0, axis_count); }
-  hb_array_t<const F2DOT14> get_start_tuple (unsigned axis_count) const
-  { return get_all_tuples (axis_count).sub_array (has_peak () * axis_count, axis_count); }
-  hb_array_t<const F2DOT14> get_end_tuple (unsigned axis_count) const
-  { return get_all_tuples (axis_count).sub_array (has_peak () * axis_count + axis_count, axis_count); }
-
-  HBUINT16     varDataSize;    /* The size in bytes of the serialized
-                                * data for this tuple variation table. */
-  TuppleIndex  tupleIndex;     /* A packed field. The high 4 bits are flags (see below).
-                                  The low 12 bits are an index into a shared tuple
-                                  records array. */
-  /* UnsizedArrayOf<F2DOT14> peakTuple - optional */
-                               /* Peak tuple record for this tuple variation table — optional,
-                                * determined by flags in the tupleIndex value.
-                                *
-                                * Note that this must always be included in the 'cvar' table. */
-  /* UnsizedArrayOf<F2DOT14> intermediateStartTuple - optional */
-                               /* Intermediate start tuple record for this tuple variation table — optional,
-                                  determined by flags in the tupleIndex value. */
-  /* UnsizedArrayOf<F2DOT14> intermediateEndTuple - optional */
-                               /* Intermediate end tuple record for this tuple variation table — optional,
-                                * determined by flags in the tupleIndex value. */
-  public:
-  DEFINE_SIZE_MIN (4);
-};
+    if (!compile_shared_tuples (axes_index_map, axes_old_index_tag_map))
+      return false;
+    for (tuple_variations_t& vars: glyph_variations)
+      if (!vars.compile_bytes (axes_index_map, axes_old_index_tag_map,
+                               true, /* use shared points*/
+                               &shared_tuples_idx_map))
+        return false;
 
-struct GlyphVariationData
-{
-  const TupleVariationHeader &get_tuple_var_header (void) const
-  { return StructAfter<TupleVariationHeader> (data); }
+    return true;
+  }
 
-  struct tuple_iterator_t
+  bool compile_shared_tuples (const hb_map_t& axes_index_map,
+                              const hb_map_t& axes_old_index_tag_map)
   {
-    void init (hb_bytes_t var_data_bytes_, unsigned int axis_count_)
-    {
-      var_data_bytes = var_data_bytes_;
-      var_data = var_data_bytes_.as<GlyphVariationData> ();
-      index = 0;
-      axis_count = axis_count_;
-      current_tuple = &var_data->get_tuple_var_header ();
-      data_offset = 0;
-    }
+    /* key is pointer to compiled_peak_coords inside each tuple, hashing
+     * function will always deref pointers first */
+    hb_hashmap_t<const hb_vector_t<char>*, unsigned> coords_count_map;
 
-    bool get_shared_indices (hb_vector_t<unsigned int> &shared_indices /* OUT */)
+    /* count the num of shared coords */
+    for (tuple_variations_t& vars: glyph_variations)
     {
-      if (var_data->has_shared_point_numbers ())
+      for (tuple_delta_t& var : vars.tuple_vars)
       {
-       const HBUINT8 *base = &(var_data+var_data->data);
-       const HBUINT8 *p = base;
-       if (!unpack_points (p, shared_indices, var_data_bytes)) return false;
-       data_offset = p - base;
+        if (!var.compile_peak_coords (axes_index_map, axes_old_index_tag_map))
+          return false;
+        unsigned* count;
+        if (coords_count_map.has (&(var.compiled_peak_coords), &count))
+          coords_count_map.set (&(var.compiled_peak_coords), *count + 1);
+        else
+          coords_count_map.set (&(var.compiled_peak_coords), 1);
       }
-      return true;
     }
 
-    bool is_valid () const
-    {
-      return (index < var_data->tupleVarCount.get_count ()) &&
-            var_data_bytes.check_range (current_tuple, TupleVariationHeader::min_size) &&
-            var_data_bytes.check_range (current_tuple, hb_max (current_tuple->get_data_size (), current_tuple->get_size (axis_count))) &&
-            current_tuple->get_size (axis_count);
-    }
+    if (!coords_count_map || coords_count_map.in_error ())
+      return false;
+
+    /* add only those coords that are used more than once into the vector and sort */
+    hb_vector_t<const hb_vector_t<char>*> shared_coords;
+    if (unlikely (!shared_coords.alloc (coords_count_map.get_population ())))
+      return false;
 
-    bool move_to_next ()
+    for (const auto _ : coords_count_map.iter ())
     {
-      data_offset += current_tuple->get_data_size ();
-      current_tuple = &current_tuple->get_next (axis_count);
-      index++;
-      return is_valid ();
+      if (_.second == 1) continue;
+      shared_coords.push (_.first);
     }
 
-    const HBUINT8 *get_serialized_data () const
-    { return &(var_data+var_data->data) + data_offset; }
+    /* no shared tuples: no coords are used more than once */
+    if (!shared_coords) return true;
+    /* sorting based on the coords frequency first (high to low), then compare
+     * the coords bytes */
+    hb_qsort (shared_coords.arrayZ, shared_coords.length, sizeof (hb_vector_t<char>*), _cmp_coords, (void *) (&coords_count_map));
 
-    private:
-    const GlyphVariationData *var_data;
-    unsigned int index;
-    unsigned int axis_count;
-    unsigned int data_offset;
-
-    public:
-    hb_bytes_t var_data_bytes;
-    const TupleVariationHeader *current_tuple;
-  };
+    /* build shared_coords->idx map and shared tuples byte array */
 
-  static bool get_tuple_iterator (hb_bytes_t var_data_bytes, unsigned axis_count,
-                                 hb_vector_t<unsigned int> &shared_indices /* OUT */,
-                                 tuple_iterator_t *iterator /* OUT */)
-  {
-    iterator->init (var_data_bytes, axis_count);
-    if (!iterator->get_shared_indices (shared_indices))
+    shared_tuples_count = hb_min (0xFFFu + 1, shared_coords.length);
+    unsigned len = shared_tuples_count * (shared_coords[0]->length);
+    if (unlikely (!compiled_shared_tuples.alloc (len)))
       return false;
-    return iterator->is_valid ();
-  }
 
-  bool has_shared_point_numbers () const { return tupleVarCount.has_shared_point_numbers (); }
+    for (unsigned i = 0; i < shared_tuples_count; i++)
+    {
+      shared_tuples_idx_map.set (shared_coords[i], i);
+      /* add a concat() in hb_vector_t? */
+      for (char c : shared_coords[i]->iter ())
+        compiled_shared_tuples.push (c);
+    }
 
-  static bool unpack_points (const HBUINT8 *&p /* IN/OUT */,
-                            hb_vector_t<unsigned int> &points /* OUT */,
-                            const hb_bytes_t &bytes)
+    return true;
+  }
+
+  static int _cmp_coords (const void *pa, const void *pb, void *arg)
   {
-    enum packed_point_flag_t
-    {
-      POINTS_ARE_WORDS     = 0x80,
-      POINT_RUN_COUNT_MASK = 0x7F
-    };
+    const hb_hashmap_t<const hb_vector_t<char>*, unsigned>* coords_count_map =
+        reinterpret_cast<const hb_hashmap_t<const hb_vector_t<char>*, unsigned>*> (arg);
 
-    if (unlikely (!bytes.check_range (p))) return false;
+    /* shared_coords is hb_vector_t<const hb_vector_t<char>*> so casting pa/pb
+     * to be a pointer to a pointer */
+    const hb_vector_t<char>** a = reinterpret_cast<const hb_vector_t<char>**> (const_cast<void*>(pa));
+    const hb_vector_t<char>** b = reinterpret_cast<const hb_vector_t<char>**> (const_cast<void*>(pb));
 
-    uint16_t count = *p++;
-    if (count & POINTS_ARE_WORDS)
-    {
-      if (unlikely (!bytes.check_range (p))) return false;
-      count = ((count & POINT_RUN_COUNT_MASK) << 8) | *p++;
-    }
-    points.resize (count);
+    bool has_a = coords_count_map->has (*a);
+    bool has_b = coords_count_map->has (*b);
 
-    unsigned int n = 0;
-    uint16_t i = 0;
-    while (i < count)
+    if (has_a && has_b)
     {
-      if (unlikely (!bytes.check_range (p))) return false;
-      uint16_t j;
-      uint8_t control = *p++;
-      uint16_t run_count = (control & POINT_RUN_COUNT_MASK) + 1;
-      if (control & POINTS_ARE_WORDS)
-      {
-       for (j = 0; j < run_count && i < count; j++, i++)
-       {
-         if (unlikely (!bytes.check_range ((const HBUINT16 *) p)))
-           return false;
-         n += *(const HBUINT16 *)p;
-         points[i] = n;
-         p += HBUINT16::static_size;
-       }
-      }
-      else
-      {
-       for (j = 0; j < run_count && i < count; j++, i++)
-       {
-         if (unlikely (!bytes.check_range (p))) return false;
-         n += *p++;
-         points[i] = n;
-       }
-      }
-      if (j < run_count) return false;
+      unsigned a_num = coords_count_map->get (*a);
+      unsigned b_num = coords_count_map->get (*b);
+
+      if (a_num != b_num)
+        return b_num - a_num;
+
+      return (*b)->as_array().cmp ((*a)->as_array ());
     }
-    return true;
+    else if (has_a) return -1;
+    else if (has_b) return 1;
+    else return 0;
   }
 
-  static bool unpack_deltas (const HBUINT8 *&p /* IN/OUT */,
-                            hb_vector_t<int> &deltas /* IN/OUT */,
-                            const hb_bytes_t &bytes)
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  bool serialize_glyph_var_data (hb_serialize_context_t *c,
+                                 Iterator it,
+                                 bool long_offset,
+                                 unsigned num_glyphs,
+                                 char* glyph_var_data_offsets /* OUT: glyph var data offsets array */) const
   {
-    enum packed_delta_flag_t
+    TRACE_SERIALIZE (this);
+
+    if (long_offset)
     {
-      DELTAS_ARE_ZERO      = 0x80,
-      DELTAS_ARE_WORDS     = 0x40,
-      DELTA_RUN_COUNT_MASK = 0x3F
-    };
-
-    unsigned int i = 0;
-    unsigned int count = deltas.length;
-    while (i < count)
+      ((HBUINT32 *) glyph_var_data_offsets)[0] = 0;
+      glyph_var_data_offsets += 4;
+    }
+    else
     {
-      if (unlikely (!bytes.check_range (p))) return false;
-      uint8_t control = *p++;
-      unsigned int run_count = (control & DELTA_RUN_COUNT_MASK) + 1;
-      unsigned int j;
-      if (control & DELTAS_ARE_ZERO)
-       for (j = 0; j < run_count && i < count; j++, i++)
-         deltas[i] = 0;
-      else if (control & DELTAS_ARE_WORDS)
-       for (j = 0; j < run_count && i < count; j++, i++)
-       {
-         if (unlikely (!bytes.check_range ((const HBUINT16 *) p)))
-           return false;
-         deltas[i] = *(const HBINT16 *) p;
-         p += HBUINT16::static_size;
-       }
-      else
-       for (j = 0; j < run_count && i < count; j++, i++)
-       {
-         if (unlikely (!bytes.check_range (p)))
-           return false;
-         deltas[i] = *(const HBINT8 *) p++;
-       }
-      if (j < run_count)
-       return false;
+      ((HBUINT16 *) glyph_var_data_offsets)[0] = 0;
+      glyph_var_data_offsets += 2;
     }
-    return true;
-  }
+    unsigned glyph_offset = 0;
+    hb_codepoint_t last_gid = 0;
+    unsigned idx = 0;
 
-  bool has_data () const { return tupleVarCount; }
+    TupleVariationData* cur_glyph = c->start_embed<TupleVariationData> ();
+    if (!cur_glyph) return_trace (false);
+    for (auto &_ : it)
+    {
+      hb_codepoint_t gid = _.first;
+      if (long_offset)
+        for (; last_gid < gid; last_gid++)
+          ((HBUINT32 *) glyph_var_data_offsets)[last_gid] = glyph_offset;
+      else
+        for (; last_gid < gid; last_gid++)
+          ((HBUINT16 *) glyph_var_data_offsets)[last_gid] = glyph_offset / 2;
 
-  protected:
-  struct TupleVarCount : HBUINT16
-  {
-    bool has_shared_point_numbers () const { return ((*this) & SharedPointNumbers); }
-    unsigned int get_count () const { return (*this) & CountMask; }
+      if (idx >= glyph_variations.length) return_trace (false);
+      if (!cur_glyph->serialize (c, true, glyph_variations[idx])) return_trace (false);
+      TupleVariationData* next_glyph = c->start_embed<TupleVariationData> ();
+      glyph_offset += (char *) next_glyph - (char *) cur_glyph;
 
-    protected:
-    enum Flags
-    {
-      SharedPointNumbers= 0x8000u,
-      CountMask                = 0x0FFFu
-    };
-    public:
-    DEFINE_SIZE_STATIC (2);
-  };
+      if (long_offset)
+        ((HBUINT32 *) glyph_var_data_offsets)[gid] = glyph_offset;
+      else
+        ((HBUINT16 *) glyph_var_data_offsets)[gid] = glyph_offset / 2;
 
-  TupleVarCount        tupleVarCount;  /* A packed field. The high 4 bits are flags, and the
-                                * low 12 bits are the number of tuple variation tables
-                                * for this glyph. The number of tuple variation tables
-                                * can be any number between 1 and 4095. */
-  Offset16To<HBUINT8>
-               data;           /* Offset from the start of the GlyphVariationData table
-                                * to the serialized data. */
-  /* TupleVariationHeader tupleVariationHeaders[] *//* Array of tuple variation headers. */
-  public:
-  DEFINE_SIZE_MIN (4);
+      last_gid++;
+      idx++;
+      cur_glyph = next_glyph;
+    }
+
+    if (long_offset)
+      for (; last_gid < num_glyphs; last_gid++)
+        ((HBUINT32 *) glyph_var_data_offsets)[last_gid] = glyph_offset;
+    else
+      for (; last_gid < num_glyphs; last_gid++)
+        ((HBUINT16 *) glyph_var_data_offsets)[last_gid] = glyph_offset / 2;
+    return_trace (true);
+  }
 };
 
 struct gvar
@@ -390,22 +297,113 @@ struct gvar
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && (version.major == 1) &&
-                 (glyphCount == c->get_num_glyphs ()) &&
                  sharedTuples.sanitize (c, this, axisCount * sharedTupleCount) &&
                  (is_long_offset () ?
-                    c->check_array (get_long_offset_array (), glyphCount+1) :
-                    c->check_array (get_short_offset_array (), glyphCount+1)) &&
-                 c->check_array (((const HBUINT8*)&(this+dataZ)) + get_offset (0),
-                                 get_offset (glyphCount) - get_offset (0)));
+                    c->check_array (get_long_offset_array (), c->get_num_glyphs () + 1) :
+                    c->check_array (get_short_offset_array (), c->get_num_glyphs () + 1)));
   }
 
   /* GlyphVariationData not sanitized here; must be checked while accessing each glyph variation data */
   bool sanitize (hb_sanitize_context_t *c) const
   { return sanitize_shallow (c); }
 
+  bool decompile_glyph_variations (hb_subset_context_t *c,
+                                   glyph_variations_t& glyph_vars /* OUT */) const
+  {
+    hb_hashmap_t<hb_codepoint_t, hb_bytes_t> new_gid_var_data_map;
+    auto it = hb_iter (c->plan->new_to_old_gid_list);
+    if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
+    {
+      new_gid_var_data_map.set (0, hb_bytes_t ());
+      it++;
+    }
+
+    for (auto &_ : it)
+    {
+      hb_codepoint_t new_gid = _.first;
+      hb_codepoint_t old_gid = _.second;
+      hb_bytes_t var_data_bytes = get_glyph_var_data_bytes (c->source_blob, glyphCountX, old_gid);
+      new_gid_var_data_map.set (new_gid, var_data_bytes);
+    }
+
+    if (new_gid_var_data_map.in_error ()) return false;
+
+    hb_array_t<const F2DOT14> shared_tuples = (this+sharedTuples).as_array ((unsigned) sharedTupleCount * (unsigned) axisCount);
+    return glyph_vars.create_from_glyphs_var_data (axisCount, shared_tuples, c->plan, new_gid_var_data_map);
+  }
+
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  bool serialize (hb_serialize_context_t *c,
+                  const glyph_variations_t& glyph_vars,
+                  Iterator it,
+                  unsigned axis_count,
+                  unsigned num_glyphs) const
+  {
+    TRACE_SERIALIZE (this);
+    gvar *out = c->allocate_min<gvar> ();
+    if (unlikely (!out)) return_trace (false);
+
+    out->version.major = 1;
+    out->version.minor = 0;
+    out->axisCount = axis_count;
+    out->glyphCountX = hb_min (0xFFFFu, num_glyphs);
+
+    unsigned glyph_var_data_size = glyph_vars.compiled_byte_size ();
+    bool long_offset = glyph_var_data_size & ~0xFFFFu;
+    out->flags = long_offset ? 1 : 0;
+
+    HBUINT8 *glyph_var_data_offsets = c->allocate_size<HBUINT8> ((long_offset ? 4 : 2) * (num_glyphs + 1), false);
+    if (!glyph_var_data_offsets) return_trace (false);
+
+    /* shared tuples */
+    unsigned shared_tuple_count = glyph_vars.compiled_shared_tuples_count ();
+    out->sharedTupleCount = shared_tuple_count;
+
+    if (!shared_tuple_count)
+      out->sharedTuples = 0;
+    else
+    {
+      hb_array_t<const char> shared_tuples = glyph_vars.compiled_shared_tuples.as_array ().copy (c);
+      if (!shared_tuples.arrayZ) return_trace (false);
+      out->sharedTuples = shared_tuples.arrayZ - (char *) out;
+    }
+
+    char *glyph_var_data = c->start_embed<char> ();
+    if (!glyph_var_data) return_trace (false);
+    out->dataZ = glyph_var_data - (char *) out;
+
+    return_trace (glyph_vars.serialize_glyph_var_data (c, it, long_offset, num_glyphs,
+                                                       (char *) glyph_var_data_offsets));
+  }
+
+  bool instantiate (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    glyph_variations_t glyph_vars;
+    if (!decompile_glyph_variations (c, glyph_vars))
+      return_trace (false);
+
+    if (!glyph_vars.instantiate (c->plan)) return_trace (false);
+    if (!glyph_vars.compile_bytes (c->plan->axes_index_map, c->plan->axes_old_index_tag_map))
+      return_trace (false);
+
+    unsigned axis_count = c->plan->axes_index_map.get_population ();
+    unsigned num_glyphs = c->plan->num_output_glyphs ();
+    auto it = hb_iter (c->plan->new_to_old_gid_list);
+    return_trace (serialize (c->serializer, glyph_vars, it, axis_count, num_glyphs));
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
+    if (c->plan->all_axes_pinned)
+      return_trace (false);
+
+    if (c->plan->normalized_coords)
+      return_trace (instantiate (c));
+
+    unsigned glyph_count = version.to_int () ? c->plan->source->get_num_glyphs () : 0;
 
     gvar *out = c->serializer->allocate_min<gvar> ();
     if (unlikely (!out)) return_trace (false);
@@ -416,22 +414,22 @@ struct gvar
     out->sharedTupleCount = sharedTupleCount;
 
     unsigned int num_glyphs = c->plan->num_output_glyphs ();
-    out->glyphCount = num_glyphs;
+    out->glyphCountX = hb_min (0xFFFFu, num_glyphs);
 
+    auto it = hb_iter (c->plan->new_to_old_gid_list);
+    if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
+      it++;
     unsigned int subset_data_size = 0;
-    for (hb_codepoint_t gid = (c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE) ? 0 : 1;
-         gid < num_glyphs;
-         gid++)
+    for (auto &_ : it)
     {
-      hb_codepoint_t old_gid;
-      if (!c->plan->old_gid_for_new_gid (gid, &old_gid)) continue;
-      subset_data_size += get_glyph_var_data_bytes (c->source_blob, old_gid).length;
+      hb_codepoint_t old_gid = _.second;
+      subset_data_size += get_glyph_var_data_bytes (c->source_blob, glyph_count, old_gid).length;
     }
 
     bool long_offset = subset_data_size & ~0xFFFFu;
     out->flags = long_offset ? 1 : 0;
 
-    HBUINT8 *subset_offsets = c->serializer->allocate_size<HBUINT8> ((long_offset ? 4 : 2) * (num_glyphs + 1));
+    HBUINT8 *subset_offsets = c->serializer->allocate_size<HBUINT8> ((long_offset ? 4 : 2) * (num_glyphs + 1), false);
     if (!subset_offsets) return_trace (false);
 
     /* shared tuples */
@@ -443,54 +441,89 @@ struct gvar
       F2DOT14 *tuples = c->serializer->allocate_size<F2DOT14> (shared_tuple_size);
       if (!tuples) return_trace (false);
       out->sharedTuples = (char *) tuples - (char *) out;
-      memcpy (tuples, this+sharedTuples, shared_tuple_size);
+      hb_memcpy (tuples, this+sharedTuples, shared_tuple_size);
     }
 
-    char *subset_data = c->serializer->allocate_size<char> (subset_data_size);
+    char *subset_data = c->serializer->allocate_size<char> (subset_data_size, false);
     if (!subset_data) return_trace (false);
     out->dataZ = subset_data - (char *) out;
 
+
+    if (long_offset)
+    {
+      ((HBUINT32 *) subset_offsets)[0] = 0;
+      subset_offsets += 4;
+    }
+    else
+    {
+      ((HBUINT16 *) subset_offsets)[0] = 0;
+      subset_offsets += 2;
+    }
     unsigned int glyph_offset = 0;
-    for (hb_codepoint_t gid = (c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE) ? 0 : 1;
-         gid < num_glyphs;
-         gid++)
+
+    hb_codepoint_t last = 0;
+    it = hb_iter (c->plan->new_to_old_gid_list);
+    if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
+      it++;
+    for (auto &_ : it)
     {
-      hb_codepoint_t old_gid;
-      hb_bytes_t var_data_bytes = c->plan->old_gid_for_new_gid (gid, &old_gid)
-                               ? get_glyph_var_data_bytes (c->source_blob, old_gid)
-                               : hb_bytes_t ();
+      hb_codepoint_t gid = _.first;
+      hb_codepoint_t old_gid = _.second;
 
       if (long_offset)
-       ((HBUINT32 *) subset_offsets)[gid] = glyph_offset;
+       for (; last < gid; last++)
+         ((HBUINT32 *) subset_offsets)[last] = glyph_offset;
       else
-       ((HBUINT16 *) subset_offsets)[gid] = glyph_offset / 2;
+       for (; last < gid; last++)
+         ((HBUINT16 *) subset_offsets)[last] = glyph_offset / 2;
+
+      hb_bytes_t var_data_bytes = get_glyph_var_data_bytes (c->source_blob,
+                                                           glyph_count,
+                                                           old_gid);
 
-      if (var_data_bytes.length > 0)
-       memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length);
+      hb_memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length);
       subset_data += var_data_bytes.length;
       glyph_offset += var_data_bytes.length;
+
+      if (long_offset)
+       ((HBUINT32 *) subset_offsets)[gid] = glyph_offset;
+      else
+       ((HBUINT16 *) subset_offsets)[gid] = glyph_offset / 2;
+
+      last++; // Skip over gid
     }
+
     if (long_offset)
-      ((HBUINT32 *) subset_offsets)[num_glyphs] = glyph_offset;
+      for (; last < num_glyphs; last++)
+       ((HBUINT32 *) subset_offsets)[last] = glyph_offset;
     else
-      ((HBUINT16 *) subset_offsets)[num_glyphs] = glyph_offset / 2;
+      for (; last < num_glyphs; last++)
+       ((HBUINT16 *) subset_offsets)[last] = glyph_offset / 2;
 
     return_trace (true);
   }
 
   protected:
-  const hb_bytes_t get_glyph_var_data_bytes (hb_blob_t *blob, hb_codepoint_t glyph) const
+  const hb_bytes_t get_glyph_var_data_bytes (hb_blob_t *blob,
+                                            unsigned glyph_count,
+                                            hb_codepoint_t glyph) const
   {
-    unsigned start_offset = get_offset (glyph);
-    unsigned length = get_offset (glyph+1) - start_offset;
+    unsigned start_offset = get_offset (glyph_count, glyph);
+    unsigned end_offset = get_offset (glyph_count, glyph+1);
+    if (unlikely (end_offset < start_offset)) return hb_bytes_t ();
+    unsigned length = end_offset - start_offset;
     hb_bytes_t var_data = blob->as_bytes ().sub_array (((unsigned) dataZ) + start_offset, length);
     return likely (var_data.length >= GlyphVariationData::min_size) ? var_data : hb_bytes_t ();
   }
 
   bool is_long_offset () const { return flags & 1; }
 
-  unsigned get_offset (unsigned i) const
-  { return is_long_offset () ? get_long_offset_array ()[i] : get_short_offset_array ()[i] * 2; }
+  unsigned get_offset (unsigned glyph_count, unsigned i) const
+  {
+    if (unlikely (i > glyph_count)) return 0;
+    _hb_compiler_memory_r_barrier ();
+    return is_long_offset () ? get_long_offset_array ()[i] : get_short_offset_array ()[i] * 2;
+  }
 
   const HBUINT32 * get_long_offset_array () const { return (const HBUINT32 *) &offsetZ; }
   const HBUINT16 *get_short_offset_array () const { return (const HBUINT16 *) &offsetZ; }
@@ -499,23 +532,55 @@ struct gvar
   struct accelerator_t
   {
     accelerator_t (hb_face_t *face)
-    { table = hb_sanitize_context_t ().reference_table<gvar> (face); }
+    {
+      table = hb_sanitize_context_t ().reference_table<gvar> (face);
+      /* If sanitize failed, set glyphCount to 0. */
+      glyphCount = table->version.to_int () ? face->get_num_glyphs () : 0;
+
+      /* For shared tuples that only have one axis active, shared the index of
+       * that axis as a cache. This will speed up caclulate_scalar() a lot
+       * for fonts with lots of axes and many "monovar" tuples. */
+      hb_array_t<const F2DOT14> shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount);
+      unsigned count = table->sharedTupleCount;
+      if (unlikely (!shared_tuple_active_idx.resize (count, false))) return;
+      unsigned axis_count = table->axisCount;
+      for (unsigned i = 0; i < count; i++)
+      {
+       hb_array_t<const F2DOT14> tuple = shared_tuples.sub_array (axis_count * i, axis_count);
+       int idx1 = -1, idx2 = -1;
+       for (unsigned j = 0; j < axis_count; j++)
+       {
+         const F2DOT14 &peak = tuple.arrayZ[j];
+         if (peak.to_int () != 0)
+         {
+           if (idx1 == -1)
+             idx1 = j;
+           else if (idx2 == -1)
+             idx2 = j;
+           else
+           {
+             idx1 = idx2 = -1;
+             break;
+           }
+         }
+       }
+       shared_tuple_active_idx.arrayZ[i] = {idx1, idx2};
+      }
+    }
     ~accelerator_t () { table.destroy (); }
 
     private:
-    struct x_getter { static float get (const contour_point_t &p) { return p.x; } };
-    struct y_getter { static float get (const contour_point_t &p) { return p.y; } };
 
-    template <typename T>
     static float infer_delta (const hb_array_t<contour_point_t> points,
                              const hb_array_t<contour_point_t> deltas,
-                             unsigned int target, unsigned int prev, unsigned int next)
+                             unsigned int target, unsigned int prev, unsigned int next,
+                             float contour_point_t::*m)
     {
-      float target_val = T::get (points[target]);
-      float prev_val = T::get (points[prev]);
-      float next_val = T::get (points[next]);
-      float prev_delta = T::get (deltas[prev]);
-      float next_delta = T::get (deltas[next]);
+      float target_val = points.arrayZ[target].*m;
+      float prev_val = points.arrayZ[prev].*m;
+      float next_val = points.arrayZ[next].*m;
+      float prev_delta =  deltas.arrayZ[prev].*m;
+      float next_delta =  deltas.arrayZ[next].*m;
 
       if (prev_val == next_val)
        return (prev_delta == next_delta) ? prev_delta : 0.f;
@@ -526,141 +591,238 @@ struct gvar
 
       /* linear interpolation */
       float r = (target_val - prev_val) / (next_val - prev_val);
-      return (1.f - r) * prev_delta + r * next_delta;
+      return prev_delta + r * (next_delta - prev_delta);
     }
 
     static unsigned int next_index (unsigned int i, unsigned int start, unsigned int end)
     { return (i >= end) ? start : (i + 1); }
 
     public:
-    bool apply_deltas_to_points (hb_codepoint_t glyph, hb_font_t *font,
-                                const hb_array_t<contour_point_t> points) const
+    bool apply_deltas_to_points (hb_codepoint_t glyph,
+                                hb_array_t<int> coords,
+                                const hb_array_t<contour_point_t> points,
+                                bool phantom_only = false) const
     {
-      /* num_coords should exactly match gvar's axisCount due to how GlyphVariationData tuples are aligned */
-      if (!font->num_coords || font->num_coords != table->axisCount) return true;
-
-      if (unlikely (glyph >= table->glyphCount)) return true;
+      if (unlikely (glyph >= glyphCount)) return true;
 
-      hb_bytes_t var_data_bytes = table->get_glyph_var_data_bytes (table.get_blob (), glyph);
+      hb_bytes_t var_data_bytes = table->get_glyph_var_data_bytes (table.get_blob (), glyphCount, glyph);
       if (!var_data_bytes.as<GlyphVariationData> ()->has_data ()) return true;
       hb_vector_t<unsigned int> shared_indices;
       GlyphVariationData::tuple_iterator_t iterator;
       if (!GlyphVariationData::get_tuple_iterator (var_data_bytes, table->axisCount,
+                                                  var_data_bytes.arrayZ,
                                                   shared_indices, &iterator))
        return true; /* so isn't applied at all */
 
       /* Save original points for inferred delta calculation */
-      contour_point_vector_t orig_points;
-      orig_points.resize (points.length);
-      for (unsigned int i = 0; i < orig_points.length; i++)
-       orig_points[i] = points[i];
+      contour_point_vector_t orig_points_vec; // Populated lazily
+      auto orig_points = orig_points_vec.as_array ();
 
-      contour_point_vector_t deltas; /* flag is used to indicate referenced point */
-      deltas.resize (points.length);
+      /* flag is used to indicate referenced point */
+      contour_point_vector_t deltas_vec; // Populated lazily
+      auto deltas = deltas_vec.as_array ();
 
-      hb_vector_t<unsigned> end_points;
-      for (unsigned i = 0; i < points.length; ++i)
-       if (points[i].is_end_point)
-         end_points.push (i);
+      hb_vector_t<unsigned> end_points; // Populated lazily
 
-      int *coords = font->coords;
-      unsigned num_coords = font->num_coords;
-      hb_array_t<const F2DOT14> shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount);
+      unsigned num_coords = table->axisCount;
+      hb_array_t<const F2DOT14> shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * num_coords);
+
+      hb_vector_t<unsigned int> private_indices;
+      hb_vector_t<int> x_deltas;
+      hb_vector_t<int> y_deltas;
+      unsigned count = points.length;
+      bool flush = false;
       do
       {
-       float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, shared_tuples);
+       float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, shared_tuples,
+                                                                &shared_tuple_active_idx);
        if (scalar == 0.f) continue;
        const HBUINT8 *p = iterator.get_serialized_data ();
        unsigned int length = iterator.current_tuple->get_data_size ();
        if (unlikely (!iterator.var_data_bytes.check_range (p, length)))
          return false;
 
-       hb_bytes_t bytes ((const char *) p, length);
-       hb_vector_t<unsigned int> private_indices;
-       if (iterator.current_tuple->has_private_points () &&
-           !GlyphVariationData::unpack_points (p, private_indices, bytes))
+       if (!deltas)
+       {
+         if (unlikely (!deltas_vec.resize (count, false))) return false;
+         deltas = deltas_vec.as_array ();
+         hb_memset (deltas.arrayZ + (phantom_only ? count - 4 : 0), 0,
+                    (phantom_only ? 4 : count) * sizeof (deltas[0]));
+       }
+
+       const HBUINT8 *end = p + length;
+
+       bool has_private_points = iterator.current_tuple->has_private_points ();
+       if (has_private_points &&
+           !GlyphVariationData::unpack_points (p, private_indices, end))
          return false;
-       const hb_array_t<unsigned int> &indices = private_indices.length ? private_indices : shared_indices;
+       const hb_array_t<unsigned int> &indices = has_private_points ? private_indices : shared_indices;
 
        bool apply_to_all = (indices.length == 0);
        unsigned int num_deltas = apply_to_all ? points.length : indices.length;
-       hb_vector_t<int> x_deltas;
-       x_deltas.resize (num_deltas);
-       if (!GlyphVariationData::unpack_deltas (p, x_deltas, bytes))
-         return false;
-       hb_vector_t<int> y_deltas;
-       y_deltas.resize (num_deltas);
-       if (!GlyphVariationData::unpack_deltas (p, y_deltas, bytes))
-         return false;
+       if (unlikely (!x_deltas.resize (num_deltas, false))) return false;
+       if (unlikely (!GlyphVariationData::unpack_deltas (p, x_deltas, end))) return false;
+       if (unlikely (!y_deltas.resize (num_deltas, false))) return false;
+       if (unlikely (!GlyphVariationData::unpack_deltas (p, y_deltas, end))) return false;
 
-       for (unsigned int i = 0; i < deltas.length; i++)
-         deltas[i].init ();
-       for (unsigned int i = 0; i < num_deltas; i++)
+       if (!apply_to_all)
        {
-         unsigned int pt_index = apply_to_all ? i : indices[i];
-         deltas[pt_index].flag = 1;    /* this point is referenced, i.e., explicit deltas specified */
-         deltas[pt_index].x += x_deltas[i] * scalar;
-         deltas[pt_index].y += y_deltas[i] * scalar;
+         if (!orig_points && !phantom_only)
+         {
+           orig_points_vec.extend (points);
+           if (unlikely (orig_points_vec.in_error ())) return false;
+           orig_points = orig_points_vec.as_array ();
+         }
+
+         if (flush)
+         {
+           for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++)
+             points.arrayZ[i].translate (deltas.arrayZ[i]);
+           flush = false;
+
+         }
+         hb_memset (deltas.arrayZ + (phantom_only ? count - 4 : 0), 0,
+                    (phantom_only ? 4 : count) * sizeof (deltas[0]));
+       }
+
+       if (HB_OPTIMIZE_SIZE_VAL)
+       {
+         for (unsigned int i = 0; i < num_deltas; i++)
+         {
+           unsigned int pt_index;
+           if (apply_to_all)
+             pt_index = i;
+           else
+           {
+             pt_index = indices[i];
+             if (unlikely (pt_index >= deltas.length)) continue;
+           }
+           if (phantom_only && pt_index < count - 4) continue;
+           auto &delta = deltas.arrayZ[pt_index];
+           delta.flag = 1;     /* this point is referenced, i.e., explicit deltas specified */
+           delta.x += x_deltas.arrayZ[i] * scalar;
+           delta.y += y_deltas.arrayZ[i] * scalar;
+         }
+       }
+       else
+       {
+         /* Ouch. Four cases... for optimization. */
+         if (scalar != 1.0f)
+         {
+           if (apply_to_all)
+             for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++)
+             {
+               unsigned int pt_index = i;
+               auto &delta = deltas.arrayZ[pt_index];
+               delta.x += x_deltas.arrayZ[i] * scalar;
+               delta.y += y_deltas.arrayZ[i] * scalar;
+             }
+           else
+             for (unsigned int i = 0; i < num_deltas; i++)
+             {
+               unsigned int pt_index = indices[i];
+               if (unlikely (pt_index >= deltas.length)) continue;
+               if (phantom_only && pt_index < count - 4) continue;
+               auto &delta = deltas.arrayZ[pt_index];
+               delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
+               delta.x += x_deltas.arrayZ[i] * scalar;
+               delta.y += y_deltas.arrayZ[i] * scalar;
+             }
+         }
+         else
+         {
+           if (apply_to_all)
+             for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++)
+             {
+               unsigned int pt_index = i;
+               auto &delta = deltas.arrayZ[pt_index];
+               delta.x += x_deltas.arrayZ[i];
+               delta.y += y_deltas.arrayZ[i];
+             }
+           else
+             for (unsigned int i = 0; i < num_deltas; i++)
+             {
+               unsigned int pt_index = indices[i];
+               if (unlikely (pt_index >= deltas.length)) continue;
+               if (phantom_only && pt_index < count - 4) continue;
+               auto &delta = deltas.arrayZ[pt_index];
+               delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
+               delta.x += x_deltas.arrayZ[i];
+               delta.y += y_deltas.arrayZ[i];
+             }
+         }
        }
 
        /* infer deltas for unreferenced points */
-       unsigned start_point = 0;
-       for (unsigned c = 0; c < end_points.length; c++)
+       if (!apply_to_all && !phantom_only)
        {
-         unsigned end_point = end_points[c];
+         if (!end_points)
+         {
+           for (unsigned i = 0; i < count; ++i)
+             if (points.arrayZ[i].is_end_point)
+               end_points.push (i);
+           if (unlikely (end_points.in_error ())) return false;
+         }
 
-         /* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */
-         unsigned unref_count = 0;
-         for (unsigned i = start_point; i <= end_point; i++)
-           if (!deltas[i].flag) unref_count++;
+         unsigned start_point = 0;
+         for (unsigned end_point : end_points)
+         {
+           /* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */
+           unsigned unref_count = 0;
+           for (unsigned i = start_point; i < end_point + 1; i++)
+             unref_count += deltas.arrayZ[i].flag;
+           unref_count = (end_point - start_point + 1) - unref_count;
 
-         unsigned j = start_point;
-         if (unref_count == 0 || unref_count > end_point - start_point)
-           goto no_more_gaps;
+           unsigned j = start_point;
+           if (unref_count == 0 || unref_count > end_point - start_point)
+             goto no_more_gaps;
 
-         for (;;)
-         {
-           /* Locate the next gap of unreferenced points between two referenced points prev and next.
-            * Note that a gap may wrap around at left (start_point) and/or at right (end_point).
-            */
-           unsigned int prev, next, i;
-           for (;;)
-           {
-             i = j;
-             j = next_index (i, start_point, end_point);
-             if (deltas[i].flag && !deltas[j].flag) break;
-           }
-           prev = j = i;
-           for (;;)
-           {
-             i = j;
-             j = next_index (i, start_point, end_point);
-             if (!deltas[i].flag && deltas[j].flag) break;
-           }
-           next = j;
-           /* Infer deltas for all unref points in the gap between prev and next */
-           i = prev;
            for (;;)
            {
-             i = next_index (i, start_point, end_point);
-             if (i == next) break;
-             deltas[i].x = infer_delta<x_getter> (orig_points.as_array (), deltas.as_array (), i, prev, next);
-             deltas[i].y = infer_delta<y_getter> (orig_points.as_array (), deltas.as_array (), i, prev, next);
-             if (--unref_count == 0) goto no_more_gaps;
+             /* Locate the next gap of unreferenced points between two referenced points prev and next.
+              * Note that a gap may wrap around at left (start_point) and/or at right (end_point).
+              */
+             unsigned int prev, next, i;
+             for (;;)
+             {
+               i = j;
+               j = next_index (i, start_point, end_point);
+               if (deltas.arrayZ[i].flag && !deltas.arrayZ[j].flag) break;
+             }
+             prev = j = i;
+             for (;;)
+             {
+               i = j;
+               j = next_index (i, start_point, end_point);
+               if (!deltas.arrayZ[i].flag && deltas.arrayZ[j].flag) break;
+             }
+             next = j;
+             /* Infer deltas for all unref points in the gap between prev and next */
+             i = prev;
+             for (;;)
+             {
+               i = next_index (i, start_point, end_point);
+               if (i == next) break;
+               deltas.arrayZ[i].x = infer_delta (orig_points, deltas, i, prev, next, &contour_point_t::x);
+               deltas.arrayZ[i].y = infer_delta (orig_points, deltas, i, prev, next, &contour_point_t::y);
+               if (--unref_count == 0) goto no_more_gaps;
+             }
            }
+         no_more_gaps:
+           start_point = end_point + 1;
          }
-no_more_gaps:
-         start_point = end_point + 1;
        }
 
-       /* apply specified / inferred deltas to points */
-       for (unsigned int i = 0; i < points.length; i++)
-       {
-         points[i].x += deltas[i].x;
-         points[i].y += deltas[i].y;
-       }
+       flush = true;
+
       } while (iterator.move_to_next ());
 
+      if (flush)
+      {
+       for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++)
+         points.arrayZ[i].translate (deltas.arrayZ[i]);
+      }
+
       return true;
     }
 
@@ -668,6 +830,8 @@ no_more_gaps:
 
     private:
     hb_blob_ptr_t<gvar> table;
+    unsigned glyphCount;
+    hb_vector_t<hb_pair_t<int, int>> shared_tuple_active_idx;
   };
 
   protected:
@@ -683,7 +847,7 @@ no_more_gaps:
   NNOffset32To<UnsizedArrayOf<F2DOT14>>
                sharedTuples;   /* Offset from the start of this table to the shared tuple records.
                                 * Array of tuple records shared across all glyph variation data tables. */
-  HBUINT16     glyphCount    /* The number of glyphs in this font. This must match the number of
+  HBUINT16     glyphCountX;    /* The number of glyphs in this font. This must match the number of
                                 * glyphs stored elsewhere in the font. */
   HBUINT16     flags;          /* Bit-field that gives the format of the offset array that follows.
                                 * If bit 0 is clear, the offsets are uint16; if bit 0 is set, the
@@ -695,7 +859,7 @@ no_more_gaps:
                offsetZ;        /* Offsets from the start of the GlyphVariationData array
                                 * to each GlyphVariationData table. */
   public:
-  DEFINE_SIZE_MIN (20);
+  DEFINE_SIZE_ARRAY (20, offsetZ);
 };
 
 struct gvar_accelerator_t : gvar::accelerator_t {
index e9d9035..ca1ea1c 100644 (file)
@@ -45,7 +45,8 @@ struct index_map_subset_plan_t
   void init (const DeltaSetIndexMap  &index_map,
             hb_inc_bimap_t          &outer_map,
             hb_vector_t<hb_set_t *> &inner_sets,
-            const hb_subset_plan_t  *plan)
+            const hb_subset_plan_t  *plan,
+            bool bypass_empty = true)
   {
     map_count = 0;
     outer_bit_count = 0;
@@ -53,55 +54,51 @@ struct index_map_subset_plan_t
     max_inners.init ();
     output_map.init ();
 
-    if (&index_map == &Null (DeltaSetIndexMap)) return;
+    if (bypass_empty && !index_map.get_map_count ()) return;
 
     unsigned int       last_val = (unsigned int)-1;
-    hb_codepoint_t     last_gid = (hb_codepoint_t)-1;
-    hb_codepoint_t     gid = (hb_codepoint_t) hb_min (index_map.get_map_count (), plan->num_output_glyphs ());
+    hb_codepoint_t     last_gid = HB_CODEPOINT_INVALID;
 
     outer_bit_count = (index_map.get_width () * 8) - index_map.get_inner_bit_count ();
     max_inners.resize (inner_sets.length);
     for (unsigned i = 0; i < inner_sets.length; i++) max_inners[i] = 0;
 
     /* Search backwards for a map value different from the last map value */
-    for (; gid > 0; gid--)
+    auto &new_to_old_gid_list = plan->new_to_old_gid_list;
+    unsigned count = new_to_old_gid_list.length;
+    for (unsigned j = count; j; j--)
     {
-      hb_codepoint_t   old_gid;
-      if (!plan->old_gid_for_new_gid (gid - 1, &old_gid))
-      {
-       if (last_gid == (hb_codepoint_t) -1)
-         continue;
-       else
-         break;
-      }
+      hb_codepoint_t gid = new_to_old_gid_list.arrayZ[j - 1].first;
+      hb_codepoint_t old_gid = new_to_old_gid_list.arrayZ[j - 1].second;
 
       unsigned int v = index_map.map (old_gid);
-      if (last_gid == (hb_codepoint_t) -1)
+      if (last_gid == HB_CODEPOINT_INVALID)
       {
        last_val = v;
        last_gid = gid;
        continue;
       }
-      if (v != last_val) break;
+      if (v != last_val)
+       break;
 
       last_gid = gid;
     }
 
     if (unlikely (last_gid == (hb_codepoint_t)-1)) return;
-    map_count = last_gid;
-    for (gid = 0; gid < map_count; gid++)
+    map_count = last_gid + 1;
+    for (auto _ : plan->new_to_old_gid_list)
     {
-      hb_codepoint_t   old_gid;
-      if (plan->old_gid_for_new_gid (gid, &old_gid))
-      {
-       unsigned int v = index_map.map (old_gid);
-       unsigned int outer = v >> 16;
-       unsigned int inner = v & 0xFFFF;
-       outer_map.add (outer);
-       if (inner > max_inners[outer]) max_inners[outer] = inner;
-       if (outer >= inner_sets.length) return;
-       inner_sets[outer]->add (inner);
-      }
+      hb_codepoint_t gid = _.first;
+      if (gid >= map_count) break;
+
+      hb_codepoint_t old_gid = _.second;
+      unsigned int v = index_map.map (old_gid);
+      unsigned int outer = v >> 16;
+      unsigned int inner = v & 0xFFFF;
+      outer_map.add (outer);
+      if (inner > max_inners[outer]) max_inners[outer] = inner;
+      if (outer >= inner_sets.length) return;
+      inner_sets[outer]->add (inner);
     }
   }
 
@@ -116,8 +113,6 @@ struct index_map_subset_plan_t
              const hb_vector_t<hb_inc_bimap_t> &inner_maps,
              const hb_subset_plan_t *plan)
   {
-    if (input_map == &Null (DeltaSetIndexMap)) return;
-
     for (unsigned int i = 0; i < max_inners.length; i++)
     {
       if (inner_maps[i].get_population () == 0) continue;
@@ -125,21 +120,50 @@ struct index_map_subset_plan_t
       if (bit_count > inner_bit_count) inner_bit_count = bit_count;
     }
 
-    output_map.resize (map_count);
-    for (hb_codepoint_t gid = 0; gid < output_map.length; gid++)
+    if (unlikely (!output_map.resize (map_count))) return;
+    for (const auto &_ : plan->new_to_old_gid_list)
     {
-      hb_codepoint_t   old_gid;
-      if (plan->old_gid_for_new_gid (gid, &old_gid))
-      {
-       uint32_t v = input_map->map (old_gid);
-       unsigned int outer = v >> 16;
-       output_map[gid] = (outer_map[outer] << 16) | (inner_maps[outer][v & 0xFFFF]);
-      }
-      else
-       output_map[gid] = 0;    /* Map unused glyph to outer/inner=0/0 */
+      hb_codepoint_t new_gid = _.first;
+      hb_codepoint_t old_gid = _.second;
+
+      if (unlikely (new_gid >= map_count)) break;
+
+      uint32_t v = input_map->map (old_gid);
+      unsigned int outer = v >> 16;
+      output_map.arrayZ[new_gid] = (outer_map[outer] << 16) | (inner_maps[outer][v & 0xFFFF]);
     }
   }
 
+  bool remap_after_instantiation (const hb_subset_plan_t *plan,
+                                  const hb_map_t& varidx_map)
+  {
+    /* recalculate bit_count after remapping */
+    outer_bit_count = 1;
+    inner_bit_count = 1;
+
+    for (const auto &_ : plan->new_to_old_gid_list)
+    {
+      hb_codepoint_t new_gid = _.first;
+      if (unlikely (new_gid >= map_count)) break;
+
+      uint32_t v = output_map.arrayZ[new_gid];
+      uint32_t *new_varidx;
+      if (!varidx_map.has (v, &new_varidx))
+        return false;
+
+      output_map.arrayZ[new_gid] = *new_varidx;
+
+      unsigned outer = (*new_varidx) >> 16;
+      unsigned bit_count = (outer == 0) ? 1 : hb_bit_storage (outer);
+      outer_bit_count = hb_max (bit_count, outer_bit_count);
+      
+      unsigned inner = (*new_varidx) & 0xFFFF;
+      bit_count = (inner == 0) ? 1 : hb_bit_storage (inner);
+      inner_bit_count = hb_max (bit_count, inner_bit_count);
+    }
+    return true;
+  }
+
   unsigned int get_inner_bit_count () const { return inner_bit_count; }
   unsigned int get_width ()           const { return ((outer_bit_count + inner_bit_count + 7) / 8); }
   unsigned int get_map_count ()       const { return map_count; }
@@ -180,17 +204,13 @@ struct hvarvvar_subset_plan_t
     if (unlikely (!index_map_plans.length || !inner_sets.length || !inner_maps.length)) return;
 
     bool retain_adv_map = false;
-    index_map_plans[0].init (*index_maps[0], outer_map, inner_sets, plan);
+    index_map_plans[0].init (*index_maps[0], outer_map, inner_sets, plan, false);
     if (index_maps[0] == &Null (DeltaSetIndexMap))
     {
       retain_adv_map = plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS;
       outer_map.add (0);
-      for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++)
-      {
-       hb_codepoint_t old_gid;
-       if (plan->old_gid_for_new_gid (gid, &old_gid))
-         inner_sets[0]->add (old_gid);
-      }
+      for (hb_codepoint_t old_gid : plan->glyphset()->iter())
+        inner_sets[0]->add (old_gid);
       hb_set_union (adv_set, inner_sets[0]);
     }
 
@@ -201,11 +221,11 @@ struct hvarvvar_subset_plan_t
 
     if (retain_adv_map)
     {
-      for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++)
-       if (inner_sets[0]->has (gid))
-         inner_maps[0].add (gid);
-       else
-         inner_maps[0].skip ();
+      for (const auto &_ : plan->new_to_old_gid_list)
+      {
+        hb_codepoint_t old_gid = _.second;
+       inner_maps[0].add (old_gid);
+      }
     }
     else
     {
@@ -221,6 +241,16 @@ struct hvarvvar_subset_plan_t
       index_map_plans[i].remap (index_maps[i], outer_map, inner_maps, plan);
   }
 
+  /* remap */
+  bool remap_index_map_plans (const hb_subset_plan_t *plan,
+                              const hb_map_t& varidx_map)
+  {
+    for (unsigned i = 0; i < index_map_plans.length; i++)
+      if (!index_map_plans[i].remap_after_instantiation (plan, varidx_map))
+        return false;
+    return true;
+  }
+
   void fini ()
   {
     for (unsigned int i = 0; i < inner_sets.length; i++)
@@ -265,6 +295,9 @@ struct HVARVVAR
                  rsbMap.sanitize (c, this));
   }
 
+  const VariationStore& get_var_store () const
+  { return this+varStore; }
+
   void listup_index_maps (hb_vector_t<const DeltaSetIndexMap *> &index_maps) const
   {
     index_maps.push (&(this+advMap));
@@ -296,6 +329,9 @@ struct HVARVVAR
   bool _subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
+    if (c->plan->all_axes_pinned)
+      return_trace (false);
+
     hvarvvar_subset_plan_t     hvar_plan;
     hb_vector_t<const DeltaSetIndexMap *>
                                index_maps;
@@ -309,33 +345,63 @@ struct HVARVVAR
     out->version.major = 1;
     out->version.minor = 0;
 
-    if (unlikely (!out->varStore
-                     .serialize_serialize (c->serializer,
-                                           hvar_plan.var_store,
-                                           hvar_plan.inner_maps.as_array ())))
+    if (c->plan->normalized_coords)
+    {
+      item_variations_t item_vars;
+      if (!item_vars.instantiate (this+varStore, c->plan,
+                                  advMap == 0 ? false : true,
+                                  false, /* use_no_variation_idx = false */
+                                  hvar_plan.inner_maps.as_array ()))
+        return_trace (false);
+
+      if (!out->varStore.serialize_serialize (c->serializer,
+                                              item_vars.has_long_word (),
+                                              c->plan->axis_tags,
+                                              item_vars.get_region_list (),
+                                              item_vars.get_vardata_encodings ()))
+        return_trace (false);
+
+      /* if varstore is optimized, remap output_map */
+      if (advMap)
+      {
+        if (!hvar_plan.remap_index_map_plans (c->plan, item_vars.get_varidx_map ()))
+          return_trace (false);
+      }
+    }
+    else
+    {
+      if (unlikely (!out->varStore
+                   .serialize_serialize (c->serializer,
+                                         hvar_plan.var_store,
+                                         hvar_plan.inner_maps.as_array ())))
       return_trace (false);
+    }
 
     return_trace (out->T::serialize_index_maps (c->serializer,
                                                hvar_plan.index_map_plans.as_array ()));
   }
 
-  float get_advance_var (hb_codepoint_t glyph, hb_font_t *font) const
+  float get_advance_delta_unscaled (hb_codepoint_t  glyph,
+                                   const int *coords, unsigned int coord_count,
+                                   VariationStore::cache_t *store_cache = nullptr) const
   {
     uint32_t varidx = (this+advMap).map (glyph);
-    return (this+varStore).get_delta (varidx, font->coords, font->num_coords);
+    return (this+varStore).get_delta (varidx,
+                                     coords, coord_count,
+                                     store_cache);
   }
 
-  float get_side_bearing_var (hb_codepoint_t glyph,
-                             const int *coords, unsigned int coord_count) const
+  bool get_lsb_delta_unscaled (hb_codepoint_t glyph,
+                              const int *coords, unsigned int coord_count,
+                              float *lsb) const
   {
-    if (!has_side_bearing_deltas ()) return 0.f;
+    if (!lsbMap) return false;
     uint32_t varidx = (this+lsbMap).map (glyph);
-    return (this+varStore).get_delta (varidx, coords, coord_count);
+    *lsb = (this+varStore).get_delta (varidx, coords, coord_count);
+    return true;
   }
 
-  bool has_side_bearing_deltas () const { return lsbMap && rsbMap; }
-
-  protected:
+  public:
   FixedVersion<>version;       /* Version of the metrics variation table
                                 * initially set to 0x00010000u */
   Offset32To<VariationStore>
@@ -387,6 +453,16 @@ struct VVAR : HVARVVAR {
 
   bool subset (hb_subset_context_t *c) const { return HVARVVAR::_subset<VVAR> (c); }
 
+  bool get_vorg_delta_unscaled (hb_codepoint_t glyph,
+                               const int *coords, unsigned int coord_count,
+                               float *delta) const
+  {
+    if (!vorgMap) return false;
+    uint32_t varidx = (this+vorgMap).map (glyph);
+    *delta = (this+varStore).get_delta (varidx, coords, coord_count);
+    return true;
+  }
+
   protected:
   Offset32To<DeltaSetIndexMap>
                vorgMap;        /* Offset to vertical-origin var-idx mapping. */
index 208db46..ceabc9a 100644 (file)
@@ -27,7 +27,7 @@
 #ifndef HB_OT_VAR_MVAR_TABLE_HH
 #define HB_OT_VAR_MVAR_TABLE_HH
 
-#include "hb-ot-layout-common.hh"
+#include "hb-ot-var-common.hh"
 
 
 namespace OT {
@@ -41,9 +41,22 @@ struct VariationValueRecord
     return_trace (c->check_struct (this));
   }
 
+  bool subset (hb_subset_context_t *c,
+               const hb_map_t& varidx_map) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+
+    hb_codepoint_t *new_idx;
+    return_trace (c->serializer->check_assign (out->varIdx,
+                                               (varidx_map.has (varIdx, &new_idx)) ? *new_idx : HB_OT_LAYOUT_NO_VARIATIONS_INDEX,
+                                               HB_SERIALIZE_ERROR_INT_OVERFLOW));
+  }
+
   public:
   Tag          valueTag;       /* Four-byte tag identifying a font-wide measure. */
-  HBUINT32             varIdx;         /* Outer/inner index into VariationStore item. */
+  VarIdx       varIdx;         /* Outer/inner index into VariationStore item. */
 
   public:
   DEFINE_SIZE_STATIC (8);
@@ -73,6 +86,47 @@ struct MVAR
                                  valueRecordSize));
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+#ifdef HB_NO_VAR
+    return_trace (false);
+#endif
+
+    if (c->plan->all_axes_pinned)
+      return_trace (false);
+
+    MVAR *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->version = version;
+    out->reserved = reserved;
+    out->valueRecordSize = valueRecordSize;
+    out->valueRecordCount = valueRecordCount;
+
+    item_variations_t item_vars;
+    const VariationStore& src_var_store = this+varStore;
+
+    if (!item_vars.instantiate (src_var_store, c->plan))
+      return_trace (false);
+
+    /* serialize varstore */
+    if (!out->varStore.serialize_serialize (c->serializer, item_vars.has_long_word (),
+                                            c->plan->axis_tags,
+                                            item_vars.get_region_list (),
+                                            item_vars.get_vardata_encodings ()))
+      return_trace (false);
+
+    /* serialize value records array */
+    unsigned value_rec_count = valueRecordCount;
+    const VariationValueRecord *record = reinterpret_cast<const VariationValueRecord*> (valuesZ.arrayZ);
+    for (unsigned i = 0; i < value_rec_count; i++)
+    {
+      if (!record->subset (c, item_vars.get_varidx_map ())) return_trace (false);
+      record++;
+    }
+    return_trace (true);
+  }
+
   float get_var (hb_tag_t tag,
                 const int *coords, unsigned int coord_count) const
   {
@@ -116,4 +170,13 @@ protected:
 } /* namespace OT */
 
 
+#define HB_ADD_MVAR_VAR(tag, field) \
+       c->serializer->check_assign (table->field, \
+                                   roundf (table->field + \
+                                           MVAR.get_var (tag, \
+                                                         c->plan->normalized_coords.arrayZ, \
+                                                         c->plan->normalized_coords.length)), \
+                                   HB_SERIALIZE_ERROR_INT_OVERFLOW)
+
+
 #endif /* HB_OT_VAR_MVAR_TABLE_HH */
index 0376e26..f000f27 100644 (file)
@@ -56,7 +56,7 @@
  *
  * Tests whether a face includes any OpenType variation data in the `fvar` table.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 1.4.2
  **/
@@ -162,7 +162,7 @@ hb_ot_var_get_axis_infos (hb_face_t             *face,
  * Fetches the variation-axis information corresponding to the specified axis tag
  * in the specified face.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.2.0
  **/
index 811e139..671b6d2 100644 (file)
@@ -90,7 +90,7 @@ struct VORG
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    VORG *vorg_prime = c->serializer->start_embed<VORG> ();
+    auto *vorg_prime = c->serializer->start_embed<VORG> ();
     if (unlikely (!c->serializer->check_success (vorg_prime))) return_trace (false);
 
     auto it =
diff --git a/src/hb-outline.cc b/src/hb-outline.cc
new file mode 100644 (file)
index 0000000..29b1f53
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * Copyright © 2023  Behdad Esfahbod
+ * Copyright © 1999  David Turner
+ * Copyright © 2005  Werner Lemberg
+ * Copyright © 2013-2015  Alexei Podtelezhnikov
+ *
+ *  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.hh"
+
+#ifndef HB_NO_OUTLINE
+
+#include "hb-outline.hh"
+
+#include "hb-machinery.hh"
+
+
+void hb_outline_t::replay (hb_draw_funcs_t *pen, void *pen_data) const
+{
+  hb_draw_state_t st = HB_DRAW_STATE_DEFAULT;
+
+  unsigned first = 0;
+  for (unsigned contour : contours)
+  {
+    auto it = points.as_array ().sub_array (first, contour - first);
+    while (it)
+    {
+      hb_outline_point_t p1 = *it++;
+      switch (p1.type)
+      {
+       case hb_outline_point_t::type_t::MOVE_TO:
+       {
+         pen->move_to (pen_data, st,
+                          p1.x, p1.y);
+       }
+       break;
+       case hb_outline_point_t::type_t::LINE_TO:
+       {
+         pen->line_to (pen_data, st,
+                          p1.x, p1.y);
+       }
+       break;
+       case hb_outline_point_t::type_t::QUADRATIC_TO:
+       {
+         hb_outline_point_t p2 = *it++;
+         pen->quadratic_to (pen_data, st,
+                               p1.x, p1.y,
+                               p2.x, p2.y);
+       }
+       break;
+       case hb_outline_point_t::type_t::CUBIC_TO:
+       {
+         hb_outline_point_t p2 = *it++;
+         hb_outline_point_t p3 = *it++;
+         pen->cubic_to (pen_data, st,
+                           p1.x, p1.y,
+                           p2.x, p2.y,
+                           p3.x, p3.y);
+       }
+       break;
+      }
+    }
+    pen->close_path (pen_data, st);
+    first = contour;
+  }
+}
+
+float hb_outline_t::control_area () const
+{
+  float a = 0;
+  unsigned first = 0;
+  for (unsigned contour : contours)
+  {
+    for (unsigned i = first; i < contour; i++)
+    {
+      unsigned j = i + 1 < contour ? i + 1 : first;
+
+      auto &pi = points[i];
+      auto &pj = points[j];
+      a += pi.x * pj.y - pi.y * pj.x;
+    }
+
+    first = contour;
+  }
+  return a * .5f;
+}
+
+void hb_outline_t::embolden (float x_strength, float y_strength,
+                            float x_shift, float y_shift)
+{
+  /* This function is a straight port of FreeType's FT_Outline_EmboldenXY.
+   * Permission has been obtained from the FreeType authors of the code
+   * to relicense it under the HarfBuzz license. */
+
+  if (!x_strength && !y_strength) return;
+  if (!points) return;
+
+  x_strength /= 2.f;
+  y_strength /= 2.f;
+
+  bool orientation_negative = control_area () < 0;
+
+  signed first = 0;
+  for (unsigned c = 0; c < contours.length; c++)
+  {
+    hb_outline_vector_t in, out, anchor, shift;
+    float l_in, l_out, l_anchor = 0, l, q, d;
+
+    l_in = 0;
+    signed last = (int) contours[c] - 1;
+
+    /* pacify compiler */
+    in.x = in.y = anchor.x = anchor.y = 0;
+
+    /* Counter j cycles though the points; counter i advances only  */
+    /* when points are moved; anchor k marks the first moved point. */
+    for ( signed i = last, j = first, k = -1;
+         j != i && i != k;
+         j = j < last ? j + 1 : first )
+    {
+      if ( j != k )
+      {
+       out.x = points[j].x - points[i].x;
+       out.y = points[j].y - points[i].y;
+       l_out = out.normalize_len ();
+
+       if ( l_out == 0 )
+         continue;
+      }
+      else
+      {
+       out   = anchor;
+       l_out = l_anchor;
+      }
+
+      if ( l_in != 0 )
+      {
+       if ( k < 0 )
+       {
+         k        = i;
+         anchor   = in;
+         l_anchor = l_in;
+       }
+
+       d = in.x * out.x + in.y * out.y;
+
+       /* shift only if turn is less than ~160 degrees */
+       if ( d > -15.f/16.f )
+       {
+         d = d + 1.f;
+
+         /* shift components along lateral bisector in proper orientation */
+         shift.x = in.y + out.y;
+         shift.y = in.x + out.x;
+
+         if ( orientation_negative )
+           shift.x = -shift.x;
+         else
+           shift.y = -shift.y;
+
+         /* restrict shift magnitude to better handle collapsing segments */
+         q = out.x * in.y - out.y * in.x;
+         if ( orientation_negative )
+           q = -q;
+
+         l = hb_min (l_in, l_out);
+
+         /* non-strict inequalities avoid divide-by-zero when q == l == 0 */
+         if (x_strength * q <= l * d)
+           shift.x = shift.x * x_strength / d;
+         else
+           shift.x = shift.x * l / q;
+
+
+         if (y_strength * q <= l * d)
+           shift.y = shift.y * y_strength / d;
+         else
+           shift.y = shift.y * l / q;
+       }
+       else
+         shift.x = shift.y = 0;
+
+       for ( ;
+             i != j;
+             i = i < last ? i + 1 : first )
+       {
+         points[i].x += x_shift + shift.x;
+         points[i].y += y_shift + shift.y;
+       }
+      }
+      else
+       i = j;
+
+      in   = out;
+      l_in = l_out;
+    }
+
+    first = last + 1;
+  }
+}
+
+static void
+hb_outline_recording_pen_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+                                 void *data,
+                                 hb_draw_state_t *st,
+                                 float to_x, float to_y,
+                                 void *user_data HB_UNUSED)
+{
+  hb_outline_t *c = (hb_outline_t *) data;
+
+  c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::MOVE_TO});
+}
+
+static void
+hb_outline_recording_pen_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+                                 void *data,
+                                 hb_draw_state_t *st,
+                                 float to_x, float to_y,
+                                 void *user_data HB_UNUSED)
+{
+  hb_outline_t *c = (hb_outline_t *) data;
+
+  c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::LINE_TO});
+}
+
+static void
+hb_outline_recording_pen_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+                                      void *data,
+                                      hb_draw_state_t *st,
+                                      float control_x, float control_y,
+                                      float to_x, float to_y,
+                                      void *user_data HB_UNUSED)
+{
+  hb_outline_t *c = (hb_outline_t *) data;
+
+  c->points.push (hb_outline_point_t {control_x, control_y, hb_outline_point_t::type_t::QUADRATIC_TO});
+  c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::QUADRATIC_TO});
+}
+
+static void
+hb_outline_recording_pen_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+                                  void *data,
+                                  hb_draw_state_t *st,
+                                  float control1_x, float control1_y,
+                                  float control2_x, float control2_y,
+                                  float to_x, float to_y,
+                                  void *user_data HB_UNUSED)
+{
+  hb_outline_t *c = (hb_outline_t *) data;
+
+  c->points.push (hb_outline_point_t {control1_x, control1_y, hb_outline_point_t::type_t::CUBIC_TO});
+  c->points.push (hb_outline_point_t {control2_x, control2_y, hb_outline_point_t::type_t::CUBIC_TO});
+  c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::CUBIC_TO});
+}
+
+static void
+hb_outline_recording_pen_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED,
+                                    void *data,
+                                    hb_draw_state_t *st,
+                                    void *user_data HB_UNUSED)
+{
+  hb_outline_t *c = (hb_outline_t *) data;
+
+  c->contours.push (c->points.length);
+}
+
+static inline void free_static_outline_recording_pen_funcs ();
+
+static struct hb_outline_recording_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_outline_recording_pen_funcs_lazy_loader_t>
+{
+  static hb_draw_funcs_t *create ()
+  {
+    hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
+
+    hb_draw_funcs_set_move_to_func (funcs, hb_outline_recording_pen_move_to, nullptr, nullptr);
+    hb_draw_funcs_set_line_to_func (funcs, hb_outline_recording_pen_line_to, nullptr, nullptr);
+    hb_draw_funcs_set_quadratic_to_func (funcs, hb_outline_recording_pen_quadratic_to, nullptr, nullptr);
+    hb_draw_funcs_set_cubic_to_func (funcs, hb_outline_recording_pen_cubic_to, nullptr, nullptr);
+    hb_draw_funcs_set_close_path_func (funcs, hb_outline_recording_pen_close_path, nullptr, nullptr);
+
+    hb_draw_funcs_make_immutable (funcs);
+
+    hb_atexit (free_static_outline_recording_pen_funcs);
+
+    return funcs;
+  }
+} static_outline_recording_pen_funcs;
+
+static inline
+void free_static_outline_recording_pen_funcs ()
+{
+  static_outline_recording_pen_funcs.free_instance ();
+}
+
+hb_draw_funcs_t *
+hb_outline_recording_pen_get_funcs ()
+{
+  return static_outline_recording_pen_funcs.get_unconst ();
+}
+
+
+#endif
diff --git a/src/hb-outline.hh b/src/hb-outline.hh
new file mode 100644 (file)
index 0000000..c43c065
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright © 2023  Behdad Esfahbod
+ *
+ *  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_OUTLINE_HH
+#define HB_OUTLINE_HH
+
+#include "hb.hh"
+
+#include "hb-draw.hh"
+
+
+struct hb_outline_point_t
+{
+  enum class type_t
+  {
+    MOVE_TO,
+    LINE_TO,
+    QUADRATIC_TO,
+    CUBIC_TO,
+  };
+
+  hb_outline_point_t (float x, float y, type_t type) :
+    x (x), y (y), type (type) {}
+
+  float x, y;
+  type_t type;
+};
+
+struct hb_outline_vector_t
+{
+  float normalize_len ()
+  {
+    float len = hypotf (x, y);
+    if (len)
+    {
+      x /= len;
+      y /= len;
+    }
+    return len;
+  }
+
+  float x, y;
+};
+
+struct hb_outline_t
+{
+  void reset () { points.shrink (0, false); contours.resize (0); }
+
+  HB_INTERNAL void replay (hb_draw_funcs_t *pen, void *pen_data) const;
+  HB_INTERNAL float control_area () const;
+  HB_INTERNAL void embolden (float x_strength, float y_strength,
+                            float x_shift, float y_shift);
+
+  hb_vector_t<hb_outline_point_t> points;
+  hb_vector_t<unsigned> contours;
+};
+
+HB_INTERNAL hb_draw_funcs_t *
+hb_outline_recording_pen_get_funcs ();
+
+
+#endif /* HB_OUTLINE_HH */
diff --git a/src/hb-paint-extents.cc b/src/hb-paint-extents.cc
new file mode 100644 (file)
index 0000000..2393322
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * Copyright © 2022 Behdad Esfahbod
+ *
+ *  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.hh"
+
+#ifndef HB_NO_PAINT
+
+#include "hb-paint-extents.hh"
+
+#include "hb-draw.h"
+
+#include "hb-machinery.hh"
+
+
+/*
+ * This file implements bounds-extraction as well as boundedness
+ * computation of COLRv1 fonts as described in:
+ *
+ * https://learn.microsoft.com/en-us/typography/opentype/spec/colr#glyph-metrics-and-boundedness
+ */
+
+static void
+hb_paint_extents_push_transform (hb_paint_funcs_t *funcs HB_UNUSED,
+                                void *paint_data,
+                                float xx, float yx,
+                                float xy, float yy,
+                                float dx, float dy,
+                                void *user_data HB_UNUSED)
+{
+  hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
+
+  c->push_transform (hb_transform_t {xx, yx, xy, yy, dx, dy});
+}
+
+static void
+hb_paint_extents_pop_transform (hb_paint_funcs_t *funcs HB_UNUSED,
+                               void *paint_data,
+                               void *user_data HB_UNUSED)
+{
+  hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
+
+  c->pop_transform ();
+}
+
+static void
+hb_draw_extents_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+                        void *data,
+                        hb_draw_state_t *st,
+                        float to_x, float to_y,
+                        void *user_data HB_UNUSED)
+{
+  hb_extents_t *extents = (hb_extents_t *) data;
+
+  extents->add_point (to_x, to_y);
+}
+
+static void
+hb_draw_extents_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+                        void *data,
+                        hb_draw_state_t *st,
+                        float to_x, float to_y,
+                        void *user_data HB_UNUSED)
+{
+  hb_extents_t *extents = (hb_extents_t *) data;
+
+  extents->add_point (to_x, to_y);
+}
+
+static void
+hb_draw_extents_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+                             void *data,
+                             hb_draw_state_t *st,
+                             float control_x, float control_y,
+                             float to_x, float to_y,
+                             void *user_data HB_UNUSED)
+{
+  hb_extents_t *extents = (hb_extents_t *) data;
+
+  extents->add_point (control_x, control_y);
+  extents->add_point (to_x, to_y);
+}
+
+static void
+hb_draw_extents_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+                         void *data,
+                         hb_draw_state_t *st,
+                         float control1_x, float control1_y,
+                         float control2_x, float control2_y,
+                         float to_x, float to_y,
+                         void *user_data HB_UNUSED)
+{
+  hb_extents_t *extents = (hb_extents_t *) data;
+
+  extents->add_point (control1_x, control1_y);
+  extents->add_point (control2_x, control2_y);
+  extents->add_point (to_x, to_y);
+}
+
+static inline void free_static_draw_extents_funcs ();
+
+static struct hb_draw_extents_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_draw_extents_funcs_lazy_loader_t>
+{
+  static hb_draw_funcs_t *create ()
+  {
+    hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
+
+    hb_draw_funcs_set_move_to_func (funcs, hb_draw_extents_move_to, nullptr, nullptr);
+    hb_draw_funcs_set_line_to_func (funcs, hb_draw_extents_line_to, nullptr, nullptr);
+    hb_draw_funcs_set_quadratic_to_func (funcs, hb_draw_extents_quadratic_to, nullptr, nullptr);
+    hb_draw_funcs_set_cubic_to_func (funcs, hb_draw_extents_cubic_to, nullptr, nullptr);
+
+    hb_draw_funcs_make_immutable (funcs);
+
+    hb_atexit (free_static_draw_extents_funcs);
+
+    return funcs;
+  }
+} static_draw_extents_funcs;
+
+static inline
+void free_static_draw_extents_funcs ()
+{
+  static_draw_extents_funcs.free_instance ();
+}
+
+static hb_draw_funcs_t *
+hb_draw_extents_get_funcs ()
+{
+  return static_draw_extents_funcs.get_unconst ();
+}
+
+static void
+hb_paint_extents_push_clip_glyph (hb_paint_funcs_t *funcs HB_UNUSED,
+                                 void *paint_data,
+                                 hb_codepoint_t glyph,
+                                 hb_font_t *font,
+                                 void *user_data HB_UNUSED)
+{
+  hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
+
+  hb_extents_t extents;
+  hb_draw_funcs_t *draw_extent_funcs = hb_draw_extents_get_funcs ();
+  hb_font_draw_glyph (font, glyph, draw_extent_funcs, &extents);
+  c->push_clip (extents);
+}
+
+static void
+hb_paint_extents_push_clip_rectangle (hb_paint_funcs_t *funcs HB_UNUSED,
+                                     void *paint_data,
+                                     float xmin, float ymin, float xmax, float ymax,
+                                     void *user_data)
+{
+  hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
+
+  hb_extents_t extents = {xmin, ymin, xmax, ymax};
+  c->push_clip (extents);
+}
+
+static void
+hb_paint_extents_pop_clip (hb_paint_funcs_t *funcs HB_UNUSED,
+                          void *paint_data,
+                          void *user_data HB_UNUSED)
+{
+  hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
+
+  c->pop_clip ();
+}
+
+static void
+hb_paint_extents_push_group (hb_paint_funcs_t *funcs HB_UNUSED,
+                            void *paint_data,
+                            void *user_data HB_UNUSED)
+{
+  hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
+
+  c->push_group ();
+}
+
+static void
+hb_paint_extents_pop_group (hb_paint_funcs_t *funcs HB_UNUSED,
+                           void *paint_data,
+                           hb_paint_composite_mode_t mode,
+                           void *user_data HB_UNUSED)
+{
+  hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
+
+  c->pop_group (mode);
+}
+
+static hb_bool_t
+hb_paint_extents_paint_image (hb_paint_funcs_t *funcs HB_UNUSED,
+                             void *paint_data,
+                             hb_blob_t *blob HB_UNUSED,
+                             unsigned int width HB_UNUSED,
+                             unsigned int height HB_UNUSED,
+                             hb_tag_t format HB_UNUSED,
+                             float slant HB_UNUSED,
+                             hb_glyph_extents_t *glyph_extents,
+                             void *user_data HB_UNUSED)
+{
+  hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
+
+  hb_extents_t extents = {(float) glyph_extents->x_bearing,
+                         (float) glyph_extents->y_bearing + glyph_extents->height,
+                         (float) glyph_extents->x_bearing + glyph_extents->width,
+                         (float) glyph_extents->y_bearing};
+  c->push_clip (extents);
+  c->paint ();
+  c->pop_clip ();
+
+  return true;
+}
+
+static void
+hb_paint_extents_paint_color (hb_paint_funcs_t *funcs HB_UNUSED,
+                             void *paint_data,
+                             hb_bool_t use_foreground HB_UNUSED,
+                             hb_color_t color HB_UNUSED,
+                             void *user_data HB_UNUSED)
+{
+  hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
+
+  c->paint ();
+}
+
+static void
+hb_paint_extents_paint_linear_gradient (hb_paint_funcs_t *funcs HB_UNUSED,
+                                       void *paint_data,
+                                       hb_color_line_t *color_line HB_UNUSED,
+                                       float x0 HB_UNUSED, float y0 HB_UNUSED,
+                                       float x1 HB_UNUSED, float y1 HB_UNUSED,
+                                       float x2 HB_UNUSED, float y2 HB_UNUSED,
+                                       void *user_data HB_UNUSED)
+{
+  hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
+
+  c->paint ();
+}
+
+static void
+hb_paint_extents_paint_radial_gradient (hb_paint_funcs_t *funcs HB_UNUSED,
+                                       void *paint_data,
+                                       hb_color_line_t *color_line HB_UNUSED,
+                                       float x0 HB_UNUSED, float y0 HB_UNUSED, float r0 HB_UNUSED,
+                                       float x1 HB_UNUSED, float y1 HB_UNUSED, float r1 HB_UNUSED,
+                                       void *user_data HB_UNUSED)
+{
+  hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
+
+  c->paint ();
+}
+
+static void
+hb_paint_extents_paint_sweep_gradient (hb_paint_funcs_t *funcs HB_UNUSED,
+                                      void *paint_data,
+                                      hb_color_line_t *color_line HB_UNUSED,
+                                      float cx HB_UNUSED, float cy HB_UNUSED,
+                                      float start_angle HB_UNUSED,
+                                      float end_angle HB_UNUSED,
+                                      void *user_data HB_UNUSED)
+{
+  hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
+
+  c->paint ();
+}
+
+static inline void free_static_paint_extents_funcs ();
+
+static struct hb_paint_extents_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_t<hb_paint_extents_funcs_lazy_loader_t>
+{
+  static hb_paint_funcs_t *create ()
+  {
+    hb_paint_funcs_t *funcs = hb_paint_funcs_create ();
+
+    hb_paint_funcs_set_push_transform_func (funcs, hb_paint_extents_push_transform, nullptr, nullptr);
+    hb_paint_funcs_set_pop_transform_func (funcs, hb_paint_extents_pop_transform, nullptr, nullptr);
+    hb_paint_funcs_set_push_clip_glyph_func (funcs, hb_paint_extents_push_clip_glyph, nullptr, nullptr);
+    hb_paint_funcs_set_push_clip_rectangle_func (funcs, hb_paint_extents_push_clip_rectangle, nullptr, nullptr);
+    hb_paint_funcs_set_pop_clip_func (funcs, hb_paint_extents_pop_clip, nullptr, nullptr);
+    hb_paint_funcs_set_push_group_func (funcs, hb_paint_extents_push_group, nullptr, nullptr);
+    hb_paint_funcs_set_pop_group_func (funcs, hb_paint_extents_pop_group, nullptr, nullptr);
+    hb_paint_funcs_set_color_func (funcs, hb_paint_extents_paint_color, nullptr, nullptr);
+    hb_paint_funcs_set_image_func (funcs, hb_paint_extents_paint_image, nullptr, nullptr);
+    hb_paint_funcs_set_linear_gradient_func (funcs, hb_paint_extents_paint_linear_gradient, nullptr, nullptr);
+    hb_paint_funcs_set_radial_gradient_func (funcs, hb_paint_extents_paint_radial_gradient, nullptr, nullptr);
+    hb_paint_funcs_set_sweep_gradient_func (funcs, hb_paint_extents_paint_sweep_gradient, nullptr, nullptr);
+
+    hb_paint_funcs_make_immutable (funcs);
+
+    hb_atexit (free_static_paint_extents_funcs);
+
+    return funcs;
+  }
+} static_paint_extents_funcs;
+
+static inline
+void free_static_paint_extents_funcs ()
+{
+  static_paint_extents_funcs.free_instance ();
+}
+
+hb_paint_funcs_t *
+hb_paint_extents_get_funcs ()
+{
+  return static_paint_extents_funcs.get_unconst ();
+}
+
+
+#endif
diff --git a/src/hb-paint-extents.hh b/src/hb-paint-extents.hh
new file mode 100644 (file)
index 0000000..f172bd4
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * Copyright © 2022 Behdad Esfahbod
+ *
+ *  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_PAINT_EXTENTS_HH
+#define HB_PAINT_EXTENTS_HH
+
+#include "hb.hh"
+#include "hb-paint.h"
+
+
+typedef struct hb_extents_t
+{
+  hb_extents_t () {}
+  hb_extents_t (float xmin, float ymin, float xmax, float ymax) :
+    xmin (xmin), ymin (ymin), xmax (xmax), ymax (ymax) {}
+
+  bool is_empty () const { return xmin >= xmax || ymin >= ymax; }
+  bool is_void () const { return xmin > xmax; }
+
+  void union_ (const hb_extents_t &o)
+  {
+    xmin = hb_min (xmin, o.xmin);
+    ymin = hb_min (ymin, o.ymin);
+    xmax = hb_max (xmax, o.xmax);
+    ymax = hb_max (ymax, o.ymax);
+  }
+
+  void intersect (const hb_extents_t &o)
+  {
+    xmin = hb_max (xmin, o.xmin);
+    ymin = hb_max (ymin, o.ymin);
+    xmax = hb_min (xmax, o.xmax);
+    ymax = hb_min (ymax, o.ymax);
+  }
+
+  void
+  add_point (float x, float y)
+  {
+    if (unlikely (is_void ()))
+    {
+      xmin = xmax = x;
+      ymin = ymax = y;
+    }
+    else
+    {
+      xmin = hb_min (xmin, x);
+      ymin = hb_min (ymin, y);
+      xmax = hb_max (xmax, x);
+      ymax = hb_max (ymax, y);
+    }
+  }
+
+  float xmin = 0.f;
+  float ymin = 0.f;
+  float xmax = -1.f;
+  float ymax = -1.f;
+} hb_extents_t;
+
+typedef struct hb_transform_t
+{
+  hb_transform_t () {}
+  hb_transform_t (float xx, float yx,
+                 float xy, float yy,
+                 float x0, float y0) :
+    xx (xx), yx (yx), xy (xy), yy (yy), x0 (x0), y0 (y0) {}
+
+  void multiply (const hb_transform_t &o)
+  {
+    /* Copied from cairo, with "o" being "a" there and "this" being "b" there. */
+    hb_transform_t r;
+
+    r.xx = o.xx * xx + o.yx * xy;
+    r.yx = o.xx * yx + o.yx * yy;
+
+    r.xy = o.xy * xx + o.yy * xy;
+    r.yy = o.xy * yx + o.yy * yy;
+
+    r.x0 = o.x0 * xx + o.y0 * xy + x0;
+    r.y0 = o.x0 * yx + o.y0 * yy + y0;
+
+    *this = r;
+  }
+
+  void transform_distance (float &dx, float &dy) const
+  {
+    float new_x = xx * dx + xy * dy;
+    float new_y = yx * dx + yy * dy;
+    dx = new_x;
+    dy = new_y;
+  }
+
+  void transform_point (float &x, float &y) const
+  {
+    transform_distance (x, y);
+    x += x0;
+    y += y0;
+  }
+
+  void transform_extents (hb_extents_t &extents) const
+  {
+    float quad_x[4], quad_y[4];
+
+    quad_x[0] = extents.xmin;
+    quad_y[0] = extents.ymin;
+    quad_x[1] = extents.xmin;
+    quad_y[1] = extents.ymax;
+    quad_x[2] = extents.xmax;
+    quad_y[2] = extents.ymin;
+    quad_x[3] = extents.xmax;
+    quad_y[3] = extents.ymax;
+
+    extents = hb_extents_t {};
+    for (unsigned i = 0; i < 4; i++)
+    {
+      transform_point (quad_x[i], quad_y[i]);
+      extents.add_point (quad_x[i], quad_y[i]);
+    }
+  }
+
+  float xx = 1.f;
+  float yx = 0.f;
+  float xy = 0.f;
+  float yy = 1.f;
+  float x0 = 0.f;
+  float y0 = 0.f;
+} hb_transform_t;
+
+typedef struct hb_bounds_t
+{
+  enum status_t {
+    UNBOUNDED,
+    BOUNDED,
+    EMPTY,
+  };
+
+  hb_bounds_t (status_t status) : status (status) {}
+  hb_bounds_t (const hb_extents_t &extents) :
+    status (extents.is_empty () ? EMPTY : BOUNDED), extents (extents) {}
+
+  void union_ (const hb_bounds_t &o)
+  {
+    if (o.status == UNBOUNDED)
+      status = UNBOUNDED;
+    else if (o.status == BOUNDED)
+    {
+      if (status == EMPTY)
+       *this = o;
+      else if (status == BOUNDED)
+        extents.union_ (o.extents);
+    }
+  }
+
+  void intersect (const hb_bounds_t &o)
+  {
+    if (o.status == EMPTY)
+      status = EMPTY;
+    else if (o.status == BOUNDED)
+    {
+      if (status == UNBOUNDED)
+       *this = o;
+      else if (status == BOUNDED)
+      {
+        extents.intersect (o.extents);
+       if (extents.is_empty ())
+         status = EMPTY;
+      }
+    }
+  }
+
+  status_t status;
+  hb_extents_t extents;
+} hb_bounds_t;
+
+typedef struct  hb_paint_extents_context_t hb_paint_extents_context_t;
+
+struct hb_paint_extents_context_t
+{
+  hb_paint_extents_context_t ()
+  {
+    transforms.push (hb_transform_t{});
+    clips.push (hb_bounds_t{hb_bounds_t::UNBOUNDED});
+    groups.push (hb_bounds_t{hb_bounds_t::EMPTY});
+  }
+
+  hb_extents_t get_extents ()
+  {
+    return groups.tail().extents;
+  }
+
+  bool is_bounded ()
+  {
+    return groups.tail().status != hb_bounds_t::UNBOUNDED;
+  }
+
+  void push_transform (const hb_transform_t &trans)
+  {
+    hb_transform_t t = transforms.tail ();
+    t.multiply (trans);
+    transforms.push (t);
+  }
+
+  void pop_transform ()
+  {
+    transforms.pop ();
+  }
+
+  void push_clip (hb_extents_t extents)
+  {
+    /* Transform extents and push a new clip. */
+    const hb_transform_t &t = transforms.tail ();
+    t.transform_extents (extents);
+
+    clips.push (hb_bounds_t {extents});
+  }
+
+  void pop_clip ()
+  {
+    clips.pop ();
+  }
+
+  void push_group ()
+  {
+    groups.push (hb_bounds_t {hb_bounds_t::EMPTY});
+  }
+
+  void pop_group (hb_paint_composite_mode_t mode)
+  {
+    const hb_bounds_t src_bounds = groups.pop ();
+    hb_bounds_t &backdrop_bounds = groups.tail ();
+
+    // https://learn.microsoft.com/en-us/typography/opentype/spec/colr#format-32-paintcomposite
+    switch ((int) mode)
+    {
+      case HB_PAINT_COMPOSITE_MODE_CLEAR:
+       backdrop_bounds.status = hb_bounds_t::EMPTY;
+       break;
+      case HB_PAINT_COMPOSITE_MODE_SRC:
+      case HB_PAINT_COMPOSITE_MODE_SRC_OUT:
+       backdrop_bounds = src_bounds;
+       break;
+      case HB_PAINT_COMPOSITE_MODE_DEST:
+      case HB_PAINT_COMPOSITE_MODE_DEST_OUT:
+       break;
+      case HB_PAINT_COMPOSITE_MODE_SRC_IN:
+      case HB_PAINT_COMPOSITE_MODE_DEST_IN:
+       backdrop_bounds.intersect (src_bounds);
+       break;
+      default:
+       backdrop_bounds.union_ (src_bounds);
+       break;
+     }
+  }
+
+  void paint ()
+  {
+    const hb_bounds_t &clip = clips.tail ();
+    hb_bounds_t &group = groups.tail ();
+
+    group.union_ (clip);
+  }
+
+  protected:
+  hb_vector_t<hb_transform_t> transforms;
+  hb_vector_t<hb_bounds_t> clips;
+  hb_vector_t<hb_bounds_t> groups;
+};
+
+HB_INTERNAL hb_paint_funcs_t *
+hb_paint_extents_get_funcs ();
+
+
+#endif /* HB_PAINT_EXTENTS_HH */
diff --git a/src/hb-paint.cc b/src/hb-paint.cc
new file mode 100644 (file)
index 0000000..8eb24eb
--- /dev/null
@@ -0,0 +1,728 @@
+/*
+ * Copyright © 2022 Matthias Clasen
+ *
+ *  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.hh"
+
+#ifndef HB_NO_PAINT
+
+#include "hb-paint.hh"
+
+/**
+ * SECTION: hb-paint
+ * @title: hb-paint
+ * @short_description: Glyph painting
+ * @include: hb.h
+ *
+ * Functions for painting glyphs.
+ *
+ * The main purpose of these functions is to paint (extract) color glyph layers
+ * from the COLRv1 table, but the API works for drawing ordinary outlines and
+ * images as well.
+ *
+ * The #hb_paint_funcs_t struct can be used with hb_font_paint_glyph().
+ **/
+
+static void
+hb_paint_push_transform_nil (hb_paint_funcs_t *funcs, void *paint_data,
+                             float xx, float yx,
+                             float xy, float yy,
+                             float dx, float dy,
+                             void *user_data) {}
+
+static void
+hb_paint_pop_transform_nil (hb_paint_funcs_t *funcs, void *paint_data,
+                            void *user_data) {}
+
+static hb_bool_t
+hb_paint_color_glyph_nil (hb_paint_funcs_t *funcs, void *paint_data,
+                          hb_codepoint_t glyph,
+                          hb_font_t *font,
+                          void *user_data) { return false; }
+
+static void
+hb_paint_push_clip_glyph_nil (hb_paint_funcs_t *funcs, void *paint_data,
+                              hb_codepoint_t glyph,
+                              hb_font_t *font,
+                              void *user_data) {}
+
+static void
+hb_paint_push_clip_rectangle_nil (hb_paint_funcs_t *funcs, void *paint_data,
+                                  float xmin, float ymin, float xmax, float ymax,
+                                  void *user_data) {}
+
+static void
+hb_paint_pop_clip_nil (hb_paint_funcs_t *funcs, void *paint_data,
+                       void *user_data) {}
+
+static void
+hb_paint_color_nil (hb_paint_funcs_t *funcs, void *paint_data,
+                    hb_bool_t is_foreground,
+                    hb_color_t color,
+                    void *user_data) {}
+
+static hb_bool_t
+hb_paint_image_nil (hb_paint_funcs_t *funcs, void *paint_data,
+                    hb_blob_t *image,
+                    unsigned int width,
+                    unsigned int height,
+                    hb_tag_t format,
+                    float slant_xy,
+                    hb_glyph_extents_t *extents,
+                    void *user_data) { return false; }
+
+static void
+hb_paint_linear_gradient_nil (hb_paint_funcs_t *funcs, void *paint_data,
+                              hb_color_line_t *color_line,
+                              float x0, float y0,
+                              float x1, float y1,
+                              float x2, float y2,
+                              void *user_data) {}
+
+static void
+hb_paint_radial_gradient_nil (hb_paint_funcs_t *funcs, void *paint_data,
+                              hb_color_line_t *color_line,
+                              float x0, float y0, float r0,
+                              float x1, float y1, float r1,
+                              void *user_data) {}
+
+static void
+hb_paint_sweep_gradient_nil (hb_paint_funcs_t *funcs, void *paint_data,
+                             hb_color_line_t *color_line,
+                             float x0, float y0,
+                             float start_angle,
+                             float end_angle,
+                             void *user_data) {}
+
+static void
+hb_paint_push_group_nil (hb_paint_funcs_t *funcs, void *paint_data,
+                         void *user_data) {}
+
+static void
+hb_paint_pop_group_nil (hb_paint_funcs_t *funcs, void *paint_data,
+                        hb_paint_composite_mode_t mode,
+                        void *user_data) {}
+
+static hb_bool_t
+hb_paint_custom_palette_color_nil (hb_paint_funcs_t *funcs, void *paint_data,
+                                   unsigned int color_index,
+                                   hb_color_t *color,
+                                   void *user_data) { return false; }
+
+static bool
+_hb_paint_funcs_set_preamble (hb_paint_funcs_t  *funcs,
+                             bool                func_is_null,
+                             void              **user_data,
+                             hb_destroy_func_t  *destroy)
+{
+  if (hb_object_is_immutable (funcs))
+  {
+    if (*destroy)
+      (*destroy) (*user_data);
+    return false;
+  }
+
+  if (func_is_null)
+  {
+    if (*destroy)
+      (*destroy) (*user_data);
+    *destroy = nullptr;
+    *user_data = nullptr;
+  }
+
+  return true;
+}
+
+static bool
+_hb_paint_funcs_set_middle (hb_paint_funcs_t  *funcs,
+                            void              *user_data,
+                            hb_destroy_func_t  destroy)
+{
+  if (user_data && !funcs->user_data)
+  {
+    funcs->user_data = (decltype (funcs->user_data)) hb_calloc (1, sizeof (*funcs->user_data));
+    if (unlikely (!funcs->user_data))
+      goto fail;
+  }
+  if (destroy && !funcs->destroy)
+  {
+    funcs->destroy = (decltype (funcs->destroy)) hb_calloc (1, sizeof (*funcs->destroy));
+    if (unlikely (!funcs->destroy))
+      goto fail;
+  }
+
+  return true;
+
+fail:
+  if (destroy)
+    (destroy) (user_data);
+  return false;
+}
+
+#define HB_PAINT_FUNC_IMPLEMENT(name)                                           \
+                                                                                \
+void                                                                            \
+hb_paint_funcs_set_##name##_func (hb_paint_funcs_t         *funcs,              \
+                                  hb_paint_##name##_func_t  func,               \
+                                  void                     *user_data,          \
+                                  hb_destroy_func_t         destroy)            \
+{                                                                               \
+  if (!_hb_paint_funcs_set_preamble (funcs, !func, &user_data, &destroy))       \
+      return;                                                                   \
+                                                                                \
+  if (funcs->destroy && funcs->destroy->name)                                   \
+    funcs->destroy->name (!funcs->user_data ? nullptr : funcs->user_data->name);\
+                                                                                \
+  if (!_hb_paint_funcs_set_middle (funcs, user_data, destroy))                  \
+      return;                                                                   \
+                                                                                \
+  if (func)                                                                     \
+    funcs->func.name = func;                                                    \
+  else                                                                          \
+    funcs->func.name = hb_paint_##name##_nil;                                   \
+                                                                                \
+  if (funcs->user_data)                                                         \
+    funcs->user_data->name = user_data;                                         \
+  if (funcs->destroy)                                                           \
+    funcs->destroy->name = destroy;                                             \
+}
+
+HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_PAINT_FUNC_IMPLEMENT
+
+/**
+ * hb_paint_funcs_create:
+ *
+ * Creates a new #hb_paint_funcs_t structure of paint functions.
+ *
+ * The initial reference count of 1 should be released with hb_paint_funcs_destroy()
+ * when you are done using the #hb_paint_funcs_t. This function never returns
+ * `NULL`. If memory cannot be allocated, a special singleton #hb_paint_funcs_t
+ * object will be returned.
+ *
+ * Returns value: (transfer full): the paint-functions structure
+ *
+ * Since: 7.0.0
+ */
+hb_paint_funcs_t *
+hb_paint_funcs_create ()
+{
+  hb_paint_funcs_t *funcs;
+  if (unlikely (!(funcs = hb_object_create<hb_paint_funcs_t> ())))
+    return const_cast<hb_paint_funcs_t *> (&Null (hb_paint_funcs_t));
+
+  funcs->func =  Null (hb_paint_funcs_t).func;
+
+  return funcs;
+}
+
+DEFINE_NULL_INSTANCE (hb_paint_funcs_t) =
+{
+  HB_OBJECT_HEADER_STATIC,
+
+  {
+#define HB_PAINT_FUNC_IMPLEMENT(name) hb_paint_##name##_nil,
+    HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_PAINT_FUNC_IMPLEMENT
+  }
+};
+
+/**
+ * hb_paint_funcs_get_empty:
+ *
+ * Fetches the singleton empty paint-functions structure.
+ *
+ * Return value: (transfer full): The empty paint-functions structure
+ *
+ * Since: 7.0.0
+ **/
+hb_paint_funcs_t *
+hb_paint_funcs_get_empty ()
+{
+  return const_cast<hb_paint_funcs_t *> (&Null (hb_paint_funcs_t));
+}
+
+/**
+ * hb_paint_funcs_reference: (skip)
+ * @funcs: The paint-functions structure
+ *
+ * Increases the reference count on a paint-functions structure.
+ *
+ * This prevents @funcs from being destroyed until a matching
+ * call to hb_paint_funcs_destroy() is made.
+ *
+ * Return value: The paint-functions structure
+ *
+ * Since: 7.0.0
+ */
+hb_paint_funcs_t *
+hb_paint_funcs_reference (hb_paint_funcs_t *funcs)
+{
+  return hb_object_reference (funcs);
+}
+
+/**
+ * hb_paint_funcs_destroy: (skip)
+ * @funcs: The paint-functions structure
+ *
+ * Decreases the reference count on a paint-functions structure.
+ *
+ * When the reference count reaches zero, the structure
+ * is destroyed, freeing all memory.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_paint_funcs_destroy (hb_paint_funcs_t *funcs)
+{
+  if (!hb_object_destroy (funcs)) return;
+
+  if (funcs->destroy)
+  {
+#define HB_PAINT_FUNC_IMPLEMENT(name) \
+    if (funcs->destroy->name) funcs->destroy->name (!funcs->user_data ? nullptr : funcs->user_data->name);
+      HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_PAINT_FUNC_IMPLEMENT
+  }
+
+  hb_free (funcs->destroy);
+  hb_free (funcs->user_data);
+  hb_free (funcs);
+}
+
+/**
+ * hb_paint_funcs_set_user_data: (skip)
+ * @funcs: The paint-functions structure
+ * @key: The user-data key
+ * @data: A pointer to the user data
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
+ * @replace: Whether to replace an existing data with the same key
+ *
+ * Attaches a user-data key/data pair to the specified paint-functions structure.
+ *
+ * Return value: `true` if success, `false` otherwise
+ *
+ * Since: 7.0.0
+ **/
+hb_bool_t
+hb_paint_funcs_set_user_data (hb_paint_funcs_t *funcs,
+                            hb_user_data_key_t *key,
+                            void *              data,
+                            hb_destroy_func_t   destroy,
+                            hb_bool_t           replace)
+{
+  return hb_object_set_user_data (funcs, key, data, destroy, replace);
+}
+
+/**
+ * hb_paint_funcs_get_user_data: (skip)
+ * @funcs: The paint-functions structure
+ * @key: The user-data key to query
+ *
+ * Fetches the user-data associated with the specified key,
+ * attached to the specified paint-functions structure.
+ *
+ * Return value: (transfer none): A pointer to the user data
+ *
+ * Since: 7.0.0
+ **/
+void *
+hb_paint_funcs_get_user_data (const hb_paint_funcs_t *funcs,
+                            hb_user_data_key_t       *key)
+{
+  return hb_object_get_user_data (funcs, key);
+}
+
+/**
+ * hb_paint_funcs_make_immutable:
+ * @funcs: The paint-functions structure
+ *
+ * Makes a paint-functions structure immutable.
+ *
+ * After this call, all attempts to set one of the callbacks
+ * on @funcs will fail.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_paint_funcs_make_immutable (hb_paint_funcs_t *funcs)
+{
+  if (hb_object_is_immutable (funcs))
+    return;
+
+  hb_object_make_immutable (funcs);
+}
+
+/**
+ * hb_paint_funcs_is_immutable:
+ * @funcs: The paint-functions structure
+ *
+ * Tests whether a paint-functions structure is immutable.
+ *
+ * Return value: `true` if @funcs is immutable, `false` otherwise
+ *
+ * Since: 7.0.0
+ */
+hb_bool_t
+hb_paint_funcs_is_immutable (hb_paint_funcs_t *funcs)
+{
+  return hb_object_is_immutable (funcs);
+}
+
+
+/**
+ * hb_color_line_get_color_stops:
+ * @color_line: a #hb_color_line_t object
+ * @start: the index of the first color stop to return
+ * @count: (inout) (optional): Input = the maximum number of feature tags to return;
+ *     Output = the actual number of feature tags returned (may be zero)
+ * @color_stops: (out) (array length=count) (optional): Array of #hb_color_stop_t to populate
+ *
+ * Fetches a list of color stops from the given color line object.
+ *
+ * Note that due to variations being applied, the returned color stops
+ * may be out of order. It is the callers responsibility to ensure that
+ * color stops are sorted by their offset before they are used.
+ *
+ * Return value: the total number of color stops in @color_line
+ *
+ * Since: 7.0.0
+ */
+unsigned int
+hb_color_line_get_color_stops (hb_color_line_t *color_line,
+                               unsigned int start,
+                               unsigned int *count,
+                               hb_color_stop_t *color_stops)
+{
+  return color_line->get_color_stops (color_line,
+                                     color_line->data,
+                                     start, count,
+                                     color_stops,
+                                     color_line->get_color_stops_user_data);
+}
+
+/**
+ * hb_color_line_get_extend:
+ * @color_line: a #hb_color_line_t object
+ *
+ * Fetches the extend mode of the color line object.
+ *
+ * Return value: the extend mode of @color_line
+ *
+ * Since: 7.0.0
+ */
+hb_paint_extend_t
+hb_color_line_get_extend (hb_color_line_t *color_line)
+{
+  return color_line->get_extend (color_line,
+                                color_line->data,
+                                color_line->get_extend_user_data);
+}
+
+
+/**
+ * hb_paint_push_transform:
+ * @funcs: paint functions
+ * @paint_data: associated data passed by the caller
+ * @xx: xx component of the transform matrix
+ * @yx: yx component of the transform matrix
+ * @xy: xy component of the transform matrix
+ * @yy: yy component of the transform matrix
+ * @dx: dx component of the transform matrix
+ * @dy: dy component of the transform matrix
+ *
+ * Perform a "push-transform" paint operation.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_paint_push_transform (hb_paint_funcs_t *funcs, void *paint_data,
+                         float xx, float yx,
+                         float xy, float yy,
+                         float dx, float dy)
+{
+  funcs->push_transform (paint_data, xx, yx, xy, yy, dx, dy);
+}
+
+/**
+ * hb_paint_pop_transform:
+ * @funcs: paint functions
+ * @paint_data: associated data passed by the caller
+ *
+ * Perform a "pop-transform" paint operation.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_paint_pop_transform (hb_paint_funcs_t *funcs, void *paint_data)
+{
+  funcs->pop_transform (paint_data);
+}
+
+/**
+ * hb_paint_color_glyph:
+ * @funcs: paint functions
+ * @paint_data: associated data passed by the caller
+ * @glyph: the glyph ID
+ * @font: the font
+ *
+ * Perform a "color-glyph" paint operation.
+ *
+ * Since: 8.2.0
+ */
+hb_bool_t
+hb_paint_color_glyph (hb_paint_funcs_t *funcs, void *paint_data,
+                      hb_codepoint_t glyph,
+                      hb_font_t *font)
+{
+  return funcs->color_glyph (paint_data, glyph, font);
+}
+
+/**
+ * hb_paint_push_clip_glyph:
+ * @funcs: paint functions
+ * @paint_data: associated data passed by the caller
+ * @glyph: the glyph ID
+ * @font: the font
+ *
+ * Perform a "push-clip-glyph" paint operation.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_paint_push_clip_glyph (hb_paint_funcs_t *funcs, void *paint_data,
+                          hb_codepoint_t glyph,
+                          hb_font_t *font)
+{
+  funcs->push_clip_glyph (paint_data, glyph, font);
+}
+
+/**
+ * hb_paint_push_clip_rectangle:
+ * @funcs: paint functions
+ * @paint_data: associated data passed by the caller
+ * @xmin: min X for the rectangle
+ * @ymin: min Y for the rectangle
+ * @xmax: max X for the rectangle
+ * @ymax: max Y for the rectangle
+ *
+ * Perform a "push-clip-rect" paint operation.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_paint_push_clip_rectangle (hb_paint_funcs_t *funcs, void *paint_data,
+                              float xmin, float ymin, float xmax, float ymax)
+{
+  funcs->push_clip_rectangle (paint_data, xmin, ymin, xmax, ymax);
+}
+
+/**
+ * hb_paint_pop_clip:
+ * @funcs: paint functions
+ * @paint_data: associated data passed by the caller
+ *
+ * Perform a "pop-clip" paint operation.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_paint_pop_clip (hb_paint_funcs_t *funcs, void *paint_data)
+{
+  funcs->pop_clip (paint_data);
+}
+
+/**
+ * hb_paint_color:
+ * @funcs: paint functions
+ * @paint_data: associated data passed by the caller
+ * @is_foreground: whether the color is the foreground
+ * @color: The color to use
+ *
+ * Perform a "color" paint operation.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_paint_color (hb_paint_funcs_t *funcs, void *paint_data,
+                hb_bool_t is_foreground,
+                hb_color_t color)
+{
+  funcs->color (paint_data, is_foreground, color);
+}
+
+/**
+ * hb_paint_image:
+ * @funcs: paint functions
+ * @paint_data: associated data passed by the caller
+ * @image: image data
+ * @width: width of the raster image in pixels, or 0
+ * @height: height of the raster image in pixels, or 0
+ * @format: the image format as a tag
+ * @slant: the synthetic slant ratio to be applied to the image during rendering
+ * @extents: (nullable): the extents of the glyph
+ *
+ * Perform a "image" paint operation.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_paint_image (hb_paint_funcs_t *funcs, void *paint_data,
+                hb_blob_t *image,
+                unsigned int width,
+                unsigned int height,
+                hb_tag_t format,
+                float slant,
+                hb_glyph_extents_t *extents)
+{
+  funcs->image (paint_data, image, width, height, format, slant, extents);
+}
+
+/**
+ * hb_paint_linear_gradient:
+ * @funcs: paint functions
+ * @paint_data: associated data passed by the caller
+ * @color_line: Color information for the gradient
+ * @x0: X coordinate of the first point
+ * @y0: Y coordinate of the first point
+ * @x1: X coordinate of the second point
+ * @y1: Y coordinate of the second point
+ * @x2: X coordinate of the third point
+ * @y2: Y coordinate of the third point
+ *
+ * Perform a "linear-gradient" paint operation.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_paint_linear_gradient (hb_paint_funcs_t *funcs, void *paint_data,
+                          hb_color_line_t *color_line,
+                          float x0, float y0,
+                          float x1, float y1,
+                          float x2, float y2)
+{
+  funcs->linear_gradient (paint_data, color_line, x0, y0, x1, y1, x2, y2);
+}
+
+/**
+ * hb_paint_radial_gradient:
+ * @funcs: paint functions
+ * @paint_data: associated data passed by the caller
+ * @color_line: Color information for the gradient
+ * @x0: X coordinate of the first circle's center
+ * @y0: Y coordinate of the first circle's center
+ * @r0: radius of the first circle
+ * @x1: X coordinate of the second circle's center
+ * @y1: Y coordinate of the second circle's center
+ * @r1: radius of the second circle
+ *
+ * Perform a "radial-gradient" paint operation.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_paint_radial_gradient (hb_paint_funcs_t *funcs, void *paint_data,
+                          hb_color_line_t *color_line,
+                          float x0, float y0, float r0,
+                          float x1, float y1, float r1)
+{
+  funcs->radial_gradient (paint_data, color_line, x0, y0, r0, y1, x1, r1);
+}
+
+/**
+ * hb_paint_sweep_gradient:
+ * @funcs: paint functions
+ * @paint_data: associated data passed by the caller
+ * @color_line: Color information for the gradient
+ * @x0: X coordinate of the circle's center
+ * @y0: Y coordinate of the circle's center
+ * @start_angle: the start angle
+ * @end_angle: the end angle
+ *
+ * Perform a "sweep-gradient" paint operation.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_paint_sweep_gradient (hb_paint_funcs_t *funcs, void *paint_data,
+                         hb_color_line_t *color_line,
+                         float x0, float y0,
+                         float start_angle, float end_angle)
+{
+  funcs->sweep_gradient (paint_data, color_line, x0, y0, start_angle, end_angle);
+}
+
+/**
+ * hb_paint_push_group:
+ * @funcs: paint functions
+ * @paint_data: associated data passed by the caller
+ *
+ * Perform a "push-group" paint operation.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_paint_push_group (hb_paint_funcs_t *funcs, void *paint_data)
+{
+  funcs->push_group (paint_data);
+}
+
+/**
+ * hb_paint_pop_group:
+ * @funcs: paint functions
+ * @paint_data: associated data passed by the caller
+ * @mode: the compositing mode to use
+ *
+ * Perform a "pop-group" paint operation.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_paint_pop_group (hb_paint_funcs_t *funcs, void *paint_data,
+                    hb_paint_composite_mode_t mode)
+{
+  funcs->pop_group (paint_data, mode);
+}
+
+/**
+ * hb_paint_custom_palette_color:
+ * @funcs: paint functions
+ * @paint_data: associated data passed by the caller
+ * @color_index: color index
+ * @color: (out): fetched color
+ *
+ * Gets the custom palette color for @color_index.
+ *
+ * Return value: `true` if found, `false` otherwise
+ *
+ * Since: 7.0.0
+ */
+hb_bool_t
+hb_paint_custom_palette_color (hb_paint_funcs_t *funcs, void *paint_data,
+                               unsigned int color_index,
+                               hb_color_t *color)
+{
+  return funcs->custom_palette_color (paint_data, color_index, color);
+}
+
+#endif
diff --git a/src/hb-paint.h b/src/hb-paint.h
new file mode 100644 (file)
index 0000000..b0cd384
--- /dev/null
@@ -0,0 +1,1029 @@
+/*
+ * Copyright © 2022 Matthias Clasen
+ *
+ *  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.
+ */
+
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_PAINT_H
+#define HB_PAINT_H
+
+#include "hb-common.h"
+
+HB_BEGIN_DECLS
+
+
+/**
+ * hb_paint_funcs_t:
+ *
+ * Glyph paint callbacks.
+ *
+ * The callbacks assume that the caller maintains a stack
+ * of current transforms, clips and intermediate surfaces,
+ * as evidenced by the pairs of push/pop callbacks. The
+ * push/pop calls will be properly nested, so it is fine
+ * to store the different kinds of object on a single stack.
+ *
+ * Not all callbacks are required for all kinds of glyphs.
+ * For rendering COLRv0 or non-color outline glyphs, the
+ * gradient callbacks are not needed, and the composite
+ * callback only needs to handle simple alpha compositing
+ * (#HB_PAINT_COMPOSITE_MODE_SRC_OVER).
+ *
+ * The paint-image callback is only needed for glyphs
+ * with image blobs in the CBDT, sbix or SVG tables.
+ *
+ * The custom-palette-color callback is only necessary if
+ * you want to override colors from the font palette with
+ * custom colors.
+ *
+ * Since: 7.0.0
+ **/
+typedef struct hb_paint_funcs_t hb_paint_funcs_t;
+
+HB_EXTERN hb_paint_funcs_t *
+hb_paint_funcs_create (void);
+
+HB_EXTERN hb_paint_funcs_t *
+hb_paint_funcs_get_empty (void);
+
+HB_EXTERN hb_paint_funcs_t *
+hb_paint_funcs_reference (hb_paint_funcs_t *funcs);
+
+HB_EXTERN void
+hb_paint_funcs_destroy (hb_paint_funcs_t *funcs);
+
+HB_EXTERN hb_bool_t
+hb_paint_funcs_set_user_data (hb_paint_funcs_t *funcs,
+                             hb_user_data_key_t *key,
+                             void *              data,
+                             hb_destroy_func_t   destroy,
+                             hb_bool_t           replace);
+
+
+HB_EXTERN void *
+hb_paint_funcs_get_user_data (const hb_paint_funcs_t *funcs,
+                             hb_user_data_key_t       *key);
+
+HB_EXTERN void
+hb_paint_funcs_make_immutable (hb_paint_funcs_t *funcs);
+
+HB_EXTERN hb_bool_t
+hb_paint_funcs_is_immutable (hb_paint_funcs_t *funcs);
+
+/**
+ * hb_paint_push_transform_func_t:
+ * @funcs: paint functions object
+ * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
+ * @xx: xx component of the transform matrix
+ * @yx: yx component of the transform matrix
+ * @xy: xy component of the transform matrix
+ * @yy: yy component of the transform matrix
+ * @dx: dx component of the transform matrix
+ * @dy: dy component of the transform matrix
+ * @user_data: User data pointer passed to hb_paint_funcs_set_push_transform_func()
+ *
+ * A virtual method for the #hb_paint_funcs_t to apply
+ * a transform to subsequent paint calls.
+ *
+ * This transform is applied after the current transform,
+ * and remains in effect until a matching call to
+ * the #hb_paint_funcs_pop_transform_func_t vfunc.
+ *
+ * Since: 7.0.0
+ */
+typedef void (*hb_paint_push_transform_func_t) (hb_paint_funcs_t *funcs,
+                                                void *paint_data,
+                                                float xx, float yx,
+                                                float xy, float yy,
+                                                float dx, float dy,
+                                                void *user_data);
+
+/**
+ * hb_paint_pop_transform_func_t:
+ * @funcs: paint functions object
+ * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
+ * @user_data: User data pointer passed to hb_paint_funcs_set_pop_transform_func()
+ *
+ * A virtual method for the #hb_paint_funcs_t to undo
+ * the effect of a prior call to the #hb_paint_funcs_push_transform_func_t
+ * vfunc.
+ *
+ * Since: 7.0.0
+ */
+typedef void (*hb_paint_pop_transform_func_t) (hb_paint_funcs_t *funcs,
+                                               void *paint_data,
+                                               void *user_data);
+
+/**
+ * hb_paint_color_glyph_func_t:
+ * @funcs: paint functions object
+ * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
+ * @glyph: the glyph ID
+ * @font: the font
+ * @user_data: User data pointer passed to hb_paint_funcs_set_color_glyph_func()
+ *
+ * A virtual method for the #hb_paint_funcs_t to render a color glyph by glyph index.
+ *
+ * Return value: %true if the glyph was painted, %false otherwise.
+ *
+ * Since: 8.2.0
+ */
+typedef hb_bool_t (*hb_paint_color_glyph_func_t) (hb_paint_funcs_t *funcs,
+                                                  void *paint_data,
+                                                  hb_codepoint_t glyph,
+                                                  hb_font_t *font,
+                                                  void *user_data);
+
+/**
+ * hb_paint_push_clip_glyph_func_t:
+ * @funcs: paint functions object
+ * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
+ * @glyph: the glyph ID
+ * @font: the font
+ * @user_data: User data pointer passed to hb_paint_funcs_set_push_clip_glyph_func()
+ *
+ * A virtual method for the #hb_paint_funcs_t to clip
+ * subsequent paint calls to the outline of a glyph.
+ *
+ * The coordinates of the glyph outline are interpreted according
+ * to the current transform.
+ *
+ * This clip is applied in addition to the current clip,
+ * and remains in effect until a matching call to
+ * the #hb_paint_funcs_pop_clip_func_t vfunc.
+ *
+ * Since: 7.0.0
+ */
+typedef void (*hb_paint_push_clip_glyph_func_t) (hb_paint_funcs_t *funcs,
+                                                 void *paint_data,
+                                                 hb_codepoint_t glyph,
+                                                 hb_font_t *font,
+                                                 void *user_data);
+
+/**
+ * hb_paint_push_clip_rectangle_func_t:
+ * @funcs: paint functions object
+ * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
+ * @xmin: min X for the rectangle
+ * @ymin: min Y for the rectangle
+ * @xmax: max X for the rectangle
+ * @ymax: max Y for the rectangle
+ * @user_data: User data pointer passed to hb_paint_funcs_set_push_clip_rectangle_func()
+ *
+ * A virtual method for the #hb_paint_funcs_t to clip
+ * subsequent paint calls to a rectangle.
+ *
+ * The coordinates of the rectangle are interpreted according
+ * to the current transform.
+ *
+ * This clip is applied in addition to the current clip,
+ * and remains in effect until a matching call to
+ * the #hb_paint_funcs_pop_clip_func_t vfunc.
+ *
+ * Since: 7.0.0
+ */
+typedef void (*hb_paint_push_clip_rectangle_func_t) (hb_paint_funcs_t *funcs,
+                                                     void *paint_data,
+                                                     float xmin, float ymin,
+                                                     float xmax, float ymax,
+                                                     void *user_data);
+
+/**
+ * hb_paint_pop_clip_func_t:
+ * @funcs: paint functions object
+ * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
+ * @user_data: User data pointer passed to hb_paint_funcs_set_pop_clip_func()
+ *
+ * A virtual method for the #hb_paint_funcs_t to undo
+ * the effect of a prior call to the #hb_paint_funcs_push_clip_glyph_func_t
+ * or #hb_paint_funcs_push_clip_rectangle_func_t vfuncs.
+ *
+ * Since: 7.0.0
+ */
+typedef void (*hb_paint_pop_clip_func_t) (hb_paint_funcs_t *funcs,
+                                          void *paint_data,
+                                          void *user_data);
+
+/**
+ * hb_paint_color_func_t:
+ * @funcs: paint functions object
+ * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
+ * @is_foreground: whether the color is the foreground
+ * @color: The color to use, unpremultiplied
+ * @user_data: User data pointer passed to hb_paint_funcs_set_color_func()
+ *
+ * A virtual method for the #hb_paint_funcs_t to paint a
+ * color everywhere within the current clip.
+ *
+ * Since: 7.0.0
+ */
+typedef void (*hb_paint_color_func_t) (hb_paint_funcs_t *funcs,
+                                       void *paint_data,
+                                       hb_bool_t is_foreground,
+                                       hb_color_t color,
+                                       void *user_data);
+
+/**
+ * HB_PAINT_IMAGE_FORMAT_PNG:
+ *
+ * Tag identifying PNG images in #hb_paint_image_func_t callbacks.
+ *
+ * Since: 7.0.0
+ */
+#define HB_PAINT_IMAGE_FORMAT_PNG HB_TAG('p','n','g',' ')
+
+/**
+ * HB_PAINT_IMAGE_FORMAT_SVG:
+ *
+ * Tag identifying SVG images in #hb_paint_image_func_t callbacks.
+ *
+ * Since: 7.0.0
+ */
+#define HB_PAINT_IMAGE_FORMAT_SVG HB_TAG('s','v','g',' ')
+
+/**
+ * HB_PAINT_IMAGE_FORMAT_BGRA:
+ *
+ * Tag identifying raw pixel-data images in #hb_paint_image_func_t callbacks.
+ * The data is in BGRA pre-multiplied sRGBA color-space format.
+ *
+ * Since: 7.0.0
+ */
+#define HB_PAINT_IMAGE_FORMAT_BGRA HB_TAG('B','G','R','A')
+
+/**
+ * hb_paint_image_func_t:
+ * @funcs: paint functions object
+ * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
+ * @image: the image data
+ * @width: width of the raster image in pixels, or 0
+ * @height: height of the raster image in pixels, or 0
+ * @format: the image format as a tag
+ * @slant: the synthetic slant ratio to be applied to the image during rendering
+ * @extents: (nullable): glyph extents for desired rendering
+ * @user_data: User data pointer passed to hb_paint_funcs_set_image_func()
+ *
+ * A virtual method for the #hb_paint_funcs_t to paint a glyph image.
+ *
+ * This method is called for glyphs with image blobs in the CBDT,
+ * sbix or SVG tables. The @format identifies the kind of data that
+ * is contained in @image. Possible values include #HB_PAINT_IMAGE_FORMAT_PNG,
+ * #HB_PAINT_IMAGE_FORMAT_SVG and #HB_PAINT_IMAGE_FORMAT_BGRA.
+ *
+ * The image dimensions and glyph extents are provided if available,
+ * and should be used to size and position the image.
+ *
+ * Return value: Whether the operation was successful.
+ *
+ * Since: 7.0.0
+ */
+typedef hb_bool_t (*hb_paint_image_func_t) (hb_paint_funcs_t *funcs,
+                                           void *paint_data,
+                                           hb_blob_t *image,
+                                           unsigned int width,
+                                           unsigned int height,
+                                           hb_tag_t format,
+                                           float slant,
+                                           hb_glyph_extents_t *extents,
+                                           void *user_data);
+
+/**
+ * hb_color_stop_t:
+ * @offset: the offset of the color stop
+ * @is_foreground: whether the color is the foreground
+ * @color: the color, unpremultiplied
+ *
+ * Information about a color stop on a color line.
+ *
+ * Color lines typically have offsets ranging between 0 and 1,
+ * but that is not required.
+ *
+ * Note: despite @color being unpremultiplied here, interpolation in
+ * gradients shall happen in premultiplied space. See the OpenType spec
+ * [COLR](https://learn.microsoft.com/en-us/typography/opentype/spec/colr)
+ * section for details.
+ *
+ * Since: 7.0.0
+ */
+typedef struct {
+  float offset;
+  hb_bool_t is_foreground;
+  hb_color_t color;
+} hb_color_stop_t;
+
+/**
+ * hb_paint_extend_t:
+ * @HB_PAINT_EXTEND_PAD: Outside the defined interval,
+ *   the color of the closest color stop is used.
+ * @HB_PAINT_EXTEND_REPEAT: The color line is repeated over
+ *   repeated multiples of the defined interval
+ * @HB_PAINT_EXTEND_REFLECT: The color line is repeated over
+ *      repeated intervals, as for the repeat mode.
+ *      However, in each repeated interval, the ordering of
+ *      color stops is the reverse of the adjacent interval.
+ *
+ * The values of this enumeration determine how color values
+ * outside the minimum and maximum defined offset on a #hb_color_line_t
+ * are determined.
+ *
+ * See the OpenType spec [COLR](https://learn.microsoft.com/en-us/typography/opentype/spec/colr)
+ * section for details.
+ *
+ * Since: 7.0.0
+ */
+typedef enum {
+  HB_PAINT_EXTEND_PAD,
+  HB_PAINT_EXTEND_REPEAT,
+  HB_PAINT_EXTEND_REFLECT
+} hb_paint_extend_t;
+
+typedef struct hb_color_line_t hb_color_line_t;
+
+/**
+ * hb_color_line_get_color_stops_func_t:
+ * @color_line: a #hb_color_line_t object
+ * @color_line_data: the data accompanying @color_line
+ * @start: the index of the first color stop to return
+ * @count: (inout) (optional): Input = the maximum number of feature tags to return;
+ *     Output = the actual number of feature tags returned (may be zero)
+ * @color_stops: (out) (array length=count) (optional): Array of #hb_color_stop_t to populate
+ * @user_data: the data accompanying this method
+ *
+ * A virtual method for the #hb_color_line_t to fetch color stops.
+ *
+ * Return value: the total number of color stops in @color_line
+ *
+ * Since: 7.0.0
+ */
+typedef unsigned int (*hb_color_line_get_color_stops_func_t) (hb_color_line_t *color_line,
+                                                             void *color_line_data,
+                                                             unsigned int start,
+                                                             unsigned int *count,
+                                                             hb_color_stop_t *color_stops,
+                                                             void *user_data);
+
+/**
+ * hb_color_line_get_extend_func_t:
+ * @color_line: a #hb_color_line_t object
+ * @color_line_data: the data accompanying @color_line
+ * @user_data: the data accompanying this method
+ *
+ * A virtual method for the @hb_color_line_t to fetches the extend mode.
+ *
+ * Return value: the extend mode of @color_line
+ *
+ * Since: 7.0.0
+ */
+typedef hb_paint_extend_t (*hb_color_line_get_extend_func_t) (hb_color_line_t *color_line,
+                                                             void *color_line_data,
+                                                             void *user_data);
+
+/**
+ * hb_color_line_t:
+ *
+ * A struct containing color information for a gradient.
+ *
+ * Since: 7.0.0
+ */
+struct hb_color_line_t {
+  void *data;
+
+  hb_color_line_get_color_stops_func_t get_color_stops;
+  void *get_color_stops_user_data;
+
+  hb_color_line_get_extend_func_t get_extend;
+  void *get_extend_user_data;
+
+  void *reserved0;
+  void *reserved1;
+  void *reserved2;
+  void *reserved3;
+  void *reserved5;
+  void *reserved6;
+  void *reserved7;
+  void *reserved8;
+};
+
+HB_EXTERN unsigned int
+hb_color_line_get_color_stops (hb_color_line_t *color_line,
+                               unsigned int start,
+                               unsigned int *count,
+                               hb_color_stop_t *color_stops);
+
+HB_EXTERN hb_paint_extend_t
+hb_color_line_get_extend (hb_color_line_t *color_line);
+
+/**
+ * hb_paint_linear_gradient_func_t:
+ * @funcs: paint functions object
+ * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
+ * @color_line: Color information for the gradient
+ * @x0: X coordinate of the first point
+ * @y0: Y coordinate of the first point
+ * @x1: X coordinate of the second point
+ * @y1: Y coordinate of the second point
+ * @x2: X coordinate of the third point
+ * @y2: Y coordinate of the third point
+ * @user_data: User data pointer passed to hb_paint_funcs_set_linear_gradient_func()
+ *
+ * A virtual method for the #hb_paint_funcs_t to paint a linear
+ * gradient everywhere within the current clip.
+ *
+ * The @color_line object contains information about the colors of the gradients.
+ * It is only valid for the duration of the callback, you cannot keep it around.
+ *
+ * The coordinates of the points are interpreted according
+ * to the current transform.
+ *
+ * See the OpenType spec [COLR](https://learn.microsoft.com/en-us/typography/opentype/spec/colr)
+ * section for details on how the points define the direction
+ * of the gradient, and how to interpret the @color_line.
+ *
+ * Since: 7.0.0
+ */
+typedef void (*hb_paint_linear_gradient_func_t) (hb_paint_funcs_t *funcs,
+                                                 void *paint_data,
+                                                 hb_color_line_t *color_line,
+                                                 float x0, float y0,
+                                                 float x1, float y1,
+                                                 float x2, float y2,
+                                                 void *user_data);
+
+/**
+ * hb_paint_radial_gradient_func_t:
+ * @funcs: paint functions object
+ * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
+ * @color_line: Color information for the gradient
+ * @x0: X coordinate of the first circle's center
+ * @y0: Y coordinate of the first circle's center
+ * @r0: radius of the first circle
+ * @x1: X coordinate of the second circle's center
+ * @y1: Y coordinate of the second circle's center
+ * @r1: radius of the second circle
+ * @user_data: User data pointer passed to hb_paint_funcs_set_radial_gradient_func()
+ *
+ * A virtual method for the #hb_paint_funcs_t to paint a radial
+ * gradient everywhere within the current clip.
+ *
+ * The @color_line object contains information about the colors of the gradients.
+ * It is only valid for the duration of the callback, you cannot keep it around.
+ *
+ * The coordinates of the points are interpreted according
+ * to the current transform.
+ *
+ * See the OpenType spec [COLR](https://learn.microsoft.com/en-us/typography/opentype/spec/colr)
+ * section for details on how the points define the direction
+ * of the gradient, and how to interpret the @color_line.
+ *
+ * Since: 7.0.0
+ */
+typedef void (*hb_paint_radial_gradient_func_t) (hb_paint_funcs_t *funcs,
+                                                 void *paint_data,
+                                                 hb_color_line_t *color_line,
+                                                 float x0, float y0, float r0,
+                                                 float x1, float y1, float r1,
+                                                 void *user_data);
+
+/**
+ * hb_paint_sweep_gradient_func_t:
+ * @funcs: paint functions object
+ * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
+ * @color_line: Color information for the gradient
+ * @x0: X coordinate of the circle's center
+ * @y0: Y coordinate of the circle's center
+ * @start_angle: the start angle, in radians
+ * @end_angle: the end angle, in radians
+ * @user_data: User data pointer passed to hb_paint_funcs_set_sweep_gradient_func()
+ *
+ * A virtual method for the #hb_paint_funcs_t to paint a sweep
+ * gradient everywhere within the current clip.
+ *
+ * The @color_line object contains information about the colors of the gradients.
+ * It is only valid for the duration of the callback, you cannot keep it around.
+ *
+ * The coordinates of the points are interpreted according
+ * to the current transform.
+ *
+ * See the OpenType spec [COLR](https://learn.microsoft.com/en-us/typography/opentype/spec/colr)
+ * section for details on how the points define the direction
+ * of the gradient, and how to interpret the @color_line.
+ *
+ * Since: 7.0.0
+ */
+typedef void (*hb_paint_sweep_gradient_func_t)  (hb_paint_funcs_t *funcs,
+                                                 void *paint_data,
+                                                 hb_color_line_t *color_line,
+                                                 float x0, float y0,
+                                                 float start_angle,
+                                                 float end_angle,
+                                                 void *user_data);
+
+/**
+ * hb_paint_composite_mode_t:
+ * @HB_PAINT_COMPOSITE_MODE_CLEAR: clear destination layer (bounded)
+ * @HB_PAINT_COMPOSITE_MODE_SRC: replace destination layer (bounded)
+ * @HB_PAINT_COMPOSITE_MODE_SRC_OVER: draw source layer on top of destination layer
+ * (bounded)
+ * @HB_PAINT_COMPOSITE_MODE_SRC_IN: draw source where there was destination content
+ * (unbounded)
+ * @HB_PAINT_COMPOSITE_MODE_SRC_OUT: draw source where there was no destination
+ * content (unbounded)
+ * @HB_PAINT_COMPOSITE_MODE_SRC_ATOP: draw source on top of destination content and
+ * only there
+ * @HB_PAINT_COMPOSITE_MODE_DEST: ignore the source
+ * @HB_PAINT_COMPOSITE_MODE_DEST_OVER: draw destination on top of source
+ * @HB_PAINT_COMPOSITE_MODE_DEST_IN: leave destination only where there was
+ * source content (unbounded)
+ * @HB_PAINT_COMPOSITE_MODE_DEST_OUT: leave destination only where there was no
+ * source content
+ * @HB_PAINT_COMPOSITE_MODE_DEST_ATOP: leave destination on top of source content
+ * and only there (unbounded)
+ * @HB_PAINT_COMPOSITE_MODE_XOR: source and destination are shown where there is only
+ * one of them
+ * @HB_PAINT_COMPOSITE_MODE_PLUS: source and destination layers are accumulated
+ * @HB_PAINT_COMPOSITE_MODE_MULTIPLY: source and destination layers are multiplied.
+ * This causes the result to be at least as dark as the darker inputs.
+ * @HB_PAINT_COMPOSITE_MODE_SCREEN: source and destination are complemented and
+ * multiplied. This causes the result to be at least as light as the lighter
+ * inputs.
+ * @HB_PAINT_COMPOSITE_MODE_OVERLAY: multiplies or screens, depending on the
+ * lightness of the destination color.
+ * @HB_PAINT_COMPOSITE_MODE_DARKEN: replaces the destination with the source if it
+ * is darker, otherwise keeps the source.
+ * @HB_PAINT_COMPOSITE_MODE_LIGHTEN: replaces the destination with the source if it
+ * is lighter, otherwise keeps the source.
+ * @HB_PAINT_COMPOSITE_MODE_COLOR_DODGE: brightens the destination color to reflect
+ * the source color.
+ * @HB_PAINT_COMPOSITE_MODE_COLOR_BURN: darkens the destination color to reflect
+ * the source color.
+ * @HB_PAINT_COMPOSITE_MODE_HARD_LIGHT: Multiplies or screens, dependent on source
+ * color.
+ * @HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT: Darkens or lightens, dependent on source
+ * color.
+ * @HB_PAINT_COMPOSITE_MODE_DIFFERENCE: Takes the difference of the source and
+ * destination color.
+ * @HB_PAINT_COMPOSITE_MODE_EXCLUSION: Produces an effect similar to difference, but
+ * with lower contrast.
+ * @HB_PAINT_COMPOSITE_MODE_HSL_HUE: Creates a color with the hue of the source
+ * and the saturation and luminosity of the target.
+ * @HB_PAINT_COMPOSITE_MODE_HSL_SATURATION: Creates a color with the saturation
+ * of the source and the hue and luminosity of the target. Painting with
+ * this mode onto a gray area produces no change.
+ * @HB_PAINT_COMPOSITE_MODE_HSL_COLOR: Creates a color with the hue and saturation
+ * of the source and the luminosity of the target. This preserves the gray
+ * levels of the target and is useful for coloring monochrome images or
+ * tinting color images.
+ * @HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY: Creates a color with the luminosity of
+ * the source and the hue and saturation of the target. This produces an
+ * inverse effect to @HB_PAINT_COMPOSITE_MODE_HSL_COLOR.
+ *
+ * The values of this enumeration describe the compositing modes
+ * that can be used when combining temporary redirected drawing
+ * with the backdrop.
+ *
+ * See the OpenType spec [COLR](https://learn.microsoft.com/en-us/typography/opentype/spec/colr)
+ * section for details.
+ *
+ * Since: 7.0.0
+ */
+typedef enum {
+  HB_PAINT_COMPOSITE_MODE_CLEAR,
+  HB_PAINT_COMPOSITE_MODE_SRC,
+  HB_PAINT_COMPOSITE_MODE_DEST,
+  HB_PAINT_COMPOSITE_MODE_SRC_OVER,
+  HB_PAINT_COMPOSITE_MODE_DEST_OVER,
+  HB_PAINT_COMPOSITE_MODE_SRC_IN,
+  HB_PAINT_COMPOSITE_MODE_DEST_IN,
+  HB_PAINT_COMPOSITE_MODE_SRC_OUT,
+  HB_PAINT_COMPOSITE_MODE_DEST_OUT,
+  HB_PAINT_COMPOSITE_MODE_SRC_ATOP,
+  HB_PAINT_COMPOSITE_MODE_DEST_ATOP,
+  HB_PAINT_COMPOSITE_MODE_XOR,
+  HB_PAINT_COMPOSITE_MODE_PLUS,
+  HB_PAINT_COMPOSITE_MODE_SCREEN,
+  HB_PAINT_COMPOSITE_MODE_OVERLAY,
+  HB_PAINT_COMPOSITE_MODE_DARKEN,
+  HB_PAINT_COMPOSITE_MODE_LIGHTEN,
+  HB_PAINT_COMPOSITE_MODE_COLOR_DODGE,
+  HB_PAINT_COMPOSITE_MODE_COLOR_BURN,
+  HB_PAINT_COMPOSITE_MODE_HARD_LIGHT,
+  HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT,
+  HB_PAINT_COMPOSITE_MODE_DIFFERENCE,
+  HB_PAINT_COMPOSITE_MODE_EXCLUSION,
+  HB_PAINT_COMPOSITE_MODE_MULTIPLY,
+  HB_PAINT_COMPOSITE_MODE_HSL_HUE,
+  HB_PAINT_COMPOSITE_MODE_HSL_SATURATION,
+  HB_PAINT_COMPOSITE_MODE_HSL_COLOR,
+  HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY
+} hb_paint_composite_mode_t;
+
+/**
+ * hb_paint_push_group_func_t:
+ * @funcs: paint functions object
+ * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
+ * @user_data: User data pointer passed to hb_paint_funcs_set_push_group_func()
+ *
+ * A virtual method for the #hb_paint_funcs_t to use
+ * an intermediate surface for subsequent paint calls.
+ *
+ * The drawing will be redirected to an intermediate surface
+ * until a matching call to the #hb_paint_funcs_pop_group_func_t
+ * vfunc.
+ *
+ * Since: 7.0.0
+ */
+typedef void (*hb_paint_push_group_func_t) (hb_paint_funcs_t *funcs,
+                                            void *paint_data,
+                                            void *user_data);
+
+/**
+ * hb_paint_pop_group_func_t:
+ * @funcs: paint functions object
+ * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
+ * @mode: the compositing mode to use
+ * @user_data: User data pointer passed to hb_paint_funcs_set_pop_group_func()
+ *
+ * A virtual method for the #hb_paint_funcs_t to undo
+ * the effect of a prior call to the #hb_paint_funcs_push_group_func_t
+ * vfunc.
+ *
+ * This call stops the redirection to the intermediate surface,
+ * and then composites it on the previous surface, using the
+ * compositing mode passed to this call.
+ *
+ * Since: 7.0.0
+ */
+typedef void (*hb_paint_pop_group_func_t) (hb_paint_funcs_t *funcs,
+                                           void *paint_data,
+                                           hb_paint_composite_mode_t mode,
+                                           void *user_data);
+
+/**
+ * hb_paint_custom_palette_color_func_t:
+ * @funcs: paint functions object
+ * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
+ * @color_index: the color index
+ * @color: (out): fetched color
+ * @user_data: User data pointer passed to hb_paint_funcs_set_pop_group_func()
+ *
+ * A virtual method for the #hb_paint_funcs_t to fetch a color from the custom
+ * color palette.
+ *
+ * Custom palette colors override the colors from the fonts selected color
+ * palette. It is not necessary to override all palette entries; for entries
+ * that should be taken from the font palette, return `false`.
+ *
+ * This function might get called multiple times, but the custom palette is
+ * expected to remain unchanged for duration of a hb_font_paint_glyph() call.
+ *
+ * Return value: `true` if found, `false` otherwise
+ *
+ * Since: 7.0.0
+ */
+typedef hb_bool_t (*hb_paint_custom_palette_color_func_t) (hb_paint_funcs_t *funcs,
+                                                           void *paint_data,
+                                                           unsigned int color_index,
+                                                           hb_color_t *color,
+                                                           void *user_data);
+
+
+/**
+ * hb_paint_funcs_set_push_transform_func:
+ * @funcs: A paint functions struct
+ * @func: (closure user_data) (destroy destroy) (scope notified): The push-transform callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): Function to call when @user_data is no longer needed
+ *
+ * Sets the push-transform callback on the paint functions struct.
+ *
+ * Since: 7.0.0
+ */
+HB_EXTERN void
+hb_paint_funcs_set_push_transform_func (hb_paint_funcs_t               *funcs,
+                                        hb_paint_push_transform_func_t  func,
+                                        void                           *user_data,
+                                        hb_destroy_func_t               destroy);
+
+/**
+ * hb_paint_funcs_set_pop_transform_func:
+ * @funcs: A paint functions struct
+ * @func: (closure user_data) (destroy destroy) (scope notified): The pop-transform callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): Function to call when @user_data is no longer needed
+ *
+ * Sets the pop-transform callback on the paint functions struct.
+ *
+ * Since: 7.0.0
+ */
+HB_EXTERN void
+hb_paint_funcs_set_pop_transform_func (hb_paint_funcs_t              *funcs,
+                                       hb_paint_pop_transform_func_t  func,
+                                       void                          *user_data,
+                                       hb_destroy_func_t              destroy);
+
+/**
+ * hb_paint_funcs_set_color_glyph_func:
+ * @funcs: A paint functions struct
+ * @func: (closure user_data) (destroy destroy) (scope notified): The color-glyph callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): Function to call when @user_data is no longer needed
+ *
+ * Sets the color-glyph callback on the paint functions struct.
+ *
+ * Since: 8.2.0
+ */
+HB_EXTERN void
+hb_paint_funcs_set_color_glyph_func (hb_paint_funcs_t                *funcs,
+                                    hb_paint_color_glyph_func_t     func,
+                                    void                            *user_data,
+                                    hb_destroy_func_t                destroy);
+
+/**
+ * hb_paint_funcs_set_push_clip_glyph_func:
+ * @funcs: A paint functions struct
+ * @func: (closure user_data) (destroy destroy) (scope notified): The push-clip-glyph callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): Function to call when @user_data is no longer needed
+ *
+ * Sets the push-clip-glyph callback on the paint functions struct.
+ *
+ * Since: 7.0.0
+ */
+HB_EXTERN void
+hb_paint_funcs_set_push_clip_glyph_func (hb_paint_funcs_t                *funcs,
+                                         hb_paint_push_clip_glyph_func_t  func,
+                                         void                            *user_data,
+                                         hb_destroy_func_t                destroy);
+
+/**
+ * hb_paint_funcs_set_push_clip_rectangle_func:
+ * @funcs: A paint functions struct
+ * @func: (closure user_data) (destroy destroy) (scope notified): The push-clip-rectangle callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): Function to call when @user_data is no longer needed
+ *
+ * Sets the push-clip-rect callback on the paint functions struct.
+ *
+ * Since: 7.0.0
+ */
+HB_EXTERN void
+hb_paint_funcs_set_push_clip_rectangle_func (hb_paint_funcs_t                    *funcs,
+                                             hb_paint_push_clip_rectangle_func_t  func,
+                                             void                                *user_data,
+                                             hb_destroy_func_t                    destroy);
+
+/**
+ * hb_paint_funcs_set_pop_clip_func:
+ * @funcs: A paint functions struct
+ * @func: (closure user_data) (destroy destroy) (scope notified): The pop-clip callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): Function to call when @user_data is no longer needed
+ *
+ * Sets the pop-clip callback on the paint functions struct.
+ *
+ * Since: 7.0.0
+ */
+HB_EXTERN void
+hb_paint_funcs_set_pop_clip_func (hb_paint_funcs_t         *funcs,
+                                  hb_paint_pop_clip_func_t  func,
+                                  void                     *user_data,
+                                  hb_destroy_func_t         destroy);
+
+/**
+ * hb_paint_funcs_set_color_func:
+ * @funcs: A paint functions struct
+ * @func: (closure user_data) (destroy destroy) (scope notified): The paint-color callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): Function to call when @user_data is no longer needed
+ *
+ * Sets the paint-color callback on the paint functions struct.
+ *
+ * Since: 7.0.0
+ */
+HB_EXTERN void
+hb_paint_funcs_set_color_func (hb_paint_funcs_t      *funcs,
+                               hb_paint_color_func_t  func,
+                               void                  *user_data,
+                               hb_destroy_func_t      destroy);
+
+/**
+ * hb_paint_funcs_set_image_func:
+ * @funcs: A paint functions struct
+ * @func: (closure user_data) (destroy destroy) (scope notified): The paint-image callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): Function to call when @user_data is no longer needed
+ *
+ * Sets the paint-image callback on the paint functions struct.
+ *
+ * Since: 7.0.0
+ */
+HB_EXTERN void
+hb_paint_funcs_set_image_func (hb_paint_funcs_t      *funcs,
+                               hb_paint_image_func_t  func,
+                               void                  *user_data,
+                               hb_destroy_func_t      destroy);
+
+/**
+ * hb_paint_funcs_set_linear_gradient_func:
+ * @funcs: A paint functions struct
+ * @func: (closure user_data) (destroy destroy) (scope notified): The linear-gradient callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): Function to call when @user_data is no longer needed
+ *
+ * Sets the linear-gradient callback on the paint functions struct.
+ *
+ * Since: 7.0.0
+ */
+HB_EXTERN void
+hb_paint_funcs_set_linear_gradient_func (hb_paint_funcs_t                *funcs,
+                                         hb_paint_linear_gradient_func_t  func,
+                                         void                            *user_data,
+                                         hb_destroy_func_t                destroy);
+
+/**
+ * hb_paint_funcs_set_radial_gradient_func:
+ * @funcs: A paint functions struct
+ * @func: (closure user_data) (destroy destroy) (scope notified): The radial-gradient callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): Function to call when @user_data is no longer needed
+ *
+ * Sets the radial-gradient callback on the paint functions struct.
+ *
+ * Since: 7.0.0
+ */
+HB_EXTERN void
+hb_paint_funcs_set_radial_gradient_func (hb_paint_funcs_t                *funcs,
+                                         hb_paint_radial_gradient_func_t  func,
+                                         void                            *user_data,
+                                         hb_destroy_func_t                destroy);
+
+/**
+ * hb_paint_funcs_set_sweep_gradient_func:
+ * @funcs: A paint functions struct
+ * @func: (closure user_data) (destroy destroy) (scope notified): The sweep-gradient callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): Function to call when @user_data is no longer needed
+ *
+ * Sets the sweep-gradient callback on the paint functions struct.
+ *
+ * Since: 7.0.0
+ */
+HB_EXTERN void
+hb_paint_funcs_set_sweep_gradient_func (hb_paint_funcs_t               *funcs,
+                                        hb_paint_sweep_gradient_func_t  func,
+                                        void                           *user_data,
+                                        hb_destroy_func_t               destroy);
+
+/**
+ * hb_paint_funcs_set_push_group_func:
+ * @funcs: A paint functions struct
+ * @func: (closure user_data) (destroy destroy) (scope notified): The push-group callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): Function to call when @user_data is no longer needed
+ *
+ * Sets the push-group callback on the paint functions struct.
+ *
+ * Since: 7.0.0
+ */
+HB_EXTERN void
+hb_paint_funcs_set_push_group_func (hb_paint_funcs_t           *funcs,
+                                    hb_paint_push_group_func_t  func,
+                                    void                       *user_data,
+                                    hb_destroy_func_t           destroy);
+
+/**
+ * hb_paint_funcs_set_pop_group_func:
+ * @funcs: A paint functions struct
+ * @func: (closure user_data) (destroy destroy) (scope notified): The pop-group callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): Function to call when @user_data is no longer needed
+ *
+ * Sets the pop-group callback on the paint functions struct.
+ *
+ * Since: 7.0.0
+ */
+HB_EXTERN void
+hb_paint_funcs_set_pop_group_func (hb_paint_funcs_t          *funcs,
+                                   hb_paint_pop_group_func_t  func,
+                                   void                       *user_data,
+                                   hb_destroy_func_t           destroy);
+
+/**
+ * hb_paint_funcs_set_custom_palette_color_func:
+ * @funcs: A paint functions struct
+ * @func: (closure user_data) (destroy destroy) (scope notified): The custom-palette-color callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): Function to call when @user_data is no longer needed
+ *
+ * Sets the custom-palette-color callback on the paint functions struct.
+ *
+ * Since: 7.0.0
+ */
+HB_EXTERN void
+hb_paint_funcs_set_custom_palette_color_func (hb_paint_funcs_t                     *funcs,
+                                              hb_paint_custom_palette_color_func_t  func,
+                                              void                                 *user_data,
+                                              hb_destroy_func_t                     destroy);
+/*
+ * Manual API
+ */
+
+HB_EXTERN void
+hb_paint_push_transform (hb_paint_funcs_t *funcs, void *paint_data,
+                         float xx, float yx,
+                         float xy, float yy,
+                         float dx, float dy);
+
+HB_EXTERN void
+hb_paint_pop_transform (hb_paint_funcs_t *funcs, void *paint_data);
+
+HB_EXTERN hb_bool_t
+hb_paint_color_glyph (hb_paint_funcs_t *funcs, void *paint_data,
+                      hb_codepoint_t glyph,
+                      hb_font_t *font);
+
+HB_EXTERN void
+hb_paint_push_clip_glyph (hb_paint_funcs_t *funcs, void *paint_data,
+                          hb_codepoint_t glyph,
+                          hb_font_t *font);
+
+HB_EXTERN void
+hb_paint_push_clip_rectangle (hb_paint_funcs_t *funcs, void *paint_data,
+                              float xmin, float ymin,
+                              float xmax, float ymax);
+
+HB_EXTERN void
+hb_paint_pop_clip (hb_paint_funcs_t *funcs, void *paint_data);
+
+HB_EXTERN void
+hb_paint_color (hb_paint_funcs_t *funcs, void *paint_data,
+                hb_bool_t is_foreground,
+                hb_color_t color);
+
+HB_EXTERN void
+hb_paint_image (hb_paint_funcs_t *funcs, void *paint_data,
+                hb_blob_t *image,
+                unsigned int width,
+                unsigned int height,
+                hb_tag_t format,
+                float slant,
+                hb_glyph_extents_t *extents);
+
+HB_EXTERN void
+hb_paint_linear_gradient (hb_paint_funcs_t *funcs, void *paint_data,
+                          hb_color_line_t *color_line,
+                          float x0, float y0,
+                          float x1, float y1,
+                          float x2, float y2);
+
+HB_EXTERN void
+hb_paint_radial_gradient (hb_paint_funcs_t *funcs, void *paint_data,
+                          hb_color_line_t *color_line,
+                          float x0, float y0,
+                          float r0,
+                          float x1, float y1,
+                          float r1);
+
+HB_EXTERN void
+hb_paint_sweep_gradient (hb_paint_funcs_t *funcs, void *paint_data,
+                         hb_color_line_t *color_line,
+                         float x0, float y0,
+                         float start_angle, float end_angle);
+
+HB_EXTERN void
+hb_paint_push_group (hb_paint_funcs_t *funcs, void *paint_data);
+
+HB_EXTERN void
+hb_paint_pop_group (hb_paint_funcs_t *funcs, void *paint_data,
+                    hb_paint_composite_mode_t mode);
+
+HB_EXTERN hb_bool_t
+hb_paint_custom_palette_color (hb_paint_funcs_t *funcs, void *paint_data,
+                               unsigned int color_index,
+                               hb_color_t *color);
+
+HB_END_DECLS
+
+#endif  /* HB_PAINT_H */
diff --git a/src/hb-paint.hh b/src/hb-paint.hh
new file mode 100644 (file)
index 0000000..56b790d
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Copyright © 2022 Matthias Clasen
+ *
+ *  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_PAINT_HH
+#define HB_PAINT_HH
+
+#include "hb.hh"
+#include "hb-face.hh"
+#include "hb-font.hh"
+
+#define HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS \
+  HB_PAINT_FUNC_IMPLEMENT (push_transform) \
+  HB_PAINT_FUNC_IMPLEMENT (pop_transform) \
+  HB_PAINT_FUNC_IMPLEMENT (color_glyph) \
+  HB_PAINT_FUNC_IMPLEMENT (push_clip_glyph) \
+  HB_PAINT_FUNC_IMPLEMENT (push_clip_rectangle) \
+  HB_PAINT_FUNC_IMPLEMENT (pop_clip) \
+  HB_PAINT_FUNC_IMPLEMENT (color) \
+  HB_PAINT_FUNC_IMPLEMENT (image) \
+  HB_PAINT_FUNC_IMPLEMENT (linear_gradient) \
+  HB_PAINT_FUNC_IMPLEMENT (radial_gradient) \
+  HB_PAINT_FUNC_IMPLEMENT (sweep_gradient) \
+  HB_PAINT_FUNC_IMPLEMENT (push_group) \
+  HB_PAINT_FUNC_IMPLEMENT (pop_group) \
+  HB_PAINT_FUNC_IMPLEMENT (custom_palette_color) \
+  /* ^--- Add new callbacks here */
+
+struct hb_paint_funcs_t
+{
+  hb_object_header_t header;
+
+  struct {
+#define HB_PAINT_FUNC_IMPLEMENT(name) hb_paint_##name##_func_t name;
+    HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_PAINT_FUNC_IMPLEMENT
+  } func;
+
+  struct {
+#define HB_PAINT_FUNC_IMPLEMENT(name) void *name;
+    HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_PAINT_FUNC_IMPLEMENT
+  } *user_data;
+
+  struct {
+#define HB_PAINT_FUNC_IMPLEMENT(name) hb_destroy_func_t name;
+    HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_PAINT_FUNC_IMPLEMENT
+  } *destroy;
+
+  void push_transform (void *paint_data,
+                       float xx, float yx,
+                       float xy, float yy,
+                       float dx, float dy)
+  { func.push_transform (this, paint_data,
+                         xx, yx, xy, yy, dx, dy,
+                         !user_data ? nullptr : user_data->push_transform); }
+  void pop_transform (void *paint_data)
+  { func.pop_transform (this, paint_data,
+                        !user_data ? nullptr : user_data->pop_transform); }
+  bool color_glyph (void *paint_data,
+                    hb_codepoint_t glyph,
+                    hb_font_t *font)
+  { return func.color_glyph (this, paint_data,
+                             glyph,
+                             font,
+                             !user_data ? nullptr : user_data->push_clip_glyph); }
+  void push_clip_glyph (void *paint_data,
+                        hb_codepoint_t glyph,
+                        hb_font_t *font)
+  { func.push_clip_glyph (this, paint_data,
+                          glyph,
+                          font,
+                          !user_data ? nullptr : user_data->push_clip_glyph); }
+  void push_clip_rectangle (void *paint_data,
+                           float xmin, float ymin, float xmax, float ymax)
+  { func.push_clip_rectangle (this, paint_data,
+                              xmin, ymin, xmax, ymax,
+                              !user_data ? nullptr : user_data->push_clip_rectangle); }
+  void pop_clip (void *paint_data)
+  { func.pop_clip (this, paint_data,
+                   !user_data ? nullptr : user_data->pop_clip); }
+  void color (void *paint_data,
+              hb_bool_t is_foreground,
+              hb_color_t color)
+  { func.color (this, paint_data,
+                is_foreground, color,
+                !user_data ? nullptr : user_data->color); }
+  bool image (void *paint_data,
+              hb_blob_t *image,
+              unsigned width, unsigned height,
+              hb_tag_t format,
+              float slant,
+              hb_glyph_extents_t *extents)
+  { return func.image (this, paint_data,
+                       image, width, height, format, slant, extents,
+                       !user_data ? nullptr : user_data->image); }
+  void linear_gradient (void *paint_data,
+                        hb_color_line_t *color_line,
+                        float x0, float y0,
+                        float x1, float y1,
+                        float x2, float y2)
+  { func.linear_gradient (this, paint_data,
+                          color_line, x0, y0, x1, y1, x2, y2,
+                          !user_data ? nullptr : user_data->linear_gradient); }
+  void radial_gradient (void *paint_data,
+                        hb_color_line_t *color_line,
+                        float x0, float y0, float r0,
+                        float x1, float y1, float r1)
+  { func.radial_gradient (this, paint_data,
+                          color_line, x0, y0, r0, x1, y1, r1,
+                          !user_data ? nullptr : user_data->radial_gradient); }
+  void sweep_gradient (void *paint_data,
+                       hb_color_line_t *color_line,
+                       float x0, float y0,
+                       float start_angle,
+                       float end_angle)
+  { func.sweep_gradient (this, paint_data,
+                         color_line, x0, y0, start_angle, end_angle,
+                         !user_data ? nullptr : user_data->sweep_gradient); }
+  void push_group (void *paint_data)
+  { func.push_group (this, paint_data,
+                     !user_data ? nullptr : user_data->push_group); }
+  void pop_group (void *paint_data,
+                  hb_paint_composite_mode_t mode)
+  { func.pop_group (this, paint_data,
+                    mode,
+                    !user_data ? nullptr : user_data->pop_group); }
+  bool custom_palette_color (void *paint_data,
+                             unsigned int color_index,
+                             hb_color_t *color)
+  { return func.custom_palette_color (this, paint_data,
+                                      color_index,
+                                      color,
+                                      !user_data ? nullptr : user_data->custom_palette_color); }
+
+
+  /* Internal specializations. */
+
+  void push_root_transform (void *paint_data,
+                            const hb_font_t *font)
+  {
+    float upem = font->face->get_upem ();
+    int xscale = font->x_scale, yscale = font->y_scale;
+    float slant = font->slant_xy;
+
+    push_transform (paint_data,
+                   xscale/upem, 0, slant * yscale/upem, yscale/upem, 0, 0);
+  }
+
+  void push_inverse_root_transform (void *paint_data,
+                                    hb_font_t *font)
+  {
+    float upem = font->face->get_upem ();
+    int xscale = font->x_scale ? font->x_scale : upem;
+    int yscale = font->y_scale ? font->y_scale : upem;
+    float slant = font->slant_xy;
+
+    push_transform (paint_data,
+                   upem/xscale, 0, -slant * upem/xscale, upem/yscale, 0, 0);
+  }
+
+  HB_NODISCARD
+  bool push_translate (void *paint_data,
+                       float dx, float dy)
+  {
+    if (!dx && !dy)
+      return false;
+
+    push_transform (paint_data,
+                   1.f, 0.f, 0.f, 1.f, dx, dy);
+    return true;
+  }
+
+  HB_NODISCARD
+  bool push_scale (void *paint_data,
+                   float sx, float sy)
+  {
+    if (sx == 1.f && sy == 1.f)
+      return false;
+
+    push_transform (paint_data,
+                   sx, 0.f, 0.f, sy, 0.f, 0.f);
+    return true;
+  }
+
+  HB_NODISCARD
+  bool push_rotate (void *paint_data,
+                    float a)
+  {
+    if (!a)
+      return false;
+
+    float cc = cosf (a * HB_PI);
+    float ss = sinf (a * HB_PI);
+    push_transform (paint_data, cc, ss, -ss, cc, 0.f, 0.f);
+    return true;
+  }
+
+  HB_NODISCARD
+  bool push_skew (void *paint_data,
+                  float sx, float sy)
+  {
+    if (!sx && !sy)
+      return false;
+
+    float x = tanf (-sx * HB_PI);
+    float y = tanf (+sy * HB_PI);
+    push_transform (paint_data, 1.f, y, x, 1.f, 0.f, 0.f);
+    return true;
+  }
+};
+DECLARE_NULL_INSTANCE (hb_paint_funcs_t);
+
+
+#endif /* HB_PAINT_HH */
index dcf8f66..fcf1066 100644 (file)
 
 #include "hb.hh"
 
-/* Memory pool for persistent allocation of small objects. */
-
-template <typename T, unsigned ChunkLen = 16>
+/* Memory pool for persistent allocation of small objects.
+ *
+ * Some AI musings on this, not necessarily true:
+ *
+ * This is a very simple implementation, but it's good enough for our
+ * purposes.  It's not thread-safe.  It's not very fast.  It's not
+ * very memory efficient.  It's not very cache efficient.  It's not
+ * very anything efficient.  But it's simple and it works.  And it's
+ * good enough for our purposes.  If you need something more
+ * sophisticated, use a real allocator.  Or use a real language. */
+
+template <typename T, unsigned ChunkLen = 32>
 struct hb_pool_t
 {
   hb_pool_t () : next (nullptr) {}
-  ~hb_pool_t () { fini (); }
-
-  void fini ()
+  ~hb_pool_t ()
   {
     next = nullptr;
 
-    for (chunk_t *_ : chunks) hb_free (_);
-
-    chunks.fini ();
+    + hb_iter (chunks)
+    | hb_apply (hb_free)
+    ;
   }
 
   T* alloc ()
@@ -51,7 +58,7 @@ struct hb_pool_t
     if (unlikely (!next))
     {
       if (unlikely (!chunks.alloc (chunks.length + 1))) return nullptr;
-      chunk_t *chunk = (chunk_t *) hb_calloc (1, sizeof (chunk_t));
+      chunk_t *chunk = (chunk_t *) hb_malloc (sizeof (chunk_t));
       if (unlikely (!chunk)) return nullptr;
       chunks.push (chunk);
       next = chunk->thread ();
@@ -60,7 +67,7 @@ struct hb_pool_t
     T* obj = next;
     next = * ((T**) next);
 
-    memset (obj, 0, sizeof (T));
+    hb_memset (obj, 0, sizeof (T));
 
     return obj;
   }
index 7d799ae..2c8ccbf 100644 (file)
  *
  * Priority queue implemented as a binary heap. Supports extract minimum
  * and insert operations.
+ *
+ * The priority queue is implemented as a binary heap, which is a complete
+ * binary tree. The root of the tree is the minimum element. The heap
+ * property is that the priority of a node is less than or equal to the
+ * priority of its children. The heap is stored in an array, with the
+ * children of node i stored at indices 2i + 1 and 2i + 2.
  */
+template <typename K>
 struct hb_priority_queue_t
 {
-  HB_DELETE_COPY_ASSIGN (hb_priority_queue_t);
-  hb_priority_queue_t ()  { init (); }
-  ~hb_priority_queue_t () { fini (); }
-
  private:
-  typedef hb_pair_t<int64_t, unsigned> item_t;
+  typedef hb_pair_t<K, unsigned> item_t;
   hb_vector_t<item_t> heap;
 
  public:
-  void init () { heap.init (); }
-
-  void fini () { heap.fini (); }
 
   void reset () { heap.resize (0); }
 
   bool in_error () const { return heap.in_error (); }
 
-  void insert (int64_t priority, unsigned value)
+#ifndef HB_OPTIMIZE_SIZE
+  HB_ALWAYS_INLINE
+#endif
+  void insert (K priority, unsigned value)
   {
     heap.push (item_t (priority, value));
+    if (unlikely (heap.in_error ())) return;
     bubble_up (heap.length - 1);
   }
 
+#ifndef HB_OPTIMIZE_SIZE
+  HB_ALWAYS_INLINE
+#endif
   item_t pop_minimum ()
   {
-    item_t result = heap[0];
+    assert (!is_empty ());
+
+    item_t result = heap.arrayZ[0];
 
-    heap[0] = heap[heap.length - 1];
-    heap.shrink (heap.length - 1);
-    bubble_down (0);
+    heap.arrayZ[0] = heap.arrayZ[heap.length - 1];
+    heap.resize (heap.length - 1);
+
+    if (!is_empty ())
+      bubble_down (0);
 
     return result;
   }
@@ -102,8 +113,12 @@ struct hb_priority_queue_t
     return 2 * index + 2;
   }
 
+  HB_ALWAYS_INLINE
   void bubble_down (unsigned index)
   {
+    repeat:
+    assert (index < heap.length);
+
     unsigned left = left_child (index);
     unsigned right = right_child (index);
 
@@ -113,38 +128,43 @@ struct hb_priority_queue_t
       return;
 
     bool has_right = right < heap.length;
-    if (heap[index].first <= heap[left].first
-        && (!has_right || heap[index].first <= heap[right].first))
+    if (heap.arrayZ[index].first <= heap.arrayZ[left].first
+        && (!has_right || heap.arrayZ[index].first <= heap.arrayZ[right].first))
       return;
 
-    if (!has_right || heap[left].first < heap[right].first)
-    {
-      swap (index, left);
-      bubble_down (left);
-      return;
-    }
+    unsigned child;
+    if (!has_right || heap.arrayZ[left].first < heap.arrayZ[right].first)
+      child = left;
+    else
+      child = right;
 
-    swap (index, right);
-    bubble_down (right);
+    swap (index, child);
+    index = child;
+    goto repeat;
   }
 
+  HB_ALWAYS_INLINE
   void bubble_up (unsigned index)
   {
+    repeat:
+    assert (index < heap.length);
+
     if (index == 0) return;
 
     unsigned parent_index = parent (index);
-    if (heap[parent_index].first <= heap[index].first)
+    if (heap.arrayZ[parent_index].first <= heap.arrayZ[index].first)
       return;
 
     swap (index, parent_index);
-    bubble_up (parent_index);
+    index = parent_index;
+    goto repeat;
   }
 
   void swap (unsigned a, unsigned b)
   {
-    item_t temp = heap[a];
-    heap[a] = heap[b];
-    heap[b] = temp;
+    assert (a < heap.length);
+    assert (b < heap.length);
+    hb_swap (heap.arrayZ[a], heap.arrayZ[b]);
   }
 };
 
index b1726d8..e9cd376 100644 (file)
 
 #include "hb-open-type.hh"
 #include "hb-map.hh"
-#include "hb-priority-queue.hh"
-#include "hb-serialize.hh"
 #include "hb-vector.hh"
+#include "graph/graph.hh"
+#include "graph/gsubgpos-graph.hh"
+#include "graph/serialize.hh"
+
+using graph::graph_t;
 
 /*
  * For a detailed writeup on the overflow resolution algorithm see:
  * docs/repacker.md
  */
 
-struct graph_t
+struct lookup_size_t
 {
-  struct vertex_t
-  {
-    hb_serialize_context_t::object_t obj;
-    int64_t distance = 0 ;
-    int64_t space = 0 ;
-    hb_vector_t<unsigned> parents;
-    unsigned start = 0;
-    unsigned end = 0;
-    unsigned priority = 0;
-
-    bool is_shared () const
-    {
-      return parents.length > 1;
-    }
-
-    unsigned incoming_edges () const
-    {
-      return parents.length;
-    }
-
-    void remove_parent (unsigned parent_index)
-    {
-      for (unsigned i = 0; i < parents.length; i++)
-      {
-        if (parents[i] != parent_index) continue;
-        parents.remove (i);
-        break;
-      }
-    }
-
-    void remap_parents (const hb_vector_t<unsigned>& id_map)
-    {
-      for (unsigned i = 0; i < parents.length; i++)
-        parents[i] = id_map[parents[i]];
-    }
-
-    void remap_parent (unsigned old_index, unsigned new_index)
-    {
-      for (unsigned i = 0; i < parents.length; i++)
-      {
-        if (parents[i] == old_index)
-          parents[i] = new_index;
-      }
-    }
-
-    bool is_leaf () const
-    {
-      return !obj.real_links.length && !obj.virtual_links.length;
-    }
-
-    bool raise_priority ()
-    {
-      if (has_max_priority ()) return false;
-      priority++;
-      return true;
-    }
-
-    bool has_max_priority () const {
-      return priority >= 3;
-    }
-
-    int64_t modified_distance (unsigned order) const
-    {
-      // TODO(garretrieger): once priority is high enough, should try
-      // setting distance = 0 which will force to sort immediately after
-      // it's parent where possible.
-
-      int64_t modified_distance =
-          hb_min (hb_max(distance + distance_modifier (), 0), 0x7FFFFFFFFFF);
-      if (has_max_priority ()) {
-        modified_distance = 0;
-      }
-      return (modified_distance << 18) | (0x003FFFF & order);
-    }
-
-    int64_t distance_modifier () const
-    {
-      if (!priority) return 0;
-      int64_t table_size = obj.tail - obj.head;
-
-      if (priority == 1)
-        return -table_size / 2;
-
-      return -table_size;
-    }
-  };
-
-  struct overflow_record_t
-  {
-    unsigned parent;
-    unsigned child;
-  };
-
-  /*
-   * A topological sorting of an object graph. Ordered
-   * in reverse serialization order (first object in the
-   * serialization is at the end of the list). This matches
-   * the 'packed' object stack used internally in the
-   * serializer
-   */
-  graph_t (const hb_vector_t<hb_serialize_context_t::object_t *>& objects)
-      : parents_invalid (true),
-        distance_invalid (true),
-        positions_invalid (true),
-        successful (true)
-  {
-    num_roots_for_space_.push (1);
-    bool removed_nil = false;
-    for (unsigned i = 0; i < objects.length; i++)
-    {
-      // TODO(grieger): check all links point to valid objects.
-
-      // If this graph came from a serialization buffer object 0 is the
-      // nil object. We don't need it for our purposes here so drop it.
-      if (i == 0 && !objects[i])
-      {
-        removed_nil = true;
-        continue;
-      }
-
-      vertex_t* v = vertices_.push ();
-      if (check_success (!vertices_.in_error ()))
-        v->obj = *objects[i];
-      if (!removed_nil) continue;
-      // Fix indices to account for removed nil object.
-      for (auto& l : v->obj.all_links_writer ()) {
-        l.objidx--;
-      }
-    }
-  }
-
-  ~graph_t ()
-  {
-    vertices_.fini ();
-  }
-
-  bool in_error () const
-  {
-    return !successful ||
-        vertices_.in_error () ||
-        num_roots_for_space_.in_error ();
-  }
-
-  const vertex_t& root () const
-  {
-    return vertices_[root_idx ()];
-  }
-
-  unsigned root_idx () const
-  {
-    // Object graphs are in reverse order, the first object is at the end
-    // of the vector. Since the graph is topologically sorted it's safe to
-    // assume the first object has no incoming edges.
-    return vertices_.length - 1;
-  }
-
-  const hb_serialize_context_t::object_t& object(unsigned i) const
-  {
-    return vertices_[i].obj;
-  }
-
-  /*
-   * serialize graph into the provided serialization buffer.
-   */
-  hb_blob_t* serialize () const
-  {
-    hb_vector_t<char> buffer;
-    size_t size = serialized_length ();
-    if (!buffer.alloc (size)) {
-      DEBUG_MSG (SUBSET_REPACK, nullptr, "Unable to allocate output buffer.");
-      return nullptr;
-    }
-    hb_serialize_context_t c((void *) buffer, size);
-
-    c.start_serialize<void> ();
-    for (unsigned i = 0; i < vertices_.length; i++) {
-      c.push ();
-
-      size_t size = vertices_[i].obj.tail - vertices_[i].obj.head;
-      char* start = c.allocate_size <char> (size);
-      if (!start) {
-        DEBUG_MSG (SUBSET_REPACK, nullptr, "Buffer out of space.");
-        return nullptr;
-      }
-
-      memcpy (start, vertices_[i].obj.head, size);
-
-      // Only real links needs to be serialized.
-      for (const auto& link : vertices_[i].obj.real_links)
-        serialize_link (link, start, &c);
-
-      // All duplications are already encoded in the graph, so don't
-      // enable sharing during packing.
-      c.pop_pack (false);
-    }
-    c.end_serialize ();
-
-    if (c.in_error ()) {
-      DEBUG_MSG (SUBSET_REPACK, nullptr, "Error during serialization. Err flag: %d",
-                 c.errors);
-      return nullptr;
-    }
-
-    return c.copy_blob ();
-  }
-
-  /*
-   * Generates a new topological sorting of graph using Kahn's
-   * algorithm: https://en.wikipedia.org/wiki/Topological_sorting#Algorithms
-   */
-  void sort_kahn ()
-  {
-    positions_invalid = true;
-
-    if (vertices_.length <= 1) {
-      // Graph of 1 or less doesn't need sorting.
-      return;
-    }
-
-    hb_vector_t<unsigned> queue;
-    hb_vector_t<vertex_t> sorted_graph;
-    if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return;
-    hb_vector_t<unsigned> id_map;
-    if (unlikely (!check_success (id_map.resize (vertices_.length)))) return;
-
-    hb_vector_t<unsigned> removed_edges;
-    if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return;
-    update_parents ();
-
-    queue.push (root_idx ());
-    int new_id = vertices_.length - 1;
-
-    while (!queue.in_error () && queue.length)
-    {
-      unsigned next_id = queue[0];
-      queue.remove (0);
-
-      vertex_t& next = vertices_[next_id];
-      sorted_graph[new_id] = next;
-      id_map[next_id] = new_id--;
-
-      for (const auto& link : next.obj.all_links ()) {
-        removed_edges[link.objidx]++;
-        if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx]))
-          queue.push (link.objidx);
-      }
-    }
-
-    check_success (!queue.in_error ());
-    check_success (!sorted_graph.in_error ());
-    if (!check_success (new_id == -1))
-      print_orphaned_nodes ();
-
-    remap_all_obj_indices (id_map, &sorted_graph);
-
-    hb_swap (vertices_, sorted_graph);
-    sorted_graph.fini ();
-  }
-
-  /*
-   * Generates a new topological sorting of graph ordered by the shortest
-   * distance to each node.
-   */
-  void sort_shortest_distance ()
-  {
-    positions_invalid = true;
-
-    if (vertices_.length <= 1) {
-      // Graph of 1 or less doesn't need sorting.
-      return;
-    }
+  unsigned lookup_index;
+  size_t size;
+  unsigned num_subtables;
 
-    update_distances ();
-
-    hb_priority_queue_t queue;
-    hb_vector_t<vertex_t> sorted_graph;
-    if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return;
-    hb_vector_t<unsigned> id_map;
-    if (unlikely (!check_success (id_map.resize (vertices_.length)))) return;
-
-    hb_vector_t<unsigned> removed_edges;
-    if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return;
-    update_parents ();
-
-    queue.insert (root ().modified_distance (0), root_idx ());
-    int new_id = root_idx ();
-    unsigned order = 1;
-    while (!queue.in_error () && !queue.is_empty ())
-    {
-      unsigned next_id = queue.pop_minimum().second;
-
-      vertex_t& next = vertices_[next_id];
-      sorted_graph[new_id] = next;
-      id_map[next_id] = new_id--;
-
-      for (const auto& link : next.obj.all_links ()) {
-        removed_edges[link.objidx]++;
-        if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx]))
-          // Add the order that the links were encountered to the priority.
-          // This ensures that ties between priorities objects are broken in a consistent
-          // way. More specifically this is set up so that if a set of objects have the same
-          // distance they'll be added to the topological order in the order that they are
-          // referenced from the parent object.
-          queue.insert (vertices_[link.objidx].modified_distance (order++),
-                        link.objidx);
-      }
-    }
-
-    check_success (!queue.in_error ());
-    check_success (!sorted_graph.in_error ());
-    if (!check_success (new_id == -1))
-      print_orphaned_nodes ();
-
-    remap_all_obj_indices (id_map, &sorted_graph);
-
-    hb_swap (vertices_, sorted_graph);
-    sorted_graph.fini ();
-  }
-
-  /*
-   * Assign unique space numbers to each connected subgraph of 32 bit offset(s).
-   */
-  bool assign_32bit_spaces ()
+  static int cmp (const void* a, const void* b)
   {
-    unsigned root_index = root_idx ();
-    hb_set_t visited;
-    hb_set_t roots;
-    for (unsigned i = 0; i <= root_index; i++)
-    {
-      // Only real links can form 32 bit spaces
-      for (auto& l : vertices_[i].obj.real_links)
-      {
-        if (l.width == 4 && !l.is_signed)
-        {
-          roots.add (l.objidx);
-          find_subgraph (l.objidx, visited);
-        }
-      }
-    }
-
-    // Mark everything not in the subgraphs of 32 bit roots as visited.
-    // This prevents 32 bit subgraphs from being connected via nodes not in the 32 bit subgraphs.
-    visited.invert ();
-
-    if (!roots) return false;
-
-    while (roots)
-    {
-      unsigned next = HB_SET_VALUE_INVALID;
-      if (unlikely (!check_success (!roots.in_error ()))) break;
-      if (!roots.next (&next)) break;
-
-      hb_set_t connected_roots;
-      find_connected_nodes (next, roots, visited, connected_roots);
-      if (unlikely (!check_success (!connected_roots.in_error ()))) break;
-
-      isolate_subgraph (connected_roots);
-      if (unlikely (!check_success (!connected_roots.in_error ()))) break;
-
-      unsigned next_space = this->next_space ();
-      num_roots_for_space_.push (0);
-      for (unsigned root : connected_roots)
-      {
-        DEBUG_MSG (SUBSET_REPACK, nullptr, "Subgraph %u gets space %u", root, next_space);
-        vertices_[root].space = next_space;
-        num_roots_for_space_[next_space] = num_roots_for_space_[next_space] + 1;
-        distance_invalid = true;
-        positions_invalid = true;
-      }
-
-      // TODO(grieger): special case for GSUB/GPOS use extension promotions to move 16 bit space
-      //                into the 32 bit space as needed, instead of using isolation.
-    }
-
-
-
-    return true;
+    return cmp ((const lookup_size_t*) a,
+                (const lookup_size_t*) b);
   }
 
-  /*
-   * Isolates the subgraph of nodes reachable from root. Any links to nodes in the subgraph
-   * that originate from outside of the subgraph will be removed by duplicating the linked to
-   * object.
-   *
-   * Indices stored in roots will be updated if any of the roots are duplicated to new indices.
-   */
-  bool isolate_subgraph (hb_set_t& roots)
+  static int cmp (const lookup_size_t* a, const lookup_size_t* b)
   {
-    update_parents ();
-    hb_hashmap_t<unsigned, unsigned> subgraph;
-
-    // incoming edges to root_idx should be all 32 bit in length so we don't need to de-dup these
-    // set the subgraph incoming edge count to match all of root_idx's incoming edges
-    hb_set_t parents;
-    for (unsigned root_idx : roots)
-    {
-      subgraph.set (root_idx, wide_parents (root_idx, parents));
-      find_subgraph (root_idx, subgraph);
-    }
-
-    unsigned original_root_idx = root_idx ();
-    hb_hashmap_t<unsigned, unsigned> index_map;
-    bool made_changes = false;
-    for (auto entry : subgraph.iter ())
-    {
-      const auto& node = vertices_[entry.first];
-      unsigned subgraph_incoming_edges = entry.second;
-
-      if (subgraph_incoming_edges < node.incoming_edges ())
-      {
-        // Only  de-dup objects with incoming links from outside the subgraph.
-        made_changes = true;
-        duplicate_subgraph (entry.first, index_map);
-      }
-    }
-
-    if (!made_changes)
-      return false;
-
-    if (original_root_idx != root_idx ()
-        && parents.has (original_root_idx))
-    {
-      // If the root idx has changed since parents was determined, update root idx in parents
-      parents.add (root_idx ());
-      parents.del (original_root_idx);
+    double subtables_per_byte_a = (double) a->num_subtables / (double) a->size;
+    double subtables_per_byte_b = (double) b->num_subtables / (double) b->size;
+    if (subtables_per_byte_a == subtables_per_byte_b) {
+      return b->lookup_index - a->lookup_index;
     }
 
-    auto new_subgraph =
-        + subgraph.keys ()
-        | hb_map([&] (unsigned node_idx) {
-          if (index_map.has (node_idx)) return index_map[node_idx];
-          return node_idx;
-        })
-        ;
-
-    remap_obj_indices (index_map, new_subgraph);
-    remap_obj_indices (index_map, parents.iter (), true);
-
-    // Update roots set with new indices as needed.
-    unsigned next = HB_SET_VALUE_INVALID;
-    while (roots.next (&next))
-    {
-      if (index_map.has (next))
-      {
-        roots.del (next);
-        roots.add (index_map[next]);
-      }
-    }
-
-    return true;
-  }
-
-  void find_subgraph (unsigned node_idx, hb_hashmap_t<unsigned, unsigned>& subgraph)
-  {
-    for (const auto& link : vertices_[node_idx].obj.all_links ())
-    {
-      if (subgraph.has (link.objidx))
-      {
-        subgraph.set (link.objidx, subgraph[link.objidx] + 1);
-        continue;
-      }
-      subgraph.set (link.objidx, 1);
-      find_subgraph (link.objidx, subgraph);
-    }
-  }
-
-  void find_subgraph (unsigned node_idx, hb_set_t& subgraph)
-  {
-    if (subgraph.has (node_idx)) return;
-    subgraph.add (node_idx);
-    for (const auto& link : vertices_[node_idx].obj.all_links ())
-      find_subgraph (link.objidx, subgraph);
-  }
-
-  /*
-   * duplicates all nodes in the subgraph reachable from node_idx. Does not re-assign
-   * links. index_map is updated with mappings from old id to new id. If a duplication has already
-   * been performed for a given index, then it will be skipped.
-   */
-  void duplicate_subgraph (unsigned node_idx, hb_hashmap_t<unsigned, unsigned>& index_map)
-  {
-    if (index_map.has (node_idx))
-      return;
-
-    index_map.set (node_idx, duplicate (node_idx));
-    for (const auto& l : object (node_idx).all_links ()) {
-      duplicate_subgraph (l.objidx, index_map);
-    }
+    double cmp = subtables_per_byte_b - subtables_per_byte_a;
+    if (cmp < 0) return -1;
+    if (cmp > 0) return 1;
+    return 0;
   }
+};
 
-  /*
-   * Creates a copy of node_idx and returns it's new index.
-   */
-  unsigned duplicate (unsigned node_idx)
-  {
-    positions_invalid = true;
-    distance_invalid = true;
-
-    auto* clone = vertices_.push ();
-    auto& child = vertices_[node_idx];
-    if (vertices_.in_error ()) {
-      return -1;
-    }
-
-    clone->obj.head = child.obj.head;
-    clone->obj.tail = child.obj.tail;
-    clone->distance = child.distance;
-    clone->space = child.space;
-    clone->parents.reset ();
-
-    unsigned clone_idx = vertices_.length - 2;
-    for (const auto& l : child.obj.real_links)
-    {
-      clone->obj.real_links.push (l);
-      vertices_[l.objidx].parents.push (clone_idx);
-    }
-    for (const auto& l : child.obj.virtual_links)
-    {
-      clone->obj.virtual_links.push (l);
-      vertices_[l.objidx].parents.push (clone_idx);
-    }
-
-    check_success (!clone->obj.real_links.in_error ());
-    check_success (!clone->obj.virtual_links.in_error ());
-
-    // The last object is the root of the graph, so swap back the root to the end.
-    // The root's obj idx does change, however since it's root nothing else refers to it.
-    // all other obj idx's will be unaffected.
-    vertex_t root = vertices_[vertices_.length - 2];
-    vertices_[clone_idx] = *clone;
-    vertices_[vertices_.length - 1] = root;
-
-    // Since the root moved, update the parents arrays of all children on the root.
-    for (const auto& l : root.obj.all_links ())
-      vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
-
-    return clone_idx;
-  }
-
-  /*
-   * Creates a copy of child and re-assigns the link from
-   * parent to the clone. The copy is a shallow copy, objects
-   * linked from child are not duplicated.
-   */
-  bool duplicate (unsigned parent_idx, unsigned child_idx)
-  {
-    update_parents ();
-
-    unsigned links_to_child = 0;
-    for (const auto& l : vertices_[parent_idx].obj.all_links ())
-    {
-      if (l.objidx == child_idx) links_to_child++;
-    }
-
-    if (vertices_[child_idx].incoming_edges () <= links_to_child)
-    {
-      // Can't duplicate this node, doing so would orphan the original one as all remaining links
-      // to child are from parent.
-      DEBUG_MSG (SUBSET_REPACK, nullptr, "  Not duplicating %d => %d",
-                 parent_idx, child_idx);
+static inline
+bool _presplit_subtables_if_needed (graph::gsubgpos_graph_context_t& ext_context)
+{
+  // For each lookup this will check the size of subtables and split them as needed
+  // so that no subtable is at risk of overflowing. (where we support splitting for
+  // that subtable type).
+  //
+  // TODO(grieger): de-dup newly added nodes as necessary. Probably just want a full de-dup
+  //                pass after this processing is done. Not super necessary as splits are
+  //                only done where overflow is likely, so de-dup probably will get undone
+  //                later anyways.
+
+  // The loop below can modify the contents of ext_context.lookups if new subtables are added
+  // to a lookup during a split. So save the initial set of lookup indices so the iteration doesn't
+  // risk access free'd memory if ext_context.lookups gets resized.
+  hb_set_t lookup_indices(ext_context.lookups.keys ());
+  for (unsigned lookup_index : lookup_indices)
+  {
+    graph::Lookup* lookup = ext_context.lookups.get(lookup_index);
+    if (!lookup->split_subtables_if_needed (ext_context, lookup_index))
       return false;
-    }
-
-    DEBUG_MSG (SUBSET_REPACK, nullptr, "  Duplicating %d => %d",
-               parent_idx, child_idx);
-
-    unsigned clone_idx = duplicate (child_idx);
-    if (clone_idx == (unsigned) -1) return false;
-    // duplicate shifts the root node idx, so if parent_idx was root update it.
-    if (parent_idx == clone_idx) parent_idx++;
-
-    auto& parent = vertices_[parent_idx];
-    for (auto& l : parent.obj.all_links_writer ())
-    {
-      if (l.objidx != child_idx)
-        continue;
-
-      reassign_link (l, parent_idx, clone_idx);
-    }
-
-    return true;
   }
 
-  /*
-   * Raises the sorting priority of all children.
-   */
-  bool raise_childrens_priority (unsigned parent_idx)
-  {
-    DEBUG_MSG (SUBSET_REPACK, nullptr, "  Raising priority of all children of %d",
-               parent_idx);
-    // This operation doesn't change ordering until a sort is run, so no need
-    // to invalidate positions. It does not change graph structure so no need
-    // to update distances or edge counts.
-    auto& parent = vertices_[parent_idx].obj;
-    bool made_change = false;
-    for (auto& l : parent.all_links_writer ())
-      made_change |= vertices_[l.objidx].raise_priority ();
-    return made_change;
-  }
-
-  /*
-   * Will any offsets overflow on graph when it's serialized?
-   */
-  bool will_overflow (hb_vector_t<overflow_record_t>* overflows = nullptr)
-  {
-    if (overflows) overflows->resize (0);
-    update_positions ();
-
-    for (int parent_idx = vertices_.length - 1; parent_idx >= 0; parent_idx--)
-    {
-      // Don't need to check virtual links for overflow
-      for (const auto& link : vertices_[parent_idx].obj.real_links)
-      {
-        int64_t offset = compute_offset (parent_idx, link);
-        if (is_valid_offset (offset, link))
-          continue;
-
-        if (!overflows) return true;
-
-        overflow_record_t r;
-        r.parent = parent_idx;
-        r.child = link.objidx;
-        overflows->push (r);
-      }
-    }
-
-    if (!overflows) return false;
-    return overflows->length;
-  }
-
-  void print_orphaned_nodes ()
-  {
-    if (!DEBUG_ENABLED(SUBSET_REPACK)) return;
-
-    DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected.");
-    parents_invalid = true;
-    update_parents();
-
-    for (unsigned i = 0; i < root_idx (); i++)
-    {
-      const auto& v = vertices_[i];
-      if (!v.parents)
-        DEBUG_MSG (SUBSET_REPACK, nullptr, "Node %u is orphaned.", i);
-    }
-  }
-
-  void print_overflows (const hb_vector_t<overflow_record_t>& overflows)
-  {
-    if (!DEBUG_ENABLED(SUBSET_REPACK)) return;
-
-    update_parents ();
-    int limit = 10;
-    for (const auto& o : overflows)
-    {
-      if (!limit--) break;
-      const auto& parent = vertices_[o.parent];
-      const auto& child = vertices_[o.child];
-      DEBUG_MSG (SUBSET_REPACK, nullptr,
-                 "  overflow from "
-                 "%4d (%4d in, %4d out, space %2d) => "
-                 "%4d (%4d in, %4d out, space %2d)",
-                 o.parent,
-                 parent.incoming_edges (),
-                 parent.obj.real_links.length + parent.obj.virtual_links.length,
-                 space_for (o.parent),
-                 o.child,
-                 child.incoming_edges (),
-                 child.obj.real_links.length + child.obj.virtual_links.length,
-                 space_for (o.child));
-    }
-    if (overflows.length > 10) {
-      DEBUG_MSG (SUBSET_REPACK, nullptr, "  ... plus %d more overflows.", overflows.length - 10);
-    }
-  }
-
-  unsigned num_roots_for_space (unsigned space) const
-  {
-    return num_roots_for_space_[space];
-  }
-
-  unsigned next_space () const
-  {
-    return num_roots_for_space_.length;
-  }
-
-  void move_to_new_space (const hb_set_t& indices)
-  {
-    num_roots_for_space_.push (0);
-    unsigned new_space = num_roots_for_space_.length - 1;
-
-    for (unsigned index : indices) {
-      auto& node = vertices_[index];
-      num_roots_for_space_[node.space] = num_roots_for_space_[node.space] - 1;
-      num_roots_for_space_[new_space] = num_roots_for_space_[new_space] + 1;
-      node.space = new_space;
-      distance_invalid = true;
-      positions_invalid = true;
-    }
-  }
-
-  unsigned space_for (unsigned index, unsigned* root = nullptr) const
-  {
-    const auto& node = vertices_[index];
-    if (node.space)
-    {
-      if (root != nullptr)
-        *root = index;
-      return node.space;
-    }
-
-    if (!node.parents)
-    {
-      if (root)
-        *root = index;
-      return 0;
-    }
-
-    return space_for (node.parents[0], root);
-  }
-
-  void err_other_error () { this->successful = false; }
-
- private:
-
-  size_t serialized_length () const {
-    size_t total_size = 0;
-    for (unsigned i = 0; i < vertices_.length; i++) {
-      size_t size = vertices_[i].obj.tail - vertices_[i].obj.head;
-      total_size += size;
-    }
-    return total_size;
-  }
+  return true;
+}
 
-  /*
-   * Returns the numbers of incoming edges that are 32bits wide.
-   */
-  unsigned wide_parents (unsigned node_idx, hb_set_t& parents) const
-  {
-    unsigned count = 0;
+/*
+ * Analyze the lookups in a GSUB/GPOS table and decide if any should be promoted
+ * to extension lookups.
+ */
+static inline
+bool _promote_extensions_if_needed (graph::gsubgpos_graph_context_t& ext_context)
+{
+  // Simple Algorithm (v1, current):
+  // 1. Calculate how many bytes each non-extension lookup consumes.
+  // 2. Select up to 64k of those to remain as non-extension (greedy, highest subtables per byte first)
+  // 3. Promote the rest.
+  //
+  // Advanced Algorithm (v2, not implemented):
+  // 1. Perform connected component analysis using lookups as roots.
+  // 2. Compute size of each connected component.
+  // 3. Select up to 64k worth of connected components to remain as non-extensions.
+  //    (greedy, highest subtables per byte first)
+  // 4. Promote the rest.
+
+  // TODO(garretrieger): support extension demotion, then consider all lookups. Requires advanced algo.
+  // TODO(garretrieger): also support extension promotion during iterative resolution phase, then
+  //                     we can use a less conservative threshold here.
+  // TODO(grieger): skip this for the 24 bit case.
+  if (!ext_context.lookups) return true;
+
+  unsigned total_lookup_table_sizes = 0;
+  hb_vector_t<lookup_size_t> lookup_sizes;
+  lookup_sizes.alloc (ext_context.lookups.get_population (), true);
+
+  for (unsigned lookup_index : ext_context.lookups.keys ())
+  {
+    const auto& lookup_v = ext_context.graph.vertices_[lookup_index];
+    total_lookup_table_sizes += lookup_v.table_size ();
+
+    const graph::Lookup* lookup = ext_context.lookups.get(lookup_index);
     hb_set_t visited;
-    for (unsigned p : vertices_[node_idx].parents)
-    {
-      if (visited.has (p)) continue;
-      visited.add (p);
-
-      // Only real links can be wide
-      for (const auto& l : vertices_[p].obj.real_links)
-      {
-        if (l.objidx == node_idx && l.width == 4 && !l.is_signed)
-        {
-          count++;
-          parents.add (p);
-        }
-      }
-    }
-    return count;
+    lookup_sizes.push (lookup_size_t {
+        lookup_index,
+        ext_context.graph.find_subgraph_size (lookup_index, visited),
+        lookup->number_of_subtables (),
+      });
   }
 
-  bool check_success (bool success)
-  { return this->successful && (success || (err_other_error (), false)); }
-
-  /*
-   * Creates a map from objid to # of incoming edges.
-   */
-  void update_parents ()
-  {
-    if (!parents_invalid) return;
-
-    for (unsigned i = 0; i < vertices_.length; i++)
-      vertices_[i].parents.reset ();
-
-    for (unsigned p = 0; p < vertices_.length; p++)
-    {
-      for (auto& l : vertices_[p].obj.all_links ())
-      {
-        vertices_[l.objidx].parents.push (p);
-      }
-    }
+  lookup_sizes.qsort ();
 
-    parents_invalid = false;
-  }
+  size_t lookup_list_size = ext_context.graph.vertices_[ext_context.lookup_list_index].table_size ();
+  size_t l2_l3_size = lookup_list_size + total_lookup_table_sizes; // Lookup List + Lookups
+  size_t l3_l4_size = total_lookup_table_sizes; // Lookups + SubTables
+  size_t l4_plus_size = 0; // SubTables + their descendants
 
-  /*
-   * compute the serialized start and end positions for each vertex.
-   */
-  void update_positions ()
+  // Start by assuming all lookups are using extension subtables, this size will be removed later
+  // if it's decided to not make a lookup extension.
+  for (auto p : lookup_sizes)
   {
-    if (!positions_invalid) return;
-
-    unsigned current_pos = 0;
-    for (int i = root_idx (); i >= 0; i--)
-    {
-      auto& v = vertices_[i];
-      v.start = current_pos;
-      current_pos += v.obj.tail - v.obj.head;
-      v.end = current_pos;
-    }
-
-    positions_invalid = false;
+    // TODO(garretrieger): this overestimates the extension subtables size because some extension subtables may be
+    //                     reused. However, we can't correct this until we have connected component analysis in place.
+    unsigned subtables_size = p.num_subtables * 8;
+    l3_l4_size += subtables_size;
+    l4_plus_size += subtables_size;
   }
 
-  /*
-   * Finds the distance to each object in the graph
-   * from the initial node.
-   */
-  void update_distances ()
+  bool layers_full = false;
+  for (auto p : lookup_sizes)
   {
-    if (!distance_invalid) return;
-
-    // Uses Dijkstra's algorithm to find all of the shortest distances.
-    // https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
-    //
-    // Implementation Note:
-    // Since our priority queue doesn't support fast priority decreases
-    // we instead just add new entries into the queue when a priority changes.
-    // Redundant ones are filtered out later on by the visited set.
-    // According to https://www3.cs.stonybrook.edu/~rezaul/papers/TR-07-54.pdf
-    // for practical performance this is faster then using a more advanced queue
-    // (such as a fibonacci queue) with a fast decrease priority.
-    for (unsigned i = 0; i < vertices_.length; i++)
-    {
-      if (i == vertices_.length - 1)
-        vertices_[i].distance = 0;
-      else
-        vertices_[i].distance = hb_int_max (int64_t);
-    }
-
-    hb_priority_queue_t queue;
-    queue.insert (0, vertices_.length - 1);
-
-    hb_vector_t<bool> visited;
-    visited.resize (vertices_.length);
-
-    while (!queue.in_error () && !queue.is_empty ())
-    {
-      unsigned next_idx = queue.pop_minimum ().second;
-      if (visited[next_idx]) continue;
-      const auto& next = vertices_[next_idx];
-      int64_t next_distance = vertices_[next_idx].distance;
-      visited[next_idx] = true;
-
-      for (const auto& link : next.obj.all_links ())
-      {
-        if (visited[link.objidx]) continue;
-
-        const auto& child = vertices_[link.objidx].obj;
-        unsigned link_width = link.width ? link.width : 4; // treat virtual offsets as 32 bits wide
-        int64_t child_weight = (child.tail - child.head) +
-                               ((int64_t) 1 << (link_width * 8)) * (vertices_[link.objidx].space + 1);
-        int64_t child_distance = next_distance + child_weight;
-
-        if (child_distance < vertices_[link.objidx].distance)
-        {
-          vertices_[link.objidx].distance = child_distance;
-          queue.insert (child_distance, link.objidx);
-        }
-      }
-    }
-
-    check_success (!queue.in_error ());
-    if (!check_success (queue.is_empty ()))
-    {
-      print_orphaned_nodes ();
-      return;
-    }
-
-    distance_invalid = false;
-  }
-
-  int64_t compute_offset (
-      unsigned parent_idx,
-      const hb_serialize_context_t::object_t::link_t& link) const
-  {
-    const auto& parent = vertices_[parent_idx];
-    const auto& child = vertices_[link.objidx];
-    int64_t offset = 0;
-    switch ((hb_serialize_context_t::whence_t) link.whence) {
-      case hb_serialize_context_t::whence_t::Head:
-        offset = child.start - parent.start; break;
-      case hb_serialize_context_t::whence_t::Tail:
-        offset = child.start - parent.end; break;
-      case hb_serialize_context_t::whence_t::Absolute:
-        offset = child.start; break;
-    }
-
-    assert (offset >= link.bias);
-    offset -= link.bias;
-    return offset;
-  }
-
-  bool is_valid_offset (int64_t offset,
-                        const hb_serialize_context_t::object_t::link_t& link) const
-  {
-    if (unlikely (!link.width))
-      // Virtual links can't overflow.
-      return link.is_signed || offset >= 0;
-
-    if (link.is_signed)
-    {
-      if (link.width == 4)
-        return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31);
-      else
-        return offset >= -(1 << 15) && offset < (1 << 15);
-    }
-    else
-    {
-      if (link.width == 4)
-        return offset >= 0 && offset < ((int64_t) 1 << 32);
-      else if (link.width == 3)
-        return offset >= 0 && offset < ((int32_t) 1 << 24);
-      else
-        return offset >= 0 && offset < (1 << 16);
-    }
-  }
-
-  /*
-   * Updates a link in the graph to point to a different object. Corrects the
-   * parents vector on the previous and new child nodes.
-   */
-  void reassign_link (hb_serialize_context_t::object_t::link_t& link,
-                      unsigned parent_idx,
-                      unsigned new_idx)
-  {
-    unsigned old_idx = link.objidx;
-    link.objidx = new_idx;
-    vertices_[old_idx].remove_parent (parent_idx);
-    vertices_[new_idx].parents.push (parent_idx);
-  }
+    const graph::Lookup* lookup = ext_context.lookups.get(p.lookup_index);
+    if (lookup->is_extension (ext_context.table_tag))
+      // already an extension so size is counted by the loop above.
+      continue;
 
-  /*
-   * Updates all objidx's in all links using the provided mapping. Corrects incoming edge counts.
-   */
-  template<typename Iterator, hb_requires (hb_is_iterator (Iterator))>
-  void remap_obj_indices (const hb_hashmap_t<unsigned, unsigned>& id_map,
-                          Iterator subgraph,
-                          bool only_wide = false)
-  {
-    if (!id_map) return;
-    for (unsigned i : subgraph)
+    if (!layers_full)
     {
-      for (auto& link : vertices_[i].obj.all_links_writer ())
-      {
-        if (!id_map.has (link.objidx)) continue;
-        if (only_wide && !(link.width == 4 && !link.is_signed)) continue;
-
-        reassign_link (link, i, id_map[link.objidx]);
-      }
-    }
-  }
+      size_t lookup_size = ext_context.graph.vertices_[p.lookup_index].table_size ();
+      hb_set_t visited;
+      size_t subtables_size = ext_context.graph.find_subgraph_size (p.lookup_index, visited, 1) - lookup_size;
+      size_t remaining_size = p.size - subtables_size - lookup_size;
 
-  /*
-   * Updates all objidx's in all links using the provided mapping.
-   */
-  void remap_all_obj_indices (const hb_vector_t<unsigned>& id_map,
-                              hb_vector_t<vertex_t>* sorted_graph) const
-  {
-    for (unsigned i = 0; i < sorted_graph->length; i++)
-    {
-      (*sorted_graph)[i].remap_parents (id_map);
-      for (auto& link : (*sorted_graph)[i].obj.all_links_writer ())
-      {
-        link.objidx = id_map[link.objidx];
-      }
-    }
-  }
+      l3_l4_size   += subtables_size;
+      l3_l4_size   -= p.num_subtables * 8;
+      l4_plus_size += subtables_size + remaining_size;
 
-  template <typename O> void
-  serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link,
-                          char* head,
-                          hb_serialize_context_t* c) const
-  {
-    OT::Offset<O>* offset = reinterpret_cast<OT::Offset<O>*> (head + link.position);
-    *offset = 0;
-    c->add_link (*offset,
-                 // serializer has an extra nil object at the start of the
-                 // object array. So all id's are +1 of what our id's are.
-                 link.objidx + 1,
-                 (hb_serialize_context_t::whence_t) link.whence,
-                 link.bias);
-  }
+      if (l2_l3_size < (1 << 16)
+          && l3_l4_size < (1 << 16)
+          && l4_plus_size < (1 << 16)) continue; // this lookup fits within all layers groups
 
-  void serialize_link (const hb_serialize_context_t::object_t::link_t& link,
-                 char* head,
-                 hb_serialize_context_t* c) const
-  {
-    switch (link.width)
-    {
-    case 0:
-      // Virtual links aren't serialized.
-      return;
-    case 4:
-      if (link.is_signed)
-      {
-        serialize_link_of_type<OT::HBINT32> (link, head, c);
-      } else {
-        serialize_link_of_type<OT::HBUINT32> (link, head, c);
-      }
-      return;
-    case 2:
-      if (link.is_signed)
-      {
-        serialize_link_of_type<OT::HBINT16> (link, head, c);
-      } else {
-        serialize_link_of_type<OT::HBUINT16> (link, head, c);
-      }
-      return;
-    case 3:
-      serialize_link_of_type<OT::HBUINT24> (link, head, c);
-      return;
-    default:
-      // Unexpected link width.
-      assert (0);
-    }
-  }
-
-  /*
-   * Finds all nodes in targets that are reachable from start_idx, nodes in visited will be skipped.
-   * For this search the graph is treated as being undirected.
-   *
-   * Connected targets will be added to connected and removed from targets. All visited nodes
-   * will be added to visited.
-   */
-  void find_connected_nodes (unsigned start_idx,
-                             hb_set_t& targets,
-                             hb_set_t& visited,
-                             hb_set_t& connected)
-  {
-    if (unlikely (!check_success (!visited.in_error ()))) return;
-    if (visited.has (start_idx)) return;
-    visited.add (start_idx);
-
-    if (targets.has (start_idx))
-    {
-      targets.del (start_idx);
-      connected.add (start_idx);
+      layers_full = true;
     }
 
-    const auto& v = vertices_[start_idx];
-
-    // Graph is treated as undirected so search children and parents of start_idx
-    for (const auto& l : v.obj.all_links ())
-      find_connected_nodes (l.objidx, targets, visited, connected);
-
-    for (unsigned p : v.parents)
-      find_connected_nodes (p, targets, visited, connected);
+    if (!ext_context.lookups.get(p.lookup_index)->make_extension (ext_context, p.lookup_index))
+      return false;
   }
 
- public:
-  // TODO(garretrieger): make private, will need to move most of offset overflow code into graph.
-  hb_vector_t<vertex_t> vertices_;
- private:
-  bool parents_invalid;
-  bool distance_invalid;
-  bool positions_invalid;
-  bool successful;
-  hb_vector_t<unsigned> num_roots_for_space_;
-};
+  return true;
+}
 
-static bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record_t>& overflows,
-                                      graph_t& sorted_graph)
+static inline
+bool _try_isolating_subgraphs (const hb_vector_t<graph::overflow_record_t>& overflows,
+                               graph_t& sorted_graph)
 {
   unsigned space = 0;
   hb_set_t roots_to_isolate;
 
   for (int i = overflows.length - 1; i >= 0; i--)
   {
-    const graph_t::overflow_record_t& r = overflows[i];
+    const graph::overflow_record_t& r = overflows[i];
 
     unsigned root;
     unsigned overflow_space = sorted_graph.space_for (r.parent, &root);
@@ -1128,14 +219,14 @@ static bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record
     // Only move at most half of the roots in a space at a time.
     unsigned extra = roots_to_isolate.get_population () - maximum_to_move;
     while (extra--) {
-      unsigned root = HB_SET_VALUE_INVALID;
+      uint32_t root = HB_SET_VALUE_INVALID;
       roots_to_isolate.previous (&root);
       roots_to_isolate.del (root);
     }
   }
 
   DEBUG_MSG (SUBSET_REPACK, nullptr,
-             "Overflow in space %d (%d roots). Moving %d roots to space %d.",
+             "Overflow in space %u (%u roots). Moving %u roots to space %u.",
              space,
              sorted_graph.num_roots_for_space (space),
              roots_to_isolate.get_population (),
@@ -1147,22 +238,23 @@ static bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record
   return true;
 }
 
-static bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& overflows,
-                                hb_set_t& priority_bumped_parents,
-                                graph_t& sorted_graph)
+static inline
+bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows,
+                         hb_set_t& priority_bumped_parents,
+                         graph_t& sorted_graph)
 {
   bool resolution_attempted = false;
 
   // Try resolving the furthest overflows first.
   for (int i = overflows.length - 1; i >= 0; i--)
   {
-    const graph_t::overflow_record_t& r = overflows[i];
+    const graph::overflow_record_t& r = overflows[i];
     const auto& child = sorted_graph.vertices_[r.child];
     if (child.is_shared ())
     {
       // The child object is shared, we may be able to eliminate the overflow
       // by duplicating it.
-      if (!sorted_graph.duplicate (r.parent, r.child)) continue;
+      if (sorted_graph.duplicate (r.parent, r.child) == (unsigned) -1) continue;
       return true;
     }
 
@@ -1194,56 +286,66 @@ static bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& o
   return resolution_attempted;
 }
 
-/*
- * Attempts to modify the topological sorting of the provided object graph to
- * eliminate offset overflows in the links between objects of the graph. If a
- * non-overflowing ordering is found the updated graph is serialized it into the
- * provided serialization context.
- *
- * If necessary the structure of the graph may be modified in ways that do not
- * affect the functionality of the graph. For example shared objects may be
- * duplicated.
- *
- * For a detailed writeup describing how the algorithm operates see:
- * docs/repacker.md
- */
-inline hb_blob_t*
-hb_resolve_overflows (const hb_vector_t<hb_serialize_context_t::object_t *>& packed,
-                      hb_tag_t table_tag,
-                      unsigned max_rounds = 20) {
-  // Kahn sort is ~twice as fast as shortest distance sort and works for many fonts
-  // so try it first to save time.
-  graph_t sorted_graph (packed);
-  sorted_graph.sort_kahn ();
-  if (!sorted_graph.will_overflow ())
+inline bool
+hb_resolve_graph_overflows (hb_tag_t table_tag,
+                            unsigned max_rounds ,
+                            bool recalculate_extensions,
+                            graph_t& sorted_graph /* IN/OUT */)
+{
+  sorted_graph.sort_shortest_distance ();
+  if (sorted_graph.in_error ())
   {
-    return sorted_graph.serialize ();
+    DEBUG_MSG (SUBSET_REPACK, nullptr, "Sorted graph in error state after initial sort.");
+    return false;
   }
 
-  sorted_graph.sort_shortest_distance ();
+  bool will_overflow = graph::will_overflow (sorted_graph);
+  if (!will_overflow)
+    return true;
 
+  graph::gsubgpos_graph_context_t ext_context (table_tag, sorted_graph);
   if ((table_tag == HB_OT_TAG_GPOS
        ||  table_tag == HB_OT_TAG_GSUB)
-      && sorted_graph.will_overflow ())
+      && will_overflow)
   {
+    if (recalculate_extensions)
+    {
+      DEBUG_MSG (SUBSET_REPACK, nullptr, "Splitting subtables if needed.");
+      if (!_presplit_subtables_if_needed (ext_context)) {
+        DEBUG_MSG (SUBSET_REPACK, nullptr, "Subtable splitting failed.");
+        return false;
+      }
+
+      DEBUG_MSG (SUBSET_REPACK, nullptr, "Promoting lookups to extensions if needed.");
+      if (!_promote_extensions_if_needed (ext_context)) {
+        DEBUG_MSG (SUBSET_REPACK, nullptr, "Extensions promotion failed.");
+        return false;
+      }
+    }
+
     DEBUG_MSG (SUBSET_REPACK, nullptr, "Assigning spaces to 32 bit subgraphs.");
-    if (sorted_graph.assign_32bit_spaces ())
+    if (sorted_graph.assign_spaces ())
       sorted_graph.sort_shortest_distance ();
+    else
+      sorted_graph.sort_shortest_distance_if_needed ();
   }
 
   unsigned round = 0;
-  hb_vector_t<graph_t::overflow_record_t> overflows;
+  hb_vector_t<graph::overflow_record_t> overflows;
   // TODO(garretrieger): select a good limit for max rounds.
   while (!sorted_graph.in_error ()
-         && sorted_graph.will_overflow (&overflows)
-         && round++ < max_rounds) {
-    DEBUG_MSG (SUBSET_REPACK, nullptr, "=== Overflow resolution round %d ===", round);
-    sorted_graph.print_overflows (overflows);
+         && graph::will_overflow (sorted_graph, &overflows)
+         && round < max_rounds) {
+    DEBUG_MSG (SUBSET_REPACK, nullptr, "=== Overflow resolution round %u ===", round);
+    print_overflows (sorted_graph, overflows);
 
     hb_set_t priority_bumped_parents;
 
     if (!_try_isolating_subgraphs (overflows, sorted_graph))
     {
+      // Don't count space isolation towards round limit. Only increment
+      // round counter if space isolation made no changes.
+      round++;
       if (!_process_overflows (overflows, priority_bumped_parents, sorted_graph))
       {
         DEBUG_MSG (SUBSET_REPACK, nullptr, "No resolution available :(");
@@ -1257,16 +359,62 @@ hb_resolve_overflows (const hb_vector_t<hb_serialize_context_t::object_t *>& pac
   if (sorted_graph.in_error ())
   {
     DEBUG_MSG (SUBSET_REPACK, nullptr, "Sorted graph in error state.");
-    return nullptr;
+    return false;
   }
 
-  if (sorted_graph.will_overflow ())
+  if (graph::will_overflow (sorted_graph))
   {
     DEBUG_MSG (SUBSET_REPACK, nullptr, "Offset overflow resolution failed.");
+    return false;
+  }
+
+  return true;
+}
+
+/*
+ * Attempts to modify the topological sorting of the provided object graph to
+ * eliminate offset overflows in the links between objects of the graph. If a
+ * non-overflowing ordering is found the updated graph is serialized it into the
+ * provided serialization context.
+ *
+ * If necessary the structure of the graph may be modified in ways that do not
+ * affect the functionality of the graph. For example shared objects may be
+ * duplicated.
+ *
+ * For a detailed writeup describing how the algorithm operates see:
+ * docs/repacker.md
+ */
+template<typename T>
+inline hb_blob_t*
+hb_resolve_overflows (const T& packed,
+                      hb_tag_t table_tag,
+                      unsigned max_rounds = 20,
+                      bool recalculate_extensions = false) {
+  graph_t sorted_graph (packed);
+  if (sorted_graph.in_error ())
+  {
+    // Invalid graph definition.
+    return nullptr;
+  }
+
+  if (!sorted_graph.is_fully_connected ())
+  {
+    sorted_graph.print_orphaned_nodes ();
+    return nullptr;
+  }
+
+  if (sorted_graph.in_error ())
+  {
+    // Allocations failed somewhere
+    DEBUG_MSG (SUBSET_REPACK, nullptr,
+               "Graph is in error, likely due to a memory allocation error.");
     return nullptr;
   }
 
-  return sorted_graph.serialize ();
+  if (!hb_resolve_graph_overflows (table_tag, max_rounds, recalculate_extensions, sorted_graph))
+    return nullptr;
+
+  return graph::serialize (sorted_graph);
 }
 
 #endif /* HB_REPACKER_HH */
index 65c2772..f2b7da1 100644 (file)
@@ -122,12 +122,14 @@ struct hb_sanitize_context_t :
 {
   hb_sanitize_context_t () :
        start (nullptr), end (nullptr),
+       length (0),
        max_ops (0), max_subtables (0),
         recursion_depth (0),
        writable (false), edit_count (0),
        blob (nullptr),
        num_glyphs (65536),
-       num_glyphs_set (false) {}
+       num_glyphs_set (false),
+       lazy_some_gpos (false) {}
 
   const char *get_name () { return "SANITIZE"; }
   template <typename T, typename F>
@@ -155,6 +157,19 @@ struct hb_sanitize_context_t :
   dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN
   ( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )
 
+  hb_sanitize_context_t (hb_blob_t *b) : hb_sanitize_context_t ()
+  {
+    init (b);
+
+    if (blob)
+      start_processing ();
+  }
+
+  ~hb_sanitize_context_t ()
+  {
+    if (blob)
+      end_processing ();
+  }
 
   void init (hb_blob_t *b)
   {
@@ -180,11 +195,15 @@ struct hb_sanitize_context_t :
 
     const char *obj_start = (const char *) obj;
     if (unlikely (obj_start < this->start || this->end <= obj_start))
+    {
       this->start = this->end = nullptr;
+      this->length = 0;
+    }
     else
     {
       this->start = obj_start;
       this->end   = obj_start + hb_min (size_t (this->end - obj_start), obj->get_size ());
+      this->length = this->end - this->start;
     }
   }
 
@@ -192,16 +211,18 @@ struct hb_sanitize_context_t :
   {
     this->start = this->blob->data;
     this->end = this->start + this->blob->length;
+    this->length = this->end - this->start;
     assert (this->start <= this->end); /* Must not overflow. */
   }
 
   void start_processing ()
   {
     reset_object ();
-    if (unlikely (hb_unsigned_mul_overflows (this->end - this->start, HB_SANITIZE_MAX_OPS_FACTOR)))
+    unsigned m;
+    if (unlikely (hb_unsigned_mul_overflows (this->end - this->start, HB_SANITIZE_MAX_OPS_FACTOR, &m)))
       this->max_ops = HB_SANITIZE_MAX_OPS_MAX;
     else
-      this->max_ops = hb_clamp ((unsigned) (this->end - this->start) * HB_SANITIZE_MAX_OPS_FACTOR,
+      this->max_ops = hb_clamp (m,
                                (unsigned) HB_SANITIZE_MAX_OPS_MIN,
                                (unsigned) HB_SANITIZE_MAX_OPS_MAX);
     this->edit_count = 0;
@@ -223,37 +244,90 @@ struct hb_sanitize_context_t :
     hb_blob_destroy (this->blob);
     this->blob = nullptr;
     this->start = this->end = nullptr;
+    this->length = 0;
   }
 
   unsigned get_edit_count () { return edit_count; }
 
+
+  bool check_ops(unsigned count)
+  {
+    /* Avoid underflow */
+    if (unlikely (this->max_ops < 0 || count >= (unsigned) this->max_ops))
+    {
+      this->max_ops = -1;
+      return false;
+    }
+    this->max_ops -= (int) count;
+    return true;
+  }
+
+#ifndef HB_OPTIMIZE_SIZE
+  HB_ALWAYS_INLINE
+#endif
   bool check_range (const void *base,
                    unsigned int len) const
   {
     const char *p = (const char *) base;
-    bool ok = !len ||
-             (this->start <= p &&
-              p <= this->end &&
-              (unsigned int) (this->end - p) >= len &&
-              (this->max_ops -= len) > 0);
+    bool ok = (uintptr_t) (p - this->start) <= this->length &&
+             (unsigned int) (this->end - p) >= len &&
+             ((this->max_ops -= len) > 0);
 
     DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
                     "check_range [%p..%p]"
-                    " (%d bytes) in [%p..%p] -> %s",
+                    " (%u bytes) in [%p..%p] -> %s",
                     p, p + len, len,
                     this->start, this->end,
                     ok ? "OK" : "OUT-OF-RANGE");
 
     return likely (ok);
   }
+#ifndef HB_OPTIMIZE_SIZE
+  HB_ALWAYS_INLINE
+#endif
+  bool check_range_fast (const void *base,
+                        unsigned int len) const
+  {
+    const char *p = (const char *) base;
+    bool ok = ((uintptr_t) (p - this->start) <= this->length &&
+              (unsigned int) (this->end - p) >= len);
+
+    DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
+                    "check_range_fast [%p..%p]"
+                    " (%u bytes) in [%p..%p] -> %s",
+                    p, p + len, len,
+                    this->start, this->end,
+                    ok ? "OK" : "OUT-OF-RANGE");
+
+    return likely (ok);
+  }
+
+#ifndef HB_OPTIMIZE_SIZE
+  HB_ALWAYS_INLINE
+#endif
+  bool check_point (const void *base) const
+  {
+    const char *p = (const char *) base;
+    bool ok = (uintptr_t) (p - this->start) <= this->length;
+
+    DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
+                    "check_point [%p]"
+                    " in [%p..%p] -> %s",
+                    p,
+                    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);
+    unsigned m;
+    return !hb_unsigned_mul_overflows (a, b, &m) &&
+          this->check_range (base, m);
   }
 
   template <typename T>
@@ -262,8 +336,23 @@ struct hb_sanitize_context_t :
                    unsigned int b,
                    unsigned int c) const
   {
-    return !hb_unsigned_mul_overflows (a, b) &&
-          this->check_range (base, a * b, c);
+    unsigned m;
+    return !hb_unsigned_mul_overflows (a, b, &m) &&
+          this->check_range (base, m, c);
+  }
+
+  template <typename T>
+  HB_ALWAYS_INLINE
+  bool check_array_sized (const T *base, unsigned int len, unsigned len_size) const
+  {
+    if (len_size >= 4)
+    {
+      if (unlikely (hb_unsigned_mul_overflows (len, hb_static_size (T), &len)))
+       return false;
+    }
+    else
+      len = len * hb_static_size (T);
+    return this->check_range (base, len);
   }
 
   template <typename T>
@@ -277,7 +366,7 @@ struct hb_sanitize_context_t :
                    unsigned int a,
                    unsigned int b) const
   {
-    return this->check_range (base, a, b, hb_static_size (T));
+    return this->check_range (base, hb_static_size (T), a, b);
   }
 
   bool check_start_recursion (int max_depth)
@@ -293,8 +382,16 @@ struct hb_sanitize_context_t :
   }
 
   template <typename Type>
+#ifndef HB_OPTIMIZE_SIZE
+  HB_ALWAYS_INLINE
+#endif
   bool check_struct (const Type *obj) const
-  { return likely (this->check_range (obj, obj->min_size)); }
+  {
+    if (sizeof (uintptr_t) == sizeof (uint32_t))
+      return likely (this->check_range_fast (obj, obj->min_size));
+    else
+      return likely (this->check_point ((const char *) obj + obj->min_size));
+  }
 
   bool may_edit (const void *base, unsigned int len)
   {
@@ -305,7 +402,7 @@ struct hb_sanitize_context_t :
     this->edit_count++;
 
     DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
-       "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
+       "may_edit(%u) [%p..%p] (%u bytes) in [%p..%p] -> %s",
        this->edit_count,
        p, p + len, len,
        this->start, this->end,
@@ -350,13 +447,13 @@ struct hb_sanitize_context_t :
     {
       if (edit_count)
       {
-       DEBUG_MSG_FUNC (SANITIZE, start, "passed first round with %d edits; going for second round", edit_count);
+       DEBUG_MSG_FUNC (SANITIZE, start, "passed first round with %u 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);
+         DEBUG_MSG_FUNC (SANITIZE, start, "requested %u edits in second round; FAILING", edit_count);
          sane = false;
        }
       }
@@ -401,6 +498,7 @@ struct hb_sanitize_context_t :
   }
 
   const char *start, *end;
+  unsigned length;
   mutable int max_ops, max_subtables;
   private:
   int recursion_depth;
@@ -409,6 +507,8 @@ struct hb_sanitize_context_t :
   hb_blob_t *blob;
   unsigned int num_glyphs;
   bool  num_glyphs_set;
+  public:
+  bool lazy_some_gpos;
 };
 
 struct hb_sanitize_with_object_t
index 6615f03..15eccb6 100644 (file)
@@ -36,6 +36,9 @@
 #include "hb-map.hh"
 #include "hb-pool.hh"
 
+#ifdef HB_EXPERIMENTAL_API
+#include "hb-subset-repacker.h"
+#endif
 
 /*
  * Serialize
@@ -70,6 +73,33 @@ struct hb_serialize_context_t
       virtual_links.fini ();
     }
 
+    object_t () = default;
+
+#ifdef HB_EXPERIMENTAL_API
+    object_t (const hb_object_t &o)
+    {
+      head = o.head;
+      tail = o.tail;
+      next = nullptr;
+      real_links.alloc (o.num_real_links, true);
+      for (unsigned i = 0 ; i < o.num_real_links; i++)
+        real_links.push (o.real_links[i]);
+
+      virtual_links.alloc (o.num_virtual_links, true);
+      for (unsigned i = 0; i < o.num_virtual_links; i++)
+        virtual_links.push (o.virtual_links[i]);
+    }
+#endif
+
+    friend void swap (object_t& a, object_t& b)
+    {
+      hb_swap (a.head, b.head);
+      hb_swap (a.tail, b.tail);
+      hb_swap (a.next, b.next);
+      hb_swap (a.real_links, b.real_links);
+      hb_swap (a.virtual_links, b.virtual_links);
+    }
+
     bool operator == (const object_t &o) const
     {
       // Virtual links aren't considered for equality since they don't affect the functionality
@@ -83,18 +113,40 @@ struct hb_serialize_context_t
     {
       // Virtual links aren't considered for equality since they don't affect the functionality
       // of the object.
-      return hb_bytes_t (head, tail - head).hash () ^
+      return hb_bytes_t (head, hb_min (128, tail - head)).hash () ^
           real_links.as_bytes ().hash ();
     }
 
     struct link_t
     {
       unsigned width: 3;
-      bool is_signed: 1;
+      unsigned is_signed: 1;
       unsigned whence: 2;
-      unsigned position: 28;
-      unsigned bias;
+      unsigned bias : 26;
+      unsigned position;
       objidx_t objidx;
+
+      link_t () = default;
+
+#ifdef HB_EXPERIMENTAL_API
+      link_t (const hb_link_t &o)
+      {
+        width = o.width;
+        is_signed = 0;
+        whence = 0;
+        position = o.position;
+        bias = 0;
+        objidx = o.objidx;
+      }
+#endif
+
+      HB_INTERNAL static int cmp (const void* a, const void* b)
+      {
+        int cmp = ((const link_t*)a)->position - ((const link_t*)b)->position;
+        if (cmp) return cmp;
+
+        return ((const link_t*)a)->objidx - ((const link_t*)b)->objidx;
+      }
     };
 
     char *head;
@@ -120,8 +172,14 @@ struct hb_serialize_context_t
   };
 
   snapshot_t snapshot ()
-  { return snapshot_t {
-      head, tail, current, current->real_links.length, current->virtual_links.length, errors }; }
+  {
+    return snapshot_t {
+      head, tail, current,
+      current ? current->real_links.length : 0,
+      current ? current->virtual_links.length : 0,
+      errors
+     };
+  }
 
   hb_serialize_context_t (void *start_, unsigned int size) :
     start ((char *) start_),
@@ -142,7 +200,6 @@ struct hb_serialize_context_t
       current = current->next;
       _->fini ();
     }
-    object_pool.fini ();
   }
 
   bool in_error () const { return bool (errors); }
@@ -172,6 +229,7 @@ struct hb_serialize_context_t
     this->errors = HB_SERIALIZE_ERROR_NONE;
     this->head = this->start;
     this->tail = this->end;
+    this->zerocopy = nullptr;
     this->debug_depth = 0;
 
     fini ();
@@ -208,7 +266,8 @@ struct hb_serialize_context_t
           propagate_error (std::forward<Ts> (os)...); }
 
   /* To be called around main operation. */
-  template <typename Type>
+  template <typename Type=char>
+  __attribute__((returns_nonnull))
   Type *start_serialize ()
   {
     DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1,
@@ -251,6 +310,7 @@ struct hb_serialize_context_t
   }
 
   template <typename Type = void>
+  __attribute__((returns_nonnull))
   Type *push ()
   {
     if (unlikely (in_error ())) return start_embed<Type> ();
@@ -271,10 +331,13 @@ struct hb_serialize_context_t
   {
     object_t *obj = current;
     if (unlikely (!obj)) return;
-    if (unlikely (in_error())) return;
+    // Allow cleanup when we've error'd out on int overflows which don't compromise
+    // the serializer state.
+    if (unlikely (in_error() && !only_overflow ())) return;
 
     current = current->next;
-    revert (obj->head, obj->tail);
+    revert (zerocopy ? zerocopy : obj->head, obj->tail);
+    zerocopy = nullptr;
     obj->fini ();
     object_pool.release (obj);
   }
@@ -287,13 +350,18 @@ struct hb_serialize_context_t
   {
     object_t *obj = current;
     if (unlikely (!obj)) return 0;
-    if (unlikely (in_error())) return 0;
+    // Allow cleanup when we've error'd out on int overflows which don't compromise
+    // the serializer state.
+    if (unlikely (in_error()  && !only_overflow ())) return 0;
 
     current = current->next;
     obj->tail = head;
     obj->next = nullptr;
+    assert (obj->head <= obj->tail);
     unsigned len = obj->tail - obj->head;
-    head = obj->head; /* Rewind head. */
+    head = zerocopy ? zerocopy : obj->head; /* Rewind head. */
+    bool was_zerocopy = zerocopy;
+    zerocopy = nullptr;
 
     if (!len)
     {
@@ -303,9 +371,11 @@ struct hb_serialize_context_t
     }
 
     objidx_t objidx;
+    uint32_t hash = 0;
     if (share)
     {
-      objidx = packed_map.get (obj);
+      hash = hb_hash (obj);
+      objidx = packed_map.get_with_hash (obj, hash);
       if (objidx)
       {
         merge_virtual_links (obj, objidx);
@@ -315,7 +385,10 @@ struct hb_serialize_context_t
     }
 
     tail -= len;
-    memmove (tail, obj->head, len);
+    if (was_zerocopy)
+      assert (tail == obj->head);
+    else
+      memmove (tail, obj->head, len);
 
     obj->head = tail;
     obj->tail = tail + len;
@@ -333,7 +406,7 @@ struct hb_serialize_context_t
 
     objidx = packed.length - 1;
 
-    if (share) packed_map.set (obj, objidx);
+    if (share) packed_map.set_with_hash (obj, hash, objidx);
     propagate_error (packed_map);
 
     return objidx;
@@ -344,8 +417,11 @@ struct hb_serialize_context_t
     // Overflows that happened after the snapshot will be erased by the revert.
     if (unlikely (in_error () && !only_overflow ())) return;
     assert (snap.current == current);
-    current->real_links.shrink (snap.num_real_links);
-    current->virtual_links.shrink (snap.num_virtual_links);
+    if (current)
+    {
+      current->real_links.shrink (snap.num_real_links);
+      current->virtual_links.shrink (snap.num_virtual_links);
+    }
     errors = snap.errors;
     revert (snap.head, snap.tail);
   }
@@ -502,13 +578,15 @@ struct hb_serialize_context_t
   {
     unsigned int l = length () % alignment;
     if (l)
-      allocate_size<void> (alignment - l);
+      (void) allocate_size<void> (alignment - l);
   }
 
   template <typename Type = void>
+  __attribute__((returns_nonnull))
   Type *start_embed (const Type *obj HB_UNUSED = nullptr) const
   { return reinterpret_cast<Type *> (this->head); }
   template <typename Type>
+  __attribute__((returns_nonnull))
   Type *start_embed (const Type &obj) const
   { return start_embed (std::addressof (obj)); }
 
@@ -517,8 +595,27 @@ struct hb_serialize_context_t
     return !bool ((errors = (errors | err_type)));
   }
 
+  bool start_zerocopy (size_t size)
+  {
+    if (unlikely (in_error ())) return false;
+
+    if (unlikely (size > INT_MAX || this->tail - this->head < ptrdiff_t (size)))
+    {
+      err (HB_SERIALIZE_ERROR_OUT_OF_ROOM);
+      return false;
+    }
+
+    assert (!this->zerocopy);
+    this->zerocopy = this->head;
+
+    assert (this->current->head == this->head);
+    this->current->head = this->current->tail = this->head = this->tail - size;
+    return true;
+  }
+
   template <typename Type>
-  Type *allocate_size (size_t size)
+  HB_NODISCARD
+  Type *allocate_size (size_t size, bool clear = true)
   {
     if (unlikely (in_error ())) return nullptr;
 
@@ -527,7 +624,8 @@ struct hb_serialize_context_t
       err (HB_SERIALIZE_ERROR_OUT_OF_ROOM);
       return nullptr;
     }
-    hb_memset (this->head, 0, size);
+    if (clear)
+      hb_memset (this->head, 0, size);
     char *ret = this->head;
     this->head += size;
     return reinterpret_cast<Type *> (ret);
@@ -538,17 +636,26 @@ struct hb_serialize_context_t
   { return this->allocate_size<Type> (Type::min_size); }
 
   template <typename Type>
+  HB_NODISCARD
   Type *embed (const Type *obj)
   {
     unsigned int size = obj->get_size ();
-    Type *ret = this->allocate_size<Type> (size);
+    Type *ret = this->allocate_size<Type> (size, false);
     if (unlikely (!ret)) return nullptr;
-    memcpy (ret, obj, size);
+    hb_memcpy (ret, obj, size);
     return ret;
   }
   template <typename Type>
+  HB_NODISCARD
   Type *embed (const Type &obj)
   { return embed (std::addressof (obj)); }
+  char *embed (const char *obj, unsigned size)
+  {
+    char *ret = this->allocate_size<char> (size, false);
+    if (unlikely (!ret)) return nullptr;
+    hb_memcpy (ret, obj, size);
+    return ret;
+  }
 
   template <typename Type, typename ...Ts> auto
   _copy (const Type &src, hb_priority<1>, Ts&&... ds) HB_RETURN
@@ -564,7 +671,7 @@ struct hb_serialize_context_t
   }
 
   /* Like embed, but active: calls obj.operator=() or obj.copy() to transfer data
-   * instead of memcpy(). */
+   * instead of hb_memcpy(). */
   template <typename Type, typename ...Ts>
   Type *copy (const Type &src, Ts&&... ds)
   { return _copy (src, hb_prioritize, std::forward<Ts> (ds)...); }
@@ -582,7 +689,7 @@ struct hb_serialize_context_t
   hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; }
 
   template <typename Type>
-  Type *extend_size (Type *obj, size_t size)
+  Type *extend_size (Type *obj, size_t size, bool clear = true)
   {
     if (unlikely (in_error ())) return nullptr;
 
@@ -590,12 +697,12 @@ struct hb_serialize_context_t
     assert ((char *) obj <= this->head);
     assert ((size_t) (this->head - (char *) obj) <= size);
     if (unlikely (((char *) obj + size < (char *) obj) ||
-                 !this->allocate_size<Type> (((char *) obj) + size - this->head))) return nullptr;
+                 !this->allocate_size<Type> (((char *) obj) + size - this->head, clear))) return nullptr;
     return reinterpret_cast<Type *> (obj);
   }
   template <typename Type>
-  Type *extend_size (Type &obj, size_t size)
-  { return extend_size (std::addressof (obj), size); }
+  Type *extend_size (Type &obj, size_t size, bool clear = true)
+  { return extend_size (std::addressof (obj), size, clear); }
 
   template <typename Type>
   Type *extend_min (Type *obj) { return extend_size (obj, obj->min_size); }
@@ -624,8 +731,8 @@ struct hb_serialize_context_t
     char *p = (char *) hb_malloc (len);
     if (unlikely (!p)) return hb_bytes_t ();
 
-    memcpy (p, this->start, this->head - this->start);
-    memcpy (p + (this->head - this->start), this->tail, this->end - this->tail);
+    hb_memcpy (p, this->start, this->head - this->start);
+    hb_memcpy (p + (this->head - this->start), this->tail, this->end - this->tail);
     return hb_bytes_t (p, len);
   }
   template <typename Type>
@@ -651,8 +758,8 @@ struct hb_serialize_context_t
     check_assign (off, offset, HB_SERIALIZE_ERROR_OFFSET_OVERFLOW);
   }
 
-  public: /* TODO Make private. */
-  char *start, *head, *tail, *end;
+  public:
+  char *start, *head, *tail, *end, *zerocopy;
   unsigned int debug_depth;
   hb_serialize_error_t errors;
 
@@ -675,9 +782,7 @@ struct hb_serialize_context_t
   hb_vector_t<object_t *> packed;
 
   /* Map view of packed objects. */
-  hb_hashmap_t<const object_t *, objidx_t,
-              const object_t *, objidx_t,
-              nullptr, 0> packed_map;
+  hb_hashmap_t<const object_t *, objidx_t> packed_map;
 };
 
 #endif /* HB_SERIALIZE_HH */
index 7d4979b..5681641 100644 (file)
 #define HB_SET_DIGEST_HH
 
 #include "hb.hh"
+#include "hb-machinery.hh"
 
 /*
- * The set digests here implement various "filters" that support
+ * The set-digests here implement various "filters" that support
  * "approximate member query".  Conceptually these are like Bloom
  * Filter and Quotient Filter, however, much smaller, faster, and
  * designed to fit the requirements of our uses for glyph coverage
  * set of glyphs, but fully flooded and ineffective if coverage is
  * all over the place.
  *
- * The frozen-set can be used instead of a digest, to trade more
- * memory for 100% accuracy, but in practice, that doesn't look like
- * an attractive trade-off.
+ * The way these are used is that the filter is first populated by
+ * a lookup's or subtable's Coverage table(s), and then when we
+ * want to apply the lookup or subtable to a glyph, before trying
+ * to apply, we ask the filter if the glyph may be covered. If it's
+ * not, we return early.  We can also match a digest against another
+ * digest.
+ *
+ * We use these filters at three levels:
+ *   - If the digest for all the glyphs in the buffer as a whole
+ *     does not match the digest for the lookup, skip the lookup.
+ *   - For each glyph, if it doesn't match the lookup digest,
+ *     skip it.
+ *   - For each glyph, if it doesn't match the subtable digest,
+ *     skip it.
+ *
+ * The main filter we use is a combination of three bits-pattern
+ * filters. A bits-pattern filter checks a number of bits (5 or 6)
+ * of the input number (glyph-id in this case) and checks whether
+ * its pattern is amongst the patterns of any of the accepted values.
+ * The accepted patterns are represented as a "long" integer. The
+ * check is done using four bitwise operations only.
  */
 
 template <typename mask_t, unsigned int shift>
-struct hb_set_digest_lowest_bits_t
+struct hb_set_digest_bits_pattern_t
 {
   static constexpr unsigned mask_bytes = sizeof (mask_t);
   static constexpr unsigned mask_bits = sizeof (mask_t) * 8;
@@ -63,18 +82,25 @@ struct hb_set_digest_lowest_bits_t
 
   void init () { mask = 0; }
 
+  void add (const hb_set_digest_bits_pattern_t &o) { mask |= o.mask; }
+
   void add (hb_codepoint_t g) { mask |= mask_for (g); }
 
   bool add_range (hb_codepoint_t a, hb_codepoint_t b)
   {
+    if (mask == (mask_t) -1) return false;
     if ((b >> shift) - (a >> shift) >= mask_bits - 1)
+    {
       mask = (mask_t) -1;
-    else {
+      return false;
+    }
+    else
+    {
       mask_t ma = mask_for (a);
       mask_t mb = mask_for (b);
       mask |= mb + (mb - ma) - (mb < ma);
+      return true;
     }
-    return true;
   }
 
   template <typename T>
@@ -83,7 +109,7 @@ struct hb_set_digest_lowest_bits_t
     for (unsigned int i = 0; i < count; i++)
     {
       add (*array);
-      array = (const T *) (stride + (const char *) array);
+      array = &StructAtOffsetUnaligned<T> ((const void *) array, stride);
     }
   }
   template <typename T>
@@ -91,18 +117,17 @@ struct hb_set_digest_lowest_bits_t
   template <typename T>
   bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
   {
-    for (unsigned int i = 0; i < count; i++)
-    {
-      add (*array);
-      array = (const T *) (stride + (const char *) array);
-    }
+    add_array (array, count, stride);
     return true;
   }
   template <typename T>
   bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
 
+  bool may_have (const hb_set_digest_bits_pattern_t &o) const
+  { return mask & o.mask; }
+
   bool may_have (hb_codepoint_t g) const
-  { return !!(mask & mask_for (g)); }
+  { return mask & mask_for (g); }
 
   private:
 
@@ -120,6 +145,12 @@ struct hb_set_digest_combiner_t
     tail.init ();
   }
 
+  void add (const hb_set_digest_combiner_t &o)
+  {
+    head.add (o.head);
+    tail.add (o.tail);
+  }
+
   void add (hb_codepoint_t g)
   {
     head.add (g);
@@ -128,9 +159,7 @@ struct hb_set_digest_combiner_t
 
   bool add_range (hb_codepoint_t a, hb_codepoint_t b)
   {
-    head.add_range (a, b);
-    tail.add_range (a, b);
-    return true;
+    return (int) head.add_range (a, b) | (int) tail.add_range (a, b);
   }
   template <typename T>
   void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
@@ -143,13 +172,17 @@ struct hb_set_digest_combiner_t
   template <typename 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;
+    return head.add_sorted_array (array, count, stride) &&
+          tail.add_sorted_array (array, count, stride);
   }
   template <typename T>
   bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
 
+  bool may_have (const hb_set_digest_combiner_t &o) const
+  {
+    return head.may_have (o.head) && tail.may_have (o.tail);
+  }
+
   bool may_have (hb_codepoint_t g) const
   {
     return head.may_have (g) && tail.may_have (g);
@@ -171,11 +204,11 @@ struct hb_set_digest_combiner_t
 using hb_set_digest_t =
   hb_set_digest_combiner_t
   <
-    hb_set_digest_lowest_bits_t<unsigned long, 4>,
+    hb_set_digest_bits_pattern_t<unsigned long, 4>,
     hb_set_digest_combiner_t
     <
-      hb_set_digest_lowest_bits_t<unsigned long, 0>,
-      hb_set_digest_lowest_bits_t<unsigned long, 9>
+      hb_set_digest_bits_pattern_t<unsigned long, 0>,
+      hb_set_digest_bits_pattern_t<unsigned long, 9>
     >
   >
 ;
index 204dbb5..a9386c5 100644 (file)
@@ -40,7 +40,7 @@
 
 
 /**
- * hb_set_create: (Xconstructor)
+ * hb_set_create:
  *
  * Creates a new, initially empty set.
  *
@@ -56,8 +56,6 @@ hb_set_create ()
   if (!(set = hb_object_create<hb_set_t> ()))
     return hb_set_get_empty ();
 
-  set->init_shallow ();
-
   return set;
 }
 
@@ -107,8 +105,6 @@ hb_set_destroy (hb_set_t *set)
 {
   if (!hb_object_destroy (set)) return;
 
-  set->fini_shallow ();
-
   hb_free (set);
 }
 
@@ -122,7 +118,7 @@ hb_set_destroy (hb_set_t *set)
  *
  * Attaches a user-data key/data pair to the specified set.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -149,7 +145,7 @@ hb_set_set_user_data (hb_set_t           *set,
  * Since: 0.9.2
  **/
 void *
-hb_set_get_user_data (hb_set_t           *set,
+hb_set_get_user_data (const hb_set_t     *set,
                      hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (set, key);
@@ -162,7 +158,7 @@ hb_set_get_user_data (hb_set_t           *set,
  *
  * Tests whether memory allocation for a set was successful.
  *
- * Return value: %true if allocation succeeded, %false otherwise
+ * Return value: `true` if allocation succeeded, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -178,7 +174,7 @@ hb_set_allocation_successful (const hb_set_t  *set)
  *
  * Allocate a copy of @set.
  *
- * Return value: Newly-allocated set.
+ * Return value: (transfer full): Newly-allocated set.
  *
  * Since: 2.8.2
  **/
@@ -186,6 +182,9 @@ hb_set_t *
 hb_set_copy (const hb_set_t *set)
 {
   hb_set_t *copy = hb_set_create ();
+  if (unlikely (copy->in_error ()))
+    return hb_set_get_empty ();
+
   copy->set (*set);
   return copy;
 }
@@ -201,7 +200,7 @@ hb_set_copy (const hb_set_t *set)
 void
 hb_set_clear (hb_set_t *set)
 {
-  /* Immutible-safe. */
+  /* Immutable-safe. */
   set->clear ();
 }
 
@@ -211,7 +210,7 @@ hb_set_clear (hb_set_t *set)
  *
  * Tests whether a set is empty (contains no elements).
  *
- * Return value: %true if @set is empty
+ * Return value: `true` if @set is empty
  *
  * Since: 0.9.7
  **/
@@ -228,7 +227,7 @@ hb_set_is_empty (const hb_set_t *set)
  *
  * Tests whether @codepoint belongs to @set.
  *
- * Return value: %true if @codepoint is in @set, %false otherwise
+ * Return value: `true` if @codepoint is in @set, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -252,11 +251,34 @@ void
 hb_set_add (hb_set_t       *set,
            hb_codepoint_t  codepoint)
 {
-  /* Immutible-safe. */
+  /* Immutable-safe. */
   set->add (codepoint);
 }
 
 /**
+ * hb_set_add_sorted_array:
+ * @set: A set
+ * @sorted_codepoints: (array length=num_codepoints): Array of codepoints to add
+ * @num_codepoints: Length of @sorted_codepoints
+ *
+ * Adds @num_codepoints codepoints to a set at once.
+ * The codepoints array must be in increasing order,
+ * with size at least @num_codepoints.
+ *
+ * Since: 4.1.0
+ */
+HB_EXTERN void
+hb_set_add_sorted_array (hb_set_t             *set,
+                        const hb_codepoint_t *sorted_codepoints,
+                        unsigned int          num_codepoints)
+{
+  /* Immutable-safe. */
+  set->add_sorted_array (sorted_codepoints,
+                        num_codepoints,
+                        sizeof(hb_codepoint_t));
+}
+
+/**
  * hb_set_add_range:
  * @set: A set
  * @first: The first element to add to @set
@@ -272,7 +294,7 @@ hb_set_add_range (hb_set_t       *set,
                  hb_codepoint_t  first,
                  hb_codepoint_t  last)
 {
-  /* Immutible-safe. */
+  /* Immutable-safe. */
   set->add_range (first, last);
 }
 
@@ -289,7 +311,7 @@ void
 hb_set_del (hb_set_t       *set,
            hb_codepoint_t  codepoint)
 {
-  /* Immutible-safe. */
+  /* Immutable-safe. */
   set->del (codepoint);
 }
 
@@ -312,7 +334,7 @@ hb_set_del_range (hb_set_t       *set,
                  hb_codepoint_t  first,
                  hb_codepoint_t  last)
 {
-  /* Immutible-safe. */
+  /* Immutable-safe. */
   set->del_range (first, last);
 }
 
@@ -324,7 +346,7 @@ hb_set_del_range (hb_set_t       *set,
  * Tests whether @set and @other are equal (contain the same
  * elements).
  *
- * Return value: %true if the two sets are equal, %false otherwise.
+ * Return value: `true` if the two sets are equal, `false` otherwise.
  *
  * Since: 0.9.7
  **/
@@ -336,13 +358,30 @@ hb_set_is_equal (const hb_set_t *set,
 }
 
 /**
+ * hb_set_hash:
+ * @set: A set
+ *
+ * Creates a hash representing @set.
+ *
+ * Return value:
+ * A hash of @set.
+ *
+ * Since: 4.4.0
+ **/
+HB_EXTERN unsigned int
+hb_set_hash (const hb_set_t *set)
+{
+  return set->hash ();
+}
+
+/**
  * hb_set_is_subset:
  * @set: A set
  * @larger_set: Another set
  *
  * Tests whether @set is a subset of @larger_set.
  *
- * Return value: %true if the @set is a subset of (or equal to) @larger_set, %false otherwise.
+ * Return value: `true` if the @set is a subset of (or equal to) @larger_set, `false` otherwise.
  *
  * Since: 1.8.1
  **/
@@ -366,7 +405,7 @@ void
 hb_set_set (hb_set_t       *set,
            const hb_set_t *other)
 {
-  /* Immutible-safe. */
+  /* Immutable-safe. */
   set->set (*other);
 }
 
@@ -383,7 +422,7 @@ void
 hb_set_union (hb_set_t       *set,
              const hb_set_t *other)
 {
-  /* Immutible-safe. */
+  /* Immutable-safe. */
   set->union_ (*other);
 }
 
@@ -400,7 +439,7 @@ void
 hb_set_intersect (hb_set_t       *set,
                  const hb_set_t *other)
 {
-  /* Immutible-safe. */
+  /* Immutable-safe. */
   set->intersect (*other);
 }
 
@@ -417,7 +456,7 @@ void
 hb_set_subtract (hb_set_t       *set,
                 const hb_set_t *other)
 {
-  /* Immutible-safe. */
+  /* Immutable-safe. */
   set->subtract (*other);
 }
 
@@ -435,7 +474,7 @@ void
 hb_set_symmetric_difference (hb_set_t       *set,
                             const hb_set_t *other)
 {
-  /* Immutible-safe. */
+  /* Immutable-safe. */
   set->symmetric_difference (*other);
 }
 
@@ -450,11 +489,27 @@ hb_set_symmetric_difference (hb_set_t       *set,
 void
 hb_set_invert (hb_set_t *set)
 {
-  /* Immutible-safe. */
+  /* Immutable-safe. */
   set->invert ();
 }
 
 /**
+ * hb_set_is_inverted:
+ * @set: A set
+ *
+ * Returns whether the set is inverted.
+ *
+ * Return value: `true` if the set is inverted, `false` otherwise
+ *
+ * Since: 7.0.0
+ **/
+hb_bool_t
+hb_set_is_inverted (const hb_set_t *set)
+{
+  return set->is_inverted ();
+}
+
+/**
  * hb_set_get_population:
  * @set: A set
  *
@@ -512,7 +567,7 @@ hb_set_get_max (const hb_set_t *set)
  *
  * Set @codepoint to #HB_SET_VALUE_INVALID to get started.
  *
- * Return value: %true if there was a next value, %false otherwise
+ * Return value: `true` if there was a next value, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -533,7 +588,7 @@ hb_set_next (const hb_set_t *set,
  *
  * Set @codepoint to #HB_SET_VALUE_INVALID to get started.
  *
- * Return value: %true if there was a previous value, %false otherwise
+ * Return value: `true` if there was a previous value, `false` otherwise
  *
  * Since: 1.8.0
  **/
@@ -556,7 +611,7 @@ hb_set_previous (const hb_set_t *set,
  *
  * Set @last to #HB_SET_VALUE_INVALID to get started.
  *
- * Return value: %true if there was a next range, %false otherwise
+ * Return value: `true` if there was a next range, `false` otherwise
  *
  * Since: 0.9.7
  **/
@@ -580,7 +635,7 @@ hb_set_next_range (const hb_set_t *set,
  *
  * Set @first to #HB_SET_VALUE_INVALID to get started.
  *
- * Return value: %true if there was a previous range, %false otherwise
+ * Return value: `true` if there was a previous range, `false` otherwise
  *
  * Since: 1.8.0
  **/
@@ -591,3 +646,28 @@ hb_set_previous_range (const hb_set_t *set,
 {
   return set->previous_range (first, last);
 }
+
+/**
+ * hb_set_next_many:
+ * @set: A set
+ * @codepoint: Outputting codepoints starting after this one.
+ *             Use #HB_SET_VALUE_INVALID to get started.
+ * @out: (array length=size): An array of codepoints to write to.
+ * @size: The maximum number of codepoints to write out.
+ *
+ * Finds the next element in @set that is greater than @codepoint. Writes out
+ * codepoints to @out, until either the set runs out of elements, or @size
+ * codepoints are written, whichever comes first.
+ *
+ * Return value: the number of values written.
+ *
+ * Since: 4.2.0
+ **/
+unsigned int
+hb_set_next_many (const hb_set_t *set,
+                 hb_codepoint_t  codepoint,
+                 hb_codepoint_t *out,
+                 unsigned int    size)
+{
+  return set->next_many (codepoint, out, size);
+}
index 423225b..192abf6 100644 (file)
@@ -43,7 +43,7 @@ HB_BEGIN_DECLS
  *
  * Since: 0.9.21
  */
-#define HB_SET_VALUE_INVALID ((hb_codepoint_t) -1)
+#define HB_SET_VALUE_INVALID HB_CODEPOINT_INVALID
 
 /**
  * hb_set_t:
@@ -77,7 +77,7 @@ hb_set_set_user_data (hb_set_t           *set,
                      hb_bool_t           replace);
 
 HB_EXTERN void *
-hb_set_get_user_data (hb_set_t           *set,
+hb_set_get_user_data (const hb_set_t     *set,
                      hb_user_data_key_t *key);
 
 
@@ -98,6 +98,9 @@ HB_EXTERN void
 hb_set_invert (hb_set_t *set);
 
 HB_EXTERN hb_bool_t
+hb_set_is_inverted (const hb_set_t *set);
+
+HB_EXTERN hb_bool_t
 hb_set_has (const hb_set_t *set,
            hb_codepoint_t  codepoint);
 
@@ -111,6 +114,11 @@ hb_set_add_range (hb_set_t       *set,
                  hb_codepoint_t  last);
 
 HB_EXTERN void
+hb_set_add_sorted_array (hb_set_t             *set,
+                        const hb_codepoint_t *sorted_codepoints,
+                        unsigned int          num_codepoints);
+
+HB_EXTERN void
 hb_set_del (hb_set_t       *set,
            hb_codepoint_t  codepoint);
 
@@ -123,6 +131,9 @@ HB_EXTERN hb_bool_t
 hb_set_is_equal (const hb_set_t *set,
                 const hb_set_t *other);
 
+HB_EXTERN unsigned int
+hb_set_hash (const hb_set_t *set);
+
 HB_EXTERN hb_bool_t
 hb_set_is_subset (const hb_set_t *set,
                  const hb_set_t *larger_set);
@@ -180,6 +191,12 @@ hb_set_previous_range (const hb_set_t *set,
                       hb_codepoint_t *first,
                       hb_codepoint_t *last);
 
+/* Pass HB_SET_VALUE_INVALID in to get started. */
+HB_EXTERN unsigned int
+hb_set_next_many (const hb_set_t *set,
+                 hb_codepoint_t  codepoint,
+                 hb_codepoint_t *out,
+                 unsigned int    size);
 
 HB_END_DECLS
 
index af02e9e..7d1c941 100644 (file)
@@ -43,8 +43,8 @@ struct hb_sparseset_t
 
   hb_sparseset_t (const hb_sparseset_t& other) : hb_sparseset_t () { set (other); }
   hb_sparseset_t (hb_sparseset_t&& other) : hb_sparseset_t () { s = std::move (other.s); }
-  hb_sparseset_t& operator= (const hb_sparseset_t& other) { set (other); return *this; }
-  hb_sparseset_t& operator= (hb_sparseset_t&& other) { hb_swap (*this, other); return *this; }
+  hb_sparseset_t& operator = (const hb_sparseset_t& other) { set (other); return *this; }
+  hb_sparseset_t& operator = (hb_sparseset_t&& other) { s = std::move (other.s); return *this; }
   friend void swap (hb_sparseset_t& a, hb_sparseset_t& b) { hb_swap (a.s, b.s); }
 
   hb_sparseset_t (std::initializer_list<hb_codepoint_t> lst) : hb_sparseset_t ()
@@ -53,23 +53,21 @@ struct hb_sparseset_t
       add (item);
   }
   template <typename Iterable,
-           hb_requires (hb_is_iterable (Iterable))>
+           hb_requires (hb_is_iterable (Iterable))>
   hb_sparseset_t (const Iterable &o) : hb_sparseset_t ()
   {
     hb_copy (o, *this);
   }
 
-  void init_shallow () { s.init (); }
   void init ()
   {
     hb_object_init (this);
-    init_shallow ();
+    s.init ();
   }
-  void fini_shallow () { s.fini (); }
   void fini ()
   {
     hb_object_fini (this);
-    fini_shallow ();
+    s.fini ();
   }
 
   explicit operator bool () const { return !is_empty (); }
@@ -77,10 +75,13 @@ struct hb_sparseset_t
   void err () { s.err (); }
   bool in_error () const { return s.in_error (); }
 
+  void alloc (unsigned sz) { s.alloc (sz); }
   void reset () { s.reset (); }
   void clear () { s.clear (); }
   void invert () { s.invert (); }
+  bool is_inverted () const { return s.is_inverted (); }
   bool is_empty () const { return s.is_empty (); }
+  uint32_t hash () const { return s.hash (); }
 
   void add (hb_codepoint_t g) { s.add (g); }
   bool add_range (hb_codepoint_t a, hb_codepoint_t b) { return s.add_range (a, b); }
@@ -105,17 +106,16 @@ struct hb_sparseset_t
   bool get (hb_codepoint_t g) const { return s.get (g); }
 
   /* Has interface. */
-  static constexpr bool SENTINEL = false;
-  typedef bool value_t;
-  value_t operator [] (hb_codepoint_t k) const { return get (k); }
-  bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+  bool operator [] (hb_codepoint_t k) const { return get (k); }
+  bool has (hb_codepoint_t k) const { return (*this)[k]; }
+
   /* Predicate. */
   bool operator () (hb_codepoint_t k) const { return has (k); }
 
   /* Sink interface. */
   hb_sparseset_t& operator << (hb_codepoint_t v)
   { add (v); return *this; }
-  hb_sparseset_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
+  hb_sparseset_t& operator << (const hb_codepoint_pair_t& range)
   { add_range (range.first, range.second); return *this; }
 
   bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
@@ -124,6 +124,8 @@ struct hb_sparseset_t
   void set (const hb_sparseset_t &other) { s.set (other.s); }
 
   bool is_equal (const hb_sparseset_t &other) const { return s.is_equal (other.s); }
+  bool operator == (const hb_set_t &other) const { return is_equal (other); }
+  bool operator != (const hb_set_t &other) const { return !is_equal (other); }
 
   bool is_subset (const hb_sparseset_t &larger_set) const { return s.is_subset (larger_set.s); }
 
@@ -138,6 +140,8 @@ struct hb_sparseset_t
   { return s.next_range (first, last); }
   bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
   { return s.previous_range (first, last); }
+  unsigned int next_many (hb_codepoint_t codepoint, hb_codepoint_t *out, unsigned int size) const
+  { return s.next_many (codepoint, out, size); }
 
   unsigned int get_population () const { return s.get_population (); }
   hb_codepoint_t get_min () const { return s.get_min (); }
@@ -155,15 +159,23 @@ struct hb_sparseset_t
 
 struct hb_set_t : hb_sparseset_t<hb_bit_set_invertible_t>
 {
-  hb_set_t () = default;
+  using sparseset = hb_sparseset_t<hb_bit_set_invertible_t>;
+
   ~hb_set_t () = default;
-  hb_set_t (hb_set_t&) = default;
-  hb_set_t& operator= (const hb_set_t&) = default;
-  hb_set_t& operator= (hb_set_t&&) = default;
-  hb_set_t (std::initializer_list<hb_codepoint_t> lst) : hb_sparseset_t<hb_bit_set_invertible_t> (lst) {}
+  hb_set_t () : sparseset () {};
+  hb_set_t (const hb_set_t &o) : sparseset ((sparseset &) o) {};
+  hb_set_t (hb_set_t&& o) : sparseset (std::move ((sparseset &) o)) {}
+  hb_set_t& operator = (const hb_set_t&) = default;
+  hb_set_t& operator = (hb_set_t&&) = default;
+  hb_set_t (std::initializer_list<hb_codepoint_t> lst) : sparseset (lst) {}
   template <typename Iterable,
            hb_requires (hb_is_iterable (Iterable))>
-  hb_set_t (const Iterable &o) : hb_sparseset_t<hb_bit_set_invertible_t> (o) {}
+  hb_set_t (const Iterable &o) : sparseset (o) {}
+
+  hb_set_t& operator << (hb_codepoint_t v)
+  { sparseset::operator<< (v); return *this; }
+  hb_set_t& operator << (const hb_codepoint_pair_t& range)
+  { sparseset::operator<< (range); return *this; }
 };
 
 static_assert (hb_set_t::INVALID == HB_SET_VALUE_INVALID, "");
index 6633216..312eeb6 100644 (file)
@@ -31,6 +31,8 @@
 #include "hb-buffer.hh"
 
 
+#ifndef HB_NO_SHAPER
+
 /**
  * SECTION:hb-shape-plan
  * @title: hb-shape-plan
@@ -74,7 +76,7 @@ hb_shape_plan_key_t::init (bool                           copy,
   this->user_features = copy ? features : user_features;
   if (copy && num_user_features)
   {
-    memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
+    hb_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++)
     {
@@ -117,7 +119,7 @@ hb_shape_plan_key_t::init (bool                           copy,
   }
   else
   {
-    const hb_shaper_entry_t *shapers = _hb_shapers_get ();
+    const HB_UNUSED hb_shaper_entry_t *shapers = _hb_shapers_get ();
     for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
       if (false)
        ;
@@ -170,7 +172,7 @@ hb_shape_plan_key_t::equal (const hb_shape_plan_key_t *other)
 
 
 /**
- * hb_shape_plan_create: (Xconstructor)
+ * hb_shape_plan_create:
  * @face: #hb_face_t to use
  * @props: The #hb_segment_properties_t of the segment
  * @user_features: (array length=num_user_features): The list of user-selected features
@@ -198,7 +200,7 @@ hb_shape_plan_create (hb_face_t                     *face,
 }
 
 /**
- * hb_shape_plan_create2: (Xconstructor)
+ * hb_shape_plan_create2:
  * @face: #hb_face_t to use
  * @props: The #hb_segment_properties_t of the segment
  * @user_features: (array length=num_user_features): The list of user-selected features
@@ -225,13 +227,14 @@ hb_shape_plan_create2 (hb_face_t                     *face,
                       const char * const            *shaper_list)
 {
   DEBUG_MSG_FUNC (SHAPE_PLAN, nullptr,
-                 "face=%p num_features=%d num_coords=%d shaper_list=%p",
+                 "face=%p num_features=%u num_coords=%u shaper_list=%p",
                  face,
                  num_user_features,
                  num_coords,
                  shaper_list);
 
-  assert (props->direction != HB_DIRECTION_INVALID);
+  if (unlikely (props->direction == HB_DIRECTION_INVALID))
+    return hb_shape_plan_get_empty ();
 
   hb_shape_plan_t *shape_plan;
 
@@ -317,10 +320,6 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
 {
   if (!hb_object_destroy (shape_plan)) return;
 
-#ifndef HB_NO_OT_SHAPE
-  shape_plan->ot.fini ();
-#endif
-  shape_plan->key.fini ();
   hb_free (shape_plan);
 }
 
@@ -334,7 +333,7 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
  *
  * Attaches a user-data key/data pair to the given shaping plan. 
  *
- * Return value: %true if success, %false otherwise.
+ * Return value: `true` if success, `false` otherwise.
  *
  * Since: 0.9.7
  **/
@@ -361,8 +360,8 @@ hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,
  * Since: 0.9.7
  **/
 void *
-hb_shape_plan_get_user_data (hb_shape_plan_t    *shape_plan,
-                            hb_user_data_key_t *key)
+hb_shape_plan_get_user_data (const hb_shape_plan_t *shape_plan,
+                            hb_user_data_key_t    *key)
 {
   return hb_object_get_user_data (shape_plan, key);
 }
@@ -392,7 +391,7 @@ _hb_shape_plan_execute_internal (hb_shape_plan_t    *shape_plan,
                                 unsigned int        num_features)
 {
   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
-                 "num_features=%d shaper_func=%p, shaper_name=%s",
+                 "num_features=%u shaper_func=%p, shaper_name=%s",
                  num_features,
                  shape_plan->key.shaper_func,
                  shape_plan->key.shaper_name);
@@ -439,7 +438,7 @@ _hb_shape_plan_execute_internal (hb_shape_plan_t    *shape_plan,
  * Executes the given shaping plan on the specified buffer, using
  * the given @font and @features.
  *
- * Return value: %true if success, %false otherwise.
+ * Return value: `true` if success, `false` otherwise.
  *
  * Since: 0.9.7
  **/
@@ -521,7 +520,7 @@ hb_shape_plan_create_cached2 (hb_face_t                     *face,
                              const char * const            *shaper_list)
 {
   DEBUG_MSG_FUNC (SHAPE_PLAN, nullptr,
-                 "face=%p num_features=%d shaper_list=%p",
+                 "face=%p num_features=%u shaper_list=%p",
                  face,
                  num_user_features,
                  shaper_list);
@@ -577,3 +576,6 @@ retry:
 
   return hb_shape_plan_reference (shape_plan);
 }
+
+
+#endif
index fc7c041..aaf5cf9 100644 (file)
@@ -102,8 +102,8 @@ hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,
                             hb_bool_t           replace);
 
 HB_EXTERN void *
-hb_shape_plan_get_user_data (hb_shape_plan_t    *shape_plan,
-                            hb_user_data_key_t *key);
+hb_shape_plan_get_user_data (const hb_shape_plan_t *shape_plan,
+                            hb_user_data_key_t    *key);
 
 
 HB_EXTERN hb_bool_t
index 8cb4ddb..6fc7393 100644 (file)
@@ -55,7 +55,7 @@ struct hb_shape_plan_key_t
                         unsigned int                   num_coords,
                         const char * const            *shaper_list);
 
-  HB_INTERNAL void fini () { hb_free ((void *) user_features); }
+  HB_INTERNAL void fini () { hb_free ((void *) user_features); user_features = nullptr; }
 
   HB_INTERNAL bool user_features_match (const hb_shape_plan_key_t *other);
 
@@ -64,6 +64,7 @@ struct hb_shape_plan_key_t
 
 struct hb_shape_plan_t
 {
+  ~hb_shape_plan_t () { key.fini (); }
   hb_object_header_t header;
   hb_face_t *face_unsafe; /* We don't carry a reference to face. */
   hb_shape_plan_key_t key;
index 3407e1a..844f7b9 100644 (file)
@@ -35,6 +35,8 @@
 #include "hb-machinery.hh"
 
 
+#ifndef HB_NO_SHAPER
+
 /**
  * SECTION:hb-shape
  * @title: hb-shape
@@ -50,7 +52,7 @@
 
 static inline void free_static_shaper_list ();
 
-static const char *nil_shaper_list[] = {nullptr};
+static const char * const nil_shaper_list[] = {nullptr};
 
 static struct hb_shaper_list_lazy_loader_t : hb_lazy_loader_t<const char *,
                                                              hb_shaper_list_lazy_loader_t>
@@ -73,7 +75,7 @@ static struct hb_shaper_list_lazy_loader_t : hb_lazy_loader_t<const char *,
   }
   static void destroy (const char **l)
   { hb_free (l); }
-  static const char ** get_null ()
+  static const char * const * get_null ()
   { return nil_shaper_list; }
 } static_shaper_list;
 
@@ -106,12 +108,12 @@ hb_shape_list_shapers ()
  * @font: an #hb_font_t to use for shaping
  * @buffer: an #hb_buffer_t to shape
  * @features: (array length=num_features) (nullable): an array of user
- *    specified #hb_feature_t or %NULL
+ *    specified #hb_feature_t or `NULL`
  * @num_features: the length of @features array
- * @shaper_list: (array zero-terminated=1) (nullable): a %NULL-terminated
- *    array of shapers to use or %NULL
+ * @shaper_list: (array zero-terminated=1) (nullable): a `NULL`-terminated
+ *    array of shapers to use or `NULL`
  *
- * See hb_shape() for details. If @shaper_list is not %NULL, the specified
+ * See hb_shape() for details. If @shaper_list is not `NULL`, the specified
  * shapers will be used in the given order, otherwise the default shapers list
  * will be used.
  *
@@ -126,6 +128,11 @@ hb_shape_full (hb_font_t          *font,
               unsigned int        num_features,
               const char * const *shaper_list)
 {
+  if (unlikely (!buffer->len))
+    return true;
+
+  buffer->enter ();
+
   hb_buffer_t *text_buffer = nullptr;
   if (buffer->flags & HB_BUFFER_FLAG_VERIFY)
   {
@@ -137,12 +144,19 @@ hb_shape_full (hb_font_t          *font,
                                                              features, num_features,
                                                              font->coords, font->num_coords,
                                                              shaper_list);
+
   hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
+
+  if (buffer->max_ops <= 0)
+    buffer->shaping_failed = true;
+
   hb_shape_plan_destroy (shape_plan);
 
   if (text_buffer)
   {
-    if (res && !buffer->verify (text_buffer,
+    if (res && buffer->successful && !buffer->shaping_failed
+           && text_buffer->successful
+           && !buffer->verify (text_buffer,
                                font,
                                features,
                                num_features,
@@ -151,6 +165,8 @@ hb_shape_full (hb_font_t          *font,
     hb_buffer_destroy (text_buffer);
   }
 
+  buffer->leave ();
+
   return res;
 }
 
@@ -159,11 +175,11 @@ hb_shape_full (hb_font_t          *font,
  * @font: an #hb_font_t to use for shaping
  * @buffer: an #hb_buffer_t to shape
  * @features: (array length=num_features) (nullable): an array of user
- *    specified #hb_feature_t or %NULL
+ *    specified #hb_feature_t or `NULL`
  * @num_features: the length of @features array
  *
  * Shapes @buffer using @font turning its Unicode characters content to
- * positioned glyphs. If @features is not %NULL, it will be used to control the
+ * positioned glyphs. If @features is not `NULL`, it will be used to control the
  * features applied during shaping. If two @features have the same tag but
  * overlapping ranges the value of the feature with the higher index takes
  * precedence.
@@ -178,3 +194,252 @@ hb_shape (hb_font_t           *font,
 {
   hb_shape_full (font, buffer, features, num_features, nullptr);
 }
+
+
+#ifdef HB_EXPERIMENTAL_API
+
+static float
+buffer_advance (hb_buffer_t *buffer)
+{
+  float a = 0;
+  auto *pos = buffer->pos;
+  unsigned count = buffer->len;
+  if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
+    for (unsigned i = 0; i < count; i++)
+      a += pos[i].x_advance;
+  else
+    for (unsigned i = 0; i < count; i++)
+      a += pos[i].y_advance;
+  return a;
+}
+
+static void
+reset_buffer (hb_buffer_t *buffer,
+             hb_array_t<const hb_glyph_info_t> text)
+{
+  assert (buffer->ensure (text.length));
+  buffer->have_positions = false;
+  buffer->len = text.length;
+  hb_memcpy (buffer->info, text.arrayZ, text.length * sizeof (buffer->info[0]));
+  hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
+}
+
+/**
+ * hb_shape_justify:
+ * @font: a mutable #hb_font_t to use for shaping
+ * @buffer: an #hb_buffer_t to shape
+ * @features: (array length=num_features) (nullable): an array of user
+ *    specified #hb_feature_t or `NULL`
+ * @num_features: the length of @features array
+ * @shaper_list: (array zero-terminated=1) (nullable): a `NULL`-terminated
+ *    array of shapers to use or `NULL`
+ * @min_target_advance: Minimum advance width/height to aim for.
+ * @max_target_advance: Maximum advance width/height to aim for.
+ * @advance: (inout): Input/output advance width/height of the buffer.
+ * @var_tag: (out): Variation-axis tag used for justification.
+ * @var_value: (out): Variation-axis value used to reach target justification.
+ *
+ * See hb_shape_full() for basic details. If @shaper_list is not `NULL`, the specified
+ * shapers will be used in the given order, otherwise the default shapers list
+ * will be used.
+ *
+ * In addition, justify the shaping results such that the shaping results reach
+ * the target advance width/height, depending on the buffer direction.
+ *
+ * If the advance of the buffer shaped with hb_shape_full() is already known,
+ * put that in *advance. Otherwise set *advance to zero.
+ *
+ * This API is currently experimental and will probably change in the future.
+ *
+ * Return value: false if all shapers failed, true otherwise
+ *
+ * XSince: EXPERIMENTAL
+ **/
+hb_bool_t
+hb_shape_justify (hb_font_t          *font,
+                 hb_buffer_t        *buffer,
+                 const hb_feature_t *features,
+                 unsigned int        num_features,
+                 const char * const *shaper_list,
+                 float               min_target_advance,
+                 float               max_target_advance,
+                 float              *advance, /* IN/OUT */
+                 hb_tag_t           *var_tag, /* OUT */
+                 float              *var_value /* OUT */)
+{
+  // TODO Negative font scales?
+
+  /* If default advance already matches target, nothing to do. Shape and return. */
+  if (min_target_advance <= *advance && *advance <= max_target_advance)
+  {
+    *var_tag = HB_TAG_NONE;
+    *var_value = 0.0f;
+    return hb_shape_full (font, buffer,
+                         features, num_features,
+                         shaper_list);
+  }
+
+  hb_face_t *face = font->face;
+
+  /* Choose variation tag to use for justification. */
+
+  hb_tag_t tag = HB_TAG_NONE;
+  hb_ot_var_axis_info_t axis_info;
+
+  hb_tag_t tags[] =
+  {
+    HB_TAG ('j','s','t','f'),
+    HB_TAG ('w','d','t','h'),
+  };
+  for (unsigned i = 0; i < ARRAY_LENGTH (tags); i++)
+    if (hb_ot_var_find_axis_info (face, tags[i], &axis_info))
+    {
+      tag = *var_tag = tags[i];
+      break;
+    }
+
+  /* If no suitable variation axis found, can't justify.  Just shape and return. */
+  if (!tag)
+  {
+    *var_tag = HB_TAG_NONE;
+    *var_value = 0.0f;
+    if (hb_shape_full (font, buffer,
+                      features, num_features,
+                      shaper_list))
+    {
+      *advance = buffer_advance (buffer);
+      return true;
+    }
+    else
+      return false;
+  }
+
+  /* Copy buffer text as we need it so we can shape multiple times. */
+  unsigned text_len = buffer->len;
+  auto *text_info = (hb_glyph_info_t *) hb_malloc (text_len * sizeof (buffer->info[0]));
+  if (unlikely (text_len && !text_info))
+    return false;
+  hb_memcpy (text_info, buffer->info, text_len * sizeof (buffer->info[0]));
+  auto text = hb_array<const hb_glyph_info_t> (text_info, text_len);
+
+  /* If default advance was not provided to us, calculate it. */
+  if (!*advance)
+  {
+    hb_font_set_variation (font, tag, axis_info.default_value);
+    if (!hb_shape_full (font, buffer,
+                       features, num_features,
+                       shaper_list))
+      return false;
+    *advance = buffer_advance (buffer);
+  }
+
+  /* If default advance already matches target, nothing to do. Shape and return.
+   * Do this again, in case advance was just calculated.
+   */
+  if (min_target_advance <= *advance && *advance <= max_target_advance)
+  {
+    *var_tag = HB_TAG_NONE;
+    *var_value = 0.0f;
+    return true;
+  }
+
+  /* Prepare for running the solver. */
+  double a, b, ya, yb;
+  if (*advance < min_target_advance)
+  {
+    /* Need to expand. */
+    ya = (double) *advance;
+    a = (double) axis_info.default_value;
+    b = (double) axis_info.max_value;
+
+    /* Shape buffer for maximum expansion to use as other
+     * starting point for the solver. */
+    hb_font_set_variation (font, tag, (float) b);
+    reset_buffer (buffer, text);
+    if (!hb_shape_full (font, buffer,
+                       features, num_features,
+                       shaper_list))
+      return false;
+    yb = (double) buffer_advance (buffer);
+    /* If the maximum expansion is less than max target,
+     * there's nothing to solve for. Just return it. */
+    if (yb <= (double) max_target_advance)
+    {
+      *var_value = (float) b;
+      *advance = (float) yb;
+      return true;
+    }
+  }
+  else
+  {
+    /* Need to shrink. */
+    yb = (double) *advance;
+    a = (double) axis_info.min_value;
+    b = (double) axis_info.default_value;
+
+    /* Shape buffer for maximum shrinkate to use as other
+     * starting point for the solver. */
+    hb_font_set_variation (font, tag, (float) a);
+    reset_buffer (buffer, text);
+    if (!hb_shape_full (font, buffer,
+                       features, num_features,
+                       shaper_list))
+      return false;
+    ya = (double) buffer_advance (buffer);
+    /* If the maximum shrinkate is more than min target,
+     * there's nothing to solve for. Just return it. */
+    if (ya >= (double) min_target_advance)
+    {
+      *var_value = (float) a;
+      *advance = (float) ya;
+      return true;
+    }
+  }
+
+  /* Run the solver to find a var axis value that hits
+   * the desired width. */
+
+  double epsilon = (b - a) / (1<<14);
+  bool failed = false;
+
+  auto f = [&] (double x)
+  {
+    hb_font_set_variation (font, tag, (float) x);
+    reset_buffer (buffer, text);
+    if (unlikely (!hb_shape_full (font, buffer,
+                                 features, num_features,
+                                 shaper_list)))
+    {
+      failed = true;
+      return (double) min_target_advance;
+    }
+
+    double w = (double) buffer_advance (buffer);
+    DEBUG_MSG (JUSTIFY, nullptr, "Trying '%c%c%c%c' axis parameter %f. Advance %g. Target: min %g max %g",
+              HB_UNTAG (tag), x, w,
+              (double) min_target_advance, (double) max_target_advance);
+    return w;
+  };
+
+  double y = 0;
+  double itp = solve_itp (f,
+                         a, b,
+                         epsilon,
+                         (double) min_target_advance, (double) max_target_advance,
+                         ya, yb, y);
+
+  hb_free (text_info);
+
+  if (failed)
+    return false;
+
+  *var_value = (float) itp;
+  *advance = (float) y;
+
+  return true;
+}
+
+#endif
+
+
+#endif
index 922f8c0..d4d4fdf 100644 (file)
@@ -53,6 +53,18 @@ hb_shape_full (hb_font_t          *font,
               unsigned int        num_features,
               const char * const *shaper_list);
 
+HB_EXTERN hb_bool_t
+hb_shape_justify (hb_font_t          *font,
+                 hb_buffer_t        *buffer,
+                 const hb_feature_t *features,
+                 unsigned int        num_features,
+                 const char * const *shaper_list,
+                 float               min_target_advance,
+                 float               max_target_advance,
+                 float              *advance, /* IN/OUT */
+                 hb_tag_t           *var_tag, /* OUT */
+                 float              *var_value /* OUT */);
+
 HB_EXTERN const char **
 hb_shape_list_shapers (void);
 
index 0d63933..f079caf 100644 (file)
 
 /* v--- Add new shapers in the right place here. */
 
+#ifdef HAVE_WASM
+/* Only picks up fonts that have a "Wasm" table. */
+HB_SHAPER_IMPLEMENT (wasm)
+#endif
+
 #ifdef HAVE_GRAPHITE2
 /* Only picks up fonts that have a "Silf" table. */
 HB_SHAPER_IMPLEMENT (graphite2)
 #endif
 
 #ifndef HB_NO_OT_SHAPE
-HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */
+HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main shaper. */
 #endif
 
 #ifdef HAVE_UNISCRIBE
index a11ed83..c4885cd 100644 (file)
 #include "hb-machinery.hh"
 
 
-static const hb_shaper_entry_t all_shapers[] = {
+static const hb_shaper_entry_t _hb_all_shapers[] = {
 #define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape},
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
 };
 #ifndef HB_NO_SHAPER
-static_assert (0 != ARRAY_LENGTH_CONST (all_shapers), "No shaper enabled.");
+static_assert (0 != ARRAY_LENGTH_CONST (_hb_all_shapers), "No shaper enabled.");
 #endif
 
 static inline void free_static_shapers ();
 
-static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_entry_t,
+static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<hb_shaper_entry_t,
                                                          hb_shapers_lazy_loader_t>
 {
   static hb_shaper_entry_t *create ()
@@ -49,11 +49,11 @@ static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_entry_
     if (!env || !*env)
       return nullptr;
 
-    hb_shaper_entry_t *shapers = (hb_shaper_entry_t *) hb_calloc (1, sizeof (all_shapers));
+    hb_shaper_entry_t *shapers = (hb_shaper_entry_t *) hb_calloc (1, sizeof (_hb_all_shapers));
     if (unlikely (!shapers))
       return nullptr;
 
-    memcpy (shapers, all_shapers, sizeof (all_shapers));
+    hb_memcpy (shapers, _hb_all_shapers, sizeof (_hb_all_shapers));
 
      /* Reorder shaper list to prefer requested shapers. */
     unsigned int i = 0;
@@ -64,7 +64,7 @@ static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_entry_
       if (!end)
        end = p + strlen (p);
 
-      for (unsigned int j = i; j < ARRAY_LENGTH (all_shapers); j++)
+      for (unsigned int j = i; j < ARRAY_LENGTH_CONST (_hb_all_shapers); j++)
        if (end - p == (int) strlen (shapers[j].name) &&
            0 == strncmp (shapers[j].name, p, end - p))
        {
@@ -85,8 +85,8 @@ static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_entry_
 
     return shapers;
   }
-  static void destroy (const hb_shaper_entry_t *p) { hb_free ((void *) p); }
-  static const hb_shaper_entry_t *get_null ()      { return all_shapers; }
+  static void destroy (hb_shaper_entry_t *p) { hb_free (p); }
+  static const hb_shaper_entry_t *get_null ()      { return _hb_all_shapers; }
 } static_shapers;
 
 static inline
index ec4b241..c9bd0a6 100644 (file)
 
 #include "hb-aat-layout-common.hh"
 #include "hb-aat-layout-feat-table.hh"
+#include "hb-cff-interp-common.hh"
 #include "hb-ot-layout-common.hh"
 #include "hb-ot-cmap-table.hh"
+#include "OT/Color/COLR/COLR.hh"
+#include "hb-ot-glyf-table.hh"
 #include "hb-ot-head-table.hh"
+#include "hb-ot-hmtx-table.hh"
 #include "hb-ot-maxp-table.hh"
 
 #ifndef HB_NO_VISIBILITY
@@ -45,27 +49,58 @@ uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof
 DEFINE_NULL_NAMESPACE_BYTES (OT, Index) =  {0xFF,0xFF};
 DEFINE_NULL_NAMESPACE_BYTES (OT, VarIdx) =  {0xFF,0xFF,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, RangeRecord) = {0x01};
+DEFINE_NULL_NAMESPACE_BYTES (OT, ClipRecord) = {0x01};
 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};
+DEFINE_NULL_NAMESPACE_BYTES (AAT, Lookup) = {0xFF,0xFF};
 
 
+/* hb_map_t */
+
+const hb_codepoint_t minus_1 = -1;
+static const unsigned char static_endchar_str[] = {OpCode_endchar};
+const unsigned char *endchar_str = static_endchar_str;
 
 /* hb_face_t */
 
+#ifndef HB_NO_BEYOND_64K
+static inline unsigned
+load_num_glyphs_from_loca (const hb_face_t *face)
+{
+  unsigned ret = 0;
+
+  unsigned indexToLocFormat = face->table.head->indexToLocFormat;
+
+  if (indexToLocFormat <= 1)
+  {
+    bool short_offset = 0 == indexToLocFormat;
+    hb_blob_t *loca_blob = face->table.loca.get_blob ();
+    ret = hb_max (1u, loca_blob->length / (short_offset ? 2 : 4)) - 1;
+  }
+
+  return ret;
+}
+#endif
+
+static inline unsigned
+load_num_glyphs_from_maxp (const hb_face_t *face)
+{
+  return face->table.maxp->get_num_glyphs ();
+}
+
 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);
+  unsigned ret = 0;
+
+#ifndef HB_NO_BEYOND_64K
+  ret = hb_max (ret, load_num_glyphs_from_loca (this));
+#endif
+
+  ret = hb_max (ret, load_num_glyphs_from_maxp (this));
+
+  num_glyphs = ret;
   return ret;
 }
 
@@ -73,40 +108,30 @@ unsigned int
 hb_face_t::load_upem () const
 {
   unsigned int ret = table.head->get_upem ();
-  upem.set_relaxed (ret);
+  upem = ret;
   return ret;
 }
 
 
-/* hb_user_data_array_t */
-
+#ifndef HB_NO_VAR
 bool
-hb_user_data_array_t::set (hb_user_data_key_t *key,
-                          void *              data,
-                          hb_destroy_func_t   destroy,
-                          hb_bool_t           replace)
+_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical,
+                                            int *lsb)
 {
-  if (!key)
-    return false;
-
-  if (replace) {
-    if (!data && !destroy) {
-      items.remove (key, lock);
-      return true;
-    }
-  }
-  hb_user_data_item_t item = {key, data, destroy};
-  bool ret = !!items.replace_or_insert (item, lock, (bool) replace);
-
-  return ret;
+  return font->face->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb);
 }
 
-void *
-hb_user_data_array_t::get (hb_user_data_key_t *key)
+unsigned
+_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
 {
-  hb_user_data_item_t item = {nullptr, nullptr, nullptr};
+  return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical);
+}
+#endif
 
-  return items.find (key, &item, lock) ? item.data : nullptr;
+bool
+_glyf_get_leading_bearing_without_var_unscaled (hb_face_t *face, hb_codepoint_t gid, bool is_vertical, int *lsb)
+{
+  return face->table.glyf->get_leading_bearing_without_var_unscaled (gid, is_vertical, lsb);
 }
 
 
index c0c5c48..bd5cb5c 100644 (file)
 static inline float
 _hb_angle_to_ratio (float a)
 {
-  return tanf (a * float (M_PI / 180.));
+  return tanf (a * -HB_PI / 180.f);
 }
 
 static inline float
 _hb_ratio_to_angle (float r)
 {
-  return atanf (r) * float (180. / M_PI);
+  return atanf (r) * -180.f / HB_PI;
 }
 
 /**
@@ -72,8 +72,7 @@ float
 hb_style_get_value (hb_font_t *font, hb_style_tag_t style_tag)
 {
   if (unlikely (style_tag == HB_STYLE_TAG_SLANT_RATIO))
-    return _hb_angle_to_ratio (hb_style_get_value (font, HB_STYLE_TAG_SLANT_ANGLE))
-        + font->slant;
+    return _hb_angle_to_ratio (hb_style_get_value (font, HB_STYLE_TAG_SLANT_ANGLE));
 
   hb_face_t *face = font->face;
 
index 30a6f2b..d17d2da 100644 (file)
@@ -43,8 +43,10 @@ HB_BEGIN_DECLS
  * @HB_STYLE_TAG_SLANT_ANGLE: Used to vary between upright and slanted text. Values
  * must be greater than -90 and less than +90. Values can be interpreted as
  * the angle, in counter-clockwise degrees, of oblique slant from whatever the
- * designer considers to be upright for that font design.
+ * designer considers to be upright for that font design. Typical right-leaning
+ * Italic fonts have a negative slant angle (typically around -12)
  * @HB_STYLE_TAG_SLANT_RATIO: same as @HB_STYLE_TAG_SLANT_ANGLE expression as ratio.
+ * Typical right-leaning Italic fonts have a positive slant ratio (typically around 0.2)
  * @HB_STYLE_TAG_WIDTH: Used to vary width of text from narrower to wider.
  * Non-zero. Values can be interpreted as a percentage of whatever the font
  * designer considers “normal width” for that font design.
diff --git a/src/hb-subset-accelerator.hh b/src/hb-subset-accelerator.hh
new file mode 100644 (file)
index 0000000..9258383
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright © 2022  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
+ */
+
+#ifndef HB_SUBSET_ACCELERATOR_HH
+#define HB_SUBSET_ACCELERATOR_HH
+
+
+#include "hb.hh"
+
+#include "hb-map.hh"
+#include "hb-multimap.hh"
+#include "hb-set.hh"
+
+extern HB_INTERNAL hb_user_data_key_t _hb_subset_accelerator_user_data_key;
+
+namespace CFF {
+struct cff_subset_accelerator_t;
+}
+
+namespace OT {
+struct SubtableUnicodesCache;
+struct cff1_subset_accelerator_t;
+struct cff2_subset_accelerator_t;
+}
+
+struct hb_subset_accelerator_t
+{
+  static hb_user_data_key_t* user_data_key()
+  {
+    return &_hb_subset_accelerator_user_data_key;
+  }
+
+  static hb_subset_accelerator_t* create(hb_face_t *source,
+                                        const hb_map_t& unicode_to_gid_,
+                                        const hb_set_t& unicodes_,
+                                        bool has_seac_) {
+    hb_subset_accelerator_t* accel =
+        (hb_subset_accelerator_t*) hb_calloc (1, sizeof(hb_subset_accelerator_t));
+
+    if (unlikely (!accel)) return accel;
+
+    new (accel) hb_subset_accelerator_t (source,
+                                        unicode_to_gid_,
+                                        unicodes_,
+                                        has_seac_);
+
+    return accel;
+  }
+
+  static void destroy (void* p)
+  {
+    if (!p) return;
+
+    hb_subset_accelerator_t *accel = (hb_subset_accelerator_t *) p;
+
+    accel->~hb_subset_accelerator_t ();
+
+    hb_free (accel);
+  }
+
+  hb_subset_accelerator_t (hb_face_t *source,
+                          const hb_map_t& unicode_to_gid_,
+                          const hb_set_t& unicodes_,
+                          bool has_seac_) :
+    unicode_to_gid(unicode_to_gid_),
+    unicodes(unicodes_),
+    cmap_cache(nullptr),
+    destroy_cmap_cache(nullptr),
+    has_seac(has_seac_),
+    source(hb_face_reference (source))
+  {
+    gid_to_unicodes.alloc (unicode_to_gid.get_population ());
+    for (const auto &_ : unicode_to_gid)
+    {
+      auto unicode = _.first;
+      auto gid = _.second;
+      gid_to_unicodes.add (gid, unicode);
+    }
+  }
+
+  HB_INTERNAL ~hb_subset_accelerator_t ();
+
+  // Generic
+
+  mutable hb_mutex_t sanitized_table_cache_lock;
+  mutable hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_blob_t>> sanitized_table_cache;
+
+  hb_map_t unicode_to_gid;
+  hb_multimap_t gid_to_unicodes;
+  hb_set_t unicodes;
+
+  // cmap
+  const OT::SubtableUnicodesCache* cmap_cache;
+  hb_destroy_func_t destroy_cmap_cache;
+
+  // CFF
+  bool has_seac;
+
+  // TODO(garretrieger): cumulative glyf checksum map
+
+  bool in_error () const
+  {
+    return unicode_to_gid.in_error () ||
+          gid_to_unicodes.in_error () ||
+          unicodes.in_error () ||
+          sanitized_table_cache.in_error ();
+  }
+
+  hb_face_t *source;
+#ifndef HB_NO_SUBSET_CFF
+  // These have to be immediately after source:
+  mutable hb_face_lazy_loader_t<OT::cff1_subset_accelerator_t, 1> cff1_accel;
+  mutable hb_face_lazy_loader_t<OT::cff2_subset_accelerator_t, 2> cff2_accel;
+#endif
+};
+
+
+#endif /* HB_SUBSET_ACCELERATOR_HH */
index 711b223..5e4ea5f 100644 (file)
@@ -66,36 +66,45 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
 
   {
     /* use hb_set to determine the subset of font dicts */
-    hb_set_t *set = hb_set_create ();
-    if (unlikely (set == &Null (hb_set_t))) return false;
+    hb_set_t set;
     hb_codepoint_t prev_fd = CFF_UNDEF_CODE;
-    for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++)
+    hb_pair_t<unsigned, hb_codepoint_t> last_range {0, 0};
+    auto it = hb_iter (plan->new_to_old_gid_list);
+    auto _ = *it;
+    for (hb_codepoint_t gid = 0; gid < subset_num_glyphs; gid++)
     {
-      hb_codepoint_t glyph;
-      hb_codepoint_t fd;
-      if (!plan->old_gid_for_new_gid (i, &glyph))
+      hb_codepoint_t old_glyph;
+      if (gid == _.first)
+      {
+       old_glyph = _.second;
+       _ = *++it;
+      }
+      else
       {
        /* fonttools retains FDSelect & font dicts for missing glyphs. do the same */
-       glyph = i;
+       old_glyph = gid;
       }
-      fd = src.get_fd (glyph);
-      set->add (fd);
+      if (old_glyph >= last_range.second)
+       last_range = src.get_fd_range (old_glyph);
+      unsigned fd = last_range.first;
 
       if (fd != prev_fd)
       {
+       set.add (fd);
        num_ranges++;
        prev_fd = fd;
-       code_pair_t pair = { fd, i };
-       fdselect_ranges.push (pair);
+       fdselect_ranges.push (code_pair_t { fd, gid });
+
+       if (gid == old_glyph)
+         gid = hb_min (_.first - 1, last_range.second - 1);
       }
     }
 
-    subset_fd_count = set->get_population ();
+    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
     {
@@ -103,9 +112,8 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
       fdmap.reset ();
 
       hb_codepoint_t fd = CFF_UNDEF_CODE;
-      while (set->next (&fd))
+      while (set.next (&fd))
        fdmap.add (fd);
-      hb_set_destroy (set);
       if (unlikely (fdmap.get_population () != subset_fd_count))
        return false;
     }
index 1865770..462e99c 100644 (file)
@@ -38,14 +38,16 @@ namespace CFF {
 struct str_encoder_t
 {
   str_encoder_t (str_buff_t &buff_)
-    : buff (buff_), error (false) {}
+    : buff (buff_) {}
 
-  void reset () { buff.resize (0); }
+  void reset () { buff.reset (); }
 
   void encode_byte (unsigned char b)
   {
-    if (unlikely (buff.push (b) == &Crap (unsigned char)))
-      set_error ();
+    if (likely ((signed) buff.length < buff.allocated))
+      buff.arrayZ[buff.length++] = b;
+    else
+      buff.push (b);
   }
 
   void encode_int (int v)
@@ -79,7 +81,8 @@ struct str_encoder_t
     }
   }
 
-  void encode_num (const number_t& n)
+  // Encode number for CharString
+  void encode_num_cs (const number_t& n)
   {
     if (n.in_int_range ())
     {
@@ -96,6 +99,91 @@ struct str_encoder_t
     }
   }
 
+  // Encode number for TopDict / Private
+  void encode_num_tp (const number_t& n)
+  {
+    if (n.in_int_range ())
+    {
+      // TODO longint
+      encode_int (n.to_int ());
+    }
+    else
+    {
+      // Sigh. BCD
+      // https://learn.microsoft.com/en-us/typography/opentype/spec/cff2#table-5-nibble-definitions
+      double v = n.to_real ();
+      encode_byte (OpCode_BCD);
+
+      // Based on:
+      // https://github.com/fonttools/fonttools/blob/97ed3a61cde03e17b8be36f866192fbd56f1d1a7/Lib/fontTools/misc/psCharStrings.py#L265-L294
+
+      char buf[16];
+      /* FontTools has the following comment:
+       *
+       * # Note: 14 decimal digits seems to be the limitation for CFF real numbers
+       * # in macOS. However, we use 8 here to match the implementation of AFDKO.
+       *
+       * We use 8 here to match FontTools X-).
+       */
+
+      hb_locale_t clocale HB_UNUSED;
+      hb_locale_t oldlocale HB_UNUSED;
+      oldlocale = hb_uselocale (clocale = newlocale (LC_ALL_MASK, "C", NULL));
+      snprintf (buf, sizeof (buf), "%.8G", v);
+      (void) hb_uselocale (((void) freelocale (clocale), oldlocale));
+
+      char *s = buf;
+      if (s[0] == '0' && s[1] == '.')
+       s++;
+      else if (s[0] == '-' && s[1] == '0' && s[2] == '.')
+      {
+       s[1] = '-';
+       s++;
+      }
+      hb_vector_t<char> nibbles;
+      while (*s)
+      {
+       char c = s[0];
+       s++;
+
+       switch (c)
+       {
+         case 'E':
+         {
+           char c2 = *s;
+           if (c2 == '-')
+           {
+             s++;
+             nibbles.push (0x0C); // E-
+             continue;
+           }
+           if (c2 == '+')
+             s++;
+           nibbles.push (0x0B); // E
+           continue;
+         }
+
+         case '.': case ',': // Comma for some European locales in case no uselocale available.
+           nibbles.push (0x0A); // .
+           continue;
+
+         case '-':
+           nibbles.push (0x0E); // .
+           continue;
+       }
+
+       nibbles.push (c - '0');
+      }
+      nibbles.push (0x0F);
+      if (nibbles.length % 2)
+       nibbles.push (0x0F);
+
+      unsigned count = nibbles.length;
+      for (unsigned i = 0; i < count; i += 2)
+        encode_byte ((nibbles[i] << 4) | nibbles[i+1]);
+    }
+  }
+
   void encode_op (op_code_t op)
   {
     if (Is_OpCode_ESC (op))
@@ -107,29 +195,18 @@ struct str_encoder_t
       encode_byte (op);
   }
 
-  void copy_str (const byte_str_t &str)
+  void copy_str (const unsigned char *str, unsigned length)
   {
-    unsigned int  offset = buff.length;
-    if (unlikely (!buff.resize (offset + str.length)))
-    {
-      set_error ();
-      return;
-    }
-    if (unlikely (buff.length < offset + str.length))
-    {
-      set_error ();
-      return;
-    }
-    memcpy (&buff[offset], &str[0], str.length);
+    assert ((signed) (buff.length + length) <= buff.allocated);
+    hb_memcpy (buff.arrayZ + buff.length, str, length);
+    buff.length += length;
   }
 
-  bool is_error () const { return error; }
+  bool in_error () const { return buff.in_error (); }
 
   protected:
-  void set_error () { error = true; }
 
   str_buff_t &buff;
-  bool    error;
 };
 
 struct cff_sub_table_info_t {
@@ -188,47 +265,22 @@ struct cff_font_dict_op_serializer_t : op_serializer_t
     }
     else
     {
-      HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length);
+      unsigned char *d = c->allocate_size<unsigned char> (opstr.length);
       if (unlikely (!d)) return_trace (false);
-      memcpy (d, &opstr.str[0], opstr.str.length);
+      /* Faster than hb_memcpy for small strings. */
+      for (unsigned i = 0; i < opstr.length; i++)
+       d[i] = opstr.ptr[i];
+      //hb_memcpy (d, opstr.ptr, opstr.length);
     }
     return_trace (true);
   }
 };
 
-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,
-                 objidx_t subrs_link) const
-  {
-    TRACE_SERIALIZE (this);
-
-    if (drop_hints && dict_opset_t::is_hint_op (opstr.op))
-      return true;
-    if (opstr.op == OpCode_Subrs)
-    {
-      if (desubroutinize || !subrs_link)
-       return_trace (true);
-      else
-       return_trace (FontDict::serialize_link2_op (c, opstr.op, subrs_link));
-    }
-    else
-      return_trace (copy_opstr (c, opstr));
-  }
-
-  protected:
-  const bool  desubroutinize;
-  const bool  drop_hints;
-};
-
 struct flatten_param_t
 {
   str_buff_t     &flatStr;
   bool drop_hints;
+  const hb_subset_plan_t *plan;
 };
 
 template <typename ACC, typename ENV, typename OPSET, op_code_t endchar_op=OpCode_Invalid>
@@ -240,11 +292,10 @@ struct subr_flattener_t
 
   bool flatten (str_buff_vec_t &flat_charstrings)
   {
-    if (!flat_charstrings.resize (plan->num_output_glyphs ()))
+    unsigned count = plan->num_output_glyphs ();
+    if (!flat_charstrings.resize_exact (count))
       return false;
-    for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
-      flat_charstrings[i].init ();
-    for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
+    for (unsigned int i = 0; i < count; i++)
     {
       hb_codepoint_t  glyph;
       if (!plan->old_gid_for_new_gid (i, &glyph))
@@ -253,15 +304,19 @@ struct subr_flattener_t
        if (endchar_op != OpCode_Invalid) flat_charstrings[i].push (endchar_op);
        continue;
       }
-      const byte_str_t str = (*acc.charStrings)[glyph];
+      const hb_ubytes_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);
+
+
+      ENV env (str, acc, fd,
+              plan->normalized_coords.arrayZ, plan->normalized_coords.length);
+      cs_interpreter_t<ENV, OPSET, flatten_param_t> interp (env);
       flatten_param_t  param = {
-        flat_charstrings[i],
-        (bool) (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+        flat_charstrings.arrayZ[i],
+        (bool) (plan->flags & HB_SUBSET_FLAGS_NO_HINTING),
+       plan
       };
       if (unlikely (!interp.interpret (param)))
        return false;
@@ -275,11 +330,9 @@ struct subr_flattener_t
 
 struct subr_closures_t
 {
-  subr_closures_t (unsigned int fd_count) : valid (false), global_closure (), local_closures ()
+  subr_closures_t (unsigned int fd_count) : global_closure (), local_closures ()
   {
-    valid = true;
-    if (!local_closures.resize (fd_count))
-      valid = false;
+    local_closures.resize_exact (fd_count);
   }
 
   void reset ()
@@ -289,47 +342,38 @@ struct subr_closures_t
       local_closures[i].clear();
   }
 
-  bool is_valid () const { return valid; }
-  bool  valid;
+  bool in_error () const { return local_closures.in_error (); }
   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)
-  {
-    subr_num = subr_num_;
-    drop_flag = false;
-    keep_flag = false;
-    skip_flag = false;
-  }
-
-  bool for_drop () const { return drop_flag; }
-  void set_drop ()       { if (!for_keep ()) drop_flag = true; }
+  parsed_cs_op_t (unsigned int subr_num_ = 0) :
+    subr_num (subr_num_) {}
 
-  bool for_keep () const { return keep_flag; }
-  void set_keep ()       { keep_flag = true; }
+  bool is_hinting () const { return hinting_flag; }
+  void set_hinting ()       { hinting_flag = true; }
 
-  bool for_skip () const { return skip_flag; }
-  void set_skip ()       { skip_flag = true; }
-
-  unsigned int  subr_num;
+  /* The layout of this struct is designed to fit within the
+   * padding of op_str_t! */
 
   protected:
-  bool   drop_flag : 1;
-  bool   keep_flag : 1;
-  bool   skip_flag : 1;
+  bool   hinting_flag = false;
+
+  public:
+  uint16_t subr_num;
 };
 
 struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t>
 {
-  void init ()
+  parsed_cs_str_t () :
+    parsed (false),
+    hint_dropped (false),
+    has_prefix_ (false),
+    has_calls_ (false)
   {
     SUPER::init ();
-    parsed = false;
-    hint_dropped = false;
-    has_prefix_ = false;
   }
 
   void add_op (op_code_t op, const byte_str_ref_t& str_ref)
@@ -342,13 +386,12 @@ struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t>
   {
     if (!is_parsed ())
     {
-      unsigned int parsed_len = get_count ();
-      if (likely (parsed_len > 0))
-       values[parsed_len-1].set_skip ();
+      has_calls_ = true;
+
+      /* Pop the subroutine number. */
+      values.pop ();
 
-      parsed_cs_op_t val;
-      val.init (subr_num);
-      SUPER::add_op (op, str_ref, val);
+      SUPER::add_op (op, str_ref, {subr_num});
     }
   }
 
@@ -378,11 +421,43 @@ struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t>
   op_code_t prefix_op () const         { return prefix_op_; }
   const number_t &prefix_num () const { return prefix_num_; }
 
+  bool has_calls () const          { return has_calls_; }
+
+  void compact ()
+  {
+    unsigned count = values.length;
+    if (!count) return;
+    auto &opstr = values.arrayZ;
+    unsigned j = 0;
+    for (unsigned i = 1; i < count; i++)
+    {
+      /* See if we can combine op j and op i. */
+      bool combine =
+        (opstr[j].op != OpCode_callsubr && opstr[j].op != OpCode_callgsubr) &&
+        (opstr[i].op != OpCode_callsubr && opstr[i].op != OpCode_callgsubr) &&
+        (opstr[j].is_hinting () == opstr[i].is_hinting ()) &&
+        (opstr[j].ptr + opstr[j].length == opstr[i].ptr) &&
+        (opstr[j].length + opstr[i].length <= 255);
+
+      if (combine)
+      {
+       opstr[j].length += opstr[i].length;
+       opstr[j].op = OpCode_Invalid;
+      }
+      else
+      {
+       opstr[++j] = opstr[i];
+      }
+    }
+    values.shrink (j + 1);
+  }
+
   protected:
-  bool    parsed;
-  bool    hint_dropped;
-  bool    vsindex_dropped;
-  bool    has_prefix_;
+  bool    parsed : 1;
+  bool    hint_dropped : 1;
+  bool    vsindex_dropped : 1;
+  bool    has_prefix_ : 1;
+  bool    has_calls_ : 1;
   op_code_t    prefix_op_;
   number_t     prefix_num_;
 
@@ -396,22 +471,82 @@ struct parsed_cs_str_vec_t : hb_vector_t<parsed_cs_str_t>
   typedef hb_vector_t<parsed_cs_str_t> SUPER;
 };
 
-struct subr_subset_param_t
+struct cff_subset_accelerator_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_)
+  static cff_subset_accelerator_t* create (
+      hb_blob_t* original_blob,
+      const parsed_cs_str_vec_t& parsed_charstrings,
+      const parsed_cs_str_vec_t& parsed_global_subrs,
+      const hb_vector_t<parsed_cs_str_vec_t>& parsed_local_subrs) {
+    cff_subset_accelerator_t* accel =
+        (cff_subset_accelerator_t*) hb_malloc (sizeof(cff_subset_accelerator_t));
+    if (unlikely (!accel)) return nullptr;
+    new (accel) cff_subset_accelerator_t (original_blob,
+                                          parsed_charstrings,
+                                          parsed_global_subrs,
+                                          parsed_local_subrs);
+    return accel;
+  }
+
+  static void destroy (void* value) {
+    if (!value) return;
+
+    cff_subset_accelerator_t* accel = (cff_subset_accelerator_t*) value;
+    accel->~cff_subset_accelerator_t ();
+    hb_free (accel);
+  }
+
+  cff_subset_accelerator_t(
+      hb_blob_t* original_blob_,
+      const parsed_cs_str_vec_t& parsed_charstrings_,
+      const parsed_cs_str_vec_t& parsed_global_subrs_,
+      const hb_vector_t<parsed_cs_str_vec_t>& parsed_local_subrs_)
   {
-    parsed_charstring = parsed_charstring_;
-    current_parsed_str = parsed_charstring;
+    parsed_charstrings = parsed_charstrings_;
     parsed_global_subrs = parsed_global_subrs_;
     parsed_local_subrs = parsed_local_subrs_;
-    global_closure = global_closure_;
-    local_closure = local_closure_;
-    drop_hints = drop_hints_;
+
+    // the parsed charstrings point to memory in the original CFF table so we must hold a reference
+    // to it to keep the memory valid.
+    original_blob = hb_blob_reference (original_blob_);
+  }
+
+  ~cff_subset_accelerator_t()
+  {
+    hb_blob_destroy (original_blob);
+    auto *mapping = glyph_to_sid_map.get_relaxed ();
+    if (mapping)
+    {
+      mapping->~glyph_to_sid_map_t ();
+      hb_free (mapping);
+    }
   }
 
+  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;
+  mutable hb_atomic_ptr_t<glyph_to_sid_map_t> glyph_to_sid_map;
+
+ private:
+  hb_blob_t* original_blob;
+};
+
+struct subr_subset_param_t
+{
+  subr_subset_param_t (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_) :
+      current_parsed_str (parsed_charstring_),
+      parsed_charstring (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)
@@ -447,7 +582,11 @@ struct subr_subset_param_t
     if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0)))
       env.set_error ();
     else
+    {
+      if (!parsed_str->is_parsed ())
+        parsed_str->alloc (env.str_ref.total_size ());
       current_parsed_str = parsed_str;
+    }
   }
 
   parsed_cs_str_t      *current_parsed_str;
@@ -468,8 +607,8 @@ struct subr_remap_t : hb_inc_bimap_t
      * no optimization based on usage counts. fonttools doesn't appear doing that either.
      */
 
-    hb_codepoint_t old_num = HB_SET_VALUE_INVALID;
-    while (hb_set_next (closure, &old_num))
+    alloc (closure->get_population ());
+    for (auto old_num : *closure)
       add (old_num);
 
     if (get_population () < 1240)
@@ -506,7 +645,7 @@ struct subr_remaps_t
   {
     global_remap.create (&closures.global_closure);
     for (unsigned int i = 0; i < local_remaps.length; i++)
-      local_remaps[i].create (&closures.local_closures[i]);
+      local_remaps.arrayZ[i].create (&closures.local_closures[i]);
   }
 
   subr_remap_t        global_remap;
@@ -517,7 +656,8 @@ template <typename SUBSETTER, typename SUBRS, typename ACC, typename ENV, typena
 struct subr_subsetter_t
 {
   subr_subsetter_t (ACC &acc_, const hb_subset_plan_t *plan_)
-      : acc (acc_), plan (plan_), closures(acc_.fdCount), remaps(acc_.fdCount)
+      : acc (acc_), plan (plan_), closures(acc_.fdCount),
+        remaps(acc_.fdCount)
   {}
 
   /* Subroutine subsetting with --no-desubroutinize runs in phases:
@@ -536,121 +676,166 @@ struct subr_subsetter_t
    */
   bool subset (void)
   {
-    parsed_charstrings.resize (plan->num_output_glyphs ());
-    parsed_global_subrs.resize (acc.globalSubrs->count);
-
-    if (unlikely (remaps.in_error()
-                  || parsed_charstrings.in_error ()
-                  || parsed_global_subrs.in_error ())) {
-      return false;
+    unsigned fd_count = acc.fdCount;
+    const cff_subset_accelerator_t* cff_accelerator = nullptr;
+    if (acc.cff_accelerator) {
+      cff_accelerator = acc.cff_accelerator;
+      fd_count = cff_accelerator->parsed_local_subrs.length;
     }
 
-    if (unlikely (!parsed_local_subrs.resize (acc.fdCount))) return false;
+    if (cff_accelerator) {
+      // If we are not dropping hinting then charstrings are not modified so we can
+      // just use a reference to the cached copies.
+      cached_charstrings.resize_exact (plan->num_output_glyphs ());
+      parsed_global_subrs = &cff_accelerator->parsed_global_subrs;
+      parsed_local_subrs = &cff_accelerator->parsed_local_subrs;
+    } else {
+      parsed_charstrings.resize_exact (plan->num_output_glyphs ());
+      parsed_global_subrs_storage.resize_exact (acc.globalSubrs->count);
 
-    for (unsigned int i = 0; i < acc.fdCount; i++)
-    {
-      parsed_local_subrs[i].resize (acc.privateDicts[i].localSubrs->count);
-      if (unlikely (parsed_local_subrs[i].in_error ())) return false;
+      if (unlikely (!parsed_local_subrs_storage.resize (fd_count))) return false;
+
+      for (unsigned int i = 0; i < acc.fdCount; i++)
+      {
+        unsigned count = acc.privateDicts[i].localSubrs->count;
+        parsed_local_subrs_storage[i].resize (count);
+        if (unlikely (parsed_local_subrs_storage[i].in_error ())) return false;
+      }
+
+      parsed_global_subrs = &parsed_global_subrs_storage;
+      parsed_local_subrs = &parsed_local_subrs_storage;
     }
-    if (unlikely (!closures.valid))
+
+    if (unlikely (remaps.in_error()
+                  || cached_charstrings.in_error ()
+                  || parsed_charstrings.in_error ()
+                  || parsed_global_subrs->in_error ()
+                  || closures.in_error ())) {
       return false;
+    }
 
     /* phase 1 & 2 */
-    for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
+    for (auto _ : plan->new_to_old_gid_list)
     {
-      hb_codepoint_t  glyph;
-      if (!plan->old_gid_for_new_gid (i, &glyph))
-       continue;
-      const byte_str_t str = (*acc.charStrings)[glyph];
-      unsigned int fd = acc.fdSelect->get_fd (glyph);
+      hb_codepoint_t new_glyph = _.first;
+      hb_codepoint_t old_glyph = _.second;
+
+      const hb_ubytes_t str = (*acc.charStrings)[old_glyph];
+      unsigned int fd = acc.fdSelect->get_fd (old_glyph);
       if (unlikely (fd >= acc.fdCount))
-       return false;
+        return false;
+
+      if (cff_accelerator)
+      {
+        // parsed string already exists in accelerator, copy it and move
+        // on.
+        if (cached_charstrings)
+          cached_charstrings[new_glyph] = &cff_accelerator->parsed_charstrings[old_glyph];
+        else
+          parsed_charstrings[new_glyph] = cff_accelerator->parsed_charstrings[old_glyph];
+
+        continue;
+      }
 
-      cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp;
-      interp.env.init (str, acc, fd);
+      ENV env (str, acc, fd);
+      cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp (env);
 
-      subr_subset_param_t  param;
-      param.init (&parsed_charstrings[i],
-                 &parsed_global_subrs,  &parsed_local_subrs[fd],
-                 &closures.global_closure, &closures.local_closures[fd],
-                 plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
+      parsed_charstrings[new_glyph].alloc (str.length);
+      subr_subset_param_t  param (&parsed_charstrings[new_glyph],
+                                  &parsed_global_subrs_storage,
+                                  &parsed_local_subrs_storage[fd],
+                                  &closures.global_closure,
+                                  &closures.local_closures[fd],
+                                  plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
 
       if (unlikely (!interp.interpret (param)))
-       return false;
+        return false;
 
       /* complete parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */
-      SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[i]);
-    }
+      SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[new_glyph]);
 
-    if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
-    {
       /* mark hint ops and arguments for drop */
-      for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
+      if ((plan->flags & HB_SUBSET_FLAGS_NO_HINTING) || plan->inprogress_accelerator)
       {
-       hb_codepoint_t  glyph;
-       if (!plan->old_gid_for_new_gid (i, &glyph))
-         continue;
-       unsigned int fd = acc.fdSelect->get_fd (glyph);
-       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],
-                    plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
+       subr_subset_param_t  param (&parsed_charstrings[new_glyph],
+                                   &parsed_global_subrs_storage,
+                                   &parsed_local_subrs_storage[fd],
+                                   &closures.global_closure,
+                                   &closures.local_closures[fd],
+                                   plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
 
        drop_hints_param_t  drop;
-       if (drop_hints_in_str (parsed_charstrings[i], param, drop))
+       if (drop_hints_in_str (parsed_charstrings[new_glyph], param, drop))
        {
-         parsed_charstrings[i].set_hint_dropped ();
+         parsed_charstrings[new_glyph].set_hint_dropped ();
          if (drop.vsindex_dropped)
-           parsed_charstrings[i].set_vsindex_dropped ();
+           parsed_charstrings[new_glyph].set_vsindex_dropped ();
        }
       }
 
-      /* after dropping hints recreate closures of actually used subrs */
-      closures.reset ();
-      for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
-      {
-       hb_codepoint_t  glyph;
-       if (!plan->old_gid_for_new_gid (i, &glyph))
-         continue;
-       unsigned int fd = acc.fdSelect->get_fd (glyph);
-       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],
-                    plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
-       collect_subr_refs_in_str (parsed_charstrings[i], param);
-      }
+      /* Doing this here one by one instead of compacting all at the end
+       * has massive peak-memory saving.
+       *
+       * The compacting both saves memory and makes further operations
+       * faster.
+       */
+      parsed_charstrings[new_glyph].compact ();
     }
 
+    /* Since parsed strings were loaded from accelerator, we still need
+     * to compute the subroutine closures which would have normally happened during
+     * parsing.
+     *
+     * Or if we are dropping hinting, redo closure to get actually used subrs.
+     */
+    if ((cff_accelerator ||
+       (!cff_accelerator && plan->flags & HB_SUBSET_FLAGS_NO_HINTING)) &&
+        !closure_subroutines(*parsed_global_subrs,
+                             *parsed_local_subrs))
+      return false;
+
     remaps.create (closures);
 
+    populate_subset_accelerator ();
     return true;
   }
 
-  bool encode_charstrings (str_buff_vec_t &buffArray) const
+  bool encode_charstrings (str_buff_vec_t &buffArray, bool encode_prefix = true) const
   {
-    if (unlikely (!buffArray.resize (plan->num_output_glyphs ())))
+    unsigned num_glyphs = plan->num_output_glyphs ();
+    if (unlikely (!buffArray.resize_exact (num_glyphs)))
       return false;
-    for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
+    hb_codepoint_t last = 0;
+    for (auto _ : plan->new_to_old_gid_list)
     {
-      hb_codepoint_t  glyph;
-      if (!plan->old_gid_for_new_gid (i, &glyph))
-      {
-       /* add an endchar only charstring for a missing glyph if CFF1 */
-       if (endchar_op != OpCode_Invalid) buffArray[i].push (endchar_op);
-       continue;
-      }
-      unsigned int  fd = acc.fdSelect->get_fd (glyph);
+      hb_codepoint_t gid = _.first;
+      hb_codepoint_t old_glyph = _.second;
+
+      if (endchar_op != OpCode_Invalid)
+        for (; last < gid; last++)
+       {
+         // Hack to point vector to static string.
+         auto &b = buffArray.arrayZ[last];
+         b.length = 1;
+         b.arrayZ = const_cast<unsigned char *>(endchar_str);
+       }
+
+      last++; // Skip over gid
+      unsigned int  fd = acc.fdSelect->get_fd (old_glyph);
       if (unlikely (fd >= acc.fdCount))
        return false;
-      if (unlikely (!encode_str (parsed_charstrings[i], fd, buffArray[i])))
+      if (unlikely (!encode_str (get_parsed_charstring (gid), fd, buffArray.arrayZ[gid], encode_prefix)))
        return false;
     }
+    if (endchar_op != OpCode_Invalid)
+      for (; last < num_glyphs; last++)
+      {
+       // Hack to point vector to static string.
+       auto &b = buffArray.arrayZ[last];
+       b.length = 1;
+       b.arrayZ = const_cast<unsigned char *>(endchar_str);
+      }
+
     return true;
   }
 
@@ -658,28 +843,27 @@ struct subr_subsetter_t
   {
     unsigned int  count = remap.get_population ();
 
-    if (unlikely (!buffArray.resize (count)))
+    if (unlikely (!buffArray.resize_exact (count)))
       return false;
-    for (unsigned int old_num = 0; old_num < subrs.length; old_num++)
+    for (unsigned int new_num = 0; new_num < count; new_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;
-      }
+      hb_codepoint_t old_num = remap.backward (new_num);
+      assert (old_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);
+    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);
+    return encode_subrs ((*parsed_local_subrs)[fd], remaps.local_remaps[fd], fd, buffArray);
   }
 
   protected:
@@ -708,7 +892,7 @@ struct subr_subsetter_t
      * then this entire subroutine must be a hint. drop its call. */
     if (drop.ends_in_hint)
     {
-      str.values[pos].set_drop ();
+      str.values[pos].set_hinting ();
       /* if this subr call is at the end of the parent subr, propagate the flag
        * otherwise reset the flag */
       if (!str.at_end (pos))
@@ -716,7 +900,7 @@ struct subr_subsetter_t
     }
     else if (drop.all_dropped)
     {
-      str.values[pos].set_drop ();
+      str.values[pos].set_hinting ();
     }
 
     return has_hint;
@@ -727,20 +911,22 @@ struct subr_subsetter_t
   {
     bool  seen_hint = false;
 
-    for (unsigned int pos = 0; pos < str.values.length; pos++)
+    unsigned count = str.values.length;
+    auto *values = str.values.arrayZ;
+    for (unsigned int pos = 0; pos < count; pos++)
     {
       bool  has_hint = false;
-      switch (str.values[pos].op)
+      switch (values[pos].op)
       {
        case OpCode_callsubr:
          has_hint = drop_hints_in_subr (str, pos,
-                                       *param.parsed_local_subrs, str.values[pos].subr_num,
+                                       *param.parsed_local_subrs, 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.parsed_global_subrs, values[pos].subr_num,
                                        param, drop);
          break;
 
@@ -754,7 +940,7 @@ struct subr_subsetter_t
        case OpCode_cntrmask:
          if (drop.seen_moveto)
          {
-           str.values[pos].set_drop ();
+           values[pos].set_hinting ();
            break;
          }
          HB_FALLTHROUGH;
@@ -764,13 +950,13 @@ struct subr_subsetter_t
        case OpCode_hstem:
        case OpCode_vstem:
          has_hint = true;
-         str.values[pos].set_drop ();
+         values[pos].set_hinting ();
          if (str.at_end (pos))
            drop.ends_in_hint = true;
          break;
 
        case OpCode_dotsection:
-         str.values[pos].set_drop ();
+         values[pos].set_hinting ();
          break;
 
        default:
@@ -781,10 +967,10 @@ struct subr_subsetter_t
       {
        for (int i = pos - 1; i >= 0; i--)
        {
-         parsed_cs_op_t  &csop = str.values[(unsigned)i];
-         if (csop.for_drop ())
+         parsed_cs_op_t  &csop = values[(unsigned)i];
+         if (csop.is_hinting ())
            break;
-         csop.set_drop ();
+         csop.set_hinting ();
          if (csop.op == OpCode_vsindexcs)
            drop.vsindex_dropped = true;
        }
@@ -797,12 +983,12 @@ struct subr_subsetter_t
      * only (usually one) hintmask operator, then calls to this subr can be dropped.
      */
     drop.all_dropped = true;
-    for (unsigned int pos = 0; pos < str.values.length; pos++)
+    for (unsigned int pos = 0; pos < count; pos++)
     {
-      parsed_cs_op_t  &csop = str.values[pos];
+      parsed_cs_op_t  &csop = values[pos];
       if (csop.op == OpCode_return)
        break;
-      if (!csop.for_drop ())
+      if (!csop.is_hinting ())
       {
        drop.all_dropped = false;
        break;
@@ -812,32 +998,61 @@ struct subr_subsetter_t
     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,
+  bool closure_subroutines (const parsed_cs_str_vec_t& global_subrs,
+                            const hb_vector_t<parsed_cs_str_vec_t>& local_subrs)
+  {
+    closures.reset ();
+    for (auto _ : plan->new_to_old_gid_list)
+    {
+      hb_codepoint_t new_glyph = _.first;
+      hb_codepoint_t old_glyph = _.second;
+      unsigned int fd = acc.fdSelect->get_fd (old_glyph);
+      if (unlikely (fd >= acc.fdCount))
+        return false;
+
+      // Note: const cast is safe here because the collect_subr_refs_in_str only performs a
+      //       closure and does not modify any of the charstrings.
+      subr_subset_param_t  param (const_cast<parsed_cs_str_t*> (&get_parsed_charstring (new_glyph)),
+                                  const_cast<parsed_cs_str_vec_t*> (&global_subrs),
+                                  const_cast<parsed_cs_str_vec_t*> (&local_subrs[fd]),
+                                  &closures.global_closure,
+                                  &closures.local_closures[fd],
+                                  plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
+      collect_subr_refs_in_str (get_parsed_charstring (new_glyph), param);
+    }
+
+    return true;
+  }
+
+  void collect_subr_refs_in_subr (unsigned int subr_num, parsed_cs_str_vec_t &subrs,
                                  hb_set_t *closure,
                                  const subr_subset_param_t &param)
   {
+    if (closure->has (subr_num))
+      return;
     closure->add (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)
+  void collect_subr_refs_in_str (const parsed_cs_str_t &str,
+                                 const subr_subset_param_t &param)
   {
-    for (unsigned int pos = 0; pos < str.values.length; pos++)
+    if (!str.has_calls ())
+      return;
+
+    for (auto &opstr : str.values)
     {
-      if (!str.values[pos].for_drop ())
+      if (!param.drop_hints || !opstr.is_hinting ())
       {
-       switch (str.values[pos].op)
+       switch (opstr.op)
        {
          case OpCode_callsubr:
-           collect_subr_refs_in_subr (str, pos,
-                                      str.values[pos].subr_num, *param.parsed_local_subrs,
+           collect_subr_refs_in_subr (opstr.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,
+           collect_subr_refs_in_subr (opstr.subr_num, *param.parsed_global_subrs,
                                       param.global_closure, param);
            break;
 
@@ -847,43 +1062,81 @@ struct subr_subsetter_t
     }
   }
 
-  bool encode_str (const parsed_cs_str_t &str, const unsigned int fd, str_buff_t &buff) const
+  bool encode_str (const parsed_cs_str_t &str, const unsigned int fd, str_buff_t &buff, bool encode_prefix = true) const
   {
-    buff.init ();
     str_encoder_t  encoder (buff);
     encoder.reset ();
+    bool hinting = !(plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
     /* 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 ())
+    if (encode_prefix && str.has_prefix () && !hinting && str.is_hint_dropped ())
     {
-      encoder.encode_num (str.prefix_num ());
+      encoder.encode_num_cs (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++)
+
+    unsigned size = 0;
+    for (auto &opstr : str.values)
+    {
+      size += opstr.length;
+      if (opstr.op == OpCode_callsubr || opstr.op == OpCode_callgsubr)
+        size += 3;
+    }
+    if (!buff.alloc (buff.length + size, true))
+      return false;
+
+    for (auto &opstr : str.values)
     {
-      const parsed_cs_op_t  &opstr = str.values[i];
-      if (!opstr.for_drop () && !opstr.for_skip ())
+      if (hinting || !opstr.is_hinting ())
       {
        switch (opstr.op)
        {
          case OpCode_callsubr:
            encoder.encode_int (remaps.local_remaps[fd].biased_num (opstr.subr_num));
-           encoder.encode_op (OpCode_callsubr);
+           encoder.copy_str (opstr.ptr, opstr.length);
            break;
 
          case OpCode_callgsubr:
            encoder.encode_int (remaps.global_remap.biased_num (opstr.subr_num));
-           encoder.encode_op (OpCode_callgsubr);
+           encoder.copy_str (opstr.ptr, opstr.length);
            break;
 
          default:
-           encoder.copy_str (opstr.str);
+           encoder.copy_str (opstr.ptr, opstr.length);
            break;
        }
       }
     }
-    return !encoder.is_error ();
+    return !encoder.in_error ();
+  }
+
+  void compact_parsed_subrs () const
+  {
+    for (auto &cs : parsed_global_subrs_storage)
+      cs.compact ();
+    for (auto &vec : parsed_local_subrs_storage)
+      for (auto &cs : vec)
+       cs.compact ();
+  }
+
+  void populate_subset_accelerator () const
+  {
+    if (!plan->inprogress_accelerator) return;
+
+    compact_parsed_subrs ();
+
+    acc.cff_accelerator =
+        cff_subset_accelerator_t::create(acc.blob,
+                                         parsed_charstrings,
+                                         parsed_global_subrs_storage,
+                                         parsed_local_subrs_storage);
+  }
+
+  const parsed_cs_str_t& get_parsed_charstring (unsigned i) const
+  {
+    if (cached_charstrings) return *(cached_charstrings[i]);
+    return parsed_charstrings[i];
   }
 
   protected:
@@ -892,13 +1145,17 @@ struct subr_subsetter_t
 
   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;
+  hb_vector_t<const parsed_cs_str_t*>     cached_charstrings;
+  const parsed_cs_str_vec_t*              parsed_global_subrs;
+  const hb_vector_t<parsed_cs_str_vec_t>* parsed_local_subrs;
 
   subr_remaps_t                        remaps;
 
   private:
+
+  parsed_cs_str_vec_t          parsed_charstrings;
+  parsed_cs_str_vec_t          parsed_global_subrs_storage;
+  hb_vector_t<parsed_cs_str_vec_t>  parsed_local_subrs_storage;
   typedef typename SUBRS::count_type subr_count_type;
 };
 
index 35fecd6..872cba6 100644 (file)
 #include "hb-ot-cff1-table.hh"
 #include "hb-set.h"
 #include "hb-bimap.hh"
-#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 : hb_inc_bimap_t
+struct remap_sid_t
 {
+  unsigned get_population () const { return vector.length; }
+
+  void alloc (unsigned size)
+  {
+    map.alloc (size);
+    vector.alloc (size, true);
+  }
+
+  bool in_error () const
+  { return map.in_error () || vector.in_error (); }
+
   unsigned int add (unsigned int sid)
   {
-    if ((sid != CFF_UNDEF_SID) && !is_std_std (sid))
-      return offset_sid (hb_inc_bimap_t::add (unoffset_sid (sid)));
-    else
+    if (is_std_str (sid) || (sid == CFF_UNDEF_SID))
       return sid;
+
+    sid = unoffset_sid (sid);
+    unsigned v = next;
+    if (map.set (sid, v, false))
+    {
+      vector.push (sid);
+      next++;
+    }
+    else
+      v = map.get (sid); // already exists
+    return offset_sid (v);
   }
 
   unsigned int operator[] (unsigned int sid) const
   {
-    if (is_std_std (sid) || (sid == CFF_UNDEF_SID))
+    if (is_std_str (sid) || (sid == CFF_UNDEF_SID))
       return sid;
-    else
-      return offset_sid (get (unoffset_sid (sid)));
+
+    return offset_sid (map.get (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 bool is_std_str (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; }
+  unsigned next = 0;
+
+  hb_map_t map;
+  hb_vector_t<unsigned> vector;
 };
 
 struct cff1_sub_table_info_t : cff_sub_table_info_t
@@ -167,9 +190,10 @@ struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<cff1_top_dic
           * 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)))
+         if ( unlikely (!(opstr.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);
+         supp_op.ptr = opstr.ptr + opstr.last_arg_offset;
+         supp_op.length = opstr.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));
@@ -233,7 +257,7 @@ struct cff1_cs_opset_flatten_t : cff1_cs_opset_t<cff1_cs_opset_flatten_t, flatte
   {
     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));
+      encoder.encode_num_cs (env.eval_arg (i));
     SUPER::flush_args (env, param);
   }
 
@@ -247,7 +271,7 @@ struct cff1_cs_opset_flatten_t : cff1_cs_opset_t<cff1_cs_opset_flatten_t, flatte
   {
     assert (env.has_width);
     str_encoder_t  encoder (param.flatStr);
-    encoder.encode_num (env.width);
+    encoder.encode_num_cs (env.width);
   }
 
   static void flush_hintmask (op_code_t op, cff1_cs_interp_env_t &env, flatten_param_t& param)
@@ -270,16 +294,17 @@ 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 complete (unsigned int last_glyph)
   {
-    bool  two_byte = false;
-    for (unsigned int i = (*this).length; i > 0; i--)
+    hb_codepoint_t all_glyphs = 0;
+    unsigned count = this->length;
+    for (unsigned int i = count; i; i--)
     {
-      code_pair_t &pair = (*this)[i - 1];
-      unsigned int  nLeft = last_glyph - pair.glyph - 1;
-      if (nLeft >= 0x100)
-       two_byte = true;
+      code_pair_t &pair = arrayZ[i - 1];
+      unsigned int nLeft = last_glyph - pair.glyph - 1;
+      all_glyphs |= nLeft;
       last_glyph = pair.glyph;
       pair.glyph = nLeft;
     }
+    bool two_byte = all_glyphs >= 0x100;
     return two_byte;
   }
 };
@@ -334,6 +359,36 @@ struct cff1_cs_opset_subr_subset_t : cff1_cs_opset_t<cff1_cs_opset_subr_subset_t
   typedef cff1_cs_opset_t<cff1_cs_opset_subr_subset_t, subr_subset_param_t> SUPER;
 };
 
+struct cff1_private_dict_op_serializer_t : op_serializer_t
+{
+  cff1_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,
+                 objidx_t subrs_link) const
+  {
+    TRACE_SERIALIZE (this);
+
+    if (drop_hints && dict_opset_t::is_hint_op (opstr.op))
+      return_trace (true);
+
+    if (opstr.op == OpCode_Subrs)
+    {
+      if (desubroutinize || !subrs_link)
+       return_trace (true);
+      else
+       return_trace (FontDict::serialize_link2_op (c, opstr.op, subrs_link));
+    }
+
+    return_trace (copy_opstr (c, opstr));
+  }
+
+  protected:
+  const bool desubroutinize;
+  const bool drop_hints;
+};
+
 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, OpCode_endchar>
 {
   cff1_subr_subsetter_t (const OT::cff1::accelerator_subset_t &acc_, const hb_subset_plan_t *plan_)
@@ -360,8 +415,10 @@ struct cff1_subr_subsetter_t : subr_subsetter_t<cff1_subr_subsetter_t, CFF1Subrs
   }
 };
 
-struct cff_subset_plan {
-  cff_subset_plan ()
+namespace OT {
+struct cff1_subset_plan
+{
+  cff1_subset_plan ()
   {
     for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
       topDictModSIDs[i] = CFF_UNDEF_SID;
@@ -371,7 +428,7 @@ struct cff_subset_plan {
   {
     const Encoding *encoding = acc.encoding;
     unsigned int  size0, size1;
-    hb_codepoint_t  code, last_code = CFF_UNDEF_CODE;
+    unsigned code, last_code = CFF_UNDEF_CODE - 1;
     hb_vector_t<hb_codepoint_t> supp_codes;
 
     if (unlikely (!subset_enc_code_ranges.resize (0)))
@@ -382,39 +439,42 @@ struct cff_subset_plan {
 
     supp_codes.init ();
 
+    code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID};
     subset_enc_num_codes = plan->num_output_glyphs () - 1;
     unsigned int glyph;
-    for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++)
+    auto it = hb_iter (plan->new_to_old_gid_list);
+    if (it->first == 0) it++;
+    auto _ = *it;
+    for (glyph = 1; glyph < num_glyphs; glyph++)
     {
-      hb_codepoint_t  old_glyph;
-      if (!plan->old_gid_for_new_gid (glyph, &old_glyph))
+      hb_codepoint_t old_glyph;
+      if (glyph == _.first)
+      {
+       old_glyph = _.second;
+       _ = *++it;
+      }
+      else
       {
-       /* Retain the code for the old missing glyph ID */
+       /* Retain the SID for the old missing glyph ID */
        old_glyph = glyph;
       }
-      code = acc.glyph_to_code (old_glyph);
+      code = acc.glyph_to_code (old_glyph, &glyph_to_sid_cache);
       if (code == CFF_UNDEF_CODE)
       {
        subset_enc_num_codes = glyph - 1;
        break;
       }
 
-      if ((last_code == CFF_UNDEF_CODE) || (code != last_code + 1))
-      {
-       code_pair_t pair = { code, glyph };
-       subset_enc_code_ranges.push (pair);
-      }
+      if (code != last_code + 1)
+       subset_enc_code_ranges.push (code_pair_t {code, glyph});
       last_code = code;
 
       if (encoding != &Null (Encoding))
       {
-       hb_codepoint_t  sid = acc.glyph_to_sid (old_glyph);
+       hb_codepoint_t  sid = acc.glyph_to_sid (old_glyph, &glyph_to_sid_cache);
        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);
-       }
+         subset_enc_supp_codes.push (code_pair_t {supp_codes[i], sid});
       }
     }
     supp_codes.fini ();
@@ -431,46 +491,93 @@ struct cff_subset_plan {
       subset_enc_format = 1;
   }
 
-  void plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
+  bool 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;
+    unsigned last_sid = CFF_UNDEF_CODE - 1;
 
     if (unlikely (!subset_charset_ranges.resize (0)))
     {
       plan->check_success (false);
-      return;
+      return false;
     }
 
-    unsigned int glyph;
-    for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++)
+    code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID};
+
+    unsigned num_glyphs = plan->num_output_glyphs ();
+
+    if (unlikely (!subset_charset_ranges.alloc (hb_min (num_glyphs,
+                                                       acc.num_charset_entries))))
     {
-      hb_codepoint_t  old_glyph;
-      if (!plan->old_gid_for_new_gid (glyph, &old_glyph))
+      plan->check_success (false);
+      return false;
+    }
+
+    glyph_to_sid_map_t *glyph_to_sid_map = acc.cff_accelerator ?
+                                          acc.cff_accelerator->glyph_to_sid_map.get_acquire () :
+                                          nullptr;
+    bool created_map = false;
+    if (!glyph_to_sid_map && acc.cff_accelerator)
+    {
+      created_map = true;
+      glyph_to_sid_map = acc.create_glyph_to_sid_map ();
+    }
+
+    auto it = hb_iter (plan->new_to_old_gid_list);
+    if (it->first == 0) it++;
+    auto _ = *it;
+    bool not_is_cid = !acc.is_CID ();
+    bool skip = !not_is_cid && glyph_to_sid_map;
+    if (not_is_cid)
+      sidmap.alloc (num_glyphs);
+    for (hb_codepoint_t glyph = 1; glyph < num_glyphs; glyph++)
+    {
+      hb_codepoint_t old_glyph;
+      if (glyph == _.first)
+      {
+       old_glyph = _.second;
+       _ = *++it;
+      }
+      else
       {
        /* Retain the SID for the old missing glyph ID */
        old_glyph = glyph;
       }
-      sid = acc.glyph_to_sid (old_glyph);
+      unsigned sid = glyph_to_sid_map ?
+                    glyph_to_sid_map->arrayZ[old_glyph].code :
+                    acc.glyph_to_sid (old_glyph, &glyph_to_sid_cache);
 
-      if (!acc.is_CID ())
+      if (not_is_cid)
        sid = sidmap.add (sid);
 
-      if ((last_sid == CFF_UNDEF_CODE) || (sid != last_sid + 1))
+      if (sid != last_sid + 1)
+       subset_charset_ranges.push (code_pair_t {sid, glyph});
+
+      if (glyph == old_glyph && skip)
       {
-       code_pair_t pair = { sid, glyph };
-       subset_charset_ranges.push (pair);
+       glyph = hb_min (_.first - 1, glyph_to_sid_map->arrayZ[old_glyph].glyph);
+       sid += glyph - old_glyph;
       }
       last_sid = sid;
     }
 
-    bool two_byte = subset_charset_ranges.complete (glyph);
+    if (created_map)
+    {
+      if ((!plan->accelerator && acc.cff_accelerator) ||
+         !acc.cff_accelerator->glyph_to_sid_map.cmpexch (nullptr, glyph_to_sid_map))
+      {
+       glyph_to_sid_map->~glyph_to_sid_map_t ();
+       hb_free (glyph_to_sid_map);
+      }
+    }
+
+    bool two_byte = subset_charset_ranges.complete (num_glyphs);
 
-    size0 = Charset0::min_size + HBUINT16::static_size * (plan->num_output_glyphs () - 1);
+    size0 = Charset0::get_size (plan->num_output_glyphs ());
     if (!two_byte)
-      size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.length;
+      size_ranges = Charset1::get_size_for_ranges (subset_charset_ranges.length);
     else
-      size_ranges = Charset2::min_size + Charset2_Range::static_size * subset_charset_ranges.length;
+      size_ranges = Charset2::get_size_for_ranges (subset_charset_ranges.length);
 
     if (size0 < size_ranges)
       subset_charset_format = 0;
@@ -478,19 +585,18 @@ struct cff_subset_plan {
       subset_charset_format = 1;
     else
       subset_charset_format = 2;
+
+    return true;
   }
 
   bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc)
   {
-    sidmap.reset ();
-
     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];
+       topDictModSIDs[i] = sidmap.add (sid);
       }
     }
 
@@ -514,19 +620,18 @@ struct cff_subset_plan {
     drop_hints = plan->flags & HB_SUBSET_FLAGS_NO_HINTING;
     desubroutinize = plan->flags & HB_SUBSET_FLAGS_DESUBROUTINIZE;
 
-    /* check whether the subset renumbers any glyph IDs */
-    gid_renum = false;
-    for (hb_codepoint_t new_glyph = 0; new_glyph < plan->num_output_glyphs (); new_glyph++)
-    {
-      if (!plan->old_gid_for_new_gid(new_glyph, &old_glyph))
-       continue;
-      if (new_glyph != old_glyph) {
-       gid_renum = true;
-       break;
+    subset_charset = !acc.is_predef_charset ();
+    if (!subset_charset)
+      /* check whether the subset renumbers any glyph IDs */
+      for (const auto &_ : plan->new_to_old_gid_list)
+      {
+       if (_.first != _.second)
+       {
+         subset_charset = true;
+         break;
+       }
       }
-    }
 
-    subset_charset = gid_renum || !acc.is_predef_charset ();
     subset_encoding = !acc.is_CID() && !acc.is_predef_encoding ();
 
     /* top dict INDEX */
@@ -568,7 +673,8 @@ struct cff_subset_plan {
       if (unlikely (sidmap.get_population () > 0x8000))        /* assumption: a dict won't reference that many strings */
        return false;
 
-      if (subset_charset) plan_subset_charset (acc, plan);
+      if (subset_charset && !plan_subset_charset (acc, plan))
+        return false;
 
       topdict_mod.reassignSIDs (sidmap);
     }
@@ -632,8 +738,9 @@ struct cff_subset_plan {
       ;
     }
 
-    return ((subset_charstrings.length == plan->num_output_glyphs ())
-          && (fontdicts_mod.length == subset_fdcount));
+    return !plan->in_error () &&
+          (subset_charstrings.length == plan->num_output_glyphs ()) &&
+          (fontdicts_mod.length == subset_fdcount);
   }
 
   cff1_top_dict_values_mod_t   topdict_mod;
@@ -672,24 +779,22 @@ struct cff_subset_plan {
 
   bool         desubroutinize = false;
 };
+} // namespace OT
 
-static bool _serialize_cff1 (hb_serialize_context_t *c,
-                            cff_subset_plan &plan,
-                            const OT::cff1::accelerator_subset_t  &acc,
-                            unsigned int num_glyphs)
+bool
+OT::cff1::accelerator_subset_t::serialize (hb_serialize_context_t *c,
+                                          struct OT::cff1_subset_plan &plan) const
 {
   /* private dicts & local subrs */
-  for (int i = (int)acc.privateDicts.length; --i >= 0 ;)
+  for (int i = (int) privateDicts.length; --i >= 0 ;)
   {
     if (plan.fdmap.has (i))
     {
       objidx_t subrs_link = 0;
       if (plan.subset_localsubrs[i].length > 0)
       {
-       CFF1Subrs *dest = c->start_embed <CFF1Subrs> ();
-       if (unlikely (!dest)) return false;
-       c->push ();
-       if (likely (dest && dest->serialize (c, plan.subset_localsubrs[i])))
+       auto *dest = c->push <CFF1Subrs> ();
+       if (likely (dest->serialize (c, plan.subset_localsubrs[i])))
          subrs_link = c->pop_pack ();
        else
        {
@@ -698,12 +803,10 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
        }
       }
 
-      PrivateDict *pd = c->start_embed<PrivateDict> ();
-      if (unlikely (!pd)) return false;
-      c->push ();
-      cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints);
+      auto *pd = c->push<PrivateDict> ();
+      cff1_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 */
-      if (likely (pd->serialize (c, acc.privateDicts[i], privSzr, subrs_link)))
+      if (likely (pd->serialize (c, privateDicts[i], privSzr, subrs_link)))
       {
        unsigned fd = plan.fdmap[i];
        plan.fontdicts_mod[fd].privateDictInfo.size = c->length ();
@@ -717,16 +820,21 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
     }
   }
 
-  if (!acc.is_CID ())
+  if (!is_CID ())
     plan.info.privateDictInfo = plan.fontdicts_mod[0].privateDictInfo;
 
   /* CharStrings */
   {
-    CFF1CharStrings  *cs = c->start_embed<CFF1CharStrings> ();
-    if (unlikely (!cs)) return false;
-    c->push ();
-    if (likely (cs->serialize (c, plan.subset_charstrings)))
-      plan.info.char_strings_link = c->pop_pack ();
+    c->push<CFF1CharStrings> ();
+
+    unsigned data_size = 0;
+    unsigned total_size = CFF1CharStrings::total_size (plan.subset_charstrings, &data_size);
+    if (unlikely (!c->start_zerocopy (total_size)))
+       return false;
+
+    auto *cs = c->start_embed<CFF1CharStrings> ();
+    if (likely (cs->serialize (c, plan.subset_charstrings, &data_size)))
+      plan.info.char_strings_link = c->pop_pack (false);
     else
     {
       c->pop_discard ();
@@ -735,11 +843,9 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
   }
 
   /* FDArray (FD Index) */
-  if (acc.fdArray != &Null (CFF1FDArray))
+  if (fdArray != &Null (CFF1FDArray))
   {
-    CFF1FDArray *fda = c->start_embed<CFF1FDArray> ();
-    if (unlikely (!fda)) return false;
-    c->push ();
+    auto *fda = c->push<CFF1FDArray> ();
     cff1_font_dict_op_serializer_t  fontSzr;
     auto it = + hb_zip (+ hb_iter (plan.fontdicts_mod), + hb_iter (plan.fontdicts_mod));
     if (likely (fda->serialize (c, it, fontSzr)))
@@ -752,10 +858,10 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
   }
 
   /* FDSelect */
-  if (acc.fdSelect != &Null (CFF1FDSelect))
+  if (fdSelect != &Null (CFF1FDSelect))
   {
     c->push ();
-    if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *acc.fdSelect, acc.fdCount,
+    if (likely (hb_serialize_cff_fdselect (c, plan.num_glyphs, *fdSelect, fdCount,
                                           plan.subset_fdselect_format, plan.info.fd_select.size,
                                           plan.subset_fdselect_ranges)))
       plan.info.fd_select.link = c->pop_pack ();
@@ -769,9 +875,7 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
   /* Charset */
   if (plan.subset_charset)
   {
-    Charset *dest = c->start_embed<Charset> ();
-    if (unlikely (!dest)) return false;
-    c->push ();
+    auto *dest = c->push<Charset> ();
     if (likely (dest->serialize (c,
                                 plan.subset_charset_format,
                                 plan.num_glyphs,
@@ -787,9 +891,7 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
   /* Encoding */
   if (plan.subset_encoding)
   {
-    Encoding *dest = c->start_embed<Encoding> ();
-    if (unlikely (!dest)) return false;
-    c->push ();
+    auto *dest = c->push<Encoding> ();
     if (likely (dest->serialize (c,
                                 plan.subset_enc_format,
                                 plan.subset_enc_num_codes,
@@ -805,11 +907,9 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
 
   /* global subrs */
   {
-    c->push ();
-    CFF1Subrs *dest = c->start_embed <CFF1Subrs> ();
-    if (unlikely (!dest)) return false;
+    auto *dest = c->push <CFF1Subrs> ();
     if (likely (dest->serialize (c, plan.subset_globalsubrs)))
-      c->pop_pack ();
+      c->pop_pack (false);
     else
     {
       c->pop_discard ();
@@ -819,10 +919,9 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
 
   /* String INDEX */
   {
-    CFF1StringIndex *dest = c->start_embed<CFF1StringIndex> ();
-    if (unlikely (!dest)) return false;
-    c->push ();
-    if (likely (dest->serialize (c, *acc.stringIndex, plan.sidmap)))
+    auto *dest = c->push<CFF1StringIndex> ();
+    if (likely (!plan.sidmap.in_error () &&
+               dest->serialize (c, *stringIndex, plan.sidmap.vector)))
       c->pop_pack ();
     else
     {
@@ -842,14 +941,12 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
   cff->offSize = 4; /* unused? */
 
   /* name INDEX */
-  if (unlikely (!(*acc.nameIndex).copy (c))) return false;
+  if (unlikely (!c->embed (*nameIndex))) return false;
 
   /* top dict INDEX */
   {
     /* serialize singleton TopDict */
-    TopDict *top = c->start_embed<TopDict> ();
-    if (!top) return false;
-    c->push ();
+    auto *top = c->push<TopDict> ();
     cff1_top_dict_op_serializer_t topSzr;
     unsigned top_size = 0;
     top_dict_modifiers_t  modifier (plan.info, plan.topDictModSIDs);
@@ -864,36 +961,23 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
       return false;
     }
     /* serialize INDEX header for above */
-    CFF1Index *dest = c->start_embed<CFF1Index> ();
-    if (!dest) return false;
-    return dest->serialize_header (c, hb_iter (hb_array_t<unsigned> (&top_size, 1)));
+    auto *dest = c->start_embed<CFF1Index> ();
+    return dest->serialize_header (c, hb_iter (&top_size, 1), top_size);
   }
 }
 
-static bool
-_hb_subset_cff1 (const OT::cff1::accelerator_subset_t  &acc,
-               hb_subset_context_t     *c)
+bool
+OT::cff1::accelerator_subset_t::subset (hb_subset_context_t *c) const
 {
-  cff_subset_plan cff_plan;
+  cff1_subset_plan cff_plan;
 
-  if (unlikely (!cff_plan.create (acc, c->plan)))
+  if (unlikely (!cff_plan.create (*this, c->plan)))
   {
     DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan.");
     return false;
   }
 
-  return _serialize_cff1 (c->serializer, cff_plan, acc, c->plan->num_output_glyphs ());
-}
-
-bool
-hb_subset_cff1 (hb_subset_context_t *c)
-{
-  OT::cff1::accelerator_subset_t acc;
-  acc.init (c->plan->source);
-  bool result = likely (acc.is_valid ()) && _hb_subset_cff1 (acc, c);
-  acc.fini ();
-
-  return result;
+  return serialize (c->serializer, cff_plan);
 }
 
 
index 92dd6b1..3c52fb9 100644 (file)
@@ -31,7 +31,6 @@
 #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"
@@ -59,7 +58,10 @@ struct cff2_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<>
     switch (opstr.op)
     {
       case OpCode_vstore:
-       return_trace (FontDict::serialize_link4_op(c, opstr.op, info.var_store_link));
+        if (info.var_store_link)
+         return_trace (FontDict::serialize_link4_op(c, opstr.op, info.var_store_link));
+       else
+         return_trace (true);
 
       default:
        return_trace (cff_top_dict_op_serializer_t<>::serialize (c, opstr, info));
@@ -67,9 +69,9 @@ struct cff2_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<>
   }
 };
 
-struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t>
+struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t, blend_arg_t>
 {
-  static void flush_args_and_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param)
+  static void flush_args_and_op (op_code_t op, cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param)
   {
     switch (op)
     {
@@ -97,7 +99,7 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte
     }
   }
 
-  static void flush_args (cff2_cs_interp_env_t &env, flatten_param_t& param)
+  static void flush_args (cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param)
   {
     for (unsigned int i = 0; i < env.argStack.get_count ();)
     {
@@ -115,14 +117,14 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte
       else
       {
        str_encoder_t  encoder (param.flatStr);
-       encoder.encode_num (arg);
+       encoder.encode_num_cs (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)
+  static void flatten_blends (const blend_arg_t &arg, unsigned int i, cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param)
   {
     /* flatten the default values */
     str_encoder_t  encoder (param.flatStr);
@@ -135,21 +137,21 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte
        env.set_error ();
        return;
       }
-      encoder.encode_num (arg1);
+      encoder.encode_num_cs (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]);
+       encoder.encode_num_cs (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)
+  static void flush_op (op_code_t op, cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param)
   {
     switch (op)
     {
@@ -162,14 +164,25 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte
     }
   }
 
+  static void flush_hintmask (op_code_t op, cff2_cs_interp_env_t<blend_arg_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 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;
+  typedef cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t, blend_arg_t> SUPER;
+  typedef cs_opset_t<blend_arg_t, cff2_cs_opset_flatten_t, cff2_cs_opset_flatten_t, cff2_cs_interp_env_t<blend_arg_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>
+struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t, blend_arg_t>
 {
-  static void process_op (op_code_t op, cff2_cs_interp_env_t &env, subr_subset_param_t& param)
+  static void process_op (op_code_t op, cff2_cs_interp_env_t<blend_arg_t> &env, subr_subset_param_t& param)
   {
     switch (op) {
 
@@ -201,7 +214,7 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t
 
   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_cs_interp_env_t<blend_arg_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;
@@ -212,15 +225,15 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t
   }
 
   private:
-  typedef cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t> SUPER;
+  typedef cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t, blend_arg_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>
+struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs, const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t<blend_arg_t>, cff2_cs_opset_subr_subset_t>
 {
   cff2_subr_subsetter_t (const OT::cff2::accelerator_subset_t &acc_, const hb_subset_plan_t *plan_)
     : subr_subsetter_t (acc_, plan_) {}
 
-  static void complete_parsed_str (cff2_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring)
+  static void complete_parsed_str (cff2_cs_interp_env_t<blend_arg_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 ())
@@ -232,20 +245,204 @@ struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs
   }
 };
 
-struct cff2_subset_plan {
+struct cff2_private_blend_encoder_param_t
+{
+  cff2_private_blend_encoder_param_t (hb_serialize_context_t *c,
+                                     const CFF2VariationStore *varStore,
+                                     hb_array_t<int> normalized_coords) :
+    c (c), varStore (varStore), normalized_coords (normalized_coords) {}
+
+  void init () {}
+
+  void process_blend ()
+  {
+    if (!seen_blend)
+    {
+      region_count = varStore->varStore.get_region_index_count (ivs);
+      scalars.resize_exact (region_count);
+      varStore->varStore.get_region_scalars (ivs, normalized_coords.arrayZ, normalized_coords.length,
+                                            &scalars[0], region_count);
+      seen_blend = true;
+    }
+  }
+
+  double blend_deltas (hb_array_t<const number_t> deltas) const
+  {
+    double v = 0;
+    if (likely (scalars.length == deltas.length))
+    {
+      unsigned count = scalars.length;
+      for (unsigned i = 0; i < count; i++)
+       v += (double) scalars.arrayZ[i] * deltas.arrayZ[i].to_real ();
+    }
+    return v;
+  }
+
+
+  hb_serialize_context_t *c = nullptr;
+  bool seen_blend = false;
+  unsigned ivs = 0;
+  unsigned region_count = 0;
+  hb_vector_t<float> scalars;
+  const         CFF2VariationStore *varStore = nullptr;
+  hb_array_t<int> normalized_coords;
+};
+
+struct cff2_private_dict_blend_opset_t : dict_opset_t
+{
+  static void process_arg_blend (cff2_private_blend_encoder_param_t& param,
+                                number_t &arg,
+                                const hb_array_t<const number_t> blends,
+                                unsigned n, unsigned i)
+  {
+    arg.set_int (round (arg.to_real () + param.blend_deltas (blends)));
+  }
+
+  static void process_blend (cff2_priv_dict_interp_env_t& env, cff2_private_blend_encoder_param_t& param)
+  {
+    unsigned int n, k;
+
+    param.process_blend ();
+    k = param.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 number_t> blends = env.argStack.sub_array (start + n + (i * k), k);
+      process_arg_blend (param, env.argStack[start + i], blends, n, i);
+    }
+
+    /* pop off blend values leaving default values now adorned with blend values */
+    env.argStack.pop (k * n);
+  }
+
+  static void process_op (op_code_t op, cff2_priv_dict_interp_env_t& env, cff2_private_blend_encoder_param_t& param)
+  {
+    switch (op) {
+      case OpCode_StdHW:
+      case OpCode_StdVW:
+      case OpCode_BlueScale:
+      case OpCode_BlueShift:
+      case OpCode_BlueFuzz:
+      case OpCode_ExpansionFactor:
+      case OpCode_LanguageGroup:
+      case OpCode_BlueValues:
+      case OpCode_OtherBlues:
+      case OpCode_FamilyBlues:
+      case OpCode_FamilyOtherBlues:
+      case OpCode_StemSnapH:
+      case OpCode_StemSnapV:
+       break;
+      case OpCode_vsindexdict:
+       env.process_vsindex ();
+       param.ivs = env.get_ivs ();
+       env.clear_args ();
+       return;
+      case OpCode_blenddict:
+       process_blend (env, param);
+       return;
+
+      default:
+       dict_opset_t::process_op (op, env);
+       if (!env.argStack.is_empty ()) return;
+       break;
+    }
+
+    if (unlikely (env.in_error ())) return;
+
+    // Write args then op
+
+    str_buff_t str;
+    str_encoder_t encoder (str);
+
+    unsigned count = env.argStack.get_count ();
+    for (unsigned i = 0; i < count; i++)
+      encoder.encode_num_tp (env.argStack[i]);
 
+    encoder.encode_op (op);
+
+    auto bytes = str.as_bytes ();
+    param.c->embed (&bytes, bytes.length);
+
+    env.clear_args ();
+  }
+};
+
+struct cff2_private_dict_op_serializer_t : op_serializer_t
+{
+  cff2_private_dict_op_serializer_t (bool desubroutinize_, bool drop_hints_, bool pinned_,
+                                    const CFF::CFF2VariationStore* varStore_,
+                                    hb_array_t<int> normalized_coords_)
+    : desubroutinize (desubroutinize_), drop_hints (drop_hints_), pinned (pinned_),
+      varStore (varStore_), normalized_coords (normalized_coords_) {}
+
+  bool serialize (hb_serialize_context_t *c,
+                 const op_str_t &opstr,
+                 objidx_t subrs_link) const
+  {
+    TRACE_SERIALIZE (this);
+
+    if (drop_hints && dict_opset_t::is_hint_op (opstr.op))
+      return_trace (true);
+
+    if (opstr.op == OpCode_Subrs)
+    {
+      if (desubroutinize || !subrs_link)
+       return_trace (true);
+      else
+       return_trace (FontDict::serialize_link2_op (c, opstr.op, subrs_link));
+    }
+
+    if (pinned)
+    {
+      // Reinterpret opstr and process blends.
+      cff2_priv_dict_interp_env_t env {hb_ubytes_t (opstr.ptr, opstr.length)};
+      cff2_private_blend_encoder_param_t param (c, varStore, normalized_coords);
+      dict_interpreter_t<cff2_private_dict_blend_opset_t, cff2_private_blend_encoder_param_t, cff2_priv_dict_interp_env_t> interp (env);
+      return_trace (interp.interpret (param));
+    }
+
+    return_trace (copy_opstr (c, opstr));
+  }
+
+  protected:
+  const bool desubroutinize;
+  const bool drop_hints;
+  const bool pinned;
+  const CFF::CFF2VariationStore* varStore;
+  hb_array_t<int> normalized_coords;
+};
+
+
+namespace OT {
+struct cff2_subset_plan
+{
   bool create (const OT::cff2::accelerator_subset_t &acc,
              hb_subset_plan_t *plan)
   {
+    /* make sure notdef is first */
+    hb_codepoint_t old_glyph;
+    if (!plan->old_gid_for_new_gid (0, &old_glyph) || (old_glyph != 0)) return false;
+
+    num_glyphs = plan->num_output_glyphs ();
     orig_fdcount = acc.fdArray->count;
 
     drop_hints = plan->flags & HB_SUBSET_FLAGS_NO_HINTING;
-    desubroutinize = plan->flags & HB_SUBSET_FLAGS_DESUBROUTINIZE;
+    pinned = (bool) plan->normalized_coords;
+    desubroutinize = plan->flags & HB_SUBSET_FLAGS_DESUBROUTINIZE ||
+                    pinned; // For instancing we need this path
 
     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>
+      subr_flattener_t<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t<blend_arg_t>, cff2_cs_opset_flatten_t>
                    flattener(acc, plan);
       if (!flattener.flatten (subset_charstrings))
        return false;
@@ -259,7 +456,7 @@ struct cff2_subset_plan {
        return false;
 
       /* encode charstrings, global subrs, local subrs with new subroutine numbers */
-      if (!subr_subsetter.encode_charstrings (subset_charstrings))
+      if (!subr_subsetter.encode_charstrings (subset_charstrings, !pinned))
        return false;
 
       if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
@@ -297,10 +494,12 @@ struct cff2_subset_plan {
 
   cff2_sub_table_info_t info;
 
+  unsigned int    num_glyphs;
   unsigned int    orig_fdcount = 0;
   unsigned int    subset_fdcount = 1;
-  unsigned int   subset_fdselect_size = 0;
+  unsigned int    subset_fdselect_size = 0;
   unsigned int    subset_fdselect_format = 0;
+  bool            pinned = false;
   hb_vector_t<code_pair_t>   subset_fdselect_ranges;
 
   hb_inc_bimap_t   fdmap;
@@ -312,17 +511,18 @@ struct cff2_subset_plan {
   bool     drop_hints = false;
   bool     desubroutinize = false;
 };
+} // namespace OT
 
-static bool _serialize_cff2 (hb_serialize_context_t *c,
-                            cff2_subset_plan &plan,
-                            const OT::cff2::accelerator_subset_t  &acc,
-                            unsigned int num_glyphs)
+bool
+OT::cff2::accelerator_subset_t::serialize (hb_serialize_context_t *c,
+                                          struct cff2_subset_plan &plan,
+                                          hb_array_t<int> normalized_coords) const
 {
   /* private dicts & local subrs */
   hb_vector_t<table_info_t>  private_dict_infos;
   if (unlikely (!private_dict_infos.resize (plan.subset_fdcount))) return false;
 
-  for (int i = (int)acc.privateDicts.length; --i >= 0 ;)
+  for (int i = (int)privateDicts.length; --i >= 0 ;)
   {
     if (plan.fdmap.has (i))
     {
@@ -330,22 +530,19 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
 
       if (plan.subset_localsubrs[i].length > 0)
       {
-       CFF2Subrs *dest = c->start_embed <CFF2Subrs> ();
-       if (unlikely (!dest)) return false;
-       c->push ();
+       auto *dest = c->push <CFF2Subrs> ();
        if (likely (dest->serialize (c, plan.subset_localsubrs[i])))
-         subrs_link = c->pop_pack ();
+         subrs_link = c->pop_pack (false);
        else
        {
          c->pop_discard ();
          return false;
        }
       }
-      PrivateDict *pd = c->start_embed<PrivateDict> ();
-      if (unlikely (!pd)) return false;
-      c->push ();
-      cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints);
-      if (likely (pd->serialize (c, acc.privateDicts[i], privSzr, subrs_link)))
+      auto *pd = c->push<PrivateDict> ();
+      cff2_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints, plan.pinned,
+                                                varStore, normalized_coords);
+      if (likely (pd->serialize (c, privateDicts[i], privSzr, subrs_link)))
       {
        unsigned fd = plan.fdmap[i];
        private_dict_infos[fd].size = c->length ();
@@ -361,11 +558,16 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
 
   /* CharStrings */
   {
-    CFF2CharStrings  *cs = c->start_embed<CFF2CharStrings> ();
-    if (unlikely (!cs)) return false;
     c->push ();
-    if (likely (cs->serialize (c, plan.subset_charstrings)))
-      plan.info.char_strings_link = c->pop_pack ();
+
+    unsigned data_size = 0;
+    unsigned total_size = CFF2CharStrings::total_size (plan.subset_charstrings, &data_size);
+    if (unlikely (!c->start_zerocopy (total_size)))
+       return false;
+
+    auto *cs = c->start_embed<CFF2CharStrings> ();
+    if (likely (cs->serialize (c, plan.subset_charstrings, &data_size)))
+      plan.info.char_strings_link = c->pop_pack (false);
     else
     {
       c->pop_discard ();
@@ -374,12 +576,13 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
   }
 
   /* FDSelect */
-  if (acc.fdSelect != &Null (CFF2FDSelect))
+  if (fdSelect != &Null (CFF2FDSelect))
   {
     c->push ();
-    if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *(const FDSelect *)acc.fdSelect,                                           plan.orig_fdcount,
-                                           plan.subset_fdselect_format, plan.subset_fdselect_size,
-                                           plan.subset_fdselect_ranges)))
+    if (likely (hb_serialize_cff_fdselect (c, plan.num_glyphs, *(const FDSelect *)fdSelect,
+                                          plan.orig_fdcount,
+                                          plan.subset_fdselect_format, plan.subset_fdselect_size,
+                                          plan.subset_fdselect_ranges)))
       plan.info.fd_select.link = c->pop_pack ();
     else
     {
@@ -390,27 +593,33 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
 
   /* FDArray (FD Index) */
   {
-    c->push ();
-    CFF2FDArray *fda = c->start_embed<CFF2FDArray> ();
-    if (unlikely (!fda)) return false;
+    auto *fda = c->push<CFF2FDArray> ();
     cff_font_dict_op_serializer_t fontSzr;
     auto it =
-    + hb_zip (+ hb_iter (acc.fontDicts)
+    + hb_zip (+ hb_iter (fontDicts)
              | hb_filter ([&] (const cff2_font_dict_values_t &_)
-               { return plan.fdmap.has (&_ - &acc.fontDicts[0]); }),
+               { return plan.fdmap.has (&_ - &fontDicts[0]); }),
              hb_iter (private_dict_infos))
     ;
-    if (unlikely (!fda->serialize (c, it, fontSzr))) return false;
-    plan.info.fd_array_link = c->pop_pack ();
+    if (unlikely (!fda->serialize (c, it, fontSzr)))
+    {
+      c->pop_discard ();
+      return false;
+    }
+    plan.info.fd_array_link = c->pop_pack (false);
   }
 
   /* variation store */
-  if (acc.varStore != &Null (CFF2VariationStore))
+  if (varStore != &Null (CFF2VariationStore) &&
+      !plan.pinned)
   {
-    c->push ();
-    CFF2VariationStore *dest = c->start_embed<CFF2VariationStore> ();
-    if (unlikely (!dest || !dest->serialize (c, acc.varStore))) return false;
-    plan.info.var_store_link = c->pop_pack ();
+    auto *dest = c->push<CFF2VariationStore> ();
+    if (unlikely (!dest->serialize (c, varStore)))
+    {
+      c->pop_discard ();
+      return false;
+    }
+    plan.info.var_store_link = c->pop_pack (false);
   }
 
   OT::cff2 *cff2 = c->allocate_min<OT::cff2> ();
@@ -425,33 +634,25 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
   {
     TopDict &dict = cff2 + cff2->topDict;
     cff2_top_dict_op_serializer_t topSzr;
-    if (unlikely (!dict.serialize (c, acc.topDict, topSzr, plan.info))) return false;
+    if (unlikely (!dict.serialize (c, topDict, topSzr, plan.info))) return false;
     cff2->topDictSize = c->head - (const char *)&dict;
   }
 
   /* global subrs */
   {
-    CFF2Subrs *dest = c->start_embed <CFF2Subrs> ();
-    if (unlikely (!dest)) return false;
+    auto *dest = c->start_embed <CFF2Subrs> ();
     return dest->serialize (c, plan.subset_globalsubrs);
   }
 }
 
-static bool
-_hb_subset_cff2 (const OT::cff2::accelerator_subset_t  &acc,
-                hb_subset_context_t    *c)
+bool
+OT::cff2::accelerator_subset_t::subset (hb_subset_context_t *c) const
 {
   cff2_subset_plan cff2_plan;
 
-  if (unlikely (!cff2_plan.create (acc, c->plan))) return false;
-  return _serialize_cff2 (c->serializer, cff2_plan, acc, c->plan->num_output_glyphs ());
-}
-
-bool
-hb_subset_cff2 (hb_subset_context_t *c)
-{
-  OT::cff2::accelerator_subset_t acc (c->plan->source);
-  return acc.is_valid () && _hb_subset_cff2 (acc, c);
+  if (unlikely (!cff2_plan.create (*this, c->plan))) return false;
+  return serialize (c->serializer, cff2_plan,
+                   c->plan->normalized_coords.as_array ());
 }
 
 #endif
index 4885280..0277d3d 100644 (file)
 
 #include "hb-subset.hh"
 #include "hb-set.hh"
+#include "hb-utf.hh"
 
-/**
- * hb_subset_input_create_or_fail:
- *
- * Creates a new subset input object.
- *
- * Return value: (transfer full): New subset input, or %NULL if failed. Destroy
- * with hb_subset_input_destroy().
- *
- * Since: 1.8.0
- **/
-hb_subset_input_t *
-hb_subset_input_create_or_fail (void)
-{
-  hb_subset_input_t *input = hb_object_create<hb_subset_input_t>();
 
-  if (unlikely (!input))
-    return nullptr;
-
-  for (auto& set : input->sets_iter ())
-    set = hb_set_create ();
+hb_subset_input_t::hb_subset_input_t ()
+{
+  for (auto& set : sets_iter ())
+    set = hb::shared_ptr<hb_set_t> (hb_set_create ());
 
-  if (input->in_error ())
-  {
-    hb_subset_input_destroy (input);
-    return nullptr;
-  }
+  if (in_error ())
+    return;
 
-  input->flags = HB_SUBSET_FLAGS_DEFAULT;
+  flags = HB_SUBSET_FLAGS_DEFAULT;
 
-  hb_set_add_range (input->sets.name_ids, 0, 6);
-  hb_set_add (input->sets.name_languages, 0x0409);
+  hb_set_add_range (sets.name_ids, 0, 6);
+  hb_set_add (sets.name_languages, 0x0409);
 
   hb_tag_t default_drop_tables[] = {
     // Layout disabled by default
@@ -83,23 +66,17 @@ hb_subset_input_create_or_fail (void)
     HB_TAG ('S', 'i', 'l', 'f'),
     HB_TAG ('S', 'i', 'l', 'l'),
   };
-  input->sets.drop_tables->add_array (default_drop_tables, ARRAY_LENGTH (default_drop_tables));
+  sets.drop_tables->add_array (default_drop_tables, ARRAY_LENGTH (default_drop_tables));
 
   hb_tag_t default_no_subset_tables[] = {
-    HB_TAG ('a', 'v', 'a', 'r'),
-    HB_TAG ('f', 'v', 'a', 'r'),
     HB_TAG ('g', 'a', 's', 'p'),
-    HB_TAG ('c', 'v', 't', ' '),
     HB_TAG ('f', 'p', 'g', 'm'),
     HB_TAG ('p', 'r', 'e', 'p'),
     HB_TAG ('V', 'D', 'M', 'X'),
     HB_TAG ('D', 'S', 'I', 'G'),
-    HB_TAG ('M', 'V', 'A', 'R'),
-    HB_TAG ('c', 'v', 'a', 'r'),
-    HB_TAG ('S', 'T', 'A', 'T'),
   };
-  input->sets.no_subset_tables->add_array (default_no_subset_tables,
-                                         ARRAY_LENGTH (default_no_subset_tables));
+  sets.no_subset_tables->add_array (default_no_subset_tables,
+                                        ARRAY_LENGTH (default_no_subset_tables));
 
   //copied from _layout_features_groups in fonttools
   hb_tag_t default_layout_features[] = {
@@ -140,7 +117,20 @@ hb_subset_input_create_or_fail (void)
     HB_TAG ('r', 't', 'l', 'a'),
     HB_TAG ('r', 't', 'l', 'm'),
 
-    //Complex shapers
+    //random
+    HB_TAG ('r', 'a', 'n', 'd'),
+
+    //justify
+    HB_TAG ('j', 'a', 'l', 't'), // HarfBuzz doesn't use; others might
+
+    //private
+    HB_TAG ('H', 'a', 'r', 'f'),
+    HB_TAG ('H', 'A', 'R', 'F'),
+    HB_TAG ('B', 'u', 'z', 'z'),
+    HB_TAG ('B', 'U', 'Z', 'Z'),
+
+    //shapers
+
     //arabic
     HB_TAG ('i', 'n', 'i', 't'),
     HB_TAG ('m', 'e', 'd', 'i'),
@@ -188,13 +178,35 @@ hb_subset_input_create_or_fail (void)
     HB_TAG ('b', 'l', 'w', 'm'),
   };
 
-  input->sets.layout_features->add_array (default_layout_features, ARRAY_LENGTH (default_layout_features));
+  sets.layout_features->add_array (default_layout_features, ARRAY_LENGTH (default_layout_features));
+
+  sets.layout_scripts->invert (); // Default to all scripts.
+}
+
+/**
+ * hb_subset_input_create_or_fail:
+ *
+ * Creates a new subset input object.
+ *
+ * Return value: (transfer full): New subset input, or `NULL` if failed. Destroy
+ * with hb_subset_input_destroy().
+ *
+ * Since: 1.8.0
+ **/
+hb_subset_input_t *
+hb_subset_input_create_or_fail (void)
+{
+  hb_subset_input_t *input = hb_object_create<hb_subset_input_t>();
+
+  if (unlikely (!input))
+    return nullptr;
 
   if (input->in_error ())
   {
     hb_subset_input_destroy (input);
     return nullptr;
   }
+
   return input;
 }
 
@@ -228,9 +240,6 @@ hb_subset_input_destroy (hb_subset_input_t *input)
 {
   if (!hb_object_destroy (input)) return;
 
-  for (hb_set_t* set : input->sets_iter ())
-    hb_set_destroy (set);
-
   hb_free (input);
 }
 
@@ -329,7 +338,7 @@ hb_subset_input_set_flags (hb_subset_input_t *input,
  *
  * Attaches a user-data key/data pair to the given subset input object.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 2.9.0
  **/
@@ -361,3 +370,302 @@ hb_subset_input_get_user_data (const hb_subset_input_t *input,
 {
   return hb_object_get_user_data (input, key);
 }
+
+/**
+ * hb_subset_input_keep_everything:
+ * @input: a #hb_subset_input_t object
+ *
+ * Configure input object to keep everything in the font face.
+ * That is, all Unicodes, glyphs, names, layout items,
+ * glyph names, etc.
+ *
+ * The input can be tailored afterwards by the caller.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_subset_input_keep_everything (hb_subset_input_t *input)
+{
+  const hb_subset_sets_t indices[] = {HB_SUBSET_SETS_UNICODE,
+                                     HB_SUBSET_SETS_GLYPH_INDEX,
+                                     HB_SUBSET_SETS_NAME_ID,
+                                     HB_SUBSET_SETS_NAME_LANG_ID,
+                                     HB_SUBSET_SETS_LAYOUT_FEATURE_TAG,
+                                     HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG};
+
+  for (auto idx : hb_iter (indices))
+  {
+    hb_set_t *set = hb_subset_input_set (input, idx);
+    hb_set_clear (set);
+    hb_set_invert (set);
+  }
+
+  // Don't drop any tables
+  hb_set_clear (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG));
+
+  hb_subset_input_set_flags (input,
+                            HB_SUBSET_FLAGS_NOTDEF_OUTLINE |
+                            HB_SUBSET_FLAGS_GLYPH_NAMES |
+                            HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES |
+                             HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED);
+}
+
+#ifndef HB_NO_VAR
+/**
+ * hb_subset_input_pin_axis_to_default: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @face: a #hb_face_t object.
+ * @axis_tag: Tag of the axis to be pinned
+ *
+ * Pin an axis to its default location in the given subset input object.
+ *
+ * All axes in a font must be pinned. Additionally, `CFF2` table, if present,
+ * will be de-subroutinized.
+ *
+ * Return value: `true` if success, `false` otherwise
+ *
+ * Since: 6.0.0
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_pin_axis_to_default (hb_subset_input_t  *input,
+                                     hb_face_t          *face,
+                                     hb_tag_t            axis_tag)
+{
+  hb_ot_var_axis_info_t axis_info;
+  if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
+    return false;
+
+  float default_val = axis_info.default_value;
+  return input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val));
+}
+
+/**
+ * hb_subset_input_pin_axis_location: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @face: a #hb_face_t object.
+ * @axis_tag: Tag of the axis to be pinned
+ * @axis_value: Location on the axis to be pinned at
+ *
+ * Pin an axis to a fixed location in the given subset input object.
+ *
+ * All axes in a font must be pinned. Additionally, `CFF2` table, if present,
+ * will be de-subroutinized.
+ *
+ * Return value: `true` if success, `false` otherwise
+ *
+ * Since: 6.0.0
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_pin_axis_location (hb_subset_input_t  *input,
+                                   hb_face_t          *face,
+                                   hb_tag_t            axis_tag,
+                                   float               axis_value)
+{
+  hb_ot_var_axis_info_t axis_info;
+  if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
+    return false;
+
+  float val = hb_clamp(axis_value, axis_info.min_value, axis_info.max_value);
+  return input->axes_location.set (axis_tag, Triple (val, val, val));
+}
+
+#ifdef HB_EXPERIMENTAL_API
+/**
+ * hb_subset_input_set_axis_range: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @face: a #hb_face_t object.
+ * @axis_tag: Tag of the axis
+ * @axis_min_value: Minimum value of the axis variation range to set
+ * @axis_max_value: Maximum value of the axis variation range to set
+ * @axis_def_value: Default value of the axis variation range to set, in case of
+ * null, it'll be determined automatically
+ *
+ * Restricting the range of variation on an axis in the given subset input object.
+ * New min/default/max values will be clamped if they're not within the fvar axis range.
+ * If the new default value is null:
+ * If the fvar axis default value is within the new range, then new default
+ * value is the same as original default value.
+ * If the fvar axis default value is not within the new range, the new default
+ * value will be changed to the new min or max value, whichever is closer to the fvar
+ * axis default.
+ *
+ * Note: input min value can not be bigger than input max value. If the input
+ * default value is not within the new min/max range, it'll be clamped.
+ * Note: currently it supports gvar and cvar tables only.
+ *
+ * Return value: `true` if success, `false` otherwise
+ *
+ * XSince: EXPERIMENTAL
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_set_axis_range (hb_subset_input_t  *input,
+                                hb_face_t          *face,
+                                hb_tag_t            axis_tag,
+                                float               axis_min_value,
+                                float               axis_max_value,
+                                float              *axis_def_value /* IN, maybe NULL */)
+{
+  if (axis_min_value > axis_max_value)
+    return false;
+
+  hb_ot_var_axis_info_t axis_info;
+  if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
+    return false;
+
+  float new_min_val = hb_clamp(axis_min_value, axis_info.min_value, axis_info.max_value);
+  float new_max_val = hb_clamp(axis_max_value, axis_info.min_value, axis_info.max_value);
+  float new_default_val = axis_def_value ? *axis_def_value : axis_info.default_value;
+  new_default_val = hb_clamp(new_default_val, new_min_val, new_max_val);
+  return input->axes_location.set (axis_tag, Triple (new_min_val, new_default_val, new_max_val));
+}
+#endif
+#endif
+
+/**
+ * hb_subset_preprocess:
+ * @source: a #hb_face_t object.
+ *
+ * Preprocesses the face and attaches data that will be needed by the
+ * subsetter. Future subsetting operations can then use the precomputed data
+ * to speed up the subsetting operation.
+ *
+ * See [subset-preprocessing](https://github.com/harfbuzz/harfbuzz/blob/main/docs/subset-preprocessing.md)
+ * for more information.
+ *
+ * Note: the preprocessed face may contain sub-blobs that reference the memory
+ * backing the source #hb_face_t. Therefore in the case that this memory is not
+ * owned by the source face you will need to ensure that memory lives
+ * as long as the returned #hb_face_t.
+ *
+ * Returns: a new #hb_face_t.
+ *
+ * Since: 6.0.0
+ **/
+
+HB_EXTERN hb_face_t *
+hb_subset_preprocess (hb_face_t *source)
+{
+  hb_subset_input_t* input = hb_subset_input_create_or_fail ();
+  if (!input)
+    return hb_face_reference (source);
+
+  hb_subset_input_keep_everything (input);
+
+  input->attach_accelerator_data = true;
+
+  // Always use long loca in the preprocessed version. This allows
+  // us to store the glyph bytes unpadded which allows the future subset
+  // operation to run faster by skipping the trim padding step.
+  input->force_long_loca = true;
+
+  hb_face_t* new_source = hb_subset_or_fail (source, input);
+  hb_subset_input_destroy (input);
+
+  if (!new_source) {
+    DEBUG_MSG (SUBSET, nullptr, "Preprocessing failed due to subset failure.");
+    return hb_face_reference (source);
+  }
+
+  return new_source;
+}
+
+/**
+ * hb_subset_input_old_to_new_glyph_mapping:
+ * @input: a #hb_subset_input_t object.
+ *
+ * Returns a map which can be used to provide an explicit mapping from old to new glyph
+ * id's in the produced subset. The caller should populate the map as desired.
+ * If this map is left empty then glyph ids will be automatically mapped to new
+ * values by the subsetter. If populated, the mapping must be unique. That
+ * is no two original glyph ids can be mapped to the same new id.
+ * Additionally, if a mapping is provided then the retain gids option cannot
+ * be enabled.
+ *
+ * Any glyphs that are retained in the subset which are not specified
+ * in this mapping will be assigned glyph ids after the highest glyph
+ * id in the mapping.
+ *
+ * Note: this will accept and apply non-monotonic mappings, however this
+ * may result in unsorted Coverage tables. Such fonts may not work for all
+ * use cases (for example ots will reject unsorted coverage tables). So it's
+ * recommended, if possible, to supply a monotonic mapping.
+ *
+ * Return value: (transfer none): pointer to the #hb_map_t of the custom glyphs ID map.
+ *
+ * Since: 7.3.0
+ **/
+HB_EXTERN hb_map_t*
+hb_subset_input_old_to_new_glyph_mapping (hb_subset_input_t *input)
+{
+  return &input->glyph_map;
+}
+
+#ifdef HB_EXPERIMENTAL_API
+/**
+ * hb_subset_input_override_name_table:
+ * @input: a #hb_subset_input_t object.
+ * @name_id: name_id of a nameRecord
+ * @platform_id: platform ID of a nameRecord
+ * @encoding_id: encoding ID of a nameRecord
+ * @language_id: language ID of a nameRecord
+ * @name_str: pointer to name string new value or null to indicate should remove
+ * @str_len: the size of @name_str, or -1 if it is `NULL`-terminated
+ *
+ * Override the name string of the NameRecord identified by name_id,
+ * platform_id, encoding_id and language_id. If a record with that name_id
+ * doesn't exist, create it and insert to the name table.
+ *
+ * Note: for mac platform, we only support name_str with all ascii characters,
+ * name_str with non-ascii characters will be ignored.
+ *
+ * XSince: EXPERIMENTAL
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_override_name_table (hb_subset_input_t  *input,
+                                     hb_ot_name_id_t     name_id,
+                                     unsigned            platform_id,
+                                     unsigned            encoding_id,
+                                     unsigned            language_id,
+                                     const char         *name_str,
+                                     int                 str_len /* -1 means nul-terminated */)
+{
+  if (!name_str)
+  {
+    str_len = 0;
+  }
+  else if (str_len == -1)
+  {
+      str_len = strlen (name_str);
+  }
+
+  hb_bytes_t name_bytes (nullptr, 0);
+  if (str_len)
+  {
+    if (platform_id == 1)
+    {
+      const uint8_t *src = reinterpret_cast<const uint8_t*> (name_str);
+      const uint8_t *src_end = src + str_len;
+
+      hb_codepoint_t unicode;
+      const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
+      while (src < src_end)
+      {
+        src = hb_utf8_t::next (src, src_end, &unicode, replacement);
+        if (unicode >= 0x0080u)
+        {
+          printf ("Non-ascii character detected, ignored...This API supports acsii characters only for mac platform\n");
+          return false;
+        }
+      }
+    }
+    char *override_name = (char *) hb_malloc (str_len);
+    if (unlikely (!override_name)) return false;
+
+    hb_memcpy (override_name, name_str, str_len);
+    name_bytes = hb_bytes_t (override_name, str_len);
+  }
+  input->name_table_overrides.set (hb_ot_name_record_ids_t (platform_id, encoding_id, language_id, name_id), name_bytes);
+  return true;
+}
+
+#endif
index 07c0e22..6ae311e 100644 (file)
 #include "hb-subset.h"
 #include "hb-map.hh"
 #include "hb-set.hh"
-
+#include "hb-cplusplus.hh"
 #include "hb-font.hh"
+#include "hb-subset-instancer-solver.hh"
+
+struct hb_ot_name_record_ids_t
+{
+  hb_ot_name_record_ids_t () = default;
+  hb_ot_name_record_ids_t (unsigned platform_id_,
+                           unsigned encoding_id_,
+                           unsigned language_id_,
+                           unsigned name_id_)
+      :platform_id (platform_id_),
+      encoding_id (encoding_id_),
+      language_id (language_id_),
+      name_id (name_id_) {}
+
+  bool operator != (const hb_ot_name_record_ids_t o) const
+  { return !(*this == o); }
+
+  inline bool operator == (const hb_ot_name_record_ids_t& o) const
+  {
+    return platform_id == o.platform_id &&
+           encoding_id == o.encoding_id &&
+           language_id == o.language_id &&
+           name_id == o.name_id;
+  }
+
+  inline uint32_t hash () const
+  {
+    uint32_t current = 0;
+    current = current * 31 + hb_hash (platform_id);
+    current = current * 31 + hb_hash (encoding_id);
+    current = current * 31 + hb_hash (language_id);
+    current = current * 31 + hb_hash (name_id);
+    return current;
+  }
+
+  unsigned platform_id;
+  unsigned encoding_id;
+  unsigned language_id;
+  unsigned name_id;
+};
+
+typedef struct hb_ot_name_record_ids_t hb_ot_name_record_ids_t;
+
 
 HB_MARK_AS_FLAG_T (hb_subset_flags_t);
 
 struct hb_subset_input_t
 {
+  HB_INTERNAL hb_subset_input_t ();
+
+  ~hb_subset_input_t ()
+  {
+    sets.~sets_t ();
+
+#ifdef HB_EXPERIMENTAL_API
+    for (auto _ : name_table_overrides.values ())
+      _.fini ();
+#endif
+  }
+
   hb_object_header_t header;
 
   struct sets_t {
-    hb_set_t *glyphs;
-    hb_set_t *unicodes;
-    hb_set_t *no_subset_tables;
-    hb_set_t *drop_tables;
-    hb_set_t *name_ids;
-    hb_set_t *name_languages;
-    hb_set_t *layout_features;
+    hb::shared_ptr<hb_set_t> glyphs;
+    hb::shared_ptr<hb_set_t> unicodes;
+    hb::shared_ptr<hb_set_t> no_subset_tables;
+    hb::shared_ptr<hb_set_t> drop_tables;
+    hb::shared_ptr<hb_set_t> name_ids;
+    hb::shared_ptr<hb_set_t> name_languages;
+    hb::shared_ptr<hb_set_t> layout_features;
+    hb::shared_ptr<hb_set_t> layout_scripts;
   };
 
   union {
     sets_t sets;
-    hb_set_t* set_ptrs[sizeof (sets_t) / sizeof (hb_set_t*)];
+    hb::shared_ptr<hb_set_t> set_ptrs[sizeof (sets_t) / sizeof (hb_set_t*)];
   };
 
   unsigned flags;
+  bool attach_accelerator_data = false;
+
+  // If set loca format will always be the long version.
+  bool force_long_loca = false;
+
+  hb_hashmap_t<hb_tag_t, Triple> axes_location;
+  hb_map_t glyph_map;
+#ifdef HB_EXPERIMENTAL_API
+  hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> name_table_overrides;
+#endif
 
   inline unsigned num_sets () const
   {
     return sizeof (set_ptrs) / sizeof (hb_set_t*);
   }
 
-  inline hb_array_t<hb_set_t*> sets_iter ()
+  inline hb_array_t<hb::shared_ptr<hb_set_t>> sets_iter ()
   {
-    return hb_array_t<hb_set_t*> (set_ptrs, num_sets ());
+    return hb_array (set_ptrs);
   }
 
   bool in_error () const
@@ -76,7 +142,12 @@ struct hb_subset_input_t
       if (unlikely (set_ptrs[i]->in_error ()))
         return true;
     }
-    return false;
+
+    return axes_location.in_error ()
+#ifdef HB_EXPERIMENTAL_API
+       || name_table_overrides.in_error ()
+#endif
+       ;
   }
 };
 
diff --git a/src/hb-subset-instancer-solver.cc b/src/hb-subset-instancer-solver.cc
new file mode 100644 (file)
index 0000000..4cb3f8a
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ * Copyright © 2023  Behdad Esfahbod
+ *
+ *  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-subset-instancer-solver.hh"
+
+/* This file is a straight port of the following:
+ *
+ * https://github.com/fonttools/fonttools/blob/f73220816264fc383b8a75f2146e8d69e455d398/Lib/fontTools/varLib/instancer/solver.py
+ *
+ * Where that file returns None for a triple, we return Triple{}.
+ * This should be safe.
+ */
+
+constexpr static float EPSILON = 1.f / (1 << 14);
+constexpr static float MAX_F2DOT14 = float (0x7FFF) / (1 << 14);
+
+static inline Triple _reverse_negate(const Triple &v)
+{ return {-v.maximum, -v.middle, -v.minimum}; }
+
+
+static inline float supportScalar (float coord, const Triple &tent)
+{
+  /* Copied from VarRegionAxis::evaluate() */
+  float start = tent.minimum, peak = tent.middle, end = tent.maximum;
+
+  if (unlikely (start > peak || peak > end))
+    return 1.;
+  if (unlikely (start < 0 && end > 0 && peak != 0))
+    return 1.;
+
+  if (peak == 0 || coord == peak)
+    return 1.;
+
+  if (coord <= start || end <= coord)
+    return 0.;
+
+  /* Interpolate */
+  if (coord < peak)
+    return (coord - start) / (peak - start);
+  else
+    return  (end - coord) / (end - peak);
+}
+
+static inline result_t
+_solve (Triple tent, Triple axisLimit, bool negative = false)
+{
+  float axisMin = axisLimit.minimum;
+  float axisDef = axisLimit.middle;
+  float axisMax = axisLimit.maximum;
+  float lower = tent.minimum;
+  float peak  = tent.middle;
+  float upper = tent.maximum;
+
+  // Mirror the problem such that axisDef <= peak
+  if (axisDef > peak)
+  {
+    result_t vec = _solve (_reverse_negate (tent),
+                          _reverse_negate (axisLimit),
+                          !negative);
+
+    for (auto &p : vec)
+      p = hb_pair (p.first, _reverse_negate (p.second));
+
+    return vec;
+  }
+  // axisDef <= peak
+
+  /* case 1: The whole deltaset falls outside the new limit; we can drop it
+   *
+   *                                          peak
+   *  1.........................................o..........
+   *                                           / \
+   *                                          /   \
+   *                                         /     \
+   *                                        /       \
+   *  0---|-----------|----------|-------- o         o----1
+   *    axisMin     axisDef    axisMax   lower     upper
+   */
+  if (axisMax <= lower && axisMax < peak)
+      return result_t{};  // No overlap
+
+  /* case 2: Only the peak and outermost bound fall outside the new limit;
+   * we keep the deltaset, update peak and outermost bound and scale deltas
+   * by the scalar value for the restricted axis at the new limit, and solve
+   * recursively.
+   *
+   *                                  |peak
+   *  1...............................|.o..........
+   *                                  |/ \
+   *                                  /   \
+   *                                 /|    \
+   *                                / |     \
+   *  0--------------------------- o  |      o----1
+   *                           lower  |      upper
+   *                                  |
+   *                                axisMax
+   *
+   * Convert to:
+   *
+   *  1............................................
+   *                                  |
+   *                                  o peak
+   *                                 /|
+   *                                /x|
+   *  0--------------------------- o  o upper ----1
+   *                           lower  |
+   *                                  |
+   *                                axisMax
+   */
+  if (axisMax < peak)
+  {
+    float mult = supportScalar (axisMax, tent);
+    tent = Triple{lower, axisMax, axisMax};
+
+    result_t vec = _solve (tent, axisLimit);
+
+    for (auto &p : vec)
+      p = hb_pair (p.first * mult, p.second);
+
+    return vec;
+  }
+
+  // lower <= axisDef <= peak <= axisMax
+
+  float gain = supportScalar (axisDef, tent);
+  result_t out {hb_pair (gain, Triple{})};
+
+  // First, the positive side
+
+  // outGain is the scalar of axisMax at the tent.
+  float outGain = supportScalar (axisMax, tent);
+
+  /* Case 3a: Gain is more than outGain. The tent down-slope crosses
+   * the axis into negative. We have to split it into multiples.
+   *
+   *                      | peak  |
+   *  1...................|.o.....|..............
+   *                      |/x\_   |
+   *  gain................+....+_.|..............
+   *                     /|    |y\|
+   *  ................../.|....|..+_......outGain
+   *                   /  |    |  | \
+   *  0---|-----------o   |    |  |  o----------1
+   *    axisMin    lower  |    |  |   upper
+   *                      |    |  |
+   *                axisDef    |  axisMax
+   *                           |
+   *                      crossing
+   */
+  if (gain > outGain)
+  {
+    // Crossing point on the axis.
+    float crossing = peak + (1 - gain) * (upper - peak);
+
+    Triple loc{axisDef, peak, crossing};
+    float scalar = 1.f;
+
+    // The part before the crossing point.
+    out.push (hb_pair (scalar - gain, loc));
+
+    /* The part after the crossing point may use one or two tents,
+     * depending on whether upper is before axisMax or not, in one
+     * case we need to keep it down to eternity.
+     *
+     * Case 3a1, similar to case 1neg; just one tent needed, as in
+     * the drawing above.
+     */
+    if (upper >= axisMax)
+    {
+      Triple loc {crossing, axisMax, axisMax};
+      float scalar = outGain;
+
+      out.push (hb_pair (scalar - gain, loc));
+    }
+
+    /* Case 3a2: Similar to case 2neg; two tents needed, to keep
+     * down to eternity.
+     *
+     *                      | peak             |
+     *  1...................|.o................|...
+     *                      |/ \_              |
+     *  gain................+....+_............|...
+     *                     /|    | \xxxxxxxxxxy|
+     *                    / |    |  \_xxxxxyyyy|
+     *                   /  |    |    \xxyyyyyy|
+     *  0---|-----------o   |    |     o-------|--1
+     *    axisMin    lower  |    |      upper  |
+     *                      |    |             |
+     *                axisDef    |             axisMax
+     *                           |
+     *                      crossing
+     */
+    else
+    {
+      // A tent's peak cannot fall on axis default. Nudge it.
+      if (upper == axisDef)
+       upper += EPSILON;
+
+      // Downslope.
+      Triple loc1 {crossing, upper, axisMax};
+      float scalar1 = 0.f;
+
+      // Eternity justify.
+      Triple loc2 {upper, axisMax, axisMax};
+      float scalar2 = 0.f;
+
+      out.push (hb_pair (scalar1 - gain, loc1));
+      out.push (hb_pair (scalar2 - gain, loc2));
+    }
+  }
+
+  else
+  {
+    // Special-case if peak is at axisMax.
+    if (axisMax == peak)
+       upper = peak;
+
+    /* Case 3:
+     * we keep deltas as is and only scale the axis upper to achieve
+     * the desired new tent if feasible.
+     *
+     *                        peak
+     *  1.....................o....................
+     *                       / \_|
+     *  ..................../....+_.........outGain
+     *                     /     | \
+     *  gain..............+......|..+_.............
+     *                   /|      |  | \
+     *  0---|-----------o |      |  |  o----------1
+     *    axisMin    lower|      |  |   upper
+     *                    |      |  newUpper
+     *              axisDef      axisMax
+     */
+    float newUpper = peak + (1 - gain) * (upper - peak);
+    assert (axisMax <= newUpper);  // Because outGain >= gain
+    if (newUpper <= axisDef + (axisMax - axisDef) * 2)
+    {
+      upper = newUpper;
+      if (!negative && axisDef + (axisMax - axisDef) * MAX_F2DOT14 < upper)
+      {
+       // we clamp +2.0 to the max F2Dot14 (~1.99994) for convenience
+       upper = axisDef + (axisMax - axisDef) * MAX_F2DOT14;
+       assert (peak < upper);
+      }
+
+      Triple loc {hb_max (axisDef, lower), peak, upper};
+      float scalar = 1.f;
+
+      out.push (hb_pair (scalar - gain, loc));
+    }
+
+    /* Case 4: New limit doesn't fit; we need to chop into two tents,
+     * because the shape of a triangle with part of one side cut off
+     * cannot be represented as a triangle itself.
+     *
+     *            |   peak |
+     *  1.........|......o.|....................
+     *  ..........|...../x\|.............outGain
+     *            |    |xxy|\_
+     *            |   /xxxy|  \_
+     *            |  |xxxxy|    \_
+     *            |  /xxxxy|      \_
+     *  0---|-----|-oxxxxxx|        o----------1
+     *    axisMin | lower  |        upper
+     *            |        |
+     *          axisDef  axisMax
+     */
+    else
+    {
+      Triple loc1 {hb_max (axisDef, lower), peak, axisMax};
+      float scalar1 = 1.f;
+
+      Triple loc2 {peak, axisMax, axisMax};
+      float scalar2 = outGain;
+
+      out.push (hb_pair (scalar1 - gain, loc1));
+      // Don't add a dirac delta!
+      if (peak < axisMax)
+       out.push (hb_pair (scalar2 - gain, loc2));
+    }
+  }
+
+  /* Now, the negative side
+   *
+   * Case 1neg: Lower extends beyond axisMin: we chop. Simple.
+   *
+   *                     |   |peak
+   *  1..................|...|.o.................
+   *                     |   |/ \
+   *  gain...............|...+...\...............
+   *                     |x_/|    \
+   *                     |/  |     \
+   *                   _/|   |      \
+   *  0---------------o  |   |       o----------1
+   *              lower  |   |       upper
+   *                     |   |
+   *               axisMin   axisDef
+   */
+  if (lower <= axisMin)
+  {
+    Triple loc {axisMin, axisMin, axisDef};
+    float scalar = supportScalar (axisMin, tent);
+
+    out.push (hb_pair (scalar - gain, loc));
+  }
+
+  /* Case 2neg: Lower is betwen axisMin and axisDef: we add two
+   * tents to keep it down all the way to eternity.
+   *
+   *      |               |peak
+   *  1...|...............|.o.................
+   *      |               |/ \
+   *  gain|...............+...\...............
+   *      |yxxxxxxxxxxxxx/|    \
+   *      |yyyyyyxxxxxxx/ |     \
+   *      |yyyyyyyyyyyx/  |      \
+   *  0---|-----------o   |       o----------1
+   *    axisMin    lower  |       upper
+   *                      |
+   *                    axisDef
+   */
+  else
+  {
+    // A tent's peak cannot fall on axis default. Nudge it.
+    if (lower == axisDef)
+      lower -= EPSILON;
+
+    // Downslope.
+    Triple loc1 {axisMin, lower, axisDef};
+    float scalar1 = 0.f;
+
+    // Eternity justify.
+    Triple loc2 {axisMin, axisMin, lower};
+    float scalar2 = 0.f;
+
+    out.push (hb_pair (scalar1 - gain, loc1));
+    out.push (hb_pair (scalar2 - gain, loc2));
+  }
+
+  return out;
+}
+
+static inline TripleDistances _reverse_triple_distances (const TripleDistances &v)
+{ return TripleDistances (v.positive, v.negative); }
+
+float renormalizeValue (float v, const Triple &triple,
+                        const TripleDistances &triple_distances, bool extrapolate)
+{
+  float lower = triple.minimum, def = triple.middle, upper = triple.maximum;
+  assert (lower <= def && def <= upper);
+
+  if (!extrapolate)
+      v = hb_max (hb_min (v, upper), lower);
+
+  if (v == def)
+    return 0.f;
+
+  if (def < 0.f)
+    return -renormalizeValue (-v, _reverse_negate (triple),
+                              _reverse_triple_distances (triple_distances), extrapolate);
+
+  /* default >= 0 and v != default */
+  if (v > def)
+    return (v - def) / (upper - def);
+
+  /* v < def */
+  if (lower >= 0.f)
+    return (v - def) / (def - lower);
+
+  /* lower < 0 and v < default */
+  float total_distance = triple_distances.negative * (-lower) + triple_distances.positive * def;
+
+  float v_distance;
+  if (v >= 0.f)
+    v_distance = (def - v) * triple_distances.positive;
+  else
+    v_distance = (-v) * triple_distances.negative + triple_distances.positive * def;
+
+  return (-v_distance) /total_distance;
+}
+
+result_t
+rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances)
+{
+  assert (-1.f <= axisLimit.minimum && axisLimit.minimum <= axisLimit.middle && axisLimit.middle <= axisLimit.maximum && axisLimit.maximum <= +1.f);
+  assert (-2.f <= tent.minimum && tent.minimum <= tent.middle && tent.middle <= tent.maximum && tent.maximum <= +2.f);
+  assert (tent.middle != 0.f);
+
+  result_t sols = _solve (tent, axisLimit);
+
+  auto n = [&axisLimit, &axis_triple_distances] (float v) { return renormalizeValue (v, axisLimit, axis_triple_distances); };
+
+  result_t out;
+  for (auto &p : sols)
+  {
+    if (!p.first) continue;
+    if (p.second == Triple{})
+    {
+      out.push (p);
+      continue;
+    }
+    Triple t = p.second;
+    out.push (hb_pair (p.first,
+                      Triple{n (t.minimum), n (t.middle), n (t.maximum)}));
+  }
+
+  return out;
+}
diff --git a/src/hb-subset-instancer-solver.hh b/src/hb-subset-instancer-solver.hh
new file mode 100644 (file)
index 0000000..563fccb
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright © 2023  Behdad Esfahbod
+ *
+ *  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_SUBSET_INSTANCER_SOLVER_HH
+#define HB_SUBSET_INSTANCER_SOLVER_HH
+
+#include "hb.hh"
+
+/* pre-normalized distances */
+struct TripleDistances
+{
+  TripleDistances (): negative (1.f), positive (1.f) {}
+  TripleDistances (float neg_, float pos_): negative (neg_), positive (pos_) {}
+  TripleDistances (float min, float default_, float max)
+  {
+    negative = default_ - min;
+    positive = max - default_;
+  }
+
+  float negative;
+  float positive;
+};
+
+struct Triple {
+
+  Triple () :
+    minimum (0.f), middle (0.f), maximum (0.f) {}
+
+  Triple (float minimum_, float middle_, float maximum_) :
+    minimum (minimum_), middle (middle_), maximum (maximum_) {}
+
+  bool operator == (const Triple &o) const
+  {
+    return minimum == o.minimum &&
+          middle  == o.middle  &&
+          maximum == o.maximum;
+  }
+
+  bool operator != (const Triple o) const
+  { return !(*this == o); }
+
+  bool is_point () const
+  { return minimum == middle && middle == maximum; }
+
+  bool contains (float point) const
+  { return minimum <= point && point <= maximum; }
+
+  /* from hb_array_t hash ()*/
+  uint32_t hash () const
+  {
+    uint32_t current = /*cbf29ce4*/0x84222325;
+    current = current ^ hb_hash (minimum);
+    current = current * 16777619;
+
+    current = current ^ hb_hash (middle);
+    current = current * 16777619;
+
+    current = current ^ hb_hash (maximum);
+    current = current * 16777619;
+    return current;
+  }
+
+
+  float minimum;
+  float middle;
+  float maximum;
+};
+
+using result_item_t = hb_pair_t<float, Triple>;
+using result_t = hb_vector_t<result_item_t>;
+
+/* renormalize a normalized value v to the range of an axis,
+ * considering the prenormalized distances as well as the new axis limits.
+ * Ported from fonttools */
+HB_INTERNAL float renormalizeValue (float v, const Triple &triple,
+                                    const TripleDistances &triple_distances,
+                                    bool extrapolate = true);
+/* Given a tuple (lower,peak,upper) "tent" and new axis limits
+ * (axisMin,axisDefault,axisMax), solves how to represent the tent
+ * under the new axis configuration.  All values are in normalized
+ * -1,0,+1 coordinate system. Tent values can be outside this range.
+ *
+ * Return value: a list of tuples. Each tuple is of the form
+ * (scalar,tent), where scalar is a multipler to multiply any
+ * delta-sets by, and tent is a new tent for that output delta-set.
+ * If tent value is Triple{}, that is a special deltaset that should
+ * be always-enabled (called "gain").
+ */
+HB_INTERNAL result_t rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances);
+
+#endif /* HB_SUBSET_INSTANCER_SOLVER_HH */
diff --git a/src/hb-subset-plan-member-list.hh b/src/hb-subset-plan-member-list.hh
new file mode 100644 (file)
index 0000000..8bc1fcb
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright © 2018  Google, Inc.
+ * Copyright © 2023  Behdad Esfahbod
+ *
+ *  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_PLAN_MEMBER_LIST_HH
+#define HB_SUBSET_PLAN_MEMBER_LIST_HH
+#endif /* HB_SUBSET_PLAN_MEMBER_LIST_HH */ /* Dummy header guards */
+
+#define E(x, y) x, y
+
+// For each cp that we'd like to retain maps to the corresponding gid.
+HB_SUBSET_PLAN_MEMBER (hb_set_t, unicodes)
+HB_SUBSET_PLAN_MEMBER (hb_sorted_vector_t<hb_codepoint_pair_t>, unicode_to_new_gid_list)
+
+HB_SUBSET_PLAN_MEMBER (hb_sorted_vector_t<hb_codepoint_pair_t>, new_to_old_gid_list)
+
+// name_ids we would like to retain
+HB_SUBSET_PLAN_MEMBER (hb_set_t, name_ids)
+
+// name_languages we would like to retain
+HB_SUBSET_PLAN_MEMBER (hb_set_t, name_languages)
+
+//layout features which will be preserved
+HB_SUBSET_PLAN_MEMBER (hb_set_t, layout_features)
+
+// layout scripts which will be preserved.
+HB_SUBSET_PLAN_MEMBER (hb_set_t, layout_scripts)
+
+//glyph ids requested to retain
+HB_SUBSET_PLAN_MEMBER (hb_set_t, glyphs_requested)
+
+// Tables which should not be processed, just pass them through.
+HB_SUBSET_PLAN_MEMBER (hb_set_t, no_subset_tables)
+
+// Tables which should be dropped.
+HB_SUBSET_PLAN_MEMBER (hb_set_t, drop_tables)
+
+// Old -> New glyph id mapping
+HB_SUBSET_PLAN_MEMBER (hb_map_t, glyph_map_gsub)
+
+HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset)
+HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset_gsub)
+HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset_mathed)
+HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset_colred)
+
+//active lookups we'd like to retain
+HB_SUBSET_PLAN_MEMBER (hb_map_t, gsub_lookups)
+HB_SUBSET_PLAN_MEMBER (hb_map_t, gpos_lookups)
+
+//active langsys we'd like to retain
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb::unique_ptr<hb_set_t>>), gsub_langsys)
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb::unique_ptr<hb_set_t>>), gpos_langsys)
+
+//active features after removing redundant langsys and prune_features
+HB_SUBSET_PLAN_MEMBER (hb_map_t, gsub_features)
+HB_SUBSET_PLAN_MEMBER (hb_map_t, gpos_features)
+
+//active feature variation records/condition index with variations
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb::shared_ptr<hb_set_t>>), gsub_feature_record_cond_idx_map)
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb::shared_ptr<hb_set_t>>), gpos_feature_record_cond_idx_map)
+
+//feature index-> address of substituation feature table mapping with
+//variations
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, const OT::Feature*>), gsub_feature_substitutes_map)
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, const OT::Feature*>), gpos_feature_substitutes_map)
+
+//active layers/palettes we'd like to retain
+HB_SUBSET_PLAN_MEMBER (hb_map_t, colrv1_layers)
+HB_SUBSET_PLAN_MEMBER (hb_map_t, colr_palettes)
+
+//Old layout item variation index -> (New varidx, delta) mapping
+HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<unsigned, hb_pair_t E(<unsigned, int>)>), layout_variation_idx_delta_map)
+
+//gdef varstore retained varidx mapping
+HB_SUBSET_PLAN_MEMBER (hb_vector_t<hb_inc_bimap_t>, gdef_varstore_inner_maps)
+
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, hb::unique_ptr<hb_blob_t>>), sanitized_table_cache)
+
+//normalized axes range map
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, Triple>), axes_location)
+HB_SUBSET_PLAN_MEMBER (hb_vector_t<int>, normalized_coords)
+
+//user specified axes range map
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, Triple>), user_axes_location)
+//axis->TripleDistances map (distances in the pre-normalized space)
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, TripleDistances>), axes_triple_distances)
+
+//retained old axis index -> new axis index mapping in fvar axis array
+HB_SUBSET_PLAN_MEMBER (hb_map_t, axes_index_map)
+
+//axis_index->axis_tag mapping in fvar axis array
+HB_SUBSET_PLAN_MEMBER (hb_map_t, axes_old_index_tag_map)
+//vector of retained axis tags in the order of axes given in the 'fvar' table
+HB_SUBSET_PLAN_MEMBER (hb_vector_t<hb_tag_t>, axis_tags)
+
+//hmtx metrics map: new gid->(advance, lsb)
+HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<hb_codepoint_t, hb_pair_t E(<unsigned, int>)>), hmtx_map)
+//vmtx metrics map: new gid->(advance, lsb)
+HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<hb_codepoint_t, hb_pair_t E(<unsigned, int>)>), vmtx_map)
+//boundsWidth map: new gid->boundsWidth, boundWidth=xMax - xMin
+HB_SUBSET_PLAN_MEMBER (mutable hb_vector_t<unsigned>, bounds_width_vec)
+//boundsHeight map: new gid->boundsHeight, boundsHeight=yMax - yMin
+HB_SUBSET_PLAN_MEMBER (mutable hb_vector_t<unsigned>, bounds_height_vec)
+
+//map: new_gid -> contour points vector
+HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<hb_codepoint_t, contour_point_vector_t>), new_gid_contour_points_map)
+
+#ifdef HB_EXPERIMENTAL_API
+// name table overrides map: hb_ot_name_record_ids_t-> name string new value or
+// None to indicate should remove
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_ot_name_record_ids_t, hb_bytes_t>), name_table_overrides)
+#endif
+
+#undef E
index af4fcb8..c688b71 100644 (file)
@@ -25,7 +25,9 @@
  */
 
 #include "hb-subset-plan.hh"
+#include "hb-subset-accelerator.hh"
 #include "hb-map.hh"
+#include "hb-multimap.hh"
 #include "hb-set.hh"
 
 #include "hb-ot-cmap-table.hh"
 #include "hb-ot-layout-gpos-table.hh"
 #include "hb-ot-layout-gsub-table.hh"
 #include "hb-ot-cff1-table.hh"
-#include "hb-ot-color-colr-table.hh"
-#include "hb-ot-color-colrv1-closure.hh"
+#include "hb-ot-cff2-table.hh"
+#include "OT/Color/COLR/COLR.hh"
+#include "OT/Color/COLR/colrv1-closure.hh"
+#include "OT/Color/CPAL/CPAL.hh"
 #include "hb-ot-var-fvar-table.hh"
+#include "hb-ot-var-avar-table.hh"
 #include "hb-ot-stat-table.hh"
 #include "hb-ot-math-table.hh"
 
+using OT::Layout::GSUB;
+using OT::Layout::GPOS;
+
+
+hb_subset_accelerator_t::~hb_subset_accelerator_t ()
+{
+  if (cmap_cache && destroy_cmap_cache)
+    destroy_cmap_cache ((void*) cmap_cache);
 
-typedef hb_hashmap_t<unsigned, hb_set_t *> script_langsys_map;
 #ifndef HB_NO_SUBSET_CFF
-static inline void
-_add_cff_seac_components (const OT::cff1::accelerator_t &cff,
+  cff1_accel.fini ();
+  cff2_accel.fini ();
+#endif
+  hb_face_destroy (source);
+}
+
+
+typedef hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> script_langsys_map;
+#ifndef HB_NO_SUBSET_CFF
+static inline bool
+_add_cff_seac_components (const OT::cff1::accelerator_subset_t &cff,
                          hb_codepoint_t gid,
                          hb_set_t *gids_to_retain)
 {
@@ -53,7 +74,9 @@ _add_cff_seac_components (const OT::cff1::accelerator_t &cff,
   {
     gids_to_retain->add (base_gid);
     gids_to_retain->add (accent_gid);
+    return true;
   }
+  return false;
 }
 #endif
 
@@ -78,114 +101,239 @@ static void
 _remap_indexes (const hb_set_t *indexes,
                hb_map_t       *mapping /* OUT */)
 {
-  unsigned count = indexes->get_population ();
-
-  for (auto _ : + hb_zip (indexes->iter (), hb_range (count)))
-    mapping->set (_.first, _.second);
+  for (auto _ : + hb_enumerate (indexes->iter ()))
+    mapping->set (_.second, _.first);
 
 }
 
 #ifndef HB_NO_SUBSET_LAYOUT
-typedef void (*layout_collect_func_t) (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 */);
-
 
-template <typename T>
-static void _collect_layout_indices (hb_face_t           *face,
-                                     const T&              table,
-                                     const hb_set_t      *layout_features_to_retain,
-                                     layout_collect_func_t layout_collect_func,
-                                     hb_set_t            *indices /* OUT */)
+/*
+ * Removes all tags from 'tags' that are not in filter. Additionally eliminates any duplicates.
+ * Returns true if anything was removed (not including duplicates).
+ */
+static bool _filter_tag_list(hb_vector_t<hb_tag_t>* tags, /* IN/OUT */
+                             const hb_set_t* filter)
 {
-  hb_vector_t<hb_tag_t> features;
-  if (!features.alloc (table.get_feature_count () + 1))
-    return;
+  hb_vector_t<hb_tag_t> out;
+  out.alloc (tags->get_size() + 1); // +1 is to allocate room for the null terminator.
+
+  bool removed = false;
+  hb_set_t visited;
 
-  hb_set_t visited_features;
-  bool retain_all_features = true;
-  for (unsigned i = 0; i < table.get_feature_count (); i++)
+  for (hb_tag_t tag : *tags)
   {
-    hb_tag_t tag = table.get_feature_tag (i);
     if (!tag) continue;
-    if (!layout_features_to_retain->has (tag))
+    if (visited.has (tag)) continue;
+
+    if (!filter->has (tag))
     {
-      retain_all_features = false;
+      removed = true;
       continue;
     }
-    
-    if (visited_features.has (tag))
-      continue;
 
-    features.push (tag);
-    visited_features.add (tag);
+    visited.add (tag);
+    out.push (tag);
   }
 
-  if (!features)
+  // The collect function needs a null element to signal end of the array.
+  out.push (HB_TAG_NONE);
+
+  hb_swap (out, *tags);
+  return removed;
+}
+
+template <typename T>
+static void _collect_layout_indices (hb_subset_plan_t     *plan,
+                                     const T&              table,
+                                     hb_set_t            *lookup_indices, /* OUT */
+                                     hb_set_t            *feature_indices, /* OUT */
+                                     hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* OUT */
+                                     hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map, /* OUT */
+                                     bool& insert_catch_all_feature_variation_record)
+{
+  unsigned num_features = table.get_feature_count ();
+  hb_vector_t<hb_tag_t> features;
+  if (!plan->check_success (features.resize (num_features))) return;
+  table.get_feature_tags (0, &num_features, features.arrayZ);
+  bool retain_all_features = !_filter_tag_list (&features, &plan->layout_features);
+
+  unsigned num_scripts = table.get_script_count ();
+  hb_vector_t<hb_tag_t> scripts;
+  if (!plan->check_success (scripts.resize (num_scripts))) return;
+  table.get_script_tags (0, &num_scripts, scripts.arrayZ);
+  bool retain_all_scripts = !_filter_tag_list (&scripts, &plan->layout_scripts);
+
+  if (!plan->check_success (!features.in_error ()) || !features
+      || !plan->check_success (!scripts.in_error ()) || !scripts)
     return;
 
-  // The collect function needs a null element to signal end of the array.
-  features.push (0);
+  hb_ot_layout_collect_features (plan->source,
+                                 T::tableTag,
+                                 retain_all_scripts ? nullptr : scripts.arrayZ,
+                                 nullptr,
+                                 retain_all_features ? nullptr : features.arrayZ,
+                                 feature_indices);
 
-  if (retain_all_features)
+#ifndef HB_NO_VAR
+  // collect feature substitutes with variations
+  if (!plan->user_axes_location.is_empty ())
   {
-    // Looking for all features, trigger the faster collection method.
-    layout_collect_func (face,
-                         T::tableTag,
-                         nullptr,
-                         nullptr,
-                         nullptr,
-                         indices);
-    return;
+    hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> conditionset_map;
+    OT::hb_collect_feature_substitutes_with_var_context_t c =
+    {
+      &plan->axes_old_index_tag_map,
+      &plan->axes_location,
+      feature_record_cond_idx_map,
+      feature_substitutes_map,
+      insert_catch_all_feature_variation_record,
+      feature_indices,
+      false,
+      false,
+      false,
+      0,
+      &conditionset_map
+    };
+    table.collect_feature_substitutes_with_variations (&c);
   }
+#endif
+
+  for (unsigned feature_index : *feature_indices)
+  {
+    const OT::Feature* f = &(table.get_feature (feature_index));
+    const OT::Feature **p = nullptr;
+    if (feature_substitutes_map->has (feature_index, &p))
+      f = *p;
+
+    f->add_lookup_indexes_to (lookup_indices);
+  }
+
+  // If all axes are pinned then all feature variations will be dropped so there's no need
+  // to collect lookups from them.
+  if (!plan->all_axes_pinned)
+  {
+    // TODO(qxliu76): this collection doesn't work correctly for feature variations that are dropped
+    //                but not applied. The collection will collect and retain the lookup indices
+    //                associated with those dropped but not activated rules. Since partial instancing
+    //                isn't yet supported this isn't an issue yet but will need to be fixed for
+    //                partial instancing.
+    table.feature_variation_collect_lookups (feature_indices, feature_substitutes_map, lookup_indices);
+  }
+}
+
 
-  layout_collect_func (face,
-                       T::tableTag,
-                      nullptr,
-                      nullptr,
-                      features.arrayZ,
-                      indices);
+static inline void
+_GSUBGPOS_find_duplicate_features (const OT::GSUBGPOS &g,
+                                  const hb_map_t *lookup_indices,
+                                  const hb_set_t *feature_indices,
+                                  const hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map,
+                                  hb_map_t *duplicate_feature_map /* OUT */)
+{
+  if (feature_indices->is_empty ()) return;
+  hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_set_t>> unique_features;
+  //find out duplicate features after subset
+  for (unsigned i : feature_indices->iter ())
+  {
+    hb_tag_t t = g.get_feature_tag (i);
+    if (t == HB_MAP_VALUE_INVALID) continue;
+    if (!unique_features.has (t))
+    {
+      if (unlikely (!unique_features.set (t, hb::unique_ptr<hb_set_t> {hb_set_create ()})))
+       return;
+      if (unique_features.has (t))
+       unique_features.get (t)->add (i);
+      duplicate_feature_map->set (i, i);
+      continue;
+    }
+
+    bool found = false;
+
+    hb_set_t* same_tag_features = unique_features.get (t);
+    for (unsigned other_f_index : same_tag_features->iter ())
+    {
+      const OT::Feature* f = &(g.get_feature (i));
+      const OT::Feature **p = nullptr;
+      if (feature_substitutes_map->has (i, &p))
+        f = *p;
+
+      const OT::Feature* other_f = &(g.get_feature (other_f_index));
+      if (feature_substitutes_map->has (other_f_index, &p))
+        other_f = *p;
+
+      auto f_iter =
+      + hb_iter (f->lookupIndex)
+      | hb_filter (lookup_indices)
+      ;
+
+      auto other_f_iter =
+      + hb_iter (other_f->lookupIndex)
+      | hb_filter (lookup_indices)
+      ;
+
+      bool is_equal = true;
+      for (; f_iter && other_f_iter; f_iter++, other_f_iter++)
+      {
+       unsigned a = *f_iter;
+       unsigned b = *other_f_iter;
+       if (a != b) { is_equal = false; break; }
+      }
+
+      if (is_equal == false || f_iter || other_f_iter) continue;
+
+      found = true;
+      duplicate_feature_map->set (i, other_f_index);
+      break;
+    }
+
+    if (found == false)
+    {
+      same_tag_features->add (i);
+      duplicate_feature_map->set (i, i);
+    }
+  }
 }
 
 template <typename T>
 static inline void
-_closure_glyphs_lookups_features (hb_face_t         *face,
+_closure_glyphs_lookups_features (hb_subset_plan_t   *plan,
                                  hb_set_t           *gids_to_retain,
-                                 const hb_set_t     *layout_features_to_retain,
                                  hb_map_t           *lookups,
                                  hb_map_t           *features,
-                                 script_langsys_map *langsys_map)
+                                 script_langsys_map *langsys_map,
+                                 hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
+                                 hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map,
+                                 bool& insert_catch_all_feature_variation_record)
 {
-  hb_blob_ptr_t<T> table = hb_sanitize_context_t ().reference_table<T> (face);
+  hb_blob_ptr_t<T> table = plan->source_table<T> ();
   hb_tag_t table_tag = table->tableTag;
-  hb_set_t lookup_indices;
-  _collect_layout_indices<T> (face,
+  hb_set_t lookup_indices, feature_indices;
+  _collect_layout_indices<T> (plan,
                               *table,
-                              layout_features_to_retain,
-                              hb_ot_layout_collect_lookups,
-                              &lookup_indices);
-
-  if (table_tag == HB_OT_TAG_GSUB)
-    hb_ot_layout_lookups_substitute_closure (face,
-                                           &lookup_indices,
+                              &lookup_indices,
+                              &feature_indices,
+                              feature_record_cond_idx_map,
+                              feature_substitutes_map,
+                              insert_catch_all_feature_variation_record);
+
+  if (table_tag == HB_OT_TAG_GSUB && !(plan->flags & HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE))
+    hb_ot_layout_lookups_substitute_closure (plan->source,
+                                             &lookup_indices,
                                             gids_to_retain);
-  table->closure_lookups (face,
+  table->closure_lookups (plan->source,
                          gids_to_retain,
-                        &lookup_indices);
+                          &lookup_indices);
   _remap_indexes (&lookup_indices, lookups);
 
-  // Collect and prune features
-  hb_set_t feature_indices;
-  _collect_layout_indices<T> (face,
-                              *table,
-                              layout_features_to_retain,
-                              hb_ot_layout_collect_features,
-                              &feature_indices);
-
-  table->prune_features (lookups, &feature_indices);
+  // prune features
+  table->prune_features (lookups,
+                         plan->user_axes_location.is_empty () ? nullptr : feature_record_cond_idx_map,
+                         feature_substitutes_map,
+                         &feature_indices);
   hb_map_t duplicate_feature_map;
-  table->find_duplicate_features (lookups, &feature_indices, &duplicate_feature_map);
+  _GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, feature_substitutes_map, &duplicate_feature_map);
 
   feature_indices.clear ();
-  table->prune_langsys (&duplicate_feature_map, langsys_map, &feature_indices);
+  table->prune_langsys (&duplicate_feature_map, &plan->layout_scripts, langsys_map, &feature_indices);
   _remap_indexes (&feature_indices, features);
 
   table.destroy ();
@@ -195,14 +343,54 @@ _closure_glyphs_lookups_features (hb_face_t            *face,
 
 #ifndef HB_NO_VAR
 static inline void
-  _collect_layout_variation_indices (hb_face_t *face,
-                                    const hb_set_t *glyphset,
-                                    const hb_map_t *gpos_lookups,
-                                    hb_set_t  *layout_variation_indices,
-                                    hb_map_t  *layout_variation_idx_map)
+_generate_varstore_inner_maps (const hb_set_t& varidx_set,
+                               unsigned subtable_count,
+                               hb_vector_t<hb_inc_bimap_t> &inner_maps /* OUT */)
 {
-  hb_blob_ptr_t<OT::GDEF> gdef = hb_sanitize_context_t ().reference_table<OT::GDEF> (face);
-  hb_blob_ptr_t<OT::GPOS> gpos = hb_sanitize_context_t ().reference_table<OT::GPOS> (face);
+  if (varidx_set.is_empty () || subtable_count == 0) return;
+
+  if (unlikely (!inner_maps.resize (subtable_count))) return;
+  for (unsigned idx : varidx_set)
+  {
+    uint16_t major = idx >> 16;
+    uint16_t minor = idx & 0xFFFF;
+
+    if (major >= subtable_count)
+      continue;
+    inner_maps[major].add (minor);
+  }
+}
+
+static inline hb_font_t*
+_get_hb_font_with_variations (const hb_subset_plan_t *plan)
+{
+  hb_font_t *font = hb_font_create (plan->source);
+
+  hb_vector_t<hb_variation_t> vars;
+  if (!vars.alloc (plan->user_axes_location.get_population ())) {
+    hb_font_destroy (font);
+    return nullptr;
+  }
+
+  for (auto _ : plan->user_axes_location)
+  {
+    hb_variation_t var;
+    var.tag = _.first;
+    var.value = _.second.middle;
+    vars.push (var);
+  }
+
+#ifndef HB_NO_VAR
+  hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location.get_population ());
+#endif
+  return font;
+}
+
+static inline void
+_collect_layout_variation_indices (hb_subset_plan_t* plan)
+{
+  hb_blob_ptr_t<OT::GDEF> gdef = plan->source_table<OT::GDEF> ();
+  hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> ();
 
   if (!gdef->has_data ())
   {
@@ -210,13 +398,24 @@ static inline void
     gpos.destroy ();
     return;
   }
-  OT::hb_collect_variation_indices_context_t c (layout_variation_indices, glyphset, gpos_lookups);
+
+  hb_set_t varidx_set;
+  OT::hb_collect_variation_indices_context_t c (&varidx_set,
+                                                &plan->_glyphset_gsub,
+                                                &plan->gpos_lookups);
   gdef->collect_variation_indices (&c);
 
-  if (hb_ot_layout_has_positioning (face))
+  if (hb_ot_layout_has_positioning (plan->source))
     gpos->collect_variation_indices (&c);
 
-  gdef->remap_layout_variation_indices (layout_variation_indices, layout_variation_idx_map);
+  gdef->remap_layout_variation_indices (&varidx_set,
+                                        plan->normalized_coords,
+                                        !plan->pinned_at_default,
+                                        plan->all_axes_pinned,
+                                        &plan->layout_variation_idx_delta_map);
+
+  unsigned subtable_count = gdef->has_var_store () ? gdef->get_var_store ().get_sub_table_count () : 0;
+  _generate_varstore_inner_maps (varidx_set, subtable_count, plan->gdef_varstore_inner_maps);
 
   gdef.destroy ();
   gpos.destroy ();
@@ -240,22 +439,16 @@ static void _colr_closure (hb_face_t *face,
   OT::COLR::accelerator_t colr (face);
   if (!colr.is_valid ()) return;
 
-  unsigned iteration_count = 0;
   hb_set_t palette_indices, layer_indices;
-  unsigned glyphs_num;
-  {
-    glyphs_num = glyphs_colred->get_population ();
-    // Collect all glyphs referenced by COLRv0
-    hb_set_t glyphset_colrv0;
-    for (hb_codepoint_t gid : glyphs_colred->iter ())
-      colr.closure_glyphs (gid, &glyphset_colrv0);
-    
-    glyphs_colred->union_ (glyphset_colrv0);
-    
-    //closure for COLRv1
-    colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices);
-  } while (iteration_count++ <= HB_CLOSURE_MAX_STAGES &&
-           glyphs_num != glyphs_colred->get_population ());
+  // Collect all glyphs referenced by COLRv0
+  hb_set_t glyphset_colrv0;
+  for (hb_codepoint_t gid : *glyphs_colred)
+    colr.closure_glyphs (gid, &glyphset_colrv0);
+
+  glyphs_colred->union_ (glyphset_colrv0);
+
+  //closure for COLRv1
+  colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices);
 
   colr.closure_V0palette_indices (glyphs_colred, &palette_indices);
   _remap_indexes (&layer_indices, layers_map);
@@ -263,10 +456,10 @@ static void _colr_closure (hb_face_t *face,
 }
 
 static inline void
-_math_closure (hb_face_t           *face,
-               hb_set_t            *glyphset)
+_math_closure (hb_subset_plan_t *plan,
+               hb_set_t         *glyphset)
 {
-  hb_blob_ptr_t<OT::MATH> math = hb_sanitize_context_t ().reference_table<OT::MATH> (face);
+  hb_blob_ptr_t<OT::MATH> math = plan->source_table<OT::MATH> ();
   if (math->has_data ())
     math->closure_glyphs (glyphset);
   math.destroy ();
@@ -277,12 +470,7 @@ static inline 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);
-  }
+  glyphs->del_range (num_glyphs, HB_SET_VALUE_INVALID);
 }
 
 static void
@@ -291,174 +479,737 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
                               hb_subset_plan_t *plan)
 {
   OT::cmap::accelerator_t cmap (plan->source);
-
-  constexpr static const int size_threshold = 4096;
-
+  unsigned size_threshold = plan->source->get_num_glyphs ();
   if (glyphs->is_empty () && unicodes->get_population () < size_threshold)
   {
-    /* This is the fast path if it's anticipated that size of unicodes
-     * is << than the number of codepoints in the font. */
-    for (hb_codepoint_t cp : *unicodes)
-    {
-      hb_codepoint_t gid;
-      if (!cmap.get_nominal_glyph (cp, &gid))
+
+    const hb_map_t* unicode_to_gid = nullptr;
+    if (plan->accelerator)
+      unicode_to_gid = &plan->accelerator->unicode_to_gid;
+
+    // This is approach to collection is faster, but can only be used  if glyphs
+    // are not being explicitly added to the subset and the input unicodes set is
+    // not excessively large (eg. an inverted set).
+    plan->unicode_to_new_gid_list.alloc (unicodes->get_population ());
+    if (!unicode_to_gid) {
+      for (hb_codepoint_t cp : *unicodes)
       {
-        DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
-        continue;
+        hb_codepoint_t gid;
+        if (!cmap.get_nominal_glyph (cp, &gid))
+        {
+          DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
+          continue;
+        }
+
+        plan->codepoint_to_glyph->set (cp, gid);
+        plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
+      }
+    } else {
+      // Use in memory unicode to gid map it's faster then looking up from
+      // the map. This code is mostly duplicated from above to avoid doing
+      // conditionals on the presence of the unicode_to_gid map each
+      // iteration.
+      for (hb_codepoint_t cp : *unicodes)
+      {
+        hb_codepoint_t gid = unicode_to_gid->get (cp);
+        if (gid == HB_MAP_VALUE_INVALID)
+        {
+          DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
+          continue;
+        }
+
+        plan->codepoint_to_glyph->set (cp, gid);
+        plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
       }
-
-      plan->codepoint_to_glyph->set (cp, gid);
     }
   }
   else
   {
-    hb_map_t unicode_glyphid_map;
-    cmap.collect_mapping (hb_set_get_empty (), &unicode_glyphid_map);
+    // This approach is slower, but can handle adding in glyphs to the subset and will match
+    // them with cmap entries.
+
+    hb_map_t unicode_glyphid_map_storage;
+    hb_set_t cmap_unicodes_storage;
+    const hb_map_t* unicode_glyphid_map = &unicode_glyphid_map_storage;
+    const hb_set_t* cmap_unicodes = &cmap_unicodes_storage;
+
+    if (!plan->accelerator) {
+      cmap.collect_mapping (&cmap_unicodes_storage, &unicode_glyphid_map_storage);
+      plan->unicode_to_new_gid_list.alloc (hb_min(unicodes->get_population ()
+                                                  + glyphs->get_population (),
+                                                  cmap_unicodes->get_population ()));
+    } else {
+      unicode_glyphid_map = &plan->accelerator->unicode_to_gid;
+      cmap_unicodes = &plan->accelerator->unicodes;
+    }
+
+    if (plan->accelerator &&
+       unicodes->get_population () < cmap_unicodes->get_population () &&
+       glyphs->get_population () < cmap_unicodes->get_population ())
+    {
+      plan->codepoint_to_glyph->alloc (unicodes->get_population () + glyphs->get_population ());
+
+      auto &gid_to_unicodes = plan->accelerator->gid_to_unicodes;
+      for (hb_codepoint_t gid : *glyphs)
+      {
+        auto unicodes = gid_to_unicodes.get (gid);
+
+       for (hb_codepoint_t cp : unicodes)
+       {
+         plan->codepoint_to_glyph->set (cp, gid);
+         plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
+       }
+      }
+      for (hb_codepoint_t cp : *unicodes)
+      {
+       /* Don't double-add entry. */
+       if (plan->codepoint_to_glyph->has (cp))
+         continue;
+
+        hb_codepoint_t *gid;
+        if (!unicode_glyphid_map->has(cp, &gid))
+          continue;
 
-    for (hb_pair_t<hb_codepoint_t, hb_codepoint_t> cp_gid :
-        + unicode_glyphid_map.iter ())
+       plan->codepoint_to_glyph->set (cp, *gid);
+       plan->unicode_to_new_gid_list.push (hb_pair (cp, *gid));
+      }
+      plan->unicode_to_new_gid_list.qsort ();
+    }
+    else
     {
-      if (!unicodes->has (cp_gid.first) && !glyphs->has (cp_gid.second))
-       continue;
+      plan->codepoint_to_glyph->alloc (cmap_unicodes->get_population ());
+      for (hb_codepoint_t cp : *cmap_unicodes)
+      {
+       hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
+       if (!unicodes->has (cp) && !glyphs->has (gid))
+         continue;
 
-      plan->codepoint_to_glyph->set (cp_gid.first, cp_gid.second);
+       plan->codepoint_to_glyph->set (cp, gid);
+       plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
+      }
     }
 
     /* Add gids which where requested, but not mapped in cmap */
-    // TODO(garretrieger):
-    // Once https://github.com/harfbuzz/harfbuzz/issues/3169
-    // is implemented, this can be done with union and del_range
-    for (hb_codepoint_t gid : glyphs->iter ())
+    unsigned num_glyphs = plan->source->get_num_glyphs ();
+    hb_codepoint_t first = HB_SET_VALUE_INVALID, last = HB_SET_VALUE_INVALID;
+    for (; glyphs->next_range (&first, &last); )
     {
-      if (gid >= plan->source->get_num_glyphs ())
+      if (first >= num_glyphs)
        break;
-      plan->_glyphset_gsub->add (gid);
+      if (last >= num_glyphs)
+        last = num_glyphs - 1;
+      plan->_glyphset_gsub.add_range (first, last);
     }
   }
 
-  + plan->codepoint_to_glyph->keys ()   | hb_sink (plan->unicodes);
-  + plan->codepoint_to_glyph->values () | hb_sink (plan->_glyphset_gsub);
+  auto &arr = plan->unicode_to_new_gid_list;
+  if (arr.length)
+  {
+    plan->unicodes.add_sorted_array (&arr.arrayZ->first, arr.length, sizeof (*arr.arrayZ));
+    plan->_glyphset_gsub.add_array (&arr.arrayZ->second, arr.length, sizeof (*arr.arrayZ));
+  }
+}
+
+#ifndef HB_COMPOSITE_OPERATIONS_PER_GLYPH
+#define HB_COMPOSITE_OPERATIONS_PER_GLYPH 64
+#endif
+
+static unsigned
+_glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
+                           hb_codepoint_t gid,
+                           hb_set_t *gids_to_retain,
+                           int operation_count,
+                           unsigned depth = 0)
+{
+  /* Check if is already visited */
+  if (gids_to_retain->has (gid)) return operation_count;
+
+  gids_to_retain->add (gid);
+
+  if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count;
+  if (unlikely (--operation_count < 0)) return operation_count;
+
+  auto glyph = glyf.glyph_for_gid (gid);
+
+  for (auto &item : glyph.get_composite_iterator ())
+    operation_count =
+      _glyf_add_gid_and_children (glyf,
+                                 item.get_gid (),
+                                 gids_to_retain,
+                                 operation_count,
+                                 depth);
+
+#ifndef HB_NO_VAR_COMPOSITES
+  for (auto &item : glyph.get_var_composite_iterator ())
+   {
+    operation_count =
+      _glyf_add_gid_and_children (glyf,
+                                 item.get_gid (),
+                                 gids_to_retain,
+                                 operation_count,
+                                 depth);
+   }
+#endif
+
+  return operation_count;
+}
+
+static void
+_nameid_closure (hb_subset_plan_t* plan,
+                hb_set_t* drop_tables)
+{
+#ifndef HB_NO_STYLE
+  plan->source->table.STAT->collect_name_ids (&plan->user_axes_location, &plan->name_ids);
+#endif
+#ifndef HB_NO_VAR
+  if (!plan->all_axes_pinned)
+    plan->source->table.fvar->collect_name_ids (&plan->user_axes_location, &plan->axes_old_index_tag_map, &plan->name_ids);
+#endif
+#ifndef HB_NO_COLOR
+  if (!drop_tables->has (HB_OT_TAG_CPAL))
+    plan->source->table.CPAL->collect_name_ids (&plan->colr_palettes, &plan->name_ids);
+#endif
+
+#ifndef HB_NO_SUBSET_LAYOUT
+  if (!drop_tables->has (HB_OT_TAG_GPOS))
+  {
+    hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> ();
+    gpos->collect_name_ids (&plan->gpos_features, &plan->name_ids);
+    gpos.destroy ();
+  }
+  if (!drop_tables->has (HB_OT_TAG_GSUB))
+  {
+    hb_blob_ptr_t<GSUB> gsub = plan->source_table<GSUB> ();
+    gsub->collect_name_ids (&plan->gsub_features, &plan->name_ids);
+    gsub.destroy ();
+  }
+#endif
 }
 
 static void
 _populate_gids_to_retain (hb_subset_plan_t* plan,
-                         bool close_over_gsub,
-                         bool close_over_gpos,
-                         bool close_over_gdef)
+                         hb_set_t* drop_tables)
 {
-  OT::glyf::accelerator_t glyf (plan->source);
+  OT::glyf_accelerator_t glyf (plan->source);
 #ifndef HB_NO_SUBSET_CFF
-  OT::cff1::accelerator_t cff (plan->source);
+  // Note: we cannot use inprogress_accelerator here, since it has not been
+  // created yet. So in case of preprocessed-face (and otherwise), we do an
+  // extra sanitize pass here, which is not ideal.
+  OT::cff1::accelerator_subset_t stack_cff (plan->accelerator ? nullptr : plan->source);
+  const OT::cff1::accelerator_subset_t *cff (plan->accelerator ? plan->accelerator->cff1_accel.get () : &stack_cff);
 #endif
 
-  plan->_glyphset_gsub->add (0); // Not-def
+  plan->_glyphset_gsub.add (0); // Not-def
 
-  _cmap_closure (plan->source, plan->unicodes, plan->_glyphset_gsub);
+  _cmap_closure (plan->source, &plan->unicodes, &plan->_glyphset_gsub);
 
 #ifndef HB_NO_SUBSET_LAYOUT
-  if (close_over_gsub)
+  if (!drop_tables->has (HB_OT_TAG_GSUB))
     // closure all glyphs/lookups/features needed for GSUB substitutions.
-    _closure_glyphs_lookups_features<OT::GSUB> (
-        plan->source,
-        plan->_glyphset_gsub,
-        plan->layout_features,
-        plan->gsub_lookups,
-        plan->gsub_features,
-        plan->gsub_langsys);
-
-  if (close_over_gpos)
-    _closure_glyphs_lookups_features<OT::GPOS> (
-        plan->source,
-        plan->_glyphset_gsub,
-        plan->layout_features,
-        plan->gpos_lookups,
-        plan->gpos_features,
-        plan->gpos_langsys);
+    _closure_glyphs_lookups_features<GSUB> (
+        plan,
+        &plan->_glyphset_gsub,
+        &plan->gsub_lookups,
+        &plan->gsub_features,
+        &plan->gsub_langsys,
+        &plan->gsub_feature_record_cond_idx_map,
+        &plan->gsub_feature_substitutes_map,
+        plan->gsub_insert_catch_all_feature_variation_rec);
+
+  if (!drop_tables->has (HB_OT_TAG_GPOS))
+    _closure_glyphs_lookups_features<GPOS> (
+        plan,
+        &plan->_glyphset_gsub,
+        &plan->gpos_lookups,
+        &plan->gpos_features,
+        &plan->gpos_langsys,
+        &plan->gpos_feature_record_cond_idx_map,
+        &plan->gpos_feature_substitutes_map,
+        plan->gpos_insert_catch_all_feature_variation_rec);
 #endif
-  _remove_invalid_gids (plan->_glyphset_gsub, plan->source->get_num_glyphs ());
-
-  hb_set_set (plan->_glyphset_mathed, plan->_glyphset_gsub);
-  _math_closure (plan->source, plan->_glyphset_mathed);
-  _remove_invalid_gids (plan->_glyphset_mathed, plan->source->get_num_glyphs ());
+  _remove_invalid_gids (&plan->_glyphset_gsub, plan->source->get_num_glyphs ());
 
-  hb_set_t cur_glyphset = *plan->_glyphset_mathed;
-  _colr_closure (plan->source, plan->colrv1_layers, plan->colr_palettes, &cur_glyphset);
-  _remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ());
+  plan->_glyphset_mathed = plan->_glyphset_gsub;
+  if (!drop_tables->has (HB_OT_TAG_MATH))
+  {
+    _math_closure (plan, &plan->_glyphset_mathed);
+    _remove_invalid_gids (&plan->_glyphset_mathed, plan->source->get_num_glyphs ());
+  }
 
-  hb_set_set (plan->_glyphset_colred, &cur_glyphset);
-  // Populate a full set of glyphs to retain by adding all referenced
-  // composite glyphs.
-  for (hb_codepoint_t gid : cur_glyphset.iter ())
+  hb_set_t cur_glyphset = plan->_glyphset_mathed;
+  if (!drop_tables->has (HB_OT_TAG_COLR))
   {
-    glyf.add_gid_and_children (gid, plan->_glyphset);
-#ifndef HB_NO_SUBSET_CFF
-    if (cff.is_valid ())
-      _add_cff_seac_components (cff, gid, plan->_glyphset);
-#endif
+    _colr_closure (plan->source, &plan->colrv1_layers, &plan->colr_palettes, &cur_glyphset);
+    _remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ());
   }
 
-  _remove_invalid_gids (plan->_glyphset, plan->source->get_num_glyphs ());
+  plan->_glyphset_colred = cur_glyphset;
+
+  _nameid_closure (plan, drop_tables);
+  /* Populate a full set of glyphs to retain by adding all referenced
+   * composite glyphs. */
+  if (glyf.has_data ())
+    for (hb_codepoint_t gid : cur_glyphset)
+      _glyf_add_gid_and_children (glyf, gid, &plan->_glyphset,
+                                 cur_glyphset.get_population () * HB_COMPOSITE_OPERATIONS_PER_GLYPH);
+  else
+    plan->_glyphset.union_ (cur_glyphset);
+#ifndef HB_NO_SUBSET_CFF
+  if (!plan->accelerator || plan->accelerator->has_seac)
+  {
+    bool has_seac = false;
+    if (cff->is_valid ())
+      for (hb_codepoint_t gid : cur_glyphset)
+       if (_add_cff_seac_components (*cff, gid, &plan->_glyphset))
+         has_seac = true;
+    plan->has_seac = has_seac;
+  }
+#endif
 
+  _remove_invalid_gids (&plan->_glyphset, plan->source->get_num_glyphs ());
 
 #ifndef HB_NO_VAR
-  if (close_over_gdef)
-    _collect_layout_variation_indices (plan->source,
-                                      plan->_glyphset_gsub,
-                                      plan->gpos_lookups,
-                                      plan->layout_variation_indices,
-                                      plan->layout_variation_idx_map);
+  if (!drop_tables->has (HB_OT_TAG_GDEF))
+    _collect_layout_variation_indices (plan);
 #endif
 }
 
 static void
+_create_glyph_map_gsub (const hb_set_t* glyph_set_gsub,
+                        const hb_map_t* glyph_map,
+                        hb_map_t* out)
+{
+  out->alloc (glyph_set_gsub->get_population ());
+  + hb_iter (glyph_set_gsub)
+  | hb_map ([&] (hb_codepoint_t gid) {
+    return hb_codepoint_pair_t (gid, glyph_map->get (gid));
+  })
+  | hb_sink (out)
+  ;
+}
+
+static bool
 _create_old_gid_to_new_gid_map (const hb_face_t *face,
                                bool             retain_gids,
                                const hb_set_t  *all_gids_to_retain,
+                                const hb_map_t  *requested_glyph_map,
                                hb_map_t        *glyph_map, /* OUT */
                                hb_map_t        *reverse_glyph_map, /* OUT */
+                               hb_sorted_vector_t<hb_codepoint_pair_t> *new_to_old_gid_list /* OUT */,
                                unsigned int    *num_glyphs /* OUT */)
 {
-  if (!retain_gids)
+  unsigned pop = all_gids_to_retain->get_population ();
+  reverse_glyph_map->alloc (pop);
+  glyph_map->alloc (pop);
+  new_to_old_gid_list->alloc (pop);
+
+  if (*requested_glyph_map)
+  {
+    hb_set_t new_gids(requested_glyph_map->values());
+    if (new_gids.get_population() != requested_glyph_map->get_population())
+    {
+      DEBUG_MSG (SUBSET, nullptr, "The provided custom glyph mapping is not unique.");
+      return false;
+    }
+
+    if (retain_gids)
+    {
+      DEBUG_MSG (SUBSET, nullptr, 
+        "HB_SUBSET_FLAGS_RETAIN_GIDS cannot be set if "
+        "a custom glyph mapping has been provided.");
+      return false;
+    }
+  
+    hb_codepoint_t max_glyph = 0;
+    hb_set_t remaining;
+    for (auto old_gid : all_gids_to_retain->iter ())
+    {
+      if (old_gid == 0) {
+       new_to_old_gid_list->push (hb_pair<hb_codepoint_t, hb_codepoint_t> (0u, 0u));
+        continue;
+      }
+
+      hb_codepoint_t* new_gid;
+      if (!requested_glyph_map->has (old_gid, &new_gid))
+      {
+        remaining.add(old_gid);
+        continue;
+      }
+
+      if (*new_gid > max_glyph)
+        max_glyph = *new_gid;
+      new_to_old_gid_list->push (hb_pair (*new_gid, old_gid));
+    }
+    new_to_old_gid_list->qsort ();
+
+    // Anything that wasn't mapped by the requested mapping should
+    // be placed after the requested mapping.
+    for (auto old_gid : remaining)
+      new_to_old_gid_list->push (hb_pair (++max_glyph, old_gid));
+
+    *num_glyphs = max_glyph + 1;
+  }
+  else if (!retain_gids)
   {
     + hb_enumerate (hb_iter (all_gids_to_retain), (hb_codepoint_t) 0)
-    | hb_sink (reverse_glyph_map)
+    | hb_sink (new_to_old_gid_list)
     ;
-    *num_glyphs = reverse_glyph_map->get_population ();
-  } else {
+    *num_glyphs = new_to_old_gid_list->length;
+  }
+  else
+  {
     + hb_iter (all_gids_to_retain)
     | hb_map ([] (hb_codepoint_t _) {
-               return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (_, _);
+               return hb_codepoint_pair_t (_, _);
              })
-    | hb_sink (reverse_glyph_map)
+    | hb_sink (new_to_old_gid_list)
     ;
 
-    unsigned max_glyph =
-    + hb_iter (all_gids_to_retain)
-    | hb_reduce (hb_max, 0u)
-    ;
+    hb_codepoint_t max_glyph = HB_SET_VALUE_INVALID;
+    hb_set_previous (all_gids_to_retain, &max_glyph);
+
     *num_glyphs = max_glyph + 1;
   }
 
-  + reverse_glyph_map->iter ()
-  | hb_map (&hb_pair_t<hb_codepoint_t, hb_codepoint_t>::reverse)
+  + hb_iter (new_to_old_gid_list)
+  | hb_sink (reverse_glyph_map)
+  ;
+  + hb_iter (new_to_old_gid_list)
+  | hb_map (&hb_codepoint_pair_t::reverse)
   | hb_sink (glyph_map)
   ;
+
+  return true;
 }
 
+#ifndef HB_NO_VAR
 static void
-_nameid_closure (hb_face_t *face,
-                hb_set_t  *nameids)
+_normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
 {
-#ifndef HB_NO_STYLE
-  face->table.STAT->collect_name_ids (nameids);
+  if (plan->user_axes_location.is_empty ())
+    return;
+
+  hb_array_t<const OT::AxisRecord> axes = face->table.fvar->get_axes ();
+  plan->normalized_coords.resize (axes.length);
+
+  bool has_avar = face->table.avar->has_data ();
+  const OT::SegmentMaps *seg_maps = nullptr;
+  unsigned avar_axis_count = 0;
+  if (has_avar)
+  {
+    seg_maps = face->table.avar->get_segment_maps ();
+    avar_axis_count = face->table.avar->get_axis_count();
+  }
+
+  bool axis_not_pinned = false;
+  unsigned old_axis_idx = 0, new_axis_idx = 0;
+  for (const auto& axis : axes)
+  {
+    hb_tag_t axis_tag = axis.get_axis_tag ();
+    plan->axes_old_index_tag_map.set (old_axis_idx, axis_tag);
+
+    if (!plan->user_axes_location.has (axis_tag) ||
+        !plan->user_axes_location.get (axis_tag).is_point ())
+    {
+      axis_not_pinned = true;
+      plan->axes_index_map.set (old_axis_idx, new_axis_idx);
+      plan->axis_tags.push (axis_tag);
+      new_axis_idx++;
+    }
+
+    Triple *axis_range;
+    if (plan->user_axes_location.has (axis_tag, &axis_range))
+    {
+      plan->axes_triple_distances.set (axis_tag, axis.get_triple_distances ());
+
+      int normalized_min = axis.normalize_axis_value (axis_range->minimum);
+      int normalized_default = axis.normalize_axis_value (axis_range->middle);
+      int normalized_max = axis.normalize_axis_value (axis_range->maximum);
+
+      if (has_avar && old_axis_idx < avar_axis_count)
+      {
+        normalized_min = seg_maps->map (normalized_min);
+        normalized_default = seg_maps->map (normalized_default);
+        normalized_max = seg_maps->map (normalized_max);
+      }
+      plan->axes_location.set (axis_tag, Triple (static_cast<float> (normalized_min / 16384.f),
+                                                 static_cast<float> (normalized_default / 16384.f),
+                                                 static_cast<float> (normalized_max / 16384.f)));
+
+      if (normalized_default != 0)
+        plan->pinned_at_default = false;
+
+      plan->normalized_coords[old_axis_idx] = normalized_default;
+    }
+
+    old_axis_idx++;
+
+    if (has_avar && old_axis_idx < avar_axis_count)
+      seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
+  }
+  plan->all_axes_pinned = !axis_not_pinned;
+}
+
+static void
+_update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan)
+{
+  if (!plan->normalized_coords) return;
+  OT::cff2::accelerator_t cff2 (plan->source);
+  if (!cff2.is_valid ()) return;
+
+  hb_font_t *font = nullptr;
+  if (unlikely (!plan->check_success (font = _get_hb_font_with_variations (plan))))
+  {
+    hb_font_destroy (font);
+    return;
+  }
+
+  hb_glyph_extents_t extents = {0x7FFF, -0x7FFF};
+  OT::hmtx_accelerator_t _hmtx (plan->source);
+  float *hvar_store_cache = nullptr;
+  if (_hmtx.has_data () && _hmtx.var_table.get_length ())
+    hvar_store_cache = _hmtx.var_table->get_var_store ().create_cache ();
+  
+  OT::vmtx_accelerator_t _vmtx (plan->source);
+  float *vvar_store_cache = nullptr;
+  if (_vmtx.has_data () && _vmtx.var_table.get_length ())
+    vvar_store_cache = _vmtx.var_table->get_var_store ().create_cache ();
+
+  for (auto p : *plan->glyph_map)
+  {
+    hb_codepoint_t old_gid = p.first;
+    hb_codepoint_t new_gid = p.second;
+    if (!cff2.get_extents (font, old_gid, &extents)) continue;
+    bool has_bounds_info = true;
+    if (extents.x_bearing == 0 && extents.width == 0 &&
+        extents.height == 0 && extents.y_bearing == 0)
+      has_bounds_info = false;
+
+    if (has_bounds_info)
+    {
+      plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, extents.x_bearing);
+      plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, extents.x_bearing + extents.width);
+      plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, extents.y_bearing);
+      plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, extents.y_bearing + extents.height);
+    }
+
+    if (_hmtx.has_data ())
+    {
+      int hori_aw = _hmtx.get_advance_without_var_unscaled (old_gid);
+      if (_hmtx.var_table.get_length ())
+        hori_aw += (int) roundf (_hmtx.var_table->get_advance_delta_unscaled (old_gid, font->coords, font->num_coords,
+                                                                              hvar_store_cache));
+      int lsb = extents.x_bearing;
+      if (!has_bounds_info)
+      {
+        if (!_hmtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb))
+          continue;
+      }
+      plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb));
+      plan->bounds_width_vec[new_gid] = extents.width;
+    }
+
+    if (_vmtx.has_data ())
+    {
+      int vert_aw = _vmtx.get_advance_without_var_unscaled (old_gid);
+      if (_vmtx.var_table.get_length ())
+        vert_aw += (int) roundf (_vmtx.var_table->get_advance_delta_unscaled (old_gid, font->coords, font->num_coords,
+                                                                              vvar_store_cache));
+
+      int tsb = extents.y_bearing;
+      if (!has_bounds_info)
+      {
+        if (!_vmtx.get_leading_bearing_without_var_unscaled (old_gid, &tsb))
+          continue;
+      }
+      plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb));
+      plan->bounds_height_vec[new_gid] = extents.height;
+    }
+  }
+  hb_font_destroy (font);
+  if (hvar_store_cache)
+    _hmtx.var_table->get_var_store ().destroy_cache (hvar_store_cache);
+  if (vvar_store_cache)
+    _vmtx.var_table->get_var_store ().destroy_cache (vvar_store_cache);
+}
+
+static bool
+_get_instance_glyphs_contour_points (hb_subset_plan_t *plan)
+{
+  /* contour_points vector only needed for updating gvar table (infer delta)
+   * during partial instancing */
+  if (plan->user_axes_location.is_empty () || plan->all_axes_pinned)
+    return true;
+
+  OT::glyf_accelerator_t glyf (plan->source);
+
+  for (auto &_ : plan->new_to_old_gid_list)
+  {
+    hb_codepoint_t new_gid = _.first;
+    contour_point_vector_t all_points;
+    if (new_gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
+    {
+      if (unlikely (!plan->new_gid_contour_points_map.set (new_gid, all_points)))
+        return false;
+      continue;
+    }
+
+    hb_codepoint_t old_gid = _.second;
+    if (unlikely (!glyf.glyph_for_gid (old_gid).get_all_points_without_var (plan->source, all_points)))
+      return false;
+    if (unlikely (!plan->new_gid_contour_points_map.set (new_gid, all_points)))
+      return false;
+  }
+  return true;
+}
+#endif
+
+hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
+                                   const hb_subset_input_t *input)
+{
+  successful = true;
+  flags = input->flags;
+
+  unicode_to_new_gid_list.init ();
+
+  name_ids = *input->sets.name_ids;
+  name_languages = *input->sets.name_languages;
+  layout_features = *input->sets.layout_features;
+  layout_scripts = *input->sets.layout_scripts;
+  glyphs_requested = *input->sets.glyphs;
+  drop_tables = *input->sets.drop_tables;
+  no_subset_tables = *input->sets.no_subset_tables;
+  source = hb_face_reference (face);
+  dest = hb_face_builder_create ();
+
+  codepoint_to_glyph = hb_map_create ();
+  glyph_map = hb_map_create ();
+  reverse_glyph_map = hb_map_create ();
+
+  gsub_insert_catch_all_feature_variation_rec = false;
+  gpos_insert_catch_all_feature_variation_rec = false;
+  gdef_varstore_inner_maps.init ();
+
+  user_axes_location = input->axes_location;
+  all_axes_pinned = false;
+  pinned_at_default = true;
+
+#ifdef HB_EXPERIMENTAL_API
+  for (auto _ : input->name_table_overrides)
+  {
+    hb_bytes_t name_bytes = _.second;
+    unsigned len = name_bytes.length;
+    char *name_str = (char *) hb_malloc (len);
+    if (unlikely (!check_success (name_str)))
+      break;
+
+    hb_memcpy (name_str, name_bytes.arrayZ, len);
+    name_table_overrides.set (_.first, hb_bytes_t (name_str, len));
+  }
+#endif
+
+  void* accel = hb_face_get_user_data(face, hb_subset_accelerator_t::user_data_key());
+
+  attach_accelerator_data = input->attach_accelerator_data;
+  force_long_loca = input->force_long_loca;
+  if (accel)
+    accelerator = (hb_subset_accelerator_t*) accel;
+
+  if (unlikely (in_error ()))
+    return;
+
+#ifndef HB_NO_VAR
+  _normalize_axes_location (face, this);
 #endif
+
+  _populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, this);
+
+  _populate_gids_to_retain (this, input->sets.drop_tables);
+  if (unlikely (in_error ()))
+    return;
+
+  if (!check_success(_create_old_gid_to_new_gid_map(
+          face,
+          input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS,
+          &_glyphset,
+          &input->glyph_map,
+          glyph_map,
+          reverse_glyph_map,
+         &new_to_old_gid_list,
+          &_num_output_glyphs))) {
+    return;
+  }
+
+  _create_glyph_map_gsub (
+      &_glyphset_gsub,
+      glyph_map,
+      &glyph_map_gsub);
+
+  // Now that we have old to new gid map update the unicode to new gid list.
+  for (unsigned i = 0; i < unicode_to_new_gid_list.length; i++)
+  {
+    // Use raw array access for performance.
+    unicode_to_new_gid_list.arrayZ[i].second =
+        glyph_map->get(unicode_to_new_gid_list.arrayZ[i].second);
+  }
+
+  bounds_width_vec.resize (_num_output_glyphs, false);
+  for (auto &v : bounds_width_vec)
+    v = 0xFFFFFFFF;
+  bounds_height_vec.resize (_num_output_glyphs, false);
+  for (auto &v : bounds_height_vec)
+    v = 0xFFFFFFFF;
+
+  if (unlikely (in_error ()))
+    return;
+
 #ifndef HB_NO_VAR
-  face->table.fvar->collect_name_ids (nameids);
+  _update_instance_metrics_map_from_cff2 (this);
+  if (!check_success (_get_instance_glyphs_contour_points (this)))
+      return;
+#endif
+
+  if (attach_accelerator_data)
+  {
+    inprogress_accelerator =
+      hb_subset_accelerator_t::create (source,
+                                      *codepoint_to_glyph,
+                                       unicodes,
+                                      has_seac);
+
+    check_success (inprogress_accelerator);
+  }
+
+#define HB_SUBSET_PLAN_MEMBER(Type, Name) check_success (!Name.in_error ());
+#include "hb-subset-plan-member-list.hh"
+#undef HB_SUBSET_PLAN_MEMBER
+}
+
+hb_subset_plan_t::~hb_subset_plan_t()
+{
+  hb_face_destroy (dest);
+
+  hb_map_destroy (codepoint_to_glyph);
+  hb_map_destroy (glyph_map);
+  hb_map_destroy (reverse_glyph_map);
+#ifndef HB_NO_SUBSET_CFF
+  cff1_accel.fini ();
+  cff2_accel.fini ();
 #endif
+  hb_face_destroy (source);
+
+#ifdef HB_EXPERIMENTAL_API
+  for (auto _ : name_table_overrides.iter_ref ())
+    _.second.fini ();
+#endif
+
+  if (inprogress_accelerator)
+    hb_subset_accelerator_t::destroy ((void*) inprogress_accelerator);
 }
 
+
 /**
- * hb_subset_plan_create:
+ * hb_subset_plan_create_or_fail:
  * @face: font face to create the plan for.
  * @input: a #hb_subset_input_t input.
  *
@@ -467,70 +1218,24 @@ _nameid_closure (hb_face_t *face,
  * which tables and glyphs should be retained.
  *
  * Return value: (transfer full): New subset plan. Destroy with
- * hb_subset_plan_destroy().
+ * hb_subset_plan_destroy(). If there is a failure creating the plan
+ * nullptr will be returned.
  *
- * Since: 1.7.5
+ * Since: 4.0.0
  **/
 hb_subset_plan_t *
-hb_subset_plan_create (hb_face_t        *face,
-                      const hb_subset_input_t *input)
+hb_subset_plan_create_or_fail (hb_face_t        *face,
+                               const hb_subset_input_t *input)
 {
   hb_subset_plan_t *plan;
-  if (unlikely (!(plan = hb_object_create<hb_subset_plan_t> ())))
-    return const_cast<hb_subset_plan_t *> (&Null (hb_subset_plan_t));
-
-  plan->successful = true;
-  plan->flags = input->flags;
-  plan->unicodes = hb_set_create ();
-  plan->name_ids = hb_set_copy (input->sets.name_ids);
-  _nameid_closure (face, plan->name_ids);
-  plan->name_languages = hb_set_copy (input->sets.name_languages);
-  plan->layout_features = hb_set_copy (input->sets.layout_features);
-  plan->glyphs_requested = hb_set_copy (input->sets.glyphs);
-  plan->drop_tables = hb_set_copy (input->sets.drop_tables);
-  plan->no_subset_tables = hb_set_copy (input->sets.no_subset_tables);
-  plan->source = hb_face_reference (face);
-  plan->dest = hb_face_builder_create ();
-
-  plan->_glyphset = hb_set_create ();
-  plan->_glyphset_gsub = hb_set_create ();
-  plan->_glyphset_mathed = hb_set_create ();
-  plan->_glyphset_colred = hb_set_create ();
-  plan->codepoint_to_glyph = hb_map_create ();
-  plan->glyph_map = hb_map_create ();
-  plan->reverse_glyph_map = hb_map_create ();
-  plan->gsub_lookups = hb_map_create ();
-  plan->gpos_lookups = hb_map_create ();
-
-  if (plan->check_success (plan->gsub_langsys = hb_object_create<script_langsys_map> ()))
-    plan->gsub_langsys->init_shallow ();
-  if (plan->check_success (plan->gpos_langsys = hb_object_create<script_langsys_map> ()))
-    plan->gpos_langsys->init_shallow ();
-
-  plan->gsub_features = hb_map_create ();
-  plan->gpos_features = hb_map_create ();
-  plan->colrv1_layers = hb_map_create ();
-  plan->colr_palettes = hb_map_create ();
-  plan->layout_variation_indices = hb_set_create ();
-  plan->layout_variation_idx_map = hb_map_create ();
-
-  if (plan->in_error ()) {
-    return plan;
-  }
-
-  _populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, plan);
-
-  _populate_gids_to_retain (plan,
-                           !input->sets.drop_tables->has (HB_OT_TAG_GSUB),
-                           !input->sets.drop_tables->has (HB_OT_TAG_GPOS),
-                           !input->sets.drop_tables->has (HB_OT_TAG_GDEF));
-
-  _create_old_gid_to_new_gid_map (face,
-                                  input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS,
-                                 plan->_glyphset,
-                                 plan->glyph_map,
-                                 plan->reverse_glyph_map,
-                                 &plan->_num_output_glyphs);
+  if (unlikely (!(plan = hb_object_create<hb_subset_plan_t> (face, input))))
+    return nullptr;
+
+  if (unlikely (plan->in_error ()))
+  {
+    hb_subset_plan_destroy (plan);
+    return nullptr;
+  }
 
   return plan;
 }
@@ -542,57 +1247,125 @@ hb_subset_plan_create (hb_face_t         *face,
  * Decreases the reference count on @plan, and if it reaches zero, destroys
  * @plan, freeing all memory.
  *
- * Since: 1.7.5
+ * Since: 4.0.0
  **/
 void
 hb_subset_plan_destroy (hb_subset_plan_t *plan)
 {
   if (!hb_object_destroy (plan)) return;
 
-  hb_set_destroy (plan->unicodes);
-  hb_set_destroy (plan->name_ids);
-  hb_set_destroy (plan->name_languages);
-  hb_set_destroy (plan->layout_features);
-  hb_set_destroy (plan->glyphs_requested);
-  hb_set_destroy (plan->drop_tables);
-  hb_set_destroy (plan->no_subset_tables);
-  hb_face_destroy (plan->source);
-  hb_face_destroy (plan->dest);
-  hb_map_destroy (plan->codepoint_to_glyph);
-  hb_map_destroy (plan->glyph_map);
-  hb_map_destroy (plan->reverse_glyph_map);
-  hb_set_destroy (plan->_glyphset);
-  hb_set_destroy (plan->_glyphset_gsub);
-  hb_set_destroy (plan->_glyphset_mathed);
-  hb_set_destroy (plan->_glyphset_colred);
-  hb_map_destroy (plan->gsub_lookups);
-  hb_map_destroy (plan->gpos_lookups);
-  hb_map_destroy (plan->gsub_features);
-  hb_map_destroy (plan->gpos_features);
-  hb_map_destroy (plan->colrv1_layers);
-  hb_map_destroy (plan->colr_palettes);
-  hb_set_destroy (plan->layout_variation_indices);
-  hb_map_destroy (plan->layout_variation_idx_map);
-
-  if (plan->gsub_langsys)
-  {
-    for (auto _ : plan->gsub_langsys->iter ())
-      hb_set_destroy (_.second);
+  hb_free (plan);
+}
 
-    hb_object_destroy (plan->gsub_langsys);
-    plan->gsub_langsys->fini_shallow ();
-    hb_free (plan->gsub_langsys);
-  }
+/**
+ * hb_subset_plan_old_to_new_glyph_mapping:
+ * @plan: a subsetting plan.
+ *
+ * Returns the mapping between glyphs in the original font to glyphs in the
+ * subset that will be produced by @plan
+ *
+ * Return value: (transfer none):
+ * A pointer to the #hb_map_t of the mapping.
+ *
+ * Since: 4.0.0
+ **/
+hb_map_t *
+hb_subset_plan_old_to_new_glyph_mapping (const hb_subset_plan_t *plan)
+{
+  return plan->glyph_map;
+}
 
-  if (plan->gpos_langsys)
-  {
-    for (auto _ : plan->gpos_langsys->iter ())
-      hb_set_destroy (_.second);
+/**
+ * hb_subset_plan_new_to_old_glyph_mapping:
+ * @plan: a subsetting plan.
+ *
+ * Returns the mapping between glyphs in the subset that will be produced by
+ * @plan and the glyph in the original font.
+ *
+ * Return value: (transfer none):
+ * A pointer to the #hb_map_t of the mapping.
+ *
+ * Since: 4.0.0
+ **/
+hb_map_t *
+hb_subset_plan_new_to_old_glyph_mapping (const hb_subset_plan_t *plan)
+{
+  return plan->reverse_glyph_map;
+}
 
-    hb_object_destroy (plan->gpos_langsys);
-    plan->gpos_langsys->fini_shallow ();
-    hb_free (plan->gpos_langsys);
-  }
+/**
+ * hb_subset_plan_unicode_to_old_glyph_mapping:
+ * @plan: a subsetting plan.
+ *
+ * Returns the mapping between codepoints in the original font and the
+ * associated glyph id in the original font.
+ *
+ * Return value: (transfer none):
+ * A pointer to the #hb_map_t of the mapping.
+ *
+ * Since: 4.0.0
+ **/
+hb_map_t *
+hb_subset_plan_unicode_to_old_glyph_mapping (const hb_subset_plan_t *plan)
+{
+  return plan->codepoint_to_glyph;
+}
 
-  hb_free (plan);
+/**
+ * hb_subset_plan_reference: (skip)
+ * @plan: a #hb_subset_plan_t object.
+ *
+ * Increases the reference count on @plan.
+ *
+ * Return value: @plan.
+ *
+ * Since: 4.0.0
+ **/
+hb_subset_plan_t *
+hb_subset_plan_reference (hb_subset_plan_t *plan)
+{
+  return hb_object_reference (plan);
+}
+
+/**
+ * hb_subset_plan_set_user_data: (skip)
+ * @plan: a #hb_subset_plan_t object.
+ * @key: The user-data key to set
+ * @data: A pointer to the user data
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
+ * @replace: Whether to replace an existing data with the same key
+ *
+ * Attaches a user-data key/data pair to the given subset plan object.
+ *
+ * Return value: `true` if success, `false` otherwise
+ *
+ * Since: 4.0.0
+ **/
+hb_bool_t
+hb_subset_plan_set_user_data (hb_subset_plan_t   *plan,
+                              hb_user_data_key_t *key,
+                              void               *data,
+                              hb_destroy_func_t   destroy,
+                              hb_bool_t                  replace)
+{
+  return hb_object_set_user_data (plan, key, data, destroy, replace);
+}
+
+/**
+ * hb_subset_plan_get_user_data: (skip)
+ * @plan: a #hb_subset_plan_t object.
+ * @key: The user-data key to query
+ *
+ * Fetches the user data associated with the specified key,
+ * attached to the specified subset plan object.
+ *
+ * Return value: (transfer none): A pointer to the user data
+ *
+ * Since: 4.0.0
+ **/
+void *
+hb_subset_plan_get_user_data (const hb_subset_plan_t *plan,
+                              hb_user_data_key_t     *key)
+{
+  return hb_object_get_user_data (plan, key);
 }
index b9244e5..a05d1d1 100644 (file)
 
 #include "hb-subset.h"
 #include "hb-subset-input.hh"
+#include "hb-subset-accelerator.hh"
 
 #include "hb-map.hh"
+#include "hb-bimap.hh"
 #include "hb-set.hh"
 
-struct hb_subset_plan_t
+namespace OT {
+struct Feature;
+}
+
+struct head_maxp_info_t
 {
-  hb_object_header_t header;
+  head_maxp_info_t ()
+      :xMin (0x7FFF), xMax (-0x7FFF), yMin (0x7FFF), yMax (-0x7FFF),
+      maxPoints (0), maxContours (0),
+      maxCompositePoints (0),
+      maxCompositeContours (0),
+      maxComponentElements (0),
+      maxComponentDepth (0),
+      allXMinIsLsb (true) {}
+
+  int xMin;
+  int xMax;
+  int yMin;
+  int yMax;
+  unsigned maxPoints;
+  unsigned maxContours;
+  unsigned maxCompositePoints;
+  unsigned maxCompositeContours;
+  unsigned maxComponentElements;
+  unsigned maxComponentDepth;
+  bool allXMinIsLsb;
+};
 
-  bool successful;
-  unsigned flags;
+typedef struct head_maxp_info_t head_maxp_info_t;
+
+struct contour_point_t
+{
+  void init (float x_ = 0.f, float y_ = 0.f, bool is_end_point_ = false)
+  { flag = 0; x = x_; y = y_; is_end_point = is_end_point_; }
+
+  void transform (const float (&matrix)[4])
+  {
+    float x_ = x * matrix[0] + y * matrix[2];
+         y  = x * matrix[1] + y * matrix[3];
+    x  = x_;
+  }
+  HB_ALWAYS_INLINE
+  void translate (const contour_point_t &p) { x += p.x; y += p.y; }
 
-  // For each cp that we'd like to retain maps to the corresponding gid.
-  hb_set_t *unicodes;
 
-  // name_ids we would like to retain
-  hb_set_t *name_ids;
+  float x;
+  float y;
+  uint8_t flag;
+  bool is_end_point;
+};
 
-  // name_languages we would like to retain
-  hb_set_t *name_languages;
+struct contour_point_vector_t : hb_vector_t<contour_point_t>
+{
+  void extend (const hb_array_t<contour_point_t> &a)
+  {
+    unsigned int old_len = length;
+    if (unlikely (!resize (old_len + a.length, false)))
+      return;
+    auto arrayZ = this->arrayZ + old_len;
+    unsigned count = a.length;
+    hb_memcpy (arrayZ, a.arrayZ, count * sizeof (arrayZ[0]));
+  }
+};
 
-  //layout features which will be preserved
-  hb_set_t *layout_features;
+namespace OT {
+  struct cff1_subset_accelerator_t;
+  struct cff2_subset_accelerator_t;
+}
 
-  //glyph ids requested to retain
-  hb_set_t *glyphs_requested;
+struct hb_subset_plan_t
+{
+  HB_INTERNAL hb_subset_plan_t (hb_face_t *,
+                               const hb_subset_input_t *input);
 
-  // Tables which should not be processed, just pass them through.
-  hb_set_t *no_subset_tables;
+  HB_INTERNAL ~hb_subset_plan_t();
 
-  // Tables which should be dropped.
-  hb_set_t *drop_tables;
+  hb_object_header_t header;
+
+  bool successful;
+  unsigned flags;
+  bool attach_accelerator_data = false;
+  bool force_long_loca = false;
 
   // The glyph subset
-  hb_map_t *codepoint_to_glyph;
+  hb_map_t *codepoint_to_glyph; // Needs to be heap-allocated
 
   // Old -> New glyph id mapping
-  hb_map_t *glyph_map;
-  hb_map_t *reverse_glyph_map;
+  hb_map_t *glyph_map; // Needs to be heap-allocated
+  hb_map_t *reverse_glyph_map; // Needs to be heap-allocated
 
   // Plan is only good for a specific source/dest so keep them with it
   hb_face_t *source;
+#ifndef HB_NO_SUBSET_CFF
+  // These have to be immediately after source:
+  hb_face_lazy_loader_t<OT::cff1_subset_accelerator_t, 1> cff1_accel;
+  hb_face_lazy_loader_t<OT::cff2_subset_accelerator_t, 2> cff2_accel;
+#endif
+
   hb_face_t *dest;
 
   unsigned int _num_output_glyphs;
-  hb_set_t *_glyphset;
-  hb_set_t *_glyphset_gsub;
-  hb_set_t *_glyphset_mathed;
-  hb_set_t *_glyphset_colred;
 
-  //active lookups we'd like to retain
-  hb_map_t *gsub_lookups;
-  hb_map_t *gpos_lookups;
+  bool all_axes_pinned;
+  bool pinned_at_default;
+  bool has_seac;
 
-  //active langsys we'd like to retain
-  hb_hashmap_t<unsigned, hb_set_t *> *gsub_langsys;
-  hb_hashmap_t<unsigned, hb_set_t *> *gpos_langsys;
+  // whether to insert a catch-all FeatureVariationRecord
+  bool gsub_insert_catch_all_feature_variation_rec;
+  bool gpos_insert_catch_all_feature_variation_rec;
 
-  //active features after removing redundant langsys and prune_features
-  hb_map_t *gsub_features;
-  hb_map_t *gpos_features;
+#define HB_SUBSET_PLAN_MEMBER(Type, Name) Type Name;
+#include "hb-subset-plan-member-list.hh"
+#undef HB_SUBSET_PLAN_MEMBER
 
-  //active layers/palettes we'd like to retain
-  hb_map_t *colrv1_layers;
-  hb_map_t *colr_palettes;
+  //recalculated head/maxp table info after instancing
+  mutable head_maxp_info_t head_maxp_info;
 
-  //The set of layout item variation store delta set indices to be retained
-  hb_set_t *layout_variation_indices;
-  //Old -> New layout item variation store delta set index mapping
-  hb_map_t *layout_variation_idx_map;
+  const hb_subset_accelerator_t* accelerator;
+  hb_subset_accelerator_t* inprogress_accelerator;
 
  public:
 
+  template<typename T>
+  struct source_table_loader
+  {
+    hb_blob_ptr_t<T> operator () (hb_subset_plan_t *plan)
+    {
+      hb_lock_t lock (plan->accelerator ? &plan->accelerator->sanitized_table_cache_lock : nullptr);
+
+      auto *cache = plan->accelerator ? &plan->accelerator->sanitized_table_cache : &plan->sanitized_table_cache;
+      if (cache
+         && !cache->in_error ()
+         && cache->has (+T::tableTag)) {
+       return hb_blob_reference (cache->get (+T::tableTag).get ());
+      }
+
+      hb::unique_ptr<hb_blob_t> table_blob {hb_sanitize_context_t ().reference_table<T> (plan->source)};
+      hb_blob_t* ret = hb_blob_reference (table_blob.get ());
+
+      if (likely (cache))
+       cache->set (+T::tableTag, std::move (table_blob));
+
+      return ret;
+    }
+  };
+
+  template<typename T>
+  auto source_table() HB_AUTO_RETURN (source_table_loader<T> {} (this))
+
   bool in_error () const { return !successful; }
 
   bool check_success(bool success)
@@ -119,7 +202,7 @@ struct hb_subset_plan_t
   inline const hb_set_t *
   glyphset () const
   {
-    return _glyphset;
+    return &_glyphset;
   }
 
   /*
@@ -128,7 +211,7 @@ struct hb_subset_plan_t
   inline const hb_set_t *
   glyphset_gsub () const
   {
-    return _glyphset_gsub;
+    return &_glyphset_gsub;
   }
 
   /*
@@ -140,15 +223,6 @@ struct hb_subset_plan_t
     return _num_output_glyphs;
   }
 
-  /*
-   * Given an output gid , returns true if that glyph id is an empty
-   * glyph (ie. it's a gid that we are dropping all data for).
-   */
-  inline bool is_empty_glyph (hb_codepoint_t gid) const
-  {
-    return !_glyphset->has (gid);
-  }
-
   inline bool new_gid_for_codepoint (hb_codepoint_t codepoint,
                                     hb_codepoint_t *new_gid) const
   {
@@ -188,7 +262,7 @@ struct hb_subset_plan_t
     if (HB_DEBUG_SUBSET)
     {
       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",
+      DEBUG_MSG(SUBSET, nullptr, "add table %c%c%c%c, dest %u bytes, source %u bytes",
                HB_UNTAG(tag),
                hb_blob_get_length (contents),
                hb_blob_get_length (source_blob));
@@ -198,13 +272,5 @@ struct hb_subset_plan_t
   }
 };
 
-typedef struct hb_subset_plan_t hb_subset_plan_t;
-
-HB_INTERNAL hb_subset_plan_t *
-hb_subset_plan_create (hb_face_t           *face,
-                      const hb_subset_input_t   *input);
-
-HB_INTERNAL void
-hb_subset_plan_destroy (hb_subset_plan_t *plan);
 
 #endif /* HB_SUBSET_PLAN_HH */
diff --git a/src/hb-subset-repacker.cc b/src/hb-subset-repacker.cc
new file mode 100644 (file)
index 0000000..6a29b35
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2022  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.
+ *
+ */
+#include "hb-repacker.hh"
+
+#ifdef HB_EXPERIMENTAL_API
+
+/**
+ * hb_subset_repack_or_fail:
+ * @table_tag: tag of the table being packed, needed to allow table specific optimizations.
+ * @hb_objects: raw array of struct hb_object_t, which provides
+ * object graph info
+ * @num_hb_objs: number of hb_object_t in the hb_objects array.
+ *
+ * Given the input object graph info, repack a table to eliminate
+ * offset overflows. A nullptr is returned if the repacking attempt fails.
+ * Table specific optimizations (eg. extension promotion in GSUB/GPOS) may be performed.
+ * Passing HB_TAG_NONE will disable table specific optimizations.
+ *
+ * XSince: EXPERIMENTAL
+ **/
+hb_blob_t* hb_subset_repack_or_fail (hb_tag_t table_tag,
+                                     hb_object_t* hb_objects,
+                                     unsigned num_hb_objs)
+{
+  hb_vector_t<const hb_object_t *> packed;
+  packed.alloc (num_hb_objs + 1);
+  packed.push (nullptr);
+  for (unsigned i = 0 ; i < num_hb_objs ; i++)
+    packed.push (&(hb_objects[i]));
+
+  return hb_resolve_overflows (packed,
+                               table_tag,
+                               20,
+                               true);
+}
+#endif
diff --git a/src/hb-subset-repacker.h b/src/hb-subset-repacker.h
new file mode 100644 (file)
index 0000000..245cf60
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright © 2022  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.
+ *
+ */
+
+#ifndef HB_SUBSET_REPACKER_H
+#define HB_SUBSET_REPACKER_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+#ifdef HB_EXPERIMENTAL_API
+/*
+ * struct hb_link_t
+ * width:    offsetSize in bytes
+ * position: position of the offset field in bytes
+ * from beginning of subtable
+ * objidx:   index of subtable
+ */
+struct hb_link_t
+{
+  unsigned width;
+  unsigned position;
+  unsigned objidx;
+};
+
+typedef struct hb_link_t hb_link_t;
+
+/*
+ * struct hb_object_t
+ * head:    start of object data
+ * tail:    end of object data
+ * num_real_links:    num of offset field in the object
+ * real_links:        pointer to array of offset info
+ * num_virtual_links: num of objects that must be packed
+ * after current object in the final serialized order
+ * virtual_links:     array of virtual link info
+ */
+struct hb_object_t
+{
+  char *head;
+  char *tail;
+  unsigned num_real_links;
+  hb_link_t *real_links;
+  unsigned num_virtual_links;
+  hb_link_t *virtual_links;
+};
+
+typedef struct hb_object_t hb_object_t;
+
+HB_EXTERN hb_blob_t*
+hb_subset_repack_or_fail (hb_tag_t table_tag,
+                          hb_object_t* hb_objects,
+                          unsigned num_hb_objs);
+
+#endif
+
+HB_END_DECLS
+
+#endif /* HB_SUBSET_REPACKER_H */
index bb46e5b..229b1c3 100644 (file)
 #include "hb-ot-hhea-table.hh"
 #include "hb-ot-hmtx-table.hh"
 #include "hb-ot-maxp-table.hh"
-#include "hb-ot-color-sbix-table.hh"
-#include "hb-ot-color-colr-table.hh"
-#include "hb-ot-color-cpal-table.hh"
+#include "OT/Color/CBDT/CBDT.hh"
+#include "OT/Color/COLR/COLR.hh"
+#include "OT/Color/CPAL/CPAL.hh"
+#include "OT/Color/sbix/sbix.hh"
 #include "hb-ot-os2-table.hh"
 #include "hb-ot-post-table.hh"
 #include "hb-ot-post-table-v2subset.hh"
 #include "hb-ot-cff2-table.hh"
 #include "hb-ot-vorg-table.hh"
 #include "hb-ot-name-table.hh"
-#include "hb-ot-color-cbdt-table.hh"
 #include "hb-ot-layout-gsub-table.hh"
 #include "hb-ot-layout-gpos-table.hh"
+#include "hb-ot-var-avar-table.hh"
+#include "hb-ot-var-cvar-table.hh"
+#include "hb-ot-var-fvar-table.hh"
 #include "hb-ot-var-gvar-table.hh"
 #include "hb-ot-var-hvar-table.hh"
+#include "hb-ot-var-mvar-table.hh"
 #include "hb-ot-math-table.hh"
+#include "hb-ot-stat-table.hh"
 #include "hb-repacker.hh"
+#include "hb-subset-accelerator.hh"
+
+using OT::Layout::GSUB;
+using OT::Layout::GPOS;
+
+
+#ifndef HB_NO_SUBSET_CFF
+template<>
+struct hb_subset_plan_t::source_table_loader<const OT::cff1>
+{
+  auto operator () (hb_subset_plan_t *plan)
+  HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff1_accel :
+                 plan->inprogress_accelerator ? plan->inprogress_accelerator->cff1_accel :
+                 plan->cff1_accel)
+};
+template<>
+struct hb_subset_plan_t::source_table_loader<const OT::cff2>
+{
+  auto operator () (hb_subset_plan_t *plan)
+  HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff2_accel :
+                 plan->inprogress_accelerator ? plan->inprogress_accelerator->cff2_accel :
+                 plan->cff2_accel)
+};
+#endif
+
 
 /**
  * SECTION:hb-subset
  * retain glyph ids option and configure the subset to pass through the layout tables untouched.
  */
 
+
+hb_user_data_key_t _hb_subset_accelerator_user_data_key = {};
+
+
+/*
+ * The list of tables in the open type spec. Used to check for tables that may need handling
+ * if we are unable to list the tables in a face.
+ */
+static hb_tag_t known_tables[] {
+  HB_TAG ('a', 'v', 'a', 'r'),
+  HB_OT_TAG_BASE,
+  HB_OT_TAG_CBDT,
+  HB_OT_TAG_CBLC,
+  HB_OT_TAG_CFF1,
+  HB_OT_TAG_CFF2,
+  HB_OT_TAG_cmap,
+  HB_OT_TAG_COLR,
+  HB_OT_TAG_CPAL,
+  HB_TAG ('c', 'v', 'a', 'r'),
+  HB_TAG ('c', 'v', 't', ' '),
+  HB_TAG ('D', 'S', 'I', 'G'),
+  HB_TAG ('E', 'B', 'D', 'T'),
+  HB_TAG ('E', 'B', 'L', 'C'),
+  HB_TAG ('E', 'B', 'S', 'C'),
+  HB_TAG ('f', 'p', 'g', 'm'),
+  HB_TAG ('f', 'v', 'a', 'r'),
+  HB_TAG ('g', 'a', 's', 'p'),
+  HB_OT_TAG_GDEF,
+  HB_OT_TAG_glyf,
+  HB_OT_TAG_GPOS,
+  HB_OT_TAG_GSUB,
+  HB_OT_TAG_gvar,
+  HB_OT_TAG_hdmx,
+  HB_OT_TAG_head,
+  HB_OT_TAG_hhea,
+  HB_OT_TAG_hmtx,
+  HB_OT_TAG_HVAR,
+  HB_OT_TAG_JSTF,
+  HB_TAG ('k', 'e', 'r', 'n'),
+  HB_OT_TAG_loca,
+  HB_TAG ('L', 'T', 'S', 'H'),
+  HB_OT_TAG_MATH,
+  HB_OT_TAG_maxp,
+  HB_TAG ('M', 'E', 'R', 'G'),
+  HB_TAG ('m', 'e', 't', 'a'),
+  HB_TAG ('M', 'V', 'A', 'R'),
+  HB_TAG ('P', 'C', 'L', 'T'),
+  HB_OT_TAG_post,
+  HB_TAG ('p', 'r', 'e', 'p'),
+  HB_OT_TAG_sbix,
+  HB_TAG ('S', 'T', 'A', 'T'),
+  HB_TAG ('S', 'V', 'G', ' '),
+  HB_TAG ('V', 'D', 'M', 'X'),
+  HB_OT_TAG_vhea,
+  HB_OT_TAG_vmtx,
+  HB_OT_TAG_VORG,
+  HB_OT_TAG_VVAR,
+  HB_OT_TAG_name,
+  HB_OT_TAG_OS2
+};
+
+static bool _table_is_empty (const hb_face_t *face, hb_tag_t tag)
+{
+  hb_blob_t* blob = hb_face_reference_table (face, tag);
+  bool result = (blob == hb_blob_get_empty ());
+  hb_blob_destroy (blob);
+  return result;
+}
+
+static unsigned int
+_get_table_tags (const hb_subset_plan_t* plan,
+                 unsigned int  start_offset,
+                 unsigned int *table_count, /* IN/OUT */
+                 hb_tag_t     *table_tags /* OUT */)
+{
+  unsigned num_tables = hb_face_get_table_tags (plan->source, 0, nullptr, nullptr);
+  if (num_tables)
+    return hb_face_get_table_tags (plan->source, start_offset, table_count, table_tags);
+
+  // If face has 0 tables associated with it, assume that it was built from
+  // hb_face_create_tables and thus is unable to list its tables. Fallback to
+  // checking each table type we can handle for existence instead.
+  auto it =
+      hb_concat (
+          + hb_array (known_tables)
+          | hb_filter ([&] (hb_tag_t tag) {
+            return !_table_is_empty (plan->source, tag) && !plan->no_subset_tables.has (tag);
+          })
+          | hb_map ([] (hb_tag_t tag) -> hb_tag_t { return tag; }),
+
+          plan->no_subset_tables.iter ()
+          | hb_filter([&] (hb_tag_t tag) {
+            return !_table_is_empty (plan->source, tag);
+          }));
+
+  it += start_offset;
+
+  unsigned num_written = 0;
+  while (bool (it) && num_written < *table_count)
+    table_tags[num_written++] = *it++;
+
+  *table_count = num_written;
+  return num_written;
+}
+
+
 static unsigned
-_plan_estimate_subset_table_size (hb_subset_plan_t *plan, unsigned table_len)
+_plan_estimate_subset_table_size (hb_subset_plan_t *plan,
+                                 unsigned table_len,
+                                 hb_tag_t table_tag)
 {
   unsigned src_glyphs = plan->source->get_num_glyphs ();
   unsigned dst_glyphs = plan->glyphset ()->get_population ();
 
-  if (unlikely (!src_glyphs))
-    return 512 + table_len;
+  unsigned bulk = 8192;
+  /* Tables that we want to allocate same space as the source table. For GSUB/GPOS it's
+   * because those are expensive to subset, so giving them more room is fine. */
+  bool same_size = table_tag == HB_OT_TAG_GSUB ||
+                  table_tag == HB_OT_TAG_GPOS ||
+                  table_tag == HB_OT_TAG_name;
+
+  if (plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS)
+  {
+    if (table_tag == HB_OT_TAG_CFF1)
+    {
+      /* Add some extra room for the CFF charset. */
+      bulk += src_glyphs * 16;
+    }
+    else if (table_tag == HB_OT_TAG_CFF2)
+    {
+      /* Just extra CharString offsets. */
+      bulk += src_glyphs * 4;
+    }
+  }
+
+  if (unlikely (!src_glyphs) || same_size)
+    return bulk + table_len;
 
-  return 512 + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs));
+  return bulk + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs));
 }
 
 /*
@@ -94,13 +253,6 @@ _plan_estimate_subset_table_size (hb_subset_plan_t *plan, unsigned table_len)
 static hb_blob_t*
 _repack (hb_tag_t tag, const hb_serialize_context_t& c)
 {
-  if (tag != HB_OT_TAG_GPOS
-      &&  tag != HB_OT_TAG_GSUB)
-  {
-    // Check for overflow in a non-handled table.
-    return c.successful () ? c.copy_blob () : nullptr;
-  }
-
   if (!c.offset_overflow ())
     return c.copy_blob ();
 
@@ -121,10 +273,9 @@ static
 bool
 _try_subset (const TableType *table,
              hb_vector_t<char>* buf,
-             unsigned buf_size,
              hb_subset_context_t* c /* OUT */)
 {
-  c->serializer->start_serialize<TableType> ();
+  c->serializer->start_serialize ();
   if (c->serializer->in_error ()) return false;
 
   bool needed = table->subset (c);
@@ -134,57 +285,67 @@ _try_subset (const TableType *table,
     return needed;
   }
 
-  buf_size += (buf_size >> 1) + 32;
+  unsigned buf_size = buf->allocated;
+  buf_size = buf_size * 2 + 16;
+
+
+
+
   DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.",
              HB_UNTAG (c->table_tag), buf_size);
 
-  if (unlikely (!buf->alloc (buf_size)))
+  if (unlikely (buf_size > c->source_blob->length * 16 ||
+               !buf->alloc (buf_size, true)))
   {
     DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.",
                HB_UNTAG (c->table_tag), buf_size);
     return needed;
   }
 
-  c->serializer->reset (buf->arrayZ, buf_size);
-  return _try_subset (table, buf, buf_size, c);
+  c->serializer->reset (buf->arrayZ, buf->allocated);
+  return _try_subset (table, buf, c);
 }
 
+template <typename T>
+static auto _do_destroy (T &t, hb_priority<1>) HB_RETURN (void, t.destroy ())
+
+template <typename T>
+static void _do_destroy (T &t, hb_priority<0>) {}
+
 template<typename TableType>
 static bool
-_subset (hb_subset_plan_t *plan)
+_subset (hb_subset_plan_t *plan, hb_vector_t<char> &buf)
 {
-  hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source);
-  const TableType *table = source_blob->as<TableType> ();
+  auto &&source_blob = plan->source_table<TableType> ();
+  auto *table = source_blob.get ();
 
   hb_tag_t tag = TableType::tableTag;
-  if (!source_blob->data)
+  hb_blob_t *blob = source_blob.get_blob();
+  if (unlikely (!blob || !blob->data))
   {
     DEBUG_MSG (SUBSET, nullptr,
                "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag));
-    hb_blob_destroy (source_blob);
+    _do_destroy (source_blob, hb_prioritize);
     return false;
   }
 
-  hb_vector_t<char> buf;
-  /* TODO Not all tables are glyph-related.  'name' table size for example should not be
-   * affected by number of glyphs.  Accommodate that. */
-  unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob->length);
+  unsigned buf_size = _plan_estimate_subset_table_size (plan, blob->length, TableType::tableTag);
   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)))
   {
     DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size);
-    hb_blob_destroy (source_blob);
+    _do_destroy (source_blob, hb_prioritize);
     return false;
   }
 
   bool needed = false;
-  hb_serialize_context_t serializer (buf.arrayZ, buf_size);
+  hb_serialize_context_t serializer (buf.arrayZ, buf.allocated);
   {
-    hb_subset_context_t c (source_blob, plan, &serializer, tag);
-    needed = _try_subset (table, &buf, buf_size, &c);
+    hb_subset_context_t c (blob, plan, &serializer, tag);
+    needed = _try_subset (table, &buf, &c);
   }
-  hb_blob_destroy (source_blob);
+  _do_destroy (source_blob, hb_prioritize);
 
   if (serializer.in_error () && !serializer.only_offset_overflow ())
   {
@@ -217,9 +378,17 @@ _subset (hb_subset_plan_t *plan)
 static bool
 _is_table_present (hb_face_t *source, hb_tag_t tag)
 {
+
+  if (!hb_face_get_table_tags (source, 0, nullptr, nullptr)) {
+    // If face has 0 tables associated with it, assume that it was built from
+    // hb_face_create_tables and thus is unable to list its tables. Fallback to
+    // checking if the blob associated with tag is empty.
+    return !_table_is_empty (source, tag);
+  }
+
   hb_tag_t table_tags[32];
   unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags);
-  while ((hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables))
+  while (((void) hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables))
   {
     for (unsigned i = 0; i < num_tables; ++i)
       if (table_tags[i] == tag)
@@ -232,12 +401,14 @@ _is_table_present (hb_face_t *source, hb_tag_t tag)
 static bool
 _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag)
 {
-  if (plan->drop_tables->has (tag))
+  if (plan->drop_tables.has (tag))
     return true;
 
   switch (tag)
   {
   case HB_TAG ('c','v','a','r'): /* hint table, fallthrough */
+    return plan->all_axes_pinned || (plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
+
   case HB_TAG ('c','v','t',' '): /* hint table, fallthrough */
   case HB_TAG ('f','p','g','m'): /* hint table, fallthrough */
   case HB_TAG ('p','r','e','p'): /* hint table, fallthrough */
@@ -257,6 +428,14 @@ _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag)
     return true;
 #endif
 
+  case HB_TAG ('a','v','a','r'):
+  case HB_TAG ('f','v','a','r'):
+  case HB_TAG ('g','v','a','r'):
+  case HB_OT_TAG_HVAR:
+  case HB_OT_TAG_VVAR:
+  case HB_TAG ('M','V','A','R'):
+    return plan->all_axes_pinned;
+
   default:
     return false;
   }
@@ -272,53 +451,102 @@ _passthrough (hb_subset_plan_t *plan, hb_tag_t tag)
 }
 
 static bool
-_subset_table (hb_subset_plan_t *plan, hb_tag_t tag)
+_dependencies_satisfied (hb_subset_plan_t *plan, hb_tag_t tag,
+                         const hb_set_t &subsetted_tags,
+                         const hb_set_t &pending_subset_tags)
+{
+  switch (tag)
+  {
+  case HB_OT_TAG_hmtx:
+  case HB_OT_TAG_vmtx:
+  case HB_OT_TAG_maxp:
+    return !plan->normalized_coords || !pending_subset_tags.has (HB_OT_TAG_glyf);
+  case HB_OT_TAG_GPOS:
+    return !plan->normalized_coords || plan->all_axes_pinned || !pending_subset_tags.has (HB_OT_TAG_GDEF);
+  default:
+    return true;
+  }
+}
+
+static bool
+_subset_table (hb_subset_plan_t *plan,
+              hb_vector_t<char> &buf,
+              hb_tag_t tag)
 {
-  if (plan->no_subset_tables->has (tag)) {
+  if (plan->no_subset_tables.has (tag)) {
     return _passthrough (plan, tag);
   }
 
   DEBUG_MSG (SUBSET, nullptr, "subset %c%c%c%c", HB_UNTAG (tag));
   switch (tag)
   {
-  case HB_OT_TAG_glyf: return _subset<const OT::glyf> (plan);
-  case HB_OT_TAG_hdmx: return _subset<const OT::hdmx> (plan);
-  case HB_OT_TAG_name: return _subset<const OT::name> (plan);
+  case HB_OT_TAG_glyf: return _subset<const OT::glyf> (plan, buf);
+  case HB_OT_TAG_hdmx: return _subset<const OT::hdmx> (plan, buf);
+  case HB_OT_TAG_name: return _subset<const OT::name> (plan, buf);
   case HB_OT_TAG_head:
     if (_is_table_present (plan->source, HB_OT_TAG_glyf) && !_should_drop_table (plan, HB_OT_TAG_glyf))
       return true; /* skip head, handled by glyf */
-    return _subset<const OT::head> (plan);
+    return _subset<const OT::head> (plan, buf);
   case HB_OT_TAG_hhea: return true; /* skip hhea, handled by hmtx */
-  case HB_OT_TAG_hmtx: return _subset<const OT::hmtx> (plan);
+  case HB_OT_TAG_hmtx: return _subset<const OT::hmtx> (plan, buf);
   case HB_OT_TAG_vhea: return true; /* skip vhea, handled by vmtx */
-  case HB_OT_TAG_vmtx: return _subset<const OT::vmtx> (plan);
-  case HB_OT_TAG_maxp: return _subset<const OT::maxp> (plan);
-  case HB_OT_TAG_sbix: return _subset<const OT::sbix> (plan);
+  case HB_OT_TAG_vmtx: return _subset<const OT::vmtx> (plan, buf);
+  case HB_OT_TAG_maxp: return _subset<const OT::maxp> (plan, buf);
+  case HB_OT_TAG_sbix: return _subset<const OT::sbix> (plan, buf);
   case HB_OT_TAG_loca: return true; /* skip loca, handled by glyf */
-  case HB_OT_TAG_cmap: return _subset<const OT::cmap> (plan);
-  case HB_OT_TAG_OS2 : return _subset<const OT::OS2 > (plan);
-  case HB_OT_TAG_post: return _subset<const OT::post> (plan);
-  case HB_OT_TAG_COLR: return _subset<const OT::COLR> (plan);
-  case HB_OT_TAG_CPAL: return _subset<const OT::CPAL> (plan);
-  case HB_OT_TAG_CBLC: return _subset<const OT::CBLC> (plan);
+  case HB_OT_TAG_cmap: return _subset<const OT::cmap> (plan, buf);
+  case HB_OT_TAG_OS2 : return _subset<const OT::OS2 > (plan, buf);
+  case HB_OT_TAG_post: return _subset<const OT::post> (plan, buf);
+  case HB_OT_TAG_COLR: return _subset<const OT::COLR> (plan, buf);
+  case HB_OT_TAG_CPAL: return _subset<const OT::CPAL> (plan, buf);
+  case HB_OT_TAG_CBLC: return _subset<const OT::CBLC> (plan, buf);
   case HB_OT_TAG_CBDT: return true; /* skip CBDT, handled by CBLC */
-  case HB_OT_TAG_MATH: return _subset<const OT::MATH> (plan);
+  case HB_OT_TAG_MATH: return _subset<const OT::MATH> (plan, buf);
 
 #ifndef HB_NO_SUBSET_CFF
-  case HB_OT_TAG_cff1: return _subset<const OT::cff1> (plan);
-  case HB_OT_TAG_cff2: return _subset<const OT::cff2> (plan);
-  case HB_OT_TAG_VORG: return _subset<const OT::VORG> (plan);
+  case HB_OT_TAG_CFF1: return _subset<const OT::cff1> (plan, buf);
+  case HB_OT_TAG_CFF2: return _subset<const OT::cff2> (plan, buf);
+  case HB_OT_TAG_VORG: return _subset<const OT::VORG> (plan, buf);
 #endif
 
 #ifndef HB_NO_SUBSET_LAYOUT
-  case HB_OT_TAG_GDEF: return _subset<const OT::GDEF> (plan);
-  case HB_OT_TAG_GSUB: return _subset<const OT::GSUB> (plan);
-  case HB_OT_TAG_GPOS: return _subset<const OT::GPOS> (plan);
-  case HB_OT_TAG_gvar: return _subset<const OT::gvar> (plan);
-  case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan);
-  case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan);
+  case HB_OT_TAG_GDEF: return _subset<const OT::GDEF> (plan, buf);
+  case HB_OT_TAG_GSUB: return _subset<const GSUB> (plan, buf);
+  case HB_OT_TAG_GPOS: return _subset<const GPOS> (plan, buf);
+  case HB_OT_TAG_gvar: return _subset<const OT::gvar> (plan, buf);
+  case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan, buf);
+  case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan, buf);
 #endif
 
+#ifndef HB_NO_VAR
+  case HB_OT_TAG_fvar:
+    if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag);
+    return _subset<const OT::fvar> (plan, buf);
+  case HB_OT_TAG_avar:
+    if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag);
+    return _subset<const OT::avar> (plan, buf);
+  case HB_OT_TAG_cvar:
+    if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag);
+    return _subset<const OT::cvar> (plan, buf);
+  case HB_OT_TAG_MVAR:
+    if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag);
+    return _subset<const OT::MVAR> (plan, buf);
+#endif
+
+  case HB_OT_TAG_STAT:
+    if (!plan->user_axes_location.is_empty ()) return _subset<const OT::STAT> (plan, buf);
+    else return _passthrough (plan, tag);
+
+  case HB_TAG ('c', 'v', 't', ' '):
+#ifndef HB_NO_VAR
+    if (_is_table_present (plan->source, HB_OT_TAG_cvar) &&
+        plan->normalized_coords && !plan->pinned_at_default)
+    {
+      auto &cvar = *plan->source->table.cvar;
+      return OT::cvar::add_cvt_and_apply_deltas (plan, cvar.get_tuple_var_data (), &cvar);
+    }
+#endif
+    return _passthrough (plan, tag);
   default:
     if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED)
       return _passthrough (plan, tag);
@@ -328,6 +556,34 @@ _subset_table (hb_subset_plan_t *plan, hb_tag_t tag)
   }
 }
 
+static void _attach_accelerator_data (hb_subset_plan_t* plan,
+                                      hb_face_t* face /* IN/OUT */)
+{
+  if (!plan->inprogress_accelerator) return;
+
+  // Transfer the accelerator from the plan to us.
+  hb_subset_accelerator_t* accel = plan->inprogress_accelerator;
+  plan->inprogress_accelerator = nullptr;
+
+  if (accel->in_error ())
+  {
+    hb_subset_accelerator_t::destroy (accel);
+    return;
+  }
+
+  // Populate caches that need access to the final tables.
+  hb_blob_ptr_t<OT::cmap> cmap_ptr (hb_sanitize_context_t ().reference_table<OT::cmap> (face));
+  accel->cmap_cache = OT::cmap::create_filled_cache (cmap_ptr);
+  accel->destroy_cmap_cache = OT::SubtableUnicodesCache::destroy;
+
+  if (!hb_face_set_user_data(face,
+                             hb_subset_accelerator_t::user_data_key(),
+                             accel,
+                             hb_subset_accelerator_t::destroy,
+                             true))
+    hb_subset_accelerator_t::destroy (accel);
+}
+
 /**
  * hb_subset_or_fail:
  * @source: font face data to be subset.
@@ -343,32 +599,102 @@ hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input)
 {
   if (unlikely (!input || !source)) return hb_face_get_empty ();
 
-  hb_subset_plan_t *plan = hb_subset_plan_create (source, input);
-  if (unlikely (plan->in_error ())) {
-    hb_subset_plan_destroy (plan);
+  hb_subset_plan_t *plan = hb_subset_plan_create_or_fail (source, input);
+  if (unlikely (!plan)) {
+    return nullptr;
+  }
+
+  hb_face_t * result = hb_subset_plan_execute_or_fail (plan);
+  hb_subset_plan_destroy (plan);
+  return result;
+}
+
+
+/**
+ * hb_subset_plan_execute_or_fail:
+ * @plan: a subsetting plan.
+ *
+ * Executes the provided subsetting @plan.
+ *
+ * Return value:
+ * on success returns a reference to generated font subset. If the subsetting operation fails
+ * returns nullptr.
+ *
+ * Since: 4.0.0
+ **/
+hb_face_t *
+hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
+{
+  if (unlikely (!plan || plan->in_error ())) {
     return nullptr;
   }
 
-  hb_set_t tags_set;
-  bool success = true;
   hb_tag_t table_tags[32];
   unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags);
-  while ((hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables))
+
+  hb_set_t subsetted_tags, pending_subset_tags;
+  while (((void) _get_table_tags (plan, offset, &num_tables, table_tags), num_tables))
   {
     for (unsigned i = 0; i < num_tables; ++i)
     {
       hb_tag_t tag = table_tags[i];
-      if (_should_drop_table (plan, tag) && !tags_set.has (tag)) continue;
-      tags_set.add (tag);
-      success = _subset_table (plan, tag);
-      if (unlikely (!success)) goto end;
+      if (_should_drop_table (plan, tag)) continue;
+      pending_subset_tags.add (tag);
     }
+
     offset += num_tables;
   }
-end:
 
-  hb_face_t *result = success ? hb_face_reference (plan->dest) : nullptr;
+  bool success = true;
 
-  hb_subset_plan_destroy (plan);
-  return result;
+  {
+    // Grouping to deallocate buf before calling hb_face_reference (plan->dest).
+
+    hb_vector_t<char> buf;
+    buf.alloc (8192 - 16);
+
+    while (!pending_subset_tags.is_empty ())
+    {
+      if (subsetted_tags.in_error ()
+         || pending_subset_tags.in_error ()) {
+       success = false;
+       goto end;
+      }
+
+      bool made_changes = false;
+      for (hb_tag_t tag : pending_subset_tags)
+      {
+       if (!_dependencies_satisfied (plan, tag,
+                                     subsetted_tags,
+                                     pending_subset_tags))
+       {
+         // delayed subsetting for some tables since they might have dependency on other tables
+         // in some cases: e.g: during instantiating glyf tables, hmetrics/vmetrics are updated
+         // and saved in subset plan, hmtx/vmtx subsetting need to use these updated metrics values
+         continue;
+       }
+
+       pending_subset_tags.del (tag);
+       subsetted_tags.add (tag);
+       made_changes = true;
+
+       success = _subset_table (plan, buf, tag);
+       if (unlikely (!success)) goto end;
+      }
+
+      if (!made_changes)
+      {
+       DEBUG_MSG (SUBSET, nullptr, "Table dependencies unable to be satisfied. Subset failed.");
+       success = false;
+       goto end;
+      }
+    }
+  }
+
+  if (success && plan->attach_accelerator_data) {
+    _attach_accelerator_data (plan, plan->dest);
+  }
+
+end:
+  return success ? hb_face_reference (plan->dest) : nullptr;
 }
index 1c65a4d..4c35699 100644 (file)
@@ -28,6 +28,7 @@
 #define HB_SUBSET_H
 
 #include "hb.h"
+#include "hb-ot.h"
 
 HB_BEGIN_DECLS
 
@@ -40,6 +41,15 @@ HB_BEGIN_DECLS
 typedef struct hb_subset_input_t hb_subset_input_t;
 
 /**
+ * hb_subset_plan_t:
+ *
+ * Contains information about how the subset operation will be executed.
+ * Such as mappings from the old glyph ids to the new ones in the subset.
+ */
+
+typedef struct hb_subset_plan_t hb_subset_plan_t;
+
+/**
  * hb_subset_flags_t:
  * @HB_SUBSET_FLAGS_DEFAULT: all flags at their default value of false.
  * @HB_SUBSET_FLAGS_NO_HINTING: If set hinting instructions will be dropped in
@@ -61,6 +71,8 @@ typedef struct hb_subset_input_t hb_subset_input_t;
  * in the final subset.
  * @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in
  * OS/2 will not be recalculated.
+ * @HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE: If set don't perform glyph closure on layout
+ * substitution rules (GSUB). Since: 7.2.0.
  *
  * List of boolean properties that can be configured on the subset input.
  *
@@ -77,6 +89,7 @@ typedef enum { /*< flags >*/
   HB_SUBSET_FLAGS_NOTDEF_OUTLINE =          0x00000040u,
   HB_SUBSET_FLAGS_GLYPH_NAMES =                     0x00000080u,
   HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES =  0x00000100u,
+  HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE =        0x00000200u,
 } hb_subset_flags_t;
 
 /**
@@ -91,6 +104,8 @@ typedef enum { /*< flags >*/
  * @HB_SUBSET_SETS_NAME_LANG_ID: the set of name lang ids that will be retained.
  * @HB_SUBSET_SETS_LAYOUT_FEATURE_TAG: the set of layout feature tags that will be retained
  * in the subset.
+ * @HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG: the set of layout script tags that will be retained
+ * in the subset. Defaults to all tags. Since: 5.0.0
  *
  * List of sets that can be configured on the subset input.
  *
@@ -104,6 +119,7 @@ typedef enum {
   HB_SUBSET_SETS_NAME_ID,
   HB_SUBSET_SETS_NAME_LANG_ID,
   HB_SUBSET_SETS_LAYOUT_FEATURE_TAG,
+  HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG,
 } hb_subset_sets_t;
 
 HB_EXTERN hb_subset_input_t *
@@ -124,7 +140,10 @@ hb_subset_input_set_user_data (hb_subset_input_t  *input,
 
 HB_EXTERN void *
 hb_subset_input_get_user_data (const hb_subset_input_t *input,
-                              hb_user_data_key_t          *key);
+                              hb_user_data_key_t      *key);
+
+HB_EXTERN void
+hb_subset_input_keep_everything (hb_subset_input_t *input);
 
 HB_EXTERN hb_set_t *
 hb_subset_input_unicode_set (hb_subset_input_t *input);
@@ -135,6 +154,9 @@ hb_subset_input_glyph_set (hb_subset_input_t *input);
 HB_EXTERN hb_set_t *
 hb_subset_input_set (hb_subset_input_t *input, hb_subset_sets_t set_type);
 
+HB_EXTERN hb_map_t*
+hb_subset_input_old_to_new_glyph_mapping (hb_subset_input_t *input);
+
 HB_EXTERN hb_subset_flags_t
 hb_subset_input_get_flags (hb_subset_input_t *input);
 
@@ -142,9 +164,78 @@ HB_EXTERN void
 hb_subset_input_set_flags (hb_subset_input_t *input,
                           unsigned value);
 
+HB_EXTERN hb_bool_t
+hb_subset_input_pin_axis_to_default (hb_subset_input_t  *input,
+                                    hb_face_t          *face,
+                                    hb_tag_t            axis_tag);
+
+HB_EXTERN hb_bool_t
+hb_subset_input_pin_axis_location (hb_subset_input_t  *input,
+                                  hb_face_t          *face,
+                                  hb_tag_t            axis_tag,
+                                  float               axis_value);
+
+#ifdef HB_EXPERIMENTAL_API
+HB_EXTERN hb_bool_t
+hb_subset_input_set_axis_range (hb_subset_input_t  *input,
+                               hb_face_t          *face,
+                               hb_tag_t            axis_tag,
+                               float               axis_min_value,
+                               float               axis_max_value,
+                               float              *axis_def_value);
+
+HB_EXTERN hb_bool_t
+hb_subset_input_override_name_table (hb_subset_input_t  *input,
+                                    hb_ot_name_id_t     name_id,
+                                    unsigned            platform_id,
+                                    unsigned            encoding_id,
+                                    unsigned            language_id,
+                                    const char         *name_str,
+                                    int                 str_len);
+
+#endif
+
+HB_EXTERN hb_face_t *
+hb_subset_preprocess (hb_face_t *source);
+
 HB_EXTERN hb_face_t *
 hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input);
 
+HB_EXTERN hb_face_t *
+hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan);
+
+HB_EXTERN hb_subset_plan_t *
+hb_subset_plan_create_or_fail (hb_face_t                 *face,
+                               const hb_subset_input_t   *input);
+
+HB_EXTERN void
+hb_subset_plan_destroy (hb_subset_plan_t *plan);
+
+HB_EXTERN hb_map_t *
+hb_subset_plan_old_to_new_glyph_mapping (const hb_subset_plan_t *plan);
+
+HB_EXTERN hb_map_t *
+hb_subset_plan_new_to_old_glyph_mapping (const hb_subset_plan_t *plan);
+
+HB_EXTERN hb_map_t *
+hb_subset_plan_unicode_to_old_glyph_mapping (const hb_subset_plan_t *plan);
+
+
+HB_EXTERN hb_subset_plan_t *
+hb_subset_plan_reference (hb_subset_plan_t *plan);
+
+HB_EXTERN hb_bool_t
+hb_subset_plan_set_user_data (hb_subset_plan_t   *plan,
+                              hb_user_data_key_t *key,
+                              void               *data,
+                              hb_destroy_func_t   destroy,
+                              hb_bool_t                  replace);
+
+HB_EXTERN void *
+hb_subset_plan_get_user_data (const hb_subset_plan_t *plan,
+                              hb_user_data_key_t     *key);
+
+
 HB_END_DECLS
 
 #endif /* HB_SUBSET_H */
index 98c5f06..4f192aa 100644 (file)
@@ -33,6 +33,7 @@
 #include "hb-subset.h"
 
 #include "hb-machinery.hh"
+#include "hb-serialize.hh"
 #include "hb-subset-input.hh"
 #include "hb-subset-plan.hh"
 
index 1a4c89c..8d3807a 100644 (file)
@@ -4,7 +4,7 @@
  *
  *   ./gen-ucd-table.py ucd.nounihan.grouped.xml
  *
- * on file with this description: Unicode 14.0.0
+ * on file with this description: Unicode 15.1.0
  */
 
 #ifndef HB_UCD_TABLE_HH
@@ -13,7 +13,7 @@
 #include "hb.hh"
 
 static const hb_script_t
-_hb_ucd_sc_map[162] =
+_hb_ucd_sc_map[165] =
 {
                    HB_SCRIPT_COMMON,              HB_SCRIPT_INHERITED,
                   HB_SCRIPT_UNKNOWN,                 HB_SCRIPT_ARABIC,
@@ -96,6 +96,8 @@ _hb_ucd_sc_map[162] =
                    HB_SCRIPT_YEZIDI,           HB_SCRIPT_CYPRO_MINOAN,
                HB_SCRIPT_OLD_UYGHUR,                 HB_SCRIPT_TANGSA,
                      HB_SCRIPT_TOTO,               HB_SCRIPT_VITHKUQI,
+                     HB_SCRIPT_MATH,                   HB_SCRIPT_KAWI,
+              HB_SCRIPT_NAG_MUNDARI,
 };
 static const uint16_t
 _hb_ucd_dm1_p0_map[825] =
@@ -1067,2903 +1069,49 @@ _hb_ucd_dm2_u64_map[388] =
 #ifndef HB_OPTIMIZE_SIZE
 
 static const uint8_t
-_hb_ucd_u8[33120] =
+_hb_ucd_u8[17884] =
 {
-    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, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 27, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   28, 26, 29, 30, 31, 32, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 33, 34, 34, 34, 34,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 36, 37, 38, 39,
-   40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
-   26, 56, 57, 58, 58, 58, 58, 59, 26, 26, 60, 58, 58, 58, 58, 58,
-   58, 58, 26, 61, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 26, 62, 58, 63, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 64, 26, 26, 65, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 66, 67, 68, 58, 58, 58, 58, 69, 58,
-   58, 58, 58, 58, 58, 58, 58, 70, 71, 72, 73, 74, 75, 76, 58, 77,
-   78, 79, 58, 80, 81, 58, 82, 83, 84, 85, 75, 86, 87, 88, 58, 58,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 89, 26, 26, 26, 26, 26, 26, 26, 90, 91, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 92, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 93, 58, 58, 58, 58, 58, 58, 26, 94, 58, 58,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 95, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   96, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 97,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 98,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-   29, 21, 21, 21, 23, 21, 21, 21, 22, 18, 21, 25, 21, 17, 21, 21,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 25, 25, 25, 21,
-   21,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 22, 21, 18, 24, 16,
-   24,  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, 22, 25, 18, 25,  0,
-   29, 21, 23, 23, 23, 23, 26, 21, 24, 26,  7, 20, 25,  1, 26, 24,
-   26, 25, 15, 15, 24,  5, 21, 21, 24, 15,  7, 19, 15, 15, 15, 21,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9, 25,  9,  9,  9,  9,  9,  9,  9,  5,
-    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
-    5,  5,  5,  5,  5,  5,  5, 25,  5,  5,  5,  5,  5,  5,  5,  5,
-    9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,
-    9,  5,  9,  5,  9,  5,  9,  5,  5,  9,  5,  9,  5,  9,  5,  9,
-    5,  9,  5,  9,  5,  9,  5,  9,  5,  5,  9,  5,  9,  5,  9,  5,
-    9,  5,  9,  5,  9,  5,  9,  5,  9,  9,  5,  9,  5,  9,  5,  5,
-    5,  9,  9,  5,  9,  5,  9,  9,  5,  9,  9,  9,  5,  5,  9,  9,
-    9,  9,  5,  9,  9,  5,  9,  9,  9,  5,  5,  5,  9,  9,  5,  9,
-    9,  5,  9,  5,  9,  5,  9,  9,  5,  9,  5,  5,  9,  5,  9,  9,
-    5,  9,  9,  9,  5,  9,  5,  9,  9,  5,  5,  7,  9,  5,  5,  5,
-    7,  7,  7,  7,  9,  8,  5,  9,  8,  5,  9,  8,  5,  9,  5,  9,
-    5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  5,  9,  5,
-    5,  9,  8,  5,  9,  5,  9,  9,  9,  5,  9,  5,  9,  5,  9,  5,
-    9,  5,  9,  5,  5,  5,  5,  5,  5,  5,  9,  9,  5,  9,  9,  5,
-    5,  9,  5,  9,  9,  9,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,
-    5,  5,  5,  5,  7,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
-    6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
-    6,  6, 24, 24, 24, 24,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
-    6,  6, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-    6,  6,  6,  6,  6, 24, 24, 24, 24, 24, 24, 24,  6, 24,  6, 24,
-   24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-    9,  5,  9,  5,  6, 24,  9,  5,  2,  2,  6,  5,  5,  5, 21,  9,
-    2,  2,  2,  2, 24, 24,  9, 21,  9,  9,  9,  2,  9,  2,  9,  9,
-    5,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  2,  9,  9,  9,  9,  9,  9,  9,  9,  9,  5,  5,  5,  5,
-    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  9,
-    5,  5,  9,  9,  9,  5,  5,  5,  9,  5,  9,  5,  9,  5,  9,  5,
-    5,  5,  5,  5,  9,  5, 25,  9,  5,  9,  9,  5,  5,  9,  9,  9,
-    9,  5, 26, 12, 12, 12, 12, 12, 11, 11,  9,  5,  9,  5,  9,  5,
-    9,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  5,
-    2,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  2,  2,  6, 21, 21, 21, 21, 21, 21,
-    5,  5,  5,  5,  5,  5,  5,  5,  5, 21, 17,  2,  2, 26, 26, 23,
-    2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 12,
-   21, 12, 12, 21, 12, 12, 21, 12,  2,  2,  2,  2,  2,  2,  2,  2,
+    0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  9, 10,  7,  7,  7,  7, 11, 12, 13, 13, 13, 14,
+   15, 16, 17, 18, 19, 20, 21, 22, 23, 22, 22, 22, 22, 24,  7,  7,
+   25, 26, 22, 22, 22, 27, 28, 29, 22, 30, 31, 32, 33, 34, 35, 36,
     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  7,
-    7,  7,  7, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    1,  1,  1,  1,  1,  1, 25, 25, 25, 21, 21, 23, 21, 21, 26, 26,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21,  1, 21, 21, 21,
-    6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21,  7,  7,
-   12,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7, 21,  7, 12, 12, 12, 12, 12, 12, 12,  1, 26, 12,
-   12, 12, 12, 12, 12,  6,  6, 12, 12, 26, 12, 12, 12, 12,  7,  7,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  7,  7,  7, 26, 26,  7,
-   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,  1,
-    7, 12,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  2,  2,  7,  7,  7,
-    7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12,
-   12, 12, 12, 12,  6,  6, 26, 21, 21, 21,  6,  2,  2, 12, 23, 23,
-    7,  7,  7,  7,  7,  7, 12, 12, 12, 12,  6, 12, 12, 12, 12, 12,
-   12, 12, 12, 12,  6, 12, 12, 12,  6, 12, 12, 12, 12, 12,  2,  2,
-   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12,  2,  2, 21,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  7, 24,  7,  7,  7,  7,  7,  7,  2,
-    1,  1,  2,  2,  2,  2,  2,  2, 12, 12, 12, 12, 12, 12, 12, 12,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  6, 12, 12, 12, 12, 12, 12,
-   12, 12,  1, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 10,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 10, 12,  7, 10, 10,
-   10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 10, 10, 12, 10, 10,
-    7, 12, 12, 12, 12, 12, 12, 12,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7, 12, 12, 21, 21, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-   21,  6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7, 12, 10, 10,  2,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  7,
-    7,  2,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,
-    7,  2,  7,  2,  2,  2,  7,  7,  7,  7,  2,  2, 12,  7, 10, 10,
-   10, 12, 12, 12, 12,  2,  2, 10, 10,  2,  2, 10, 10, 12,  7,  2,
-    2,  2,  2,  2,  2,  2,  2, 10,  2,  2,  2,  2,  7,  7,  2,  7,
-    7,  7, 12, 12,  2,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-    7,  7, 23, 23, 15, 15, 15, 15, 15, 15, 26, 23,  7, 21, 12,  2,
-    2, 12, 12, 10,  2,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  7,
-    7,  2,  7,  7,  2,  7,  7,  2,  7,  7,  2,  2, 12,  2, 10, 10,
-   10, 12, 12,  2,  2,  2,  2, 12, 12,  2,  2, 12, 12, 12,  2,  2,
-    2, 12,  2,  2,  2,  2,  2,  2,  2,  7,  7,  7,  7,  2,  7,  2,
-    2,  2,  2,  2,  2,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-   12, 12,  7,  7,  7, 12, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2, 12, 12, 10,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,
-    7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  2,  7,  7,  2,  7,  7,  7,  7,  7,  2,  2, 12,  7, 10, 10,
-   10, 12, 12, 12, 12, 12,  2, 12, 12, 10,  2, 10, 10, 12,  2,  2,
-    7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   21, 23,  2,  2,  2,  2,  2,  2,  2,  7, 12, 12, 12, 12, 12, 12,
-    2, 12, 10, 10,  2,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  7,
-    7,  2,  7,  7,  2,  7,  7,  7,  7,  7,  2,  2, 12,  7, 10, 12,
-   10, 12, 12, 12, 12,  2,  2, 10, 10,  2,  2, 10, 10, 12,  2,  2,
-    2,  2,  2,  2,  2, 12, 12, 10,  2,  2,  2,  2,  7,  7,  2,  7,
-   26,  7, 15, 15, 15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2, 12,  7,  2,  7,  7,  7,  7,  7,  7,  2,  2,  2,  7,  7,
-    7,  2,  7,  7,  7,  7,  2,  2,  2,  7,  7,  2,  7,  2,  7,  7,
-    2,  2,  2,  7,  7,  2,  2,  2,  7,  7,  7,  2,  2,  2,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2, 10, 10,
-   12, 10, 10,  2,  2,  2, 10, 10, 10,  2, 10, 10, 10, 12,  2,  2,
-    7,  2,  2,  2,  2,  2,  2, 10,  2,  2,  2,  2,  2,  2,  2,  2,
-   15, 15, 15, 26, 26, 26, 26, 26, 26, 23, 26,  2,  2,  2,  2,  2,
-   12, 10, 10, 10, 12,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,
-    7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2, 12,  7, 12, 12,
-   12, 10, 10, 10, 10,  2, 12, 12, 12,  2, 12, 12, 12, 12,  2,  2,
-    2,  2,  2,  2,  2, 12, 12,  2,  7,  7,  7,  2,  2,  7,  2,  2,
-    2,  2,  2,  2,  2,  2,  2, 21, 15, 15, 15, 15, 15, 15, 15, 26,
-    7, 12, 10, 10, 21,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,
-    7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  2,  2, 12,  7, 10, 12,
-   10, 10, 10, 10, 10,  2, 12, 10, 10,  2, 10, 10, 12, 12,  2,  2,
-    2,  2,  2,  2,  2, 10, 10,  2,  2,  2,  2,  2,  2,  7,  7,  2,
-    2,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   12, 12, 10, 10,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12,  7, 10, 10,
-   10, 12, 12, 12, 12,  2, 10, 10, 10,  2, 10, 10, 10, 12,  7, 26,
-    2,  2,  2,  2,  7,  7,  7, 10, 15, 15, 15, 15, 15, 15, 15,  7,
-   15, 15, 15, 15, 15, 15, 15, 15, 15, 26,  7,  7,  7,  7,  7,  7,
-    2, 12, 10, 10,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  7,  7,  7,  7,  7,  7,
-    7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  2,  2,  2, 12,  2,  2,  2,  2, 10,
-   10, 10, 12, 12, 12,  2, 12,  2, 10, 10, 10, 10, 10, 10, 10, 10,
-    2,  2, 10, 10, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7, 12,  7,  7, 12, 12, 12, 12, 12, 12, 12,  2,  2,  2,  2, 23,
-    7,  7,  7,  7,  7,  7,  6, 12, 12, 12, 12, 12, 12, 12, 12, 21,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  7,  7,  2,  7,  2,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,
-    7,  7,  7,  7,  2,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7, 12,  7,  7, 12, 12, 12, 12, 12, 12, 12, 12, 12,  7,  2,  2,
-    7,  7,  7,  7,  7,  2,  6,  2, 12, 12, 12, 12, 12, 12,  2,  2,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  7,  7,  7,  7,
-    7, 26, 26, 26, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-   21, 21, 21, 26, 21, 26, 26, 26, 12, 12, 26, 26, 26, 26, 26, 26,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15,
-   15, 15, 15, 15, 26, 12, 26, 12, 26, 12, 22, 18, 22, 18, 10, 10,
-    7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,
-    2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10,
-   12, 12, 12, 12, 12, 21, 12, 12,  7,  7,  7,  7,  7, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12,  2, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  2, 26, 26,
-   26, 26, 26, 26, 26, 26, 12, 26, 26, 26, 26, 26, 26,  2, 26, 26,
-   21, 21, 21, 21, 21, 26, 26, 26, 26, 21, 21,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 10, 10, 12, 12, 12,
-   12, 10, 12, 12, 12, 12, 12, 12, 10, 12, 12, 10, 10, 12, 12,  7,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 21, 21,
-    7,  7,  7,  7,  7,  7, 10, 10, 12, 12,  7,  7,  7,  7, 12, 12,
-   12,  7, 10, 10, 10,  7,  7, 10, 10, 10, 10, 10, 10, 10,  7,  7,
-    7, 12, 12, 12, 12,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7, 12, 10, 10, 12, 12, 10, 10, 10, 10, 10, 10, 12,  7, 10,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 10, 10, 10, 12, 26, 26,
-    9,  9,  9,  9,  9,  9,  2,  9,  2,  2,  2,  2,  2,  9,  2,  2,
-    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 21,  6,  5,  5,  5,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  2,  7,  2,  7,  7,  7,  7,  2,  2,
-    7,  2,  7,  7,  7,  7,  2,  2,  7,  7,  7,  7,  7,  7,  7,  2,
-    7,  2,  7,  7,  7,  7,  2,  2,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2, 12, 12, 12,
-   21, 21, 21, 21, 21, 21, 21, 21, 21, 15, 15, 15, 15, 15, 15, 15,
-   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,  2,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,  2,
-    9,  9,  9,  9,  9,  9,  2,  2,  5,  5,  5,  5,  5,  5,  2,  2,
-   17,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 26, 21,  7,
-   29,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 22, 18,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 21, 21, 21, 14, 14,
-   14,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,
-    7,  7, 12, 12, 12, 10,  2,  2,  2,  2,  2,  2,  2,  2,  2,  7,
-    7,  7, 12, 12, 10, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,
-    7,  2, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7, 12, 12, 10, 12, 12, 12, 12, 12, 12, 12, 10, 10,
-   10, 10, 10, 10, 10, 10, 12, 10, 10, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 21, 21, 21,  6, 21, 21, 21, 23,  7, 12,  2,  2,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  2,  2,  2,
-   15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,  2,  2,  2,  2,
-   21, 21, 21, 21, 21, 21, 17, 21, 21, 21, 21, 12, 12, 12,  1, 12,
-    7,  7,  7,  6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7, 12, 12,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7, 12,  7,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,
-   12, 12, 12, 10, 10, 10, 10, 12, 12, 10, 10, 10,  2,  2,  2,  2,
-   10, 10, 12, 10, 10, 10, 10, 10, 10, 12, 12, 12,  2,  2,  2,  2,
-   26,  2,  2,  2, 21, 21, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,
-    7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15,  2,  2,  2, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-    7,  7,  7,  7,  7,  7,  7, 12, 12, 10, 10, 12,  2,  2, 21, 21,
-    7,  7,  7,  7,  7, 10, 12, 10, 12, 12, 12, 12, 12, 12, 12,  2,
-   12, 10, 12, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 10,
-   10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  2,  2, 12,
-   21, 21, 21, 21, 21, 21, 21,  6, 21, 21, 21, 21, 21, 21,  2,  2,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  2,
-   12, 12, 12, 12, 10,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7, 12, 10, 12, 12, 12, 12, 12, 10, 12, 10, 10, 10,
-   10, 10, 12, 10, 10,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,
-   21, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 26, 26, 26, 26, 26, 26, 26, 26, 26, 21, 21,  2,
-   12, 12, 10,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7, 10, 12, 12, 12, 12, 10, 10, 12, 12, 10, 12, 12, 12,  7,  7,
-    7,  7,  7,  7,  7,  7, 12, 10, 12, 12, 10, 10, 10, 12, 10, 12,
-   12, 12, 10, 10,  2,  2,  2,  2,  2,  2,  2,  2, 21, 21, 21, 21,
-    7,  7,  7,  7, 10, 10, 10, 10, 10, 10, 10, 10, 12, 12, 12, 12,
-   12, 12, 12, 12, 10, 10, 12, 12,  2,  2,  2, 21, 21, 21, 21, 21,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  6,  6,  6,  6,  6,  6, 21, 21,
-    5,  5,  5,  5,  5,  5,  5,  5,  5,  2,  2,  2,  2,  2,  2,  2,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  2,  2,  9,  9,  9,
-   21, 21, 21, 21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,
-   12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 10, 12, 12, 12, 12, 12, 12, 12,  7,  7,  7,  7, 12,  7,  7,
-    7,  7,  7,  7, 12,  7,  7, 10, 12, 12,  7,  2,  2,  2,  2,  2,
-    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  6,  6,  6,  6,
-    6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  5,  5,  5,  5,  5,
-    5,  5,  5,  5,  5,  5,  5,  5,  6,  5,  5,  5,  5,  5,  5,  5,
-    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  6,  6,  6,  6,  6,
-    9,  5,  9,  5,  9,  5,  5,  5,  5,  5,  5,  5,  5,  5,  9,  5,
-    5,  5,  5,  5,  5,  5,  5,  5,  9,  9,  9,  9,  9,  9,  9,  9,
-    5,  5,  5,  5,  5,  5,  2,  2,  9,  9,  9,  9,  9,  9,  2,  2,
-    5,  5,  5,  5,  5,  5,  5,  5,  2,  9,  2,  9,  2,  9,  2,  9,
-    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,  2,
-    5,  5,  5,  5,  5,  5,  5,  5,  8,  8,  8,  8,  8,  8,  8,  8,
-    5,  5,  5,  5,  5,  2,  5,  5,  9,  9,  9,  9,  8, 24,  5, 24,
-   24, 24,  5,  5,  5,  2,  5,  5,  9,  9,  9,  9,  8, 24, 24, 24,
-    5,  5,  5,  5,  2,  2,  5,  5,  9,  9,  9,  9,  2, 24, 24, 24,
-    5,  5,  5,  5,  5,  5,  5,  5,  9,  9,  9,  9,  9, 24, 24, 24,
-    2,  2,  5,  5,  5,  2,  5,  5,  9,  9,  9,  9,  8, 24, 24,  2,
-   29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,  1,  1,  1,  1,  1,
-   17, 17, 17, 17, 17, 17, 21, 21, 20, 19, 22, 20, 20, 19, 22, 20,
-   21, 21, 21, 21, 21, 21, 21, 21, 27, 28,  1,  1,  1,  1,  1, 29,
-   21, 21, 21, 21, 21, 21, 21, 21, 21, 20, 19, 21, 21, 21, 21, 16,
-   16, 21, 21, 21, 25, 22, 18, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-   21, 21, 25, 21, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 29,
-    1,  1,  1,  1,  1,  2,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
-   15,  6,  2,  2, 15, 15, 15, 15, 15, 15, 25, 25, 25, 22, 18,  6,
-   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 25, 25, 25, 22, 18,  2,
-    6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  2,  2,  2,
-   23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
-   23,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11,
-   11, 12, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   26, 26,  9, 26, 26, 26, 26,  9, 26, 26,  5,  9,  9,  9,  5,  5,
-    9,  9,  9,  5, 26,  9, 26, 26, 25,  9,  9,  9,  9,  9, 26, 26,
-   26, 26, 26, 26,  9, 26,  9, 26,  9, 26,  9,  9,  9,  9, 26,  5,
-    9,  9,  9,  9,  5,  7,  7,  7,  7,  5, 26, 26,  5,  5,  9,  9,
-   25, 25, 25, 25, 25,  9,  5,  5,  5,  5, 26, 25, 26, 26,  5, 26,
-   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
-   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
-   14, 14, 14,  9,  5, 14, 14, 14, 14, 15, 26, 26,  2,  2,  2,  2,
-   25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 25, 25, 26, 26, 26, 26,
-   25, 26, 26, 25, 26, 26, 25, 26, 26, 26, 26, 26, 26, 26, 25, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 25,
-   26, 26, 25, 26, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-   26, 26, 26, 26, 26, 26, 26, 26, 22, 18, 22, 18, 26, 26, 26, 26,
-   25, 25, 26, 26, 26, 26, 26, 26, 26, 22, 18, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25, 25,
-   25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25,
-   25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,
-   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 15, 15, 15, 15, 15, 15,
-   26, 26, 26, 26, 26, 26, 26, 25, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25, 25, 25, 25, 25,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25,
-   26, 26, 26, 26, 26, 26, 26, 26, 22, 18, 22, 18, 22, 18, 22, 18,
-   22, 18, 22, 18, 22, 18, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
-   15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   25, 25, 25, 25, 25, 22, 18, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-   25, 25, 25, 25, 25, 25, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18,
-   25, 25, 25, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22,
-   18, 22, 18, 22, 18, 22, 18, 22, 18, 25, 25, 25, 25, 25, 25, 25,
-   25, 25, 25, 25, 25, 25, 25, 25, 22, 18, 22, 18, 25, 25, 25, 25,
-   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 22, 18, 25, 25,
-   25, 25, 25, 25, 25, 26, 26, 25, 25, 25, 25, 25, 25, 26, 26, 26,
-   26, 26, 26, 26,  2,  2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26,  2, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-    9,  5,  9,  9,  9,  5,  5,  9,  5,  9,  5,  9,  5,  9,  9,  9,
-    9,  5,  9,  5,  5,  9,  5,  5,  5,  5,  5,  5,  6,  6,  9,  9,
-    9,  5,  9,  5,  5, 26, 26, 26, 26, 26, 26,  9,  5,  9,  5, 12,
-   12, 12,  9,  5,  2,  2,  2,  2,  2, 21, 21, 21, 21, 15, 21, 21,
-    5,  5,  5,  5,  5,  5,  2,  5,  2,  2,  2,  2,  2,  5,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  6,
-   21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 12,
-    7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  2,
-   21, 21, 20, 19, 20, 19, 21, 21, 21, 20, 19, 21, 20, 19, 21, 21,
-   21, 21, 21, 21, 21, 21, 21, 17, 21, 21, 17, 21, 20, 19, 21, 21,
-   20, 19, 22, 18, 22, 18, 22, 18, 22, 18, 21, 21, 21, 21, 21,  6,
-   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 17, 17, 21, 21, 21, 21,
-   17, 21, 22, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-   26, 26, 21, 21, 21, 22, 18, 22, 18, 22, 18, 22, 18, 17,  2,  2,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2, 26, 26, 26, 26, 26,
-   26, 26, 26, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,
-   29, 21, 21, 21, 26,  6,  7, 14, 22, 18, 22, 18, 22, 18, 22, 18,
-   22, 18, 26, 26, 22, 18, 22, 18, 22, 18, 22, 18, 17, 22, 18, 18,
-   26, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, 10, 10,
-   17,  6,  6,  6,  6,  6, 26, 26, 14, 14, 14,  6,  7, 21, 26, 26,
-    7,  7,  7,  7,  7,  7,  7,  2,  2, 12, 12, 24, 24,  6,  6,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 21,  6,  6,  6,  7,
-    2,  2,  2,  2,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-   26, 26, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,
-   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 15, 15, 15, 15, 15, 15, 15, 15,
-   26, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
-    7,  7,  7,  7,  7,  6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  6, 21, 21, 21,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  7,  7,  2,  2,  2,  2,
-    9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  7, 12,
-   11, 11, 11, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21,  6,
-    9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  6,  6, 12, 12,
-    7,  7,  7,  7,  7,  7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
-   12, 12, 21, 21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,
-   24, 24, 24, 24, 24, 24, 24,  6,  6,  6,  6,  6,  6,  6,  6,  6,
-   24, 24,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,
-    5,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,
-    6,  5,  5,  5,  5,  5,  5,  5,  5,  9,  5,  9,  5,  9,  9,  5,
-    9,  5,  9,  5,  9,  5,  9,  5,  6, 24, 24,  9,  5,  9,  5,  7,
-    9,  5,  9,  5,  5,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,
-    9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  9,  9,  9,  9,  5,
-    9,  9,  9,  9,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,
-    9,  5,  9,  5,  9,  9,  9,  9,  5,  9,  5,  2,  2,  2,  2,  2,
-    9,  5,  2,  5,  2,  5,  9,  5,  9,  5,  2,  2,  2,  2,  2,  2,
-    2,  2,  6,  6,  6,  9,  5,  7,  6,  6,  5,  7,  7,  7,  7,  7,
-    7,  7, 12,  7,  7,  7, 12,  7,  7,  7,  7, 12,  7,  7,  7,  7,
-    7,  7,  7, 10, 10, 12, 12, 10, 26, 26, 26, 26, 12,  2,  2,  2,
-   15, 15, 15, 15, 15, 15, 26, 26, 23, 26,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,
-   10, 10,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
-   10, 10, 10, 10, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2, 21, 21,
-   12, 12,  7,  7,  7,  7,  7,  7, 21, 21, 21,  7, 21,  7,  7, 12,
-    7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21,
-    7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 10, 10,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 21,
-    7,  7,  7, 12, 10, 10, 12, 12, 12, 12, 10, 10, 12, 12, 10, 10,
-   10, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,  6,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  2, 21, 21,
-    7,  7,  7,  7,  7, 12,  6,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  7,  7,  7,  7,  7,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 12, 10,
-   10, 12, 12, 10, 10, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7, 12,  7,  7,  7,  7,  7,  7,  7,  7, 12, 10,  2,  2,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2, 21, 21, 21, 21,
-    6,  7,  7,  7,  7,  7,  7, 26, 26, 26,  7, 10, 12, 10,  7,  7,
-   12,  7, 12, 12, 12,  7,  7, 12, 12,  7,  7,  7,  7,  7, 12, 12,
-    7, 12,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  7,  7,  6, 21, 21,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 10, 12, 12, 10, 10,
-   21, 21,  7,  6,  6, 10, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  7,  7,  7,  7,  7,  7,  2,  2,  7,  7,  7,  7,  7,  7,  2,
-    2,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 24,  6,  6,  6,  6,
-    5,  5,  5,  5,  5,  5,  5,  5,  5,  6, 24, 24,  2,  2,  2,  2,
-    7,  7,  7, 10, 10, 12, 10, 10, 12, 10, 10, 21, 10, 12,  2,  2,
-    7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  7,  7,  7,  7,  7,
-    4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
-    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
-    5,  5,  5,  5,  5,  5,  5,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  5,  5,  5,  5,  5,  2,  2,  2,  2,  2,  7, 12,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7, 25,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  2,  7,  2,
-    7,  7,  2,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-   24, 24, 24,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 18, 22,
-    2,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2, 26,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 23, 26, 26, 26,
-   21, 21, 21, 21, 21, 21, 21, 22, 18, 21,  2,  2,  2,  2,  2,  2,
-   21, 17, 17, 16, 16, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22,
-   18, 22, 18, 22, 18, 21, 21, 22, 18, 21, 21, 21, 21, 16, 16, 16,
-   21, 21, 21,  2, 21, 21, 21, 21, 17, 22, 18, 22, 18, 22, 18, 21,
-   21, 21, 25, 17, 25, 25, 25,  2, 21, 23, 21, 21,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  1,
-    2, 21, 21, 21, 23, 21, 21, 21, 22, 18, 21, 25, 21, 17, 21, 21,
-    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 22, 25, 18, 25, 22,
-   18, 21, 22, 18, 21, 21,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  6,  6,
-    2,  2,  7,  7,  7,  7,  7,  7,  2,  2,  7,  7,  7,  7,  7,  7,
-    2,  2,  7,  7,  7,  7,  7,  7,  2,  2,  7,  7,  7,  2,  2,  2,
-   23, 23, 25, 24, 26, 23, 23,  2, 26, 25, 25, 25, 25, 26, 26,  2,
-    2,  2,  2,  2,  2,  2,  2,  2,  2,  1,  1,  1, 26, 26,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  2,  7,
-   21, 21, 21,  2,  2,  2,  2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
-   15, 15, 15, 15,  2,  2,  2, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   14, 14, 14, 14, 14, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 15, 15, 26, 26, 26,  2,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,
-   26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 12,  2,  2,
-   12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
-   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,  2,  2,
-   15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,  2,  2,  7,  7,  7,
-    7, 14,  7,  7,  7,  7,  7,  7,  7,  7, 14,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2, 21,
-    7,  7,  7,  7,  2,  2,  2,  2,  7,  7,  7,  7,  7,  7,  7,  7,
-   21, 14, 14, 14, 14, 14,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    9,  9,  9,  9,  9,  9,  9,  9,  5,  5,  5,  5,  5,  5,  5,  5,
-    9,  9,  9,  9,  2,  2,  2,  2,  5,  5,  5,  5,  5,  5,  5,  5,
-    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 21,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  2,  9,  9,  9,  9,
-    9,  9,  9,  2,  9,  9,  2,  5,  5,  5,  5,  5,  5,  5,  5,  5,
-    5,  5,  2,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
-    5,  5,  2,  5,  5,  5,  5,  5,  5,  5,  2,  5,  5,  2,  2,  2,
-    6,  6,  6,  6,  6,  6,  2,  6,  6,  6,  6,  6,  6,  6,  6,  6,
-    6,  2,  6,  6,  6,  6,  6,  6,  6,  6,  6,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  2,  2,  7,  2,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  2,  7,  7,  2,  2,  2,  7,  2,  2,  7,
-    7,  7,  7,  7,  7,  7,  2, 21, 15, 15, 15, 15, 15, 15, 15, 15,
-    7,  7,  7,  7,  7,  7,  7, 26, 26, 15, 15, 15, 15, 15, 15, 15,
-    2,  2,  2,  2,  2,  2,  2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
-    7,  7,  7,  2,  7,  7,  2,  2,  2,  2,  2, 15, 15, 15, 15, 15,
-    7,  7,  7,  7,  7,  7, 15, 15, 15, 15, 15, 15,  2,  2,  2, 21,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2, 21,
-    7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2, 15, 15,  7,  7,
-    2,  2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
-    7, 12, 12, 12,  2, 12, 12,  2,  2,  2,  2,  2, 12, 12, 12, 12,
-    7,  7,  7,  7,  2,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  2,  2, 12, 12, 12,  2,  2,  2,  2, 12,
-   15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,
-   21, 21, 21, 21, 21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 15, 15, 21,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 15, 15, 15,
-    7,  7,  7,  7,  7,  7,  7,  7, 26,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7, 12, 12,  2,  2,  2,  2, 15, 15, 15, 15, 15,
-   21, 21, 21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  2,  2,  2, 21, 21, 21, 21, 21, 21, 21,
-    7,  7,  7,  7,  7,  7,  2,  2, 15, 15, 15, 15, 15, 15, 15, 15,
-    7,  7,  7,  2,  2,  2,  2,  2, 15, 15, 15, 15, 15, 15, 15, 15,
-    7,  7,  2,  2,  2,  2,  2,  2,  2, 21, 21, 21, 21,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  2,  2,  2, 15, 15, 15, 15, 15, 15, 15,
-    9,  9,  9,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    5,  5,  5,  2,  2,  2,  2,  2,  2,  2, 15, 15, 15, 15, 15, 15,
-    7,  7,  7,  7, 12, 12, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,
-   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2, 12, 12, 17,  2,  2,
-    7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   15, 15, 15, 15, 15, 15, 15,  7,  2,  2,  2,  2,  2,  2,  2,  2,
-   12, 15, 15, 15, 15, 21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,
-    7,  7, 12, 12, 12, 12, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7, 15, 15, 15, 15, 15, 15, 15,  2,  2,  2,  2,
-   10, 12, 10,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21,  2,  2,
-   15, 15, 15, 15, 15, 15, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-   12,  7,  7, 12, 12,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2, 12,
-   10, 10, 10, 12, 12, 12, 12, 10, 10, 12, 12, 21, 21,  1, 21, 21,
-   21, 21, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  1,  2,  2,
-   12, 12, 12,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 10, 12, 12, 12,
-   12, 12, 12, 12, 12,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-   21, 21, 21, 21,  7, 10, 10,  7,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7, 12, 21, 21,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10,
-   10,  7,  7,  7,  7, 21, 21, 21, 21, 12, 12, 12, 12, 21, 10, 12,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  7, 21,  7, 21, 21, 21,
-    2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
-   15, 15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 10, 10, 10, 12,
-   12, 12, 10, 10, 12, 10, 12, 12, 21, 21, 21, 21, 21, 21, 12,  2,
-    7,  7,  7,  7,  7,  7,  7,  2,  7,  2,  7,  7,  7,  7,  2,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7, 21,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12,
-   10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12,  2,  2,  2,  2,  2,
-   12, 12, 10, 10,  2,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  7,
-    7,  2,  7,  7,  2,  7,  7,  7,  7,  7,  2, 12, 12,  7, 10, 10,
-   12, 10, 10, 10, 10,  2,  2, 10, 10,  2,  2, 10, 10, 10,  2,  2,
-    7,  2,  2,  2,  2,  2,  2, 10,  2,  2,  2,  2,  2,  7,  7,  7,
-    7,  7, 10, 10,  2,  2, 12, 12, 12, 12, 12, 12, 12,  2,  2,  2,
-   12, 12, 12, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12,
-   10, 10, 12, 12, 12, 10, 12,  7,  7,  7,  7, 21, 21, 21, 21, 21,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21,  2, 21, 12,  7,
-   10, 10, 10, 12, 12, 12, 12, 12, 12, 10, 12, 10, 10, 10, 10, 12,
-   12, 10, 12, 12,  7,  7, 21,  7,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 10,
-   10, 10, 12, 12, 12, 12,  2,  2, 10, 10, 10, 10, 12, 12, 10, 12,
-   12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-   21, 21, 21, 21, 21, 21, 21, 21,  7,  7,  7,  7, 12, 12,  2,  2,
-   10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 12, 10, 12,
-   12, 21, 21, 21,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 10, 12, 10, 10,
-   12, 12, 12, 12, 12, 12, 10, 12,  7, 21,  2,  2,  2,  2,  2,  2,
-   10, 10, 12, 12, 12, 12, 10, 12, 12, 12, 12, 12,  2,  2,  2,  2,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 21, 21, 21, 26,
-   12, 12, 12, 12, 12, 12, 12, 12, 10, 12, 12, 21,  2,  2,  2,  2,
-   15, 15, 15,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  7,
-    7,  7,  7,  7,  7,  7,  7,  2,  2,  7,  2,  2,  7,  7,  7,  7,
-    7,  7,  7,  7,  2,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,
-   10, 10, 10, 10, 10, 10,  2, 10, 10,  2,  2, 12, 12, 10, 12,  7,
-   10,  7, 10, 12, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  7,  7,  7,  7,  7,  7,
-    7, 10, 10, 10, 12, 12, 12, 12,  2,  2, 12, 12, 10, 10, 10, 10,
-   12,  7, 21,  7, 10,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    7, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  7,  7,  7,  7,  7,
-    7,  7,  7, 12, 12, 12, 12, 12, 12, 10,  7, 12, 12, 12, 12, 21,
-   21, 21, 21, 21, 21, 21, 21, 12,  2,  2,  2,  2,  2,  2,  2,  2,
-    7, 12, 12, 12, 12, 12, 12, 10, 10, 12, 12, 12,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 10, 12, 12, 21, 21, 21,  7, 21, 21,
-   21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   12, 12, 12, 12, 12, 12, 12,  2, 12, 12, 12, 12, 12, 12, 10, 12,
-    7, 21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   21, 21,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    2,  2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12,  2, 10, 12, 12, 12, 12, 12, 12,
-   12, 10, 12, 12, 10, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  2,  7,  7,  7,  7,  7,
-    7, 12, 12, 12, 12, 12, 12,  2,  2,  2, 12,  2, 12, 12,  2, 12,
-   12, 12, 12, 12, 12, 12,  7, 12,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  2,  7,  7,  2,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 10, 10, 10, 10, 10,  2,
-   12, 12,  2, 10, 10, 12, 10, 12,  7,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7, 12, 12, 10, 10, 21, 21,  2,  2,  2,  2,  2,  2,  2,
-   15, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, 26, 23, 23, 23,
-   23, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 21,
-   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,  2,
-   21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    7, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    1,  1,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,
-   12, 12, 12, 12, 12, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 26, 26, 26, 26,
-    6,  6,  6,  6, 21, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2, 15, 15, 15, 15, 15,
-   15, 15,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  7,  7,  7,
-   15, 15, 15, 15, 15, 15, 15, 21, 21, 21, 21,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2, 12,
-    7, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
-   10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
-   10, 10, 10, 10, 10, 10, 10, 10,  2,  2,  2,  2,  2,  2,  2, 12,
-   12, 12, 12,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
-    6,  6, 21,  6, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   10, 10,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    6,  6,  6,  6,  2,  6,  6,  6,  6,  6,  6,  6,  2,  6,  6,  2,
-    7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2, 26, 12, 12, 21,
-    1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  2,  2,
-   12, 12, 12, 12, 12, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   26, 26, 26, 26, 26, 26, 26,  2,  2, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 10, 10, 12, 12, 12, 26, 26, 26, 10, 10, 10,
-   10, 10, 10,  1,  1,  1,  1,  1,  1,  1,  1, 12, 12, 12, 12, 12,
-   12, 12, 12, 26, 26, 12, 12, 12, 12, 12, 12, 12, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 12, 12, 12, 12, 26, 26,
-   26, 26, 12, 12, 12, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  5,  5,  5,  5,  5,  5,
-    5,  5,  5,  5,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  5,  5,
-    5,  5,  5,  5,  5,  2,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
-    9,  9,  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,  9,  2,  9,  9,
-    2,  2,  9,  2,  2,  9,  9,  2,  2,  9,  9,  9,  9,  2,  9,  9,
-    9,  9,  9,  9,  9,  9,  5,  5,  5,  5,  2,  5,  2,  5,  5,  5,
-    5,  5,  5,  5,  2,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
-    5,  5,  5,  5,  9,  9,  2,  9,  9,  9,  9,  2,  2,  9,  9,  9,
-    9,  9,  9,  9,  9,  2,  9,  9,  9,  9,  9,  9,  9,  2,  5,  5,
-    5,  5,  5,  5,  5,  5,  5,  5,  9,  9,  2,  9,  9,  9,  9,  2,
-    9,  9,  9,  9,  9,  2,  9,  2,  2,  2,  9,  9,  9,  9,  9,  9,
-    9,  2,  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,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
-    5,  5,  5,  5,  5,  5,  2,  2,  9,  9,  9,  9,  9,  9,  9,  9,
-    9, 25,  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, 25,  5,  5,  5,  5,
-    5,  5,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 25,  5,  5,  5,  5,
-    5,  5,  5,  5,  5, 25,  5,  5,  5,  5,  5,  5,  9,  9,  9,  9,
-    9,  9,  9,  9,  9, 25,  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, 25,
-    5,  5,  5,  5,  5,  5,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 25,
-    5,  5,  5,  5,  5,  5,  5,  5,  5, 25,  5,  5,  5,  5,  5,  5,
-    9,  9,  9,  9,  9,  9,  9,  9,  9, 25,  5,  5,  5,  5,  5,  5,
-    5,  5,  5, 25,  5,  5,  5,  5,  5,  5,  9,  5,  2,  2, 13, 13,
+    7,  7,  7,  7, 37,  7, 38, 39,  7, 40,  7,  7,  7, 41, 22, 42,
+    7,  7, 43,  7, 44, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   45, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-   12, 12, 12, 12, 12, 12, 12, 26, 26, 26, 26, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 26, 26, 26,
-   26, 26, 26, 26, 26, 12, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 12, 26, 26, 21, 21, 21, 21, 21,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 12, 12, 12, 12, 12,
-    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  7,  5,  5,  5,  5,  5,
-    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,
-   12, 12, 12, 12, 12, 12, 12,  2, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12,  2,  2, 12, 12, 12, 12, 12,
-   12, 12,  2, 12, 12,  2, 12, 12, 12, 12, 12,  2,  2,  2,  2,  2,
-   12, 12, 12, 12, 12, 12, 12,  6,  6,  6,  6,  6,  6,  6,  2,  2,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  2,  7, 26,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  2,  2, 23,
-    7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  2,  7,  7,  2,
-    7,  7,  7,  7,  7,  2,  2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
-    5,  5,  5,  5, 12, 12, 12, 12, 12, 12, 12,  6,  2,  2,  2,  2,
-   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 15, 15, 15,
-   23, 15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 15,
-   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,
-    7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    2,  7,  7,  2,  7,  2,  2,  7,  2,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  2,  7,  7,  7,  7,  2,  7,  2,  7,  2,  2,  2,  2,
-    2,  2,  7,  2,  2,  2,  2,  7,  2,  7,  2,  7,  2,  7,  7,  7,
-    2,  7,  7,  2,  7,  2,  2,  7,  2,  7,  2,  7,  2,  7,  2,  7,
-    2,  7,  7,  2,  7,  2,  2,  7,  7,  7,  7,  2,  7,  7,  7,  7,
-    7,  7,  7,  2,  7,  7,  7,  7,  2,  7,  7,  7,  7,  2,  7,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,
-    2,  7,  7,  7,  2,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,
-   25, 25,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,
-    2,  2,  2,  2,  2,  2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,  2,  2,
-   26, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 24, 24, 24, 24, 24,
-   26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,  2,  2,  2,
-   26, 26, 26, 26, 26,  2,  2,  2, 26, 26, 26, 26, 26,  2,  2,  2,
-   26, 26, 26,  2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-    2,  1,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
-    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  2,  2,
-    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  0,
-    0,  0,  0,  0,  0,  0,  1,  0,  0,  2,  0,  3,  4,  5,  6,  7,
-    8,  9, 10, 11, 12, 12, 12, 13, 14, 12, 15, 16, 17, 18, 19, 20,
-   21, 22,  0,  0,  0,  0, 23,  0,  0,  0,  0,  0,  0,  0, 24, 25,
-    0, 26, 27,  0, 28, 29, 30, 31, 32, 33,  0, 34,  0,  0,  0,  0,
-    0, 35,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0, 36, 37, 38,  0,  0,  0,  0,
-   39, 40,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 41, 42,  0,  0,
-   43, 44, 45, 46,  0, 47,  0, 48,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 49,  0,  0,  0,  0,  0, 50,  0,  0,  0,
-    0,  0,  0, 51,  0, 52, 53,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0, 54, 55,  0,  0,  0,  0, 56,  0,  0, 57, 58, 59,
-   60, 61, 62, 63, 64, 65, 66,  0, 67, 68,  0, 69, 70, 71, 72,  0,
-   61,  0, 73, 74, 75, 76,  0,  0, 70,  0, 77, 78,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0, 79, 80,  0,  0,  0,  0,  0,  0,  0,  0, 81,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0, 82,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0, 83, 84, 85,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-   86,  0, 80,  0,  0, 87,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0, 88, 89,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  1,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,
-   12,  1,  0,  0, 13,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 14, 15, 16, 17, 18, 19, 20,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  1, 21,  0,  0,  0,  0,  0, 22, 23, 24,
-    0,  0, 25,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 26, 27,
-   28, 29,  0,  0,  0,  0, 30,  0,  0,  0, 31, 32, 33, 34,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0, 13, 35, 36,  0,  0, 26, 37, 38, 39,  0,  0,  0,  0,  0, 40,
-    0,  0,  0,  0,  0,  0,  0, 41,  0,  0,  0,  0,  0, 42, 43,  1,
-   44, 45, 46, 47,  0,  0,  0,  0,  0,  0,  0, 48,  0, 49, 50,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 48,  0, 49,  0,  0,
-    0,  0,  0, 51,  0,  0,  0,  0,  0,  0,  0, 48,  0, 49,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 49,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 48,  0, 49, 52,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 53,  0, 49,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 54,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 55,  0, 56,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 57,  0, 58,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 59,  0,  0, 60, 61,  0,  0,  0,  0,
-    0,  0, 62, 63, 64,  0,  0,  0,  0,  0,  0,  0, 65,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 66, 67,  0,  0,  0,  0,
-    0,  0,  0,  0,  0, 36,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 68,
-    0,  0,  0,  0,  0,  0, 69,  0,  0,  0, 70,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 54, 71,
-    0,  0,  0,  0,  0,  0,  0,  0,  0, 72,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 73,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 74, 75,  0,  0,  0,  0,  0,  0,  0,  0,
-   76,  0, 68, 77,  0,  0,  0,  0,  0,  0, 78, 79, 80, 81,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 48,  0, 70,  0,  0,  0,
-    0, 82, 83,  0,  0,  0,  0,  0,  0, 84,  0,  0,  0,  0,  0,  0,
-   85,  0, 84,  0,  0,  0,  0,  0,  0,  0, 66,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 86, 87,
-   88, 89, 90, 91,  0,  0,  0,  0,  0,  0,  0,  0, 92, 93, 94,  1,
-    1,  1, 95, 96,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 97, 98,
-   99,100,101,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0, 74, 91,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,102,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    1,  1,  1,  1,  0,  0,  0,  0,  0,103,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,104,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0, 74,105,106,  0,  0,  0, 26,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0, 91,  0,107,  0,  0,  0,  0, 70,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 70,  0,  0,  0,
-    1,  1, 91,  0,  0,  0,  0,  0,  0,108,  0,  0,  0,  0,109,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,110,  0, 76,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,111,112,113,  0,  0,  0,
-    0,  0,107,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0, 49,  0,  0,  0,  0,  0,114,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,115,116,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0, 36,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-   75,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0, 26,117,  0,118,  0,  0,  0,  0,  0,119,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-  120,  0,  0,  0,  0,  0,  0,  0,105,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,121,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,122,123, 75,  0,
-    0,  0,  0,  0,124,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,  0,  0,
-    0,  0, 76,102,  0,  0,  0,  0,  0,  0,  0,125,  0,  0,  0,  0,
-    0,  0,  0,  0,117,  0,  0,  0,  0,  0, 53,  0,  0,  0,  0,  0,
-    0,  0,110,  0,  0,  0,  0,  0,  0,  0,  0,  0, 76,126,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,127,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,128,  0,  0,  0,  0,  0,  0,  0,  0,  0,129,  0, 49,  0,  0,
-   26,130,130,  0,  0,  0,  0,  0,  0,  0,  0,  0,131,  0,  0, 51,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,132,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,102,133,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,102,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,134,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,109,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,135,110,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-   76,  0,  0,  0,  0,  0,  0,  0,  0,  0, 70,  0,102,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,136,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,137,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,102,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,138,  0,  0,  0,  0,  0,  0,  0,139,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,140,  0,  0,  0,  0,141,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-  142,143,144,145,146,147,  0,  0,  0,148,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,149,  0,  0,  0,
-    0,  0,  0,  0,139,  1,  1,150,151,117,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0, 51,  0,  0,  0,  0,  0,  0,
-    0,105,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,152,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,105,153,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,230,230,230,
-  230,230,230,230,230,230,230,230,230,232,220,220,220,220,232,216,
-  220,220,220,220,220,202,202,220,220,220,220,202,202,220,220,220,
-  220,220,220,220,220,220,220,220,  1,  1,  1,  1,  1,220,220,220,
-  220,230,230,230,230,230,230,230,230,240,230,220,220,220,230,230,
-  230,220,220,  0,230,230,230,220,220,220,220,230,232,220,220,230,
-  233,234,234,233,234,234,233,230,230,230,230,230,  0,  0,  0,230,
-  230,230,230,230,  0,220,230,230,230,230,220,230,230,230,222,220,
-  230,230,230,230,230,230,220,220,220,220,220,220,230,230,220,230,
-  230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20,
-   21, 22,  0, 23,  0, 24, 25,  0,230,220,  0, 18, 30, 31, 32,  0,
-    0,  0,  0,  0,  0,  0,  0, 27, 28, 29, 30, 31, 32, 33, 34,230,
-  230,220,220,230,230,230,230,230,220,230,230,220, 35,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,230,230,230,230,230,
-  230,  0,  0,230,230,230,230,220,230,  0,  0,230,230,  0,220,230,
-  230,220,  0,  0,  0, 36,  0,  0,  0,  0,  0,  0,230,220,230,230,
-  220,230,230,220,220,220,230,220,220,230,220,230,230,230,220,230,
-  220,230,220,230,220,230,230,  0,  0,  0,  0,  0,230,230,220,230,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,220,  0,  0,230,230,  0,230,
-  230,230,230,230,230,230,230,230,  0,230,230,230,  0,230,230,230,
-  230,230,  0,  0,  0,220,220,220,  0,  0,  0,  0,230,220,220,220,
-  230,230,230,230,  0,  0,230,230,230,230,230,220,220,220,220,220,
-  230,230,230,230,230,230,  0,220,230,230,220,230,230,220,230,230,
-  230,220,220,220, 27, 28, 29,230,230,230,220,230,230,220,220,230,
-  230,230,230,230,  0,  0,  0,  0,  7,  0,  0,  0,  0,  0,  0,  0,
-    0,  9,  0,  0,  0,230,220,230,230,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,230,  0,  0,  0,  0,  0,  0, 84, 91,  0,  0,  0,  0,  9,
-    9,  0,  0,  0,  0,  0,  9,  0,  0,  0,  0,  0,103,103,  9,  0,
-    0,  0,  0,  0,107,107,107,107,  0,  0,  0,  0,118,118,  9,  0,
-    0,  0,  0,  0,122,122,122,122,  0,  0,  0,  0,220,220,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,220,  0,220,  0,216,  0,  0,
-    0,  0,  0,  0,  0,129,130,  0,132,  0,  0,  0,  0,  0,130,130,
-  130,130,  0,  0,130,  0,230,230,  9,  0,230,230,  0,  0,  0,  0,
-    0,  0,220,  0,  0,  0,  0,  0,  0,  0,  0,  7,  0,  9,  9,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,230,230,230,  0,  0,  0,  0,
-    9,  9,  0,  0,  0,  0,  0,  0,  9,  0,  0,  0,  0,  0,  0,  0,
-    0,230,  0,  0,  0,228,  0,  0,  0,  0,  0,  0,  0,222,230,220,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,220,  0,  0,  0,
-    0,  0,  0,  0,  9,  0,  0,  0,  0,  0,  0,  0,230,230,230,230,
-  230,  0,  0,220,230,230,230,230,230,220,220,220,220,220,220,230,
-  230,220,  0,220,220,230,230,220,220,230,230,230,230,230,220,230,
-  230,230,230,  0,  0,  0,  0,230,220,230,230,230,230,230,230,230,
-    0,  0,  0,  0,  0,  0,  9,  9,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  7,  0,230,230,230,  0,  1,220,220,220,220,220,230,230,
-  220,220,220,220,230,  0,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,
-    0,220,  0,  0,  0,  0,  0,  0,230,  0,  0,  0,230,230,  0,  0,
-    0,  0,  0,  0,230,230,220,230,230,230,230,230,230,230,220,230,
-  230,234,214,220,202,230,230,230,230,230,230,230,230,230,230,230,
-  230,230,232,228,228,220,218,230,233,220,230,220,230,230,  1,  1,
-  230,230,230,230,  1,  1,  1,230,230,  0,  0,  0,  0,230,  0,  0,
-    0,  1,  1,230,220,230,  1,  1,220,220,220,220,230,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  0,  0,218,228,
-  232,222,224,224,  0,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-  230,230,230,230,230,230,230,230,230,230,  0,  0,  0,  0,  0,  0,
-    0,  0,  9,  0,  0,  0,  0,220,220,220,  0,  0,  0,  0,  0,  9,
-    0,  0,  0,  0,  0,  0,  0,  7,  0,  0,  0,  0,230,  0,230,230,
-  220,  0,  0,230,230,  0,  0,  0,  0,  0,230,230,  0,230,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 26,  0,230,230,230,230,
-  230,230,230,220,220,220,220,220,220,220,230,230,230,230,230,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,220,  0,230,230,  1,220,  0,
-    0,  0,  0,  9,  0,  0,  0,  0,  0,230,220,  0,  0,  0,  0,230,
-  230,  0,  0,  0,  0,  0,  0,  0,  0,  0,220,220,230,230,230,220,
-  230,220,220,220,  0,  0,230,220,230,220,  0,  0,  0,  9,  7,  0,
-    0,  0,  0,  0,  0,  0,  7,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  9,  7,  0,  0,  7,  9,  0,  0,  0,  0,  0,  0,  0,  0,  7,
-    7,  0,  0,  0,230,230,230,230,230,  0,  0,  0,  0,  0,  9,  0,
-    0,  0,  7,  0,  0,  0,  9,  7,  0,  0,  0,  0,  7,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  7,  0,  0,  0,  0,
-    0,  9,  9,  0,  0,  9,  0,  0,  0,  0,  0,  0,  0,  0,  7,  0,
-    9,  9,  0,  0,  1,  1,  1,  1,  1,  0,  0,  0,230,230,230,230,
-  230,230,230,  0,  6,  6,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  1,  0,  0,  0,  0,  0,  0,216,216,  1,  1,  1,  0,  0,
-    0,226,216,216,216,216,216,  0,  0,  0,  0,  0,  0,  0,  0,220,
-  220,220,220,220,220,220,220,  0,  0,230,230,230,230,230,220,220,
-    0,  0,  0,  0,  0,  0,230,230,230,230,  0,  0,  0,  0,230,230,
-  230,  0,  0,  0,230,  0,  0,230,230,230,230,230,230,230,  0,230,
-  230,  0,230,230,220,220,220,220,220,220,220,  0,230,230,  7,  0,
-    0,  0,  0,  0, 16, 17, 17, 17, 17, 17, 17, 33, 17, 17, 17, 19,
-   17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27, 28, 17, 17, 17,
-   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17,237,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,
-    0,  0,  0,  2,  0,  0,  0,  0,  0,  0,  3,  4,  0,  0,  0,  0,
-    0,  0,  3,  4,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  5,  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,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  7,  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,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8,  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, 10,  0,  0, 10,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0, 10,  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, 11, 12,  0, 13,  0, 14, 15, 16,  0,  0,
-    0,  0,  0,  1, 17, 18,  0, 19,  7,  1,  0,  0,  0, 20, 20,  7,
-   20, 20, 20, 20, 20, 20, 20,  8, 21,  0, 22,  0,  7, 23, 24,  0,
-   20, 20, 25,  0,  0,  0, 26, 27,  1,  7, 20, 20, 20, 20, 20,  1,
-   28, 29, 30, 31,  0,  0, 20,  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,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 20, 20,
-   20,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  8, 21, 32,  4,  0, 10,  0, 33,  7, 20, 20, 20,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  8, 34, 34, 35, 36, 34, 37,  0, 38,  1, 20, 20,
-    0,  0, 39,  0,  1,  1,  0,  8, 21,  1, 20,  0,  0,  0,  1,  0,
-    0, 40,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8, 21,
-    0,  1,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,
-    0,  0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21,  7, 20, 41,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 21,  0, 42, 43, 44,  0, 45,
-    0,  8, 21,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0, 46,  7,  1, 10,  1,  0,  0,  0,  1, 20, 20,  1,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0, 26, 34,  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, 20, 20,  1, 20, 20,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 26, 21,  0,  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,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  2,  0,  0,  0,  0,
-    0,  0,  3,  4,  0,  0,  0,  0,  0,  0,  3, 47, 48,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,
-    0,  0,  0,  2,  0,  0,  0,  0,  0,  0,  3,  4,  0,  0,  0,  0,
-    0,  0,  3,  4,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,
-   12, 13, 14, 15, 16, 17, 18, 17, 19, 20, 21, 22, 23, 24, 25, 25,
-   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 25, 25, 25, 25, 25,
-   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-   25, 25, 25, 25, 27, 27, 28, 29, 30, 31, 32, 32, 32, 32, 32, 32,
-   32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
-   51, 52, 53, 54, 55, 56, 57, 34, 34, 34, 34, 58, 59, 59, 60, 34,
-   34, 34, 34, 34, 34, 34, 61, 62, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 63, 64, 34, 65, 66, 66, 66, 66,
-   66, 66, 66, 66, 66, 66, 66, 67, 66, 68, 69, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 70, 71, 72, 34, 34,
-   34, 34, 73, 34, 34, 34, 34, 34, 34, 34, 34, 74, 75, 76, 77, 78,
-   79, 80, 34, 81, 82, 83, 34, 84, 85, 34, 86, 87, 88, 89, 17, 90,
-   91, 92, 34, 34, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-   25, 25, 25, 25, 25, 25, 25, 93, 25, 25, 25, 25, 25, 25, 25, 94,
-   95, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 96, 25, 25, 25, 25,
-   25, 25, 25, 25, 25, 25, 25, 25, 25, 97, 34, 34, 34, 34, 34, 34,
-   25, 98, 34, 34, 25, 25, 25, 25, 25, 25, 25, 25, 25, 99, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34,100,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-   19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-   19,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-   19,  0,  0,  0,  0,  0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-   19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,  0, 19, 19,
-   19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,  0,
-    0,  0,  0,  0,  0,  0, 19, 19, 19, 19, 19,  0,  0,  0,  0,  0,
-   26, 26,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
-    1,  1,  1,  1,  1,  1,  9,  9,  9,  9,  0,  9,  9,  9,  2,  2,
-    9,  9,  9,  9,  0,  9,  2,  2,  2,  2,  9,  0,  9,  0,  9,  9,
-    9,  2,  9,  2,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  2,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9, 55, 55, 55, 55, 55, 55, 55, 55,
-   55, 55, 55, 55, 55, 55,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
-    6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  1,  1,  6,  6,  6,
-    6,  6,  6,  6,  6,  6,  2,  4,  4,  4,  4,  4,  4,  4,  4,  4,
-    4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
-    4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  2,  2,  4,
-    4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
-    4,  2,  2,  4,  4,  4,  2, 14, 14, 14, 14, 14, 14, 14, 14, 14,
-   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
-   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,  2,  2,
-    2,  2,  2,  2,  2,  2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
-   14,  2,  2,  2,  2, 14, 14, 14, 14, 14, 14,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  0,  3,  3,  3,  3,
-    3,  3,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
-    3,  0,  3,  3,  3,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
-    3,  3,  3,  3,  3,  3,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,
-    3,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  3,  3,  3,  3,
-    3,  3,  3,  3,  3,  3,  1,  3,  3,  3,  3,  3,  3,  3,  3,  3,
-    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
-    3,  3,  3,  0,  3,  3, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
-   37, 37, 37, 37,  2, 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,  2,  2, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
-   38, 38, 38, 38, 38, 38, 38, 38,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
-   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
-   64,  2,  2, 64, 64, 64, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
-   90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
-   90, 90, 90, 90,  2,  2, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
-   90, 90, 90, 90, 90,  2, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
-   95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
-   95, 95,  2,  2, 95,  2, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
-   37,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
-    3,  3,  3,  3,  3,  2,  3,  3,  2,  2,  2,  2,  2,  2,  3,  3,
-    3,  3,  3,  3,  3,  3,  3,  3,  0,  3,  3,  3,  3,  3,  3,  3,
-    3,  3,  3,  3,  3,  3,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  1,  1,  1,  1,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  0,  0,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  5,  5,  5,  5,  2,  5,  5,  5,  5,  5,
-    5,  5,  5,  2,  2,  5,  5,  2,  2,  5,  5,  5,  5,  5,  5,  5,
-    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,
-    5,  5,  5,  5,  5,  5,  5,  2,  5,  2,  2,  2,  5,  5,  5,  5,
-    2,  2,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,  2,  5,  5,  2,
-    2,  5,  5,  5,  5,  2,  2,  2,  2,  2,  2,  2,  2,  5,  2,  2,
-    2,  2,  5,  5,  2,  5,  5,  5,  5,  5,  2,  2,  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,  2,  2, 11, 11, 11,  2, 11, 11, 11, 11, 11,
-   11,  2,  2,  2,  2, 11, 11,  2,  2, 11, 11, 11, 11, 11, 11, 11,
-   11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,  2,
-   11, 11, 11, 11, 11, 11, 11,  2, 11, 11,  2, 11, 11,  2, 11, 11,
-    2,  2, 11,  2, 11, 11, 11, 11, 11,  2,  2,  2,  2, 11, 11,  2,
-    2, 11, 11, 11,  2,  2,  2, 11,  2,  2,  2,  2,  2,  2,  2, 11,
-   11, 11, 11,  2, 11,  2,  2,  2,  2,  2,  2,  2, 11, 11, 11, 11,
-   11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  2, 10, 10, 10,  2, 10, 10, 10, 10, 10,
-   10, 10, 10, 10,  2, 10, 10, 10,  2, 10, 10, 10, 10, 10, 10, 10,
-   10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,  2,
-   10, 10, 10, 10, 10, 10, 10,  2, 10, 10,  2, 10, 10, 10, 10, 10,
-    2,  2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,  2, 10, 10, 10,
-    2, 10, 10, 10,  2,  2, 10,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 10, 10, 10, 10,  2,  2, 10, 10, 10, 10,
-   10, 10, 10, 10, 10, 10, 10, 10,  2,  2,  2,  2,  2,  2,  2, 10,
-   10, 10, 10, 10, 10, 10,  2, 21, 21, 21,  2, 21, 21, 21, 21, 21,
-   21, 21, 21,  2,  2, 21, 21,  2,  2, 21, 21, 21, 21, 21, 21, 21,
-   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,
-   21, 21, 21, 21, 21, 21, 21,  2, 21, 21,  2, 21, 21, 21, 21, 21,
-    2,  2, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,  2, 21, 21,  2,
-    2, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2, 21, 21, 21,  2,  2,
-    2,  2, 21, 21,  2, 21, 21, 21, 21, 21,  2,  2, 21, 21, 21, 21,
-   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,  2,
-    2,  2,  2,  2,  2,  2,  2,  2, 22, 22,  2, 22, 22, 22, 22, 22,
-   22,  2,  2,  2, 22, 22, 22,  2, 22, 22, 22, 22,  2,  2,  2, 22,
-   22,  2, 22,  2, 22, 22,  2,  2,  2, 22, 22,  2,  2,  2, 22, 22,
-   22,  2,  2,  2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-    2,  2,  2,  2, 22, 22, 22, 22, 22,  2,  2,  2, 22, 22, 22,  2,
-   22, 22, 22, 22,  2,  2, 22,  2,  2,  2,  2,  2,  2, 22,  2,  2,
-    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22,  2,  2,  2,  2,  2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
-   23, 23, 23,  2, 23, 23, 23,  2, 23, 23, 23, 23, 23, 23, 23, 23,
-   23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,  2,
-   23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
-    2,  2, 23, 23, 23, 23, 23, 23, 23, 23, 23,  2, 23, 23, 23,  2,
-   23, 23, 23, 23,  2,  2,  2,  2,  2,  2,  2, 23, 23,  2, 23, 23,
-   23,  2,  2, 23,  2,  2, 23, 23, 23, 23,  2,  2, 23, 23, 23, 23,
-   23, 23, 23, 23, 23, 23,  2,  2,  2,  2,  2,  2,  2, 23, 23, 23,
-   23, 23, 23, 23, 23, 23, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
-   16, 16, 16,  2, 16, 16, 16,  2, 16, 16, 16, 16, 16, 16, 16, 16,
-   16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,  2,
-   16, 16, 16, 16, 16, 16, 16, 16, 16, 16,  2, 16, 16, 16, 16, 16,
-    2,  2, 16, 16, 16, 16, 16, 16, 16, 16, 16,  2, 16, 16, 16,  2,
-   16, 16, 16, 16,  2,  2,  2,  2,  2,  2,  2, 16, 16,  2,  2,  2,
-    2,  2,  2, 16, 16,  2, 16, 16, 16, 16,  2,  2, 16, 16, 16, 16,
-   16, 16, 16, 16, 16, 16,  2, 16, 16,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
-   20, 20, 20,  2, 20, 20, 20,  2, 20, 20, 20, 20, 20, 20, 20, 20,
-   20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
-   20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,  2, 20, 20, 20,  2,
-   20, 20, 20, 20, 20, 20,  2,  2,  2,  2, 20, 20, 20, 20, 20, 20,
-   20, 20, 20, 20, 20, 20, 20, 20, 20, 20,  2,  2, 20, 20, 20, 20,
-   20, 20, 20, 20, 20, 20,  2, 36, 36, 36,  2, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  2,  2,  2,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 36,  2, 36, 36, 36, 36, 36, 36, 36,
-   36, 36,  2, 36,  2,  2, 36, 36, 36, 36, 36, 36, 36,  2,  2,  2,
-   36,  2,  2,  2,  2, 36, 36, 36, 36, 36, 36,  2, 36,  2, 36, 36,
-   36, 36, 36, 36, 36, 36,  2,  2,  2,  2,  2,  2, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36,  2,  2, 36, 36, 36,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  2, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-   24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-   24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-   24,  2,  2,  2,  2,  0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-   24, 24,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  2, 18, 18,  2, 18,  2, 18, 18, 18, 18,
-   18,  2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
-   18, 18, 18, 18, 18, 18, 18, 18, 18, 18,  2, 18,  2, 18, 18, 18,
-   18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
-   18, 18, 18, 18,  2,  2, 18, 18, 18, 18, 18,  2, 18,  2, 18, 18,
-   18, 18, 18, 18,  2,  2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
-    2,  2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,  2, 25,
-   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-   25, 25, 25,  2,  2,  2,  2, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-   25, 25, 25,  2, 25, 25, 25, 25, 25, 25, 25,  0,  0,  0,  0, 25,
-   25,  2,  2,  2,  2,  2, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
-   33, 33, 33, 33, 33, 33,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
-    8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  2,  8,  2,  2,
-    2,  2,  2,  8,  2,  2,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
-    8,  0,  8,  8,  8,  8, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
-   30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,  2,
-   30, 30, 30, 30,  2,  2, 30, 30, 30, 30, 30, 30, 30,  2, 30,  2,
-   30, 30, 30, 30,  2,  2, 30,  2, 30, 30, 30, 30,  2,  2, 30, 30,
-   30, 30, 30, 30, 30,  2, 30,  2, 30, 30, 30, 30,  2,  2, 30, 30,
-   30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,  2, 30, 30,
-   30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
-   30,  2,  2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
-   30, 30, 30,  2,  2,  2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
-    2,  2,  2,  2,  2,  2, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
-   29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,  2,  2, 29, 29,
-   29, 29, 29, 29,  2,  2, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
-   28, 28, 28, 28, 28, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34,  2,  2,  2, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-   35,  0,  0,  0, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,  2,
-    2,  2,  2,  2,  2,  2, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
-   45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,  2,  2,  2,  2,
-    2,  2,  2,  2,  2, 45, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-   44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,  0,  0,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
-   43, 43, 43, 43, 43, 43, 43, 43, 43, 43,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
-   46, 46, 46,  2, 46, 46, 46,  2, 46, 46,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
-   31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
-   31, 31, 31, 31,  2,  2, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
-    2,  2,  2,  2,  2,  2, 32, 32,  0,  0, 32,  0, 32, 32, 32, 32,
-   32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-    2,  2,  2,  2,  2,  2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-   32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,  2,
-    2,  2,  2,  2,  2,  2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-   32,  2,  2,  2,  2,  2, 28, 28, 28, 28, 28, 28,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
-   48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
-   48, 48, 48, 48, 48,  2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
-   48, 48,  2,  2,  2,  2, 48,  2,  2,  2, 48, 48, 48, 48, 48, 48,
-   48, 48, 48, 48, 48, 48, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-   52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-   52, 52, 52, 52,  2,  2, 52, 52, 52, 52, 52,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58, 58,  2,  2,  2,  2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-    2,  2,  2,  2,  2,  2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-   58,  2,  2,  2, 58, 58, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-   54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-   54, 54,  2,  2, 54, 54, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
-   91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
-   91, 91, 91, 91, 91,  2, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
-   91, 91, 91,  2,  2, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
-    2,  2,  2,  2,  2,  2, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
-   91, 91, 91, 91,  2,  2,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
-    1,  1,  1,  1,  1,  2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
-   62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
-   62, 62, 62,  2,  2,  2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
-   62, 62, 62, 62, 62,  2, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
-   76, 76, 76, 76, 76, 76, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
-   93, 93, 93, 93, 93, 93, 93, 93, 93, 93,  2,  2,  2,  2,  2,  2,
-    2,  2, 93, 93, 93, 93, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
-   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,  2,  2,
-    2, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
-    2,  2,  2, 70, 70, 70, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
-   73, 73, 73, 73, 73, 73,  6,  6,  6,  6,  6,  6,  6,  6,  6,  2,
-    2,  2,  2,  2,  2,  2,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
-    8,  2,  2,  8,  8,  8, 76, 76, 76, 76, 76, 76, 76, 76,  2,  2,
-    2,  2,  2,  2,  2,  2,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,
-    1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  0,
-    0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1,  1,
-    0,  2,  2,  2,  2,  2, 19, 19, 19, 19, 19, 19,  9,  9,  9,  9,
-    9,  6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-   19, 19, 19,  9,  9,  9,  9,  9, 19, 19, 19, 19,  9,  9,  9,  9,
-    9, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,  6, 19,
-   19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-   19, 19, 19, 19, 19,  9,  9,  9,  9,  9,  9,  9,  2,  2,  9,  9,
-    9,  9,  9,  9,  2,  2,  9,  9,  9,  9,  9,  9,  9,  9,  2,  9,
-    2,  9,  2,  9,  2,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  2,  2,  9,  9,  9,  9,  9,  2,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  2,  2,  9,  9,  9,  9,
-    9,  9,  2,  9,  9,  9,  2,  2,  9,  9,  9,  2,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  1,  1,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 19,  2,  2,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0, 19,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  2, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-   19, 19, 19,  2,  2,  2,  0,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  1,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  9,  0,  0,  0,
-   19, 19,  0,  0,  0,  0,  0,  0, 19,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0, 19,  0, 19, 19, 19, 19, 19, 19, 19, 19, 19,  0,
-    0,  0,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  2,  2,  2,  2,  2, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
-   27, 27, 27, 27, 27, 27,  0,  0,  0,  0,  2,  2,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-   56, 56, 56, 56, 56, 56, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
-   55, 55, 55, 55, 55, 55, 55, 55, 55, 55,  2,  2,  2,  2,  2, 55,
-   55, 55, 55, 55, 55, 55, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-   61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,  2,  2,
-    2,  2,  2,  2,  2, 61, 61,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2, 61, 30, 30, 30, 30, 30, 30, 30,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 30, 30, 30, 30, 30, 30, 30,  2, 30, 30,
-   30, 30, 30, 30, 30,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  2,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-    2, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 13, 13, 13, 13, 13, 13,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  2,  2,  2,  2,  0,  0,  0,  0,  0, 13,  0, 13,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-    1,  1,  1,  1, 12, 12,  0,  0,  0,  0,  0,  0,  0,  0, 13, 13,
-   13, 13,  0,  0,  0,  0,  2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
-   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
-   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,  1,
-    1,  0,  0, 15, 15, 15,  0, 17, 17, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
-   17,  0,  0, 17, 17, 17,  2,  2,  2,  2,  2, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26,  2, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12,  2,  0,  0,  0,  0,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12,  0, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17, 17, 17,  0, 17, 17, 17, 17, 17, 17, 17, 17,  0,  0,
-    0,  0,  0,  0,  0,  0, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-   39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-   39, 39, 39,  2,  2,  2, 39, 39, 39, 39, 39, 39, 39,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-   86, 86, 86, 86, 86, 86, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
-   77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
-   77, 77,  2,  2,  2,  2, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
-   79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,  2,  2,
-    2,  2,  2,  2,  2,  2,  0,  0, 19, 19, 19, 19, 19, 19, 19, 19,
-   19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,  0,  0,
-    0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-   19,  2,  2,  2,  2,  2, 19, 19,  2, 19,  2, 19, 19, 19, 19, 19,
-    2,  2,  2,  2,  2,  2,  2,  2, 19, 19, 19, 19, 19, 19, 19, 19,
-   19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
-   60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
-   60, 60, 60,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    2,  2,  2,  2,  2,  2, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-   65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,  2,  2,
-    2,  2,  2,  2,  2,  2, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
-   75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,  2,  2,  2,  2,
-    2,  2,  2,  2, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
-    2,  2,  2,  2,  2,  2, 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,  0, 69, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-   74, 74, 74, 74, 74, 74, 74, 74, 74, 74,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2, 74, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12,  2,  2,  2, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
-   84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
-   84, 84, 84, 84,  2,  0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
-    2,  2,  2,  2, 84, 84, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
-   33, 33, 33, 33, 33,  2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
-   68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
-   68, 68, 68, 68,  2,  2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
-    2,  2, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
-   92, 92, 92, 92, 92, 92, 92, 92, 92,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2, 92, 92, 92, 92, 92, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
-   87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  2, 30, 30, 30, 30, 30, 30,  2,  2, 30,
-   30, 30, 30, 30, 30,  2,  2, 30, 30, 30, 30, 30, 30,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-   19,  0, 19, 19, 19, 19, 19, 19, 19, 19, 19,  9, 19, 19, 19, 19,
-    0,  0,  2,  2,  2,  2, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
-   87, 87, 87, 87,  2,  2, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
-    2,  2,  2,  2,  2,  2, 12, 12, 12, 12,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 12, 12, 12, 12, 12, 12, 12,  2,  2,  2,
-    2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12,  2,  2,  2,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-   13, 13, 13, 13,  2,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-    2,  2,  2,  2,  2,  2, 19, 19, 19, 19, 19, 19, 19,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  2,  2,  2,  4,  4,  4,  4,  4,  2,  2,
-    2,  2,  2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,  2, 14, 14,
-   14, 14, 14,  2, 14,  2, 14, 14,  2, 14, 14,  2, 14, 14, 14, 14,
-   14, 14, 14, 14, 14, 14,  3,  3,  3,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,
-    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
-    3,  3,  3,  3,  0,  0,  2,  2,  3,  3,  3,  3,  3,  3,  3,  3,
-    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  2,  2,
-    2,  2,  2,  2,  2,  3,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
-    1,  1,  1,  1,  6,  6,  0,  0,  0,  2,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,
-    0,  0,  2,  2,  2,  2,  3,  3,  3,  3,  3,  2,  3,  3,  3,  3,
-    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
-    3,  3,  3,  2,  2,  0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 17, 17, 17, 17,
-   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17, 17,  0,  0,  2,  2, 12, 12, 12, 12, 12, 12,  2,  2,
-   12, 12, 12, 12, 12, 12,  2,  2, 12, 12, 12, 12, 12, 12,  2,  2,
-   12, 12, 12,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,
-    0,  0,  0,  0,  0,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  0,
-    0,  0,  0,  0,  2,  2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-   49, 49,  2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-   49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,  2, 49, 49,
-   49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-   49,  2, 49, 49,  2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-   49, 49, 49, 49,  2,  2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-   49,  2,  2,  2,  2,  2,  0,  0,  0,  2,  2,  2,  2,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,  2,  2,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  2,  2,  2,  9,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  1,  2,  2, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
-   71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
-   71, 71, 71,  2,  2,  2, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-   67, 67, 67, 67, 67, 67, 67,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-   42, 42, 42, 42, 42, 42, 42, 42, 42, 42,  2,  2,  2,  2,  2,  2,
-    2,  2,  2, 42, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-   41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-   41,  2,  2,  2,  2,  2,118,118,118,118,118,118,118,118,118,118,
-  118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,
-  118,  2,  2,  2,  2,  2, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
-   53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
-   53, 53, 53, 53,  2, 53, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59,  2,  2,  2,  2, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
-   40, 40, 40, 40, 40, 40, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-   51, 51, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-   50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-   50, 50, 50, 50,  2,  2, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-    2,  2,  2,  2,  2,  2,135,135,135,135,135,135,135,135,135,135,
-  135,135,135,135,135,135,135,135,135,135,  2,  2,  2,  2,135,135,
-  135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,
-  135,135,  2,  2,  2,  2,106,106,106,106,106,106,106,106,106,106,
-  106,106,106,106,106,106,106,106,106,106,106,106,106,106,  2,  2,
-    2,  2,  2,  2,  2,  2,104,104,104,104,104,104,104,104,104,104,
-  104,104,104,104,104,104,104,104,104,104,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,104,161,161,161,161,161,161,161,161,161,161,
-  161,  2,161,161,161,161,161,161,161,  2,161,161,  2,161,161,161,
-  161,161,161,161,161,161,161,161,  2,161,161,161,161,161,161,161,
-  161,161,161,161,161,161,161,161,  2,161,161,161,161,161,161,161,
-    2,161,161,  2,  2,  2,110,110,110,110,110,110,110,110,110,110,
-  110,110,110,110,110,110,110,110,110,110,110,110,110,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,110,110,110,110,110,110,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,110,110,110,110,110,110,110,110,  2,  2,
-    2,  2,  2,  2,  2,  2, 19, 19, 19, 19, 19, 19,  2, 19, 19, 19,
-   19, 19, 19, 19, 19, 19, 19,  2, 19, 19, 19, 19, 19, 19, 19, 19,
-   19,  2,  2,  2,  2,  2, 47, 47, 47, 47, 47, 47,  2,  2, 47,  2,
-   47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
-   47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,  2, 47, 47,  2,
-    2,  2, 47,  2,  2, 47, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
-   81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,  2, 81, 81, 81,
-   81, 81, 81, 81, 81, 81,120,120,120,120,120,120,120,120,120,120,
-  120,120,120,120,120,120,116,116,116,116,116,116,116,116,116,116,
-  116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
-  116,116,116,116,116,  2,  2,  2,  2,  2,  2,  2,  2,116,116,116,
-  116,116,116,116,116,116,128,128,128,128,128,128,128,128,128,128,
-  128,128,128,128,128,128,128,128,128,  2,128,128,  2,  2,  2,  2,
-    2,128,128,128,128,128, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
-   66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
-   66, 66,  2,  2,  2, 66, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
-   72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
-    2,  2,  2,  2,  2, 72, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
-   98, 98, 98, 98, 98, 98, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
-   97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,  2,  2,
-    2,  2, 97, 97, 97, 97,  2,  2, 97, 97, 97, 97, 97, 97, 97, 97,
-   97, 97, 97, 97, 97, 97, 57, 57, 57, 57,  2, 57, 57,  2,  2,  2,
-    2,  2, 57, 57, 57, 57, 57, 57, 57, 57,  2, 57, 57, 57,  2, 57,
-   57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-   57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,  2,  2, 57, 57,
-   57,  2,  2,  2,  2, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,  2,
-    2,  2,  2,  2,  2,  2, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,
-   88, 88, 88, 88, 88, 88,117,117,117,117,117,117,117,117,117,117,
-  117,117,117,117,117,117,112,112,112,112,112,112,112,112,112,112,
-  112,112,112,112,112,112,112,112,112,112,112,112,112,  2,  2,  2,
-    2,112,112,112,112,112,112,112,112,112,112,112,112,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
-   78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,  2,  2,  2, 78,
-   78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,
-   83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,  2,  2, 83, 83,
-   83, 83, 83, 83, 83, 83, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
-   82, 82, 82, 82, 82, 82, 82, 82, 82,  2,  2,  2,  2,  2, 82, 82,
-   82, 82, 82, 82, 82, 82,122,122,122,122,122,122,122,122,122,122,
-  122,122,122,122,122,122,122,122,  2,  2,  2,  2,  2,  2,  2,122,
-  122,122,122,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,122,
-  122,122,122,122,122,122, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
-   89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,  2,
-    2,  2,  2,  2,  2,  2,130,130,130,130,130,130,130,130,130,130,
-  130,130,130,130,130,130,130,130,130,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,130,130,130,  2,  2,  2,  2,  2,  2,  2,
-  130,130,130,130,130,130,144,144,144,144,144,144,144,144,144,144,
-  144,144,144,144,144,144,144,144,144,144,144,144,144,144,  2,  2,
-    2,  2,  2,  2,  2,  2,144,144,144,144,144,144,144,144,144,144,
-    2,  2,  2,  2,  2,  2,156,156,156,156,156,156,156,156,156,156,
-  156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,
-    2,156,156,156,  2,  2,156,156,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,147,147,147,147,147,147,147,147,147,147,
-  147,147,147,147,147,147,147,147,147,147,147,147,147,147,  2,  2,
-    2,  2,  2,  2,  2,  2,148,148,148,148,148,148,148,148,148,148,
-  148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
-    2,  2,  2,  2,  2,  2,158,158,158,158,158,158,158,158,158,158,
-  158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,
-    2,  2,  2,  2,  2,  2,153,153,153,153,153,153,153,153,153,153,
-  153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
-  153,153,  2,  2,  2,  2,149,149,149,149,149,149,149,149,149,149,
-  149,149,149,149,149,149,149,149,149,149,149,149,149,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
-   94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
-   94, 94, 94, 94,  2,  2,  2,  2, 94, 94, 94, 94, 94, 94, 94, 94,
-   94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,  2,  2,  2,  2,
-    2,  2,  2,  2,  2, 94, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
-   85, 85, 85, 85, 85, 85, 85, 85, 85,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2, 85,  2,  2,101,101,101,101,101,101,101,101,101,101,
-  101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,  2,
-    2,  2,  2,  2,  2,  2,101,101,101,101,101,101,101,101,101,101,
-    2,  2,  2,  2,  2,  2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,  2, 96, 96, 96, 96,
-   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,  2,  2,
-    2,  2,  2,  2,  2,  2,111,111,111,111,111,111,111,111,111,111,
-  111,111,111,111,111,111,111,111,111,111,111,111,111,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,100,100,100,100,100,100,100,100,100,100,
-  100,100,100,100,100,100,  2, 36, 36, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,108,108,108,108,108,108,108,108,108,108,
-  108,108,108,108,108,108,108,108,  2,108,108,108,108,108,108,108,
-  108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
-  108,108,108,108,108,  2,129,129,129,129,129,129,129,  2,129,  2,
-  129,129,129,129,  2,129,129,129,129,129,129,129,129,129,129,129,
-  129,129,129,129,  2,129,129,129,129,129,129,129,129,129,129,129,
-    2,  2,  2,  2,  2,  2,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,  2,  2,  2,  2,  2,109,109,109,109,109,109,109,109,109,109,
-    2,  2,  2,  2,  2,  2,107,107,107,107,  2,107,107,107,107,107,
-  107,107,107,  2,  2,107,107,  2,  2,107,107,107,107,107,107,107,
-  107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,  2,
-  107,107,107,107,107,107,107,  2,107,107,  2,107,107,107,107,107,
-    2,  1,107,107,107,107,107,107,107,107,107,  2,  2,107,107,  2,
-    2,107,107,107,  2,  2,107,  2,  2,  2,  2,  2,  2,107,  2,  2,
-    2,  2,  2,107,107,107,107,107,107,107,  2,  2,107,107,107,107,
-  107,107,107,  2,  2,  2,107,107,107,107,107,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,137,137,137,137,137,137,137,137,137,137,
-  137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
-  137,137,  2,137,137,137,137,137,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,124,124,124,124,124,124,124,124,124,124,
-  124,124,124,124,124,124,124,124,124,124,124,124,124,124,  2,  2,
-    2,  2,  2,  2,  2,  2,124,124,124,124,124,124,124,124,124,124,
-    2,  2,  2,  2,  2,  2,123,123,123,123,123,123,123,123,123,123,
-  123,123,123,123,123,123,123,123,123,123,123,123,  2,  2,123,123,
-  123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,
-  123,123,123,123,  2,  2,114,114,114,114,114,114,114,114,114,114,
-  114,114,114,114,114,114,114,114,114,114,114,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,114,114,114,114,114,114,114,114,114,114,
-    2,  2,  2,  2,  2,  2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-   32, 32, 32,  2,  2,  2,102,102,102,102,102,102,102,102,102,102,
-  102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,
-    2,  2,  2,  2,  2,  2,126,126,126,126,126,126,126,126,126,126,
-  126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,
-  126,  2,  2,126,126,126,126,126,126,126,126,126,126,126,126,126,
-  126,126,  2,  2,  2,  2,126,126,126,126,126,126,126,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,142,142,142,142,142,142,142,142,142,142,
-  142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,
-  142,142,  2,  2,  2,  2,125,125,125,125,125,125,125,125,125,125,
-  125,125,125,125,125,125,125,125,125,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,125,154,154,154,154,154,154,154,  2,  2,154,
-    2,  2,154,154,154,154,154,154,154,154,  2,154,154,  2,154,154,
-  154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,
-  154,154,154,154,154,154,154,154,154,154,154,154,  2,154,154,  2,
-    2,154,154,154,154,154,154,154,154,154,154,154,154,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,154,154,154,154,154,154,154,154,154,154,
-    2,  2,  2,  2,  2,  2,150,150,150,150,150,150,150,150,  2,  2,
-  150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,
-  150,150,150,150,150,150,150,150,150,150,150,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,141,141,141,141,141,141,141,141,141,141,
-  141,141,141,141,141,141,141,141,141,141,141,141,141,141,  2,  2,
-    2,  2,  2,  2,  2,  2,140,140,140,140,140,140,140,140,140,140,
-  140,140,140,140,140,140,140,140,140,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,121,121,121,121,121,121,121,121,121,121,
-  121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,  2,
-    2,  2,  2,  2,  2,  2,133,133,133,133,133,133,133,133,133,  2,
-  133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
-  133,133,133,133,133,133,133,133,133,133,133,133,133,  2,133,133,
-  133,133,133,133,133,133,133,133,133,133,133,133,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,133,133,133,133,133,133,133,133,133,133,
-  133,133,133,  2,  2,  2,134,134,134,134,134,134,134,134,134,134,
-  134,134,134,134,134,134,  2,  2,134,134,134,134,134,134,134,134,
-  134,134,134,134,134,134,134,134,134,134,134,134,134,134,  2,134,
-  134,134,134,134,134,134,134,134,134,134,134,134,134,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,138,138,138,138,138,138,138,  2,138,138,
-    2,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,
-  138,138,138,138,138,138,138,138,138,138,138,138,138,  2,  2,  2,
-  138,  2,138,138,  2,138,138,138,138,138,138,138,138,138,  2,  2,
-    2,  2,  2,  2,  2,  2,138,138,138,138,138,138,138,138,138,138,
-    2,  2,  2,  2,  2,  2,143,143,143,143,143,143,  2,143,143,  2,
-  143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
-  143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
-  143,143,143,143,143,  2,143,143,  2,143,143,143,143,143,143,  2,
-    2,  2,  2,  2,  2,  2,143,143,143,143,143,143,143,143,143,143,
-    2,  2,  2,  2,  2,  2,145,145,145,145,145,145,145,145,145,145,
-  145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,  2,
-    2,  2,  2,  2,  2,  2, 86,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2, 22, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
-   63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
-    2,  2,  2,  2,  2,  2, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
-   63, 63, 63, 63, 63,  2, 63, 63, 63, 63, 63,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 63, 63, 63, 63,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,157,157,157,157,157,157,157,157,157,157,
-  157,157,157,157,157,157,157,157,157,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
-   80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
-   80, 80, 80, 80, 80,  2, 80, 80, 80, 80, 80, 80, 80, 80, 80,  2,
-    2,  2,  2,  2,  2,  2,127,127,127,127,127,127,127,127,127,127,
-  127,127,127,127,127,127,127,127,127,127,127,127,127,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 79, 79, 79, 79, 79, 79, 79, 79, 79,  2,
-    2,  2,  2,  2,  2,  2,115,115,115,115,115,115,115,115,115,115,
-  115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
-  115,115,115,115,115,  2,115,115,115,115,115,115,115,115,115,115,
-    2,  2,  2,  2,115,115,159,159,159,159,159,159,159,159,159,159,
-  159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,
-  159,159,159,159,159,  2,159,159,159,159,159,159,159,159,159,159,
-    2,  2,  2,  2,  2,  2,103,103,103,103,103,103,103,103,103,103,
-  103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,
-  103,103,103,103,  2,  2,103,103,103,103,103,103,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,119,119,119,119,119,119,119,119,119,119,
-  119,119,119,119,119,119,119,119,119,119,119,119,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,119,119,119,119,119,119,119,119,119,119,
-    2,119,119,119,119,119,119,119,  2,119,119,119,119,119,119,119,
-  119,119,119,119,119,119,119,119,119,119,119,119,119,119,  2,  2,
-    2,  2,  2,119,119,119,146,146,146,146,146,146,146,146,146,146,
-  146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,
-  146,  2,  2,  2,  2,  2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-   99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-   99,  2,  2,  2,  2, 99, 99, 99, 99, 99, 99, 99, 99, 99,  2,  2,
-    2,  2,  2,  2,  2, 99,136,139, 13, 13,155,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 13, 13,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,136,136,136,136,136,136,136,136,136,136,
-  136,136,136,136,136,136,136,136,136,136,136,136,136,136,  2,  2,
-    2,  2,  2,  2,  2,  2,155,155,155,155,155,155,155,155,155,155,
-  155,155,155,155,155,155,155,155,155,155,155,155,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,136,136,136,136,136,136,136,136,136,  2,
-    2,  2,  2,  2,  2,  2, 17, 17, 17, 17,  2, 17, 17, 17, 17, 17,
-   17, 17,  2, 17, 17,  2, 17, 15, 15, 15, 15, 15, 15, 15, 15, 15,
-   15, 15, 15, 15, 15, 15, 17, 17, 17,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 17, 17, 17, 17,  2,  2,
-    2,  2,  2,  2,  2,  2,139,139,139,139,139,139,139,139,139,139,
-  139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,
-  139,139,  2,  2,  2,  2,105,105,105,105,105,105,105,105,105,105,
-  105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
-  105,  2,  2,  2,  2,  2,105,105,105,105,105,105,105,105,105,105,
-  105,105,105,  2,  2,  2,105,105,105,105,105,105,105,105,105,  2,
-    2,  2,  2,  2,  2,  2,105,105,105,105,105,105,105,105,105,105,
-    2,  2,105,105,105,105,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
-    1,  1,  1,  1,  2,  2,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  2,  2,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  1,  1,  1,
-    1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    1,  1,  1,  1,  0,  0,  9,  9,  9,  9,  9,  9,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,
-    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  2,  0,  0,  2,  2,  0,  2,  2,  0,  0,  2,  2,  0,
-    0,  0,  0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    2,  0,  2,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,
-    0,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,  0,
-    0,  0,  0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    2,  0,  0,  0,  0,  2,  0,  0,  0,  0,  0,  2,  0,  2,  2,  2,
-    0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,  2,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  2,  2,  0,  0,131,131,131,131,131,131,131,131,131,131,
-  131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
-  131,131,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,131,131,131,131,131,  2,131,131,131,131,131,131,131,131,131,
-  131,131,131,131,131,131, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-   19, 19, 19, 19, 19,  2, 56, 56, 56, 56, 56, 56, 56,  2, 56, 56,
-   56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,  2,
-    2, 56, 56, 56, 56, 56, 56, 56,  2, 56, 56,  2, 56, 56, 56, 56,
-   56,  2,  2,  2,  2,  2,151,151,151,151,151,151,151,151,151,151,
-  151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,
-  151,151,151,  2,  2,  2,151,151,151,151,151,151,151,151,151,151,
-  151,151,151,151,  2,  2,151,151,151,151,151,151,151,151,151,151,
-    2,  2,  2,  2,151,151,160,160,160,160,160,160,160,160,160,160,
-  160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
-  160,160,160,160,160,  2,152,152,152,152,152,152,152,152,152,152,
-  152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
-    2,  2,  2,  2,  2,152, 30, 30, 30, 30, 30, 30, 30,  2, 30, 30,
-   30, 30,  2, 30, 30,  2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
-   30, 30, 30, 30, 30,  2,113,113,113,113,113,113,113,113,113,113,
-  113,113,113,113,113,113,113,113,113,113,113,  2,  2,113,113,113,
-  113,113,113,113,113,113,113,113,113,113,113,113,113,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,132,132,132,132,132,132,132,132,132,132,
-  132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
-  132,132,  2,  2,  2,  2,132,132,132,132,132,132,132,132,132,132,
-    2,  2,  2,  2,132,132,  0,  0,  0,  0,  0,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  3,  3,  3,  3,  2,  3,  3,  3,  3,  3,
-    3,  3,  3,  3,  3,  3,  2,  3,  3,  2,  3,  2,  2,  3,  2,  3,
-    3,  3,  3,  3,  3,  3,  3,  3,  3,  2,  3,  3,  3,  3,  2,  3,
-    2,  3,  2,  2,  2,  2,  2,  2,  3,  2,  2,  2,  2,  3,  2,  3,
-    2,  3,  2,  3,  3,  3,  2,  3,  3,  2,  3,  2,  2,  3,  2,  3,
-    2,  3,  2,  3,  2,  3,  2,  3,  3,  2,  3,  2,  2,  3,  3,  3,
-    3,  2,  3,  3,  3,  3,  3,  3,  3,  2,  3,  3,  3,  3,  2,  3,
-    3,  3,  3,  2,  3,  2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
-    2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
-    3,  3,  2,  2,  2,  2,  2,  3,  3,  3,  2,  3,  3,  3,  3,  3,
-    2,  3,  3,  3,  3,  3,  3,  3,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 15,  0,  0,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  0,  0,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  2,  2,
-    2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,  2,
-    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  2,  2,  2,  0,  0,
-    0,  0,  0,  2,  2,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,
-    2,  2,  2,  2,  2,  2, 13,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-   13,  2,  2,  2,  2,  2,  2,  0,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  0,  0,  0,  1,  2,  3,  4,  5,  6,  0,
-    0,  0,  0,  7,  8,  9, 10, 11,  0, 12,  0,  0,  0,  0, 13,  0,
-    0, 14,  0,  0,  0,  0,  0,  0,  0,  0, 15, 16,  0, 17, 18, 19,
-    0,  0,  0, 20, 21, 22,  0, 23,  0, 24,  0, 25,  0, 26,  0,  0,
-    0,  0,  0, 27, 28,  0, 29,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0, 30, 31,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 32, 33,
-   34, 35, 36, 37, 38, 39, 40,  0,  0,  0, 41,  0, 42, 43, 44, 45,
-   46, 47, 48,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0, 49,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 50, 51, 52,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 53, 54, 55, 56, 57, 58,
-   59, 60, 61, 62,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0, 63,  0, 64,  0,  0,  0,  0,  0,
-    0,  0,  0, 65,  0,  0,  0,  0, 66,  0,  0,  0, 67,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 68,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 69, 70, 71,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 72, 73, 74, 75, 76, 77, 78, 79, 80,  0,
-};
-static const uint16_t
-_hb_ucd_u16[11584] =
-{
-     0,   0,   1,   2,   3,   4,   5,   6,   0,   0,   7,   8,   9,  10,  11,  12,
-    13,  13,  13,  14,  15,  13,  13,  16,  17,  18,  19,  20,  21,  22,  13,  23,
-    13,  13,  13,  24,  25,  11,  11,  11,  11,  26,  11,  27,  28,  29,  30,  31,
-    32,  32,  32,  32,  32,  32,  32,  33,  34,  35,  36,  11,  37,  38,  13,  39,
-     9,   9,   9,  11,  11,  11,  13,  13,  40,  13,  13,  13,  41,  13,  13,  13,
-    13,  13,  13,  42,   9,  43,  11,  11,  44,  45,  32,  46,  47,  48,  49,  50,
-    51,  52,  48,  48,  53,  32,  54,  55,  48,  48,  48,  48,  48,  56,  57,  58,
-    59,  60,  48,  32,  61,  48,  48,  48,  48,  48,  62,  63,  64,  48,  65,  66,
-    48,  67,  68,  69,  48,  70,  71,  48,  72,  73,  48,  48,  74,  32,  75,  32,
-    76,  48,  48,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,
-    90,  83,  84,  91,  92,  93,  94,  95,  96,  97,  84,  98,  99, 100,  88, 101,
-   102,  83,  84, 103, 104, 105,  88, 106, 107, 108, 109, 110, 111, 112,  94, 113,
-   114, 115,  84, 116, 117, 118,  88, 119, 120, 115,  84, 121, 122, 123,  88, 124,
-   125, 115,  48, 126, 127, 128,  88, 129, 130, 131,  48, 132, 133, 134,  94, 135,
-   136,  48,  48, 137, 138, 139, 140, 140, 141,  48, 142, 143, 144, 145, 140, 140,
-   146, 147, 148, 149, 150,  48, 151, 152, 153, 154,  32, 155, 156, 157, 140, 140,
-    48,  48, 158, 159, 160, 161, 162, 163, 164, 165,   9,   9, 166,  11,  11, 167,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48, 168, 169,  48,  48, 168,  48,  48, 170, 171, 172,  48,  48,
-    48, 171,  48,  48,  48, 173, 174, 175,  48, 176,   9,   9,   9,   9,   9, 177,
-   178,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48, 179,  48, 180, 181,  48,  48,  48,  48, 182, 183,
-    48, 184,  48, 185,  48, 186, 187, 188,  48,  48,  48, 189, 190, 191, 192, 193,
-   194, 192,  48,  48, 195,  48,  48, 196, 197,  48, 198,  48,  48,  48,  48, 199,
-    48, 200, 201, 202, 203,  48, 204, 205,  48,  48, 206,  48, 207, 208, 209, 209,
-    48, 210,  48,  48,  48, 211, 212, 213, 192, 192, 214, 215, 216, 140, 140, 140,
-   217,  48,  48, 218, 219, 160, 220, 221, 222,  48, 223,  64,  48,  48, 224, 225,
-    48,  48, 226, 227, 228,  64,  48, 229, 230,   9,   9, 231, 232, 233, 234, 235,
-    11,  11, 236,  27,  27,  27, 237, 238,  11, 239,  27,  27,  32,  32,  32,  32,
-    13,  13,  13,  13,  13,  13,  13,  13,  13, 240,  13,  13,  13,  13,  13,  13,
-   241, 242, 241, 241, 242, 243, 241, 244, 245, 245, 245, 246, 247, 248, 249, 250,
-   251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 261, 262, 263, 264, 265,
-   266, 267, 268, 269, 270, 271, 272, 272, 273, 274, 275, 209, 276, 277, 209, 278,
-   279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279,
-   280, 209, 281, 209, 209, 209, 209, 282, 209, 283, 279, 284, 209, 285, 286, 209,
-   209, 209, 287, 140, 288, 140, 271, 271, 271, 289, 209, 209, 209, 209, 290, 271,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 291, 292, 209, 209, 293,
-   209, 209, 209, 209, 209, 209, 294, 209, 209, 209, 209, 209, 209, 209, 209, 209,
-   209, 209, 209, 209, 209, 209, 295, 296, 271, 297, 209, 209, 298, 279, 299, 279,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
-   279, 279, 279, 279, 279, 279, 279, 279, 300, 301, 279, 279, 279, 302, 279, 303,
-   279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279,
-   209, 209, 209, 279, 304, 209, 209, 305, 209, 306, 209, 209, 209, 209, 209, 209,
-     9,   9,   9,  11,  11,  11, 307, 308,  13,  13,  13,  13,  13,  13, 309, 310,
-    11,  11, 311,  48,  48,  48, 312, 313,  48, 314, 315, 315, 315, 315,  32,  32,
-   316, 317, 318, 319, 320, 321, 140, 140, 209, 322, 209, 209, 209, 209, 209, 323,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 324, 140, 325,
-   326, 327, 328, 329, 136,  48,  48,  48,  48, 330, 178,  48,  48,  48,  48, 331,
-   332,  48,  48, 136,  48,  48,  48,  48, 200, 333,  48,  48, 209, 209, 323,  48,
-   209, 334, 335, 209, 336, 337, 209, 209, 335, 209, 209, 337, 209, 209, 209, 209,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 209, 209, 209, 209,
-    48, 338,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48,  48,  48, 151, 209, 209, 209, 287,  48,  48, 229,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-   339,  48, 340, 140,  13,  13, 341, 342,  13, 343,  48,  48,  48,  48, 344, 345,
-    31, 346, 347, 348,  13,  13,  13, 349, 350, 351, 352, 353, 354, 355, 140, 356,
-   357,  48, 358, 359,  48,  48,  48, 360, 361,  48,  48, 362, 363, 192,  32, 364,
-    64,  48, 365,  48, 366, 367,  48, 151,  76,  48,  48, 368, 369, 370, 371, 372,
-    48,  48, 373, 374, 375, 376,  48, 377,  48,  48,  48, 378, 379, 380, 381, 382,
-   383, 384, 315,  11,  11, 385, 386,  11,  11,  11,  11,  11,  48,  48, 387, 192,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 388,  48, 389,  48,  48, 206,
-   390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390,
-   390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390,
-   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
-   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
-   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48, 204,  48,  48,  48,  48,  48,  48, 207, 140, 140,
-   392, 393, 394, 395, 396,  48,  48,  48,  48,  48,  48, 397, 398, 399,  48,  48,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48, 400, 209,  48,  48,  48,  48, 401,  48,  48, 402, 140, 140, 403,
-    32, 404,  32, 405, 406, 407, 408, 409,  48,  48,  48,  48,  48,  48,  48, 410,
-   411,   2,   3,   4,   5, 412, 413, 414,  48, 415,  48, 200, 416, 417, 418, 419,
-   420,  48, 172, 421, 204, 204, 140, 140,  48,  48,  48,  48,  48,  48,  48,  71,
-   422, 271, 271, 423, 272, 272, 272, 424, 425, 426, 427, 140, 140, 209, 209, 428,
-   140, 140, 140, 140, 140, 140, 140, 140,  48, 151,  48,  48,  48, 100, 429, 430,
-    48,  48, 431,  48, 432,  48,  48, 433,  48, 434,  48,  48, 435, 436, 140, 140,
-     9,   9, 437,  11,  11,  48,  48,  48,  48, 204, 192,   9,   9, 438,  11, 439,
-    48,  48, 440,  48,  48,  48, 441, 442, 442, 443, 444, 445, 140, 140, 140, 140,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48, 314,  48, 199, 440, 140, 446,  27,  27, 447, 140, 140, 140, 140,
-   448,  48,  48, 449,  48, 450,  48, 451,  48, 200, 452, 140, 140, 140,  48, 453,
-    48, 454,  48, 455, 140, 140, 140, 140,  48,  48,  48, 456, 271, 457, 271, 271,
-   458, 459,  48, 460, 461, 462,  48, 463,  48, 464, 140, 140, 465,  48, 466, 467,
-    48,  48,  48, 468,  48, 469,  48, 470,  48, 471, 472, 140, 140, 140, 140, 140,
-    48,  48,  48,  48, 196, 140, 140, 140,   9,   9,   9, 473,  11,  11,  11, 474,
-    48,  48, 475, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 271, 476,  48,  48, 477, 478, 140, 140, 140, 140,
-    48, 464, 479,  48,  62, 480, 140,  48, 481, 140, 140,  48, 482, 140,  48, 314,
-   483,  48,  48, 484, 485, 457, 486, 487, 222,  48,  48, 488, 489,  48, 196, 192,
-   490,  48, 491, 492, 493,  48,  48, 494, 222,  48,  48, 495, 496, 497, 498, 499,
-    48,  97, 500, 501, 140, 140, 140, 140, 502, 503, 504,  48,  48, 505, 506, 192,
-   507,  83,  84, 508, 509, 510, 511, 512, 140, 140, 140, 140, 140, 140, 140, 140,
-    48,  48,  48, 513, 514, 515, 478, 140,  48,  48,  48, 516, 517, 192, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140,  48,  48, 518, 519, 520, 521, 140, 140,
-    48,  48,  48, 522, 523, 192, 524, 140,  48,  48, 525, 526, 192, 140, 140, 140,
-    48, 173, 527, 528, 314, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-    48,  48, 500, 529, 140, 140, 140, 140, 140, 140,   9,   9,  11,  11, 148, 530,
-   531, 532,  48, 533, 534, 192, 140, 140, 140, 140, 535,  48,  48, 536, 537, 140,
-   538,  48,  48, 539, 540, 541,  48,  48, 542, 543, 544,  48,  48,  48,  48, 196,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-    84,  48, 518, 545, 546, 148, 175, 547,  48, 548, 549, 550, 140, 140, 140, 140,
-   551,  48,  48, 552, 553, 192, 554,  48, 555, 556, 192, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 557,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 100, 271, 558, 559, 560,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48,  48,  48,  48, 207, 140, 140, 140, 140, 140, 140,
-   272, 272, 272, 272, 272, 272, 561, 562,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48, 388, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140,  48,  48,  48,  48,  48,  48, 563,
-    48,  48, 200, 564, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-    48,  48,  48,  48, 314, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-    48,  48,  48, 196,  48, 200, 370,  48,  48,  48,  48, 200, 192,  48, 204, 565,
-    48,  48,  48, 566, 567, 568, 569, 570,  48, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140,   9,   9,  11,  11, 271, 571, 140, 140, 140, 140, 140, 140,
-    48,  48,  48,  48, 572, 573, 574, 574, 575, 576, 140, 140, 140, 140, 577, 578,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 440,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 199, 140, 140,
-   196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 579,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48, 580, 140, 140, 580, 581,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 206,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-    48,  48,  48,  48,  48,  48,  71, 151, 196, 582, 583, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-    32,  32, 584,  32, 585, 209, 209, 209, 209, 209, 209, 209, 323, 140, 140, 140,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 324,
-   209, 209, 586, 209, 209, 209, 587, 588, 589, 209, 590, 209, 209, 209, 288, 140,
-   209, 209, 209, 209, 591, 140, 140, 140, 140, 140, 140, 140, 140, 140, 271, 592,
-   209, 209, 209, 209, 209, 287, 271, 461, 140, 140, 140, 140, 140, 140, 140, 140,
-     9, 593,  11, 594, 595, 596, 241,   9, 597, 598, 599, 600, 601,   9, 593,  11,
-   602, 603,  11, 604, 605, 606, 607,   9, 608,  11,   9, 593,  11, 594, 595,  11,
-   241,   9, 597, 607,   9, 608,  11,   9, 593,  11, 609,   9, 610, 611, 612, 613,
-    11, 614,   9, 615, 616, 617, 618,  11, 619,   9, 620,  11, 621, 622, 622, 622,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
-    32,  32,  32, 623,  32,  32, 624, 625, 626, 627,  45, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   628, 629, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   630, 631, 632, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-    48,  48, 151, 633, 634, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 635, 140,  48,  48, 636, 637,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 638, 200,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 639, 585, 140, 140,
-     9,   9, 597,  11, 640, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 498, 271, 271, 641, 642, 140, 140, 140, 140,
-   498, 271, 643, 644, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   645,  48, 646, 647, 648, 649, 650, 651, 652, 206, 653, 206, 140, 140, 140, 654,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   209, 209, 325, 209, 209, 209, 209, 209, 209, 323, 334, 655, 655, 655, 209, 324,
-   656, 209, 209, 209, 209, 209, 209, 209, 209, 209, 657, 140, 140, 140, 658, 209,
-   659, 209, 209, 325, 660, 661, 324, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 662,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 663, 426, 426,
-   209, 209, 209, 209, 209, 209, 209, 323, 209, 209, 209, 209, 209, 660, 325, 427,
-   325, 209, 209, 209, 664, 176, 209, 209, 664, 209, 657, 661, 140, 140, 140, 140,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
-   209, 209, 209, 209, 209, 323, 657, 665, 287, 209, 426, 288, 324, 176, 664, 287,
-   209, 209, 209, 209, 209, 209, 209, 209, 209, 666, 209, 209, 288, 140, 140, 192,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 140, 140,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48, 196,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48, 204,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 478,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 100, 140,
-    48, 204, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  71, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
-   667, 140, 668, 668, 668, 668, 668, 668, 140, 140, 140, 140, 140, 140, 140, 140,
-    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32, 140,
-   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
-   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 669,
-   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
-   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 670,
-     0,   0,   0,   0,   1,   2,   1,   2,   0,   0,   3,   3,   4,   5,   4,   5,
-     4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,
-     4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   6,   0,   0,   7,   0,
-     8,   8,   8,   8,   8,   8,   8,   9,  10,  11,  12,  11,  11,  11,  13,  11,
-    14,  14,  14,  14,  14,  14,  14,  14,  15,  14,  14,  14,  14,  14,  14,  14,
-    14,  14,  14,  16,  17,  18,  17,  17,  19,  20,  21,  21,  22,  21,  23,  24,
-    25,  26,  27,  27,  28,  29,  27,  30,  27,  27,  27,  27,  27,  31,  27,  27,
-    32,  33,  33,  33,  34,  27,  27,  27,  35,  35,  35,  36,  37,  37,  37,  38,
-    39,  39,  40,  41,  42,  43,  44,  27,  45,  46,  27,  27,  27,  27,  47,  27,
-    48,  48,  48,  48,  48,  49,  50,  48,  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, 109, 110, 111, 112, 109, 113, 114, 115, 116, 117, 118, 119, 120,
-   121, 122, 122, 123, 122, 124, 125, 125, 126, 127, 128, 129, 130, 131, 125, 125,
-   132, 132, 132, 132, 133, 132, 134, 135, 132, 133, 132, 136, 136, 137, 125, 125,
-   138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 139, 139, 140, 139, 139, 141,
-   142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
-   143, 143, 143, 143, 144, 145, 143, 143, 144, 143, 143, 146, 147, 148, 143, 143,
-   143, 147, 143, 143, 143, 149, 143, 150, 143, 151, 152, 152, 152, 152, 152, 153,
-   154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
-   154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
-   154, 154, 154, 154, 154, 154, 154, 154, 155, 156, 157, 157, 157, 157, 158, 159,
-   160, 161, 162, 163, 164, 165, 166, 167, 168, 168, 168, 168, 168, 169, 170, 170,
-   171, 172, 173, 173, 173, 173, 173, 174, 173, 173, 175, 154, 154, 154, 154, 176,
-   177, 178, 179, 179, 180, 181, 182, 183, 184, 184, 185, 184, 186, 187, 168, 168,
-   188, 189, 190, 190, 190, 191, 190, 192, 193, 193, 194,   8, 195, 125, 125, 125,
-   196, 196, 196, 196, 197, 196, 196, 198, 199, 199, 199, 199, 200, 200, 200, 201,
-   202, 202, 202, 203, 204, 205, 205, 205, 206, 139, 139, 207, 208, 209, 210, 211,
-     4,   4, 212,   4,   4, 213, 214, 215,   4,   4,   4, 216,   8,   8,   8,   8,
-     4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,
-    11, 217,  11,  11, 217, 218,  11, 219,  11,  11,  11, 220, 220, 221,  11, 222,
-   223,   0,   0,   0,   0,   0, 224, 225, 226, 227,   0,   0, 228,   8,   8, 229,
-     0,   0, 230, 231, 232,   0,   4,   4, 233,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0, 234, 125, 235, 125,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-   236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0, 237,   0, 238,   0,   0,   0,   0,   0,   0,
-   239, 239, 239, 239, 239, 239,   4,   4, 240, 240, 240, 240, 240, 240, 240, 241,
-   139, 139, 140, 242, 242, 242, 243, 244, 143, 245, 246, 246, 246, 246,  14,  14,
-     0,   0,   0,   0,   0, 247, 125, 125, 248, 249, 248, 248, 248, 248, 248, 250,
-   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 251, 125, 252,
-   253,   0, 254, 255, 256, 257, 257, 257, 257, 258, 259, 260, 260, 260, 260, 261,
-   262, 263, 263, 264, 142, 142, 142, 142, 265,   0, 263, 263,   0,   0, 266, 260,
-   142, 265,   0,   0,   0,   0, 142, 267,   0,   0,   0,   0,   0, 260, 260, 268,
-   260, 260, 260, 260, 260, 269,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
-   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
-   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
-   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,   0,   0,   0,   0,
-   270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270,
-   270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270,
-   270, 270, 270, 270, 270, 270, 270, 270, 271, 270, 270, 270, 272, 273, 273, 273,
-   274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274,
-   274, 274, 275, 125,  14,  14,  14,  14,  14,  14, 276, 276, 276, 276, 276, 277,
-     0,   0, 278,   4,   4,   4,   4,   4, 279,   4,   4,   4, 280, 281, 125, 282,
-   283, 283, 284, 285, 286, 286, 286, 287, 288, 288, 288, 288, 289, 290,  48,  48,
-   291, 291, 292, 293, 293, 294, 142, 295, 296, 296, 296, 296, 297, 298, 138, 299,
-   300, 300, 300, 301, 302, 303, 138, 138, 304, 304, 304, 304, 305, 306, 307, 308,
-   309, 310, 246,   4,   4, 311, 312, 152, 152, 152, 152, 152, 307, 307, 313, 314,
-   142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
-   142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
-   142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
-   142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 315, 142, 316, 142, 142, 317,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
-   248, 248, 248, 248, 248, 248, 318, 248, 248, 248, 248, 248, 248, 319, 125, 125,
-   320, 321,  21, 322, 323,  27,  27,  27,  27,  27,  27,  27, 324, 325,  27,  27,
-    27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,
-    27,  27,  27, 326,  27,  27,  27,  27,  27, 327,  27,  27, 328, 125, 125,  27,
-     8, 285, 329,   0,   0, 330, 331, 332,  27,  27,  27,  27,  27,  27,  27, 333,
-   334,   0,   1,   2,   1,   2, 335, 259, 260, 336, 142, 265, 337, 338, 339, 340,
-   341, 342, 343, 344, 345, 345, 125, 125, 342, 342, 342, 342, 342, 342, 342, 346,
-   347,   0,   0, 348,  11,  11,  11,  11, 349, 350, 351, 125, 125,   0,   0, 352,
-   125, 125, 125, 125, 125, 125, 125, 125, 353, 354, 355, 355, 355, 356, 357, 252,
-   358, 358, 359, 360, 361, 362, 362, 363, 364, 365, 366, 366, 367, 368, 125, 125,
-   369, 369, 369, 369, 369, 370, 370, 370, 371, 372, 373, 374, 374, 375, 374, 376,
-   377, 377, 378, 379, 379, 379, 380, 381, 381, 382, 383, 384, 125, 125, 125, 125,
-   385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385,
-   385, 385, 385, 386, 385, 387, 388, 125, 389,   4,   4, 390, 125, 125, 125, 125,
-   391, 392, 392, 393, 394, 395, 396, 396, 397, 398, 399, 125, 125, 125, 400, 401,
-   402, 403, 404, 405, 125, 125, 125, 125, 406, 406, 407, 408, 407, 409, 407, 407,
-   410, 411, 412, 413, 414, 414, 415, 415, 416, 416, 125, 125, 417, 417, 418, 419,
-   420, 420, 420, 421, 422, 423, 424, 425, 426, 427, 428, 125, 125, 125, 125, 125,
-   429, 429, 429, 429, 430, 125, 125, 125, 431, 431, 431, 432, 431, 431, 431, 433,
-   434, 434, 435, 436, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 125, 125,  27,  45, 437, 437, 438, 439, 125, 125, 125, 125,
-   440, 440, 441, 442, 442, 443, 125, 444, 445, 125, 125, 446, 447, 125, 448, 449,
-   450, 450, 450, 450, 451, 452, 450, 453, 454, 454, 454, 454, 455, 456, 457, 458,
-   459, 459, 459, 460, 461, 462, 462, 463, 464, 464, 464, 464, 464, 464, 465, 466,
-   467, 468, 467, 469, 125, 125, 125, 125, 470, 471, 472, 473, 473, 473, 474, 475,
-   476, 477, 478, 479, 480, 481, 482, 483, 125, 125, 125, 125, 125, 125, 125, 125,
-   484, 484, 484, 484, 484, 485, 486, 125, 487, 487, 487, 487, 488, 489, 125, 125,
-   125, 125, 125, 125, 125, 125, 125, 125, 490, 490, 490, 491, 490, 492, 125, 125,
-   493, 493, 493, 493, 494, 495, 496, 125, 497, 497, 497, 498, 498, 125, 125, 125,
-   499, 500, 501, 499, 502, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   503, 503, 503, 504, 125, 125, 125, 125, 125, 125, 505, 505, 505, 505, 505, 506,
-   507, 508, 509, 510, 511, 512, 125, 125, 125, 125, 513, 514, 514, 513, 515, 125,
-   516, 516, 516, 516, 517, 518, 518, 518, 518, 518, 519, 154, 520, 520, 520, 521,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   522, 523, 523, 524, 525, 523, 526, 527, 527, 528, 529, 530, 125, 125, 125, 125,
-   531, 532, 532, 533, 534, 535, 536, 537, 538, 539, 540, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 541, 542,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 543, 544, 544, 544, 545,
-   546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546,
-   546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546,
-   546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546,
-   546, 546, 546, 546, 546, 546, 546, 546, 546, 547, 125, 125, 125, 125, 125, 125,
-   546, 546, 546, 546, 546, 546, 548, 549, 546, 546, 546, 546, 546, 546, 546, 546,
-   546, 546, 546, 546, 550, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 551, 551, 551, 551, 551, 551, 552,
-   553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553,
-   553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553,
-   553, 553, 554, 555, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556,
-   556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556,
-   556, 556, 556, 556, 557, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
-   276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
-   276, 276, 276, 558, 559, 560, 561, 562, 562, 562, 562, 563, 564, 565, 566, 567,
-   568, 568, 568, 568, 569, 570, 571, 572, 568, 125, 125, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 573, 573, 573, 573, 573, 574, 125, 125, 125, 125, 125, 125,
-   575, 575, 575, 575, 576, 575, 575, 575, 577, 575, 125, 125, 125, 125, 578, 579,
-   580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580,
-   580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580,
-   580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580,
-   580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 581,
-   580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580,
-   582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582,
-   582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 583, 125, 125,
-   584, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 585,
-   586, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257,
-   257, 257, 587, 125, 125, 588, 589, 590, 590, 590, 590, 590, 590, 590, 590, 590,
-   590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 591,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   592, 592, 592, 592, 592, 592, 593, 594, 595, 596, 266, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-     8,   8, 597,   8, 598,   0,   0,   0,   0,   0,   0,   0, 266, 125, 125, 125,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 599,
-     0,   0, 600,   0,   0,   0, 601, 602, 603,   0, 604,   0,   0,   0, 235, 125,
-    11,  11,  11,  11, 605, 125, 125, 125, 125, 125, 125, 125, 125, 125,   0, 266,
-     0,   0,   0,   0,   0, 234,   0, 606, 125, 125, 125, 125, 125, 125, 125, 125,
-     0,   0,   0,   0,   0, 224,   0,   0,   0, 607, 608, 609, 610,   0,   0,   0,
-   611, 612,   0, 613, 614, 615,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 616,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 617,   0,   0,   0,
-   618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618,
-   618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618,
-   618, 618, 618, 618, 618, 618, 618, 618, 619, 620, 621, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-     4, 622, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   623, 624, 625, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   626, 626, 627, 628, 629, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 630, 631, 125, 632, 632, 632, 633,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 634, 635,
-   636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 637, 638, 125, 125,
-   639, 639, 639, 639, 640, 641, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 125, 125, 125, 334,   0,   0,   0, 642, 125, 125, 125, 125,
-   334,   0,   0, 247, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   643,  27, 644, 645, 646, 647, 648, 649, 650, 651, 652, 651, 125, 125, 125, 653,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-     0,   0, 252,   0,   0,   0,   0,   0,   0, 266, 226, 334, 334, 334,   0, 599,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 247, 125, 125, 125, 654,   0,
-   655,   0,   0, 252, 606, 656, 599, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 657, 350, 350,
-     0,   0,   0,   0,   0,   0,   0, 266,   0,   0,   0,   0,   0, 606, 252, 228,
-   252,   0,   0,   0, 658, 285,   0,   0, 658,   0, 247, 656, 125, 125, 125, 125,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0, 266, 247, 659, 234,   0, 350, 235, 599, 285, 658, 234,
-     0,   0,   0,   0,   0,   0,   0,   0,   0, 330,   0,   0, 235, 125, 125, 285,
-   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 125, 125,
-   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
-   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
-   248, 248, 248, 660, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
-   248, 318, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
-   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
-   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 579, 248, 248, 248, 248, 248,
-   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
-   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
-   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 661, 125,
-   248, 318, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
-   248, 248, 248, 248, 662, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
-   663, 125,   0,   0,   0,   0,   0,   0, 125, 125, 125, 125, 125, 125, 125, 125,
-     8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-   939, 940, 941, 942, 946, 948,   0, 962, 969, 970, 971, 976,1001,1002,1003,1008,
-     0,1033,1040,1041,1042,1043,1047,   0,   0,1080,1081,1082,1086,1110,   0,   0,
-  1124,1125,1126,1127,1131,1133,   0,1147,1154,1155,1156,1161,1187,1188,1189,1193,
-     0,1219,1226,1227,1228,1229,1233,   0,   0,1267,1268,1269,1273,1298,   0,1303,
-   943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149,
-     0,   0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175,
-   991,1176, 993,1178, 994,1179,   0,   0,1004,1190,1005,1191,1006,1192,1014,1199,
-  1007,   0,   0,   0,1016,1201,1020,1206,   0,1022,1208,1025,1211,1023,1209,   0,
-     0,   0,   0,1032,1218,1037,1223,1035,1221,   0,   0,   0,1044,1230,1045,1231,
-  1049,1235,   0,   0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258,
-  1069,1255,1077,1264,1074,1261,   0,   0,1083,1270,1084,1271,1085,1272,1088,1275,
-  1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-  1053,1239,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1093,
-  1280,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 949,1134,1010,
-  1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366,   0,1320,1347,
-  1418,1419,1323,1350,   0,   0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424,
-  1202,   0,   0,   0, 987,1172,   0,   0,1031,1217,1321,1348,1322,1349,1338,1365,
-   950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238,
-  1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263,   0,   0, 997,1182,
-     0,   0,   0,   0,   0,   0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232,
-  1422,1423,1113,1301,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     8,   9,   0,  10,1425,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   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,   1,   0,
-     0,   0,   0,   0,   0,1314,1427,   5,1434,1438,1443,   0,1450,   0,1455,1461,
-  1514,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1446,1458,1468,1476,1480,1486,
-  1517,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1489,1503,1494,1500,1508,   0,
-     0,   0,   0,1520,1521,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-  1526,1528,   0,1525,   0,   0,   0,1522,   0,   0,   0,   0,1536,1532,1539,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,1534,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,1556,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-  1548,1550,   0,1547,   0,   0,   0,1567,   0,   0,   0,   0,1558,1554,1561,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,1568,1569,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,1529,1551,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-  1523,1545,1524,1546,   0,   0,1527,1549,   0,   0,1570,1571,1530,1552,1531,1553,
-     0,   0,1533,1555,1535,1557,1537,1559,   0,   0,1572,1573,1544,1566,1538,1560,
-  1540,1562,1541,1563,1542,1564,   0,   0,1543,1565,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,1606,1607,1609,1608,1610,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-  1613,   0,1611,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,1612,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,1620,   0,   0,   0,   0,   0,   0,
-     0,1623,   0,   0,1624,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,1614,1615,1616,1617,1618,1619,1621,1622,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1628,1629,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1625,1626,   0,1627,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,1634,   0,   0,1635,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,1630,1631,1632,   0,   0,1633,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,1639,   0,   0,1638,1640,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1636,1637,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,1641,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1642,1644,1643,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,1645,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-  1646,   0,   0,   0,   0,   0,   0,1648,1649,   0,1647,1650,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1651,1653,1652,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1654,   0,1655,1657,1656,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,1659,   0,   0,   0,   0,   0,   0,   0,   0,   0,1660,   0,   0,
-     0,   0,1661,   0,   0,   0,   0,1662,   0,   0,   0,   0,1663,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,1658,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,1664,   0,1665,1673,   0,1674,   0,   0,   0,   0,   0,   0,   0,
-     0,1666,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,1668,   0,   0,   0,   0,   0,   0,   0,   0,   0,1669,   0,   0,
-     0,   0,1670,   0,   0,   0,   0,1671,   0,   0,   0,   0,1672,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,1667,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,1675,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,1676,   0,1677,   0,1678,   0,1679,   0,1680,   0,
-     0,   0,1681,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1682,   0,1683,   0,   0,
-  1684,1685,   0,1686,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-   953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153,
-   966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171,
-   989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356,
-  1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214,
-  1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363,
-  1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251,
-  1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266,
-  1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287,
-  1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302,
-  1119,1308,1122,1311,1123,1312,1186,1260,1293,1305,   0,1394,   0,   0,   0,   0,
-   952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375,
-  1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353,
-  1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234,
-  1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403,
-  1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412,
-  1409,1414,1109,1297,1117,1306,1116,1304,1112,1300,   0,   0,   0,   0,   0,   0,
-  1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721,
-  1477,1478,1729,1731,1730,1732,   0,   0,1435,1436,1733,1735,1734,1736,   0,   0,
-  1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757,
-  1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776,
-  1495,1496,1777,1779,1778,1780,   0,   0,1451,1452,1781,1783,1782,1784,   0,   0,
-  1504,1505,1785,1788,1786,1789,1787,1790,   0,1459,   0,1791,   0,1792,   0,1793,
-  1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814,
-  1467,  21,1475,  22,1479,  23,1485,  24,1493,  27,1499,  28,1507,  29,   0,   0,
-  1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728,
-  1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764,
-  1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821,
-  1470,1469,1822,1474,1465,   0,1473,1825,1429,1428,1426,  12,1432,   0,  26,   0,
-     0,1315,1823,1484,1466,   0,1483,1829,1433,  13,1437,  14,1441,1826,1827,1828,
-  1488,1487,1513,  19,   0,   0,1492,1515,1445,1444,1442,  15,   0,1831,1832,1833,
-  1502,1501,1516,  25,1497,1498,1506,1518,1457,1456,1454,  17,1453,1313,  11,   3,
-     0,   0,1824,1512,1519,   0,1511,1830,1449,  16,1460,  18,1464,   4,   0,   0,
-    30,  31,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,  20,   0,   0,   0,   2,   6,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1834,1835,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1836,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1837,1839,1838,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,1840,   0,   0,   0,   0,1841,   0,   0,1842,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,1843,   0,1844,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,1845,   0,   0,1846,   0,   0,1847,   0,1848,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-   937,   0,1850,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1849, 936, 938,
-  1851,1852,   0,   0,1853,1854,   0,   0,1855,1856,   0,   0,   0,   0,   0,   0,
-  1857,1858,   0,   0,1861,1862,   0,   0,1863,1864,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1867,1868,1869,1870,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-  1859,1860,1865,1866,   0,   0,   0,   0,   0,   0,1871,1872,1873,1874,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,  32,  33,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1875,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1877,   0,1878,   0,
-  1879,   0,1880,   0,1881,   0,1882,   0,1883,   0,1884,   0,1885,   0,1886,   0,
-  1887,   0,1888,   0,   0,1889,   0,1890,   0,1891,   0,   0,   0,   0,   0,   0,
-  1892,1893,   0,1894,1895,   0,1896,1897,   0,1898,1899,   0,1900,1901,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,1876,   0,   0,   0,   0,   0,   0,   0,   0,   0,1902,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1904,   0,1905,   0,
-  1906,   0,1907,   0,1908,   0,1909,   0,1910,   0,1911,   0,1912,   0,1913,   0,
-  1914,   0,1915,   0,   0,1916,   0,1917,   0,1918,   0,   0,   0,   0,   0,   0,
-  1919,1920,   0,1921,1922,   0,1923,1924,   0,1925,1926,   0,1927,1928,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,1903,   0,   0,1929,1930,1931,1932,   0,   0,   0,1933,   0,
-   710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601,
-   663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662,
-   810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168,
-   368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758,
-   811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585,
-   594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259,
-   313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697,
-   424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170,
-   193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330,
-   337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473,
-   683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603,
-   608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411,
-   479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583,
-   791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269,
-   377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510,
-   659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156,
-   153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210,   0,   0,
-   227,   0, 379,   0,   0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604,   0,
-   661,   0, 703,   0,   0, 735, 743,   0,   0,   0, 793, 794, 795, 808, 741, 773,
-   118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329,
-   335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548,
-   549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651,
-   690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623,   0,   0,
-   102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243,
-   250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362,
-   370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490,
-   493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586,
-   591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706,
-   709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848,
-   847, 857,  55,  65,  66, 883, 892, 916, 822, 824,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1586,   0,1605,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1602,1603,1934,1935,1574,1575,
-  1576,1577,1579,1580,1581,1583,1584,   0,1585,1587,1588,1589,1591,   0,1592,   0,
-  1593,1594,   0,1595,1596,   0,1598,1599,1600,1601,1604,1582,1578,1590,1597,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1936,   0,1937,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1938,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1939,1940,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1941,1942,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1944,1943,   0,1945,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1946,1947,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,1948,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1949,1950,
-  1951,1952,1953,1954,1955,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1956,1957,1958,1960,1959,
-  1961,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-   106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125,  34, 830, 130, 131,
-   132, 137, 827,  35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152,  37,
-   157, 158, 159, 160,  38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179,
-   181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195,
-   197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216,
-   153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244,
-   836, 837, 247, 248, 249, 246, 251,  39,  40, 253, 255, 255, 838, 257, 258, 259,
-   261, 839, 262, 263, 301, 264,  41, 266, 270, 272, 271, 841, 274, 842, 277, 276,
-   278, 281, 282,  42, 283, 284, 285, 286,  43, 843,  44, 289, 290, 291, 293, 934,
-   298, 845, 845, 621, 300, 300,  45, 852, 894, 302, 304,  46, 306, 309, 310, 312,
-   316,  48,  47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334,
-   335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361,
-   358, 356,  49, 363, 365, 367, 364,  50, 369, 371, 851, 376, 386, 378,  53, 381,
-    52,  51, 140, 141, 387, 382, 614,  78, 388, 389, 390, 394, 392, 856,  54, 399,
-   396, 402, 404, 858, 405, 401, 407,  55, 408, 409, 410, 413, 859, 415,  56, 417,
-   860, 418,  57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433,
-   437, 441, 438, 439, 442, 443, 864, 436, 449, 450,  58, 454, 453, 865, 447, 460,
-   866, 867, 461, 466, 465, 464,  59, 467, 470, 469, 472, 828, 475, 868, 478, 870,
-   483, 485, 486, 871, 488, 489, 872, 873, 495, 497,  60, 498,  61,  61, 504, 505,
-   507, 508, 511,  62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878,  63,  64,
-   528, 880, 879, 881, 882, 530, 531, 531, 533,  66, 534,  67,  68, 884, 536, 538,
-   541,  69, 885, 549, 886, 887, 556, 559,  70, 561, 562, 563, 888, 889, 889, 567,
-    71, 890, 570, 571,  72, 891, 577,  73, 581, 579, 582, 893, 587,  74, 590, 592,
-   596,  75, 895, 896,  76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611,
-   853,  77, 615, 616,  79, 617, 252, 902, 903, 854, 855, 621, 622, 731,  80, 627,
-   626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651,
-   638, 643, 644, 645, 905, 907, 906,  81, 653, 654, 656, 911, 657, 908,  82,  83,
-   909, 910,  84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675,  85,
-   677, 678,  86, 681, 682, 912, 685, 686,  87, 689,  36, 913, 914,  88,  89, 696,
-   702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728,
-   918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762,  90,
-   764, 922,  91, 775, 279, 780, 923, 925,  92,  93, 785, 926,  94, 927, 787, 787,
-   789, 928, 792,  95, 796, 797, 798, 800,  96, 929, 802, 804, 806,  97,  98, 807,
-   930,  99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   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 int16_t
-_hb_ucd_i16[196] =
-{
-      0,    0,    0,    0,    1,   -1,    0,    0,    2,    0,   -2,    0,    0,    0,    0,    2,
-      0,   -2,    0,    0,    0,    0,    0,   16,    0,    0,    0,  -16,    0,    0,    1,   -1,
-      0,    0,    0,    1,   -1,    0,    0,    0,    0,    1,   -1,    0,    3,    3,    3,   -3,
-     -3,   -3,    0,    0,    0, 2016,    0,    0,    0,    0,    0, 2527, 1923, 1914, 1918,    0,
-   2250,    0,    0,    0,    0,    0,    0,  138,    0,    7,    0,    0,   -7,    0,    0,    0,
-      1,   -1,    1,   -1,   -1,    1,   -1,    0, 1824,    0,    0,    0,    0,    0, 2104,    0,
-   2108, 2106,    0, 2106, 1316,    0,    0,    0,    0,    1,   -1,    1,   -1, -138,    0,    0,
-      1,   -1,    8,    8,    8,    0,    7,    7,    0,    0,   -8,   -8,   -8,   -7,   -7,    0,
-      1,   -1,    0,    2,-1316,    1,   -1,    0,   -1,    1,   -1,    1,   -1,    3,    1,   -1,
-     -3,    1,   -1,    1,   -1,    0,    0,-1914,-1918,    0,    0,-1923,-1824,    0,    0,    0,
-      0,-2016,    0,    0,    1,   -1,    0,    1,    0,    0,-2104,    0,    0,    0,    0,-2106,
-  -2108,-2106,    0,    0,    1,   -1,-2250,    0,    0,    0,-2527,    0,    0,   -2,    0,    1,
-     -1,    0,    1,   -1,
-};
-
-static inline uint_fast8_t
-_hb_ucd_gc (unsigned u)
-{
-  return u<1114110u?_hb_ucd_u8[2176+(((_hb_ucd_u16[((_hb_ucd_u8[u>>4>>5])<<5)+((u>>4)&31u)])<<4)+((u)&15u))]:2;
-}
-static inline uint_fast8_t
-_hb_ucd_ccc (unsigned u)
-{
-  return u<125259u?_hb_ucd_u8[15332+(((_hb_ucd_u8[13892+(((_hb_ucd_u8[12912+(u>>3>>4)])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:0;
-}
-static inline unsigned
-_hb_ucd_b4 (const uint8_t* a, unsigned i)
-{
-  return (a[i>>1]>>((i&1u)<<2))&15u;
-}
-static inline int_fast16_t
-_hb_ucd_bmg (unsigned u)
-{
-  return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[16692+(((_hb_ucd_b4(16564+_hb_ucd_u8,u>>2>>6))<<6)+((u>>2)&63u))])<<2)+((u)&3u)]:0;
-}
-static inline uint_fast8_t
-_hb_ucd_sc (unsigned u)
-{
-  return u<918000u?_hb_ucd_u8[19446+(((_hb_ucd_u16[3168+(((_hb_ucd_u8[17652+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:2;
-}
-static inline uint_fast16_t
-_hb_ucd_dm (unsigned u)
-{
-  return u<195102u?_hb_ucd_u16[6400+(((_hb_ucd_u8[30070+(u>>6)])<<6)+((u)&63u))]:0;
-}
-
-
-#elif !defined(HB_NO_UCD_UNASSIGNED)
-
-static const uint8_t
-_hb_ucd_u8[17936] =
-{
-    0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  9, 10,  7,  7,  7,  7, 11, 12, 13, 13, 13, 14,
-   15, 16, 17, 18, 19, 20, 21, 22, 23, 22, 22, 22, 22, 24,  7,  7,
-   25, 26, 22, 22, 22, 27, 28, 29, 22, 30, 31, 32, 33, 34, 35, 36,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7, 37,  7, 38, 39,  7, 40,  7,  7,  7, 41, 22, 42,
-    7,  7, 43, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   44, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 45,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 46,
-    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, 34, 35, 36, 37, 38, 39, 34, 34, 34, 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, 64, 65, 66, 67, 68, 69, 70, 71, 69, 72, 73,
-   69, 69, 64, 74, 64, 64, 75, 76, 77, 78, 79, 80, 81, 82, 69, 83,
-   84, 85, 86, 87, 88, 89, 69, 69, 34, 34, 34, 34, 34, 34, 34, 34,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 46,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 47,
+    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, 34, 35, 36, 37, 38, 39, 34, 34, 34, 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, 64, 65, 66, 67, 68, 69, 70, 71, 69, 72, 73,
+   69, 69, 64, 74, 64, 64, 75, 76, 77, 78, 79, 80, 81, 82, 69, 83,
+   84, 85, 86, 87, 88, 89, 69, 69, 34, 34, 34, 34, 34, 34, 34, 34,
    34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
    34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 90, 34, 34, 34, 34,
    91, 34, 34, 34, 34, 34, 34, 34, 34, 92, 34, 34, 93, 94, 95, 96,
@@ -3975,35 +1123,36 @@ _hb_ucd_u8[17936] =
   118,119,120,121,122,123,124,125,126,127,128,129, 34, 34,130,131,
   132,133,134,135,136,137,138,139,140,141,142,122,143,144,145,146,
   147,148,149,150,151,152,153,122,154,155,122,156,157,158,159,122,
-  160,161,162,163,164,165,122,122,166,167,168,169,122,170,122,171,
-   34, 34, 34, 34, 34, 34, 34,172,173, 34,174,122,122,122,122,122,
-  122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,175,
-   34, 34, 34, 34, 34, 34, 34, 34,176,122,122,122,122,122,122,122,
+  160,161,162,163,164,165,166,122,167,168,169,170,122,171,172,173,
+   34, 34, 34, 34, 34, 34, 34,174,175, 34,176,122,122,122,122,122,
+  122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,177,
+   34, 34, 34, 34, 34, 34, 34, 34,178,122,122,122,122,122,122,122,
   122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,
-  122,122,122,122,122,122,122,122, 34, 34, 34, 34,177,122,122,122,
-   34, 34, 34, 34,178,179,180,181,122,122,122,122,182,183,184,185,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,186,
-   34, 34, 34, 34, 34, 34, 34, 34, 34,187,188,122,122,122,122,122,
-  122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,189,
-   34, 34,190, 34, 34,191,122,122,122,122,122,122,122,122,122,122,
-  122,122,122,122,122,122,122,122,192,193,122,122,122,122,122,122,
-  122,122,122,122,122,122,122,122,122,122,122,122,122,122,194,195,
-   69,196,197,198,199,200,201,122,202,203,204,205,206,207,208,209,
-   69, 69, 69, 69,210,211,122,122,122,122,122,122,122,122,212,122,
-  213,122,214,122,122,215,122,122,122,122,122,122,122,122,122,216,
-   34,217,218,122,122,122,122,122,219,220,221,122,222,223,122,122,
-  224,225,226,227,228,122, 69,229, 69, 69, 69, 69, 69,230,231,232,
-  233,234, 69, 69,235,236, 69,237,122,122,122,122,122,122,122,122,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,238, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,239, 34,
-  240, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,241, 34, 34,
-   34, 34, 34, 34, 34, 34, 34,242,122,122,122,122,122,122,122,122,
-   34, 34, 34, 34,243,122,122,122,122,122,122,122,122,122,122,122,
-   34, 34, 34, 34, 34, 34,244,122,122,122,122,122,122,122,122,122,
-  245,122,246,247,122,122,122,122,122,122,122,122,122,122,122,122,
-  107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,248,
-  107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,249,
+  122,122,122,122,122,122,122,122, 34, 34, 34, 34,179,122,122,122,
+   34, 34, 34, 34,180,181,182,183,122,122,122,122,184,185,186,187,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,188,
+   34, 34, 34, 34, 34, 34, 34, 34, 34,189,190,122,122,122,122,122,
+  122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,191,
+   34, 34,192, 34, 34,193,122,122,122,122,122,122,122,122,122,122,
+  122,122,122,122,122,122,122,122,194,195,122,122,122,122,122,122,
+  122,122,122,122,122,122,122,122,122,122,122,122,122,122,196,197,
+   69,198,199,200,201,202,203,122,204,205,206,207,208,209,210,211,
+   69, 69, 69, 69,212,213,122,122,122,122,122,122,122,122,214,122,
+  215,216,217,122,122,218,122,122,122,219,122,122,122,122,122,220,
+   34,221,222,122,122,122,122,122,223,224,225,122,226,227,122,122,
+  228,229,230,231,232,122, 69,233, 69, 69, 69, 69, 69,234,235,236,
+  237,238, 69, 69,239,240, 69,241,122,122,122,122,122,122,122,122,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,242, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,243, 34,
+  244, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,245, 34, 34,
+   34, 34, 34, 34, 34, 34, 34,246, 34, 34, 34, 34,247,122,122,122,
+   34, 34, 34, 34,248,122,122,122,122,122,122,122,122,122,122,122,
+   34, 34, 34, 34, 34, 34,249, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34,250,122,122,122,122,122,122,122,122,
+  251,122,252,253,122,122,122,122,122,122,122,122,122,122,122,122,
+  107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,254,
+  107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,255,
     0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  2,  4,  5,  6,  2,
     7,  7,  7,  7,  7,  2,  8,  9, 10, 11, 11, 11, 11, 11, 11, 11,
    11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16,
@@ -4066,7 +1215,7 @@ _hb_ucd_u8[17936] =
    44, 44, 57, 80, 36, 61, 62, 44, 44, 44, 44, 93, 27, 27, 27, 91,
    70, 86, 72, 36, 36, 36, 61, 36, 36, 36, 62, 36, 36, 44, 71, 87,
    86, 86, 90, 85, 90, 86, 43, 44, 44, 44, 89, 90, 44, 44, 62, 61,
-   62, 61, 44, 44, 44, 44, 44, 44, 43, 86, 36, 36, 36, 36, 61, 36,
+   62, 94, 44, 44, 44, 44, 44, 44, 43, 86, 36, 36, 36, 36, 61, 36,
    36, 36, 36, 36, 36, 70, 71, 86, 87, 43, 80, 86, 90, 86, 87, 77,
    44, 44, 36, 94, 27, 27, 27, 95, 27, 27, 27, 27, 91, 36, 36, 36,
    57, 86, 62, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 36, 36, 36,
@@ -4076,7 +1225,7 @@ _hb_ucd_u8[17936] =
    36, 36, 36, 75, 43, 43, 43, 60,  7,  7,  7,  7,  7,  2, 44, 44,
    44, 44, 44, 44, 44, 44, 44, 44, 62, 61, 61, 36, 36, 61, 36, 36,
    36, 36, 62, 62, 36, 36, 36, 36, 70, 36, 43, 43, 43, 43, 71, 44,
-   36, 36, 61, 81, 43, 43, 43, 44,  7,  7,  7,  7,  7, 44, 36, 36,
+   36, 36, 61, 81, 43, 43, 43, 80,  7,  7,  7,  7,  7, 44, 36, 36,
    77, 67,  2,  2,  2,  2,  2,  2,  2, 97, 97, 67, 43, 67, 67, 67,
     7,  7,  7,  7,  7, 27, 27, 27, 27, 27, 50, 50, 50,  4,  4, 86,
    36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44,
@@ -4166,11 +1315,11 @@ _hb_ucd_u8[17936] =
   121,  4,  4,  4,  4,  2,  2, 88,  2,  2,  2,  2,  2,120,  2,  2,
   108,151,  2,  2,  2,  2,  2,  2, 67,  2,152,148,148,148,153, 44,
    67, 67, 67, 67, 67, 55, 67, 67, 67, 67, 44, 44, 44, 44, 44, 44,
-   67, 67, 67, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 44, 44,
-    1,  2,154,155,  4,  4,  4,  4,  4, 67,  4,  4,  4,  4,156,157,
-  158,105,105,105,105, 43, 43, 86,159, 40, 40, 67,105,160, 63, 67,
-   36, 36, 36, 61, 57,161,162, 69, 36, 36, 36, 36, 36, 63, 40, 69,
-   44, 44, 62, 36, 36, 36, 36, 36, 67, 27, 27, 67, 67, 67, 67, 67,
+   67, 67, 67, 44, 44, 44, 44, 44,  1,  2,154,155,  4,  4,  4,  4,
+    4, 67,  4,  4,  4,  4,156,157,158,105,105,105,105, 43, 43, 86,
+  159, 40, 40, 67,105,160, 63, 67, 36, 36, 36, 61, 57,161,162, 69,
+   36, 36, 36, 36, 36, 63, 40, 69, 44, 44, 62, 36, 36, 36, 36, 36,
+   67, 27, 27, 67, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44, 44, 55,
    67, 67, 67, 67, 67, 67, 67, 92, 27, 27, 27, 27, 27, 67, 67, 67,
    67, 67, 67, 67, 27, 27, 27, 27,163, 27, 27, 27, 27, 27, 27, 27,
    36, 36, 83, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,164,  2,
@@ -4243,18 +1392,19 @@ _hb_ucd_u8[17936] =
    44, 44, 44, 44,179, 27, 27, 27, 11, 47, 44, 44, 44, 44, 44, 44,
    16,110, 44, 44, 44, 27, 27, 27, 36, 36, 43, 43, 44, 44, 44, 44,
    27, 27, 27, 27, 27, 27, 27,100, 36, 36, 36, 36, 36, 57,184, 44,
-   36, 44, 44, 44, 44, 44, 44, 44, 27, 27, 27, 95, 44, 44, 44, 44,
-  180, 27, 30,  2,  2, 44, 44, 44, 36, 43, 43,  2,  2, 44, 44, 44,
-   36, 36,183, 27, 27, 27, 44, 44, 87, 98, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 43, 60,  2,  2,  2, 44,
-   27, 27, 27,  7,  7,  7,  7,  7, 71, 70, 71, 44, 44, 44, 44, 57,
-   86, 87, 43, 85, 87, 60,185,  2,  2, 80, 44, 44, 44, 44, 79, 44,
-   43, 71, 36, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43, 87, 43,
-   43, 43, 80,  7,  7,  7,  7,  7,  2,  2, 94, 98, 44, 44, 44, 44,
-   36, 70,  2, 61, 44, 44, 44, 44, 36, 94, 86, 43, 43, 43, 43, 85,
-   98, 36, 63,  2, 59, 43, 60, 87,  7,  7,  7,  7,  7, 63, 63,  2,
-  179, 27, 27, 27, 27, 27, 27, 27, 27, 27,100, 44, 44, 44, 44, 44,
-   36, 36, 36, 36, 36, 36, 86, 87, 43, 86, 85, 43,  2,  2,  2, 80,
+   36, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 57, 43,
+   27, 27, 27, 95, 44, 44, 44, 44,180, 27, 30,  2,  2, 44, 44, 44,
+   36, 43, 43,  2,  2, 44, 44, 44, 36, 36,183, 27, 27, 27, 44, 44,
+   87, 98, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43,
+   43, 43, 43, 60,  2,  2,  2, 44, 27, 27, 27,  7,  7,  7,  7,  7,
+   71, 70, 71, 44, 44, 44, 44, 57, 86, 87, 43, 85, 87, 60,185,  2,
+    2, 80, 44, 44, 44, 44, 79, 44, 43, 71, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 70, 43, 43, 87, 43, 43, 43, 80,  7,  7,  7,  7,  7,
+    2,  2, 94, 98, 44, 44, 44, 44, 36, 70,  2, 61, 44, 44, 44, 44,
+   36, 94, 86, 43, 43, 43, 43, 85, 98, 36, 63,  2, 59, 43, 60, 87,
+    7,  7,  7,  7,  7, 63, 63,  2,179, 27, 27, 27, 27, 27, 27, 27,
+   27, 27,100, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 86, 87,
+   43, 86, 85, 43,  2,  2,  2, 71, 70, 44, 44, 44, 44, 44, 44, 44,
    36, 36, 36, 61, 61, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 62,
    36, 36, 36, 36, 63, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 70,
    86, 87, 43, 43, 43, 80, 44, 44, 43, 86, 62, 36, 36, 36, 61, 62,
@@ -4276,17 +1426,20 @@ _hb_ucd_u8[17936] =
    70, 43, 43, 43, 43, 71, 36, 36, 36, 70, 43, 43, 85, 70, 43, 60,
     2,  2,  2, 59, 44, 44, 44, 44, 70, 43, 43, 85, 87, 43, 36, 36,
    36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 85, 43,  2, 72,  2,
-    2, 64, 44, 44, 44, 44, 44, 44, 43, 43, 43, 80, 43, 43, 43, 87,
-   63,  2,  2, 44, 44, 44, 44, 44,  2, 36, 36, 36, 36, 36, 36, 36,
-   44, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 89, 43, 43, 43,
-   85, 43, 87, 80, 44, 44, 44, 44, 36, 36, 36, 61, 36, 62, 36, 36,
-   70, 43, 43, 80, 44, 80, 43, 57, 43, 43, 43, 70, 44, 44, 44, 44,
-   36, 36, 36, 62, 61, 36, 36, 36, 36, 36, 36, 36, 36, 86, 86, 90,
-   43, 89, 87, 87, 61, 44, 44, 44, 36, 70, 85,107, 64, 44, 44, 44,
+    2, 64, 44, 44, 44, 44, 44, 44,  2,  2,  2,  2,  2, 44, 44, 44,
+   43, 43, 43, 80, 43, 43, 43, 87, 63,  2,  2, 44, 44, 44, 44, 44,
+    2, 36, 36, 36, 36, 36, 36, 36, 44, 43, 43, 43, 43, 43, 43, 43,
+   43, 43, 43, 43, 89, 43, 43, 43, 85, 43, 87, 80, 44, 44, 44, 44,
+   36, 36, 36, 61, 36, 62, 36, 36, 70, 43, 43, 80, 44, 80, 43, 57,
+   43, 43, 43, 70, 44, 44, 44, 44, 36, 36, 36, 62, 61, 36, 36, 36,
+   36, 36, 36, 36, 36, 86, 86, 90, 43, 89, 87, 87, 61, 44, 44, 44,
+   36, 70, 85,107, 64, 44, 44, 44, 43, 94, 36, 36, 36, 36, 36, 36,
+   36, 36, 86, 43, 43, 80, 44, 86, 85, 60,  2,  2,  2,  2,  2,  2,
    27, 27, 91, 67, 67, 67, 56, 20,168, 67, 67, 67, 67, 67, 67, 67,
    67, 44, 44, 44, 44, 44, 44, 93,105,105,105,105,105,105,105,181,
     2,  2, 64, 44, 44, 44, 44, 44, 63, 64, 44, 44, 44, 44, 44, 44,
-   65, 65, 65, 65,132, 44, 44, 44, 43, 43, 60, 44, 44, 44, 44, 44,
+   65, 65, 65, 65, 65, 65, 65, 65, 71, 36, 36, 70, 43, 43, 43, 43,
+   43, 43, 43, 44, 44, 44, 44, 44, 43, 43, 60, 44, 44, 44, 44, 44,
    43, 43, 43, 60,  2,  2, 67, 67, 40, 40, 97, 44, 44, 44, 44, 44,
     7,  7,  7,  7,  7,179, 27, 27, 27, 62, 36, 36, 36, 36, 36, 36,
    36, 36, 36, 36, 44, 44, 62, 36, 27, 27, 27, 30,  2, 64, 44, 44,
@@ -4294,7 +1447,8 @@ _hb_ucd_u8[17936] =
    86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 44, 44, 44, 57,
    43, 74, 40, 40, 40, 40, 40, 40, 40, 88, 80, 44, 44, 44, 44, 44,
    86, 44, 44, 44, 44, 44, 44, 44, 40, 40, 52, 40, 40, 40, 52, 81,
-   36, 61, 44, 44, 44, 44, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44,
+   36, 61, 44, 44, 44, 44, 44, 44, 44, 61, 44, 44, 44, 44, 44, 44,
+   36, 61, 62, 44, 44, 44, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44,
    36, 36, 36, 36, 36, 44, 50, 60, 65, 65, 44, 44, 44, 44, 44, 44,
    43, 43, 43, 43, 43, 43, 43, 44, 43, 43, 43, 80, 44, 44, 44, 44,
    67, 67, 67, 92, 55, 67, 67, 67, 67, 67,186, 87, 43, 67,186, 86,
@@ -4319,10 +1473,12 @@ _hb_ucd_u8[17936] =
    43, 43, 43, 43, 43, 43, 76, 67, 67, 67, 50, 67, 67, 67, 67, 67,
    67, 67, 76, 21,  2,  2, 44, 44, 44, 44, 44, 44, 44, 57, 43, 43,
    16, 16, 16, 16, 16, 39, 16, 16, 16, 16, 16, 16, 16, 16, 16,110,
-   43, 43, 43, 80, 43, 43, 43, 43, 43, 43, 43, 43, 80, 57, 43, 43,
-   43, 57, 80, 43, 43, 80, 44, 44, 43, 43, 43, 74, 40, 40, 40, 44,
-    7,  7,  7,  7,  7, 44, 44, 77, 36, 36, 36, 36, 36, 36, 36, 80,
-   36, 36, 36, 36, 36, 36, 43, 43,  7,  7,  7,  7,  7, 44, 44, 96,
+   44, 44,150, 16, 16,110, 44, 44, 43, 43, 43, 80, 43, 43, 43, 43,
+   43, 43, 43, 43, 80, 57, 43, 43, 43, 57, 80, 43, 43, 80, 44, 44,
+   40, 40, 40, 40, 40, 40, 40, 44, 44, 44, 44, 44, 44, 44, 44, 57,
+   43, 43, 43, 74, 40, 40, 40, 44,  7,  7,  7,  7,  7, 44, 44, 77,
+   36, 36, 36, 36, 36, 36, 36, 80, 36, 36, 36, 36, 36, 36, 43, 43,
+    7,  7,  7,  7,  7, 44, 44, 96, 36, 36, 36, 36, 36, 83, 43, 43,
    36, 36, 36, 61, 36, 36, 62, 61, 36, 36, 61,179, 27, 27, 27, 27,
    16, 16, 43, 43, 43, 74, 44, 44, 27, 27, 27, 27, 27, 27,163, 27,
   188, 27,100, 44, 44, 44, 44, 44, 27, 27, 27, 27, 27, 27, 27,163,
@@ -4331,14 +1487,15 @@ _hb_ucd_u8[17936] =
    44, 61, 44, 62, 62, 62, 62, 36, 62, 61, 61, 62, 62, 62, 62, 62,
    62, 61, 61, 62, 36, 61, 36, 36, 36, 61, 36, 36, 62, 36, 61, 61,
    36, 36, 36, 36, 36, 62, 36, 36, 62, 36, 62, 36, 36, 62, 36, 36,
-    8, 44, 44, 44, 44, 44, 44, 44, 55, 67, 67, 67, 67, 67, 67, 67,
-   27, 27, 27, 27, 27, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 44,
-   44, 44, 44, 67, 67, 67, 67, 67, 67, 92, 44, 44, 44, 44, 44, 44,
-   67, 67, 67, 67, 92, 44, 44, 44, 67, 44, 44, 44, 44, 44, 44, 44,
-   67, 67, 67, 67, 67, 25, 41, 41, 67, 67, 67, 67, 44, 44, 55, 67,
-   67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 92, 44, 67, 67, 92, 44,
-   67, 92, 67, 67, 67, 67, 67, 67, 79, 44, 44, 44, 44, 44, 44, 44,
-   65, 65, 65, 65, 65, 65, 65, 65,171,171,171,171,171,171,171, 44,
+    8, 44, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 44, 44,
+   55, 67, 67, 67, 67, 67, 67, 67, 27, 27, 27, 27, 27, 27, 91, 67,
+   67, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 67, 67, 67,
+   67, 92, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 92, 44, 44, 44,
+   67, 44, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 25, 41, 41,
+   67, 67, 67, 67, 44, 44, 67, 67, 67, 67, 67, 92, 44, 55, 67, 67,
+   67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 67, 55,
+   67, 67, 67, 44, 44, 44, 44, 67, 67, 92, 67, 67, 67, 67, 67, 67,
+   79, 44, 44, 44, 44, 44, 44, 44,171,171,171,171,171,171,171, 44,
   171,171,171,171,171,171,171,  0,  0,  0, 29, 21, 21, 21, 23, 21,
    22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21,  9,  9,  9,
     9, 22, 21, 18, 24, 16, 24,  5,  5,  5,  5, 22, 25, 18, 25,  0,
@@ -4372,193 +1529,173 @@ _hb_ucd_u8[17936] =
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 20,
     0, 21, 22, 23,  0,  0,  0, 24, 25, 26, 27, 28, 29, 30, 31, 32,
-   33,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 34,  0, 35,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-   36,  0,  0,  0,  0,  0,  0,  0,  0,  0, 37, 38,  0,  0,  0,  0,
-    0,  0, 39, 40,  0,  0, 41,  0,  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,  0,  0,  0,  0,  0,  0,  0,  0,  5,  0,  0,  0,
-    0,  0,  0,  0,  6,  7,  8,  0,  9,  0, 10, 11,  0,  0, 12, 13,
-   14, 15, 16,  0,  0,  0,  0, 17, 18, 19, 20,  0, 21,  0, 22, 23,
-    0, 24, 25,  0,  0, 24, 26, 27,  0, 24, 26,  0,  0, 24, 26,  0,
-    0, 24, 26,  0,  0,  0, 26,  0,  0, 24, 28,  0,  0, 24, 26,  0,
-    0, 29, 26,  0,  0,  0, 30,  0,  0, 31, 32,  0,  0, 33, 34,  0,
-   35, 36,  0, 37, 38,  0, 39,  0,  0, 40,  0,  0, 41,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0, 42,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-   43, 44,  0,  0,  0,  0, 45,  0,  0,  0,  0,  0,  0, 46,  0,  0,
-    0, 47,  0,  0,  0,  0,  0,  0, 48,  0,  0, 49,  0, 50, 51,  0,
-    0, 52, 53, 54,  0, 55,  0, 56,  0, 57,  0,  0,  0,  0, 58, 59,
-    0,  0,  0,  0,  0,  0, 60, 61,  0,  0,  0,  0,  0,  0, 62, 63,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 64,
-    0,  0,  0, 65,  0,  0,  0, 66,  0, 67,  0,  0, 68,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 69, 70,  0,  0, 71,
-    0,  0,  0,  0,  0,  0,  0,  0, 72, 73,  0,  0,  0,  0, 53, 74,
-    0, 75, 76,  0,  0, 77, 78,  0,  0,  0,  0,  0,  0, 79, 80, 81,
-    0,  0,  0,  0,  0,  0,  0, 26,  0,  0,  0,  0,  0,  0,  0,  0,
-   82,  0,  0,  0,  0,  0,  0,  0,  0, 83,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 84,  0,  0,  0,  0,  0,  0,  0, 85,
-    0,  0,  0, 86,  0,  0,  0,  0, 87, 88,  0,  0,  0,  0,  0, 89,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0, 90,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 91,  0,  0,
-    0,  0, 92,  0, 93,  0,  0,  0,  0,  0, 72, 94,  0, 95,  0,  0,
-   96, 97,  0, 77,  0,  0, 98,  0,  0, 99,  0,  0,  0,  0,  0,100,
-    0,101, 26,102,  0,  0,  0,  0,  0,  0,103,  0,  0,  0,104,  0,
-    0,  0,  0,  0,  0, 65,105,  0,  0, 65,  0,  0,  0,106,  0,  0,
-    0,107,  0,  0,  0,  0,  0,  0,  0, 95,  0,  0,  0,  0,  0,  0,
-    0,108,109,  0,  0,  0,  0, 78,  0, 44,110,  0,111,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0, 65,  0,  0,  0,  0,  0,  0,
-    0,  0,112,  0,113,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,114,
-    0,115,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,116,  0,  0,  0,  0,117,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,118,119,120,  0,  0,  0,  0,121,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,122,123,  0,  0,  0,  0,  0,  0,
-    0,115,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,124,  0,125,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,126,  0,
-    0,  0,127,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    1,  1,  1,  1,  1,  2,  3,  4,  5,  6,  7,  4,  4,  8,  9, 10,
-    1, 11, 12, 13, 14, 15, 16, 17, 18,  1,  1,  1,  0,  0,  0,  0,
-   19,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 20, 21, 22,  1,
-   23,  4, 21, 24, 25, 26, 27, 28, 29, 30,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  1,  1, 31,  0,  0,  0, 32, 33, 34, 35,  1, 36,
-    0,  0,  0,  0, 37,  0,  0,  0,  0,  0,  0,  0,  0, 38,  1, 39,
-   14, 39, 40, 41,  0,  0,  0,  0,  0,  0,  0,  0, 42,  0,  0,  0,
-    0,  0,  0,  0, 43, 36, 44, 45, 21, 45, 46,  0,  0,  0,  0,  0,
-    0,  0, 19,  1, 21,  0,  0, 47,  0,  0,  0,  0,  0, 38, 48,  1,
-    1, 49, 49, 50,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 51,  0,
-    0,  0,  0,  0,  0,  0, 52,  1,  0,  0, 38, 14,  4,  1,  1,  1,
-   53, 21, 43, 52, 54, 21, 35,  1,  0,  0,  0,  0,  0,  0,  0, 55,
-    0,  0,  0, 56, 57, 58,  0,  0,  0,  0,  0, 56,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 59,  0,  0,  0, 56,  0, 60,  0,  0,
-    0,  0,  0,  0,  0,  0, 61, 62,  0,  0, 63,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 64,  0,  0,  0, 65,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 66,  0,  0,  0, 67,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 68,  0,  0,  0,  0,  0,  0, 69, 70,  0,
-    0,  0,  0,  0, 71, 72, 73, 74, 75, 76,  0,  0,  0,  0,  0,  0,
-    0, 77,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 78, 79,  0,
-    0,  0,  0, 47,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 49,
-    0,  0,  0,  0,  0, 80,  0,  0,  0,  0,  0,  0,  0, 62,  0,  0,
-    0,  0,  0,  0, 63,  0,  0, 81,  0,  0, 82,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 83,  0,  0,  0,  0,  0,  0, 19, 84,  0,
-   62,  0,  0,  0,  0, 49,  1, 85,  0,  0,  0,  0,  1, 52, 15, 86,
-   36, 10, 21, 87,  0,  0,  0,  0,  0,  0,  0,  0,  0, 55,  0,  0,
-    0, 62,  0,  0,  0,  0,  0,  0,  0,  0, 19, 10,  1,  0,  0,  0,
-    0,  0, 88,  0,  0,  0,  0,  0,  0, 89,  0,  0, 88,  0,  0,  0,
-    0,  0,  0,  0,  0, 78,  0,  0,  0,  0,  0,  0, 87,  9, 12,  4,
-   90,  8, 91, 47,  0, 58, 50,  0, 21,  1, 21, 92, 93,  1,  1,  1,
-    1,  1,  1,  1,  1, 94, 95, 96,  0,  0,  0,  0, 97,  1, 98, 58,
+   33, 34,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 35,  0, 36,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   37,  0,  0,  0,  0,  0,  0,  0,  0,  0, 38, 39,  0,  0,  0,  0,
+    0,  0, 40, 41, 42,  0, 43,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  1,  2,  0,  0,  0,  0,  3,  0,  0,  0,  4,  5,
+    6,  7,  0,  8,  9, 10,  0, 11, 12, 13, 14, 15, 16, 17, 16, 18,
+   16, 19, 16, 19, 16, 19,  0, 19, 16, 20, 16, 19, 21, 19,  0, 22,
+   23, 24, 25, 26, 27, 28, 29, 30, 31,  0, 32,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0, 33,  0,  0,  0,  0,  0,  0, 34,  0,  0, 35,
+    0,  0, 36,  0, 37,  0,  0,  0, 38, 39, 40, 41, 42, 43, 44, 45,
+   46,  0,  0, 47,  0,  0,  0, 48,  0,  0,  0, 49,  0,  0,  0,  0,
+    0,  0,  0, 50,  0, 51,  0, 52, 53,  0, 54,  0,  0,  0,  0,  0,
+    0, 55, 56, 57,  0,  0,  0,  0, 58,  0,  0, 59, 60, 61, 62, 63,
+    0,  0, 64, 65,  0,  0,  0, 66,  0,  0,  0,  0, 67,  0,  0,  0,
+   68,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 69,
+    0,  0,  0, 70,  0, 71,  0,  0, 72,  0,  0, 73,  0,  0,  0,  0,
+    0,  0,  0,  0, 74,  0,  0,  0,  0,  0, 75, 76,  0, 77, 78,  0,
+    0, 79, 80,  0, 81, 62,  0, 82, 83,  0,  0, 84, 85, 86,  0,  0,
+    0, 87,  0, 88,  0,  0, 51, 89, 51,  0, 90,  0, 91,  0,  0,  0,
+   80,  0,  0,  0, 92, 93,  0, 94, 95, 96, 97,  0,  0,  0,  0,  0,
+   51,  0,  0,  0,  0, 98, 99,  0,  0,  0,  0,  0,  0,100,  0,  0,
+    0,  0,  0,101,102,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,103,
+    0,  0,104,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,105,106,  0,
+    0,107,  0,  0,  0,  0,  0,  0,108,  0,109,  0,102,  0,  0,  0,
+    0,  0,110,111,  0,  0,  0,  0,  0,  0,  0,112,  0,  0,  0,  0,
+    0,  0,  0,113,  0,114,  0,  0,  0,  0,  0,  0,  1,  2,  3,  4,
+    5,  6,  7,  0,  8,  0,  0,  0,  0,  9, 10, 11, 12,  0,  0,  0,
+    0, 13,  0,  0, 14, 15,  0, 16,  0, 17, 18,  0,  0, 19,  0, 20,
+   21,  0,  0,  0,  0,  0, 22, 23,  0, 24, 25,  0,  0, 26,  0,  0,
+    0, 27,  0,  0, 28, 29, 30, 31,  0,  0,  0, 32, 33, 34,  0,  0,
+   33,  0,  0, 35, 33,  0,  0,  0, 33, 36,  0,  0,  0,  0,  0, 37,
+   38,  0,  0,  0,  0,  0,  0, 39, 40,  0,  0,  0,  0,  0,  0, 41,
+   42,  0,  0,  0,  0, 43,  0, 44,  0,  0,  0, 45, 46,  0,  0,  0,
+   47,  0,  0,  0,  0,  0,  0, 48, 49,  0,  0,  0,  0, 50,  0,  0,
+    0, 51,  0, 52,  0, 53,  0,  0,  0,  0, 54,  0,  0,  0,  0, 55,
+    0, 56,  0,  0,  0,  0, 57, 58,  0,  0,  0, 59, 60,  0,  0,  0,
+    0,  0,  0, 61, 52,  0, 62, 63,  0,  0, 64,  0,  0,  0, 65, 66,
+    0,  0,  0, 67,  0, 68, 69, 70, 71, 72,  1, 73,  0, 74, 75, 76,
+    0,  0, 77, 78,  0,  0,  0, 79,  0,  0,  1,  1,  0,  0, 80,  0,
+    0, 81,  0,  0,  0,  0, 77, 82,  0, 83,  0,  0,  0,  0,  0, 78,
+   84,  0, 85,  0, 52,  0,  1, 78,  0,  0, 86,  0,  0, 87,  0,  0,
+    0,  0,  0, 88, 57,  0,  0,  0,  0,  0,  0, 89, 90,  0,  0, 84,
+    0,  0, 33,  0,  0, 91,  0,  0,  0,  0, 92,  0,  0,  0,  0, 49,
+    0,  0, 93,  0,  0,  0,  0, 94, 95,  0,  0, 96,  0,  0, 97,  0,
+    0,  0, 98,  0,  0,  0, 99,  0,  0,  0,  0,100,101, 93,  0,  0,
+  102,  0,  0,  0, 84,  0,  0,103,  0,  0,  0,104,105,  0,  0,106,
+  107,  0,  0,  0,  0,  0,  0,108,  0,  0,109,  0,  0,  0,  0,110,
+   33,  0,111,112,113, 35,  0,  0,114,  0,  0,  0,115,  0,  0,  0,
+    0,  0,  0,116,  0,  0,117,  0,  0,  0,  0,118, 88,  0,  0,  0,
+    0,  0, 57,  0,  0,  0,  0, 52,119,  0,  0,  0,  0,120,  0,  0,
+  121,  0,  0,  0,  0,119,  0,  0,122,  0,  0,  0,  0,  0,  0,123,
+    0,  0,  0,124,  0,  0,  0,125,  0,126,  0,  0,  0,  0,127,128,
+  129,  0,130,  0,131,  0,  0,  0,132,133,134,  0, 77,  0,  0,  0,
+    0,  0, 35,  0,  0,  0,135,  0,  0,  0,136,  0,  0,137,  0,  0,
+  138,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  2,  3,  4,
+    5,  6,  7,  4,  4,  8,  9, 10,  1, 11, 12, 13, 14, 15, 16, 17,
+   18,  1,  1,  1, 19,  1,  0,  0, 20, 21, 22,  1, 23,  4, 21, 24,
+   25, 26, 27, 28, 29, 30,  0,  0,  1,  1, 31,  0,  0,  0, 32, 33,
+   34, 35,  1, 36, 37,  0,  0,  0,  0, 38,  1, 39, 14, 39, 40, 41,
+   42,  0,  0,  0, 43, 36, 44, 45, 21, 45, 46,  0,  0,  0, 19,  1,
+   21,  0,  0, 47,  0, 38, 48,  1,  1, 49, 49, 50,  0,  0, 51,  0,
+    0,  0, 52,  1,  0,  0, 38, 14,  4,  1,  1,  1, 53, 21, 43, 52,
+   54, 21, 35,  1,  0,  0,  0, 55,  0,  0,  0, 56, 57, 58,  0,  0,
+    0,  0,  0, 59,  0, 60,  0,  0,  0,  0, 61, 62,  0,  0, 63,  0,
+    0,  0, 64,  0,  0,  0, 65,  0,  0,  0, 66,  0,  0,  0, 67,  0,
+    0,  0, 68,  0,  0, 69, 70,  0, 71, 72, 73, 74, 75, 76,  0,  0,
+    0, 77,  0,  0,  0, 78, 79,  0,  0,  0,  0, 47,  0,  0,  0, 49,
+    0, 80,  0,  0,  0, 62,  0,  0, 63,  0,  0, 81,  0,  0, 82,  0,
+    0,  0, 83,  0,  0, 19, 84,  0, 62,  0,  0,  0,  0, 49,  1, 85,
+    1, 52, 15, 86, 36, 10, 21, 87,  0, 55,  0,  0,  0,  0, 19, 10,
+    1,  0,  0,  0,  0,  0, 88,  0,  0, 89,  0,  0, 88,  0,  0,  0,
+    0, 78,  0,  0, 87,  9, 12,  4, 90,  8, 91, 47,  0, 58, 50,  0,
+   21,  1, 21, 92, 93,  1,  1,  1,  1, 94, 95, 96, 97,  1, 98, 58,
    81, 99,100,  4, 58,  0,  0,  0,  0,  0,  0, 19, 50,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 61,  1,  1,  1,  1,  1,  1,  1,  1,
-    0,  0,101,102,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,103,  0,
-    0,  0,  0, 19,  0,  1,  1, 50,  0,  0,  0,  0,  0,  0,  0, 38,
-    0,  0,  0,  0, 50,  0,  0,  0,  0, 63,  0,  0,  0,  0,  0,  0,
-    0,  0,  0, 62,  0,  0,  0,  0,  1,  1,  1,  1, 50,  0,  0,  0,
-    0,  0,104, 68,  0,  0,  0,  0,  0,  0,  0,  0, 61,  0,  0,  0,
-    0,  0,  0,  0, 78,  0,  0,  0, 62,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,105,106, 58, 38, 81,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0, 63,  0,  0,  0,  0,  0,  0,  0,  0,  0,107,
-    1, 14,  4, 12,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 47,
-   84,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 38, 87,  0,
-    0,  0,  0,108,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,109, 61,
-    0,110,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,
-    0,  0, 19, 58,  0,  0,  0,  0,  0,111, 14, 52, 84,  0,  0,  0,
-  112, 41,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 62,  0,  0, 61,
-    0,  0,  0,  0,  0,  0,113,  0, 87,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0, 61, 62,  0,  0, 62,  0, 89,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,113,  0,  0,  0,  0,114,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 78, 55,  0, 38,  1, 58,  1, 58,  0,  0,
-   63, 89,  0,  0,  0,  0,  0, 59,115,  0,  0,  0,  0,  0,  0,  0,
-   55,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,115,  0,  0,
-    0,  0, 61,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 79,
-   78,  0,  0,  0,  0,  0,  0,  0,  0, 61,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 56,  0, 89, 80,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0, 61,  0,  0,  0,  0,  0,  0,  8, 91,  0,  0,
-    0,  0,  0,  0,  1, 87,  0,  0,  0,  0,  0,  0,116,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,117,  0,118,119,120,121,  0,104,  4,
-  122, 49, 23,  0,  0,  0,  0,  0,  0,  0, 38, 50,  0,  0,  0,  0,
-   38, 58,  0,  0,  0,  0,  0,  0,  1, 87,  1,  1,  1,  1, 39,  1,
-   48,105, 87,  0,  0,  0,  0,  0,  0,  0,  0, 59,  0,  0,  0,  0,
-    0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  4,122,  0,  0,
-    0,  1,123,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,230,230,230,
-  230,232,220,220,220,220,232,216,220,220,220,220,220,202,202,220,
-  220,220,220,202,202,220,220,220,  1,  1,  1,  1,  1,220,220,220,
-  220,230,230,230,230,240,230,220,220,220,230,230,230,220,220,  0,
-  230,230,230,220,220,220,220,230,232,220,220,230,233,234,234,233,
-  234,234,233,230,  0,  0,  0,230,  0,220,230,230,230,230,220,230,
-  230,230,222,220,230,230,220,220,230,222,228,230, 10, 11, 12, 13,
-   14, 15, 16, 17, 18, 19, 19, 20, 21, 22,  0, 23,  0, 24, 25,  0,
-  230,220,  0, 18, 30, 31, 32,  0,  0,  0,  0, 27, 28, 29, 30, 31,
-   32, 33, 34,230,230,220,220,230,220,230,230,220, 35,  0,  0,  0,
-    0,  0,230,230,230,  0,  0,230,230,  0,220,230,230,220,  0,  0,
-    0, 36,  0,  0,230,220,230,230,220,220,230,220,220,230,220,230,
-  220,230,230,  0,  0,220,  0,  0,230,230,  0,230,  0,230,230,230,
-  230,230,  0,  0,  0,220,220,220,230,220,220,220,230,230,  0,220,
-   27, 28, 29,230,  7,  0,  0,  0,  0,  9,  0,  0,  0,230,220,230,
-  230,  0,  0,  0,  0,  0,230,  0,  0, 84, 91,  0,  0,  0,  0,  9,
-    9,  0,  0,  0,  0,  0,  9,  0,103,103,  9,  0,107,107,107,107,
-  118,118,  9,  0,122,122,122,122,220,220,  0,  0,  0,220,  0,220,
-    0,216,  0,  0,  0,129,130,  0,132,  0,  0,  0,  0,  0,130,130,
-  130,130,  0,  0,130,  0,230,230,  9,  0,230,230,  0,  0,220,  0,
-    0,  0,  0,  7,  0,  9,  9,  0,  9,  9,  0,  0,  0,230,  0,  0,
-    0,228,  0,  0,  0,222,230,220,220,  0,  0,  0,230,  0,  0,220,
-  230,220,  0,220,230,230,230,  0,  0,  0,  9,  9,  0,  0,  7,  0,
-  230,  0,  1,  1,  1,  0,  0,  0,230,234,214,220,202,230,230,230,
-  230,230,232,228,228,220,218,230,233,220,230,220,230,230,  1,  1,
-    1,  1,  1,230,  0,  1,  1,230,220,230,  1,  1,  0,  0,218,228,
-  232,222,224,224,  0,  8,  8,  0,  0,  0,  0,220,230,  0,230,230,
-  220,  0,  0,230,  0,  0, 26,  0,  0,220,  0,230,230,  1,220,  0,
-    0,230,220,  0,  0,  0,220,220,  0,  0,230,220,  0,  9,  7,  0,
-    0,  7,  9,  0,  0,  0,  9,  7,  6,  6,  0,  0,  0,  0,  1,  0,
-    0,216,216,  1,  1,  1,  0,  0,  0,226,216,216,216,216,216,  0,
-  220,220,220,  0,230,230,  7,  0, 16, 17, 17, 17, 17, 17, 17, 33,
-   17, 17, 17, 19, 17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27,
-   28, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+    0,  0,  0, 61,  0,  0,101,102,  0,  0,103,  0,  0,  1,  1, 50,
+    0,  0,  0, 38,  0, 63,  0,  0,  0,  0,  0, 62,  0,  0,104, 68,
+   61,  0,  0,  0, 78,  0,  0,  0,105,106, 58, 38, 81,  0,  0,  0,
+    0,  0,  0,107,  1, 14,  4, 12, 84,  0,  0,  0,  0, 38, 87,  0,
+    0,  0,  0,108,  0,  0,109, 61,  0,110,  0,  0,  0,  1,  0,  0,
+    0,  0, 19, 58,  0,  0,  0, 51,  0,111, 14, 52,112, 41,  0,  0,
+   62,  0,  0, 61,  0,  0,113,  0, 87,  0,  0,  0, 61, 62,  0,  0,
+   62,  0, 89,  0,  0,113,  0,  0,  0,  0,114,  0,  0,  0, 78, 55,
+    0, 38,  1, 58,  1, 58,  0,  0, 63, 89,  0,  0,115,  0,  0,  0,
+   55,  0,  0,  0,  0,115,  0,  0,  0,  0, 61,  0,  0,  0,  0, 79,
+    0, 61,  0,  0,  0,  0, 56,  0, 89, 80,  0,  0, 79,  0,  0,  0,
+    8, 91,  0,  0,  1, 87,  0,  0,116,  0,  0,  0,  0,  0,  0,117,
+    0,118,119,120,121,  0,104,  4,122, 49, 23,  0,  0,  0, 38, 50,
+   38, 58,  0,  0,  1, 87,  1,  1,  1,  1, 39,  1, 48,105, 87,  0,
+    0,  0,  0,  1,  0,  0,  0,123,  4,122,  0,  0,  0,  1,124,  0,
+    0,  0,  0,  0,230,230,230,230,230,232,220,220,220,220,232,216,
+  220,220,220,220,220,202,202,220,220,220,220,202,202,220,220,220,
+    1,  1,  1,  1,  1,220,220,220,220,230,230,230,230,240,230,220,
+  220,220,230,230,230,220,220,  0,230,230,230,220,220,220,220,230,
+  232,220,220,230,233,234,234,233,234,234,233,230,  0,  0,  0,230,
+    0,220,230,230,230,230,220,230,230,230,222,220,230,230,220,220,
+  230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20,
+   21, 22,  0, 23,  0, 24, 25,  0,230,220,  0, 18, 30, 31, 32,  0,
+    0,  0,  0, 27, 28, 29, 30, 31, 32, 33, 34,230,230,220,220,230,
+  220,230,230,220, 35,  0,  0,  0,  0,  0,230,230,230,  0,  0,230,
+  230,  0,220,230,230,220,  0,  0,  0, 36,  0,  0,230,220,230,230,
+  220,220,230,220,220,230,220,230,220,230,230,  0,  0,220,  0,  0,
+  230,230,  0,230,  0,230,230,230,230,230,  0,  0,  0,220,220,220,
+  230,220,220,220,230,230,  0,220, 27, 28, 29,230,  7,  0,  0,  0,
+    0,  9,  0,  0,  0,230,220,230,230,  0,  0,  0,  0,  0,230,  0,
+    0, 84, 91,  0,  0,  0,  0,  9,  9,  0,  0,  0,  0,  0,  9,  0,
+  103,103,  9,  0,107,107,107,107,118,118,  9,  0,122,122,122,122,
+  220,220,  0,  0,  0,220,  0,220,  0,216,  0,  0,  0,129,130,  0,
+  132,  0,  0,  0,  0,  0,130,130,130,130,  0,  0,130,  0,230,230,
+    9,  0,230,230,  0,  0,220,  0,  0,  0,  0,  7,  0,  9,  9,  0,
+    9,  9,  0,  0,  0,230,  0,  0,  0,228,  0,  0,  0,222,230,220,
+  220,  0,  0,  0,230,  0,  0,220,230,220,  0,220,230,230,230,  0,
+    0,  0,  9,  9,  0,  0,  7,  0,230,  0,  1,  1,  1,  0,  0,  0,
+  230,234,214,220,202,230,230,230,230,230,232,228,228,220,218,230,
+  233,220,230,220,230,230,  1,  1,  1,  1,  1,230,  0,  1,  1,230,
+  220,230,  1,  1,  0,  0,218,228,232,222,224,224,  0,  8,  8,  0,
+    0,  0,  0,220,230,  0,230,230,220,  0,  0,230,  0,  0, 26,  0,
+    0,220,  0,230,230,  1,220,  0,  0,230,220,  0,  0,  0,220,220,
+    0,  0,230,220,  0,  9,  7,  0,  0,  7,  9,  0,  0,  0,  9,  7,
+    6,  6,  0,  0,  0,  0,  1,  0,  0,216,216,  1,  1,  1,  0,  0,
+    0,226,216,216,216,216,216,  0,220,220,220,  0,232,232,220,230,
+  230,230,  7,  0, 16, 17, 17, 17, 17, 17, 17, 33, 17, 17, 17, 19,
+   17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27, 28, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17, 17, 17, 17, 17,237,  0,  1,  2,  2,  0,  3,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  4,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  5,  0,  0,  0,  0,  6,  7,  8,  9,  0,  0,  0,
-   10, 11, 12, 13, 14, 15, 16, 17, 18, 19,  0,  0,  0,  0,  0,  0,
-    0,  0,  0, 20,  0,  0, 21, 22,  0,  0,  0,  0, 23, 24, 25, 26,
-    0, 27,  0, 28, 29, 30, 31, 32,  0,  0,  0,  0,  0,  0,  0, 33,
-   34, 35, 36,  0,  0,  0,  0,  0, 37,  0,  0,  0,  0,  0,  0,  0,
-    0,  0, 38, 39,  0,  0,  0,  0,  1,  2, 40, 41,  0,  1,  2,  2,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  2,
-    0,  0,  0,  0,  0,  0,  3,  4,  0,  0,  5,  0,  0,  0,  6,  0,
-    0,  0,  0,  0,  0,  0,  7,  1,  0,  0,  0,  0,  0,  0,  8,  9,
-    0,  0,  0,  0,  0,  0, 10,  0,  0, 10,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 10,  0,  0,  0, 10,  0,  0,  0,  0,
-    0,  0, 11, 12,  0, 13,  0, 14, 15, 16,  0,  0,  0,  0,  0,  1,
-   17, 18,  0, 19,  7,  1,  0,  0,  0, 20, 20,  7, 20, 20, 20, 20,
-   20, 20, 20,  8, 21,  0, 22,  0,  7, 23, 24,  0, 20, 20, 25,  0,
-    0,  0, 26, 27,  1,  7, 20, 20, 20, 20, 20,  1, 28, 29, 30, 31,
-    0,  0, 20,  0,  0,  0,  0,  0,  0,  0, 10,  0,  0,  0,  0,  0,
-    0,  0, 20, 20, 20,  1,  0,  0,  8, 21, 32,  4,  0, 10,  0, 33,
-    7, 20, 20, 20,  0,  0,  0,  0,  8, 34, 34, 35, 36, 34, 37,  0,
-   38,  1, 20, 20,  0,  0, 39,  0,  1,  1,  0,  8, 21,  1, 20,  0,
-    0,  0,  1,  0,  0, 40,  1,  1,  0,  0,  8, 21,  0,  1,  0,  1,
-    0,  1,  0,  0,  0,  0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   21,  7, 20, 41, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21,  0, 42,
-   43, 44,  0, 45,  0,  8, 21,  0,  0,  0,  0,  0,  0,  0,  0, 46,
-    7,  1, 10,  1,  0,  0,  0,  1, 20, 20,  1,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0, 26, 34,  9,  0,  0, 20, 20,  1, 20, 20,  0,
-    0,  0,  0,  0,  0,  0, 26, 21,  0,  1,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  3, 47, 48,  0,  0,  0,  0,  0,  0,  0,
-    0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  9, 10, 11, 11, 11, 11, 12, 13, 13, 13, 13, 14,
-   15, 16, 17, 18, 19, 20, 21, 13, 22, 13, 13, 13, 13, 23, 24, 24,
-   25, 26, 13, 13, 13, 27, 28, 29, 13, 30, 31, 32, 33, 34, 35, 36,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17,237,  0,  1,  2,  2,  0,  3,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  4,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    5,  0,  0,  0,  0,  6,  7,  8,  9,  0,  0,  0, 10, 11, 12, 13,
+   14, 15, 16, 17, 18, 19,  0,  0,  0,  0,  0,  0,  0,  0,  0, 20,
+    0,  0, 21, 22,  0,  0,  0,  0, 23, 24, 25, 26,  0, 27,  0, 28,
+   29, 30, 31, 32,  0,  0,  0,  0,  0,  0,  0, 33, 34, 35, 36,  0,
+    0,  0,  0,  0, 37,  0,  0,  0,  0,  0,  0,  0,  0,  0, 38, 39,
+    0,  0,  0,  0,  1,  2, 40, 41,  0,  1,  2,  2,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  2,  0,  0,  0,  0,
+    0,  0,  3,  4,  0,  0,  5,  0,  0,  0,  6,  0,  0,  0,  0,  0,
+    0,  0,  7,  1,  0,  0,  0,  0,  0,  0,  8,  9,  0,  0,  0,  0,
+    0,  0, 10,  0,  0, 10,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0, 10,  0,  0,  0, 10,  0,  0,  0,  0,  0,  0, 11, 12,
+    0, 13,  0, 14, 15, 16,  0,  0,  0,  0,  0,  1, 17, 18,  0, 19,
+    7,  1,  0,  0,  0, 20, 20,  7, 20, 20, 20, 20, 20, 20, 20,  8,
+   21,  0, 22,  0,  7, 23, 24,  0, 20, 20, 25,  0,  0,  0, 26, 27,
+    1,  7, 20, 20, 20, 20, 20,  1, 28, 29, 30, 31,  0,  0, 20,  0,
+    0,  0,  0,  0,  0,  0, 10,  0,  0,  0,  0,  0,  0,  0, 20, 20,
+   20,  1,  0,  0,  8, 21, 32,  4,  0, 10,  0, 33,  7, 20, 20, 20,
+    0,  0,  0,  0,  8, 34, 34, 35, 36, 34, 37,  0, 38,  1, 20, 20,
+    0,  0, 39,  0,  1,  1,  0,  8, 21,  1, 20,  0,  0,  0,  1,  0,
+    0, 40,  1,  1,  0,  0,  8, 21,  0,  1,  0,  1,  0,  1,  0,  0,
+    0,  0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21,  7, 20, 41,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 21,  0, 42, 43, 44,  0, 45,
+    0,  8, 21,  0,  0,  0,  0,  0,  0,  0,  0, 46,  7,  1, 10,  1,
+    0,  0,  0,  1, 20, 20,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0, 26, 34,  9,  0,  0, 20, 20,  1, 20, 20,  0,  0,  0,  0,  0,
+    0,  0, 26, 21,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  3, 47, 48,  0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,
+    4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    9, 10, 11, 11, 11, 11, 12, 13, 13, 13, 13, 14, 15, 16, 17, 18,
+   19, 20, 21, 13, 22, 13, 13, 13, 13, 23, 24, 24, 25, 26, 13, 13,
+   13, 27, 28, 29, 13, 30, 31, 32, 33, 34, 35, 36,  7,  7,  7,  7,
     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7, 37,  7, 38, 39,  7, 40,  7,  7,  7, 41, 13, 42,
-    7,  7, 43, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   37,  7, 38, 39,  7, 40,  7,  7,  7, 41, 13, 42,  7,  7, 43,  7,
+   44, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
@@ -4579,412 +1716,420 @@ _hb_ucd_u8[17936] =
    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-   44,  0,  0,  1,  2,  2,  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, 32, 33, 34, 35, 36, 37, 37, 37, 37, 37, 38,
-   39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,  2,  2,
-   53, 54, 55, 56, 57, 58, 59, 59, 59, 59, 60, 59, 59, 59, 59, 59,
-   59, 59, 61, 61, 59, 59, 59, 59, 62, 63, 64, 65, 66, 67, 68, 69,
-   70, 71, 72, 73, 74, 75, 76, 77, 78, 59, 70, 70, 70, 70, 70, 70,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 45,  0,  0,  1,
+    2,  2,  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, 32, 33, 34, 35, 36, 37, 37, 37, 37, 37, 38, 39, 40, 41, 42,
+   43, 44, 45, 46, 47, 48, 49, 50, 51, 52,  2,  2, 53, 54, 55, 56,
+   57, 58, 59, 59, 59, 59, 60, 59, 59, 59, 59, 59, 59, 59, 61, 61,
+   59, 59, 59, 59, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
+   74, 75, 76, 77, 78, 59, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
-   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 79, 70, 70,
-   70, 70, 80, 80, 80, 80, 80, 80, 80, 80, 80, 81, 82, 82, 83, 84,
-   85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 32, 32, 32, 32, 32, 32,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 79, 70, 70, 70, 70, 80, 80,
+   80, 80, 80, 80, 80, 80, 80, 81, 82, 82, 83, 84, 85, 86, 87, 88,
+   89, 90, 91, 92, 93, 94, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-   32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-   32, 95, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-   96, 96, 96, 96, 70, 70, 97, 98, 99,100,101,101,102,103,104,105,
-  106,107,108,109,110,111, 96,112,113,114,115,116,117,118,119,119,
-  120,121,122,123,124,125,126,127,128,129,130,131,132, 96,133,134,
-  135,136,137,138,139,140,141,142,143, 96,144,145, 96,146,147,148,
-  149, 96,150,151,152,153,154,155, 96, 96,156,157,158,159, 96,160,
-   96,161,162,162,162,162,162,162,162,163,164,162,165, 96, 96, 96,
-   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-   96,166,167,167,167,167,167,167,167,167,168, 96, 96, 96, 96, 96,
-   96, 96, 96, 96, 96, 96, 96, 96, 96, 96,169,169,169,169,170, 96,
-   96, 96,171,171,171,171,172,173,174,175, 96, 96, 96, 96,176,177,
-  178,179,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
-  180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
-  180,181,180,180,180,180,180,180,182,182,182,183,184, 96, 96, 96,
+   32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 95, 96, 96,
    96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-   96,185,186,187,188,189,189,190, 96, 96, 96, 96, 96, 96, 96, 96,
-   96, 96, 96, 96, 96, 96, 96, 96, 96, 96,191,192, 96, 96, 96, 96,
-   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-  193,194, 59,195,196,197,198,199,200, 96,201,202,203, 59, 59,204,
-   59,205,206,206,206,206,206,207, 96, 96, 96, 96, 96, 96, 96, 96,
-  208, 96,209, 96,210, 96, 96,211, 96, 96, 96, 96, 96, 96, 96, 96,
-   96,212,213,214,215, 96, 96, 96, 96, 96,216,217,218, 96,219,220,
-   96, 96,221,222, 59,223,224, 96, 59, 59, 59, 59, 59, 59, 59,225,
-  226,227,228,229, 59, 59,230,231, 59,232, 96, 96, 96, 96, 96, 96,
-   96, 96, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,233,
+   70, 70, 97, 98, 99,100,101,101,102,103,104,105,106,107,108,109,
+  110,111, 96,112,113,114,115,116,117,118,119,119,120,121,122,123,
+  124,125,126,127,128,129,130,131,132, 96,133,134,135,136,137,138,
+  139,140,141,142,143, 96,144,145, 96,146,147,148,149, 96,150,151,
+  152,153,154,155,156, 96,157,158,159,160, 96,161,162,163,164,164,
+  164,164,164,164,164,165,166,164,167, 96, 96, 96, 96, 96, 96, 96,
+   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,168,169,169,
+  169,169,169,169,169,169,170, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+   96, 96, 96, 96, 96, 96,171,171,171,171,172, 96, 96, 96,173,173,
+  173,173,174,175,176,177, 96, 96, 96, 96,178,179,180,181,182,182,
+  182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,
+  182,182,182,182,182,182,182,182,182,182,182,182,182,183,182,182,
+  182,182,182,182,184,184,184,185,186, 96, 96, 96, 96, 96, 96, 96,
+   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,187,188,189,
+  190,191,191,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+   96, 96, 96, 96, 96, 96,193,194, 96, 96, 96, 96, 96, 96, 96, 96,
+   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,195,196, 59,197,
+  198,199,200,201,202, 96,203,204,205, 59, 59,206, 59,207,208,208,
+  208,208,208,209, 96, 96, 96, 96, 96, 96, 96, 96,210, 96,211,212,
+  213, 96, 96,214, 96, 96, 96,215, 96, 96, 96, 96, 96,216,217,218,
+  219, 96, 96, 96, 96, 96,220,221,222, 96,223,224, 96, 96,225,226,
+   59,227,228, 96, 59, 59, 59, 59, 59, 59, 59,229,230,231,232,233,
+   59, 59,234,235, 59,236, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,237, 70, 70, 70, 70,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,238, 70,239, 70,
    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
-  234, 70,235, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
-   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,236,
-   70, 70, 70, 70, 70, 70, 70, 70, 70,237, 96, 96, 96, 96, 96, 96,
-   96, 96, 70, 70, 70, 70,238, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-   96, 96, 70, 70, 70, 70, 70, 70,239, 96, 96, 96, 96, 96, 96, 96,
-   96, 96,240, 96,241,242,  0,  1,  2,  2,  0,  1,  2,  2,  2,  3,
-    4,  5,  0,  0,  0,  0,  0,  0,  0,  0,  0, 19, 19, 19, 19, 19,
-   19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,  0,  0,  0,
-    0,  0,  0,  0, 19,  0,  0,  0,  0,  0, 19, 19, 19, 19, 19, 19,
-   19,  0, 19,  0,  0,  0,  0,  0,  0,  0, 19, 19, 19, 19, 19,  0,
-    0,  0,  0,  0, 26, 26,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,
-    1,  1,  9,  9,  9,  9,  0,  9,  9,  9,  2,  2,  9,  9,  9,  9,
-    0,  9,  2,  2,  2,  2,  9,  0,  9,  0,  9,  9,  9,  2,  9,  2,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  2,  9,  9,  9,
-    9,  9,  9,  9, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
-   55, 55,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  1,
-    1,  6,  2,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
-    4,  4,  4,  4,  4,  4,  4,  4,  4,  2,  4,  4,  4,  2,  2,  4,
-    4,  4,  2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
-   14, 14,  2,  2,  2,  2,  2,  2,  2,  2, 14, 14, 14,  2,  2,  2,
-    2, 14, 14, 14, 14, 14, 14,  2,  2,  2,  3,  3,  3,  3,  3,  0,
-    3,  3,  3,  3,  3,  3,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,
-    3,  3,  3,  3,  3,  0,  3,  3,  3,  0,  0,  3,  3,  3,  3,  3,
-    3,  3,  3,  3,  3,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
-    3,  3,  1,  3,  3,  3,  3,  3,  3,  3, 37, 37, 37, 37, 37, 37,
-   37, 37, 37, 37, 37, 37, 37, 37,  2, 37, 37, 37, 37,  2,  2, 37,
-   37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,  2,  2,  2,  2,
-    2,  2, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,  2,  2, 64,
-   64, 64, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
-    2,  2, 90, 90, 90, 90, 90, 90, 90,  2, 95, 95, 95, 95, 95, 95,
-   95, 95, 95, 95, 95, 95,  2,  2, 95,  2, 37, 37, 37,  2,  2,  2,
-    2,  2,  3,  3,  3,  3,  3,  3,  3,  2,  3,  3,  2,  2,  2,  2,
-    2,  2,  3,  3,  0,  3,  3,  3,  3,  3,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  1,  1,  1,  1,  7,  7,  7,  7,  7,  7,  7,  0,  0,
-    7,  7,  5,  5,  5,  5,  2,  5,  5,  5,  5,  5,  5,  5,  5,  2,
-    2,  5,  5,  2,  2,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
-    5,  5,  5,  2,  5,  5,  5,  5,  5,  5,  5,  2,  5,  2,  2,  2,
-    5,  5,  5,  5,  2,  2,  5,  5,  5,  5,  5,  2,  2,  5,  5,  5,
-    5,  2,  2,  2,  2,  2,  2,  2,  2,  5,  2,  2,  2,  2,  5,  5,
-    2,  5,  5,  5,  5,  5,  2,  2,  5,  5,  5,  5,  5,  5,  5,  5,
-    5,  2,  2, 11, 11, 11,  2, 11, 11, 11, 11, 11, 11,  2,  2,  2,
-    2, 11, 11,  2,  2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
-   11, 11, 11,  2, 11, 11, 11, 11, 11, 11, 11,  2, 11, 11,  2, 11,
-   11,  2, 11, 11,  2,  2, 11,  2, 11, 11, 11,  2,  2, 11, 11, 11,
-    2,  2,  2, 11,  2,  2,  2,  2,  2,  2,  2, 11, 11, 11, 11,  2,
-   11,  2,  2,  2,  2,  2,  2,  2, 11, 11, 11, 11, 11, 11, 11, 11,
-   11,  2,  2, 10, 10, 10,  2, 10, 10, 10, 10, 10, 10, 10, 10, 10,
-    2, 10, 10, 10,  2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
-   10, 10, 10,  2, 10, 10, 10, 10, 10, 10, 10,  2, 10, 10,  2, 10,
-   10, 10, 10, 10,  2,  2, 10, 10, 10, 10, 10, 10,  2, 10, 10, 10,
-    2,  2, 10,  2,  2,  2,  2,  2,  2,  2, 10, 10, 10, 10,  2,  2,
-   10, 10, 10, 10,  2,  2,  2,  2,  2,  2,  2, 10, 10, 10, 10, 10,
-   10, 10,  2, 21, 21, 21,  2, 21, 21, 21, 21, 21, 21, 21, 21,  2,
-    2, 21, 21,  2,  2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-   21, 21, 21,  2, 21, 21, 21, 21, 21, 21, 21,  2, 21, 21,  2, 21,
-   21, 21, 21, 21,  2,  2, 21, 21, 21, 21, 21,  2,  2, 21, 21, 21,
-    2,  2,  2,  2,  2,  2,  2, 21, 21, 21,  2,  2,  2,  2, 21, 21,
-    2, 21, 21, 21, 21, 21,  2,  2, 21, 21,  2,  2, 22, 22,  2, 22,
-   22, 22, 22, 22, 22,  2,  2,  2, 22, 22, 22,  2, 22, 22, 22, 22,
-    2,  2,  2, 22, 22,  2, 22,  2, 22, 22,  2,  2,  2, 22, 22,  2,
-    2,  2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,  2,  2,  2,  2,
-   22, 22, 22,  2,  2,  2,  2,  2,  2, 22,  2,  2,  2,  2,  2,  2,
-   22, 22, 22, 22, 22,  2,  2,  2,  2,  2, 23, 23, 23, 23, 23, 23,
-   23, 23, 23, 23, 23, 23, 23,  2, 23, 23, 23,  2, 23, 23, 23, 23,
-   23, 23, 23, 23,  2,  2, 23, 23, 23, 23, 23,  2, 23, 23, 23, 23,
-    2,  2,  2,  2,  2,  2,  2, 23, 23,  2, 23, 23, 23,  2,  2, 23,
-    2,  2, 23, 23, 23, 23,  2,  2, 23, 23,  2,  2,  2,  2,  2,  2,
-    2, 23, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,  2,
-   16, 16, 16,  2, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,  2, 16,
-   16, 16, 16, 16,  2,  2, 16, 16, 16, 16, 16,  2, 16, 16, 16, 16,
-    2,  2,  2,  2,  2,  2,  2, 16, 16,  2, 16, 16, 16, 16,  2,  2,
-   16, 16,  2, 16, 16,  2,  2,  2,  2,  2, 20, 20, 20, 20, 20, 20,
-   20, 20, 20, 20, 20, 20, 20,  2, 20, 20, 20,  2, 20, 20, 20, 20,
-   20, 20,  2,  2,  2,  2, 20, 20, 20, 20, 20, 20, 20, 20,  2,  2,
-   20, 20,  2, 36, 36, 36,  2, 36, 36, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 36, 36,  2,  2,  2, 36, 36, 36, 36,
-   36, 36, 36, 36,  2, 36, 36, 36, 36, 36, 36, 36, 36, 36,  2, 36,
-    2,  2,  2,  2, 36,  2,  2,  2,  2, 36, 36, 36, 36, 36, 36,  2,
-   36,  2,  2,  2,  2,  2,  2,  2, 36, 36,  2,  2, 36, 36, 36,  2,
-    2,  2,  2, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-   24, 24, 24, 24, 24,  2,  2,  2,  2,  0, 24, 24, 24, 24,  2,  2,
-    2,  2,  2, 18, 18,  2, 18,  2, 18, 18, 18, 18, 18,  2, 18, 18,
-   18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,  2, 18,
-    2, 18, 18, 18, 18, 18, 18, 18,  2,  2, 18, 18, 18, 18, 18,  2,
-   18,  2, 18, 18,  2,  2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 25,
-   25, 25,  2, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,  2,
-    2,  2, 25, 25, 25, 25, 25,  2, 25, 25, 25, 25, 25, 25, 25,  0,
-    0,  0,  0, 25, 25,  2,  2,  2,  2,  2, 33, 33, 33, 33, 33, 33,
-   33, 33,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
-    2,  8,  2,  2,  2,  2,  2,  8,  2,  2,  8,  8,  8,  0,  8,  8,
-    8,  8, 12, 12, 12, 12, 12, 12, 12, 12, 30, 30, 30, 30, 30, 30,
-   30, 30, 30,  2, 30, 30, 30, 30,  2,  2, 30, 30, 30, 30, 30, 30,
-   30,  2, 30, 30, 30,  2,  2, 30, 30, 30, 30, 30, 30, 30, 30,  2,
-    2,  2, 30, 30,  2,  2,  2,  2,  2,  2, 29, 29, 29, 29, 29, 29,
-   29, 29, 29, 29, 29, 29, 29, 29,  2,  2, 28, 28, 28, 28, 28, 28,
-   28, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,  2,
-    2,  2, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,  0,  0,  0,
-   35, 35, 35,  2,  2,  2,  2,  2,  2,  2, 45, 45, 45, 45, 45, 45,
-   45, 45, 45, 45, 45, 45, 45, 45,  2,  2,  2,  2,  2,  2,  2,  2,
-    2, 45, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,  0,
-    0,  2, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,  2,  2,
-    2,  2, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,  2,
-   46, 46, 46,  2, 46, 46,  2,  2,  2,  2, 31, 31, 31, 31, 31, 31,
-   31, 31, 31, 31, 31, 31, 31, 31,  2,  2, 31, 31,  2,  2,  2,  2,
-    2,  2, 32, 32,  0,  0, 32,  0, 32, 32, 32, 32, 32, 32, 32, 32,
-   32, 32, 32, 32,  2,  2,  2,  2,  2,  2, 32,  2,  2,  2,  2,  2,
-    2,  2, 32, 32, 32,  2,  2,  2,  2,  2, 28, 28, 28, 28, 28, 28,
-    2,  2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
-   48,  2, 48, 48, 48, 48,  2,  2,  2,  2, 48,  2,  2,  2, 48, 48,
-   48, 48, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-    2,  2, 52, 52, 52, 52, 52,  2,  2,  2, 58, 58, 58, 58, 58, 58,
-   58, 58, 58, 58, 58, 58,  2,  2,  2,  2, 58, 58,  2,  2,  2,  2,
-    2,  2, 58, 58, 58,  2,  2,  2, 58, 58, 54, 54, 54, 54, 54, 54,
-   54, 54, 54, 54, 54, 54,  2,  2, 54, 54, 91, 91, 91, 91, 91, 91,
-   91, 91, 91, 91, 91, 91, 91, 91, 91,  2, 91, 91, 91, 91, 91,  2,
-    2, 91, 91, 91,  2,  2,  2,  2,  2,  2, 91, 91, 91, 91, 91, 91,
-    2,  2,  1,  1,  1,  1,  1,  1,  1,  2, 62, 62, 62, 62, 62, 62,
-   62, 62, 62, 62, 62, 62, 62,  2,  2,  2, 62, 62, 62, 62, 62, 62,
-   62,  2, 76, 76, 76, 76, 76, 76, 76, 76, 93, 93, 93, 93, 93, 93,
-   93, 93, 93, 93, 93, 93,  2,  2,  2,  2,  2,  2,  2,  2, 93, 93,
-   93, 93, 70, 70, 70, 70, 70, 70, 70, 70,  2,  2,  2, 70, 70, 70,
-   70, 70, 70, 70,  2,  2,  2, 70, 70, 70, 73, 73, 73, 73, 73, 73,
-   73, 73,  6,  2,  2,  2,  2,  2,  2,  2,  8,  8,  8,  2,  2,  8,
-    8,  8,  1,  1,  1,  0,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,
-    1,  1,  1,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  1,  0,
-    0,  0,  1,  1,  0,  2,  2,  2,  2,  2, 19, 19, 19, 19, 19, 19,
-    9,  9,  9,  9,  9,  6, 19, 19, 19, 19, 19, 19, 19, 19, 19,  9,
-    9,  9,  9,  9, 19, 19, 19, 19,  9,  9,  9,  9,  9, 19, 19, 19,
-   19, 19,  6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-   19,  9,  9,  9,  9,  9,  9,  9,  2,  2,  2,  9,  2,  9,  2,  9,
-    2,  9,  9,  9,  9,  9,  9,  2,  9,  9,  9,  9,  9,  9,  2,  2,
-    9,  9,  9,  9,  9,  9,  2,  9,  9,  9,  2,  2,  9,  9,  9,  2,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  2,  0,  0,  0,  0,  1,  1,
-    0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0, 19,  2,  2,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0, 19,  0,  0,  0,  0,  0,  0,
-    0,  2, 19, 19, 19, 19, 19,  2,  2,  2,  0,  2,  2,  2,  2,  2,
-    2,  2,  1,  2,  2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,
-    9,  0,  0,  0, 19, 19,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-   19,  0, 19,  0,  0,  0,  2,  2,  2,  2,  0,  0,  0,  2,  2,  2,
-    2,  2, 27, 27, 27, 27, 27, 27, 27, 27,  0,  0,  0,  0,  2,  2,
-    0,  0,  0,  0,  0,  0,  0,  0,  2,  0, 56, 56, 56, 56, 56, 56,
-   56, 56, 55, 55, 55, 55,  2,  2,  2,  2,  2, 55, 55, 55, 55, 55,
-   55, 55, 61, 61, 61, 61, 61, 61, 61, 61,  2,  2,  2,  2,  2,  2,
-    2, 61, 61,  2,  2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,
-    2,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2, 13, 13, 13,
-   13, 13, 13, 13, 13, 13,  2,  2,  2,  2, 13, 13, 13, 13, 13, 13,
-    2,  2,  0,  0,  0,  0,  2,  2,  2,  2,  0,  0,  0,  0,  0, 13,
-    0, 13,  0, 13, 13, 13, 13, 13, 13, 13, 13, 13,  1,  1,  1,  1,
-   12, 12, 13, 13, 13, 13,  0,  0,  0,  0,  2, 15, 15, 15, 15, 15,
-   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
-   15,  2,  2,  1,  1,  0,  0, 15, 15, 15,  0, 17, 17, 17, 17, 17,
-   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,  0,  0, 17,
-   17, 17,  2,  2,  2,  2,  2, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26,  2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12,  2, 12, 12, 12, 12, 12, 12, 12,  0, 17, 17, 17, 17, 17, 17,
-   17,  0, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,  2,
-    2,  2, 39, 39, 39, 39, 39, 39, 39,  2, 86, 86, 86, 86, 86, 86,
-   86, 86, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,  2,  2,
-    2,  2, 79, 79, 79, 79, 79, 79, 79, 79,  0,  0, 19, 19, 19, 19,
-   19, 19,  0,  0,  0, 19, 19, 19, 19, 19, 19, 19, 19,  2,  2,  2,
-    2,  2, 19, 19,  2, 19,  2, 19, 19, 19, 19, 19,  2,  2,  2,  2,
-    2,  2,  2,  2, 19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 60,
-   60, 60, 60, 60, 60, 60, 60,  2,  2,  2,  0,  0,  2,  2,  2,  2,
-    2,  2, 65, 65, 65, 65, 65, 65, 65, 65, 75, 75, 75, 75, 75, 75,
-   75, 75, 75, 75, 75, 75, 75, 75,  2,  2,  2,  2,  2,  2,  2,  2,
-   75, 75, 75, 75,  2,  2,  2,  2,  2,  2, 69, 69, 69, 69, 69, 69,
-   69, 69, 69, 69, 69, 69, 69, 69,  0, 69, 74, 74, 74, 74, 74, 74,
-   74, 74, 74, 74, 74, 74,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2, 74, 12, 12, 12, 12, 12,  2,  2,  2, 84, 84, 84, 84, 84, 84,
-   84, 84, 84, 84, 84, 84, 84, 84,  2,  0, 84, 84,  2,  2,  2,  2,
-   84, 84, 33, 33, 33, 33, 33, 33, 33,  2, 68, 68, 68, 68, 68, 68,
-   68, 68, 68, 68, 68, 68, 68, 68, 68,  2, 68, 68, 68, 68, 68, 68,
-    2,  2, 68, 68,  2,  2, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92,
-   92, 92, 92, 92, 92,  2,  2,  2,  2,  2,  2,  2,  2, 92, 92, 92,
-   92, 92, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
-   87,  2,  2, 30, 30, 30, 30, 30, 30,  2, 19, 19, 19,  0, 19, 19,
-   19, 19, 19, 19, 19, 19, 19,  9, 19, 19, 19, 19,  0,  0,  2,  2,
-    2,  2, 87, 87, 87, 87, 87, 87,  2,  2, 87, 87,  2,  2,  2,  2,
-    2,  2, 12, 12, 12, 12,  2,  2,  2,  2,  2,  2,  2, 12, 12, 12,
-   12, 12, 13, 13,  2,  2,  2,  2,  2,  2, 19, 19, 19, 19, 19, 19,
-   19,  2,  2,  2,  2,  4,  4,  4,  4,  4,  2,  2,  2,  2,  2, 14,
-   14, 14, 14, 14, 14, 14, 14, 14, 14,  2, 14, 14, 14, 14, 14,  2,
-   14,  2, 14, 14,  2, 14, 14,  2, 14, 14,  3,  3,  3,  2,  2,  2,
-    2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
-    0,  0,  2,  2,  3,  3,  3,  3,  3,  3,  2,  2,  2,  2,  2,  2,
-    2,  3,  1,  1,  1,  1,  1,  1,  6,  6,  0,  0,  0,  2,  0,  0,
-    0,  0,  3,  3,  3,  3,  3,  2,  3,  3,  3,  3,  3,  3,  3,  2,
-    2,  0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-   17, 17, 17, 17, 17, 17, 17, 17,  0,  0,  2,  2, 12, 12, 12, 12,
-   12, 12,  2,  2, 12, 12, 12,  2,  2,  2,  2,  0,  0,  0,  0,  0,
-    2,  2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,  2, 49,
-   49, 49, 49, 49, 49, 49, 49, 49, 49,  2, 49, 49, 49,  2, 49, 49,
-    2, 49, 49, 49, 49, 49, 49, 49,  2,  2, 49, 49, 49,  2,  2,  2,
-    2,  2,  0,  0,  0,  2,  2,  2,  2,  0,  0,  0,  0,  0,  2,  2,
-    2,  0,  0,  0,  0,  0,  0,  2,  2,  2,  9,  2,  2,  2,  2,  2,
-    2,  2,  0,  0,  0,  0,  0,  1,  2,  2, 71, 71, 71, 71, 71, 71,
-   71, 71, 71, 71, 71, 71, 71,  2,  2,  2, 67, 67, 67, 67, 67, 67,
-   67, 67, 67,  2,  2,  2,  2,  2,  2,  2,  1,  0,  0,  0,  0,  0,
-    0,  0, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,  2,  2,
-    2,  2,  2,  2,  2,  2,  2, 42, 42, 42, 41, 41, 41, 41, 41, 41,
-   41, 41, 41, 41, 41,  2,  2,  2,  2,  2,118,118,118,118,118,118,
-  118,118,118,118,118,  2,  2,  2,  2,  2, 53, 53, 53, 53, 53, 53,
-   53, 53, 53, 53, 53, 53, 53, 53,  2, 53, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59,  2,  2,  2,  2, 59, 59, 59, 59, 59, 59,
-    2,  2, 40, 40, 40, 40, 40, 40, 40, 40, 51, 51, 51, 51, 51, 51,
-   51, 51, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-    2,  2, 50, 50,  2,  2,  2,  2,  2,  2,135,135,135,135,135,135,
-  135,135,135,135,135,135,  2,  2,  2,  2,106,106,106,106,106,106,
-  106,106,104,104,104,104,104,104,104,104,104,104,104,104,  2,  2,
-    2,  2,  2,  2,  2,  2,  2,  2,  2,104,161,161,161,161,161,161,
-  161,161,161,161,161,  2,161,161,161,161,161,161,161,  2,161,161,
-    2,161,161,161,  2,161,161,161,161,161,161,161,  2,161,161,  2,
-    2,  2,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
-  110,  2,110,110,110,110,110,110,  2,  2, 19, 19, 19, 19, 19, 19,
-    2, 19, 19,  2, 19, 19, 19, 19, 19, 19, 47, 47, 47, 47, 47, 47,
-    2,  2, 47,  2, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
-   47, 47, 47, 47, 47, 47, 47, 47,  2, 47, 47,  2,  2,  2, 47,  2,
-    2, 47, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
-    2, 81,120,120,120,120,120,120,120,120,116,116,116,116,116,116,
-  116,116,116,116,116,116,116,116,116,  2,  2,  2,  2,  2,  2,  2,
-    2,116,128,128,128,128,128,128,128,128,128,128,128,  2,128,128,
-    2,  2,  2,  2,  2,128,128,128,128,128, 66, 66, 66, 66, 66, 66,
-   66, 66, 66, 66, 66, 66,  2,  2,  2, 66, 72, 72, 72, 72, 72, 72,
-   72, 72, 72, 72,  2,  2,  2,  2,  2, 72, 98, 98, 98, 98, 98, 98,
-   98, 98, 97, 97, 97, 97, 97, 97, 97, 97,  2,  2,  2,  2, 97, 97,
-   97, 97,  2,  2, 97, 97, 97, 97, 97, 97, 57, 57, 57, 57,  2, 57,
-   57,  2,  2,  2,  2,  2, 57, 57, 57, 57, 57, 57, 57, 57,  2, 57,
-   57, 57,  2, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-   57, 57, 57, 57, 57, 57, 57, 57,  2,  2, 57, 57, 57,  2,  2,  2,
-    2, 57, 57,  2,  2,  2,  2,  2,  2,  2, 88, 88, 88, 88, 88, 88,
-   88, 88,117,117,117,117,117,117,117,117,112,112,112,112,112,112,
-  112,112,112,112,112,112,112,112,112,  2,  2,  2,  2,112,112,112,
-  112,112, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
-    2,  2,  2, 78, 78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83,
-   83, 83, 83, 83, 83, 83, 83, 83,  2,  2, 82, 82, 82, 82, 82, 82,
-   82, 82, 82, 82, 82,  2,  2,  2,  2,  2,122,122,122,122,122,122,
-  122,122,122,122,  2,  2,  2,  2,  2,  2,  2,122,122,122,122,  2,
-    2,  2,  2,122,122,122,122,122,122,122, 89, 89, 89, 89, 89, 89,
-   89, 89, 89,  2,  2,  2,  2,  2,  2,  2,130,130,130,130,130,130,
-  130,130,130,130,130,  2,  2,  2,  2,  2,  2,  2,130,130,130,130,
-  130,130,144,144,144,144,144,144,144,144,144,144,  2,  2,  2,  2,
-    2,  2,156,156,156,156,156,156,156,156,156,156,  2,156,156,156,
-    2,  2,156,156,  2,  2,  2,  2,  2,  2,147,147,147,147,147,147,
-  147,147,148,148,148,148,148,148,148,148,148,148,  2,  2,  2,  2,
-    2,  2,158,158,158,158,158,158,158,158,158,158,  2,  2,  2,  2,
-    2,  2,153,153,153,153,153,153,153,153,153,153,153,153,  2,  2,
-    2,  2,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
-  149,  2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
-    2,  2,  2,  2, 94, 94, 94, 94, 94, 94,  2,  2,  2,  2,  2,  2,
-    2, 94, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  2, 85,  2,  2,101,101,101,101,101,101,
-  101,101,101,  2,  2,  2,  2,  2,  2,  2,101,101,  2,  2,  2,  2,
-    2,  2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,  2,
-   96, 96,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
-  111,  2,100,100,100,100,100,100,100,100,  2, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36,  2,  2,  2,108,108,108,108,108,108,
-  108,108,108,108,  2,108,108,108,108,108,108,108,108,108,108,108,
-  108,  2,129,129,129,129,129,129,129,  2,129,  2,129,129,129,129,
-    2,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
-    2,129,129,129,  2,  2,  2,  2,  2,  2,109,109,109,109,109,109,
-  109,109,109,109,109,  2,  2,  2,  2,  2,109,109,  2,  2,  2,  2,
-    2,  2,107,107,107,107,  2,107,107,107,107,107,107,107,107,  2,
-    2,107,107,  2,  2,107,107,107,107,107,107,107,107,107,107,107,
-  107,107,107,  2,107,107,107,107,107,107,107,  2,107,107,  2,107,
-  107,107,107,107,  2,  1,107,107,107,107,107,  2,  2,107,107,107,
-    2,  2,107,  2,  2,  2,  2,  2,  2,107,  2,  2,  2,  2,  2,107,
-  107,107,107,107,107,107,  2,  2,107,107,107,107,107,107,107,  2,
-    2,  2,137,137,137,137,137,137,137,137,137,137,137,137,  2,137,
-  137,137,137,137,  2,  2,  2,  2,  2,  2,124,124,124,124,124,124,
-  124,124,124,124,  2,  2,  2,  2,  2,  2,123,123,123,123,123,123,
-  123,123,123,123,123,123,123,123,  2,  2,114,114,114,114,114,114,
-  114,114,114,114,114,114,114,  2,  2,  2,114,114,  2,  2,  2,  2,
-    2,  2, 32, 32, 32, 32, 32,  2,  2,  2,102,102,102,102,102,102,
-  102,102,102,102,  2,  2,  2,  2,  2,  2,126,126,126,126,126,126,
-  126,126,126,126,126,  2,  2,126,126,126,126,126,126,126,  2,  2,
-    2,  2,126,126,126,126,126,126,126,  2,142,142,142,142,142,142,
-  142,142,142,142,142,142,  2,  2,  2,  2,125,125,125,125,125,125,
-  125,125,125,125,125,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,125,154,154,154,154,154,154,154,  2,  2,154,  2,  2,154,154,
-  154,154,154,154,154,154,  2,154,154,  2,154,154,154,154,154,154,
-  154,154,154,154,154,154,154,154,  2,154,154,  2,  2,154,154,154,
-  154,154,154,154,  2,  2,  2,  2,  2,  2,150,150,150,150,150,150,
-  150,150,  2,  2,150,150,150,150,150,150,150,150,150,150,150,  2,
-    2,  2,141,141,141,141,141,141,141,141,140,140,140,140,140,140,
-  140,140,140,140,140,  2,  2,  2,  2,  2,121,121,121,121,121,121,
-  121,121,121,  2,  2,  2,  2,  2,  2,  2,133,133,133,133,133,133,
-  133,133,133,  2,133,133,133,133,133,133,133,133,133,133,133,133,
-  133,  2,133,133,133,133,133,133,  2,  2,133,133,133,133,133,  2,
-    2,  2,134,134,134,134,134,134,134,134,  2,  2,134,134,134,134,
-  134,134,  2,134,134,134,134,134,134,134,134,134,134,134,134,134,
-  134,  2,138,138,138,138,138,138,138,  2,138,138,  2,138,138,138,
-  138,138,138,138,138,138,138,138,138,138,  2,  2,138,  2,138,138,
-    2,138,138,138,  2,  2,  2,  2,  2,  2,143,143,143,143,143,143,
-    2,143,143,  2,143,143,143,143,143,143,143,143,143,143,143,143,
-  143,143,143,143,143,143,143,143,143,  2,143,143,  2,143,143,143,
-  143,143,143,  2,  2,  2,  2,  2,  2,  2,143,143,  2,  2,  2,  2,
-    2,  2,145,145,145,145,145,145,145,145,145,  2,  2,  2,  2,  2,
-    2,  2, 86,  2,  2,  2,  2,  2,  2,  2, 22, 22,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  2,  2,  2, 22, 63, 63, 63, 63, 63, 63,
-   63, 63, 63, 63,  2,  2,  2,  2,  2,  2, 63, 63, 63, 63, 63, 63,
-   63,  2, 63, 63, 63, 63, 63,  2,  2,  2, 63, 63, 63, 63,  2,  2,
-    2,  2,157,157,157,157,157,157,157,157,157,157,157,  2,  2,  2,
-    2,  2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
-   80,  2, 80,  2,  2,  2,  2,  2,  2,  2,127,127,127,127,127,127,
-  127,127,127,127,127,127,127,127,127,  2, 79,  2,  2,  2,  2,  2,
-    2,  2,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
-  115,  2,115,115,  2,  2,  2,  2,115,115,159,159,159,159,159,159,
-  159,159,159,159,159,159,159,159,159,  2,159,159,  2,  2,  2,  2,
-    2,  2,103,103,103,103,103,103,103,103,103,103,103,103,103,103,
-    2,  2,119,119,119,119,119,119,119,119,119,119,119,119,119,119,
-    2,  2,119,119,  2,119,119,119,119,119,  2,  2,  2,  2,  2,119,
-  119,119,146,146,146,146,146,146,146,146,146,146,146,  2,  2,  2,
-    2,  2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,  2,  2,  2,
-    2, 99,  2,  2,  2,  2,  2,  2,  2, 99,136,139, 13, 13,155,  2,
-    2,  2,136,136,136,136,136,136,136,136,155,155,155,155,155,155,
-  155,155,155,155,155,155,155,155,  2,  2,136,  2,  2,  2,  2,  2,
-    2,  2, 17, 17, 17, 17,  2, 17, 17, 17, 17, 17, 17, 17,  2, 17,
-   17,  2, 17, 15, 15, 15, 15, 15, 15, 15, 17, 17, 17,  2,  2,  2,
-    2,  2, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,  2,  2, 17, 17,
-   17, 17,139,139,139,139,139,139,139,139,139,139,139,139,  2,  2,
-    2,  2,105,105,105,105,105,105,105,105,105,105,105,  2,  2,  2,
-    2,  2,105,105,105,105,105,  2,  2,  2,105,  2,  2,  2,  2,  2,
-    2,  2,105,105,  2,  2,105,105,105,105,  1,  1,  1,  1,  1,  1,
-    2,  2,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,
-    1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,
-    0,  0,  2,  2,  0,  2,  2,  0,  0,  2,  2,  0,  0,  0,  0,  2,
-    0,  0,  0,  0,  2,  0,  2,  0,  0,  0,  0,  0,  0,  0,  2,  0,
-    0,  0,  0,  0,  0,  2,  2,  0,  0,  0,  0,  0,  2,  0,  0,  0,
-    0,  2,  0,  0,  0,  0,  0,  2,  0,  2,  2,  2,  0,  0,  0,  0,
-    0,  0,  0,  2,  0,  0,  0,  0,  0,  0,131,131,131,131,131,131,
-  131,131,131,131,131,131,  2,  2,  2,  2,  2,  2,  2,131,131,131,
-  131,131,  2,131,131,131,131,131,131,131, 56, 56, 56, 56, 56, 56,
-   56,  2, 56,  2,  2, 56, 56, 56, 56, 56, 56, 56,  2, 56, 56,  2,
-   56, 56, 56, 56, 56,  2,  2,  2,  2,  2,151,151,151,151,151,151,
-  151,151,151,151,151,151,151,  2,  2,  2,151,151,151,151,151,151,
-    2,  2,151,151,  2,  2,  2,  2,151,151,160,160,160,160,160,160,
-  160,160,160,160,160,160,160,160,160,  2,152,152,152,152,152,152,
-  152,152,152,152,  2,  2,  2,  2,  2,152, 30, 30, 30, 30,  2, 30,
-   30,  2,113,113,113,113,113,113,113,113,113,113,113,113,113,  2,
-    2,113,113,113,113,113,113,113,113,  2,132,132,132,132,132,132,
-  132,132,132,132,132,132,  2,  2,  2,  2,132,132,  2,  2,  2,  2,
-  132,132,  3,  3,  3,  3,  2,  3,  3,  3,  2,  3,  3,  2,  3,  2,
-    2,  3,  2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  2,  3,  3,
-    3,  3,  2,  3,  2,  3,  2,  2,  2,  2,  2,  2,  3,  2,  2,  2,
-    2,  3,  2,  3,  2,  3,  2,  3,  3,  3,  2,  3,  2,  3,  2,  3,
-    2,  3,  2,  3,  3,  3,  3,  2,  3,  2,  3,  3,  2,  3,  3,  3,
-    3,  3,  3,  3,  3,  3,  2,  2,  2,  2,  2,  3,  3,  3,  2,  3,
-    3,  3,  2,  2,  2,  2,  2,  2,  0,  0, 15,  0,  0,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  2,  0,  0,  0, 13,  2,  2,  2,  2,  2,
-    2,  2, 13, 13, 13,  2,  2,  2,  2,  2,  2,  0,  2,  2,  2,  2,
-    2,  2,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  9,  9,  9, 10,
-    9, 11, 12, 13,  9,  9,  9, 14,  9,  9, 15,  9,  9,  9,  9,  9,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,240, 70, 70, 70, 70,
+   70, 70, 70, 70, 70,241, 70, 70, 70, 70,242, 96, 96, 96, 70, 70,
+   70, 70,243, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
+   70, 70, 70, 70,244, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 70, 70, 70, 70,245, 96, 96, 96, 96, 96, 96, 96, 96,246, 96,
+  247,248,  0,  1,  2,  2,  0,  1,  2,  2,  2,  3,  4,  5,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+   19, 19, 19, 19, 19, 19, 19, 19, 19,  0,  0,  0,  0,  0,  0,  0,
+   19,  0,  0,  0,  0,  0, 19, 19, 19, 19, 19, 19, 19,  0, 19,  0,
+    0,  0,  0,  0,  0,  0, 19, 19, 19, 19, 19,  0,  0,  0,  0,  0,
+   26, 26,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  9,  9,
+    9,  9,  0,  9,  9,  9,  2,  2,  9,  9,  9,  9,  0,  9,  2,  2,
+    2,  2,  9,  0,  9,  0,  9,  9,  9,  2,  9,  2,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  2,  9,  9,  9,  9,  9,  9,  9,
+   55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,  6,  6,
+    6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  1,  1,  6,  2,  4,
+    4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+    4,  4,  4,  4,  4,  2,  4,  4,  4,  2,  2,  4,  4,  4,  2, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,  2,  2,
+    2,  2,  2,  2,  2,  2, 14, 14, 14,  2,  2,  2,  2, 14, 14, 14,
+   14, 14, 14,  2,  2,  2,  3,  3,  3,  3,  3,  0,  3,  3,  3,  3,
+    3,  3,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  0,  3,  3,  3,  0,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  3,  3,  1,  3,
+    3,  3,  3,  3,  3,  3, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+   37, 37, 37, 37,  2, 37, 37, 37, 37,  2,  2, 37, 37, 37, 38, 38,
+   38, 38, 38, 38, 38, 38, 38, 38,  2,  2,  2,  2,  2,  2, 64, 64,
+   64, 64, 64, 64, 64, 64, 64, 64, 64,  2,  2, 64, 64, 64, 90, 90,
+   90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,  2,  2, 90, 90,
+   90, 90, 90, 90, 90,  2, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+   95, 95,  2,  2, 95,  2, 37, 37, 37,  2,  2,  2,  2,  2,  3,  3,
+    3,  3,  3,  3,  3,  2,  3,  3,  2,  2,  2,  2,  2,  2,  3,  3,
+    0,  3,  3,  3,  3,  3,  7,  7,  7,  7,  7,  7,  7,  7,  7,  1,
+    1,  1,  1,  7,  7,  7,  7,  7,  7,  7,  0,  0,  7,  7,  5,  5,
+    5,  5,  2,  5,  5,  5,  5,  5,  5,  5,  5,  2,  2,  5,  5,  2,
+    2,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,
+    5,  5,  5,  5,  5,  5,  5,  2,  5,  2,  2,  2,  5,  5,  5,  5,
+    2,  2,  5,  5,  5,  5,  5,  2,  2,  5,  5,  5,  5,  2,  2,  2,
+    2,  2,  2,  2,  2,  5,  2,  2,  2,  2,  5,  5,  2,  5,  5,  5,
+    5,  5,  2,  2,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,  2, 11,
+   11, 11,  2, 11, 11, 11, 11, 11, 11,  2,  2,  2,  2, 11, 11,  2,
+    2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,  2,
+   11, 11, 11, 11, 11, 11, 11,  2, 11, 11,  2, 11, 11,  2, 11, 11,
+    2,  2, 11,  2, 11, 11, 11,  2,  2, 11, 11, 11,  2,  2,  2, 11,
+    2,  2,  2,  2,  2,  2,  2, 11, 11, 11, 11,  2, 11,  2,  2,  2,
+    2,  2,  2,  2, 11, 11, 11, 11, 11, 11, 11, 11, 11,  2,  2, 10,
+   10, 10,  2, 10, 10, 10, 10, 10, 10, 10, 10, 10,  2, 10, 10, 10,
+    2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,  2,
+   10, 10, 10, 10, 10, 10, 10,  2, 10, 10,  2, 10, 10, 10, 10, 10,
+    2,  2, 10, 10, 10, 10, 10, 10,  2, 10, 10, 10,  2,  2, 10,  2,
+    2,  2,  2,  2,  2,  2, 10, 10, 10, 10,  2,  2, 10, 10, 10, 10,
+    2,  2,  2,  2,  2,  2,  2, 10, 10, 10, 10, 10, 10, 10,  2, 21,
+   21, 21,  2, 21, 21, 21, 21, 21, 21, 21, 21,  2,  2, 21, 21,  2,
+    2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,
+   21, 21, 21, 21, 21, 21, 21,  2, 21, 21,  2, 21, 21, 21, 21, 21,
+    2,  2, 21, 21, 21, 21, 21,  2,  2, 21, 21, 21,  2,  2,  2,  2,
+    2,  2,  2, 21, 21, 21,  2,  2,  2,  2, 21, 21,  2, 21, 21, 21,
+   21, 21,  2,  2, 21, 21,  2,  2, 22, 22,  2, 22, 22, 22, 22, 22,
+   22,  2,  2,  2, 22, 22, 22,  2, 22, 22, 22, 22,  2,  2,  2, 22,
+   22,  2, 22,  2, 22, 22,  2,  2,  2, 22, 22,  2,  2,  2, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22,  2,  2,  2,  2, 22, 22, 22,  2,
+    2,  2,  2,  2,  2, 22,  2,  2,  2,  2,  2,  2, 22, 22, 22, 22,
+   22,  2,  2,  2,  2,  2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+   23, 23, 23,  2, 23, 23, 23,  2, 23, 23, 23, 23, 23, 23, 23, 23,
+    2,  2, 23, 23, 23, 23, 23,  2, 23, 23, 23, 23,  2,  2,  2,  2,
+    2,  2,  2, 23, 23,  2, 23, 23, 23,  2,  2, 23,  2,  2, 23, 23,
+   23, 23,  2,  2, 23, 23,  2,  2,  2,  2,  2,  2,  2, 23, 16, 16,
+   16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,  2, 16, 16, 16,  2,
+   16, 16, 16, 16, 16, 16, 16, 16, 16, 16,  2, 16, 16, 16, 16, 16,
+    2,  2, 16, 16, 16, 16, 16,  2, 16, 16, 16, 16,  2,  2,  2,  2,
+    2,  2,  2, 16, 16,  2, 16, 16, 16, 16,  2,  2, 16, 16,  2, 16,
+   16, 16,  2,  2,  2,  2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+   20, 20, 20,  2, 20, 20, 20,  2, 20, 20, 20, 20, 20, 20,  2,  2,
+    2,  2, 20, 20, 20, 20, 20, 20, 20, 20,  2,  2, 20, 20,  2, 36,
+   36, 36,  2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36,  2,  2,  2, 36, 36, 36, 36, 36, 36, 36, 36,
+    2, 36, 36, 36, 36, 36, 36, 36, 36, 36,  2, 36,  2,  2,  2,  2,
+   36,  2,  2,  2,  2, 36, 36, 36, 36, 36, 36,  2, 36,  2,  2,  2,
+    2,  2,  2,  2, 36, 36,  2,  2, 36, 36, 36,  2,  2,  2,  2, 24,
+   24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+   24,  2,  2,  2,  2,  0, 24, 24, 24, 24,  2,  2,  2,  2,  2, 18,
+   18,  2, 18,  2, 18, 18, 18, 18, 18,  2, 18, 18, 18, 18, 18, 18,
+   18, 18, 18, 18, 18, 18, 18, 18, 18, 18,  2, 18,  2, 18, 18, 18,
+   18, 18, 18, 18,  2,  2, 18, 18, 18, 18, 18,  2, 18,  2, 18, 18,
+   18, 18, 18, 18, 18,  2, 18, 18,  2,  2, 18, 18, 18, 18, 25, 25,
+   25, 25, 25, 25, 25, 25,  2, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25,  2,  2,  2, 25, 25, 25, 25, 25,  2, 25, 25, 25, 25,
+   25, 25, 25,  0,  0,  0,  0, 25, 25,  2,  2,  2,  2,  2, 33, 33,
+   33, 33, 33, 33, 33, 33,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
+    8,  8,  8,  8,  2,  8,  2,  2,  2,  2,  2,  8,  2,  2,  8,  8,
+    8,  0,  8,  8,  8,  8, 12, 12, 12, 12, 12, 12, 12, 12, 30, 30,
+   30, 30, 30, 30, 30, 30, 30,  2, 30, 30, 30, 30,  2,  2, 30, 30,
+   30, 30, 30, 30, 30,  2, 30, 30, 30,  2,  2, 30, 30, 30, 30, 30,
+   30, 30, 30,  2,  2,  2, 30, 30,  2,  2,  2,  2,  2,  2, 29, 29,
+   29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,  2,  2, 28, 28,
+   28, 28, 28, 28, 28, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34,  2,  2,  2, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35,  0,  0,  0, 35, 35, 35,  2,  2,  2,  2,  2,  2,  2, 45, 45,
+   45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,  2,  2,  2,  2,
+    2,  2,  2,  2,  2, 45, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+   44, 44, 44,  0,  0,  2, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+   43, 43,  2,  2,  2,  2, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+   46, 46, 46,  2, 46, 46, 46,  2, 46, 46,  2,  2,  2,  2, 31, 31,
+   31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,  2,  2, 31, 31,
+    2,  2,  2,  2,  2,  2, 32, 32,  0,  0, 32,  0, 32, 32, 32, 32,
+   32, 32, 32, 32, 32, 32, 32, 32,  2,  2,  2,  2,  2,  2, 32,  2,
+    2,  2,  2,  2,  2,  2, 32, 32, 32,  2,  2,  2,  2,  2, 28, 28,
+   28, 28, 28, 28,  2,  2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
+   48, 48, 48, 48, 48,  2, 48, 48, 48, 48,  2,  2,  2,  2, 48,  2,
+    2,  2, 48, 48, 48, 48, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+   52, 52, 52, 52,  2,  2, 52, 52, 52, 52, 52,  2,  2,  2, 58, 58,
+   58, 58, 58, 58, 58, 58, 58, 58, 58, 58,  2,  2,  2,  2, 58, 58,
+    2,  2,  2,  2,  2,  2, 58, 58, 58,  2,  2,  2, 58, 58, 54, 54,
+   54, 54, 54, 54, 54, 54, 54, 54, 54, 54,  2,  2, 54, 54, 91, 91,
+   91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,  2, 91, 91,
+   91, 91, 91,  2,  2, 91, 91, 91,  2,  2,  2,  2,  2,  2, 91, 91,
+   91, 91, 91, 91,  2,  2,  1,  1,  1,  1,  1,  1,  1,  2, 62, 62,
+   62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,  2,  2,  2, 62, 62,
+   62, 62, 62, 62, 62,  2, 76, 76, 76, 76, 76, 76, 76, 76, 93, 93,
+   93, 93, 93, 93, 93, 93, 93, 93, 93, 93,  2,  2,  2,  2,  2,  2,
+    2,  2, 93, 93, 93, 93, 70, 70, 70, 70, 70, 70, 70, 70,  2,  2,
+    2, 70, 70, 70, 70, 70, 70, 70,  2,  2,  2, 70, 70, 70, 73, 73,
+   73, 73, 73, 73, 73, 73,  6,  2,  2,  2,  2,  2,  2,  2,  8,  8,
+    8,  2,  2,  8,  8,  8,  1,  1,  1,  0,  1,  1,  1,  1,  1,  0,
+    1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  1,  0,  0,  0,  0,
+    0,  0,  1,  0,  0,  0,  1,  1,  0,  2,  2,  2,  2,  2, 19, 19,
+   19, 19, 19, 19,  9,  9,  9,  9,  9,  6, 19, 19, 19, 19, 19, 19,
+   19, 19, 19,  9,  9,  9,  9,  9, 19, 19, 19, 19,  9,  9,  9,  9,
+    9, 19, 19, 19, 19, 19,  6, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+   19, 19, 19, 19, 19,  9,  9,  9,  9,  9,  9,  9,  2,  2,  2,  9,
+    2,  9,  2,  9,  2,  9,  9,  9,  9,  9,  9,  2,  9,  9,  9,  9,
+    9,  9,  2,  2,  9,  9,  9,  9,  9,  9,  2,  9,  9,  9,  2,  2,
+    9,  9,  9,  2,  9,  9,  9,  9,  9,  9,  9,  9,  9,  2,  0,  0,
+    0,  0,  1,  1,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0, 19,
+    2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 19,  0,  0,
+    0,  0,  0,  0,  0,  2, 19, 19, 19, 19, 19,  2,  2,  2,  0,  2,
+    2,  2,  2,  2,  2,  2,  1,  2,  2,  2,  2,  2,  2,  2,  0,  0,
+    0,  0,  0,  0,  9,  0,  0,  0, 19, 19,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 19,  0, 19,  0,  0,  0,  2,  2,  2,  2,  0,  0,
+    0,  2,  2,  2,  2,  2, 27, 27, 27, 27, 27, 27, 27, 27,  0,  0,
+    0,  0,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  2,  0, 56, 56,
+   56, 56, 56, 56, 56, 56, 55, 55, 55, 55,  2,  2,  2,  2,  2, 55,
+   55, 55, 55, 55, 55, 55, 61, 61, 61, 61, 61, 61, 61, 61,  2,  2,
+    2,  2,  2,  2,  2, 61, 61,  2,  2,  2,  2,  2,  2,  2,  0,  0,
+    0,  0,  0,  0,  2,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    2, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  2, 13, 13,
+   13, 13, 13, 13,  2,  2,  0,  0,  0,  0,  0, 13,  0, 13,  0, 13,
+   13, 13, 13, 13, 13, 13, 13, 13,  1,  1,  1,  1, 12, 12, 13, 13,
+   13, 13,  0,  0,  0,  0,  2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,  1,
+    1,  0,  0, 15, 15, 15,  0, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17,  0,  0, 17, 17, 17,  2,  2,
+    2,  2,  2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  2,  0,  0,
+    0,  0,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  0, 12, 12,
+   12, 12, 12, 12, 12,  0, 17, 17, 17, 17, 17, 17, 17,  0, 39, 39,
+   39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,  2,  2,  2, 39, 39,
+   39, 39, 39, 39, 39,  2, 86, 86, 86, 86, 86, 86, 86, 86, 77, 77,
+   77, 77, 77, 77, 77, 77, 77, 77, 77, 77,  2,  2,  2,  2, 79, 79,
+   79, 79, 79, 79, 79, 79,  0,  0, 19, 19, 19, 19, 19, 19,  0,  0,
+    0, 19, 19, 19, 19, 19, 19, 19, 19,  2,  2,  2,  2,  2, 19, 19,
+    2, 19,  2, 19, 19, 19, 19, 19,  2,  2,  2,  2,  2,  2,  2,  2,
+   19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+   60, 60, 60,  2,  2,  2,  0,  0,  2,  2,  2,  2,  2,  2, 65, 65,
+   65, 65, 65, 65, 65, 65, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+   75, 75, 75, 75,  2,  2,  2,  2,  2,  2,  2,  2, 75, 75, 75, 75,
+    2,  2,  2,  2,  2,  2, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
+   69, 69, 69, 69,  0, 69, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+   74, 74,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 74, 12, 12,
+   12, 12, 12,  2,  2,  2, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+   84, 84, 84, 84,  2,  0, 84, 84,  2,  2,  2,  2, 84, 84, 33, 33,
+   33, 33, 33, 33, 33,  2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+   68, 68, 68, 68, 68,  2, 68, 68, 68, 68, 68, 68,  2,  2, 68, 68,
+    2,  2, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
+   92,  2,  2,  2,  2,  2,  2,  2,  2, 92, 92, 92, 92, 92, 87, 87,
+   87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,  2,  2, 30,
+   30, 30, 30, 30, 30,  2, 19, 19, 19,  0, 19, 19, 19, 19, 19, 19,
+   19, 19, 19,  9, 19, 19, 19, 19,  0,  0,  2,  2,  2,  2, 87, 87,
+   87, 87, 87, 87,  2,  2, 87, 87,  2,  2,  2,  2,  2,  2, 12, 12,
+   12, 12,  2,  2,  2,  2,  2,  2,  2, 12, 12, 12, 12, 12, 13, 13,
+    2,  2,  2,  2,  2,  2, 19, 19, 19, 19, 19, 19, 19,  2,  2,  2,
+    2,  4,  4,  4,  4,  4,  2,  2,  2,  2,  2, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14,  2, 14, 14, 14, 14, 14,  2, 14,  2, 14, 14,
+    2, 14, 14,  2, 14, 14,  3,  3,  3,  2,  2,  2,  2,  2,  2,  2,
+    2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  0,  2,  2,
+    3,  3,  3,  3,  3,  3,  2,  2,  2,  2,  2,  2,  2,  3,  1,  1,
+    1,  1,  1,  1,  6,  6,  0,  0,  0,  2,  0,  0,  0,  0,  3,  3,
+    3,  3,  3,  2,  3,  3,  3,  3,  3,  3,  3,  2,  2,  0,  2,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 17, 17, 17, 17,
+   17, 17, 17, 17,  0,  0,  2,  2, 12, 12, 12, 12, 12, 12,  2,  2,
+   12, 12, 12,  2,  2,  2,  2,  0,  0,  0,  0,  0,  2,  2, 49, 49,
+   49, 49, 49, 49, 49, 49, 49, 49, 49, 49,  2, 49, 49, 49, 49, 49,
+   49, 49, 49, 49, 49,  2, 49, 49, 49,  2, 49, 49,  2, 49, 49, 49,
+   49, 49, 49, 49,  2,  2, 49, 49, 49,  2,  2,  2,  2,  2,  0,  0,
+    0,  2,  2,  2,  2,  0,  0,  0,  0,  0,  2,  2,  2,  0,  0,  0,
+    0,  0,  0,  2,  2,  2,  9,  2,  2,  2,  2,  2,  2,  2,  0,  0,
+    0,  0,  0,  1,  2,  2, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
+   71, 71, 71,  2,  2,  2, 67, 67, 67, 67, 67, 67, 67, 67, 67,  2,
+    2,  2,  2,  2,  2,  2,  1,  0,  0,  0,  0,  0,  0,  0, 42, 42,
+   42, 42, 42, 42, 42, 42, 42, 42, 42, 42,  2,  2,  2,  2,  2,  2,
+    2,  2,  2, 42, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+   41,  2,  2,  2,  2,  2,118,118,118,118,118,118,118,118,118,118,
+  118,  2,  2,  2,  2,  2, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+   53, 53, 53, 53,  2, 53, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59,  2,  2,  2,  2, 59, 59, 59, 59, 59, 59,  2,  2, 40, 40,
+   40, 40, 40, 40, 40, 40, 51, 51, 51, 51, 51, 51, 51, 51, 50, 50,
+   50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,  2,  2, 50, 50,
+    2,  2,  2,  2,  2,  2,135,135,135,135,135,135,135,135,135,135,
+  135,135,  2,  2,  2,  2,106,106,106,106,106,106,106,106,104,104,
+  104,104,104,104,104,104,104,104,104,104,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,104,161,161,161,161,161,161,161,161,161,161,
+  161,  2,161,161,161,161,161,161,161,  2,161,161,  2,161,161,161,
+    2,161,161,161,161,161,161,161,  2,161,161,  2,  2,  2,110,110,
+  110,110,110,110,110,110,110,110,110,110,110,110,110,  2,110,110,
+  110,110,110,110,  2,  2, 19, 19, 19, 19, 19, 19,  2, 19, 19,  2,
+   19, 19, 19, 19, 19, 19, 47, 47, 47, 47, 47, 47,  2,  2, 47,  2,
+   47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+   47, 47, 47, 47,  2, 47, 47,  2,  2,  2, 47,  2,  2, 47, 81, 81,
+   81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,  2, 81,120,120,
+  120,120,120,120,120,120,116,116,116,116,116,116,116,116,116,116,
+  116,116,116,116,116,  2,  2,  2,  2,  2,  2,  2,  2,116,128,128,
+  128,128,128,128,128,128,128,128,128,  2,128,128,  2,  2,  2,  2,
+    2,128,128,128,128,128, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+   66, 66,  2,  2,  2, 66, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+    2,  2,  2,  2,  2, 72, 98, 98, 98, 98, 98, 98, 98, 98, 97, 97,
+   97, 97, 97, 97, 97, 97,  2,  2,  2,  2, 97, 97, 97, 97,  2,  2,
+   97, 97, 97, 97, 97, 97, 57, 57, 57, 57,  2, 57, 57,  2,  2,  2,
+    2,  2, 57, 57, 57, 57, 57, 57, 57, 57,  2, 57, 57, 57,  2, 57,
+   57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+   57, 57, 57, 57,  2,  2, 57, 57, 57,  2,  2,  2,  2, 57, 57,  2,
+    2,  2,  2,  2,  2,  2, 88, 88, 88, 88, 88, 88, 88, 88,117,117,
+  117,117,117,117,117,117,112,112,112,112,112,112,112,112,112,112,
+  112,112,112,112,112,  2,  2,  2,  2,112,112,112,112,112, 78, 78,
+   78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,  2,  2,  2, 78,
+   78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,
+   83, 83, 83, 83,  2,  2, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
+   82,  2,  2,  2,  2,  2,122,122,122,122,122,122,122,122,122,122,
+    2,  2,  2,  2,  2,  2,  2,122,122,122,122,  2,  2,  2,  2,122,
+  122,122,122,122,122,122, 89, 89, 89, 89, 89, 89, 89, 89, 89,  2,
+    2,  2,  2,  2,  2,  2,130,130,130,130,130,130,130,130,130,130,
+  130,  2,  2,  2,  2,  2,  2,  2,130,130,130,130,130,130,144,144,
+  144,144,144,144,144,144,144,144,  2,  2,  2,  2,  2,  2,156,156,
+  156,156,156,156,156,156,156,156,  2,156,156,156,  2,  2,156,156,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,147,147,
+  147,147,147,147,147,147,148,148,148,148,148,148,148,148,148,148,
+    2,  2,  2,  2,  2,  2,158,158,158,158,158,158,158,158,158,158,
+    2,  2,  2,  2,  2,  2,153,153,153,153,153,153,153,153,153,153,
+  153,153,  2,  2,  2,  2,149,149,149,149,149,149,149,149,149,149,
+  149,149,149,149,149,  2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+   94, 94, 94, 94,  2,  2,  2,  2, 94, 94, 94, 94, 94, 94,  2,  2,
+    2,  2,  2,  2,  2, 94, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+   85,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 85,  2,  2,101,101,
+  101,101,101,101,101,101,101,  2,  2,  2,  2,  2,  2,  2,101,101,
+    2,  2,  2,  2,  2,  2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+   96, 96, 96,  2, 96, 96,111,111,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,  2,100,100,100,100,100,100,100,100,  2, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  2,  2,  2,108,108,
+  108,108,108,108,108,108,108,108,  2,108,108,108,108,108,108,108,
+    2,  2,  2,  2,  2,  2,129,129,129,129,129,129,129,  2,129,  2,
+  129,129,129,129,  2,129,129,129,129,129,129,129,129,129,129,129,
+  129,129,129,129,  2,129,129,129,  2,  2,  2,  2,  2,  2,109,109,
+  109,109,109,109,109,109,109,109,109,  2,  2,  2,  2,  2,109,109,
+    2,  2,  2,  2,  2,  2,107,107,107,107,  2,107,107,107,107,107,
+  107,107,107,  2,  2,107,107,  2,  2,107,107,107,107,107,107,107,
+  107,107,107,107,107,107,107,  2,107,107,107,107,107,107,107,  2,
+  107,107,  2,107,107,107,107,107,  2,  1,107,107,107,107,107,  2,
+    2,107,107,107,  2,  2,107,  2,  2,  2,  2,  2,  2,107,  2,  2,
+    2,  2,  2,107,107,107,107,107,107,107,  2,  2,107,107,107,107,
+  107,107,107,  2,  2,  2,137,137,137,137,137,137,137,137,137,137,
+  137,137,  2,137,137,137,137,137,  2,  2,  2,  2,  2,  2,124,124,
+  124,124,124,124,124,124,124,124,  2,  2,  2,  2,  2,  2,123,123,
+  123,123,123,123,123,123,123,123,123,123,123,123,  2,  2,114,114,
+  114,114,114,114,114,114,114,114,114,114,114,  2,  2,  2,114,114,
+    2,  2,  2,  2,  2,  2, 32, 32, 32, 32, 32,  2,  2,  2,102,102,
+  102,102,102,102,102,102,102,102,  2,  2,  2,  2,  2,  2,126,126,
+  126,126,126,126,126,126,126,126,126,  2,  2,126,126,126,126,126,
+  126,126,  2,  2,  2,  2,126,126,126,126,126,126,126,  2,142,142,
+  142,142,142,142,142,142,142,142,142,142,  2,  2,  2,  2,125,125,
+  125,125,125,125,125,125,125,125,125,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,125,154,154,154,154,154,154,154,  2,  2,154,
+    2,  2,154,154,154,154,154,154,154,154,  2,154,154,  2,154,154,
+  154,154,154,154,154,154,154,154,154,154,154,154,  2,154,154,  2,
+    2,154,154,154,154,154,154,154,  2,  2,  2,  2,  2,  2,150,150,
+  150,150,150,150,150,150,  2,  2,150,150,150,150,150,150,150,150,
+  150,150,150,  2,  2,  2,141,141,141,141,141,141,141,141,140,140,
+  140,140,140,140,140,140,140,140,140,  2,  2,  2,  2,  2,121,121,
+  121,121,121,121,121,121,121,  2,  2,  2,  2,  2,  2,  2,  7,  7,
+    2,  2,  2,  2,  2,  2,133,133,133,133,133,133,133,133,133,  2,
+  133,133,133,133,133,133,133,133,133,133,133,133,133,  2,133,133,
+  133,133,133,133,  2,  2,133,133,133,133,133,  2,  2,  2,134,134,
+  134,134,134,134,134,134,  2,  2,134,134,134,134,134,134,  2,134,
+  134,134,134,134,134,134,134,134,134,134,134,134,134,  2,138,138,
+  138,138,138,138,138,  2,138,138,  2,138,138,138,138,138,138,138,
+  138,138,138,138,138,138,  2,  2,138,  2,138,138,  2,138,138,138,
+    2,  2,  2,  2,  2,  2,143,143,143,143,143,143,  2,143,143,  2,
+  143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
+  143,143,143,143,143,  2,143,143,  2,143,143,143,143,143,143,  2,
+    2,  2,  2,  2,  2,  2,143,143,  2,  2,  2,  2,  2,  2,145,145,
+  145,145,145,145,145,145,145,  2,  2,  2,  2,  2,  2,  2,163,163,
+  163,163,163,163,163,163,163,  2,163,163,163,163,163,163,163,163,
+  163,  2,  2,  2,163,163,163,163,  2,  2,  2,  2,  2,  2, 86,  2,
+    2,  2,  2,  2,  2,  2, 22, 22,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2, 22, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+    2,  2,  2,  2,  2,  2, 63, 63, 63, 63, 63, 63, 63,  2, 63, 63,
+   63, 63, 63,  2,  2,  2, 63, 63, 63, 63,  2,  2,  2,  2,157,157,
+  157,157,157,157,157,157,157,157,157,  2,  2,  2,  2,  2, 80, 80,
+   80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,  2,  2,127,127,
+  127,127,127,127,127,127,127,127,127,127,127,127,127,  2, 79,  2,
+    2,  2,  2,  2,  2,  2,115,115,115,115,115,115,115,115,115,115,
+  115,115,115,115,115,  2,115,115,  2,  2,  2,  2,115,115,159,159,
+  159,159,159,159,159,159,159,159,159,159,159,159,159,  2,159,159,
+    2,  2,  2,  2,  2,  2,103,103,103,103,103,103,103,103,103,103,
+  103,103,103,103,  2,  2,119,119,119,119,119,119,119,119,119,119,
+  119,119,119,119,  2,  2,119,119,  2,119,119,119,119,119,  2,  2,
+    2,  2,  2,119,119,119,146,146,146,146,146,146,146,146,146,146,
+  146,  2,  2,  2,  2,  2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+   99,  2,  2,  2,  2, 99,  2,  2,  2,  2,  2,  2,  2, 99,136,139,
+   13, 13,155,  2,  2,  2,136,136,136,136,136,136,136,136,155,155,
+  155,155,155,155,155,155,155,155,155,155,155,155,  2,  2,136,  2,
+    2,  2,  2,  2,  2,  2, 17, 17, 17, 17,  2, 17, 17, 17, 17, 17,
+   17, 17,  2, 17, 17,  2, 17, 15, 15, 15, 15, 15, 15, 15, 17, 17,
+   17,  2,  2,  2,  2,  2,  2,  2, 15,  2,  2,  2,  2,  2, 15, 15,
+   15,  2,  2, 17,  2,  2,  2,  2,  2,  2, 17, 17, 17, 17,139,139,
+  139,139,139,139,139,139,139,139,139,139,  2,  2,  2,  2,105,105,
+  105,105,105,105,105,105,105,105,105,  2,  2,  2,  2,  2,105,105,
+  105,105,105,  2,  2,  2,105,  2,  2,  2,  2,  2,  2,  2,105,105,
+    2,  2,105,105,105,105,  1,  1,  1,  1,  1,  1,  2,  2,  0,  0,
+    0,  0,  0,  0,  0,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  1,  1,  1,
+    1,  1,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  0,  0,  2,  2,
+    0,  2,  2,  0,  0,  2,  2,  0,  0,  0,  0,  2,  0,  0,  0,  0,
+    2,  0,  2,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,  0,  0,
+    0,  2,  2,  0,  0,  0,  0,  0,  2,  0,  0,  0,  0,  2,  0,  0,
+    0,  0,  0,  2,  0,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  2,
+    0,  0,  0,  0,  0,  0,131,131,131,131,131,131,131,131,131,131,
+  131,131,  2,  2,  2,  2,  2,  2,  2,131,131,131,131,131,  2,131,
+  131,131,131,131,131,131,  2,  2,  2,  2,  2, 19, 19, 19, 56, 56,
+   56, 56, 56, 56, 56,  2, 56,  2,  2, 56, 56, 56, 56, 56, 56, 56,
+    2, 56, 56,  2, 56, 56, 56, 56, 56,  2,  2,  2,  2,  2,  6,  6,
+    6,  6,  6,  6,  2,  2,  2,  2,  2,  2,  2,  2,  2,  6,151,151,
+  151,151,151,151,151,151,151,151,151,151,151,  2,  2,  2,151,151,
+  151,151,151,151,  2,  2,151,151,  2,  2,  2,  2,151,151,160,160,
+  160,160,160,160,160,160,160,160,160,160,160,160,160,  2,152,152,
+  152,152,152,152,152,152,152,152,  2,  2,  2,  2,  2,152,164,164,
+  164,164,164,164,164,164,164,164,  2,  2,  2,  2,  2,  2, 30, 30,
+   30, 30,  2, 30, 30,  2,113,113,113,113,113,113,113,113,113,113,
+  113,113,113,  2,  2,113,113,113,113,113,113,113,113,  2,132,132,
+  132,132,132,132,132,132,132,132,132,132,  2,  2,  2,  2,132,132,
+    2,  2,  2,  2,132,132,  3,  3,  3,  3,  2,  3,  3,  3,  2,  3,
+    3,  2,  3,  2,  2,  3,  2,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  2,  3,  3,  3,  3,  2,  3,  2,  3,  2,  2,  2,  2,  2,  2,
+    3,  2,  2,  2,  2,  3,  2,  3,  2,  3,  2,  3,  3,  3,  2,  3,
+    2,  3,  2,  3,  2,  3,  2,  3,  3,  3,  3,  2,  3,  2,  3,  3,
+    2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  2,  2,  2,  2,  2,  3,
+    3,  3,  2,  3,  3,  3,  2,  2,  2,  2,  2,  2,  0,  0, 15,  0,
+    0,  2,  2,  2,  2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  2,  2,
+    2,  0,  0,  0,  0,  0, 13,  2,  2,  2,  2,  2,  2,  2, 13, 13,
+   13,  2,  2,  2,  2,  2,  2,  0,  2,  2,  2,  2,  2,  2,  0,  1,
+    2,  3,  4,  5,  6,  7,  8,  9,  9,  9,  9, 10,  9, 11, 12, 13,
+    9,  9,  9, 14,  9,  9, 15,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 16, 17,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 18, 19, 20,  9, 21,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 16, 17,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9, 18, 19, 20,  9, 21,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 22,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9, 22,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
@@ -4993,60 +2138,60 @@ _hb_ucd_u8[17936] =
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 23, 24,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  4,
-    5,  6,  7,  8,  9, 10, 11, 12,  0,  0, 13, 14, 15, 16, 17, 18,
-   19, 20, 21, 22,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0, 23,  0,  0, 24, 25, 26, 27, 28, 29, 30,  0,  0,
-   31, 32,  0, 33,  0, 34,  0, 35,  0,  0,  0,  0, 36, 37, 38, 39,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 23, 24,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  8,
+    9, 10, 11, 12,  0,  0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0, 40,  0,  0,  0,  0,  0,  0,  0,  0,  0, 41, 42,  0,  0,
+   23,  0,  0, 24, 25, 26, 27, 28, 29, 30,  0,  0, 31, 32,  0, 33,
+    0, 34,  0, 35,  0,  0,  0,  0, 36, 37, 38, 39,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 40,  0,
+    0,  0,  0,  0,  0,  0,  0,  0, 41, 42,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 43, 44,
+    0, 45,  0,  0,  0,  0,  0,  0, 46, 47,  0,  0,  0,  0,  0, 48,
+    0, 49,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   50, 51,  0,  0,  0, 52,  0,  0, 53,  0,  0,  0,  0,  0,  0,  0,
+   54,  0,  0,  0,  0,  0,  0,  0, 55,  0,  0,  0,  0,  0,  0,  0,
+   56,  0,  0,  0,  0,  0,  0,  0,  0, 57,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0, 43, 44,  0, 45,  0,  0,  0,  0,  0,  0, 46, 47,  0,  0,
-    0,  0,  0, 48,  0, 49,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0, 50, 51,  0,  0,  0, 52,  0,  0, 53,  0,  0,  0,
-    0,  0,  0,  0, 54,  0,  0,  0,  0,  0,  0,  0, 55,  0,  0,  0,
-    0,  0,  0,  0, 56,  0,  0,  0,  0,  0,  0,  0,  0, 57,  0,  0,
+   58, 59, 60, 61, 62, 63, 64, 65,  0,  0,  0,  0,  0,  0, 66,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0, 58, 59, 60, 61, 62, 63, 64, 65,  0,  0,  0,  0,
-    0,  0, 66,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 67, 68,  0, 69,
+   70,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 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,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,104,  0,
+    0,  0,  0,  0,  0,105,106,  0,107,  0,  0,  0,108,  0,109,  0,
+  110,  0,111,112,113,  0,114,  0,  0,  0,115,  0,  0,  0,116,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-   67, 68,  0, 69, 70,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-   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,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,104,  0,  0,  0,  0,  0,  0,105,106,  0,107,  0,  0,  0,
-  108,  0,109,  0,110,  0,111,112,113,  0,114,  0,  0,  0,115,  0,
-    0,  0,116,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,117,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,117,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,118,119,120,121,  0,122,123,124,125,126,  0,127,
+  118,119,120,121,  0,122,123,124,125,126,  0,127,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,128,129,130,131,
+  132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,
+  148,149,150,151,152,153,154,155,156,157,  0,  0,  0,158,159,160,
+  161,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,162,163,  0,  0,  0,  0,  0,  0,  0,164,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-  128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
-  144,145,146,147,148,149,150,151,152,153,154,155,156,157,  0,  0,
-    0,158,159,160,161,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,162,163,  0,  0,  0,  0,  0,
-    0,  0,164,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,165,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,166,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,167,  0,  0,  0,  0,
+  165,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,166,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,167,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,168,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,168,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,169,170,  0,  0,  0,  0,171,172,  0,  0,  0,
-  173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,
-  189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,
-  205,206,  0,  0,  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,
+    0,169,170,  0,  0,  0,  0,171,172,  0,  0,  0,173,174,175,176,
+  177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,
+  193,194,195,196,197,198,199,200,201,202,203,204,205,206,  0,  0,
+    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,
 };
 static const uint16_t
-_hb_ucd_u16[9200] =
+_hb_ucd_u16[9344] =
 {
      0,   0,   1,   2,   3,   4,   5,   6,   0,   0,   7,   8,   9,  10,  11,  12,
     13,  13,  13,  14,  15,  13,  13,  16,  17,  18,  19,  20,  21,  22,  13,  23,
@@ -5089,9 +2234,9 @@ _hb_ucd_u16[9200] =
    209, 306, 209, 209, 209, 209, 209, 209,   9,   9,   9,  11,  11,  11, 307, 308,
     13,  13,  13,  13,  13,  13, 309, 310,  11,  11, 311,  48,  48,  48, 312, 313,
     48, 314, 315, 315, 315, 315,  32,  32, 316, 317, 318, 319, 320, 321, 140, 140,
-   209, 322, 209, 209, 209, 209, 209, 323, 209, 209, 209, 209, 209, 324, 140, 325,
-   326, 327, 328, 329, 136,  48,  48,  48,  48, 330, 178,  48,  48,  48,  48, 331,
-   332,  48,  48, 136,  48,  48,  48,  48, 200, 333,  48,  48, 209, 209, 323,  48,
+   209, 322, 209, 209, 209, 209, 209, 323, 209, 209, 209, 209, 209, 324, 140, 209,
+   325, 326, 327, 328, 136,  48,  48,  48,  48, 329, 178,  48,  48,  48,  48, 330,
+   331,  48,  48, 136,  48,  48,  48,  48, 200, 332,  48,  48, 209, 209, 333,  48,
    209, 334, 335, 209, 336, 337, 209, 209, 335, 209, 209, 337, 209, 209, 209, 209,
     48,  48,  48,  48, 209, 209, 209, 209,  48, 338,  48,  48,  48,  48,  48,  48,
    151, 209, 209, 209, 287,  48,  48, 229, 339,  48, 340, 140,  13,  13, 341, 342,
@@ -5120,59 +2265,62 @@ _hb_ucd_u16[9200] =
     48,  48,  48, 468,  48, 469,  48, 470,  48, 471, 472, 140, 140, 140, 140, 140,
     48,  48,  48,  48, 196, 140, 140, 140,   9,   9,   9, 473,  11,  11,  11, 474,
     48,  48, 475, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 271, 476,
-    48,  48, 477, 478, 140, 140, 140, 140,  48, 464, 479,  48,  62, 480, 140,  48,
-   481, 140, 140,  48, 482, 140,  48, 314, 483,  48,  48, 484, 485, 457, 486, 487,
-   222,  48,  48, 488, 489,  48, 196, 192, 490,  48, 491, 492, 493,  48,  48, 494,
-   222,  48,  48, 495, 496, 497, 498, 499,  48,  97, 500, 501, 140, 140, 140, 140,
-   502, 503, 504,  48,  48, 505, 506, 192, 507,  83,  84, 508, 509, 510, 511, 512,
-    48,  48,  48, 513, 514, 515, 478, 140,  48,  48,  48, 516, 517, 192, 140, 140,
-    48,  48, 518, 519, 520, 521, 140, 140,  48,  48,  48, 522, 523, 192, 524, 140,
-    48,  48, 525, 526, 192, 140, 140, 140,  48, 173, 527, 528, 314, 140, 140, 140,
-    48,  48, 500, 529, 140, 140, 140, 140, 140, 140,   9,   9,  11,  11, 148, 530,
-   531, 532,  48, 533, 534, 192, 140, 140, 140, 140, 535,  48,  48, 536, 537, 140,
-   538,  48,  48, 539, 540, 541,  48,  48, 542, 543, 544,  48,  48,  48,  48, 196,
-    84,  48, 518, 545, 546, 148, 175, 547,  48, 548, 549, 550, 140, 140, 140, 140,
-   551,  48,  48, 552, 553, 192, 554,  48, 555, 556, 192, 140, 140, 140, 140, 140,
-   140, 140, 140, 140, 140, 140,  48, 557, 140, 140, 140, 100, 271, 558, 559, 560,
-    48, 207, 140, 140, 140, 140, 140, 140, 272, 272, 272, 272, 272, 272, 561, 562,
-    48,  48,  48,  48, 388, 140, 140, 140, 140,  48,  48,  48,  48,  48,  48, 563,
-    48,  48, 200, 564, 140, 140, 140, 140,  48,  48,  48,  48, 314, 140, 140, 140,
-    48,  48,  48, 196,  48, 200, 370,  48,  48,  48,  48, 200, 192,  48, 204, 565,
-    48,  48,  48, 566, 567, 568, 569, 570,  48, 140, 140, 140, 140, 140, 140, 140,
-   140, 140, 140, 140,   9,   9,  11,  11, 271, 571, 140, 140, 140, 140, 140, 140,
-    48,  48,  48,  48, 572, 573, 574, 574, 575, 576, 140, 140, 140, 140, 577, 578,
+    48,  48, 477, 478, 140, 140, 140, 479,  48, 464, 480,  48,  62, 481, 140,  48,
+   482, 140, 140,  48, 483, 140,  48, 314, 484,  48,  48, 485, 486, 457, 487, 488,
+   222,  48,  48, 489, 490,  48, 196, 192, 491,  48, 492, 493, 494,  48,  48, 495,
+   222,  48,  48, 496, 497, 498, 499, 500,  48,  97, 501, 502, 503, 140, 140, 140,
+   504, 505, 506,  48,  48, 507, 508, 192, 509,  83,  84, 510, 511, 512, 513, 514,
+    48,  48,  48, 515, 516, 517, 478, 140,  48,  48,  48, 518, 519, 192, 140, 140,
+    48,  48, 520, 521, 522, 523, 140, 140,  48,  48,  48, 524, 525, 192, 526, 140,
+    48,  48, 527, 528, 192, 140, 140, 140,  48, 173, 529, 530, 314, 140, 140, 140,
+    48,  48, 501, 531, 140, 140, 140, 140, 140, 140,   9,   9,  11,  11, 148, 532,
+   533, 534,  48, 535, 536, 192, 140, 140, 140, 140, 537,  48,  48, 538, 539, 140,
+   540,  48,  48, 541, 542, 543,  48,  48, 544, 545, 546,  48,  48,  48,  48, 196,
+   547, 140, 140, 140, 140, 140, 140, 140,  84,  48, 520, 548, 549, 148, 175, 550,
+    48, 551, 552, 553, 140, 140, 140, 140, 554,  48,  48, 555, 556, 192, 557,  48,
+   558, 559, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 560,
+   561, 115,  48, 562, 563, 192, 140, 140, 140, 140, 140, 100, 271, 564, 565, 566,
+    48, 207, 140, 140, 140, 140, 140, 140, 272, 272, 272, 272, 272, 272, 567, 568,
+    48,  48,  48,  48, 388, 140, 140, 140, 140,  48,  48,  48,  48,  48,  48, 569,
+    48,  48,  48, 570, 571, 572, 140, 140,  48,  48,  48,  48, 314, 140, 140, 140,
+    48,  48,  48, 196,  48, 200, 370,  48,  48,  48,  48, 200, 192,  48, 204, 573,
+    48,  48,  48, 574, 575, 576, 577, 578,  48, 140, 140, 140, 140, 140, 140, 140,
+   140, 140, 140, 140,   9,   9,  11,  11, 271, 579, 140, 140, 140, 140, 140, 140,
+    48,  48,  48,  48, 580, 581, 582, 582, 583, 584, 140, 140, 140, 140, 585, 586,
     48,  48,  48,  48,  48,  48,  48, 440,  48,  48,  48,  48,  48, 199, 140, 140,
-   196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 579,
-    48,  48, 580, 140, 140, 580, 581,  48,  48,  48,  48,  48,  48,  48,  48, 206,
-    48,  48,  48,  48,  48,  48,  71, 151, 196, 582, 583, 140, 140, 140, 140, 140,
-    32,  32, 584,  32, 585, 209, 209, 209, 209, 209, 209, 209, 323, 140, 140, 140,
-   209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 586, 209, 209, 209, 587, 588,
-   589, 209, 590, 209, 209, 209, 288, 140, 209, 209, 209, 209, 591, 140, 140, 140,
-   140, 140, 140, 140, 140, 140, 271, 592, 209, 209, 209, 209, 209, 287, 271, 461,
-     9, 593,  11, 594, 595, 596, 241,   9, 597, 598, 599, 600, 601,   9, 593,  11,
-   602, 603,  11, 604, 605, 606, 607,   9, 608,  11,   9, 593,  11, 594, 595,  11,
-   241,   9, 597, 607,   9, 608,  11,   9, 593,  11, 609,   9, 610, 611, 612, 613,
-    11, 614,   9, 615, 616, 617, 618,  11, 619,   9, 620,  11, 621, 622, 622, 622,
-    32,  32,  32, 623,  32,  32, 624, 625, 626, 627,  45, 140, 140, 140, 140, 140,
-   628, 629, 140, 140, 140, 140, 140, 140, 630, 631, 632, 140, 140, 140, 140, 140,
-    48,  48, 151, 633, 634, 140, 140, 140, 140,  48, 635, 140,  48,  48, 636, 637,
-   140, 140, 140, 140, 140, 140, 638, 200,  48,  48,  48,  48, 639, 585, 140, 140,
-     9,   9, 597,  11, 640, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 498,
-   271, 271, 641, 642, 140, 140, 140, 140, 498, 271, 643, 644, 140, 140, 140, 140,
-   645,  48, 646, 647, 648, 649, 650, 651, 652, 206, 653, 206, 140, 140, 140, 654,
-   209, 209, 325, 209, 209, 209, 209, 209, 209, 323, 334, 655, 655, 655, 209, 324,
-   656, 209, 209, 209, 209, 209, 209, 209, 209, 209, 657, 140, 140, 140, 658, 209,
-   659, 209, 209, 325, 660, 661, 324, 140, 209, 209, 209, 209, 209, 209, 209, 662,
-   209, 209, 209, 209, 209, 663, 426, 426, 209, 209, 209, 209, 209, 209, 209, 323,
-   209, 209, 209, 209, 209, 660, 325, 427, 325, 209, 209, 209, 664, 176, 209, 209,
-   664, 209, 657, 661, 140, 140, 140, 140, 209, 209, 209, 209, 209, 323, 657, 665,
-   287, 209, 426, 288, 324, 176, 664, 287, 209, 666, 209, 209, 288, 140, 140, 192,
-    48,  48,  48,  48,  48,  48, 140, 140,  48,  48,  48, 196,  48,  48,  48,  48,
+   196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 587,
+    48,  48, 588, 589, 140, 590, 591,  48,  48,  48,  48,  48,  48,  48,  48, 206,
+    48,  48,  48,  48,  48,  48,  71, 151, 196, 592, 593, 140, 140, 140, 140, 140,
+    32,  32, 594,  32, 595, 209, 209, 209, 209, 209, 209, 209, 323, 140, 140, 140,
+   209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 596, 209, 209, 209, 597, 598,
+   599, 209, 600, 209, 209, 209, 288, 140, 209, 209, 209, 209, 601, 140, 140, 140,
+   140, 140, 140, 140, 271, 602, 271, 602, 209, 209, 209, 209, 209, 287, 271, 461,
+     9, 603,  11, 604, 605, 606, 241,   9, 607, 608, 609, 610, 611,   9, 603,  11,
+   612, 613,  11, 614, 615, 616, 617,   9, 618,  11,   9, 603,  11, 604, 605,  11,
+   241,   9, 607, 617,   9, 618,  11,   9, 603,  11, 619,   9, 620, 621, 622, 623,
+    11, 624,   9, 625, 626, 627, 628,  11, 629,   9, 630,  11, 631, 632, 632, 632,
+    32,  32,  32, 633,  32,  32, 634, 635, 636, 637,  45, 140, 140, 140, 140, 140,
+   638, 639, 640, 140, 140, 140, 140, 140, 641, 642, 643,  27,  27,  27, 644, 140,
+   645, 140, 140, 140, 140, 140, 140, 140,  48,  48, 151, 646, 647, 140, 140, 140,
+   140,  48, 648, 140,  48,  48, 649, 650, 140, 140, 140, 140, 140,  48, 651, 192,
+   140, 140, 140, 140, 140, 140, 652, 200,  48,  48,  48,  48, 653, 595, 140, 140,
+     9,   9, 607,  11, 654, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 499,
+   271, 271, 655, 656, 140, 140, 140, 140, 499, 271, 657, 658, 140, 140, 140, 140,
+   659,  48, 660, 661, 662, 663, 664, 665, 666, 206, 667, 206, 140, 140, 140, 668,
+   209, 209, 669, 209, 209, 209, 209, 209, 209, 323, 334, 670, 670, 670, 209, 324,
+   671, 209, 209, 209, 209, 209, 209, 209, 209, 209, 672, 140, 140, 140, 673, 209,
+   674, 209, 209, 669, 675, 676, 324, 140, 209, 209, 209, 209, 209, 209, 209, 677,
+   209, 209, 209, 209, 209, 678, 426, 426, 209, 209, 209, 209, 209, 209, 209, 679,
+   209, 209, 209, 209, 209, 176, 669, 427, 669, 209, 209, 209, 680, 176, 209, 209,
+   680, 209, 672, 676, 140, 140, 140, 140, 209, 209, 209, 209, 209, 323, 672, 426,
+   675, 209, 209, 681, 682, 669, 675, 675, 209, 683, 209, 209, 288, 140, 140, 192,
+    48,  48,  48,  48,  48,  48, 140, 140,  48,  48,  48, 207,  48,  48,  48,  48,
     48, 204,  48,  48,  48,  48,  48,  48,  48,  48, 478,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48, 100, 140,  48, 204, 140, 140, 140, 140, 140, 140,
-    48,  48,  48,  48,  71, 140, 140, 140, 667, 140, 668, 668, 668, 668, 668, 668,
+    48,  48,  48,  48,  48,  48, 100,  48,  48,  48,  48,  48,  48, 204, 140, 140,
+    48, 204, 140, 140, 140, 140, 140, 140,  48,  48,  48,  48,  71,  48,  48,  48,
+    48,  48,  48, 140, 140, 140, 140, 140, 684, 140, 570, 570, 570, 570, 570, 570,
     32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32, 140,
-   391, 391, 391, 391, 391, 391, 391, 669, 391, 391, 391, 391, 391, 391, 391, 670,
+   391, 391, 391, 391, 391, 391, 391, 685, 391, 391, 391, 391, 391, 391, 391, 686,
      0,   0,   0,   0,   0,   0,   0,   0,   1,   2,   2,   3,   1,   2,   2,   3,
      0,   0,   0,   0,   0,   4,   0,   4,   2,   2,   5,   2,   2,   2,   5,   2,
      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
@@ -5200,220 +2348,226 @@ _hb_ucd_u16[9200] =
    131, 132, 133, 131, 131, 131, 131, 131, 132, 133, 134, 131, 135, 131, 131, 131,
    136, 137, 138, 139, 137, 137, 140, 141, 138, 142, 143, 137, 144, 137, 145,  26,
    146, 147, 147, 147, 147, 147, 147, 148, 147, 147, 147, 149,  26,  26,  26,  26,
-   150, 151, 152, 152, 153, 152, 152, 154, 155, 154, 152, 156,  26,  26,  26,  26,
-   157, 157, 157, 157, 157, 157, 157, 157, 157, 158, 157, 157, 157, 159, 158, 157,
-   157, 157, 157, 158, 157, 157, 157, 160, 157, 160, 161, 162,  26,  26,  26,  26,
-   163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163,
-   163, 163, 163, 163, 164, 164, 164, 164, 165, 166, 164, 164, 164, 164, 164, 167,
-   168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168,
-   169, 169, 169, 169, 169, 169, 169, 169, 169, 170, 171, 170, 169, 169, 169, 169,
-   169, 170, 169, 169, 169, 169, 170, 171, 170, 169, 171, 169, 169, 169, 169, 169,
-   169, 169, 170, 169, 169, 169, 169, 169, 169, 169, 169, 172, 169, 169, 169, 173,
-   169, 169, 169, 174, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 176, 176,
-   177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
-   178, 178, 178, 179, 180, 180, 180, 180, 180, 180, 180, 180, 180, 181, 180, 182,
-   183, 183, 184, 185, 186, 186, 187,  26, 188, 188, 189,  26, 190, 191, 192,  26,
-   193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 194, 193, 195, 193, 195,
-   196, 197, 197, 198, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 199,
-   197, 197, 197, 197, 197, 200, 177, 177, 177, 177, 177, 177, 177, 177, 201,  26,
-   202, 202, 202, 203, 202, 204, 202, 204, 205, 202, 206, 206, 206, 207, 208,  26,
-   209, 209, 209, 209, 209, 210, 209, 209, 209, 211, 209, 212, 193, 193, 193, 193,
-   213, 213, 213, 214, 215, 215, 215, 215, 215, 215, 215, 216, 215, 215, 215, 217,
-   215, 218, 215, 218, 215, 219,   9,   9,   9, 220,  26,  26,  26,  26,  26,  26,
-   221, 221, 221, 221, 221, 221, 221, 221, 221, 222, 221, 221, 221, 221, 221, 223,
-   224, 224, 224, 224, 224, 224, 224, 224, 225, 225, 225, 225, 225, 225, 226, 227,
-   228, 228, 228, 228, 228, 228, 228, 229, 228, 230, 231, 231, 231, 231, 231, 231,
-    18, 232, 164, 164, 164, 164, 164, 233, 224,  26, 234,   9, 235, 236, 237, 238,
-     2,   2,   2,   2, 239, 240,   2,   2,   2,   2,   2, 241, 242, 243,   2, 244,
-     2,   2,   2,   2,   2,   2,   2, 245,   9,   9,   9,   9,   9,   9,   9,   9,
-    14,  14, 246, 246,  14,  14,  14,  14, 246, 246,  14, 247,  14,  14,  14, 246,
-    14,  14,  14,  14,  14,  14, 248,  14, 248,  14, 249, 250,  14,  14, 251, 252,
-     0, 253,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 254,   0, 255, 256,
-     0, 257,   2, 258,   0,   0,   0,   0, 259,  26,   9,   9,   9,   9, 260,  26,
-     0,   0,   0,   0, 261, 262,   4,   0,   0, 263,   0,   0,   2,   2,   2,   2,
-     2, 264,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0, 257,  26,  26,  26,   0, 265,  26,  26,   0,   0,   0,   0,
-   266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 267,   0,
-     0,   0, 268,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-   269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269,   2,   2,   2,   2,
-    17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17, 270, 271,
-   164, 164, 164, 164, 165, 166, 272, 272, 272, 272, 272, 272, 272, 273, 274, 273,
-   169, 169, 171,  26, 171, 171, 171, 171, 171, 171, 171, 171,  18,  18,  18,  18,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 275,  26,  26,  26,  26,
-   276, 276, 276, 277, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 278,  26,
-   276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
-   276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279,  26,  26,  26,   0, 280,
+   150, 151, 152, 152, 153, 152, 152, 154, 155, 156, 152, 157,  26,  26,  26,  26,
+   158, 158, 158, 158, 158, 158, 158, 158, 158, 159, 158, 158, 158, 160, 159, 158,
+   158, 158, 158, 159, 158, 158, 158, 161, 158, 161, 162, 163,  26,  26,  26,  26,
+   164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
+   164, 164, 164, 164, 165, 165, 165, 165, 166, 167, 165, 165, 165, 165, 165, 168,
+   169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169,
+   170, 170, 170, 170, 170, 170, 170, 170, 170, 171, 172, 171, 170, 170, 170, 170,
+   170, 171, 170, 170, 170, 170, 171, 172, 171, 170, 172, 170, 170, 170, 170, 170,
+   170, 170, 171, 170, 170, 170, 170, 170, 170, 170, 170, 173, 170, 170, 170, 174,
+   170, 170, 170, 175, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 177, 177,
+   178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178,
+   179, 179, 179, 180, 181, 181, 181, 181, 181, 181, 181, 181, 181, 182, 181, 183,
+   184, 184, 185, 186, 187, 187, 188,  26, 189, 189, 190,  26, 191, 192, 193,  26,
+   194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 195, 194, 196, 194, 196,
+   197, 198, 198, 199, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 200,
+   198, 198, 198, 198, 198, 201, 178, 178, 178, 178, 178, 178, 178, 178, 202,  26,
+   203, 203, 203, 204, 203, 205, 203, 205, 206, 203, 207, 207, 207, 208, 209,  26,
+   210, 210, 210, 210, 210, 211, 210, 210, 210, 212, 210, 213, 194, 194, 194, 194,
+   214, 214, 214, 215, 216, 216, 216, 216, 216, 216, 216, 217, 216, 216, 216, 218,
+   216, 219, 216, 219, 216, 220,   9,   9,   9, 221,  26,  26,  26,  26,  26,  26,
+   222, 222, 222, 222, 222, 222, 222, 222, 222, 223, 222, 222, 222, 222, 222, 224,
+   225, 225, 225, 225, 225, 225, 225, 225, 226, 226, 226, 226, 226, 226, 227, 228,
+   229, 229, 229, 229, 229, 229, 229, 230, 229, 231, 232, 232, 232, 232, 232, 232,
+    18, 233, 165, 165, 165, 165, 165, 234, 225,  26, 235,   9, 236, 237, 238, 239,
+     2,   2,   2,   2, 240, 241,   2,   2,   2,   2,   2, 242, 243, 244,   2, 245,
+     2,   2,   2,   2,   2,   2,   2, 246,   9,   9,   9,   9,   9,   9,   9,   9,
+    14,  14, 247, 247,  14,  14,  14,  14, 247, 247,  14, 248,  14,  14,  14, 247,
+    14,  14,  14,  14,  14,  14, 249,  14, 249,  14, 250, 251,  14,  14, 252, 253,
+     0, 254,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 255,   0, 256, 257,
+     0, 258,   2, 259,   0,   0,   0,   0, 260,  26,   9,   9,   9,   9, 261,  26,
+     0,   0,   0,   0, 262, 263,   4,   0,   0, 264,   0,   0,   2,   2,   2,   2,
+     2, 265,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0, 258,  26,  26,  26,   0, 266,  26,  26,   0,   0,   0,   0,
+   267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 268,   0,
+     0,   0, 269,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270,   2,   2,   2,   2,
+    17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17, 271, 272,
+   165, 165, 165, 165, 166, 167, 273, 273, 273, 273, 273, 273, 273, 274, 275, 274,
+   170, 170, 172,  26, 172, 172, 172, 172, 172, 172, 172, 172,  18,  18,  18,  18,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 276,  26,  26,  26,  26,
+   277, 277, 277, 278, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 279,  26,
+   277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+   277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 280,  26,  26,  26,   0,   0,
    281,   0,   0,   0, 282, 283,   0, 284, 285, 286, 286, 286, 286, 286, 286, 286,
    286, 286, 287, 288, 289, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 291,
-   292, 293, 293, 293, 293, 293, 294, 168, 168, 168, 168, 168, 168, 168, 168, 168,
-   168, 295,   0,   0, 293, 293, 293, 293,   0,   0,   0,   0, 280,  26, 290, 290,
-   168, 168, 168, 295,   0,   0,   0,   0,   0,   0,   0,   0, 168, 168, 168, 296,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 290, 290, 290, 290, 290, 297,
+   292, 293, 293, 293, 293, 293, 294, 169, 169, 169, 169, 169, 169, 169, 169, 169,
+   169, 295,   0,   0, 293, 293, 293, 293,   0,   0,   0,   0, 296, 297, 290, 290,
+   169, 169, 169, 295,   0,   0,   0,   0,   0,   0,   0,   0, 169, 169, 169, 298,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 290, 290, 290, 290, 290, 299,
    290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290,   0,   0,   0,   0,   0,
-   276, 276, 276, 276, 276, 276, 276, 276,   0,   0,   0,   0,   0,   0,   0,   0,
-   298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298,
-   298, 299, 298, 298, 298, 298, 298, 298, 300,  26, 301, 301, 301, 301, 301, 301,
-   302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302,
-   302, 302, 302, 302, 302, 303,  26,  26,  18,  18,  18,  18,  18,  18,  18,  18,
-    18,  18,  18,  18, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304,  26,
-     0,   0,   0,   0, 305,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
-     2, 306,   2,   2,   2,   2,   2,   2,   2, 307, 308, 309,  26,  26, 310,   2,
-   311, 311, 311, 311, 311, 312,   0, 313, 314, 314, 314, 314, 314, 314, 314,  26,
-   315, 315, 315, 315, 315, 315, 315, 315, 316, 317, 315, 318,  53,  53,  53,  53,
-   319, 319, 319, 319, 319, 320, 321, 321, 321, 321, 322, 323, 168, 168, 168, 324,
-   325, 325, 325, 325, 325, 325, 325, 325, 325, 326, 325, 327, 163, 163, 163, 328,
-   329, 329, 329, 329, 329, 329, 330,  26, 329, 331, 329, 332, 163, 163, 163, 163,
-   333, 333, 333, 333, 333, 333, 333, 333, 334,  26,  26, 335, 336, 336, 337,  26,
-   338, 338, 338,  26, 171, 171,   2,   2,   2,   2,   2, 339, 340, 341, 175, 175,
-   175, 175, 175, 175, 175, 175, 175, 175, 336, 336, 336, 336, 336, 342, 336, 343,
-   168, 168, 168, 168, 344,  26, 168, 168, 295, 345, 168, 168, 168, 168, 168, 344,
+   277, 277, 277, 277, 277, 277, 277, 277,   0,   0,   0,   0,   0,   0,   0,   0,
+   300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300,
+   300, 301, 300, 300, 300, 300, 300, 300, 302,  26, 303, 303, 303, 303, 303, 303,
+   304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304,
+   304, 304, 304, 304, 304, 305,  26,  26,  18,  18,  18,  18,  18,  18,  18,  18,
+    18,  18,  18,  18, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306,  26,
+     0,   0,   0,   0, 307,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+     2, 308,   2,   2,   2,   2,   2,   2,   2, 309, 310, 311,  26,  26, 312,   2,
+   313, 313, 313, 313, 313, 314,   0, 315, 316, 316, 316, 316, 316, 316, 316,  26,
+   317, 317, 317, 317, 317, 317, 317, 317, 318, 319, 317, 320,  53,  53,  53,  53,
+   321, 321, 321, 321, 321, 322, 323, 323, 323, 323, 324, 325, 169, 169, 169, 326,
+   327, 327, 327, 327, 327, 327, 327, 327, 327, 328, 327, 329, 164, 164, 164, 330,
+   331, 331, 331, 331, 331, 331, 332,  26, 331, 333, 331, 334, 164, 164, 164, 164,
+   335, 335, 335, 335, 335, 335, 335, 335, 336,  26,  26, 337, 338, 338, 339,  26,
+   340, 340, 340,  26, 172, 172,   2,   2,   2,   2,   2, 341, 342, 343, 176, 176,
+   176, 176, 176, 176, 176, 176, 176, 176, 338, 338, 338, 338, 338, 344, 338, 345,
+   169, 169, 169, 169, 346,  26, 169, 169, 295, 347, 169, 169, 169, 169, 169, 346,
     26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 276, 276,
-   276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 346,  26,  26,  26,  26,
-   347,  26, 348, 349,  25,  25, 350, 351, 352,  25,  31,  31,  31,  31,  31,  31,
-    31,  31,  31,  31,  31,  31,  31,  31, 353,  26, 354,  31,  31,  31,  31,  31,
+   277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 280, 277, 277,
+   277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 348,  26,  26,  26,  26,
+   349,  26, 350, 351,  25,  25, 352, 353, 354,  25,  31,  31,  31,  31,  31,  31,
+    31,  31,  31,  31,  31,  31,  31,  31, 355,  26, 356,  31,  31,  31,  31,  31,
     31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
-    31,  31,  31,  31,  31,  31,  31, 355,  31,  31,  31,  31,  31,  31,  31,  31,
-    31,  31, 356,  31,  31,  31,  31,  31,  31, 357,  26,  26,  26,  26,  31,  31,
-     9,   9,   0, 313,   9, 358,   0,   0,   0,   0, 359,   0, 257, 280, 360,  31,
-    31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31, 361,
-   362,   0,   0,   0,   1,   2,   2,   3,   1,   2,   2,   3, 363, 290, 289, 290,
-   290, 290, 290, 364, 168, 168, 168, 295, 365, 365, 365, 366, 257, 257,  26, 367,
-   368, 369, 368, 368, 370, 368, 368, 371, 368, 372, 368, 372,  26,  26,  26,  26,
-   368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 373,
-   374,   0,   0,   0,   0,   0, 375,   0,  14,  14,  14,  14,  14,  14,  14,  14,
-    14, 252,   0, 376, 377,  26,  26,  26,  26,  26,   0,   0,   0,   0,   0, 378,
-   379, 379, 379, 380, 381, 381, 381, 381, 381, 381, 382,  26, 383,   0,   0, 280,
-   384, 384, 384, 384, 385, 386, 387, 387, 387, 388, 389, 389, 389, 389, 389, 390,
-   391, 391, 391, 392, 393, 393, 393, 393, 394, 393, 395,  26,  26,  26,  26,  26,
-   396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 397, 397, 397, 397, 397, 397,
-   398, 398, 398, 399, 398, 400, 401, 401, 401, 401, 402, 401, 401, 401, 401, 402,
-   403, 403, 403, 403, 403,  26, 404, 404, 404, 404, 404, 404, 405, 406, 407, 408,
-   407, 408, 409, 407, 410, 407, 410, 411,  26,  26,  26,  26,  26,  26,  26,  26,
-   412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
-   412, 412, 412, 412, 412, 412, 413,  26, 412, 412, 414,  26, 412,  26,  26,  26,
-   415,   2,   2,   2,   2,   2, 416, 307,  26,  26,  26,  26,  26,  26,  26,  26,
-   417, 418, 419, 419, 419, 419, 420, 421, 422, 422, 423, 422, 424, 424, 424, 424,
-   425, 425, 425, 426, 427, 425,  26,  26,  26,  26,  26,  26, 428, 428, 429, 430,
-   431, 431, 431, 432, 433, 433, 433, 434,  26,  26,  26,  26,  26,  26,  26,  26,
-   435, 435, 435, 435, 436, 436, 436, 437, 436, 436, 438, 436, 436, 436, 436, 436,
-   439, 440, 441, 442, 443, 443, 444, 445, 443, 446, 443, 446, 447, 447, 447, 447,
-   448, 448, 448, 448,  26,  26,  26,  26, 449, 449, 449, 449, 450, 451, 450,  26,
-   452, 452, 452, 452, 452, 452, 453, 454, 455, 455, 456, 455, 457, 457, 458, 457,
-   459, 459, 460, 461,  26, 462,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   463, 463, 463, 463, 463, 463, 463, 463, 463, 464,  26,  26,  26,  26,  26,  26,
-   465, 465, 465, 465, 465, 465, 466,  26, 465, 465, 465, 465, 465, 465, 466, 467,
-   468, 468, 468, 468, 468,  26, 468, 469,  26,  26,  26,  26,  26,  26,  26,  26,
+    31,  31,  31,  31,  31,  31,  31, 357,  31,  31,  31,  31,  31,  31,  31,  31,
+    31,  31, 358,  31,  31,  31,  31,  31,  31, 359,  26,  26,  26,  26,  31,  31,
+     9,   9,   0, 315,   9, 360,   0,   0,   0,   0, 361,   0, 258, 296, 362,  31,
+    31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31, 363,
+   364,   0,   0,   0,   1,   2,   2,   3,   1,   2,   2,   3, 365, 290, 289, 290,
+   290, 290, 290, 366, 169, 169, 169, 295, 367, 367, 367, 368, 258, 258,  26, 369,
+   370, 371, 370, 370, 372, 370, 370, 373, 370, 374, 370, 374,  26,  26,  26,  26,
+   370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 375,
+   376,   0,   0,   0,   0,   0, 377,   0,  14,  14,  14,  14,  14,  14,  14,  14,
+    14, 253,   0, 378, 379,  26,  26,  26,  26,  26,   0,   0,   0,   0,   0, 380,
+   381, 381, 381, 382, 383, 383, 383, 383, 383, 383, 384,  26, 385,   0,   0, 296,
+   386, 386, 386, 386, 387, 388, 389, 389, 389, 390, 391, 391, 391, 391, 391, 392,
+   393, 393, 393, 394, 395, 395, 395, 395, 396, 395, 397,  26,  26,  26,  26,  26,
+   398, 398, 398, 398, 398, 398, 398, 398, 398, 398, 399, 399, 399, 399, 399, 399,
+   400, 400, 400, 401, 400, 402, 403, 403, 403, 403, 404, 403, 403, 403, 403, 404,
+   405, 405, 405, 405, 405,  26, 406, 406, 406, 406, 406, 406, 407, 408, 409, 410,
+   409, 410, 411, 409, 412, 409, 412, 413,  26,  26,  26,  26,  26,  26,  26,  26,
+   414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414,
+   414, 414, 414, 414, 414, 414, 415,  26, 414, 414, 416,  26, 414,  26,  26,  26,
+   417,   2,   2,   2,   2,   2, 418, 309,  26,  26,  26,  26,  26,  26,  26,  26,
+   419, 420, 421, 421, 421, 421, 422, 423, 424, 424, 425, 424, 426, 426, 426, 426,
+   427, 427, 427, 428, 429, 427,  26,  26,  26,  26,  26,  26, 430, 430, 431, 432,
+   433, 433, 433, 434, 435, 435, 435, 436,  26,  26,  26,  26,  26,  26,  26,  26,
+   437, 437, 437, 437, 438, 438, 438, 439, 438, 438, 440, 438, 438, 438, 438, 438,
+   441, 442, 443, 444, 445, 445, 446, 447, 445, 448, 445, 448, 449, 449, 449, 449,
+   450, 450, 450, 450,  26,  26,  26,  26, 451, 451, 451, 451, 452, 453, 452,  26,
+   454, 454, 454, 454, 454, 454, 455, 456, 457, 457, 458, 457, 459, 459, 460, 459,
+   461, 461, 462, 463,  26, 464,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   465, 465, 465, 465, 465, 465, 465, 465, 465, 466,  26,  26,  26,  26,  26,  26,
+   467, 467, 467, 467, 467, 467, 468,  26, 467, 467, 467, 467, 467, 467, 468, 469,
+   470, 470, 470, 470, 470,  26, 470, 471,  26,  26,  26,  26,  26,  26,  26,  26,
     26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  31,  31,  31,  50,
-   470, 470, 470, 470, 470, 471, 472,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   473, 473, 473, 473, 473,  26, 474, 474, 474, 474, 474, 475,  26,  26, 476, 476,
-   476, 477,  26,  26,  26,  26, 478, 478, 478, 479,  26,  26, 480, 480, 481,  26,
-   482, 482, 482, 482, 482, 482, 482, 482, 482, 483, 484, 482, 482, 482, 483, 485,
-   486, 486, 486, 486, 486, 486, 486, 486, 487, 488, 489, 489, 489, 490, 489, 491,
-   492, 492, 492, 492, 492, 492, 493, 492, 492,  26, 494, 494, 494, 494, 495,  26,
-   496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 497, 137, 498,  26,
-   499, 499, 500, 499, 499, 499, 499, 501,  26,  26,  26,  26,  26,  26,  26,  26,
-   502, 503, 504, 505, 504, 506, 507, 507, 507, 507, 507, 507, 507, 508, 507, 509,
-   510, 511, 512, 513, 513, 514, 515, 516, 511, 517, 518, 519, 520, 521, 521,  26,
-   522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 523, 524,  26,  26,  26,
-   525, 525, 525, 525, 525, 525, 525, 525, 525,  26, 525, 526,  26,  26,  26,  26,
-   527, 527, 527, 527, 527, 527, 528, 527, 527, 527, 527, 528,  26,  26,  26,  26,
-   529, 529, 529, 529, 529, 529, 529, 529, 530,  26, 529, 531, 197, 532,  26,  26,
-   533, 533, 533, 533, 533, 533, 533, 534, 533, 534,  26,  26,  26,  26,  26,  26,
-   535, 535, 535, 536, 535, 537, 535, 535, 538,  26,  26,  26,  26,  26,  26,  26,
-   539, 539, 539, 539, 539, 539, 539, 540,  26,  26,  26,  26,  26,  26,  26,  26,
-    26,  26,  26,  26, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 542, 543,
-   544, 545, 546, 547, 547, 547, 548, 549, 544,  26, 547, 550,  26,  26,  26,  26,
-    26,  26,  26,  26, 551, 552, 551, 551, 551, 551, 551, 552, 553,  26,  26,  26,
-   554, 554, 554, 554, 554, 554, 554, 554, 554,  26, 555, 555, 555, 555, 555, 555,
-   555, 555, 555, 555, 556,  26, 177, 177, 557, 557, 557, 557, 557, 557, 557, 558,
-   559, 560, 559, 559, 559, 559, 561, 559, 562,  26, 559, 559, 559, 563, 564, 564,
-   564, 564, 565, 564, 564, 566, 567,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   568, 569, 570, 570, 570, 570, 568, 571, 570,  26, 570, 572, 573, 574, 575, 575,
-   575, 576, 577, 578, 575, 579,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 580, 580, 580, 581,
-    26,  26,  26,  26,  26,  26, 582,  26, 108, 108, 108, 108, 108, 108, 583, 584,
-   585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585,
-   585, 585, 585, 586,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 587, 588,  26,
-   585, 585, 585, 585, 585, 585, 585, 585, 589,  26,  26,  26,  26,  26,  26,  26,
-    26,  26, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 591,  26,
-   592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592,
-   592, 592, 592, 592, 592, 593, 592, 594,  26,  26,  26,  26,  26,  26,  26,  26,
-   595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595,
-   595, 595, 595, 595, 595, 595, 595, 595, 596,  26,  26,  26,  26,  26,  26,  26,
-   304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304,
-   304, 304, 304, 304, 304, 304, 304, 597, 598, 598, 598, 599, 598, 600, 601, 601,
-   601, 601, 601, 601, 601, 601, 601, 602, 601, 603, 604, 604, 604, 605, 605,  26,
-   606, 606, 606, 606, 606, 606, 606, 606, 607,  26, 606, 608, 608, 606, 606, 609,
-   606, 606,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-    26,  26,  26,  26,  26,  26,  26,  26, 610, 610, 610, 610, 610, 610, 610, 610,
-   610, 610, 610, 611,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   612, 612, 612, 612, 612, 612, 612, 612, 612, 613, 612, 612, 612, 612, 612, 612,
-   612, 614, 612, 612,  26,  26,  26,  26,  26,  26,  26,  26, 615,  26, 346,  26,
-   616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616,
-   616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616,  26,
-   617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617,
-   617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 618,  26,  26,  26,  26,  26,
-   616, 619,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 620, 621,
-   622, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
+   472, 472, 472, 472, 472, 473, 474,  26,  26,  26,  26,  26,  26,  26,  26, 475,
+   476, 476, 476, 476, 476,  26, 477, 477, 477, 477, 477, 478,  26,  26, 479, 479,
+   479, 480,  26,  26,  26,  26, 481, 481, 481, 482,  26,  26, 483, 483, 484,  26,
+   485, 485, 485, 485, 485, 485, 485, 485, 485, 486, 487, 485, 485, 485, 486, 488,
+   489, 489, 489, 489, 489, 489, 489, 489, 490, 491, 492, 492, 492, 493, 492, 494,
+   495, 495, 495, 495, 495, 495, 496, 495, 495,  26, 497, 497, 497, 497, 498,  26,
+   499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 500, 137, 501,  26,
+   502, 502, 503, 502, 502, 502, 502, 502, 504,  26,  26,  26,  26,  26,  26,  26,
+   505, 506, 507, 508, 507, 509, 510, 510, 510, 510, 510, 510, 510, 511, 510, 512,
+   513, 514, 515, 516, 516, 517, 518, 519, 514, 520, 521, 522, 523, 524, 524,  26,
+   525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 526, 527,  26,  26,  26,
+   528, 528, 528, 528, 528, 528, 528, 528, 528,  26, 528, 529,  26,  26,  26,  26,
+   530, 530, 530, 530, 530, 530, 531, 530, 530, 530, 530, 531,  26,  26,  26,  26,
+   532, 532, 532, 532, 532, 532, 532, 532, 533,  26, 532, 534, 198, 535,  26,  26,
+   536, 536, 536, 536, 536, 536, 536, 537, 536, 537,  26,  26,  26,  26,  26,  26,
+   538, 538, 538, 539, 538, 540, 538, 538, 541,  26,  26,  26,  26,  26,  26,  26,
+   542, 542, 542, 542, 542, 542, 542, 543,  26,  26,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26, 544, 544, 544, 544, 544, 544, 544, 544, 544, 544, 545, 546,
+   547, 548, 549, 550, 550, 550, 551, 552, 547,  26, 550, 553,  26,  26,  26,  26,
+    26,  26,  26,  26, 554, 555, 554, 554, 554, 554, 554, 555, 556,  26,  26,  26,
+   557, 557, 557, 557, 557, 557, 557, 557, 557,  26, 558, 558, 558, 558, 558, 558,
+   558, 558, 558, 558, 559,  26, 178, 178, 560, 560, 560, 560, 560, 560, 560, 561,
+    53, 562,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   563, 564, 563, 563, 563, 563, 565, 563, 566,  26, 563, 563, 563, 567, 568, 568,
+   568, 568, 569, 568, 568, 570, 571,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   572, 573, 574, 574, 574, 574, 572, 575, 574,  26, 574, 576, 577, 578, 579, 579,
+   579, 580, 581, 582, 579, 583,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 584, 584, 584, 585,
+   586, 586, 587, 586, 586, 586, 586, 588, 586, 586, 586, 589,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26, 590,  26, 108, 108, 108, 108, 108, 108, 591, 592,
+   593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593,
+   593, 593, 593, 594,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 595, 596,  26,
+   593, 593, 593, 593, 593, 593, 593, 593, 597,  26,  26,  26,  26,  26,  26,  26,
+    26,  26, 598, 598, 598, 598, 598, 598, 598, 598, 598, 598, 598, 598, 599,  26,
+   600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
+   600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 601,  26,  26,  26,  26,  26,
+   602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602,
+   602, 602, 602, 602, 602, 602, 602, 602, 603,  26,  26,  26,  26,  26,  26,  26,
+   306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306,
+   306, 306, 306, 306, 306, 306, 306, 604, 605, 605, 605, 606, 605, 607, 608, 608,
+   608, 608, 608, 608, 608, 608, 608, 609, 608, 610, 611, 611, 611, 612, 612,  26,
+   613, 613, 613, 613, 613, 613, 613, 613, 614,  26, 613, 615, 615, 613, 613, 616,
+   613, 613,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26, 617, 617, 617, 617, 617, 617, 617, 617,
+   617, 617, 617, 618,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   619, 619, 619, 619, 619, 619, 619, 619, 619, 620, 619, 619, 619, 619, 619, 619,
+   619, 621, 619, 619,  26,  26,  26,  26,  26,  26,  26,  26, 622,  26, 348,  26,
+   623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
+   623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,  26,
+   624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624,
+   624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 625,  26,  26,  26,  26,  26,
+   623, 626,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 627, 628,
+   629, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
    286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
-   286, 286, 286, 286, 623,  26,  26,  26,  26,  26, 624,  26, 625,  26, 626, 626,
-   626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626,
-   626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 627,
-   628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 629, 628, 630,
-   628, 631, 628, 632, 280,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-     9,   9,   9,   9,   9, 633,   9,   9, 220,  26,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0, 280,  26,  26,  26,  26,  26,  26,  26,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 275,  26,
-     0,   0,   0,   0, 257, 362,   0,   0,   0,   0,   0,   0, 634, 635,   0, 636,
-   637, 638,   0,   0,   0, 639,   0,   0,   0,   0,   0,   0,   0, 265,  26,  26,
-    14,  14,  14,  14,  14,  14,  14,  14, 246,  26,  26,  26,  26,  26,  26,  26,
-    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,   0,   0, 280,  26,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 257,  26,   0,   0,   0, 259,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 254,   0,   0,   0,   0,   0,
-     0,   0,   0, 254, 640, 641,   0, 642, 643,   0,   0,   0,   0,   0,   0,   0,
-   268, 644, 254, 254,   0,   0,   0, 645, 646, 647, 648,   0,   0,   0,   0,   0,
-     0,   0,   0,   0, 275,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0, 267,   0,   0,   0,   0,   0,   0,
-   649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649,
-   649, 650,  26, 651, 652, 649,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-     2,   2,   2, 347,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   653, 269, 269, 654, 655, 656,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   657, 657, 657, 657, 657, 658, 657, 659, 657, 660,  26,  26,  26,  26,  26,  26,
-    26,  26, 661, 661, 661, 662,  26,  26, 663, 663, 663, 663, 663, 663, 663, 664,
-    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 171, 665, 169, 171,
-   666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666,
-   666, 666, 666, 666, 666, 666, 666, 666, 667, 666, 668,  26,  26,  26,  26,  26,
-   669, 669, 669, 669, 669, 669, 669, 669, 669, 670, 669, 671,  26,  26,  26,  26,
-    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 362,   0,
-     0,   0,   0,   0,   0,   0, 376,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   362,   0,   0,   0,   0,   0,   0, 275,  26,  26,  26,  26,  26,  26,  26,  26,
-   672,  31,  31,  31, 673, 674, 675, 676, 677, 678, 673, 679, 673, 675, 675, 680,
-    31, 681,  31, 682, 683, 681,  31, 682,  26,  26,  26,  26,  26,  26,  51,  26,
-     0,   0,   0,   0,   0, 280,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0, 280,  26,   0, 257, 362,   0, 362,   0, 362,   0,   0,   0, 275,  26,
-     0,   0,   0,   0,   0, 275,  26,  26,  26,  26,  26,  26, 684,   0,   0,   0,
-   685,  26,   0,   0,   0,   0,   0, 280,   0, 259, 313,  26, 275,  26,  26,  26,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 686,   0, 376,   0, 376,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 280,  26,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 259,   0, 280, 259,  26,
-     0, 280,   0,   0,   0,   0,   0,   0,   0,  26,   0, 313,   0,   0,   0,   0,
-     0,  26,   0,   0,   0, 275, 313,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 280,  26,   0, 275, 376, 376,
-   257,  26,   0,   0,   0, 376,   0, 265, 275,  26,   0, 313,   0,  26, 257,  26,
-     0,   0, 359,   0,   0,   0,   0,   0,   0, 265,  26,  26,  26,  26,   0, 313,
-   276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,  26,  26,  26,  26,
-   276, 276, 276, 276, 276, 276, 276, 687, 276, 276, 276, 276, 276, 276, 276, 276,
-   276, 276, 276, 279, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
-   276, 276, 276, 276, 346,  26, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
-   276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 687,  26,  26,  26,
-   276, 276, 276, 279,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   276, 276, 276, 276, 276, 276, 276, 276, 276, 688,  26,  26,  26,  26,  26,  26,
-   689,  26,  26,  26,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   286, 286, 286, 286, 630,  26, 631,  26,  26,  26, 632,  26, 633,  26, 634, 634,
+   634, 634, 634, 634, 634, 634, 634, 634, 634, 634, 634, 634, 634, 634, 634, 634,
+   634, 634, 634, 634, 634, 634, 634, 634, 634, 634, 634, 634, 634, 634, 634, 635,
+   636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 637, 636, 638,
+   636, 639, 636, 640, 296,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+     9,   9,   9,   9,   9, 641,   9,   9, 221,  26,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0, 296,  26,  26,  26,  26,  26,  26,  26,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 276,  26,
+     0,   0,   0,   0, 258, 364,   0,   0,   0,   0,   0,   0, 642, 643,   0, 644,
+   645, 646,   0,   0,   0, 647,   0,   0,   0,   0,   0,   0,   0, 266,  26,  26,
+    14,  14,  14,  14,  14,  14,  14,  14, 247,  26,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26,   0,   0, 296,  26,   0,   0, 296,  26,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 258,  26,   0,   0,   0, 260,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 255,   0,   0,   0,   0,   0,
+     0,   0,   0, 255, 648, 649,   0, 650, 651,   0,   0,   0,   0,   0,   0,   0,
+   269, 652, 255, 255,   0,   0,   0, 653, 654, 655, 656,   0,   0,   0,   0,   0,
+     0,   0,   0,   0, 276,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0, 268,   0,   0,   0,   0,   0,   0,
+   657, 657, 657, 657, 657, 657, 657, 657, 657, 657, 657, 657, 657, 657, 657, 657,
+   657, 658,  26, 659, 660, 657,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+     2,   2,   2, 349, 661, 309,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   662, 270, 270, 663, 664, 665,  18,  18,  18,  18,  18,  18,  18, 666,  26,  26,
+    26, 667,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   668, 668, 668, 668, 668, 669, 668, 670, 668, 671,  26,  26,  26,  26,  26,  26,
+    26,  26, 672, 672, 672, 673,  26,  26, 674, 674, 674, 674, 674, 674, 674, 675,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 676, 676, 676, 676, 676, 677,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 172, 678, 170, 172,
+   679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679,
+   679, 679, 679, 679, 679, 679, 679, 679, 680, 679, 681,  26,  26,  26,  26,  26,
+   682, 682, 682, 682, 682, 682, 682, 682, 682, 683, 682, 684,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 364,   0,
+     0,   0,   0,   0,   0,   0, 378,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   364,   0,   0,   0,   0,   0,   0, 276,  26,  26,  26,  26,  26,  26,  26,  26,
+   685,  31,  31,  31, 686, 687, 688, 689, 690, 691, 686, 692, 686, 688, 688, 693,
+    31, 694,  31, 695, 696, 694,  31, 695,  26,  26,  26,  26,  26,  26,  51,  26,
+     0,   0,   0,   0,   0, 296,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0, 296,  26,   0, 258, 364,   0, 364,   0, 364,   0,   0,   0, 276,  26,
+     0,   0,   0,   0,   0, 276,  26,  26,  26,  26,  26,  26, 697,   0,   0,   0,
+   698,  26,   0,   0,   0,   0,   0, 296,   0, 260, 315,  26, 276,  26,  26,  26,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 699,   0, 378,   0, 378,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 258, 700,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 315,   0, 296, 260,  26,
+     0, 296,   0,   0,   0,   0,   0,   0,   0,  26,   0, 315,   0,   0,   0,   0,
+     0,  26,   0,   0,   0, 276, 315,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 296,  26,   0, 276,   0, 378,
+     0, 260,   0,   0,   0,   0,   0, 269, 276, 697,   0, 296,   0, 260,   0, 260,
+     0,   0, 361,   0,   0,   0,   0,   0,   0, 266,  26,  26,  26,  26,   0, 315,
+   277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,  26,  26,  26,  26,
+   277, 277, 277, 277, 277, 277, 277, 348, 277, 277, 277, 277, 277, 277, 277, 277,
+   277, 277, 277, 280, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+   277, 277, 277, 277, 348,  26, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+   277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 701,  26, 277, 277,
+   277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 280,  26,  26,  26,  26,
+   277, 277, 277, 280,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   277, 277, 277, 277, 277, 277, 277, 277, 277, 702, 277, 277, 277, 277, 277, 277,
+   277, 277, 277, 277, 277, 277,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   703,  26,  26,  26,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
      9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,
      9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   0,   0,
      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
@@ -5625,32 +2779,1636 @@ _hb_ucd_u16[9200] =
    930,  99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935,   0,   0,
 };
 static const int16_t
-_hb_ucd_i16[196] =
+_hb_ucd_i16[196] =
+{
+      0,    0,    0,    0,    1,   -1,    0,    0,    2,    0,   -2,    0,    0,    0,    0,    2,
+      0,   -2,    0,    0,    0,    0,    0,   16,    0,    0,    0,  -16,    0,    0,    1,   -1,
+      0,    0,    0,    1,   -1,    0,    0,    0,    0,    1,   -1,    0,    3,    3,    3,   -3,
+     -3,   -3,    0,    0,    0, 2016,    0,    0,    0,    0,    0, 2527, 1923, 1914, 1918,    0,
+   2250,    0,    0,    0,    0,    0,    0,  138,    0,    7,    0,    0,   -7,    0,    0,    0,
+      1,   -1,    1,   -1,   -1,    1,   -1,    0, 1824,    0,    0,    0,    0,    0, 2104,    0,
+   2108, 2106,    0, 2106, 1316,    0,    0,    0,    0,    1,   -1,    1,   -1, -138,    0,    0,
+      1,   -1,    8,    8,    8,    0,    7,    7,    0,    0,   -8,   -8,   -8,   -7,   -7,    0,
+      1,   -1,    0,    2,-1316,    1,   -1,    0,   -1,    1,   -1,    1,   -1,    3,    1,   -1,
+     -3,    1,   -1,    1,   -1,    0,    0,-1914,-1918,    0,    0,-1923,-1824,    0,    0,    0,
+      0,-2016,    0,    0,    1,   -1,    0,    1,    0,    0,-2104,    0,    0,    0,    0,-2106,
+  -2108,-2106,    0,    0,    1,   -1,-2250,    0,    0,    0,-2527,    0,    0,   -2,    0,    1,
+     -1,    0,    1,   -1,
+};
+
+static inline uint_fast8_t
+_hb_ucd_gc (unsigned u)
+{
+  return u<1114110u?_hb_ucd_u8[6808+(((_hb_ucd_u8[1312+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
+}
+static inline uint_fast8_t
+_hb_ucd_ccc (unsigned u)
+{
+  return u<125259u?_hb_ucd_u8[8800+(((_hb_ucd_u8[8244+(((_hb_ucd_u8[7784+(((_hb_ucd_u8[7432+(((_hb_ucd_u8[7186+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
+}
+static inline unsigned
+_hb_ucd_b4 (const uint8_t* a, unsigned i)
+{
+  return (a[i>>1]>>((i&1u)<<2))&15u;
+}
+static inline int_fast16_t
+_hb_ucd_bmg (unsigned u)
+{
+  return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9548+(((_hb_ucd_u8[9428+(((_hb_ucd_b4(9300+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
+}
+static inline uint_fast8_t
+_hb_ucd_sc (unsigned u)
+{
+  return u<918000u?_hb_ucd_u8[11070+(((_hb_ucd_u16[2048+(((_hb_ucd_u8[10334+(((_hb_ucd_u8[9884+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2;
+}
+static inline uint_fast16_t
+_hb_ucd_dm (unsigned u)
+{
+  return u<195102u?_hb_ucd_u16[6032+(((_hb_ucd_u8[17084+(((_hb_ucd_u8[16702+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+}
+
+
+#elif !defined(HB_NO_UCD_UNASSIGNED)
+
+static const uint8_t
+_hb_ucd_u8[14752] =
+{
+    0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  9, 10,  7,  7,  7,  7, 11, 12, 13, 13, 13, 14,
+   15, 16, 17, 18, 19, 20, 21, 22, 23, 22, 22, 22, 22, 24,  7,  7,
+   25, 26, 22, 22, 22, 27, 28, 29, 22, 30, 31, 32, 33, 34, 35, 36,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7, 37,  7, 38, 39,  7, 40,  7,  7,  7, 41, 22, 42,
+    7,  7, 43,  7, 44, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   45, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 46,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 47,
+    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, 34, 35, 36, 37, 38, 39, 34, 34, 34, 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, 64, 65, 66, 67, 68, 69, 70, 71, 69, 72, 73,
+   69, 69, 64, 74, 64, 64, 75, 76, 77, 78, 79, 80, 81, 82, 69, 83,
+   84, 85, 86, 87, 88, 89, 69, 69, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 90, 34, 34, 34, 34,
+   91, 34, 34, 34, 34, 34, 34, 34, 34, 92, 34, 34, 93, 94, 95, 96,
+   97, 98, 99,100,101,102,103,104, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,105,
+  106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,
+  107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,
+  107,107, 34, 34,108,109,110,111, 34, 34,112,113,114,115,116,117,
+  118,119,120,121,122,123,124,125,126,127,128,129, 34, 34,130,131,
+  132,133,134,135,136,137,138,139,140,141,142,122,143,144,145,146,
+  147,148,149,150,151,152,153,122,154,155,122,156,157,158,159,122,
+  160,161,162,163,164,165,166,122,167,168,169,170,122,171,172,173,
+   34, 34, 34, 34, 34, 34, 34,174,175, 34,176,122,122,122,122,122,
+  122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,177,
+   34, 34, 34, 34, 34, 34, 34, 34,178,122,122,122,122,122,122,122,
+  122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,
+  122,122,122,122,122,122,122,122, 34, 34, 34, 34,179,122,122,122,
+   34, 34, 34, 34,180,181,182,183,122,122,122,122,184,185,186,187,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,188,
+   34, 34, 34, 34, 34, 34, 34, 34, 34,189,190,122,122,122,122,122,
+  122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,191,
+   34, 34,192, 34, 34,193,122,122,122,122,122,122,122,122,122,122,
+  122,122,122,122,122,122,122,122,194,195,122,122,122,122,122,122,
+  122,122,122,122,122,122,122,122,122,122,122,122,122,122,196,197,
+   69,198,199,200,201,202,203,122,204,205,206,207,208,209,210,211,
+   69, 69, 69, 69,212,213,122,122,122,122,122,122,122,122,214,122,
+  215,216,217,122,122,218,122,122,122,219,122,122,122,122,122,220,
+   34,221,222,122,122,122,122,122,223,224,225,122,226,227,122,122,
+  228,229,230,231,232,122, 69,233, 69, 69, 69, 69, 69,234,235,236,
+  237,238, 69, 69,239,240, 69,241,122,122,122,122,122,122,122,122,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,242, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,243, 34,
+  244, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,245, 34, 34,
+   34, 34, 34, 34, 34, 34, 34,246, 34, 34, 34, 34,247,122,122,122,
+   34, 34, 34, 34,248,122,122,122,122,122,122,122,122,122,122,122,
+   34, 34, 34, 34, 34, 34,249, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34,250,122,122,122,122,122,122,122,122,
+  251,122,252,253,122,122,122,122,122,122,122,122,122,122,122,122,
+  107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,254,
+  107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,255,
+    0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  2,  4,  5,  6,  2,
+    7,  7,  7,  7,  7,  2,  8,  9, 10, 11, 11, 11, 11, 11, 11, 11,
+   11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 17, 18, 19,  1, 20, 20, 21, 22, 23, 24, 25,
+   26, 27, 15,  2, 28, 29, 27, 30, 11, 11, 11, 11, 11, 11, 11, 11,
+   11, 11, 11, 31, 11, 11, 11, 32, 16, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 33, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32,
+   32, 32, 32, 32, 34, 34, 34, 34, 34, 34, 34, 34, 16, 32, 32, 32,
+   32, 32, 32, 32, 11, 34, 34, 16, 34, 32, 32, 11, 34, 11, 16, 11,
+   11, 34, 32, 11, 32, 16, 11, 34, 32, 32, 32, 11, 34, 16, 32, 11,
+   34, 11, 34, 34, 32, 35, 32, 16, 36, 36, 37, 34, 38, 37, 34, 34,
+   34, 34, 34, 34, 34, 34, 16, 32, 34, 38, 32, 11, 32, 32, 32, 32,
+   32, 32, 16, 16, 16, 11, 34, 32, 34, 34, 11, 32, 32, 32, 32, 32,
+   16, 16, 39, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 40,
+   40, 41, 41, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41,
+   40, 40, 42, 41, 41, 41, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41,
+   43, 43, 43, 43, 43, 43, 43, 43, 32, 32, 42, 32, 44, 45, 16, 10,
+   44, 44, 41, 46, 11, 47, 47, 11, 34, 11, 11, 11, 11, 11, 11, 11,
+   11, 48, 11, 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 34,
+   16, 11, 32, 16, 32, 32, 32, 32, 16, 16, 32, 49, 34, 32, 34, 11,
+   32, 50, 43, 43, 51, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16,
+   48, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 47, 52,  2,  2,  2,
+   16, 16, 16, 16, 53, 54, 55, 56, 57, 43, 43, 43, 43, 43, 43, 43,
+   43, 43, 43, 43, 43, 43, 43, 58, 59, 60, 43, 59, 44, 44, 44, 44,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 62,
+   36, 63, 64, 44, 44, 44, 44, 44, 65, 65, 65,  8,  9, 66,  2, 67,
+   43, 43, 43, 43, 43, 60, 68,  2, 69, 36, 36, 36, 36, 70, 43, 43,
+    7,  7,  7,  7,  7,  2,  2, 36, 71, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 72, 43, 43, 43, 73, 50, 43, 43, 74, 75, 76, 43, 43, 36,
+    7,  7,  7,  7,  7, 36, 77, 78,  2,  2,  2,  2,  2,  2,  2, 79,
+   70, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 80, 62, 36,
+   36, 36, 36, 43, 43, 43, 43, 43, 71, 44, 44, 44, 44, 44, 44, 44,
+    7,  7,  7,  7,  7, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43,
+   43, 43, 40, 21,  2, 81, 57, 20, 36, 36, 36, 43, 43, 75, 43, 43,
+   43, 43, 75, 43, 75, 43, 43, 44,  2,  2,  2,  2,  2,  2,  2, 64,
+   36, 36, 36, 36, 70, 43, 44, 64, 36, 36, 36, 36, 36, 61, 44, 44,
+   36, 36, 36, 36, 82, 36, 36, 61, 65, 44, 44, 44, 43, 43, 43, 43,
+   36, 36, 36, 36, 83, 43, 43, 43, 43, 84, 43, 43, 43, 43, 43, 43,
+   43, 85, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 85, 71, 86,
+   87, 43, 43, 43, 85, 86, 87, 86, 70, 43, 43, 43, 36, 36, 36, 36,
+   36, 43,  2,  7,  7,  7,  7,  7, 88, 36, 36, 36, 36, 36, 36, 36,
+   70, 86, 62, 36, 36, 36, 61, 62, 61, 62, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 61, 36, 36, 36, 61, 61, 44, 36, 36, 44, 71, 86,
+   87, 43, 80, 89, 90, 89, 87, 61, 44, 44, 44, 89, 44, 44, 36, 62,
+   36, 43, 44,  7,  7,  7,  7,  7, 36, 20, 27, 27, 27, 56, 63, 80,
+   57, 85, 62, 36, 36, 61, 44, 62, 61, 36, 62, 61, 36, 44, 80, 86,
+   87, 80, 44, 57, 80, 57, 43, 44, 57, 44, 44, 44, 62, 36, 61, 61,
+   44, 44, 44,  7,  7,  7,  7,  7, 43, 36, 70, 64, 44, 44, 44, 44,
+   57, 85, 62, 36, 36, 36, 36, 62, 36, 62, 36, 36, 36, 36, 36, 36,
+   61, 36, 62, 36, 36, 44, 71, 86, 87, 43, 43, 57, 85, 89, 87, 44,
+   61, 44, 44, 44, 44, 44, 44, 44, 66, 44, 44, 44, 62, 43, 43, 43,
+   57, 86, 62, 36, 36, 36, 61, 62, 61, 36, 62, 36, 36, 44, 71, 87,
+   87, 43, 80, 89, 90, 89, 87, 44, 44, 44, 57, 85, 44, 44, 36, 62,
+   78, 27, 27, 27, 44, 44, 44, 44, 44, 71, 62, 36, 36, 61, 44, 36,
+   61, 36, 36, 44, 62, 61, 61, 36, 44, 62, 61, 44, 36, 61, 44, 36,
+   36, 36, 36, 36, 36, 44, 44, 86, 85, 90, 44, 86, 90, 86, 87, 44,
+   61, 44, 44, 89, 44, 44, 44, 44, 27, 91, 67, 67, 56, 92, 44, 44,
+   85, 86, 71, 36, 36, 36, 61, 36, 61, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 44, 71, 43, 85, 86, 90, 43, 80, 43, 43, 44,
+   44, 44, 57, 80, 36, 61, 62, 44, 44, 44, 44, 93, 27, 27, 27, 91,
+   70, 86, 72, 36, 36, 36, 61, 36, 36, 36, 62, 36, 36, 44, 71, 87,
+   86, 86, 90, 85, 90, 86, 43, 44, 44, 44, 89, 90, 44, 44, 62, 61,
+   62, 94, 44, 44, 44, 44, 44, 44, 43, 86, 36, 36, 36, 36, 61, 36,
+   36, 36, 36, 36, 36, 70, 71, 86, 87, 43, 80, 86, 90, 86, 87, 77,
+   44, 44, 36, 94, 27, 27, 27, 95, 27, 27, 27, 27, 91, 36, 36, 36,
+   57, 86, 62, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 36, 36, 36,
+   36, 62, 36, 36, 36, 36, 62, 44, 36, 36, 36, 61, 44, 80, 44, 89,
+   86, 43, 80, 80, 86, 86, 86, 86, 44, 86, 64, 44, 44, 44, 44, 44,
+   62, 36, 36, 36, 36, 36, 36, 36, 70, 36, 43, 43, 43, 80, 44, 96,
+   36, 36, 36, 75, 43, 43, 43, 60,  7,  7,  7,  7,  7,  2, 44, 44,
+   44, 44, 44, 44, 44, 44, 44, 44, 62, 61, 61, 36, 36, 61, 36, 36,
+   36, 36, 62, 62, 36, 36, 36, 36, 70, 36, 43, 43, 43, 43, 71, 44,
+   36, 36, 61, 81, 43, 43, 43, 80,  7,  7,  7,  7,  7, 44, 36, 36,
+   77, 67,  2,  2,  2,  2,  2,  2,  2, 97, 97, 67, 43, 67, 67, 67,
+    7,  7,  7,  7,  7, 27, 27, 27, 27, 27, 50, 50, 50,  4,  4, 86,
+   36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44,
+   57, 43, 43, 43, 43, 43, 43, 85, 43, 43, 60, 43, 36, 36, 70, 43,
+   43, 43, 43, 43, 57, 43, 43, 43, 43, 43, 43, 43, 43, 43, 80, 67,
+   67, 67, 67, 76, 67, 67, 92, 67,  2,  2, 97, 67, 21, 64, 44, 44,
+   36, 36, 36, 36, 36, 94, 87, 43, 85, 43, 43, 43, 87, 85, 87, 71,
+    7,  7,  7,  7,  7,  2,  2,  2, 36, 36, 36, 86, 43, 36, 36, 43,
+   71, 86, 98, 94, 86, 86, 86, 36, 70, 43, 71, 36, 36, 36, 36, 36,
+   36, 85, 87, 85, 86, 86, 87, 94,  7,  7,  7,  7,  7, 86, 87, 67,
+   11, 11, 11, 48, 44, 44, 48, 44, 16, 16, 16, 16, 16, 53, 45, 16,
+   36, 36, 36, 36, 61, 36, 36, 44, 36, 36, 36, 61, 61, 36, 36, 44,
+   61, 36, 36, 44, 36, 36, 36, 61, 61, 36, 36, 44, 36, 36, 36, 36,
+   36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 57, 43,
+    2,  2,  2,  2, 99, 27, 27, 27, 27, 27, 27, 27, 27, 27,100, 44,
+   67, 67, 67, 67, 67, 44, 44, 44, 11, 11, 11, 44, 16, 16, 16, 44,
+  101, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 77, 72,
+  102, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,103,104, 44,
+   36, 36, 36, 36, 36, 63,  2,105,106, 36, 36, 36, 61, 44, 44, 44,
+   36, 43, 85, 44, 44, 44, 44, 62, 36, 43,107, 64, 44, 44, 44, 44,
+   36, 43, 44, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 61, 36,
+   61, 43, 44, 44, 44, 44, 44, 44, 36, 36, 43, 87, 43, 43, 43, 86,
+   86, 86, 86, 85, 87, 43, 43, 43, 43, 43,  2, 88,  2, 66, 70, 44,
+    7,  7,  7,  7,  7, 44, 44, 44, 27, 27, 27, 27, 27, 44, 44, 44,
+    2,  2,  2,108,  2, 59, 43, 84, 36, 83, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 61, 44, 44, 44, 36, 36, 70, 71, 36, 36, 36, 36,
+   36, 36, 36, 36, 70, 61, 44, 44, 36, 36, 36, 44, 44, 44, 44, 44,
+   36, 36, 36, 36, 36, 36, 36, 61, 43, 85, 86, 87, 85, 86, 44, 44,
+   86, 85, 86, 86, 87, 43, 44, 44, 92, 44,  2,  7,  7,  7,  7,  7,
+   36, 36, 36, 36, 36, 36, 36, 44, 36, 36, 61, 44, 44, 44, 44, 44,
+   36, 36, 36, 36, 36, 36, 44, 44, 36, 36, 36, 36, 36, 44, 44, 44,
+    7,  7,  7,  7,  7,100, 44, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+   36, 36, 36, 70, 85, 87, 44,  2, 36, 36, 94, 85, 43, 43, 43, 80,
+   85, 85, 87, 43, 43, 43, 85, 86, 86, 87, 43, 43, 43, 43, 80, 57,
+    2,  2,  2, 88,  2,  2,  2, 44, 43, 43, 43, 43, 43, 43, 43,109,
+   43, 43, 43, 43, 43, 43, 43, 80, 43, 43, 98, 36, 36, 36, 36, 36,
+   36, 36, 85, 43, 43, 85, 85, 86, 86, 85, 98, 36, 36, 36, 61, 44,
+   97, 67, 67, 67, 67, 50, 43, 43, 43, 43, 67, 67, 67, 67, 21, 64,
+   43, 98, 36, 36, 36, 36, 36, 36, 94, 43, 43, 86, 43, 87, 43, 36,
+   36, 36, 36, 85, 43, 86, 87, 87, 43, 86, 44, 44, 44, 44,  2,  2,
+   36, 36, 86, 86, 86, 86, 43, 43, 43, 43, 86, 43, 44, 93,  2,  2,
+    7,  7,  7,  7,  7, 44, 62, 36, 36, 36, 36, 36, 40, 40, 40,  2,
+   16, 16, 16, 16,110, 44, 44, 44, 11, 11, 11, 11, 11, 47, 48, 11,
+    2,  2,  2,  2, 44, 44, 44, 44, 43, 60, 43, 43, 43, 43, 43, 43,
+   85, 43, 43, 43, 71, 36, 70, 36, 36, 36, 71, 94, 43, 61, 44, 44,
+   16, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 45, 16, 16,
+   16, 16, 16, 16, 45, 16, 16, 16, 16, 16, 16, 16, 16,111, 40, 40,
+   32, 32, 32, 16, 16, 16, 16, 32, 16, 16, 16, 16, 11, 11, 11, 11,
+   16, 16, 16, 44, 11, 11, 11, 44, 16, 16, 16, 16, 48, 48, 48, 48,
+   16, 16, 16, 16, 16, 16, 16, 44, 16, 16, 16, 16,112,112,112,112,
+   16, 16,110, 16, 11, 11,113,114, 41, 16,110, 16, 11, 11,113, 41,
+   16, 16, 44, 16, 11, 11,115, 41, 16, 16, 16, 16, 11, 11,116, 41,
+   44, 16,110, 16, 11, 11,113,117,118,118,118,118,118,119, 65, 65,
+  120,120,120,  2,121,122,121,122,  2,  2,  2,  2,123, 65, 65,124,
+    2,  2,  2,  2,125,126,  2,127,128,  2,129,130,  2,  2,  2,  2,
+    2,  9,128,  2,  2,  2,  2,131, 65, 65,132, 65, 65, 65, 65, 65,
+  133, 44, 27, 27, 27,  8,129,134, 27, 27, 27, 27, 27,  8,129,104,
+   40, 40, 40, 40, 40, 40, 81, 44, 20, 20, 20, 20, 20, 20, 20, 20,
+  135, 44, 44, 44, 44, 44, 44, 44, 43, 43, 43, 43, 43, 43,136, 51,
+  109, 51,109, 43, 43, 43, 43, 43, 80, 44, 44, 44, 44, 44, 44, 44,
+   67,137, 67,138, 67, 34, 11, 16, 11, 32,138, 67, 49, 11, 11, 67,
+   67, 67,137,137,137, 11, 11,139, 11, 11, 35, 36, 39, 67, 16, 11,
+    8,  8, 49, 16, 16, 26, 67,140, 27, 27, 27, 27, 27, 27, 27, 27,
+  105,105,105,105,105,105,105,105,105,141,142,105,143, 67, 44, 44,
+    8,  8,144, 67, 67,  8, 67, 67,144, 26, 67,144, 67, 67, 67,144,
+   67, 67, 67, 67, 67, 67, 67,  8, 67,144,144, 67, 67, 67, 67, 67,
+   67, 67,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
+   67, 67, 67, 67,  4,  4, 67, 67,  8, 67, 67, 67,145,146, 67, 67,
+   67, 67, 67, 67, 67, 67,144, 67, 67, 67, 67, 67, 67, 26,  8,  8,
+    8,  8, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67,  8,  8,
+    8, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 92, 44, 44, 44, 44,
+   67, 67, 67, 67, 67, 92, 44, 44, 27, 27, 27, 27, 27, 27, 67, 67,
+   67, 67, 67, 67, 67, 27, 27, 27, 67, 67, 67, 26, 67, 67, 67, 67,
+   26, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67,  8,  8,  8,  8,
+   67, 67, 67, 67, 67, 67, 67, 26, 67, 67, 67, 67,  4,  4,  4,  4,
+    4,  4,  4, 27, 27, 27, 27, 27, 27, 27, 67, 67, 67, 67, 67, 67,
+    8,  8,129,147,  8,  8,  8,  8,  8,  8,  8,  4,  4,  4,  4,  4,
+    8,129,148,148,148,148,148,148,148,148,148,148,147,  8,  8,  8,
+    8,  8,  8,  8,  4,  4,  8,  8,  8,  8,  8,  8,  8,  8,  4,  8,
+    8,  8,144, 26,  8,  8,144, 67, 67, 67, 44, 67, 67, 67, 67, 67,
+   67, 67, 67, 55, 67, 67, 67, 67, 32, 11, 32, 34, 34, 34, 34, 11,
+   32, 32, 34, 16, 16, 16, 40, 11, 32, 32,140, 67, 67,138, 34,149,
+   43, 32, 44, 44, 93,  2, 99,  2, 16, 16, 16,150, 44, 44,150, 44,
+   36, 36, 36, 36, 44, 44, 44, 52, 64, 44, 44, 44, 44, 44, 44, 57,
+   36, 36, 36, 61, 44, 44, 44, 44, 36, 36, 36, 61, 36, 36, 36, 61,
+    2,121,121,  2,125,126,121,  2,  2,  2,  2,  6,  2,108,121,  2,
+  121,  4,  4,  4,  4,  2,  2, 88,  2,  2,  2,  2,  2,120,  2,  2,
+  108,151,  2,  2,  2,  2,  2,  2, 67,  2,152,148,148,148,153, 44,
+   67, 67, 67, 67, 67, 55, 67, 67, 67, 67, 44, 44, 44, 44, 44, 44,
+   67, 67, 67, 44, 44, 44, 44, 44,  1,  2,154,155,  4,  4,  4,  4,
+    4, 67,  4,  4,  4,  4,156,157,158,105,105,105,105, 43, 43, 86,
+  159, 40, 40, 67,105,160, 63, 67, 36, 36, 36, 61, 57,161,162, 69,
+   36, 36, 36, 36, 36, 63, 40, 69, 44, 44, 62, 36, 36, 36, 36, 36,
+   67, 27, 27, 67, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44, 44, 55,
+   67, 67, 67, 67, 67, 67, 67, 92, 27, 27, 27, 27, 27, 67, 67, 67,
+   67, 67, 67, 67, 27, 27, 27, 27,163, 27, 27, 27, 27, 27, 27, 27,
+   36, 36, 83, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,164,  2,
+    7,  7,  7,  7,  7, 36, 44, 44, 32, 32, 32, 32, 32, 32, 32, 70,
+   51,165, 43, 43, 43, 43, 43, 88, 32, 32, 32, 32, 32, 32, 40, 43,
+   36, 36, 36,105,105,105,105,105, 43,  2,  2,  2, 44, 44, 44, 44,
+   41, 41, 41,162, 40, 40, 40, 40, 41, 32, 32, 32, 32, 32, 32, 32,
+   16, 32, 32, 32, 32, 32, 32, 32, 45, 16, 16, 16, 34, 34, 34, 32,
+   32, 32, 32, 32, 42,166, 34, 35, 32, 32, 16, 32, 32, 32, 32, 32,
+   32, 32, 32, 32, 32, 11, 11, 32, 11, 11, 32, 32, 32, 32, 32, 32,
+   32, 32, 11, 11, 34,110, 44, 44, 32,150,150, 32, 32, 44, 44, 44,
+   44, 40,167, 35, 40, 35, 36, 36, 36, 71, 36, 71, 36, 70, 36, 36,
+   36, 94, 87, 85, 67, 67, 80, 44, 27, 27, 27, 67,168, 44, 44, 44,
+   36, 36,  2,  2, 44, 44, 44, 44, 86, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 86, 86, 86, 86, 86, 86, 86, 86, 43, 44, 44, 44, 44,  2,
+   43, 36, 36, 36,  2, 72, 72, 70, 36, 36, 36, 43, 43, 43, 43,  2,
+   36, 36, 36, 70, 43, 43, 43, 43, 43, 86, 44, 44, 44, 44, 44, 93,
+   36, 70, 86, 43, 43, 86, 43, 86,107,  2,  2,  2,  2,  2,  2, 52,
+    7,  7,  7,  7,  7, 44, 44,  2, 36, 36, 70, 69, 36, 36, 36, 36,
+    7,  7,  7,  7,  7, 36, 36, 61, 36, 36, 36, 36, 70, 43, 43, 85,
+   87, 85, 87, 80, 44, 44, 44, 44, 36, 70, 36, 36, 36, 36, 85, 44,
+    7,  7,  7,  7,  7, 44,  2,  2, 69, 36, 36, 77, 67, 94, 85, 36,
+   71, 43, 71, 70, 71, 36, 36, 43, 70, 61, 44, 44, 44, 44, 44, 44,
+   44, 44, 44, 44, 44, 62, 83,  2, 36, 36, 36, 36, 36, 94, 43, 86,
+    2, 83,169, 80, 44, 44, 44, 44, 62, 36, 36, 61, 62, 36, 36, 61,
+   62, 36, 36, 61, 44, 44, 44, 44, 16, 16, 16, 16, 16,114, 40, 40,
+   16, 16, 16, 16,111, 41, 44, 44, 36, 94, 87, 86, 85,107, 87, 44,
+   36, 36, 44, 44, 44, 44, 44, 44, 36, 36, 36, 61, 44, 62, 36, 36,
+  170,170,170,170,170,170,170,170,171,171,171,171,171,171,171,171,
+   16, 16, 16,110, 44, 44, 44, 44, 44,150, 16, 16, 44, 44, 62, 71,
+   36, 36, 36, 36,172, 36, 36, 36, 36, 36, 36, 61, 36, 36, 61, 61,
+   36, 62, 61, 36, 36, 36, 36, 36, 36, 41, 41, 41, 41, 41, 41, 41,
+   41,117, 44, 44, 44, 44, 44, 44, 44, 62, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36,148, 44, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 44, 44, 44, 55, 36, 36, 36, 36, 36, 36,168, 67,
+    2,  2,  2,152,130, 44, 44, 44,  6,173,174,148,148,148,148,148,
+  148,148,130,152,130,  2,127,175,  2, 64,  2,  2,156,148,148,130,
+    2,176,  8,177, 66,  2, 44, 44, 36, 36, 61, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 61, 79, 93,  2,  3,  2,  4,  5,  6,  2,
+   16, 16, 16, 16, 16, 17, 18,129,130,  4,  2, 36, 36, 36, 36, 36,
+   69, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 40,
+   44, 36, 36, 36, 44, 36, 36, 36, 44, 36, 36, 36, 44, 36, 61, 44,
+   20,178, 56,135, 26,  8,144, 92, 44, 44, 44, 44, 79, 65, 67, 44,
+   36, 36, 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 61, 36, 62,
+    2, 64, 44,179, 27, 27, 27, 27, 27, 27, 44, 55, 67, 67, 67, 67,
+  105,105,143, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 27, 67, 92,
+   67, 67, 67, 67, 67, 67, 92, 44, 92, 44, 44, 44, 44, 44, 44, 44,
+   67, 67, 67, 67, 67, 67, 50, 44,180, 27, 27, 27, 27, 27, 27, 27,
+   27, 27, 27, 27, 27, 27, 44, 44, 27, 27, 44, 44, 44, 44, 62, 36,
+  155, 36, 36, 36, 36,181, 44, 44, 36, 36, 36, 43, 43, 80, 44, 44,
+   36, 36, 36, 36, 36, 36, 36, 93, 36, 36, 44, 44, 36, 36, 36, 36,
+  182,105,105, 44, 44, 44, 44, 44, 11, 11, 11, 11, 16, 16, 16, 16,
+   11, 11, 44, 44, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 44, 44,
+   36, 36, 36, 36, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44, 44, 93,
+   11, 11, 11, 11, 11, 47, 11, 11, 11, 47, 11,150, 16, 16, 16, 16,
+   16,150, 16, 16, 16, 16, 16, 16, 16,150, 16, 16, 16,150,110, 44,
+   40, 40, 40, 52, 40, 40, 40, 40, 81, 40, 40, 40, 40, 81, 44, 44,
+   36, 36, 36, 44, 61, 36, 36, 36, 36, 36, 36, 62, 61, 44, 61, 62,
+   36, 36, 36, 93, 27, 27, 27, 27, 36, 36, 36, 77,163, 27, 27, 27,
+   44, 44, 44,179, 27, 27, 27, 27, 36, 61, 36, 44, 44,179, 27, 27,
+   36, 36, 36, 27, 27, 27, 44, 93, 36, 36, 36, 36, 36, 44, 44, 93,
+   36, 36, 36, 36, 44, 44, 27, 36, 44, 27, 27, 27, 27, 27, 27, 27,
+   70, 43, 57, 80, 44, 44, 43, 43, 36, 36, 62, 36, 62, 36, 36, 36,
+   36, 36, 36, 44, 43, 80, 44, 57, 27, 27, 27, 27,100, 44, 44, 44,
+    2,  2,  2,  2, 64, 44, 44, 44, 36, 36, 36, 36, 36, 36,183, 30,
+   36, 36, 36, 36, 36, 36,183, 27, 36, 36, 36, 36, 78, 36, 36, 36,
+   36, 36, 70, 80, 44,179, 27, 27,  2,  2,  2, 64, 44, 44, 44, 44,
+   36, 36, 36, 44, 93,  2,  2,  2, 36, 36, 36, 44, 27, 27, 27, 27,
+   36, 61, 44, 44, 27, 27, 27, 27, 36, 44, 44, 44, 93,  2, 64, 44,
+   44, 44, 44, 44,179, 27, 27, 27, 11, 47, 44, 44, 44, 44, 44, 44,
+   16,110, 44, 44, 44, 27, 27, 27, 36, 36, 43, 43, 44, 44, 44, 44,
+   27, 27, 27, 27, 27, 27, 27,100, 36, 36, 36, 36, 36, 57,184, 44,
+   36, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 57, 43,
+   27, 27, 27, 95, 44, 44, 44, 44,180, 27, 30,  2,  2, 44, 44, 44,
+   36, 43, 43,  2,  2, 44, 44, 44, 36, 36,183, 27, 27, 27, 44, 44,
+   87, 98, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43,
+   43, 43, 43, 60,  2,  2,  2, 44, 27, 27, 27,  7,  7,  7,  7,  7,
+   71, 70, 71, 44, 44, 44, 44, 57, 86, 87, 43, 85, 87, 60,185,  2,
+    2, 80, 44, 44, 44, 44, 79, 44, 43, 71, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 70, 43, 43, 87, 43, 43, 43, 80,  7,  7,  7,  7,  7,
+    2,  2, 94, 98, 44, 44, 44, 44, 36, 70,  2, 61, 44, 44, 44, 44,
+   36, 94, 86, 43, 43, 43, 43, 85, 98, 36, 63,  2, 59, 43, 60, 87,
+    7,  7,  7,  7,  7, 63, 63,  2,179, 27, 27, 27, 27, 27, 27, 27,
+   27, 27,100, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 86, 87,
+   43, 86, 85, 43,  2,  2,  2, 71, 70, 44, 44, 44, 44, 44, 44, 44,
+   36, 36, 36, 61, 61, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 62,
+   36, 36, 36, 36, 63, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 70,
+   86, 87, 43, 43, 43, 80, 44, 44, 43, 86, 62, 36, 36, 36, 61, 62,
+   61, 36, 62, 36, 36, 57, 71, 86, 85, 86, 90, 89, 90, 89, 86, 44,
+   61, 44, 44, 89, 44, 44, 62, 36, 36, 86, 44, 43, 43, 43, 80, 44,
+   43, 43, 80, 44, 44, 44, 44, 44, 36, 36, 94, 86, 43, 43, 43, 43,
+   86, 43, 85, 71, 36, 63,  2,  2,  7,  7,  7,  7,  7,  2, 93, 71,
+   86, 87, 43, 43, 85, 85, 86, 87, 85, 43, 36, 72, 44, 44, 44, 44,
+   36, 36, 36, 36, 36, 36, 36, 94, 86, 43, 43, 44, 86, 86, 43, 87,
+   60,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 36, 36, 43, 44,
+   86, 87, 43, 43, 43, 85, 87, 87, 60,  2, 61, 44, 44, 44, 44, 44,
+    2,  2,  2,  2,  2,  2, 64, 44, 36, 36, 36, 36, 36, 70, 87, 86,
+   43, 43, 43, 87, 63, 44, 44, 44, 86, 43, 43, 87, 43, 43, 44, 44,
+    7,  7,  7,  7,  7, 27,  2, 97, 43, 43, 43, 43, 87, 60, 44, 44,
+   27,100, 44, 44, 44, 44, 44, 62, 36, 36, 36, 61, 62, 44, 36, 36,
+   36, 36, 62, 61, 36, 36, 36, 36, 86, 86, 86, 89, 90, 57, 85, 71,
+   98, 87,  2, 64, 44, 44, 44, 44, 36, 36, 36, 36, 44, 36, 36, 36,
+   94, 86, 43, 43, 44, 43, 86, 86, 71, 72, 90, 44, 44, 44, 44, 44,
+   70, 43, 43, 43, 43, 71, 36, 36, 36, 70, 43, 43, 85, 70, 43, 60,
+    2,  2,  2, 59, 44, 44, 44, 44, 70, 43, 43, 85, 87, 43, 36, 36,
+   36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 85, 43,  2, 72,  2,
+    2, 64, 44, 44, 44, 44, 44, 44,  2,  2,  2,  2,  2, 44, 44, 44,
+   43, 43, 43, 80, 43, 43, 43, 87, 63,  2,  2, 44, 44, 44, 44, 44,
+    2, 36, 36, 36, 36, 36, 36, 36, 44, 43, 43, 43, 43, 43, 43, 43,
+   43, 43, 43, 43, 89, 43, 43, 43, 85, 43, 87, 80, 44, 44, 44, 44,
+   36, 36, 36, 61, 36, 62, 36, 36, 70, 43, 43, 80, 44, 80, 43, 57,
+   43, 43, 43, 70, 44, 44, 44, 44, 36, 36, 36, 62, 61, 36, 36, 36,
+   36, 36, 36, 36, 36, 86, 86, 90, 43, 89, 87, 87, 61, 44, 44, 44,
+   36, 70, 85,107, 64, 44, 44, 44, 43, 94, 36, 36, 36, 36, 36, 36,
+   36, 36, 86, 43, 43, 80, 44, 86, 85, 60,  2,  2,  2,  2,  2,  2,
+   27, 27, 91, 67, 67, 67, 56, 20,168, 67, 67, 67, 67, 67, 67, 67,
+   67, 44, 44, 44, 44, 44, 44, 93,105,105,105,105,105,105,105,181,
+    2,  2, 64, 44, 44, 44, 44, 44, 63, 64, 44, 44, 44, 44, 44, 44,
+   65, 65, 65, 65, 65, 65, 65, 65, 71, 36, 36, 70, 43, 43, 43, 43,
+   43, 43, 43, 44, 44, 44, 44, 44, 43, 43, 60, 44, 44, 44, 44, 44,
+   43, 43, 43, 60,  2,  2, 67, 67, 40, 40, 97, 44, 44, 44, 44, 44,
+    7,  7,  7,  7,  7,179, 27, 27, 27, 62, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 44, 44, 62, 36, 27, 27, 27, 30,  2, 64, 44, 44,
+   36, 36, 36, 36, 36, 61, 44, 57, 94, 86, 86, 86, 86, 86, 86, 86,
+   86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 44, 44, 44, 57,
+   43, 74, 40, 40, 40, 40, 40, 40, 40, 88, 80, 44, 44, 44, 44, 44,
+   86, 44, 44, 44, 44, 44, 44, 44, 40, 40, 52, 40, 40, 40, 52, 81,
+   36, 61, 44, 44, 44, 44, 44, 44, 44, 61, 44, 44, 44, 44, 44, 44,
+   36, 61, 62, 44, 44, 44, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44,
+   36, 36, 36, 36, 36, 44, 50, 60, 65, 65, 44, 44, 44, 44, 44, 44,
+   43, 43, 43, 43, 43, 43, 43, 44, 43, 43, 43, 80, 44, 44, 44, 44,
+   67, 67, 67, 92, 55, 67, 67, 67, 67, 67,186, 87, 43, 67,186, 86,
+   86,187, 65, 65, 65, 84, 43, 43, 43, 76, 50, 43, 43, 43, 67, 67,
+   67, 67, 67, 67, 67, 43, 43, 67, 67, 43, 76, 44, 44, 44, 44, 44,
+   27, 27, 44, 44, 44, 44, 44, 44, 11, 11, 11, 11, 11, 16, 16, 16,
+   16, 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 16,
+   16, 16,110, 16, 16, 16, 16, 16, 11, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16, 47, 11, 44, 47, 48, 47, 48, 11, 47, 11,
+   11, 11, 11, 16, 16,150,150, 16, 16, 16,150, 16, 16, 16, 16, 16,
+   16, 16, 11, 48, 11, 47, 48, 11, 11, 11, 47, 11, 11, 11, 47, 16,
+   16, 16, 16, 16, 11, 48, 11, 47, 11, 11, 47, 47, 44, 11, 11, 11,
+   47, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 11, 11,
+   11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 44, 11, 11, 11, 11,
+   31, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 33, 16, 16,
+   16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 31, 16, 16,
+   16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 31, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 11,
+   11, 11, 11, 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16,
+   11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, 32, 44,  7,
+    7,  7,  7,  7,  7,  7,  7,  7, 43, 43, 43, 76, 67, 50, 43, 43,
+   43, 43, 43, 43, 43, 43, 76, 67, 67, 67, 50, 67, 67, 67, 67, 67,
+   67, 67, 76, 21,  2,  2, 44, 44, 44, 44, 44, 44, 44, 57, 43, 43,
+   16, 16, 16, 16, 16, 39, 16, 16, 16, 16, 16, 16, 16, 16, 16,110,
+   44, 44,150, 16, 16,110, 44, 44, 43, 43, 43, 80, 43, 43, 43, 43,
+   43, 43, 43, 43, 80, 57, 43, 43, 43, 57, 80, 43, 43, 80, 44, 44,
+   40, 40, 40, 40, 40, 40, 40, 44, 44, 44, 44, 44, 44, 44, 44, 57,
+   43, 43, 43, 74, 40, 40, 40, 44,  7,  7,  7,  7,  7, 44, 44, 77,
+   36, 36, 36, 36, 36, 36, 36, 80, 36, 36, 36, 36, 36, 36, 43, 43,
+    7,  7,  7,  7,  7, 44, 44, 96, 36, 36, 36, 36, 36, 83, 43, 43,
+   36, 36, 36, 61, 36, 36, 62, 61, 36, 36, 61,179, 27, 27, 27, 27,
+   16, 16, 43, 43, 43, 74, 44, 44, 27, 27, 27, 27, 27, 27,163, 27,
+  188, 27,100, 44, 44, 44, 44, 44, 27, 27, 27, 27, 27, 27, 27,163,
+   27, 27, 27, 27, 27, 27, 27, 44, 36, 36, 62, 36, 36, 36, 36, 36,
+   62, 61, 61, 62, 62, 36, 36, 36, 36, 61, 36, 36, 62, 62, 44, 44,
+   44, 61, 44, 62, 62, 62, 62, 36, 62, 61, 61, 62, 62, 62, 62, 62,
+   62, 61, 61, 62, 36, 61, 36, 36, 36, 61, 36, 36, 62, 36, 61, 61,
+   36, 36, 36, 36, 36, 62, 36, 36, 62, 36, 62, 36, 36, 62, 36, 36,
+    8, 44, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 44, 44,
+   55, 67, 67, 67, 67, 67, 67, 67, 27, 27, 27, 27, 27, 27, 91, 67,
+   67, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 67, 67, 67,
+   67, 92, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 92, 44, 44, 44,
+   67, 44, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 25, 41, 41,
+   67, 67, 67, 67, 44, 44, 67, 67, 67, 67, 67, 92, 44, 55, 67, 67,
+   67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 67, 55,
+   67, 67, 67, 44, 44, 44, 44, 67, 67, 92, 67, 67, 67, 67, 67, 67,
+   79, 44, 44, 44, 44, 44, 44, 44,171,171,171,171,171,171,171, 44,
+  171,171,171,171,171,171,171,  0,  0,  0, 29, 21, 21, 21, 23, 21,
+   22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21,  9,  9,  9,
+    9, 22, 21, 18, 24, 16, 24,  5,  5,  5,  5, 22, 25, 18, 25,  0,
+   23, 23, 26, 21, 24, 26,  7, 20, 25,  1, 26, 24, 26, 25, 15, 15,
+   24, 15,  7, 19, 15, 21,  9, 25,  9,  5,  5, 25,  5,  9,  5,  7,
+    7,  7,  9,  8,  8,  5,  7,  5,  6,  6, 24, 24,  6, 24, 12, 12,
+    2,  2,  6,  5,  9, 21,  9,  2,  2,  9, 25,  9, 26, 12, 11, 11,
+    2,  6,  5, 21, 17,  2,  2, 26, 26, 23,  2, 12, 17, 12, 21, 12,
+   12, 21,  7,  2,  2,  7,  7, 21, 21,  2,  1,  1, 21, 23, 26, 26,
+    1, 21,  6,  7,  7, 12, 12,  7, 21,  7, 12,  1, 12,  6,  6, 12,
+   12, 26,  7, 26, 26,  7,  2,  1, 12,  2,  6,  2, 24,  7,  7,  6,
+    1, 12, 12, 10, 10, 10, 10, 12, 21,  6,  2, 10, 10,  2, 15, 26,
+   26,  2,  2, 21,  7, 10, 15,  7,  2, 23, 21, 26, 10,  7, 21, 15,
+   15,  2, 17,  7, 29,  7,  7, 22, 18,  2, 14, 14, 14,  7, 10, 21,
+   17, 21, 11, 12,  5,  2,  5,  6,  8,  8,  8, 24,  5, 24,  2, 24,
+    9, 24, 24,  2, 29, 29, 29,  1, 17, 17, 20, 19, 22, 20, 27, 28,
+    1, 29, 21, 20, 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29,
+    1,  2, 15,  6, 18,  6, 23,  2, 12, 11,  9, 26, 26,  9, 26,  5,
+    5, 26, 14,  9,  5, 14, 14, 15, 25, 26, 26, 22, 18, 26, 18, 25,
+   18, 22,  5, 12,  2,  5, 22, 21, 21, 22, 18, 17, 26,  6,  7, 14,
+   17, 22, 18, 18, 26, 14, 17,  6, 14,  6, 12, 24, 24,  6, 26, 15,
+    6, 21, 11, 21, 24,  9,  6,  9, 23, 26,  6, 10,  4,  4,  3,  3,
+    7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 25,  2, 25, 24,  2, 15,
+   12, 15, 14,  2, 21, 14,  7, 15, 12, 17, 21,  1, 26, 10, 10,  1,
+   23, 15,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  0, 10, 11, 12,
+   13,  0, 14,  0,  0,  0,  0,  0, 15,  0, 16,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0, 17, 18, 19,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 20,
+    0, 21, 22, 23,  0,  0,  0, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+   33, 34,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 35,  0, 36,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   37,  0,  0,  0,  0,  0,  0,  0,  0,  0, 38, 39,  0,  0,  0,  0,
+    0,  0, 40, 41, 42,  0, 43,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  1,  2,  0,  0,  0,  0,  3,  0,  0,  0,  4,  5,
+    6,  7,  0,  8,  9, 10,  0, 11, 12, 13, 14, 15, 16, 17, 16, 18,
+   16, 19, 16, 19, 16, 19,  0, 19, 16, 20, 16, 19, 21, 19,  0, 22,
+   23, 24, 25, 26, 27, 28, 29, 30, 31,  0, 32,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0, 33,  0,  0,  0,  0,  0,  0, 34,  0,  0, 35,
+    0,  0, 36,  0, 37,  0,  0,  0, 38, 39, 40, 41, 42, 43, 44, 45,
+   46,  0,  0, 47,  0,  0,  0, 48,  0,  0,  0, 49,  0,  0,  0,  0,
+    0,  0,  0, 50,  0, 51,  0, 52, 53,  0, 54,  0,  0,  0,  0,  0,
+    0, 55, 56, 57,  0,  0,  0,  0, 58,  0,  0, 59, 60, 61, 62, 63,
+    0,  0, 64, 65,  0,  0,  0, 66,  0,  0,  0,  0, 67,  0,  0,  0,
+   68,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 69,
+    0,  0,  0, 70,  0, 71,  0,  0, 72,  0,  0, 73,  0,  0,  0,  0,
+    0,  0,  0,  0, 74,  0,  0,  0,  0,  0, 75, 76,  0, 77, 78,  0,
+    0, 79, 80,  0, 81, 62,  0, 82, 83,  0,  0, 84, 85, 86,  0,  0,
+    0, 87,  0, 88,  0,  0, 51, 89, 51,  0, 90,  0, 91,  0,  0,  0,
+   80,  0,  0,  0, 92, 93,  0, 94, 95, 96, 97,  0,  0,  0,  0,  0,
+   51,  0,  0,  0,  0, 98, 99,  0,  0,  0,  0,  0,  0,100,  0,  0,
+    0,  0,  0,101,102,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,103,
+    0,  0,104,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,105,106,  0,
+    0,107,  0,  0,  0,  0,  0,  0,108,  0,109,  0,102,  0,  0,  0,
+    0,  0,110,111,  0,  0,  0,  0,  0,  0,  0,112,  0,  0,  0,  0,
+    0,  0,  0,113,  0,114,  0,  0,  0,  0,  0,  0,  1,  2,  3,  4,
+    5,  6,  7,  0,  8,  0,  0,  0,  0,  9, 10, 11, 12,  0,  0,  0,
+    0, 13,  0,  0, 14, 15,  0, 16,  0, 17, 18,  0,  0, 19,  0, 20,
+   21,  0,  0,  0,  0,  0, 22, 23,  0, 24, 25,  0,  0, 26,  0,  0,
+    0, 27,  0,  0, 28, 29, 30, 31,  0,  0,  0, 32, 33, 34,  0,  0,
+   33,  0,  0, 35, 33,  0,  0,  0, 33, 36,  0,  0,  0,  0,  0, 37,
+   38,  0,  0,  0,  0,  0,  0, 39, 40,  0,  0,  0,  0,  0,  0, 41,
+   42,  0,  0,  0,  0, 43,  0, 44,  0,  0,  0, 45, 46,  0,  0,  0,
+   47,  0,  0,  0,  0,  0,  0, 48, 49,  0,  0,  0,  0, 50,  0,  0,
+    0, 51,  0, 52,  0, 53,  0,  0,  0,  0, 54,  0,  0,  0,  0, 55,
+    0, 56,  0,  0,  0,  0, 57, 58,  0,  0,  0, 59, 60,  0,  0,  0,
+    0,  0,  0, 61, 52,  0, 62, 63,  0,  0, 64,  0,  0,  0, 65, 66,
+    0,  0,  0, 67,  0, 68, 69, 70, 71, 72,  1, 73,  0, 74, 75, 76,
+    0,  0, 77, 78,  0,  0,  0, 79,  0,  0,  1,  1,  0,  0, 80,  0,
+    0, 81,  0,  0,  0,  0, 77, 82,  0, 83,  0,  0,  0,  0,  0, 78,
+   84,  0, 85,  0, 52,  0,  1, 78,  0,  0, 86,  0,  0, 87,  0,  0,
+    0,  0,  0, 88, 57,  0,  0,  0,  0,  0,  0, 89, 90,  0,  0, 84,
+    0,  0, 33,  0,  0, 91,  0,  0,  0,  0, 92,  0,  0,  0,  0, 49,
+    0,  0, 93,  0,  0,  0,  0, 94, 95,  0,  0, 96,  0,  0, 97,  0,
+    0,  0, 98,  0,  0,  0, 99,  0,  0,  0,  0,100,101, 93,  0,  0,
+  102,  0,  0,  0, 84,  0,  0,103,  0,  0,  0,104,105,  0,  0,106,
+  107,  0,  0,  0,  0,  0,  0,108,  0,  0,109,  0,  0,  0,  0,110,
+   33,  0,111,112,113, 35,  0,  0,114,  0,  0,  0,115,  0,  0,  0,
+    0,  0,  0,116,  0,  0,117,  0,  0,  0,  0,118, 88,  0,  0,  0,
+    0,  0, 57,  0,  0,  0,  0, 52,119,  0,  0,  0,  0,120,  0,  0,
+  121,  0,  0,  0,  0,119,  0,  0,122,  0,  0,  0,  0,  0,  0,123,
+    0,  0,  0,124,  0,  0,  0,125,  0,126,  0,  0,  0,  0,127,128,
+  129,  0,130,  0,131,  0,  0,  0,132,133,134,  0, 77,  0,  0,  0,
+    0,  0, 35,  0,  0,  0,135,  0,  0,  0,136,  0,  0,137,  0,  0,
+  138,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  2,  3,  4,
+    5,  6,  7,  4,  4,  8,  9, 10,  1, 11, 12, 13, 14, 15, 16, 17,
+   18,  1,  1,  1, 19,  1,  0,  0, 20, 21, 22,  1, 23,  4, 21, 24,
+   25, 26, 27, 28, 29, 30,  0,  0,  1,  1, 31,  0,  0,  0, 32, 33,
+   34, 35,  1, 36, 37,  0,  0,  0,  0, 38,  1, 39, 14, 39, 40, 41,
+   42,  0,  0,  0, 43, 36, 44, 45, 21, 45, 46,  0,  0,  0, 19,  1,
+   21,  0,  0, 47,  0, 38, 48,  1,  1, 49, 49, 50,  0,  0, 51,  0,
+    0,  0, 52,  1,  0,  0, 38, 14,  4,  1,  1,  1, 53, 21, 43, 52,
+   54, 21, 35,  1,  0,  0,  0, 55,  0,  0,  0, 56, 57, 58,  0,  0,
+    0,  0,  0, 59,  0, 60,  0,  0,  0,  0, 61, 62,  0,  0, 63,  0,
+    0,  0, 64,  0,  0,  0, 65,  0,  0,  0, 66,  0,  0,  0, 67,  0,
+    0,  0, 68,  0,  0, 69, 70,  0, 71, 72, 73, 74, 75, 76,  0,  0,
+    0, 77,  0,  0,  0, 78, 79,  0,  0,  0,  0, 47,  0,  0,  0, 49,
+    0, 80,  0,  0,  0, 62,  0,  0, 63,  0,  0, 81,  0,  0, 82,  0,
+    0,  0, 83,  0,  0, 19, 84,  0, 62,  0,  0,  0,  0, 49,  1, 85,
+    1, 52, 15, 86, 36, 10, 21, 87,  0, 55,  0,  0,  0,  0, 19, 10,
+    1,  0,  0,  0,  0,  0, 88,  0,  0, 89,  0,  0, 88,  0,  0,  0,
+    0, 78,  0,  0, 87,  9, 12,  4, 90,  8, 91, 47,  0, 58, 50,  0,
+   21,  1, 21, 92, 93,  1,  1,  1,  1, 94, 95, 96, 97,  1, 98, 58,
+   81, 99,100,  4, 58,  0,  0,  0,  0,  0,  0, 19, 50,  0,  0,  0,
+    0,  0,  0, 61,  0,  0,101,102,  0,  0,103,  0,  0,  1,  1, 50,
+    0,  0,  0, 38,  0, 63,  0,  0,  0,  0,  0, 62,  0,  0,104, 68,
+   61,  0,  0,  0, 78,  0,  0,  0,105,106, 58, 38, 81,  0,  0,  0,
+    0,  0,  0,107,  1, 14,  4, 12, 84,  0,  0,  0,  0, 38, 87,  0,
+    0,  0,  0,108,  0,  0,109, 61,  0,110,  0,  0,  0,  1,  0,  0,
+    0,  0, 19, 58,  0,  0,  0, 51,  0,111, 14, 52,112, 41,  0,  0,
+   62,  0,  0, 61,  0,  0,113,  0, 87,  0,  0,  0, 61, 62,  0,  0,
+   62,  0, 89,  0,  0,113,  0,  0,  0,  0,114,  0,  0,  0, 78, 55,
+    0, 38,  1, 58,  1, 58,  0,  0, 63, 89,  0,  0,115,  0,  0,  0,
+   55,  0,  0,  0,  0,115,  0,  0,  0,  0, 61,  0,  0,  0,  0, 79,
+    0, 61,  0,  0,  0,  0, 56,  0, 89, 80,  0,  0, 79,  0,  0,  0,
+    8, 91,  0,  0,  1, 87,  0,  0,116,  0,  0,  0,  0,  0,  0,117,
+    0,118,119,120,121,  0,104,  4,122, 49, 23,  0,  0,  0, 38, 50,
+   38, 58,  0,  0,  1, 87,  1,  1,  1,  1, 39,  1, 48,105, 87,  0,
+    0,  0,  0,  1,  0,  0,  0,123,  4,122,  0,  0,  0,  1,124,  0,
+    0,  0,  0,  0,230,230,230,230,230,232,220,220,220,220,232,216,
+  220,220,220,220,220,202,202,220,220,220,220,202,202,220,220,220,
+    1,  1,  1,  1,  1,220,220,220,220,230,230,230,230,240,230,220,
+  220,220,230,230,230,220,220,  0,230,230,230,220,220,220,220,230,
+  232,220,220,230,233,234,234,233,234,234,233,230,  0,  0,  0,230,
+    0,220,230,230,230,230,220,230,230,230,222,220,230,230,220,220,
+  230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20,
+   21, 22,  0, 23,  0, 24, 25,  0,230,220,  0, 18, 30, 31, 32,  0,
+    0,  0,  0, 27, 28, 29, 30, 31, 32, 33, 34,230,230,220,220,230,
+  220,230,230,220, 35,  0,  0,  0,  0,  0,230,230,230,  0,  0,230,
+  230,  0,220,230,230,220,  0,  0,  0, 36,  0,  0,230,220,230,230,
+  220,220,230,220,220,230,220,230,220,230,230,  0,  0,220,  0,  0,
+  230,230,  0,230,  0,230,230,230,230,230,  0,  0,  0,220,220,220,
+  230,220,220,220,230,230,  0,220, 27, 28, 29,230,  7,  0,  0,  0,
+    0,  9,  0,  0,  0,230,220,230,230,  0,  0,  0,  0,  0,230,  0,
+    0, 84, 91,  0,  0,  0,  0,  9,  9,  0,  0,  0,  0,  0,  9,  0,
+  103,103,  9,  0,107,107,107,107,118,118,  9,  0,122,122,122,122,
+  220,220,  0,  0,  0,220,  0,220,  0,216,  0,  0,  0,129,130,  0,
+  132,  0,  0,  0,  0,  0,130,130,130,130,  0,  0,130,  0,230,230,
+    9,  0,230,230,  0,  0,220,  0,  0,  0,  0,  7,  0,  9,  9,  0,
+    9,  9,  0,  0,  0,230,  0,  0,  0,228,  0,  0,  0,222,230,220,
+  220,  0,  0,  0,230,  0,  0,220,230,220,  0,220,230,230,230,  0,
+    0,  0,  9,  9,  0,  0,  7,  0,230,  0,  1,  1,  1,  0,  0,  0,
+  230,234,214,220,202,230,230,230,230,230,232,228,228,220,218,230,
+  233,220,230,220,230,230,  1,  1,  1,  1,  1,230,  0,  1,  1,230,
+  220,230,  1,  1,  0,  0,218,228,232,222,224,224,  0,  8,  8,  0,
+    0,  0,  0,220,230,  0,230,230,220,  0,  0,230,  0,  0, 26,  0,
+    0,220,  0,230,230,  1,220,  0,  0,230,220,  0,  0,  0,220,220,
+    0,  0,230,220,  0,  9,  7,  0,  0,  7,  9,  0,  0,  0,  9,  7,
+    6,  6,  0,  0,  0,  0,  1,  0,  0,216,216,  1,  1,  1,  0,  0,
+    0,226,216,216,216,216,216,  0,220,220,220,  0,232,232,220,230,
+  230,230,  7,  0, 16, 17, 17, 33, 17, 49, 17, 17, 84, 97,135,145,
+   26, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17,177,  0,  1,  2,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  4,  3,  3,  3,  3,  3,  5,  3,
+    3,  3,  3,  3,  6,  7,  8,  3,  3,  3,  3,  3,  9, 10, 11, 12,
+   13,  3,  3,  3,  3,  3,  3,  3,  3, 14,  3, 15,  3,  3,  3,  3,
+    3,  3, 16, 17, 18, 19, 20, 21,  3,  3,  3, 22, 23, 24,  3,  3,
+    3,  3,  3,  3, 25,  3,  3,  3,  3,  3,  3,  3,  3, 26,  3,  3,
+   27, 28,  0,  1,  0,  0,  0,  0,  0,  1,  0,  2,  0,  0,  0,  3,
+    0,  0,  0,  3,  0,  0,  0,  0,  0,  4,  0,  5,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0,  0,  0,  7,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8,  9,  0,  0,  0,
+    0,  0,  0,  9,  0,  9,  0,  0,  0,  0,  0,  0,  0, 10, 11, 12,
+   13,  0,  0, 14, 15, 16,  6,  0, 17, 18, 19, 19, 19, 20, 21, 22,
+   23, 24, 19, 25,  0, 26, 27, 19, 19, 28, 29, 30,  0, 31,  0,  0,
+    0,  8,  0,  0,  0,  0,  0,  0,  0, 19, 28,  0, 32, 33,  9, 34,
+   35, 19,  0,  0, 36, 37, 38, 39, 40, 19,  0, 41, 42, 43, 44, 31,
+    0,  1, 45, 42,  0,  0,  0,  0,  0, 32, 14, 14,  0,  0,  0,  0,
+   14,  0,  0, 46, 47, 47, 47, 47, 48, 49, 47, 47, 47, 47, 50, 51,
+   52, 53, 43, 21,  0,  0,  0,  0,  0,  0,  0, 54,  6, 55,  0, 14,
+   19,  1,  0,  0,  0,  0, 56, 57,  0,  0,  0,  0,  0, 19, 58, 31,
+    0,  0,  0,  0,  0,  0,  0, 59, 14,  0,  0,  0,  0,  1,  0,  2,
+    0,  0,  0,  3,  0,  0,  0, 60, 61,  0,  0,  0,  0,  0,  0,  0,
+    1,  0,  0,  0,  0,  0,  2,  3,  0,  4,  5,  0,  0,  6,  0,  0,
+    0,  7,  0,  0,  0,  1,  1,  0,  0,  8,  9,  0,  8,  9,  0,  0,
+    0,  0,  8,  9, 10, 11, 12,  0,  0,  0, 13,  0,  0,  0,  0, 14,
+   15, 16, 17,  0,  0,  0,  1,  0,  0, 18, 19,  0,  0,  0, 20,  0,
+    0,  0,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  0,  8,
+   21,  9,  0,  0, 22,  0,  0,  0,  0,  1,  0, 23, 24, 25,  0,  0,
+   26,  0,  0,  0,  8, 21, 27,  0,  1,  0,  0,  1,  1,  1,  1,  0,
+    1, 28, 29, 30,  0, 31, 32, 20,  1,  1,  0,  0,  0,  8, 21,  9,
+    1,  4,  5,  0,  0,  0, 33,  9,  0,  1,  1,  1,  0,  8, 21, 21,
+   21, 21, 34,  1, 35, 21, 21, 21,  9, 36,  0,  0, 37, 38,  1,  0,
+   39,  0,  0,  0,  1,  0,  1,  0,  0,  0,  0,  8, 21,  9,  1,  0,
+    0,  0, 40,  0,  8, 21, 21, 21, 21, 21, 21, 21, 21,  9,  0,  1,
+    1,  1,  1,  8, 21, 21, 21,  9,  0,  0,  0, 41,  0, 42, 43,  0,
+    0,  0,  1, 44,  0,  0,  0, 45,  8,  9,  1,  0,  0,  0,  8, 21,
+   21, 21,  9,  0,  1,  0,  1,  1,  8, 21, 21,  9,  0,  4,  5,  8,
+    9,  1,  0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  9, 10, 11, 11, 11, 11, 12, 13,
+   13, 13, 13, 14, 15, 16, 17, 18, 19, 20, 21, 13, 22, 13, 13, 13,
+   13, 23, 24, 24, 25, 26, 13, 13, 13, 27, 28, 29, 13, 30, 31, 32,
+   33, 34, 35, 36,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7, 37,  7, 38, 39,  7, 40,  7,  7,
+    7, 41, 13, 42,  7,  7, 43,  7, 44, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 45,  0,  0,  1,  2,  2,  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, 32, 33, 34, 35, 36, 37, 37,
+   37, 37, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+   51, 52,  2,  2, 53, 54, 55, 56, 57, 58, 59, 59, 59, 59, 60, 59,
+   59, 59, 59, 59, 59, 59, 61, 61, 59, 59, 59, 59, 62, 63, 64, 65,
+   66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 59, 70, 70,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 79, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 80, 80, 80, 81,
+   82, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 32, 32,
+   32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+   32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+   32, 32, 32, 32, 32, 95, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+   96, 96, 96, 96, 96, 96, 96, 96, 70, 70, 97, 98, 99,100,101,101,
+  102,103,104,105,106,107,108,109,110,111, 96,112,113,114,115,116,
+  117,118,119,119,120,121,122,123,124,125,126,127,128,129,130,131,
+  132, 96,133,134,135,136,137,138,139,140,141,142,143, 96,144,145,
+   96,146,147,148,149, 96,150,151,152,153,154,155,156, 96,157,158,
+  159,160, 96,161,162,163,164,164,164,164,164,164,164,165,166,164,
+  167, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+   96, 96, 96, 96, 96,168,169,169,169,169,169,169,169,169,170, 96,
+   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,171,171,
+  171,171,172, 96, 96, 96,173,173,173,173,174,175,176,177, 96, 96,
+   96, 96,178,179,180,181,182,182,182,182,182,182,182,182,182,182,
+  182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,
+  182,182,182,182,182,183,182,182,182,182,182,182,184,184,184,185,
+  186, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+   96, 96, 96, 96, 96,187,188,189,190,191,191,192, 96, 96, 96, 96,
+   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,193,194,
+   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+   96, 96, 96, 96,195,196, 59,197,198,199,200,201,202, 96,203,204,
+  205, 59, 59,206, 59,207,208,208,208,208,208,209, 96, 96, 96, 96,
+   96, 96, 96, 96,210, 96,211,212,213, 96, 96,214, 96, 96, 96,215,
+   96, 96, 96, 96, 96,216,217,218,219, 96, 96, 96, 96, 96,220,221,
+  222, 96,223,224, 96, 96,225,226, 59,227,228, 96, 59, 59, 59, 59,
+   59, 59, 59,229,230,231,232,233, 59, 59,234,235, 59,236, 96, 96,
+   96, 96, 96, 96, 96, 96, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 70, 70,237, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 70, 70, 70,238, 70,239, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 70, 70,240, 70, 70, 70, 70, 70, 70, 70, 70, 70,241, 70, 70,
+   70, 70,242, 96, 96, 96, 70, 70, 70, 70,243, 96, 96, 96, 96, 96,
+   96, 96, 96, 96, 96, 96, 70, 70, 70, 70, 70, 70,244, 70, 70, 70,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,245, 96, 96,
+   96, 96, 96, 96, 96, 96,246, 96,247,248,  0,  1,  2,  2,  0,  1,
+    2,  2,  2,  3,  4,  5,  0,  0,  0,  0,  0, 19, 19, 19, 19, 19,
+   19, 19, 19, 19, 19,  0,  0,  0, 19,  0, 19,  0,  0,  0,  0,  0,
+   26, 26,  1,  1,  1,  1,  9,  9,  9,  9,  0,  9,  9,  9,  2,  2,
+    9,  9,  9,  9,  0,  9,  2,  2,  2,  2,  9,  0,  9,  0,  9,  9,
+    9,  2,  9,  2,  9,  9,  9,  9,  2,  9,  9,  9, 55, 55, 55, 55,
+   55, 55,  6,  6,  6,  6,  6,  1,  1,  6,  2,  4,  4,  4,  4,  4,
+    4,  4,  4,  4,  4,  2,  2, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14,  2,  2,  2,  2, 14, 14,  2,  2,  2,  3,  3,  3,  3,  3,  0,
+    3,  3,  0,  3,  3,  3,  3,  3,  3,  0,  3,  3,  3,  1,  1,  1,
+    3,  3,  1,  3,  3,  3, 37, 37, 37, 37, 37, 37,  2, 37, 37, 37,
+   37,  2,  2, 37, 37, 37, 38, 38, 38, 38, 38, 38,  2,  2, 64, 64,
+   64, 64, 64, 64, 64,  2,  2, 64, 64, 64, 90, 90, 90, 90, 90, 90,
+    2,  2, 90, 90, 90,  2, 95, 95, 95, 95,  2,  2, 95,  2,  3,  3,
+    3,  2,  3,  3,  2,  2,  3,  3,  0,  3,  7,  7,  7,  7,  7,  1,
+    1,  1,  1,  7,  7,  7,  0,  0,  7,  7,  5,  5,  5,  5,  2,  5,
+    5,  5,  5,  2,  2,  5,  5,  2,  5,  5,  5,  2,  5,  2,  2,  2,
+    5,  5,  5,  5,  2,  2,  5,  5,  5,  2,  2,  2,  2,  5,  5,  5,
+    2,  5,  2, 11, 11, 11, 11, 11, 11,  2,  2,  2,  2, 11, 11,  2,
+    2, 11, 11, 11, 11, 11, 11,  2, 11, 11,  2, 11, 11,  2, 11, 11,
+    2,  2,  2, 11,  2,  2, 11,  2, 11,  2,  2,  2, 11, 11,  2, 10,
+   10, 10, 10, 10, 10, 10, 10, 10,  2, 10, 10,  2, 10, 10, 10, 10,
+    2,  2, 10,  2,  2,  2,  2,  2, 10, 10,  2, 21, 21, 21, 21, 21,
+   21, 21, 21,  2,  2, 21, 21,  2, 21, 21, 21, 21,  2,  2, 21, 21,
+    2, 21,  2,  2, 21, 21,  2,  2, 22, 22,  2, 22, 22, 22, 22, 22,
+   22,  2, 22,  2, 22, 22, 22, 22,  2,  2,  2, 22, 22,  2,  2,  2,
+    2, 22, 22,  2,  2,  2, 22, 22, 22, 22, 23, 23, 23, 23, 23,  2,
+   23, 23, 23, 23,  2,  2,  2, 23, 23,  2, 23, 23, 23,  2,  2, 23,
+    2,  2,  2,  2, 23, 23,  2,  2,  2, 23, 16, 16, 16, 16, 16,  2,
+   16, 16,  2, 16, 16, 16, 16, 16,  2,  2,  2, 16, 16,  2,  2,  2,
+   16, 16, 20, 20, 20, 20, 20,  2, 20, 20,  2,  2, 20, 20,  2, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36,  2,  2,  2, 36, 36, 36, 36,
+    2, 36,  2, 36,  2,  2,  2,  2, 36,  2,  2,  2,  2, 36, 36,  2,
+   36,  2, 36,  2,  2,  2,  2, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+   24,  2,  2,  2,  2,  0,  2, 18, 18,  2, 18,  2, 18, 18, 18, 18,
+   18,  2, 18, 18, 18, 18,  2, 18,  2, 18, 18, 18,  2,  2, 18,  2,
+   18,  2, 25, 25, 25, 25,  2, 25, 25, 25, 25,  2,  2,  2, 25,  2,
+   25, 25, 25,  0,  0,  0,  0, 25, 25,  2, 33, 33, 33, 33,  8,  8,
+    8,  8,  8,  8,  2,  8,  2,  8,  2,  2,  8,  8,  8,  0, 12, 12,
+   12, 12, 30, 30, 30, 30, 30,  2, 30, 30, 30, 30,  2,  2, 30, 30,
+   30,  2,  2, 30, 30, 30, 30,  2,  2,  2, 29, 29, 29, 29, 29, 29,
+    2,  2, 28, 28, 28, 28, 34, 34, 34, 34, 34,  2,  2,  2, 35, 35,
+   35, 35, 35, 35, 35,  0,  0,  0, 35, 35, 35,  2,  2,  2, 45, 45,
+   45, 45, 45, 45,  2,  2,  2,  2,  2, 45, 44, 44, 44, 44, 44,  0,
+    0,  2, 43, 43, 43, 43, 46, 46, 46, 46, 46,  2, 46, 46, 31, 31,
+   31, 31, 31, 31,  2,  2, 32, 32,  0,  0, 32,  0, 32, 32, 32, 32,
+   32, 32, 32, 32,  2,  2, 32,  2,  2,  2, 32, 32, 32,  2, 28, 28,
+    2,  2, 48, 48, 48, 48, 48, 48, 48,  2, 48,  2,  2,  2, 52, 52,
+   52, 52, 52, 52,  2,  2, 52,  2,  2,  2, 58, 58, 58, 58, 58, 58,
+    2,  2, 58, 58, 58,  2,  2,  2, 58, 58, 54, 54, 54, 54,  2,  2,
+   54, 54, 91, 91, 91, 91, 91, 91, 91,  2, 91,  2,  2, 91, 91, 91,
+    2,  2,  1,  1,  1,  2, 62, 62, 62, 62, 62,  2,  2,  2, 62, 62,
+   62,  2, 76, 76, 76, 76, 93, 93, 93, 93, 70, 70, 70, 70,  2,  2,
+    2, 70, 70, 70,  2,  2,  2, 70, 70, 70, 73, 73, 73, 73,  6,  2,
+    2,  2,  8,  8,  8,  2,  2,  8,  8,  8,  1,  1,  1,  0,  1,  0,
+    1,  1,  1,  0,  0,  0,  0,  1,  0,  0,  1,  1,  0,  2, 19, 19,
+    9,  9,  9,  9,  9,  6, 19,  9,  9,  9,  9,  9, 19, 19,  9,  9,
+    9, 19,  6, 19, 19, 19, 19, 19, 19,  9,  9,  9,  2,  2,  2,  9,
+    2,  9,  2,  9,  9,  9,  1,  1,  0,  0,  0,  2,  0,  0,  0, 19,
+    2,  2,  0,  0,  0, 19,  0,  0,  0,  2, 19,  2,  2,  2,  0,  2,
+    2,  2,  1,  2,  2,  2,  0,  0,  9,  0,  0,  0, 19, 19, 27, 27,
+   27, 27,  2,  2,  0,  0,  0,  0,  2,  0, 56, 56, 56, 56,  2, 55,
+   55, 55, 61, 61, 61, 61,  2,  2,  2, 61, 61,  2,  2,  2,  0,  0,
+    2,  2, 13, 13, 13, 13, 13, 13,  2, 13, 13, 13,  2,  2,  0, 13,
+    0, 13,  0, 13, 13, 13, 13, 13,  1,  1,  1,  1, 12, 12,  2, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,  1,  1,  0,  0, 15,
+   15, 15,  0, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,  0,  2, 26,
+   26, 26, 26, 26, 26, 26,  2, 12, 12, 12, 12, 12, 12,  2, 12, 12,
+   12,  0, 39, 39, 39, 39, 39,  2,  2,  2, 39, 39, 39,  2, 86, 86,
+   86, 86, 77, 77, 77, 77, 79, 79, 79, 79, 19, 19, 19,  2, 19, 19,
+    2, 19,  2, 19, 19, 19, 19, 19,  2,  2,  2,  2, 19, 19, 60, 60,
+   60, 60, 60,  2,  2,  2, 65, 65, 65, 65, 75, 75, 75, 75, 75, 75,
+    2,  2,  2,  2, 75, 75, 69, 69, 69, 69, 69, 69,  0, 69, 74, 74,
+   74, 74,  2,  2,  2, 74, 12,  2,  2,  2, 84, 84, 84, 84, 84, 84,
+    2,  0, 84, 84,  2,  2,  2,  2, 84, 84, 33, 33, 33,  2, 68, 68,
+   68, 68, 68, 68, 68,  2, 68, 68,  2,  2, 92, 92, 92, 92, 92, 92,
+   92,  2,  2,  2,  2, 92, 87, 87, 87, 87, 87, 87, 87,  2, 19,  9,
+   19, 19, 19, 19,  0,  0, 87, 87,  2,  2,  2,  2,  2, 12,  2,  2,
+    2,  4, 14,  2, 14,  2, 14, 14,  2, 14, 14,  2, 14, 14,  2,  2,
+    2,  3,  3,  3,  0,  0,  2,  2,  3,  3,  1,  1,  6,  6,  3,  2,
+    3,  3,  3,  2,  2,  0,  2,  0,  0,  0,  0,  0, 17, 17, 17, 17,
+    0,  0,  2,  2, 12, 12, 49, 49, 49, 49,  2, 49, 49, 49, 49, 49,
+   49,  2, 49, 49,  2, 49, 49, 49,  2,  2,  9,  2,  2,  2,  0,  1,
+    2,  2, 71, 71, 71, 71, 71,  2,  2,  2, 67, 67, 67, 67, 67,  2,
+    2,  2, 42, 42, 42, 42,  2, 42, 42, 42, 41, 41, 41, 41, 41, 41,
+   41,  2,118,118,118,118,118,118,118,  2, 53, 53, 53, 53, 53, 53,
+    2, 53, 59, 59, 59, 59, 59, 59,  2,  2, 40, 40, 40, 40, 51, 51,
+   51, 51, 50, 50, 50, 50, 50, 50,  2,  2,135,135,135,135,106,106,
+  106,106,104,104,104,104,  2,  2,  2,104,161,161,161,161,161,161,
+  161,  2,161,161,  2,161,161,  2,  2,  2,110,110,110,110,110,110,
+  110,  2,110,110,  2,  2, 19,  2, 19, 19, 47, 47, 47, 47, 47, 47,
+    2,  2, 47,  2, 47, 47, 47, 47,  2, 47, 47,  2,  2,  2, 47,  2,
+    2, 47, 81, 81, 81, 81, 81, 81,  2, 81,120,120,120,120,116,116,
+  116,116,116,116,116,  2,  2,  2,  2,116,128,128,128,128,128,128,
+  128,  2,128,128,  2,  2,  2,  2,  2,128, 66, 66, 66, 66,  2,  2,
+    2, 66, 72, 72, 72, 72, 72, 72,  2,  2,  2,  2,  2, 72, 98, 98,
+   98, 98, 97, 97, 97, 97,  2,  2, 97, 97, 57, 57, 57, 57,  2, 57,
+   57,  2,  2, 57, 57, 57, 57, 57,  2,  2, 57, 57, 57,  2,  2,  2,
+    2, 57, 57,  2,  2,  2, 88, 88, 88, 88,117,117,117,117,112,112,
+  112,112,112,112,112,  2,  2,  2,  2,112, 78, 78, 78, 78, 78, 78,
+    2,  2,  2, 78, 78, 78, 83, 83, 83, 83, 83, 83,  2,  2, 82, 82,
+   82, 82, 82, 82, 82,  2,122,122,122,122,122,122,  2,  2,  2,122,
+  122,122,122,  2,  2,  2, 89, 89, 89, 89, 89,  2,  2,  2,130,130,
+  130,130,130,130,130,  2,  2,  2,130,130,144,144,144,144,144,144,
+    2,  2,156,156,156,156,156,156,  2,156,156,156,  2,  2,  2,  3,
+    3,  3,147,147,147,147,148,148,148,148,148,148,  2,  2,158,158,
+  158,158,158,158,  2,  2,153,153,153,153,149,149,149,149,149,149,
+  149,  2, 94, 94, 94, 94, 94, 94,  2,  2,  2,  2, 94, 94,  2,  2,
+    2, 94, 85, 85, 85, 85, 85, 85, 85,  2,  2, 85,  2,  2,101,101,
+  101,101,101,  2,  2,  2,101,101,  2,  2, 96, 96, 96, 96, 96,  2,
+   96, 96,111,111,111,111,111,111,111,  2,100,100,100,100,108,108,
+  108,108,108,108,  2,108,108,108,  2,  2,129,129,129,129,129,129,
+  129,  2,129,  2,129,129,129,129,  2,129,129,129,  2,  2,109,109,
+  109,109,109,109,109,  2,109,109,  2,  2,107,107,107,107,  2,107,
+  107,107,107,  2,  2,107,107,  2,107,107,107,107,  2,  1,107,107,
+    2,  2,107,  2,  2,  2,  2,  2,  2,107,  2,  2,107,107,137,137,
+  137,137,  2,137,137,137,137,137,  2,  2,124,124,124,124,124,124,
+    2,  2,123,123,123,123,123,123,  2,  2,114,114,114,114,114,  2,
+    2,  2,114,114,  2,  2,102,102,102,102,102,102,  2,  2,126,126,
+  126,126,126,126,126,  2,  2,126,126,126,142,142,142,142,125,125,
+  125,125,125,125,125,  2,  2,  2,  2,125,154,154,154,154,154,154,
+  154,  2,  2,154,  2,  2,  2,154,154,  2,154,154,  2,154,154,  2,
+    2,154,154,154,  2,  2,150,150,150,150,  2,  2,150,150,150,  2,
+    2,  2,141,141,141,141,140,140,140,140,140,140,140,  2,121,121,
+  121,121,121,  2,  2,  2,  7,  7,  2,  2,133,133,133,133,133,  2,
+  133,133,133,133,133,  2,133,133,  2,  2,133,  2,  2,  2,134,134,
+  134,134,  2,  2,134,134,  2,134,134,134,134,134,134,  2,138,138,
+  138,138,138,138,138,  2,138,138,  2,138,  2,  2,138,  2,138,138,
+    2,  2,143,143,143,143,143,143,  2,143,143,  2,143,143,143,143,
+  143,  2,143,  2,  2,  2,143,143,  2,  2,145,145,145,145,145,  2,
+    2,  2,163,163,163,163,163,  2,163,163,163,163,163,  2,  2,  2,
+  163,163,163,163,  2,  2, 86,  2,  2,  2, 63, 63, 63, 63, 63, 63,
+    2,  2, 63, 63, 63,  2, 63,  2,  2,  2,157,157,157,157,157,157,
+  157,  2, 80, 80, 80, 80, 80, 80,  2,  2,127,127,127,127,127,127,
+  127,  2, 79,  2,  2,  2,115,115,115,115,115,115,115,  2,115,115,
+    2,  2,  2,  2,115,115,159,159,159,159,159,159,159,  2,159,159,
+    2,  2,103,103,103,103,103,103,  2,  2,119,119,119,119,119,119,
+    2,  2,119,119,  2,119,  2,119,119,119,146,146,146,146,146,146,
+  146,  2, 99, 99, 99, 99, 99, 99, 99,  2,  2,  2,  2, 99,136,139,
+   13, 13,155,  2,  2,  2,136,136,136,136,155,155,155,155,155,155,
+    2,  2,136,  2,  2,  2,  2, 17, 17, 17,  2, 17, 17,  2, 17, 15,
+   15, 15, 17, 17, 17,  2,  2,  2, 15,  2,  2, 17,  2,  2,139,139,
+  139,139,105,105,105,105,105,105,105,  2,105,  2,  2,  2,105,105,
+    2,  2,  1,  1,  2,  2,  0,  0,  0,  1,  0,  1,  1,  1,  0,  0,
+    1,  1,  2,  2,  0,  2,  2,  0,  0,  2,  0,  2,  0,  2,131,131,
+  131,131,  2,  2,  2,131,  2,131,131,131, 56, 56, 56,  2, 56,  2,
+    2, 56, 56, 56,  2, 56, 56,  2, 56, 56,  6,  6,  2,  2,  2,  2,
+    2,  6,151,151,151,151,151,  2,  2,  2,151,151,  2,  2,  2,  2,
+  151,151,160,160,160,160,160,160,160,  2,152,152,152,152,152,152,
+    2,  2,  2,  2,  2,152,164,164,164,164,164,164,  2,  2,  2, 30,
+   30,  2,113,113,113,113,113,  2,  2,113,113,113,113,  2,132,132,
+  132,132,132,132,  2,  2,  2,  2,132,132,  2,  3,  3,  2,  3,  2,
+    2,  3,  2,  3,  2,  3,  2,  2,  3,  2,  3,  2,  3,  2,  3,  3,
+    2,  3, 15,  0,  0,  2, 13,  2,  2,  2, 13, 13, 13,  2,  2,  0,
+    2,  2,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  9,  9,  9, 10,
+    9, 11, 12, 13,  9,  9,  9, 14,  9,  9, 15,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 16, 17,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 18, 19, 20,  9, 21,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 22,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 23, 24,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  4,
+    5,  6,  7,  8,  9, 10, 11, 12,  0,  0, 13, 14, 15, 16, 17, 18,
+   19, 20, 21, 22,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 23,  0,  0, 24, 25, 26, 27, 28, 29, 30,  0,  0,
+   31, 32,  0, 33,  0, 34,  0, 35,  0,  0,  0,  0, 36, 37, 38, 39,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 40,  0,  0,  0,  0,  0,  0,  0,  0,  0, 41, 42,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 43, 44,  0, 45,  0,  0,  0,  0,  0,  0, 46, 47,  0,  0,
+    0,  0,  0, 48,  0, 49,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 50, 51,  0,  0,  0, 52,  0,  0, 53,  0,  0,  0,
+    0,  0,  0,  0, 54,  0,  0,  0,  0,  0,  0,  0, 55,  0,  0,  0,
+    0,  0,  0,  0, 56,  0,  0,  0,  0,  0,  0,  0,  0, 57,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 58, 59, 60, 61, 62, 63, 64, 65,  0,  0,  0,  0,
+    0,  0, 66,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   67, 68,  0, 69, 70,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   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,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,104,  0,  0,  0,  0,  0,  0,105,106,  0,107,  0,  0,  0,
+  108,  0,109,  0,110,  0,111,112,113,  0,114,  0,  0,  0,115,  0,
+    0,  0,116,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,117,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,118,119,120,121,  0,122,123,124,125,126,  0,127,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+  144,145,146,147,148,149,150,151,152,153,154,155,156,157,  0,  0,
+    0,158,159,160,161,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,162,163,  0,  0,  0,  0,  0,
+    0,  0,164,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,165,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,166,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,167,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,168,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,169,170,  0,  0,  0,  0,171,172,  0,  0,  0,
+  173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,
+  189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,
+  205,206,  0,  0,  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,
+};
+static const uint16_t
+_hb_ucd_u16[10060] =
+{
+     0,   0,   1,   2,   3,   4,   5,   6,   0,   0,   7,   8,   9,  10,  11,  12,
+    13,  13,  13,  14,  15,  13,  13,  16,  17,  18,  19,  20,  21,  22,  13,  23,
+    13,  13,  13,  24,  25,  11,  11,  11,  11,  26,  11,  27,  28,  29,  30,  31,
+    32,  32,  32,  32,  32,  32,  32,  33,  34,  35,  36,  11,  37,  38,  13,  39,
+     9,   9,   9,  11,  11,  11,  13,  13,  40,  13,  13,  13,  41,  13,  13,  13,
+    13,  13,  13,  42,   9,  43,  11,  11,  44,  45,  32,  46,  47,  48,  49,  50,
+    51,  52,  48,  48,  53,  32,  54,  55,  48,  48,  48,  48,  48,  56,  57,  58,
+    59,  60,  48,  32,  61,  48,  48,  48,  48,  48,  62,  63,  64,  48,  65,  66,
+    48,  67,  68,  69,  48,  70,  71,  48,  72,  73,  48,  48,  74,  32,  75,  32,
+    76,  48,  48,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,
+    90,  83,  84,  91,  92,  93,  94,  95,  96,  97,  84,  98,  99, 100,  88, 101,
+   102,  83,  84, 103, 104, 105,  88, 106, 107, 108, 109, 110, 111, 112,  94, 113,
+   114, 115,  84, 116, 117, 118,  88, 119, 120, 115,  84, 121, 122, 123,  88, 124,
+   125, 115,  48, 126, 127, 128,  88, 129, 130, 131,  48, 132, 133, 134,  94, 135,
+   136,  48,  48, 137, 138, 139, 140, 140, 141,  48, 142, 143, 144, 145, 140, 140,
+   146, 147, 148, 149, 150,  48, 151, 152, 153, 154,  32, 155, 156, 157, 140, 140,
+    48,  48, 158, 159, 160, 161, 162, 163, 164, 165,   9,   9, 166,  11,  11, 167,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 168, 169,  48,  48,
+   168,  48,  48, 170, 171, 172,  48,  48,  48, 171,  48,  48,  48, 173, 174, 175,
+    48, 176,   9,   9,   9,   9,   9, 177, 178,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48, 179,  48, 180, 181,  48,  48,  48,  48, 182, 183,
+    48, 184,  48, 185,  48, 186, 187, 188,  48,  48,  48, 189, 190, 191, 192, 193,
+   194, 192,  48,  48, 195,  48,  48, 196, 197,  48, 198,  48,  48,  48,  48, 199,
+    48, 200, 201, 202, 203,  48, 204, 205,  48,  48, 206,  48, 207, 208, 209, 209,
+    48, 210,  48,  48,  48, 211, 212, 213, 192, 192, 214, 215, 216, 140, 140, 140,
+   217,  48,  48, 218, 219, 160, 220, 221, 222,  48, 223,  64,  48,  48, 224, 225,
+    48,  48, 226, 227, 228,  64,  48, 229, 230,   9,   9, 231, 232, 233, 234, 235,
+    11,  11, 236,  27,  27,  27, 237, 238,  11, 239,  27,  27,  32,  32,  32,  32,
+    13,  13,  13,  13,  13,  13,  13,  13,  13, 240,  13,  13,  13,  13,  13,  13,
+   241, 242, 241, 241, 242, 243, 241, 244, 245, 245, 245, 246, 247, 248, 249, 250,
+   251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 261, 262, 263, 264, 265,
+   266, 267, 268, 269, 270, 271, 272, 272, 273, 274, 275, 209, 276, 277, 209, 278,
+   279, 279, 279, 279, 279, 279, 279, 279, 280, 209, 281, 209, 209, 209, 209, 282,
+   209, 283, 279, 284, 209, 285, 286, 209, 209, 209, 287, 140, 288, 140, 271, 271,
+   271, 289, 209, 209, 209, 209, 290, 271, 209, 209, 209, 209, 209, 209, 209, 209,
+   209, 209, 209, 291, 292, 209, 209, 293, 209, 209, 209, 209, 209, 209, 294, 209,
+   209, 209, 209, 209, 209, 209, 295, 296, 271, 297, 209, 209, 298, 279, 299, 279,
+   300, 301, 279, 279, 279, 302, 279, 303, 209, 209, 209, 279, 304, 209, 209, 305,
+   209, 306, 209, 209, 209, 209, 209, 209,   9,   9,   9,  11,  11,  11, 307, 308,
+    13,  13,  13,  13,  13,  13, 309, 310,  11,  11, 311,  48,  48,  48, 312, 313,
+    48, 314, 315, 315, 315, 315,  32,  32, 316, 317, 318, 319, 320, 321, 140, 140,
+   209, 322, 209, 209, 209, 209, 209, 323, 209, 209, 209, 209, 209, 324, 140, 209,
+   325, 326, 327, 328, 136,  48,  48,  48,  48, 329, 178,  48,  48,  48,  48, 330,
+   331,  48,  48, 136,  48,  48,  48,  48, 200, 332,  48,  48, 209, 209, 333,  48,
+   209, 334, 335, 209, 336, 337, 209, 209, 335, 209, 209, 337, 209, 209, 209, 209,
+    48,  48,  48,  48, 209, 209, 209, 209,  48, 338,  48,  48,  48,  48,  48,  48,
+   151, 209, 209, 209, 287,  48,  48, 229, 339,  48, 340, 140,  13,  13, 341, 342,
+    13, 343,  48,  48,  48,  48, 344, 345,  31, 346, 347, 348,  13,  13,  13, 349,
+   350, 351, 352, 353, 354, 355, 140, 356, 357,  48, 358, 359,  48,  48,  48, 360,
+   361,  48,  48, 362, 363, 192,  32, 364,  64,  48, 365,  48, 366, 367,  48, 151,
+    76,  48,  48, 368, 369, 370, 371, 372,  48,  48, 373, 374, 375, 376,  48, 377,
+    48,  48,  48, 378, 379, 380, 381, 382, 383, 384, 315,  11,  11, 385, 386,  11,
+    11,  11,  11,  11,  48,  48, 387, 192,  48,  48, 388,  48, 389,  48,  48, 206,
+   390, 390, 390, 390, 390, 390, 390, 390, 391, 391, 391, 391, 391, 391, 391, 391,
+    48,  48,  48,  48,  48,  48, 204,  48,  48,  48,  48,  48,  48, 207, 140, 140,
+   392, 393, 394, 395, 396,  48,  48,  48,  48,  48,  48, 397, 398, 399,  48,  48,
+    48,  48,  48, 400, 209,  48,  48,  48,  48, 401,  48,  48, 402, 140, 140, 403,
+    32, 404,  32, 405, 406, 407, 408, 409,  48,  48,  48,  48,  48,  48,  48, 410,
+   411,   2,   3,   4,   5, 412, 413, 414,  48, 415,  48, 200, 416, 417, 418, 419,
+   420,  48, 172, 421, 204, 204, 140, 140,  48,  48,  48,  48,  48,  48,  48,  71,
+   422, 271, 271, 423, 272, 272, 272, 424, 425, 426, 427, 140, 140, 209, 209, 428,
+   140, 140, 140, 140, 140, 140, 140, 140,  48, 151,  48,  48,  48, 100, 429, 430,
+    48,  48, 431,  48, 432,  48,  48, 433,  48, 434,  48,  48, 435, 436, 140, 140,
+     9,   9, 437,  11,  11,  48,  48,  48,  48, 204, 192,   9,   9, 438,  11, 439,
+    48,  48, 440,  48,  48,  48, 441, 442, 442, 443, 444, 445, 140, 140, 140, 140,
+    48,  48,  48, 314,  48, 199, 440, 140, 446,  27,  27, 447, 140, 140, 140, 140,
+   448,  48,  48, 449,  48, 450,  48, 451,  48, 200, 452, 140, 140, 140,  48, 453,
+    48, 454,  48, 455, 140, 140, 140, 140,  48,  48,  48, 456, 271, 457, 271, 271,
+   458, 459,  48, 460, 461, 462,  48, 463,  48, 464, 140, 140, 465,  48, 466, 467,
+    48,  48,  48, 468,  48, 469,  48, 470,  48, 471, 472, 140, 140, 140, 140, 140,
+    48,  48,  48,  48, 196, 140, 140, 140,   9,   9,   9, 473,  11,  11,  11, 474,
+    48,  48, 475, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 271, 476,
+    48,  48, 477, 478, 140, 140, 140, 479,  48, 464, 480,  48,  62, 481, 140,  48,
+   482, 140, 140,  48, 483, 140,  48, 314, 484,  48,  48, 485, 486, 457, 487, 488,
+   222,  48,  48, 489, 490,  48, 196, 192, 491,  48, 492, 493, 494,  48,  48, 495,
+   222,  48,  48, 496, 497, 498, 499, 500,  48,  97, 501, 502, 503, 140, 140, 140,
+   504, 505, 506,  48,  48, 507, 508, 192, 509,  83,  84, 510, 511, 512, 513, 514,
+    48,  48,  48, 515, 516, 517, 478, 140,  48,  48,  48, 518, 519, 192, 140, 140,
+    48,  48, 520, 521, 522, 523, 140, 140,  48,  48,  48, 524, 525, 192, 526, 140,
+    48,  48, 527, 528, 192, 140, 140, 140,  48, 173, 529, 530, 314, 140, 140, 140,
+    48,  48, 501, 531, 140, 140, 140, 140, 140, 140,   9,   9,  11,  11, 148, 532,
+   533, 534,  48, 535, 536, 192, 140, 140, 140, 140, 537,  48,  48, 538, 539, 140,
+   540,  48,  48, 541, 542, 543,  48,  48, 544, 545, 546,  48,  48,  48,  48, 196,
+   547, 140, 140, 140, 140, 140, 140, 140,  84,  48, 520, 548, 549, 148, 175, 550,
+    48, 551, 552, 553, 140, 140, 140, 140, 554,  48,  48, 555, 556, 192, 557,  48,
+   558, 559, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,  48, 560,
+   561, 115,  48, 562, 563, 192, 140, 140, 140, 140, 140, 100, 271, 564, 565, 566,
+    48, 207, 140, 140, 140, 140, 140, 140, 272, 272, 272, 272, 272, 272, 567, 568,
+    48,  48,  48,  48, 388, 140, 140, 140, 140,  48,  48,  48,  48,  48,  48, 569,
+    48,  48,  48, 570, 571, 572, 140, 140,  48,  48,  48,  48, 314, 140, 140, 140,
+    48,  48,  48, 196,  48, 200, 370,  48,  48,  48,  48, 200, 192,  48, 204, 573,
+    48,  48,  48, 574, 575, 576, 577, 578,  48, 140, 140, 140, 140, 140, 140, 140,
+   140, 140, 140, 140,   9,   9,  11,  11, 271, 579, 140, 140, 140, 140, 140, 140,
+    48,  48,  48,  48, 580, 581, 582, 582, 583, 584, 140, 140, 140, 140, 585, 586,
+    48,  48,  48,  48,  48,  48,  48, 440,  48,  48,  48,  48,  48, 199, 140, 140,
+   196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 587,
+    48,  48, 588, 589, 140, 590, 591,  48,  48,  48,  48,  48,  48,  48,  48, 206,
+    48,  48,  48,  48,  48,  48,  71, 151, 196, 592, 593, 140, 140, 140, 140, 140,
+    32,  32, 594,  32, 595, 209, 209, 209, 209, 209, 209, 209, 323, 140, 140, 140,
+   209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 596, 209, 209, 209, 597, 598,
+   599, 209, 600, 209, 209, 209, 288, 140, 209, 209, 209, 209, 601, 140, 140, 140,
+   140, 140, 140, 140, 271, 602, 271, 602, 209, 209, 209, 209, 209, 287, 271, 461,
+     9, 603,  11, 604, 605, 606, 241,   9, 607, 608, 609, 610, 611,   9, 603,  11,
+   612, 613,  11, 614, 615, 616, 617,   9, 618,  11,   9, 603,  11, 604, 605,  11,
+   241,   9, 607, 617,   9, 618,  11,   9, 603,  11, 619,   9, 620, 621, 622, 623,
+    11, 624,   9, 625, 626, 627, 628,  11, 629,   9, 630,  11, 631, 632, 632, 632,
+    32,  32,  32, 633,  32,  32, 634, 635, 636, 637,  45, 140, 140, 140, 140, 140,
+   638, 639, 640, 140, 140, 140, 140, 140, 641, 642, 643,  27,  27,  27, 644, 140,
+   645, 140, 140, 140, 140, 140, 140, 140,  48,  48, 151, 646, 647, 140, 140, 140,
+   140,  48, 648, 140,  48,  48, 649, 650, 140, 140, 140, 140, 140,  48, 651, 192,
+   140, 140, 140, 140, 140, 140, 652, 200,  48,  48,  48,  48, 653, 595, 140, 140,
+     9,   9, 607,  11, 654, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 499,
+   271, 271, 655, 656, 140, 140, 140, 140, 499, 271, 657, 658, 140, 140, 140, 140,
+   659,  48, 660, 661, 662, 663, 664, 665, 666, 206, 667, 206, 140, 140, 140, 668,
+   209, 209, 669, 209, 209, 209, 209, 209, 209, 323, 334, 670, 670, 670, 209, 324,
+   671, 209, 209, 209, 209, 209, 209, 209, 209, 209, 672, 140, 140, 140, 673, 209,
+   674, 209, 209, 669, 675, 676, 324, 140, 209, 209, 209, 209, 209, 209, 209, 677,
+   209, 209, 209, 209, 209, 678, 426, 426, 209, 209, 209, 209, 209, 209, 209, 679,
+   209, 209, 209, 209, 209, 176, 669, 427, 669, 209, 209, 209, 680, 176, 209, 209,
+   680, 209, 672, 676, 140, 140, 140, 140, 209, 209, 209, 209, 209, 323, 672, 426,
+   675, 209, 209, 681, 682, 669, 675, 675, 209, 683, 209, 209, 288, 140, 140, 192,
+    48,  48,  48,  48,  48,  48, 140, 140,  48,  48,  48, 207,  48,  48,  48,  48,
+    48, 204,  48,  48,  48,  48,  48,  48,  48,  48, 478,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48, 100,  48,  48,  48,  48,  48,  48, 204, 140, 140,
+    48, 204, 140, 140, 140, 140, 140, 140,  48,  48,  48,  48,  71,  48,  48,  48,
+    48,  48,  48, 140, 140, 140, 140, 140, 684, 140, 570, 570, 570, 570, 570, 570,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32, 140,
+   391, 391, 391, 391, 391, 391, 391, 685, 391, 391, 391, 391, 391, 391, 391, 686,
+     0,   0,   0,   0,   1,   2,   1,   2,   0,   0,   3,   3,   4,   5,   4,   5,
+     4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   6,   0,   0,   7,   0,
+     8,   8,   8,   8,   8,   8,   8,   9,  10,  11,  12,  11,  11,  11,  13,  11,
+    14,  14,  14,  14,  14,  14,  14,  14,  15,  14,  14,  14,  14,  14,  14,  14,
+    14,  14,  14,  16,  17,  18,  17,  17,  19,  20,  21,  21,  22,  21,  23,  24,
+    25,  26,  27,  27,  28,  29,  27,  30,  27,  27,  27,  27,  27,  31,  27,  27,
+    32,  33,  33,  33,  34,  27,  27,  27,  35,  35,  35,  36,  37,  37,  37,  38,
+    39,  39,  40,  41,  42,  43,  44,  27,  45,  46,  27,  27,  27,  27,  47,  27,
+    48,  48,  48,  48,  48,  49,  50,  48,  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, 109, 110, 111, 112, 109, 113, 114, 115, 116, 117, 118, 119, 120,
+   121, 122, 122, 123, 122, 124, 125, 125, 126, 127, 128, 129, 130, 131, 125, 125,
+   132, 132, 132, 132, 133, 132, 134, 135, 132, 133, 132, 136, 136, 137, 125, 125,
+   138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 139, 139, 140, 139, 139, 141,
+   142, 142, 142, 142, 142, 142, 142, 142, 143, 143, 143, 143, 144, 145, 143, 143,
+   144, 143, 143, 146, 147, 148, 143, 143, 143, 147, 143, 143, 143, 149, 143, 150,
+   143, 151, 152, 152, 152, 152, 152, 153, 154, 154, 154, 154, 154, 154, 154, 154,
+   155, 156, 157, 157, 157, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
+   168, 168, 168, 168, 168, 169, 170, 170, 171, 172, 173, 173, 173, 173, 173, 174,
+   173, 173, 175, 154, 154, 154, 154, 176, 177, 178, 179, 179, 180, 181, 182, 183,
+   184, 184, 185, 184, 186, 187, 168, 168, 188, 189, 190, 190, 190, 191, 190, 192,
+   193, 193, 194,   8, 195, 125, 125, 125, 196, 196, 196, 196, 197, 196, 196, 198,
+   199, 199, 199, 199, 200, 200, 200, 201, 202, 202, 202, 203, 204, 205, 205, 205,
+   206, 139, 139, 207, 208, 209, 210, 211,   4,   4, 212,   4,   4, 213, 214, 215,
+     4,   4,   4, 216,   8,   8,   8,   8,  11, 217,  11,  11, 217, 218,  11, 219,
+    11,  11,  11, 220, 220, 221,  11, 222, 223,   0,   0,   0,   0,   0, 224, 225,
+   226, 227,   0,   0, 228,   8,   8, 229,   0,   0, 230, 231, 232,   0,   4,   4,
+   233,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0, 234, 125, 235, 125,   0,   0, 236, 236, 236, 236, 236, 236, 236, 236,
+     0,   0,   0,   0,   0,   0,   0, 237,   0, 238,   0,   0,   0,   0,   0,   0,
+   239, 239, 239, 239, 239, 239,   4,   4, 240, 240, 240, 240, 240, 240, 240, 241,
+   139, 139, 140, 242, 242, 242, 243, 244, 143, 245, 246, 246, 246, 246,  14,  14,
+     0,   0,   0,   0,   0, 247, 125, 125, 248, 249, 248, 248, 248, 248, 248, 250,
+   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 251, 125,   0,
+   252,   0, 253, 254, 255, 256, 256, 256, 256, 257, 258, 259, 259, 259, 259, 260,
+   261, 262, 262, 263, 142, 142, 142, 142, 264,   0, 262, 262,   0,   0, 265, 259,
+   142, 264,   0,   0,   0,   0, 142, 266,   0,   0,   0,   0,   0, 259, 259, 267,
+   259, 259, 259, 259, 259, 268,   0,   0, 248, 248, 248, 248,   0,   0,   0,   0,
+   269, 269, 269, 269, 269, 269, 269, 269, 270, 269, 269, 269, 271, 272, 272, 272,
+   273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 274, 125,  14,  14,  14,  14,
+    14,  14, 275, 275, 275, 275, 275, 276,   0,   0, 277,   4,   4,   4,   4,   4,
+   278,   4,   4,   4, 279, 280, 125, 281, 282, 282, 283, 284, 285, 285, 285, 286,
+   287, 287, 287, 287, 288, 289,  48,  48, 290, 290, 291, 292, 292, 293, 142, 294,
+   295, 295, 295, 295, 296, 297, 138, 298, 299, 299, 299, 300, 301, 302, 138, 138,
+   303, 303, 303, 303, 304, 305, 306, 307, 308, 309, 246,   4,   4, 310, 311, 152,
+   152, 152, 152, 152, 306, 306, 312, 313, 142, 142, 314, 142, 315, 142, 142, 316,
+   125, 125, 125, 125, 125, 125, 125, 125, 248, 248, 248, 248, 248, 248, 317, 248,
+   248, 248, 248, 248, 248, 318, 125, 125, 319, 320,  21, 321, 322,  27,  27,  27,
+    27,  27,  27,  27, 323, 324,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,
+    27,  27,  27, 325,  27,  27,  27,  27,  27, 326,  27,  27, 327, 125, 125,  27,
+     8, 284, 328,   0,   0, 329, 330, 331,  27,  27,  27,  27,  27,  27,  27, 332,
+   333,   0,   1,   2,   1,   2, 334, 258, 259, 335, 142, 264, 336, 337, 338, 339,
+   340, 341, 342, 343, 344, 344, 125, 125, 341, 341, 341, 341, 341, 341, 341, 345,
+   346,   0,   0, 347,  11,  11,  11,  11, 348, 349, 350, 125, 125,   0,   0, 351,
+   352, 353, 354, 354, 354, 355, 356, 357, 358, 358, 359, 360, 361, 362, 362, 363,
+   364, 365, 366, 366, 367, 368, 125, 125, 369, 369, 369, 369, 369, 370, 370, 370,
+   371, 372, 373, 374, 374, 375, 374, 376, 377, 377, 378, 379, 379, 379, 380, 381,
+   381, 382, 383, 384, 125, 125, 125, 125, 385, 385, 385, 385, 385, 385, 385, 385,
+   385, 385, 385, 386, 385, 387, 388, 125, 389,   4,   4, 390, 125, 125, 125, 125,
+   391, 392, 392, 393, 394, 395, 396, 396, 397, 398, 399, 125, 125, 125, 400, 401,
+   402, 403, 404, 405, 125, 125, 125, 125, 406, 406, 407, 408, 407, 409, 407, 407,
+   410, 411, 412, 413, 414, 414, 415, 415, 416, 416, 125, 125, 417, 417, 418, 419,
+   420, 420, 420, 421, 422, 423, 424, 425, 426, 427, 428, 125, 125, 125, 125, 125,
+   429, 429, 429, 429, 430, 125, 125, 125, 431, 431, 431, 432, 431, 431, 431, 433,
+   434, 434, 435, 436, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,  27,  45,
+   437, 437, 438, 439, 125, 125, 125, 440, 441, 441, 442, 443, 443, 444, 125, 445,
+   446, 125, 125, 447, 448, 125, 449, 450, 451, 451, 451, 451, 452, 453, 451, 454,
+   455, 455, 455, 455, 456, 457, 458, 459, 460, 460, 460, 461, 462, 463, 463, 464,
+   465, 465, 465, 465, 465, 465, 466, 467, 468, 469, 468, 468, 470, 125, 125, 125,
+   471, 472, 473, 474, 474, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484,
+   485, 485, 485, 485, 485, 486, 487, 125, 488, 488, 488, 488, 489, 490, 125, 125,
+   491, 491, 491, 492, 491, 493, 125, 125, 494, 494, 494, 494, 495, 496, 497, 125,
+   498, 498, 498, 499, 499, 125, 125, 125, 500, 501, 502, 500, 503, 125, 125, 125,
+   504, 504, 504, 505, 125, 125, 125, 125, 125, 125, 506, 506, 506, 506, 506, 507,
+   508, 509, 510, 511, 512, 513, 125, 125, 125, 125, 514, 515, 515, 514, 516, 125,
+   517, 517, 517, 517, 518, 519, 519, 519, 519, 519, 520, 154, 521, 521, 521, 522,
+   523, 125, 125, 125, 125, 125, 125, 125, 524, 525, 525, 526, 527, 525, 528, 529,
+   529, 530, 531, 532, 125, 125, 125, 125, 533, 534, 534, 535, 536, 537, 538, 539,
+   540, 541, 542, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 543, 544,
+   545, 546, 545, 547, 545, 548, 125, 125, 125, 125, 125, 549, 550, 550, 550, 551,
+   552, 552, 552, 552, 552, 552, 552, 552, 552, 553, 125, 125, 125, 125, 125, 125,
+   552, 552, 552, 552, 552, 552, 554, 555, 552, 552, 552, 552, 556, 125, 125, 125,
+   125, 557, 557, 557, 557, 557, 557, 558, 559, 559, 559, 559, 559, 559, 559, 559,
+   559, 559, 559, 559, 559, 560, 125, 125, 561, 561, 561, 561, 561, 561, 561, 561,
+   561, 561, 561, 561, 562, 125, 125, 125, 275, 275, 275, 275, 275, 275, 275, 275,
+   275, 275, 275, 563, 564, 565, 566, 567, 567, 567, 567, 568, 569, 570, 571, 572,
+   573, 573, 573, 573, 574, 575, 576, 577, 573, 125, 125, 125, 125, 125, 125, 125,
+   125, 125, 125, 125, 578, 578, 578, 578, 578, 579, 125, 125, 125, 125, 125, 125,
+   580, 580, 580, 580, 581, 580, 580, 580, 582, 580, 125, 125, 125, 125, 583, 584,
+   585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 586,
+   587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 588, 125, 125,
+   589, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 590,
+   591, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
+   256, 256, 592, 593, 125, 594, 595, 596, 596, 596, 596, 596, 596, 596, 596, 596,
+   596, 596, 596, 596, 596, 596, 596, 597, 598, 598, 598, 598, 598, 598, 599, 600,
+   601, 602, 603, 125, 125, 125, 125, 125,   8,   8, 604,   8, 605,   0,   0,   0,
+     0,   0,   0,   0, 603, 125, 125, 125,   0,   0,   0,   0,   0,   0,   0, 606,
+     0,   0, 607,   0,   0,   0, 608, 609, 610,   0, 611,   0,   0,   0, 235, 125,
+    11,  11,  11,  11, 612, 125, 125, 125, 125, 125, 125, 125,   0, 603,   0, 603,
+     0,   0,   0,   0,   0, 234,   0, 613,   0,   0,   0,   0,   0, 224,   0,   0,
+     0, 614, 615, 616, 617,   0,   0,   0, 618, 619,   0, 620, 621, 622,   0,   0,
+     0,   0, 623,   0,   0,   0,   0,   0,   0,   0,   0,   0, 624,   0,   0,   0,
+   625, 625, 625, 625, 625, 625, 625, 625, 626, 627, 628, 125, 125, 125, 125, 125,
+     4, 629, 630, 125, 125, 125, 125, 125, 631, 632, 633,  14,  14,  14, 634, 125,
+   635, 125, 125, 125, 125, 125, 125, 125, 636, 636, 637, 638, 639, 125, 125, 125,
+   125, 640, 641, 125, 642, 642, 642, 643, 125, 125, 125, 125, 125, 644, 644, 645,
+   125, 125, 125, 125, 125, 125, 646, 647, 648, 648, 648, 648, 648, 648, 648, 648,
+   648, 648, 648, 648, 649, 650, 125, 125, 651, 651, 651, 651, 652, 653, 125, 125,
+   125, 125, 125, 125, 125, 125, 125, 333,   0,   0,   0, 654, 125, 125, 125, 125,
+   333,   0,   0, 247, 125, 125, 125, 125, 655,  27, 656, 657, 658, 659, 660, 661,
+   662, 663, 664, 663, 125, 125, 125, 665,   0,   0, 357,   0,   0,   0,   0,   0,
+     0, 603, 226, 333, 333, 333,   0, 606,   0,   0, 247, 125, 125, 125, 666,   0,
+   667,   0,   0, 357, 613, 668, 606, 125,   0,   0,   0,   0,   0, 669, 349, 349,
+     0,   0,   0,   0,   0,   0,   0, 670,   0,   0,   0,   0,   0, 284, 357, 228,
+   357,   0,   0,   0, 671, 284,   0,   0, 671,   0, 247, 668, 125, 125, 125, 125,
+     0,   0,   0,   0,   0, 603, 247, 349, 613,   0,   0, 672, 673, 357, 613, 613,
+     0, 329,   0,   0, 235, 125, 125, 284, 248, 248, 248, 248, 248, 248, 125, 125,
+   248, 248, 248, 318, 248, 248, 248, 248, 248, 317, 248, 248, 248, 248, 248, 248,
+   248, 248, 584, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 674, 248,
+   248, 248, 248, 248, 248, 317, 125, 125, 248, 317, 125, 125, 125, 125, 125, 125,
+   248, 248, 248, 248, 675, 248, 248, 248, 248, 248, 248, 125, 125, 125, 125, 125,
+   676, 125,   0,   0,   0,   0,   0,   0,   8,   8,   8,   8,   8,   8,   8,   8,
+     8,   8,   8,   8,   8,   8,   8,   0,   0,   0,   0,   0,   1,   2,   2,   2,
+     2,   2,   3,   0,   0,   0,   4,   0,   2,   2,   2,   2,   2,   3,   2,   2,
+     2,   2,   5,   0,   2,   5,   6,   0,   7,   7,   7,   7,   8,   9,  10,  11,
+    12,  13,  14,  15,   8,   8,   8,   8,  16,   8,   8,   8,  17,  18,  18,  18,
+    19,  19,  19,  19,  19,  20,  19,  19,  21,  22,  22,  22,  22,  22,  22,  22,
+    22,  23,  21,  22,  22,  22,  23,  21,  24,  25,  25,  25,  25,  25,  25,  25,
+    25,  25,  12,  12,  25,  25,  26,  27,  25,  28,  12,  12,  29,  30,  29,  31,
+    29,  29,  32,  32,  29,  29,  29,  29,  31,  29,  33,   7,   7,  34,  29,  29,
+    35,  29,  29,  29,  29,  29,  29,  30,  36,  36,  36,  37,  36,  36,  36,  36,
+    36,  36,  38,  39,  40,  40,  40,  40,  41,  12,  12,  12,  42,  42,  42,  42,
+    42,  42,  43,  44,  45,  45,  45,  45,  45,  45,  45,  46,  45,  45,  45,  47,
+    48,  48,  48,  48,  48,  48,  48,  49,  36,  36,  38,  12,  29,  29,  29,  50,
+    51,  12,  29,  29,  52,  29,  29,  29,  53,  53,  53,  53,  54,  55,  53,  53,
+    53,  56,  53,  53,  57,  58,  57,  59,  59,  57,  57,  57,  57,  57,  60,  57,
+    61,  62,  63,  57,  57,  59,  59,  64,  12,  65,  12,  66,  57,  62,  57,  57,
+    57,  57,  57,  64,  67,  67,  68,  69,  70,  71,  71,  71,  71,  71,  72,  71,
+    72,  73,  74,  72,  68,  69,  70,  74,  75,  12,  67,  76,  12,  77,  71,  71,
+    71,  68,  12,  12,  78,  78,  79,  80,  80,  79,  79,  79,  79,  79,  81,  79,
+    81,  78,  82,  79,  79,  80,  80,  82,  83,  12,  12,  12,  79,  84,  79,  79,
+    82,  12,  78,  79,  85,  85,  86,  87,  87,  86,  86,  86,  86,  86,  88,  86,
+    88,  85,  89,  86,  86,  87,  87,  89,  12,  85,  12,  90,  86,  91,  86,  86,
+    86,  86,  12,  12,  92,  93,  94,  92,  95,  96,  97,  95,  98,  99,  94,  92,
+   100, 100,  96,  92,  94,  92,  95,  96,  99,  98,  12,  12,  12,  92, 100, 100,
+   100, 100,  94,  12, 101, 101, 101, 102, 102, 101, 101, 101, 101, 101, 102, 101,
+   101, 101, 103, 101, 101, 102, 102, 103,  12, 104, 105, 106, 101, 107, 101, 101,
+    12, 108, 101, 101, 109, 109, 109, 110, 110, 109, 109, 109, 109, 109, 110, 109,
+   109, 111, 112, 109, 109, 110, 110, 112,  12, 113,  12, 113, 109, 114, 109, 109,
+   111,  12,  12,  12, 115, 115, 115, 116, 116, 115, 115, 115, 115, 115, 115, 115,
+   115, 116, 116, 115,  12, 115, 115, 115, 115, 117, 115, 115, 118, 118, 119, 119,
+   119, 120, 121, 119, 119, 119, 119, 119, 122, 119, 119, 123, 119, 120, 124, 125,
+   119, 126, 119, 119,  12, 121, 119, 119, 121, 127,  12,  12, 128, 129, 129, 129,
+   129, 129, 129, 129, 129, 129, 130, 131, 129, 129, 129,  12,  12,  12,  12,  12,
+   132, 133, 134, 135, 135, 135, 135, 135, 135, 136, 135, 135, 135, 135, 135, 137,
+   135, 138, 135, 134, 135, 135, 137, 135, 139, 139, 139, 139, 139, 139, 140, 139,
+   139, 139, 139, 141, 140, 139, 139, 139, 139, 139, 139, 142, 139, 143, 144,  12,
+   145, 145, 145, 145, 146, 146, 146, 146, 146, 147,  12, 148, 146, 146, 149, 146,
+   150, 150, 150, 150, 151, 151, 151, 151, 151, 151, 152, 153, 151, 154, 152, 153,
+   152, 153, 151, 154, 152, 153, 151, 151, 151, 154, 151, 151, 151, 151, 154, 155,
+   151, 151, 151, 156, 151, 151, 153,  12, 157, 157, 157, 157, 157, 158, 157, 158,
+   159, 159, 159, 159, 160, 160, 160, 160, 160, 160, 160, 161, 162, 162, 162, 162,
+   162, 162, 163, 164, 162, 162, 165,  12, 166, 166, 166, 166, 166, 167,  12, 168,
+   169, 169, 169, 169, 169, 170,  12,  12, 171, 171, 171, 171, 171,  12,  12,  12,
+   172, 172, 172, 173, 173,  12,  12,  12, 174, 174, 174, 174, 174, 174, 174, 175,
+   174, 174, 175,  12, 176, 177, 178, 178, 178, 178, 179,  12, 178, 178, 178, 178,
+   178, 178, 180,  12, 178, 178, 181,  12, 159, 182,  12,  12, 183, 183, 183, 183,
+   183, 183, 183, 184, 183, 183, 183,  12, 185, 183, 183, 183, 186, 186, 186, 186,
+   186, 186, 186, 187, 186, 188,  12,  12, 189, 189, 189, 189, 189, 189, 189,  12,
+   189, 189, 190,  12, 189, 189, 191, 192, 193, 193, 193, 193, 193, 193, 193, 194,
+   195, 195, 195, 195, 195, 195, 195, 196, 195, 195, 195, 197, 195, 195, 198,  12,
+   195, 195, 195, 198,   7,   7,   7, 199, 200, 200, 200, 200, 200, 200, 200, 201,
+   200, 200, 200, 202, 203, 203, 203, 203, 204, 204, 204, 204, 204,  12,  12, 204,
+   205, 205, 205, 205, 205, 205, 206, 205, 205, 205, 207, 208, 209, 209, 209, 209,
+    19,  19, 210,  12, 146, 146, 211, 212, 203, 203,  12,  12, 213,   7,   7,   7,
+   214,   7, 215, 216,   0, 215, 217,  12,   2, 218, 219,   2,   2,   2,   2, 220,
+   221, 218, 222,   2,   2,   2, 223,   2,   2,   2,   2, 224,   8, 225,   8, 225,
+     8,   8, 226, 226,   8,   8,   8, 225,   8,  15,   8,   8,   8,  10,   8, 227,
+    10,  15,   8,  14,   0,   0,   0, 228,   0, 229,   0,   0, 230,   0,   0, 231,
+     0,   0,   0, 232,   2,   2,   2, 233, 234,  12,  12,  12, 235,  12,  12,  12,
+     0, 236, 237,   0,   4,   0,   0,   0,   0,   0,   0,   4,   2,   2,   5,  12,
+     0, 232,  12,  12,   0,   0, 232,  12, 238, 238, 238, 238,   0, 239,   0,   0,
+     0, 240,   0,   0, 241, 241, 241, 241,  18,  18,  18,  18,  18,  12, 242,  18,
+   243, 243, 243, 243, 243, 243,  12, 244, 245,  12,  12, 244, 151, 154,  12,  12,
+   151, 154, 151, 154,   0,   0,   0, 246, 247, 247, 247, 247, 247, 247, 248, 247,
+   247,  12,  12,  12, 247, 249,  12,  12,   0, 250,   0,   0, 251, 247, 252, 253,
+     0,   0, 247,   0, 254, 255, 255, 255, 255, 255, 255, 255, 255, 256, 257, 258,
+   259, 260, 260, 260, 260, 260, 260, 260, 260, 260, 261, 259,  12, 262, 263, 263,
+   263, 263, 263, 263, 264, 150, 150, 150, 150, 150, 150, 265,   0,  12,  12, 131,
+   150, 150, 150, 266, 260, 260, 260, 261, 260, 260,   0,   0, 267, 267, 267, 267,
+   267, 267, 267, 268, 267, 269,  12,  12, 270, 270, 270, 270, 271, 271, 271, 271,
+   271, 271, 271,  12, 272, 272, 272, 272, 272, 272,  12,  12, 237,   2,   2,   2,
+     2,   2, 231,   2,   2,   2, 273,  12, 274, 275, 276,  12, 277,   2,   2,   2,
+   278, 278, 278, 278, 278, 278, 278, 279,   0,   0, 246,  12, 280, 280, 280, 280,
+   280, 280,  12,  12, 281, 281, 281, 281, 281, 282,  12, 283, 281, 281, 282,  12,
+   284, 284, 284, 284, 284, 284, 284, 285, 286, 286, 286, 286, 286,  12,  12, 287,
+   150, 150, 150, 288, 289, 289, 289, 289, 289, 289, 289, 290, 289, 289, 291, 292,
+   145, 145, 145, 293, 294, 294, 294, 294, 294, 295,  12,  12, 294, 294, 294, 296,
+   294, 294, 296, 294, 297, 297, 297, 297, 298,  12,  12,  12,  12,  12, 299, 297,
+   300, 300, 300, 300, 300, 301,  12,  12, 155, 154, 155, 154, 155, 154,  12,  12,
+     2,   2,   3,   2,   2, 302, 303,  12, 300, 300, 300, 304, 300, 300, 304,  12,
+   150,  12,  12,  12, 150, 265, 305, 150, 150, 150, 150,  12, 247, 247, 247, 249,
+   247, 247, 249,  12,   2, 273,  12,  12, 306,  22,  12,  24,  25,  26,  25, 307,
+   308, 309,  25,  25,  50,  12,  12,  12, 310,  29,  29,  29,  29,  29,  29, 311,
+   312,  29,  29,  29,  29,  29,  12, 310,   7,   7,   7, 313, 232,   0,   0,   0,
+     0, 232,   0,  12,  29, 314,  29,  29,  29,  29,  29, 315, 316,   0,   0,   0,
+     0, 317, 260, 260, 260, 260, 260, 318, 319, 150, 319, 150, 319, 150, 319, 288,
+     0, 232,   0, 232,  12,  12, 316, 246, 320, 320, 320, 321, 320, 320, 320, 320,
+   320, 322, 320, 320, 320, 320, 322, 323, 320, 320, 320, 324, 320, 320, 322,  12,
+   232, 131,   0,   0,   0, 131,   0,   0,   8,   8,   8,  14,   0,   0,   0, 234,
+   325,  12,  12,  12,   0,   0,   0, 326, 327, 327, 327, 327, 327, 327, 327, 328,
+   329, 329, 329, 329, 330,  12,  12,  12, 215,   0,   0,   0,   0,   0,   0,  12,
+   331, 331, 331, 331, 331,  12,  12, 332, 333, 333, 333, 333, 333, 333, 334,  12,
+   335, 335, 335, 335, 335, 335, 336,  12, 337, 337, 337, 337, 337, 337, 337, 338,
+   339, 339, 339, 339, 339,  12, 339, 339, 339, 340,  12,  12, 341, 341, 341, 341,
+   342, 342, 342, 342, 343, 343, 343, 343, 343, 343, 343, 344, 343, 343, 344,  12,
+   345, 345, 345, 345, 345,  12, 345, 345, 345, 345, 345,  12, 346, 346, 346, 346,
+   346, 346,  12,  12, 347, 347, 347, 347, 347,  12,  12, 348, 349, 349, 350, 349,
+   350, 351, 349, 349, 351, 349, 349, 349, 351, 349, 351, 352, 353, 353, 353, 353,
+   353, 354,  12,  12, 353, 355,  12,  12, 353, 353,  12,  12,   2, 274,   2,   2,
+   356,   2, 273,  12, 357, 358, 359, 357, 357, 357, 357, 357, 357, 360, 361, 362,
+   363, 363, 363, 363, 363, 364, 363, 363, 365, 365, 365, 365, 366, 366, 366, 366,
+   366, 366, 366, 367,  12, 368, 366, 366, 369, 369, 369, 369, 370, 371, 372, 369,
+   373, 373, 373, 373, 373, 373, 373, 374, 375, 375, 375, 375, 375, 375, 376, 377,
+   378, 378, 378, 378, 379, 379, 379, 379, 379, 379,  12, 379, 380, 379, 379, 379,
+   381, 382,  12, 381, 381, 383, 383, 381, 381, 381, 381, 381, 381, 384, 385, 386,
+   381, 381, 387,  12, 388, 388, 388, 388, 389, 389, 389, 389, 390, 390, 390, 390,
+   390, 391, 392, 390, 390, 391,  12,  12, 393, 393, 393, 393, 393, 394, 395, 393,
+   396, 396, 396, 396, 396, 397, 396, 396, 398, 398, 398, 398, 399,  12, 398, 398,
+   400, 400, 400, 400, 401,  12, 402, 403,  12,  12, 402, 400, 404, 404, 404, 404,
+   404, 404, 405,  12, 406, 406, 406, 406, 407,  12,  12,  12, 407,  12, 408, 406,
+   409, 409, 409, 409, 409, 409,  12,  12, 409, 409, 410,  12, 411, 411, 411, 411,
+   411, 411, 412, 413, 413,  12,  12,  12,  12,  12,  12, 414, 415, 415, 415, 415,
+   415, 415,  12,  12, 416, 416, 416, 416, 416, 416, 417,  12, 418, 418, 418, 418,
+   418, 418, 419,  12, 420, 420, 420, 420, 420, 420, 420,  12, 421, 421, 421, 421,
+   421, 422,  12,  12, 423, 423, 423, 423, 423, 423, 423, 424, 425, 423, 423, 423,
+   423, 424,  12, 426, 427, 427, 427, 427, 428,  12,  12, 429, 430, 430, 430, 430,
+   430, 430, 431,  12, 430, 430, 432,  12, 433, 433, 433, 433, 433, 434, 433, 433,
+   433, 433,  12,  12, 435, 435, 435, 435, 435, 436,  12,  12, 437, 437, 437, 437,
+   118, 119, 119, 119, 119, 127,  12,  12, 438, 438, 438, 438, 439, 438, 438, 438,
+   440,  12,  12,  12, 441, 442, 443, 444, 441, 441, 441, 444, 441, 441, 445,  12,
+   446, 446, 446, 446, 446, 446, 447,  12, 446, 446, 448,  12, 449, 450, 449, 451,
+   451, 449, 449, 449, 449, 449, 452, 449, 452, 450, 453, 449, 449, 451, 451, 454,
+   455, 456,  12, 450, 449, 457, 449, 455, 449, 455,  12,  12, 458, 458, 458, 458,
+   458, 458, 458, 459, 460,  12,  12,  12, 461, 461, 461, 461, 461, 461,  12,  12,
+   461, 461, 462,  12, 463, 463, 463, 463, 463, 464, 463, 463, 463, 463, 463, 464,
+   465, 465, 465, 465, 465, 466,  12,  12, 465, 465, 467,  12, 178, 178, 178, 180,
+   468, 468, 468, 468, 468, 468, 469,  12, 470, 470, 470, 470, 470, 470, 471, 472,
+   470, 470, 470,  12, 470, 471,  12,  12, 473, 473, 473, 473, 473, 473, 473,  12,
+   474, 474, 474, 474, 475,  12,  12, 476, 477, 478, 479, 477, 477, 480, 477, 477,
+   477, 477, 477, 477, 477, 481, 482, 477, 477, 478,  12,  12, 477, 477, 483,  12,
+   484, 484, 485, 484, 484, 484, 484, 484, 484, 486,  12,  12, 487, 487, 487, 487,
+   487, 487,  12,  12, 488, 488, 488, 488, 489,  12,  12,  12, 490, 490, 490, 490,
+   490, 490, 491,  12,  53,  53, 492,  12, 493, 493, 494, 493, 493, 493, 493, 493,
+   493, 495, 493, 493, 493, 496,  12,  12, 493, 493, 493, 497, 498, 498, 498, 498,
+   499, 498, 498, 498, 498, 498, 500, 498, 498, 501,  12,  12, 502, 503, 504, 502,
+   502, 502, 502, 502, 502, 503, 505, 504, 502, 502,  12,  12, 502, 502, 506,  12,
+   507, 508, 509, 507, 507, 507, 507, 507, 507, 507, 507, 510, 508, 507, 511,  12,
+   507, 507, 512,  12, 513, 513, 513, 513, 513, 513, 514,  12, 515, 515, 515, 515,
+   516, 515, 515, 515, 515, 515, 517, 518, 515, 515, 519,  12, 520,  12,  12,  12,
+   100, 100, 100, 100,  96,  12,  12,  98, 521, 521, 521, 521, 521, 521, 522,  12,
+   521, 521, 521, 523, 521, 524,  12,  12, 521,  12,  12,  12, 525, 525, 525, 525,
+   526,  12,  12,  12, 527, 527, 527, 527, 527, 528,  12,  12, 529, 529, 529, 529,
+   529, 530,  12,  12, 272, 272, 531,  12, 532, 532, 532, 532, 532, 532, 532, 533,
+   532, 532, 534, 535, 536, 536, 536, 536, 536, 536, 536, 537, 536, 536, 538,  12,
+   539, 539, 539, 539, 539, 539, 539, 540, 539, 540,  12,  12, 541, 541, 541, 541,
+   541, 542,  12,  12, 541, 541, 543, 541, 543, 541, 541, 541, 541, 541,  12, 544,
+   545, 545, 545, 545, 545, 545, 546,  12, 547, 547, 547, 547, 547, 547, 548, 549,
+   547, 547,  12, 549, 550, 551,  12,  12, 249,  12,  12,  12, 552, 552, 552, 552,
+   552, 552,  12,  12, 553, 553, 553, 553, 553, 554,  12,  12, 552, 552, 555,  12,
+   260, 556, 260, 557, 558, 255, 255, 255, 559,  12,  12,  12, 560,  12,  12,  12,
+   256, 561,  12,  12,  12, 260,  12,  12, 562, 562, 562, 562, 562, 562, 562,  12,
+   563, 563, 563, 563, 563, 563, 564,  12, 563, 563, 563, 565, 563, 563, 565,  12,
+   563, 563, 566, 563,   0,  12,  12,  12,   7,   7,   7, 567,   7, 199,  12,  12,
+     0, 246,  12,  12,   0, 232, 316,   0,   0, 568, 228,   0,   0,   0, 568,   7,
+   213, 569,   7,   0,   0,   0, 570, 228,   8, 225,  12,  12,   0,   0, 234,  12,
+     0,   0,   0, 229, 571, 572, 316, 229,   0,   0, 240, 316,   0, 316,   0,   0,
+     0, 240, 232, 316,   0, 229,   0, 229,   0,   0, 240, 232,   0, 573, 239,   0,
+   229,   0,   0,   0,   0, 246,   0,   0,   0,   0,   0, 239, 574, 574, 574, 574,
+   574, 574, 574,  12,  12,  12, 575, 574, 576, 574, 574, 574,   2,   2,   2, 273,
+    12, 275, 273,  12, 241, 577, 241, 241, 241, 241, 578, 241, 579, 580, 577,  12,
+    19,  19,  19, 581,  12,  12,  12, 582, 583, 583, 583, 583, 583, 583, 583, 584,
+   583, 583, 583, 585, 583, 583, 585, 586, 587, 587, 587, 587, 587, 587, 587, 588,
+   589, 589, 589, 589, 589, 589, 590, 591, 592, 592, 592, 592, 592, 592, 593,  12,
+   151, 154, 151, 594, 151, 151, 151, 154, 595, 595, 595, 595, 595, 596, 595, 595,
+   595, 597,  12,  12, 598, 598, 598, 598, 598, 598, 598,  12, 598, 598, 599, 600,
+     0, 234,  12,  12,  29, 414,  29,  29, 601, 602, 414,  29,  50,  29, 603,  12,
+   604, 310, 603, 414, 601, 602, 603, 603, 601, 602,  50,  29,  50,  29, 414, 605,
+    29,  29, 606,  29,  29,  29,  29,  12, 414, 414, 606,  29,  51,  12,  12,  12,
+    12, 239,   0,   0, 607,  12,  12,  12, 246,  12,  12,  12,   0,   0,  12,   0,
+     0, 232, 131,   0,   0,   0,  12,  12,   0,   0,   0, 240,   0, 246,  12, 239,
+   608,  12,  12,  12, 247, 247, 609,  12, 610,  12,  12,  12,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 939, 940, 941, 942,
+   946, 948,   0, 962, 969, 970, 971, 976,1001,1002,1003,1008,   0,1033,1040,1041,
+  1042,1043,1047,   0,   0,1080,1081,1082,1086,1110,   0,   0,1124,1125,1126,1127,
+  1131,1133,   0,1147,1154,1155,1156,1161,1187,1188,1189,1193,   0,1219,1226,1227,
+  1228,1229,1233,   0,   0,1267,1268,1269,1273,1298,   0,1303, 943,1128, 944,1129,
+   954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149,   0,   0, 973,1158,
+   974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175, 991,1176, 993,1178,
+   994,1179,   0,   0,1004,1190,1005,1191,1006,1192,1014,1199,1007,   0,   0,   0,
+  1016,1201,1020,1206,   0,1022,1208,1025,1211,1023,1209,   0,   0,   0,   0,1032,
+  1218,1037,1223,1035,1221,   0,   0,   0,1044,1230,1045,1231,1049,1235,   0,   0,
+  1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258,1069,1255,1077,1264,
+  1074,1261,   0,   0,1083,1270,1084,1271,1085,1272,1088,1275,1089,1276,1096,1283,
+  1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310,   0,1053,1239,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1093,1280,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0, 949,1134,1010,1195,1050,1236,1090,
+  1277,1341,1368,1340,1367,1342,1369,1339,1366,   0,1320,1347,1418,1419,1323,1350,
+     0,   0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424,1202,   0,   0,   0,
+   987,1172,   0,   0,1031,1217,1321,1348,1322,1349,1338,1365, 950,1135, 951,1136,
+   979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238,1061,1247,1062,1248,
+  1091,1278,1092,1279,1071,1257,1076,1263,   0,   0, 997,1182,   0,   0,   0,   0,
+     0,   0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232,1422,1423,1113,1301,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   8,   9,   0,  10,
+  1425,   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,   1,   0,   0,   0,   0,   0,
+     0,1314,1427,   5,1434,1438,1443,   0,1450,   0,1455,1461,1514,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1446,1458,1468,1476,1480,1486,1517,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1489,1503,1494,1500,1508,   0,   0,   0,   0,1520,
+  1521,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1526,1528,   0,1525,
+     0,   0,   0,1522,   0,   0,   0,   0,1536,1532,1539,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,1534,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,1556,   0,   0,   0,   0,   0,   0,1548,1550,   0,1547,
+     0,   0,   0,1567,   0,   0,   0,   0,1558,1554,1561,   0,   0,   0,   0,   0,
+     0,   0,1568,1569,   0,   0,   0,   0,   0,   0,   0,   0,   0,1529,1551,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1523,1545,1524,1546,
+     0,   0,1527,1549,   0,   0,1570,1571,1530,1552,1531,1553,   0,   0,1533,1555,
+  1535,1557,1537,1559,   0,   0,1572,1573,1544,1566,1538,1560,1540,1562,1541,1563,
+  1542,1564,   0,   0,1543,1565,   0,   0,   0,   0,   0,   0,   0,   0,1606,1607,
+  1609,1608,1610,   0,   0,   0,   0,   0,   0,   0,   0,   0,1613,   0,1611,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1612,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,1620,   0,   0,   0,   0,   0,   0,   0,1623,   0,   0,
+  1624,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1614,1615,1616,1617,1618,1619,1621,1622,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,1628,1629,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1625,1626,   0,1627,   0,   0,   0,1634,
+     0,   0,1635,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,1630,1631,1632,   0,   0,1633,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1639,   0,   0,1638,1640,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1636,1637,   0,   0,   0,   0,   0,   0,
+  1641,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1642,1644,1643,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1645,   0,   0,   0,   0,   0,   0,   0,1646,   0,   0,   0,
+     0,   0,   0,1648,1649,   0,1647,1650,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1651,1653,1652,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1654,   0,1655,1657,1656,   0,   0,   0,   0,1659,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1660,   0,   0,   0,   0,1661,   0,
+     0,   0,   0,1662,   0,   0,   0,   0,1663,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,1658,   0,   0,   0,   0,   0,   0,   0,   0,   0,1664,
+     0,1665,1673,   0,1674,   0,   0,   0,   0,   0,   0,   0,   0,1666,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1668,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1669,   0,   0,   0,   0,1670,   0,
+     0,   0,   0,1671,   0,   0,   0,   0,1672,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,1667,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,1675,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,1676,   0,1677,   0,1678,   0,1679,   0,1680,   0,   0,   0,1681,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,1682,   0,1683,   0,   0,1684,1685,   0,1686,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 953,1138, 955,1140,
+   956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153, 966,1151, 967,1152,
+  1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171, 989,1174, 995,1180,
+   998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356,1017,1203,1019,1205,
+  1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214,1029,1215,1030,1216,
+  1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363,1382,1384,1383,1385,
+  1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251,1068,1254,1070,1256,
+  1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266,1078,1265,1095,1282,
+  1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287,1101,1288,1102,1289,
+  1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302,1119,1308,1122,1311,
+  1123,1312,1186,1260,1293,1305,   0,1394,   0,   0,   0,   0, 952,1137, 947,1132,
+  1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375,1370,1374,1373,1377,
+  1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353,1325,1352,1328,1355,
+  1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234,1331,1358,1330,1357,
+  1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403,1397,1402,1399,1404,
+  1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412,1409,1414,1109,1297,
+  1117,1306,1116,1304,1112,1300,   0,   0,   0,   0,   0,   0,1471,1472,1701,1705,
+  1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721,1477,1478,1729,1731,
+  1730,1732,   0,   0,1435,1436,1733,1735,1734,1736,   0,   0,1481,1482,1737,1741,
+  1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757,1490,1491,1765,1768,
+  1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776,1495,1496,1777,1779,
+  1778,1780,   0,   0,1451,1452,1781,1783,1782,1784,   0,   0,1504,1505,1785,1788,
+  1786,1789,1787,1790,   0,1459,   0,1791,   0,1792,   0,1793,1509,1510,1794,1798,
+  1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814,1467,  21,1475,  22,
+  1479,  23,1485,  24,1493,  27,1499,  28,1507,  29,   0,   0,1704,1708,1709,1710,
+  1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728,1740,1744,1745,1746,
+  1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764,1797,1801,1802,1803,
+  1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821,1470,1469,1822,1474,
+  1465,   0,1473,1825,1429,1428,1426,  12,1432,   0,  26,   0,   0,1315,1823,1484,
+  1466,   0,1483,1829,1433,  13,1437,  14,1441,1826,1827,1828,1488,1487,1513,  19,
+     0,   0,1492,1515,1445,1444,1442,  15,   0,1831,1832,1833,1502,1501,1516,  25,
+  1497,1498,1506,1518,1457,1456,1454,  17,1453,1313,  11,   3,   0,   0,1824,1512,
+  1519,   0,1511,1830,1449,  16,1460,  18,1464,   4,   0,   0,  30,  31,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,  20,   0,   0,   0,   2,   6,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1834,1835,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1836,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1837,1839,1838,   0,   0,   0,   0,
+  1840,   0,   0,   0,   0,1841,   0,   0,1842,   0,   0,   0,   0,   0,   0,   0,
+  1843,   0,1844,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1845,   0,   0,
+  1846,   0,   0,1847,   0,1848,   0,   0,   0,   0,   0,   0, 937,   0,1850,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1849, 936, 938,1851,1852,   0,   0,
+  1853,1854,   0,   0,1855,1856,   0,   0,   0,   0,   0,   0,1857,1858,   0,   0,
+  1861,1862,   0,   0,1863,1864,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1867,1868,1869,1870,1859,1860,1865,1866,
+     0,   0,   0,   0,   0,   0,1871,1872,1873,1874,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,  32,  33,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1875,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1877,   0,1878,   0,1879,   0,1880,   0,
+  1881,   0,1882,   0,1883,   0,1884,   0,1885,   0,1886,   0,1887,   0,1888,   0,
+     0,1889,   0,1890,   0,1891,   0,   0,   0,   0,   0,   0,1892,1893,   0,1894,
+  1895,   0,1896,1897,   0,1898,1899,   0,1900,1901,   0,   0,   0,   0,   0,   0,
+  1876,   0,   0,   0,   0,   0,   0,   0,   0,   0,1902,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1904,   0,1905,   0,1906,   0,1907,   0,
+  1908,   0,1909,   0,1910,   0,1911,   0,1912,   0,1913,   0,1914,   0,1915,   0,
+     0,1916,   0,1917,   0,1918,   0,   0,   0,   0,   0,   0,1919,1920,   0,1921,
+  1922,   0,1923,1924,   0,1925,1926,   0,1927,1928,   0,   0,   0,   0,   0,   0,
+  1903,   0,   0,1929,1930,1931,1932,   0,   0,   0,1933,   0, 710, 385, 724, 715,
+   455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601, 663, 676, 688, 738,
+   411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662, 810, 275, 462, 658,
+   692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168, 368, 414, 481, 527,
+   606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758, 811, 701, 233, 299,
+   573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585, 594, 766, 167, 613,
+   149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259, 313, 496, 518, 174,
+   542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697, 424, 732, 428, 349,
+   632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170, 193, 245, 297, 374,
+   463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330, 337, 366, 459, 476,
+   509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473, 683, 697, 292, 311,
+   353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603, 608, 752, 778, 782,
+   788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411, 479, 523, 655, 737,
+   823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583, 791, 136, 340, 769,
+   122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269, 377, 391, 406, 432,
+   501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510, 659, 772, 805, 813,
+   397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156, 153, 288, 346, 578,
+   256, 435, 383, 729, 680, 767, 694, 295, 128, 210,   0,   0, 227,   0, 379,   0,
+     0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604,   0, 661,   0, 703,   0,
+     0, 735, 743,   0,   0,   0, 793, 794, 795, 808, 741, 773, 118, 127, 130, 166,
+   169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329, 335, 369, 375, 381,
+   404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548, 549, 550, 554, 555,
+   561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651, 690, 695, 705, 706,
+   716, 717, 733, 735, 777, 786, 790, 315, 869, 623,   0,   0, 102, 145, 134, 115,
+   129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243, 250, 254, 294, 296,
+   303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362, 370, 379, 388, 389,
+   393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490, 493, 507, 512, 514,
+   521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586, 591, 597, 607, 637,
+   647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706, 709, 717, 728, 736,
+   747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848, 847, 857,  55,  65,
+    66, 883, 892, 916, 822, 824,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1586,   0,1605,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1602,1603,1934,1935,1574,1575,1576,1577,1579,1580,
+  1581,1583,1584,   0,1585,1587,1588,1589,1591,   0,1592,   0,1593,1594,   0,1595,
+  1596,   0,1598,1599,1600,1601,1604,1582,1578,1590,1597,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1936,   0,1937,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,1938,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1939,1940,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,1941,1942,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,1944,1943,   0,1945,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1946,1947,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1948,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1949,1950,1951,1952,1953,1954,
+  1955,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,1956,1957,1958,1960,1959,1961,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 106, 104, 107, 826,
+   114, 118, 119, 121, 123, 124, 127, 125,  34, 830, 130, 131, 132, 137, 827,  35,
+   133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152,  37, 157, 158, 159, 160,
+    38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179, 181, 182, 182, 182,
+   833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195, 197, 199, 200, 201,
+   203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216, 153, 234, 221, 222,
+   223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244, 836, 837, 247, 248,
+   249, 246, 251,  39,  40, 253, 255, 255, 838, 257, 258, 259, 261, 839, 262, 263,
+   301, 264,  41, 266, 270, 272, 271, 841, 274, 842, 277, 276, 278, 281, 282,  42,
+   283, 284, 285, 286,  43, 843,  44, 289, 290, 291, 293, 934, 298, 845, 845, 621,
+   300, 300,  45, 852, 894, 302, 304,  46, 306, 309, 310, 312, 316,  48,  47, 317,
+   846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334, 335, 336, 338, 339,
+   342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361, 358, 356,  49, 363,
+   365, 367, 364,  50, 369, 371, 851, 376, 386, 378,  53, 381,  52,  51, 140, 141,
+   387, 382, 614,  78, 388, 389, 390, 394, 392, 856,  54, 399, 396, 402, 404, 858,
+   405, 401, 407,  55, 408, 409, 410, 413, 859, 415,  56, 417, 860, 418,  57, 419,
+   422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433, 437, 441, 438, 439,
+   442, 443, 864, 436, 449, 450,  58, 454, 453, 865, 447, 460, 866, 867, 461, 466,
+   465, 464,  59, 467, 470, 469, 472, 828, 475, 868, 478, 870, 483, 485, 486, 871,
+   488, 489, 872, 873, 495, 497,  60, 498,  61,  61, 504, 505, 507, 508, 511,  62,
+   513, 874, 515, 875, 518, 844, 520, 876, 877, 878,  63,  64, 528, 880, 879, 881,
+   882, 530, 531, 531, 533,  66, 534,  67,  68, 884, 536, 538, 541,  69, 885, 549,
+   886, 887, 556, 559,  70, 561, 562, 563, 888, 889, 889, 567,  71, 890, 570, 571,
+    72, 891, 577,  73, 581, 579, 582, 893, 587,  74, 590, 592, 596,  75, 895, 896,
+    76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611, 853,  77, 615, 616,
+    79, 617, 252, 902, 903, 854, 855, 621, 622, 731,  80, 627, 626, 628, 164, 629,
+   630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651, 638, 643, 644, 645,
+   905, 907, 906,  81, 653, 654, 656, 911, 657, 908,  82,  83, 909, 910,  84, 664,
+   665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675,  85, 677, 678,  86, 681,
+   682, 912, 685, 686,  87, 689,  36, 913, 914,  88,  89, 696, 702, 709, 711, 915,
+   712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728, 918, 919, 739, 742,
+   744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762,  90, 764, 922,  91, 775,
+   279, 780, 923, 925,  92,  93, 785, 926,  94, 927, 787, 787, 789, 928, 792,  95,
+   796, 797, 798, 800,  96, 929, 802, 804, 806,  97,  98, 807, 930,  99, 931, 932,
+   933, 814, 100, 816, 817, 818, 819, 820, 821, 935,   0,   0,
+};
+static const int16_t
+_hb_ucd_i16[92] =
 {
-      0,    0,    0,    0,    1,   -1,    0,    0,    2,    0,   -2,    0,    0,    0,    0,    2,
-      0,   -2,    0,    0,    0,    0,    0,   16,    0,    0,    0,  -16,    0,    0,    1,   -1,
-      0,    0,    0,    1,   -1,    0,    0,    0,    0,    1,   -1,    0,    3,    3,    3,   -3,
-     -3,   -3,    0,    0,    0, 2016,    0,    0,    0,    0,    0, 2527, 1923, 1914, 1918,    0,
-   2250,    0,    0,    0,    0,    0,    0,  138,    0,    7,    0,    0,   -7,    0,    0,    0,
-      1,   -1,    1,   -1,   -1,    1,   -1,    0, 1824,    0,    0,    0,    0,    0, 2104,    0,
-   2108, 2106,    0, 2106, 1316,    0,    0,    0,    0,    1,   -1,    1,   -1, -138,    0,    0,
-      1,   -1,    8,    8,    8,    0,    7,    7,    0,    0,   -8,   -8,   -8,   -7,   -7,    0,
-      1,   -1,    0,    2,-1316,    1,   -1,    0,   -1,    1,   -1,    1,   -1,    3,    1,   -1,
-     -3,    1,   -1,    1,   -1,    0,    0,-1914,-1918,    0,    0,-1923,-1824,    0,    0,    0,
-      0,-2016,    0,    0,    1,   -1,    0,    1,    0,    0,-2104,    0,    0,    0,    0,-2106,
-  -2108,-2106,    0,    0,    1,   -1,-2250,    0,    0,    0,-2527,    0,    0,   -2,    0,    1,
-     -1,    0,    1,   -1,
+      0,    0,    1,   -1,    2,    0,   -2,    0,    0,    2,    0,   -2,    0,   16,    0,  -16,
+      0,    1,   -1,    0,    3,    3,    3,   -3,   -3,   -3,    0, 2016,    0, 2527, 1923, 1914,
+   1918,    0, 2250,    0,    0,  138,    0,    7,   -7,    0,   -1,    1, 1824,    0, 2104,    0,
+   2108, 2106,    0, 2106, 1316,    0,   -1, -138,    8,    8,    8,    0,    7,    7,   -8,   -8,
+     -8,   -7,-1316,    1,   -1,    3,   -3,    1,    0,-1914,-1918,    0,    0,-1923,-1824,    0,
+      0,-2016,-2104,    0,    0,-2106,-2108,-2106,-2250,    0,-2527,    0,
 };
 
 static inline uint_fast8_t
 _hb_ucd_gc (unsigned u)
 {
-  return u<1114110u?_hb_ucd_u8[6664+(((_hb_ucd_u8[1296+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
+  return u<1114110u?_hb_ucd_u8[6808+(((_hb_ucd_u8[1312+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
 }
 static inline uint_fast8_t
 _hb_ucd_ccc (unsigned u)
 {
-  return u<125259u?_hb_ucd_u8[8984+(((_hb_ucd_u8[7960+(((_hb_ucd_u8[7288+(((_hb_ucd_u8[7042+(u>>2>>3>>4)])<<4)+((u>>2>>3)&15u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u))]:0;
+  return u<125259u?_hb_ucd_u8[8800+(((_hb_ucd_u8[8244+(((_hb_ucd_u8[7784+(((_hb_ucd_u8[7432+(((_hb_ucd_u8[7186+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
 }
 static inline unsigned
 _hb_ucd_b4 (const uint8_t* a, unsigned i)
@@ -5660,24 +4418,24 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i)
 static inline int_fast16_t
 _hb_ucd_bmg (unsigned u)
 {
-  return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9728+(((_hb_ucd_u8[9608+(((_hb_ucd_b4(9480+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
+  return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9692+(((_hb_ucd_u8[9460+(((_hb_ucd_u8[9364+(((_hb_ucd_b4(9300+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0;
 }
 static inline uint_fast8_t
 _hb_ucd_sc (unsigned u)
 {
-  return u<918000u?_hb_ucd_u8[11234+(((_hb_ucd_u16[2000+(((_hb_ucd_u8[10514+(((_hb_ucd_u8[10064+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2;
+  return u<918000u?_hb_ucd_u8[11126+(((_hb_ucd_u16[4040+(((_hb_ucd_u16[2048+(((_hb_ucd_u8[10390+(((_hb_ucd_u8[9940+(u>>2>>2>>3>>4)])<<4)+((u>>2>>2>>3)&15u))])<<3)+((u>>2>>2)&7u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2;
 }
 static inline uint_fast16_t
 _hb_ucd_dm (unsigned u)
 {
-  return u<195102u?_hb_ucd_u16[5888+(((_hb_ucd_u8[17136+(((_hb_ucd_u8[16754+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+  return u<195102u?_hb_ucd_u16[6748+(((_hb_ucd_u8[13952+(((_hb_ucd_u8[13570+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
 }
 
 
 #else
 
 static const uint8_t
-_hb_ucd_u8[13602] =
+_hb_ucd_u8[13386] =
 {
     0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
     7,  7,  7,  7,  9, 10,  7,  7,  7,  7,  7, 11, 12, 12, 12, 13,
@@ -5685,7 +4443,7 @@ _hb_ucd_u8[13602] =
     7, 24, 21, 21, 21, 25, 26, 27, 21, 28, 29, 30, 31, 32, 33, 34,
     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 35, 21, 36,
-    7,  7, 37, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    7,  7,  7,  7, 37, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
@@ -5730,28 +4488,28 @@ _hb_ucd_u8[13602] =
    34, 34,109,110,111,112,113,114,115,116,117,118, 34, 34, 34,119,
   120,121,122,123,124,125,126,127, 34,128,129,111,130,131,132,133,
   134,135,136,137,138,139,140,111,141,142,111,143,144,145,146,111,
-  147,148,149,150,151,152,111,111,153,154,155,156,111,157,111,158,
-   34, 34, 34, 34, 34, 34, 34, 34,159, 34, 34,111,111,111,111,111,
-  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,160,
-   34, 34, 34, 34, 34, 34, 34, 34,161,111,111,111,111,111,111,111,
+  147,148,149,150,151,152,153,111,154,155,156,157,111,158,159,160,
+   34, 34, 34, 34, 34, 34, 34, 34,161, 34, 34,111,111,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,162,
+   34, 34, 34, 34, 34, 34, 34, 34,163,111,111,111,111,111,111,111,
   111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
   111,111,111,111,111,111,111,111, 34, 34, 34, 34, 34,111,111,111,
-   34, 34, 34, 34,162,163,164, 34,111,111,111,111,165,166,167,168,
+   34, 34, 34, 34,164,165,166, 34,111,111,111,111,167,168,169,170,
    34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,
   111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,119,
    34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111,
-  111,111,111,111,111,111,111,111, 34,169,111,111,111,111,111,111,
-  111,111,111,111,111,111,111,111,111,111,111,111,111,111,170, 67,
-   67, 67,171,172,173,130, 65,111,174,175,176,177,178,179,180,181,
-   67, 67, 67, 67,182,183,111,111,111,111,111,111,111,111,184,111,
-  185,111,186,111,111,187,111,111,111,111,111,111,111,111,111, 34,
-   34,188,189,111,111,111,111,111,130,190,191,111, 34,192,111,111,
-   67, 67,193, 67, 67,111, 67,194, 67, 67, 67, 67, 67, 67, 67, 67,
-   67, 67, 67, 67, 67, 67, 67,195,111,111,111,111,111,111,111,111,
-   34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111, 34,171,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,172, 67,
+   67, 67,173,174,175,130, 65,111,176,177,178,179,180,181,182,183,
+   67, 67, 67, 67,184,185,111,111,111,111,111,111,111,111,186,111,
+  187,188,189,111,111,190,111,111,111,191,111,111,111,111,111, 34,
+   34,192,193,111,111,111,111,111,130,194,195,111, 34,196,111,111,
+   67, 67,197, 67, 67,111, 67,198, 67, 67, 67, 67, 67, 67, 67, 67,
+   67, 67, 67, 67, 67, 67, 67,199,111,111,111,111,111,111,111,111,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,
    34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111,111,
-   34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,
-  196,111,185,185,111,111,111,111,111,111,111,111,111,111,111,111,
+   34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,
+  200,111,188,188,111,111,111,111,111,111,111,111,111,111,111,111,
     0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  2,  4,  5,  6,  2,
     7,  7,  7,  7,  7,  2,  8,  9, 10, 11, 11, 11, 11, 11, 11, 11,
    11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16,
@@ -5807,7 +4565,7 @@ _hb_ucd_u8[13602] =
    36, 36, 36, 36, 36, 36, 65, 43, 77, 78, 78, 43, 43, 43, 43, 43,
    43, 43, 43, 43, 36, 36, 36, 36,  7,  7,  7, 85, 27, 27, 27, 84,
    64, 78, 66, 36, 36, 36, 36, 36, 78, 78, 78, 77, 78, 78, 43, 43,
-   43, 43, 77, 78, 78, 78, 81, 36, 86, 36, 36, 36, 36, 36, 36, 36,
+   43, 43, 77, 78, 78, 78, 81, 36, 86, 82, 78, 78, 78, 78, 78, 78,
    43, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 65, 78,
    79, 43, 43, 78, 78, 78, 79, 71, 61, 61, 36, 82, 27, 27, 27, 87,
    27, 27, 27, 27, 84, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 77,
@@ -5947,7 +4705,7 @@ _hb_ucd_u8[13602] =
    36, 64,  2, 36, 36, 36, 36, 36, 36, 82, 78, 43, 43, 43, 43, 77,
    81, 36, 58,  2, 56, 43, 57, 79,  7,  7,  7,  7,  7, 58, 58,  2,
    90, 27, 27, 27, 27, 27, 27, 27, 36, 36, 36, 36, 36, 36, 78, 79,
-   43, 78, 77, 43,  2,  2,  2, 43, 36, 36, 36, 36, 36, 36, 36, 64,
+   43, 78, 77, 43,  2,  2,  2, 65, 36, 36, 36, 36, 36, 36, 36, 64,
    77, 78, 78, 78, 78, 78, 78, 78, 36, 36, 36, 82, 78, 78, 81, 36,
    36, 78, 78, 43, 43, 43, 43, 43, 36, 36, 82, 78, 43, 43, 43, 43,
    78, 43, 77, 65, 36, 58,  2,  2,  7,  7,  7,  7,  7,  2,  2, 65,
@@ -5968,8 +4726,10 @@ _hb_ucd_u8[13602] =
    43, 43, 43, 43, 77, 43, 43, 43, 77, 43, 79, 43, 43, 43, 43, 43,
    43, 43, 43, 64, 43, 43, 43, 43, 36, 36, 36, 36, 36, 78, 78, 78,
    43, 77, 79, 79, 36, 36, 36, 36, 36, 64, 77, 97,  2,  2,  2,  2,
-   27, 27, 84, 61, 61, 61, 53, 20,150, 61, 61, 61, 61, 61, 61, 61,
-   61, 61, 61, 61, 61, 61, 61, 21, 43, 43, 57,  2,  2,  2,  2,  2,
+   43, 82, 36, 36, 36, 36, 36, 36, 36, 36, 78, 43, 43, 43, 43, 78,
+   77, 57,  2,  2,  2,  2,  2,  2, 27, 27, 84, 61, 61, 61, 53, 20,
+  150, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 21,
+   65, 36, 36, 64, 43, 43, 43, 43, 43, 43, 57,  2,  2,  2,  2,  2,
    43, 43, 43, 57,  2,  2, 61, 61, 40, 40, 89, 61, 61, 61, 61, 61,
     7,  7,  7,  7,  7,167, 27, 27, 27, 87, 36, 36, 36, 36, 36, 36,
    27, 27, 27, 30,  2,  2,  2,  2, 82, 78, 78, 78, 78, 78, 78, 78,
@@ -5992,485 +4752,469 @@ _hb_ucd_u8[13602] =
    16, 16, 16, 16, 16, 39, 16, 16, 43, 43, 43, 68, 40, 40, 40, 40,
     7,  7,  7,  7,  7,  7,  7, 71, 36, 36, 36, 36, 36, 36, 36, 43,
    36, 36, 36, 36, 36, 36, 43, 43,  7,  7,  7,  7,  7,  7,  7,170,
-   16, 16, 43, 43, 43, 68, 40, 40, 27, 27, 27, 27, 27, 27,145, 27,
-  171, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,145,
-   27, 27, 27, 27, 27, 27, 84, 61, 61, 61, 61, 61, 61, 25, 41, 41,
-    0,  0, 29, 21, 21, 21, 23, 21, 22, 18, 21, 25, 21, 17, 13, 13,
-   25, 25, 25, 21, 21,  9,  9,  9,  9, 22, 21, 18, 24, 16, 24,  5,
-    5,  5,  5, 22, 25, 18, 25,  0, 23, 23, 26, 21, 24, 26,  7, 20,
-   25,  1, 26, 24, 26, 25, 15, 15, 24, 15,  7, 19, 15, 21,  9, 25,
-    9,  5,  5, 25,  5,  9,  5,  7,  7,  7,  9,  8,  8,  5,  7,  5,
-    6,  6, 24, 24,  6, 24, 12, 12,  6,  5,  9, 21, 25,  9, 26, 12,
-   11, 11,  9,  6,  5, 21, 17, 17, 17, 26, 26, 23, 23, 12, 17, 12,
-   21, 12, 12, 21,  7, 21,  1,  1, 21, 23, 26, 26,  1, 21,  6,  7,
-    7, 12, 12,  7, 21,  7, 12,  1, 12,  6,  6, 12, 12, 26,  7, 26,
-   26,  7, 21,  1, 24,  7,  7,  6,  1, 12, 12, 10, 10, 10, 10, 12,
-   21,  6, 10,  7,  7, 10, 23,  7, 15, 26, 13, 21, 13,  7, 15,  7,
-   12, 23, 21, 26, 21, 15, 17,  7, 29,  7,  7, 22, 18, 18, 14, 14,
-   14,  7, 10, 21, 17, 21, 11, 12,  5,  6,  8,  8,  8, 24,  5, 24,
-    9, 24, 29, 29, 29,  1, 20, 19, 22, 20, 27, 28,  1, 29, 21, 20,
-   19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29, 15,  6, 18,  6,
-   12, 11,  9, 26, 26,  9, 26,  5,  5, 26, 14,  9,  5, 14, 14, 15,
-   25, 26, 26, 22, 18, 26, 18, 25, 18, 22,  5, 12, 22, 21, 21, 22,
-   18, 17, 26,  6,  7, 14, 17, 22, 26, 14, 17,  6, 14,  6, 12, 24,
-   24,  6, 26, 15,  6, 21, 11, 21, 24,  9,  6,  9, 23, 26,  6, 10,
-    4,  4,  3,  3,  7, 25, 17, 16, 16, 22, 16, 16, 25, 17,  7,  1,
-   25, 24, 26,  1,  2,  2, 12, 15, 21, 14,  7, 15, 12, 17, 13, 15,
-   26, 10, 10,  1, 13, 23, 23, 15,  0,  1,  2,  3,  4,  5,  6,  7,
-    8,  9,  0, 10, 11, 12, 13,  0, 14,  0,  0,  0,  0,  0, 15,  0,
-   16,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 17, 18, 19,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0, 20,  0, 21, 22, 23,  0,  0,  0, 24, 25, 26,
-   27, 28, 29, 30, 31, 32, 33,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 34,  0, 35,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 36,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-   37, 38,  0,  0,  0,  0,  0,  0, 39, 40,  0,  0, 41,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  0,  0,  0,  0,
-    3,  0,  0,  0,  4,  5,  6,  7,  0,  8,  9, 10,  0, 11, 12, 13,
-   14, 15, 16, 17, 16, 18, 16, 19, 16, 19, 16, 19,  0, 19, 16, 20,
-   16, 19, 21, 19,  0, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,  0,
-   32,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 33,  0,  0,  0,  0,
-    0,  0, 34,  0,  0, 35,  0,  0, 36,  0, 37,  0,  0,  0, 38, 39,
-   40, 41, 42, 43, 44, 45, 46,  0,  0, 47,  0,  0,  0, 48,  0,  0,
-    0, 49,  0,  0,  0,  0,  0,  0,  0, 50,  0, 51,  0, 52, 53,  0,
-   54,  0,  0,  0,  0,  0,  0, 55, 56, 57,  0,  0,  0,  0, 58,  0,
-    0, 59, 60, 61, 62, 63,  0,  0, 64, 65,  0,  0,  0, 66,  0,  0,
-    0,  0, 67,  0,  0,  0, 68,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0, 69,  0,  0,  0, 70,  0, 71,  0,  0, 72,  0,
-    0, 73,  0,  0,  0,  0,  0,  0,  0,  0, 74,  0,  0,  0,  0,  0,
-   75,  0,  0, 76, 77,  0,  0, 78, 79,  0, 80, 62,  0, 81, 82,  0,
-    0, 83, 84, 85,  0,  0,  0, 86,  0, 87,  0,  0, 51, 88, 51,  0,
-   89,  0, 90,  0,  0,  0, 79,  0,  0,  0, 91, 92,  0, 93, 94, 95,
-   96,  0,  0,  0,  0,  0, 51,  0,  0,  0,  0, 97, 98,  0,  0,  0,
-    0, 99,100,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,101,  0,  0,
-  102,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,103,104,  0,  0,105,
-    0,  0,  0,  0,  0,  0,106,  0,  0,  0,100,  0,  0,  0,  0,  0,
-  107,108,  0,  0,  0,  0,  0,  0,  0,109,  0,110,  0,  0,  0,  0,
-    0,  0,  1,  2,  3,  4,  5,  6,  7,  0,  8,  0,  0,  0,  0,  9,
-   10, 11, 12,  0,  0,  0,  0, 13,  0,  0, 14, 15,  0, 16,  0, 17,
-   18,  0,  0, 19,  0, 20, 21,  0,  0,  0,  0,  0, 22, 23,  0, 24,
-   25,  0,  0, 26,  0,  0,  0, 27,  0,  0, 28, 29, 30, 31,  0,  0,
-    0, 32, 33, 34,  0,  0, 33,  0,  0, 35, 33,  0,  0,  0, 33, 36,
-    0,  0,  0,  0,  0, 37, 38,  0,  0,  0,  0,  0,  0, 39, 40,  0,
-    0,  0,  0,  0,  0, 41, 42,  0,  0,  0,  0, 43,  0, 44,  0,  0,
-    0, 45, 46,  0,  0,  0, 47,  0,  0,  0,  0,  0,  0, 48, 49,  0,
-    0,  0,  0, 50,  0,  0,  0, 51,  0, 52,  0, 53,  0,  0,  0,  0,
-   54,  0,  0,  0,  0, 55,  0, 56,  0,  0,  0,  0, 57, 58,  0,  0,
-    0, 59, 60,  0,  0,  0,  0,  0,  0, 61, 52,  0, 62, 63,  0,  0,
-   64,  0,  0,  0, 65, 66,  0,  0,  0, 67,  0, 68, 69, 70, 71, 72,
-    1, 73,  0, 74, 75, 76,  0,  0, 77, 78,  0,  0,  0, 79,  0,  0,
-    1,  1,  0,  0, 80,  0,  0, 81,  0,  0,  0,  0, 77, 82,  0, 83,
-    0,  0,  0,  0,  0, 78, 84,  0, 85,  0, 52,  0,  1, 78,  0,  0,
-   86,  0,  0, 87,  0,  0,  0,  0,  0, 88, 57,  0,  0,  0,  0,  0,
-    0, 89, 90,  0,  0, 84,  0,  0, 33,  0,  0, 91,  0,  0,  0,  0,
-   92,  0,  0,  0,  0, 49,  0,  0, 93,  0,  0,  0,  0, 94, 95,  0,
-    0, 96,  0,  0, 97,  0,  0,  0, 98,  0,  0,  0, 99,  0,100, 93,
-    0,  0,101,  0,  0,  0, 84,  0,  0,102,  0,  0,  0,103,104,  0,
-    0,105,106,  0,  0,  0,  0,  0,  0,107,  0,  0,108,  0,  0,  0,
-    0,109, 33,  0,110,111,112, 35,  0,  0,113,  0,  0,  0,114,  0,
-    0,  0,  0,  0,  0,115,  0,  0,116,  0,  0,  0,  0,117, 88,  0,
-    0,  0,  0,  0, 57,  0,  0,  0,  0, 52,118,  0,  0,  0,  0,119,
-    0,  0,120,  0,  0,  0,  0,118,  0,  0,  0,  0,  0,121,  0,  0,
-    0,122,  0,  0,  0,123,  0,124,  0,  0,  0,  0,125,126,127,  0,
-  128,  0,129,  0,  0,  0,130,131,132,  0,  0,  0, 35,  0,  0,  0,
-  133,  0,  0,134,  0,  0,135,  0,  0,  0,  0,  0,  0,  0,  1,  1,
-    1,  1,  1,  2,  3,  4,  5,  6,  7,  4,  4,  8,  9, 10,  1, 11,
-   12, 13, 14, 15, 16, 17, 18,  1,  1,  1, 19,  1,  0,  0, 20, 21,
-   22,  1, 23,  4, 21, 24, 25, 26, 27, 28, 29, 30,  0,  0,  1,  1,
-   31,  0,  0,  0, 32, 33, 34, 35,  1, 36, 37,  0,  0,  0,  0, 38,
-    1, 39, 14, 39, 40, 41, 42,  0,  0,  0, 43, 36, 44, 45, 21, 45,
-   46,  0,  0,  0, 19,  1, 21,  0,  0, 47,  0, 38, 48,  1,  1, 49,
-   49, 50,  0,  0, 51,  0,  0,  0, 52,  1,  0,  0, 38, 14,  4,  1,
-    1,  1, 53, 21, 43, 52, 54, 21, 35,  1,  0,  0,  0, 55,  0,  0,
-    0, 56, 57, 58,  0,  0,  0,  0,  0, 59,  0, 60,  0,  0,  0,  0,
-   61, 62,  0,  0, 63,  0,  0,  0, 64,  0,  0,  0, 65,  0,  0,  0,
-   66,  0,  0,  0, 67,  0,  0,  0, 68,  0,  0, 69, 70,  0, 71, 72,
-   73, 74, 75, 76,  0,  0,  0, 77,  0,  0,  0, 78, 79,  0,  0,  0,
-    0, 47,  0,  0,  0, 49,  0, 80,  0,  0,  0, 62,  0,  0, 63,  0,
-    0, 81,  0,  0, 82,  0,  0,  0, 83,  0,  0, 19, 84,  0, 62,  0,
-    0,  0,  0, 49,  1, 85,  1, 52, 15, 86, 36, 10, 21, 87,  0, 55,
-    0,  0,  0,  0, 19, 10,  1,  0,  0,  0,  0,  0, 88,  0,  0, 89,
-    0,  0, 88,  0,  0,  0,  0, 78,  0,  0, 87,  9, 12,  4, 90,  8,
-   91, 47,  0, 58, 50,  0, 21,  1, 21, 92, 93,  1,  1,  1,  1, 94,
-   95, 96, 97,  1, 98, 58, 81, 99,100,  4, 58,  0,  0,  0,  0,  0,
-    0, 19, 50,  0,  0,  0,  0,  0,  0, 61,  0,  0,101,102,  0,  0,
-  103,  0,  0,  1,  1, 50,  0,  0,  0, 38,  0, 63,  0,  0,  0,  0,
-    0, 62,  0,  0,104, 68, 61,  0,  0,  0, 78,  0,  0,  0,105,106,
-   58, 38, 81,  0,  0,  0,  0,  0,  0,107,  1, 14,  4, 12, 84,  0,
-    0,  0,  0, 38, 87,  0,  0,  0,  0,108,  0,  0,109, 61,  0,110,
-    0,  0,  0,  1,  0,  0,  0,  0, 19, 58,  0,111, 14, 52,112, 41,
-    0,  0, 62,  0,  0, 61,  0,  0,113,  0, 87,  0,  0,  0, 61, 62,
-    0,  0, 62,  0, 89,  0,  0,113,  0,  0,  0,  0,114,  0,  0,  0,
-   78, 55,  0, 38,  1, 58,  1, 58,  0,  0, 63, 89,  0,  0,115,  0,
-    0,  0, 55,  0,  0,  0,  0,115,  0,  0,  0,  0, 61,  0,  0,  0,
-    0, 79,  0, 61,  0,  0,  0,  0, 56,  0, 89, 80,  0,  0,  8, 91,
+   36, 36, 36, 36, 36, 75, 43, 43, 16, 16, 43, 43, 43, 68, 40, 40,
+   27, 27, 27, 27, 27, 27,145, 27,171, 27, 27, 27, 27, 27, 27, 27,
+   27, 27, 27, 27, 27, 27, 27,145, 27, 27, 27, 27, 27, 27, 84, 61,
+   61, 61, 61, 61, 61, 25, 41, 41,  0,  0, 29, 21, 21, 21, 23, 21,
+   22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21,  9,  9,  9,
+    9, 22, 21, 18, 24, 16, 24,  5,  5,  5,  5, 22, 25, 18, 25,  0,
+   23, 23, 26, 21, 24, 26,  7, 20, 25,  1, 26, 24, 26, 25, 15, 15,
+   24, 15,  7, 19, 15, 21,  9, 25,  9,  5,  5, 25,  5,  9,  5,  7,
+    7,  7,  9,  8,  8,  5,  7,  5,  6,  6, 24, 24,  6, 24, 12, 12,
+    6,  5,  9, 21, 25,  9, 26, 12, 11, 11,  9,  6,  5, 21, 17, 17,
+   17, 26, 26, 23, 23, 12, 17, 12, 21, 12, 12, 21,  7, 21,  1,  1,
+   21, 23, 26, 26,  1, 21,  6,  7,  7, 12, 12,  7, 21,  7, 12,  1,
+   12,  6,  6, 12, 12, 26,  7, 26, 26,  7, 21,  1, 24,  7,  7,  6,
+    1, 12, 12, 10, 10, 10, 10, 12, 21,  6, 10,  7,  7, 10, 23,  7,
+   15, 26, 13, 21, 13,  7, 15,  7, 12, 23, 21, 26, 21, 15, 17,  7,
+   29,  7,  7, 22, 18, 18, 14, 14, 14,  7, 10, 21, 17, 21, 11, 12,
+    5,  6,  8,  8,  8, 24,  5, 24,  9, 24, 29, 29, 29,  1, 20, 19,
+   22, 20, 27, 28,  1, 29, 21, 20, 19, 21, 21, 16, 16, 21, 25, 22,
+   18, 21, 21, 29, 15,  6, 18,  6, 12, 11,  9, 26, 26,  9, 26,  5,
+    5, 26, 14,  9,  5, 14, 14, 15, 25, 26, 26, 22, 18, 26, 18, 25,
+   18, 22,  5, 12, 22, 21, 21, 22, 18, 17, 26,  6,  7, 14, 17, 22,
+   26, 14, 17,  6, 14,  6, 12, 24, 24,  6, 26, 15,  6, 21, 11, 21,
+   24,  9,  6,  9, 23, 26,  6, 10,  4,  4,  3,  3,  7, 25, 17, 16,
+   16, 22, 16, 16, 25, 17,  7,  1, 25, 24, 26,  1,  2,  2, 12, 15,
+   21, 14,  7, 15, 12, 17, 13, 15, 26, 10, 10,  1, 13, 23, 23, 15,
+    0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  0, 10, 11, 12, 13,  0,
+   14,  0,  0,  0,  0,  0, 15,  0, 16,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0, 17, 18, 19,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 20,  0, 21,
+   22, 23,  0,  0,  0, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0, 35,  0, 36,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 37,  0,
+    0,  0,  0,  0,  0,  0,  0,  0, 38, 39,  0,  0,  0,  0,  0,  0,
+   40, 41, 42,  0, 43,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  1,  2,  0,  0,  0,  0,  3,  0,  0,  0,  4,  5,  6,  7,
+    0,  8,  9, 10,  0, 11, 12, 13, 14, 15, 16, 17, 16, 18, 16, 19,
+   16, 19, 16, 19,  0, 19, 16, 20, 16, 19, 21, 19,  0, 22, 23, 24,
+   25, 26, 27, 28, 29, 30, 31,  0, 32,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0, 33,  0,  0,  0,  0,  0,  0, 34,  0,  0, 35,  0,  0,
+   36,  0, 37,  0,  0,  0, 38, 39, 40, 41, 42, 43, 44, 45, 46,  0,
+    0, 47,  0,  0,  0, 48,  0,  0,  0, 49,  0,  0,  0,  0,  0,  0,
+    0, 50,  0, 51,  0, 52, 53,  0, 54,  0,  0,  0,  0,  0,  0, 55,
+   56, 57,  0,  0,  0,  0, 58,  0,  0, 59, 60, 61, 62, 63,  0,  0,
+   64, 65,  0,  0,  0, 66,  0,  0,  0,  0, 67,  0,  0,  0, 68,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 69,  0,  0,
+    0, 70,  0, 71,  0,  0, 72,  0,  0, 73,  0,  0,  0,  0,  0,  0,
+    0,  0, 74,  0,  0,  0,  0,  0, 75, 76,  0, 77, 78,  0,  0, 79,
+   80,  0, 81, 62,  0, 82, 83,  0,  0, 84, 85, 86,  0,  0,  0, 87,
+    0, 88,  0,  0, 51, 89, 51,  0, 90,  0, 91,  0,  0,  0, 80,  0,
+    0,  0, 92, 93,  0, 94, 95, 96, 97,  0,  0,  0,  0,  0, 51,  0,
+    0,  0,  0, 98, 99,  0,  0,  0,  0,  0,  0,100,  0,  0,  0,  0,
+    0,101,102,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,103,  0,  0,
+  104,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,105,106,  0,  0,107,
+    0,  0,  0,  0,  0,  0,108,  0,109,  0,102,  0,  0,  0,  0,  0,
+  110,111,  0,  0,  0,  0,  0,  0,  0,112,  0,  0,  0,  0,  0,  0,
+    0,113,  0,114,  0,  0,  0,  0,  0,  0,  1,  2,  3,  4,  5,  6,
+    7,  0,  8,  0,  0,  0,  0,  9, 10, 11, 12,  0,  0,  0,  0, 13,
+    0,  0, 14, 15,  0, 16,  0, 17, 18,  0,  0, 19,  0, 20, 21,  0,
+    0,  0,  0,  0, 22, 23,  0, 24, 25,  0,  0, 26,  0,  0,  0, 27,
+    0,  0, 28, 29, 30, 31,  0,  0,  0, 32, 33, 34,  0,  0, 33,  0,
+    0, 35, 33,  0,  0,  0, 33, 36,  0,  0,  0,  0,  0, 37, 38,  0,
+    0,  0,  0,  0,  0, 39, 40,  0,  0,  0,  0,  0,  0, 41, 42,  0,
+    0,  0,  0, 43,  0, 44,  0,  0,  0, 45, 46,  0,  0,  0, 47,  0,
+    0,  0,  0,  0,  0, 48, 49,  0,  0,  0,  0, 50,  0,  0,  0, 51,
+    0, 52,  0, 53,  0,  0,  0,  0, 54,  0,  0,  0,  0, 55,  0, 56,
+    0,  0,  0,  0, 57, 58,  0,  0,  0, 59, 60,  0,  0,  0,  0,  0,
+    0, 61, 52,  0, 62, 63,  0,  0, 64,  0,  0,  0, 65, 66,  0,  0,
+    0, 67,  0, 68, 69, 70, 71, 72,  1, 73,  0, 74, 75, 76,  0,  0,
+   77, 78,  0,  0,  0, 79,  0,  0,  1,  1,  0,  0, 80,  0,  0, 81,
+    0,  0,  0,  0, 77, 82,  0, 83,  0,  0,  0,  0,  0, 78, 84,  0,
+   85,  0, 52,  0,  1, 78,  0,  0, 86,  0,  0, 87,  0,  0,  0,  0,
+    0, 88, 57,  0,  0,  0,  0,  0,  0, 89, 90,  0,  0, 84,  0,  0,
+   33,  0,  0, 91,  0,  0,  0,  0, 92,  0,  0,  0,  0, 49,  0,  0,
+   93,  0,  0,  0,  0, 94, 95,  0,  0, 96,  0,  0, 97,  0,  0,  0,
+   98,  0,  0,  0, 99,  0,  0,  0,  0,100,101, 93,  0,  0,102,  0,
+    0,  0, 84,  0,  0,103,  0,  0,  0,104,105,  0,  0,106,107,  0,
+    0,  0,  0,  0,  0,108,  0,  0,109,  0,  0,  0,  0,110, 33,  0,
+  111,112,113, 35,  0,  0,114,  0,  0,  0,115,  0,  0,  0,  0,  0,
+    0,116,  0,  0,117,  0,  0,  0,  0,118, 88,  0,  0,  0,  0,  0,
+   57,  0,  0,  0,  0, 52,119,  0,  0,  0,  0,120,  0,  0,121,  0,
+    0,  0,  0,119,  0,  0,122,  0,  0,  0,  0,  0,  0,123,  0,  0,
+    0,124,  0,  0,  0,125,  0,126,  0,  0,  0,  0,127,128,129,  0,
+  130,  0,131,  0,  0,  0,132,133,134,  0, 77,  0,  0,  0,  0,  0,
+   35,  0,  0,  0,135,  0,  0,  0,136,  0,  0,137,  0,  0,138,  0,
+    0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  2,  3,  4,  5,  6,
+    7,  4,  4,  8,  9, 10,  1, 11, 12, 13, 14, 15, 16, 17, 18,  1,
+    1,  1, 19,  1,  0,  0, 20, 21, 22,  1, 23,  4, 21, 24, 25, 26,
+   27, 28, 29, 30,  0,  0,  1,  1, 31,  0,  0,  0, 32, 33, 34, 35,
+    1, 36, 37,  0,  0,  0,  0, 38,  1, 39, 14, 39, 40, 41, 42,  0,
+    0,  0, 43, 36, 44, 45, 21, 45, 46,  0,  0,  0, 19,  1, 21,  0,
+    0, 47,  0, 38, 48,  1,  1, 49, 49, 50,  0,  0, 51,  0,  0,  0,
+   52,  1,  0,  0, 38, 14,  4,  1,  1,  1, 53, 21, 43, 52, 54, 21,
+   35,  1,  0,  0,  0, 55,  0,  0,  0, 56, 57, 58,  0,  0,  0,  0,
+    0, 59,  0, 60,  0,  0,  0,  0, 61, 62,  0,  0, 63,  0,  0,  0,
+   64,  0,  0,  0, 65,  0,  0,  0, 66,  0,  0,  0, 67,  0,  0,  0,
+   68,  0,  0, 69, 70,  0, 71, 72, 73, 74, 75, 76,  0,  0,  0, 77,
+    0,  0,  0, 78, 79,  0,  0,  0,  0, 47,  0,  0,  0, 49,  0, 80,
+    0,  0,  0, 62,  0,  0, 63,  0,  0, 81,  0,  0, 82,  0,  0,  0,
+   83,  0,  0, 19, 84,  0, 62,  0,  0,  0,  0, 49,  1, 85,  1, 52,
+   15, 86, 36, 10, 21, 87,  0, 55,  0,  0,  0,  0, 19, 10,  1,  0,
+    0,  0,  0,  0, 88,  0,  0, 89,  0,  0, 88,  0,  0,  0,  0, 78,
+    0,  0, 87,  9, 12,  4, 90,  8, 91, 47,  0, 58, 50,  0, 21,  1,
+   21, 92, 93,  1,  1,  1,  1, 94, 95, 96, 97,  1, 98, 58, 81, 99,
+  100,  4, 58,  0,  0,  0,  0,  0,  0, 19, 50,  0,  0,  0,  0,  0,
+    0, 61,  0,  0,101,102,  0,  0,103,  0,  0,  1,  1, 50,  0,  0,
+    0, 38,  0, 63,  0,  0,  0,  0,  0, 62,  0,  0,104, 68, 61,  0,
+    0,  0, 78,  0,  0,  0,105,106, 58, 38, 81,  0,  0,  0,  0,  0,
+    0,107,  1, 14,  4, 12, 84,  0,  0,  0,  0, 38, 87,  0,  0,  0,
+    0,108,  0,  0,109, 61,  0,110,  0,  0,  0,  1,  0,  0,  0,  0,
+   19, 58,  0,  0,  0, 51,  0,111, 14, 52,112, 41,  0,  0, 62,  0,
+    0, 61,  0,  0,113,  0, 87,  0,  0,  0, 61, 62,  0,  0, 62,  0,
+   89,  0,  0,113,  0,  0,  0,  0,114,  0,  0,  0, 78, 55,  0, 38,
+    1, 58,  1, 58,  0,  0, 63, 89,  0,  0,115,  0,  0,  0, 55,  0,
+    0,  0,  0,115,  0,  0,  0,  0, 61,  0,  0,  0,  0, 79,  0, 61,
+    0,  0,  0,  0, 56,  0, 89, 80,  0,  0, 79,  0,  0,  0,  8, 91,
     0,  0,  1, 87,  0,  0,116,  0,  0,  0,  0,  0,  0,117,  0,118,
   119,120,121,  0,104,  4,122, 49, 23,  0,  0,  0, 38, 50, 38, 58,
     0,  0,  1, 87,  1,  1,  1,  1, 39,  1, 48,105, 87,  0,  0,  0,
-    0,  1,  4,122,  0,  0,  0,  1,123,  0,  0,  0,  0,  0,230,230,
-  230,230,230,232,220,220,220,220,232,216,220,220,220,220,220,202,
-  202,220,220,220,220,202,202,220,220,220,  1,  1,  1,  1,  1,220,
-  220,220,220,230,230,230,230,240,230,220,220,220,230,230,230,220,
-  220,  0,230,230,230,220,220,220,220,230,232,220,220,230,233,234,
-  234,233,234,234,233,230,  0,  0,  0,230,  0,220,230,230,230,230,
-  220,230,230,230,222,220,230,230,220,220,230,222,228,230, 10, 11,
-   12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22,  0, 23,  0, 24,
-   25,  0,230,220,  0, 18, 30, 31, 32,  0,  0,  0,  0, 27, 28, 29,
-   30, 31, 32, 33, 34,230,230,220,220,230,220,230,230,220, 35,  0,
-    0,  0,  0,  0,230,230,230,  0,  0,230,230,  0,220,230,230,220,
-    0,  0,  0, 36,  0,  0,230,220,230,230,220,220,230,220,220,230,
-  220,230,220,230,230,  0,  0,220,  0,  0,230,230,  0,230,  0,230,
-  230,230,230,230,  0,  0,  0,220,220,220,230,220,220,220,230,230,
-    0,220, 27, 28, 29,230,  7,  0,  0,  0,  0,  9,  0,  0,  0,230,
-  220,230,230,  0,  0,  0,  0,  0,230,  0,  0, 84, 91,  0,  0,  0,
-    0,  9,  9,  0,  0,  0,  0,  0,  9,  0,103,103,  9,  0,107,107,
-  107,107,118,118,  9,  0,122,122,122,122,220,220,  0,  0,  0,220,
-    0,220,  0,216,  0,  0,  0,129,130,  0,132,  0,  0,  0,  0,  0,
-  130,130,130,130,  0,  0,130,  0,230,230,  9,  0,230,230,  0,  0,
-  220,  0,  0,  0,  0,  7,  0,  9,  9,  0,  9,  9,  0,  0,  0,230,
-    0,  0,  0,228,  0,  0,  0,222,230,220,220,  0,  0,  0,230,  0,
-    0,220,230,220,  0,220,230,230,230,  0,  0,  0,  9,  9,  0,  0,
-    7,  0,230,  0,  1,  1,  1,  0,  0,  0,230,234,214,220,202,230,
-  230,230,230,230,232,228,228,220,218,230,233,220,230,220,230,230,
-    1,  1,  1,  1,  1,230,  0,  1,  1,230,220,230,  1,  1,  0,  0,
-  218,228,232,222,224,224,  0,  8,  8,  0,  0,  0,  0,220,230,  0,
-  230,230,220,  0,  0,230,  0,  0, 26,  0,  0,220,  0,230,230,  1,
-  220,  0,  0,230,220,  0,  0,  0,220,220,  0,  0,230,220,  0,  9,
-    7,  0,  0,  7,  9,  0,  0,  0,  9,  7,  6,  6,  0,  0,  0,  0,
-    1,  0,  0,216,216,  1,  1,  1,  0,  0,  0,226,216,216,216,216,
-  216,  0,220,220,220,  0,230,230,  7,  0, 16, 17, 17, 17, 17, 17,
-   17, 33, 17, 17, 17, 19, 17, 17, 17, 17, 20,101, 17,113,129,169,
-   17, 27, 28, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+    0,  1,  0,  0,  0,123,  4,122,  0,  0,  0,  1,124,  0,  0,  0,
+    0,  0,230,230,230,230,230,232,220,220,220,220,232,216,220,220,
+  220,220,220,202,202,220,220,220,220,202,202,220,220,220,  1,  1,
+    1,  1,  1,220,220,220,220,230,230,230,230,240,230,220,220,220,
+  230,230,230,220,220,  0,230,230,230,220,220,220,220,230,232,220,
+  220,230,233,234,234,233,234,234,233,230,  0,  0,  0,230,  0,220,
+  230,230,230,230,220,230,230,230,222,220,230,230,220,220,230,222,
+  228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22,
+    0, 23,  0, 24, 25,  0,230,220,  0, 18, 30, 31, 32,  0,  0,  0,
+    0, 27, 28, 29, 30, 31, 32, 33, 34,230,230,220,220,230,220,230,
+  230,220, 35,  0,  0,  0,  0,  0,230,230,230,  0,  0,230,230,  0,
+  220,230,230,220,  0,  0,  0, 36,  0,  0,230,220,230,230,220,220,
+  230,220,220,230,220,230,220,230,230,  0,  0,220,  0,  0,230,230,
+    0,230,  0,230,230,230,230,230,  0,  0,  0,220,220,220,230,220,
+  220,220,230,230,  0,220, 27, 28, 29,230,  7,  0,  0,  0,  0,  9,
+    0,  0,  0,230,220,230,230,  0,  0,  0,  0,  0,230,  0,  0, 84,
+   91,  0,  0,  0,  0,  9,  9,  0,  0,  0,  0,  0,  9,  0,103,103,
+    9,  0,107,107,107,107,118,118,  9,  0,122,122,122,122,220,220,
+    0,  0,  0,220,  0,220,  0,216,  0,  0,  0,129,130,  0,132,  0,
+    0,  0,  0,  0,130,130,130,130,  0,  0,130,  0,230,230,  9,  0,
+  230,230,  0,  0,220,  0,  0,  0,  0,  7,  0,  9,  9,  0,  9,  9,
+    0,  0,  0,230,  0,  0,  0,228,  0,  0,  0,222,230,220,220,  0,
+    0,  0,230,  0,  0,220,230,220,  0,220,230,230,230,  0,  0,  0,
+    9,  9,  0,  0,  7,  0,230,  0,  1,  1,  1,  0,  0,  0,230,234,
+  214,220,202,230,230,230,230,230,232,228,228,220,218,230,233,220,
+  230,220,230,230,  1,  1,  1,  1,  1,230,  0,  1,  1,230,220,230,
+    1,  1,  0,  0,218,228,232,222,224,224,  0,  8,  8,  0,  0,  0,
+    0,220,230,  0,230,230,220,  0,  0,230,  0,  0, 26,  0,  0,220,
+    0,230,230,  1,220,  0,  0,230,220,  0,  0,  0,220,220,  0,  0,
+  230,220,  0,  9,  7,  0,  0,  7,  9,  0,  0,  0,  9,  7,  6,  6,
+    0,  0,  0,  0,  1,  0,  0,216,216,  1,  1,  1,  0,  0,  0,226,
+  216,216,216,216,216,  0,220,220,220,  0,232,232,220,230,230,230,
+    7,  0, 16, 17, 17, 33, 17, 49, 17, 17, 84, 97,135,145, 26, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17,177,  0,  1,  2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  4,  3,  3,  3,  3,  3,  5,  3,  3,  3,
+    3,  3,  6,  7,  8,  3,  3,  3,  3,  3,  9, 10, 11, 12, 13,  3,
+    3,  3,  3,  3,  3,  3,  3, 14,  3, 15,  3,  3,  3,  3,  3,  3,
+   16, 17, 18, 19, 20, 21,  3,  3,  3, 22, 23, 24,  3,  3,  3,  3,
+    3,  3, 25,  3,  3,  3,  3,  3,  3,  3,  3, 26,  3,  3, 27, 28,
+    0,  1,  0,  0,  0,  0,  0,  1,  0,  2,  0,  0,  0,  3,  0,  0,
+    0,  3,  0,  0,  0,  0,  0,  4,  0,  5,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0,  0,  0,  7,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  8,  9,  0,  0,  0,  0,  0,
+    0,  9,  0,  9,  0,  0,  0,  0,  0,  0,  0, 10, 11, 12, 13,  0,
+    0, 14, 15, 16,  6,  0, 17, 18, 19, 19, 19, 20, 21, 22, 23, 24,
+   19, 25,  0, 26, 27, 19, 19, 28, 29, 30,  0, 31,  0,  0,  0,  8,
+    0,  0,  0,  0,  0,  0,  0, 19, 28,  0, 32, 33,  9, 34, 35, 19,
+    0,  0, 36, 37, 38, 39, 40, 19,  0, 41, 42, 43, 44, 31,  0,  1,
+   45, 42,  0,  0,  0,  0,  0, 32, 14, 14,  0,  0,  0,  0, 14,  0,
+    0, 46, 47, 47, 47, 47, 48, 49, 47, 47, 47, 47, 50, 51, 52, 53,
+   43, 21,  0,  0,  0,  0,  0,  0,  0, 54,  6, 55,  0, 14, 19,  1,
+    0,  0,  0,  0, 56, 57,  0,  0,  0,  0,  0, 19, 58, 31,  0,  0,
+    0,  0,  0,  0,  0, 59, 14,  0,  0,  0,  0,  1,  0,  2,  0,  0,
+    0,  3,  0,  0,  0, 60, 61,  0,  0,  0,  0,  0,  0,  0,  1,  0,
+    0,  0,  0,  0,  2,  3,  0,  4,  5,  0,  0,  6,  0,  0,  0,  7,
+    0,  0,  0,  1,  1,  0,  0,  8,  9,  0,  8,  9,  0,  0,  0,  0,
+    8,  9, 10, 11, 12,  0,  0,  0, 13,  0,  0,  0,  0, 14, 15, 16,
+   17,  0,  0,  0,  1,  0,  0, 18, 19,  0,  0,  0, 20,  0,  0,  0,
+    1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  0,  8, 21,  9,
+    0,  0, 22,  0,  0,  0,  0,  1,  0, 23, 24, 25,  0,  0, 26,  0,
+    0,  0,  8, 21, 27,  0,  1,  0,  0,  1,  1,  1,  1,  0,  1, 28,
+   29, 30,  0, 31, 32, 20,  1,  1,  0,  0,  0,  8, 21,  9,  1,  4,
+    5,  0,  0,  0, 33,  9,  0,  1,  1,  1,  0,  8, 21, 21, 21, 21,
+   34,  1, 35, 21, 21, 21,  9, 36,  0,  0, 37, 38,  1,  0, 39,  0,
+    0,  0,  1,  0,  1,  0,  0,  0,  0,  8, 21,  9,  1,  0,  0,  0,
+   40,  0,  8, 21, 21, 21, 21, 21, 21, 21, 21,  9,  0,  1,  1,  1,
+    1,  8, 21, 21, 21,  9,  0,  0,  0, 41,  0, 42, 43,  0,  0,  0,
+    1, 44,  0,  0,  0, 45,  8,  9,  1,  0,  0,  0,  8, 21, 21, 21,
+    9,  0,  1,  0,  1,  1,  8, 21, 21,  9,  0,  4,  5,  8,  9,  1,
+    0,  0,  0,  1,  2,  3,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12,
+   13, 14,  3,  3,  3,  3,  3,  3,  3, 15,  3, 16, 17, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17, 17, 17, 17, 17, 17, 17,237,  0,  1,  2,  2,  0,  3,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  4,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  5,  0,  0,  0,  0,  6,  7,  8,  9,  0,
-    0,  0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,  0,  0,  0,  0,
-    0,  0,  0,  0,  0, 20,  0,  0, 21, 22,  0,  0,  0,  0, 23, 24,
-   25, 26,  0, 27,  0, 28, 29, 30, 31, 32,  0,  0,  0,  0,  0,  0,
-    0, 33, 34, 35, 36,  0,  0,  0,  0,  0, 37,  0,  0,  0,  0,  0,
-    0,  0,  0,  0, 38, 39,  0,  0,  0,  0,  1,  2, 40, 41,  0,  1,
-    2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,
-    0,  2,  0,  0,  0,  0,  0,  0,  3,  4,  0,  0,  5,  0,  0,  0,
-    6,  0,  0,  0,  0,  0,  0,  0,  7,  1,  0,  0,  0,  0,  0,  0,
-    8,  9,  0,  0,  0,  0,  0,  0, 10,  0,  0, 10,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0, 10,  0,  0,  0, 10,  0,  0,
-    0,  0,  0,  0, 11, 12,  0, 13,  0, 14, 15, 16,  0,  0,  0,  0,
-    0,  1, 17, 18,  0, 19,  7,  1,  0,  0,  0, 20, 20,  7, 20, 20,
-   20, 20, 20, 20, 20,  8, 21,  0, 22,  0,  7, 23, 24,  0, 20, 20,
-   25,  0,  0,  0, 26, 27,  1,  7, 20, 20, 20, 20, 20,  1, 28, 29,
-   30, 31,  0,  0, 20,  0,  0,  0,  0,  0,  0,  0, 10,  0,  0,  0,
-    0,  0,  0,  0, 20, 20, 20,  1,  0,  0,  8, 21, 32,  4,  0, 10,
-    0, 33,  7, 20, 20, 20,  0,  0,  0,  0,  8, 34, 34, 35, 36, 34,
-   37,  0, 38,  1, 20, 20,  0,  0, 39,  0,  1,  1,  0,  8, 21,  1,
-   20,  0,  0,  0,  1,  0,  0, 40,  1,  1,  0,  0,  8, 21,  0,  1,
-    0,  1,  0,  1,  0,  0,  0,  0, 26, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 21,  7, 20, 41, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21,
-    0, 42, 43, 44,  0, 45,  0,  8, 21,  0,  0,  0,  0,  0,  0,  0,
-    0, 46,  7,  1, 10,  1,  0,  0,  0,  1, 20, 20,  1,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 26, 34,  9,  0,  0, 20, 20,  1, 20,
-   20,  0,  0,  0,  0,  0,  0,  0, 26, 21,  0,  1,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  3, 47, 48,  0,  0,  0,  0,  0,
-    0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  9, 10, 11, 11, 11, 11, 11, 12, 12, 12,
-   12, 13, 14, 15, 16, 17, 18, 19, 20, 12, 21, 12, 12, 12, 12, 22,
-   23, 23, 23, 24, 12, 12, 12, 25, 26, 27, 12, 28, 29, 30, 31, 32,
-   33, 34,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 35,
-   12, 36,  7,  7, 37, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 38,  0,  0,  1,  2,  2,  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, 32, 33, 33, 33, 34, 35, 35, 35, 35,
-   35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
-    2,  2, 51, 51, 52, 53, 54, 55, 56, 56, 56, 56, 56, 56, 56, 56,
-   56, 56, 56, 56, 57, 57, 56, 56, 56, 56, 56, 56, 58, 59, 60, 61,
-   56, 62, 62, 63, 64, 65, 66, 67, 68, 69, 70, 56, 62, 62, 62, 62,
-   62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
-   62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 71,
-   62, 62, 62, 62, 72, 72, 72, 72, 72, 72, 72, 72, 72, 73, 74, 74,
-   75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 32, 32, 32, 32,
-   32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-   32, 32, 32, 32, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
-   87, 87, 87, 87, 87, 87, 62, 62, 62, 62, 88, 89, 89, 89, 90, 89,
-   91, 92, 93, 94, 95, 95, 96, 97, 87, 98, 99,100,101,102,103,104,
-  105,105,105,  2,106,107,108,109,110,111,112,113,114,115,116, 87,
-   89,117,118,119,120,121,122,123,124,125,126, 87,127,128, 87,129,
-  130,131,132, 87,133,134,135,136,137,138, 87, 87,139,140,141,142,
-   87,143, 87,144,145,145,145,145,145,145,145,145,145,145,145, 87,
-   87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
-   87, 87, 87,146,147,147,147,147,147,147,147,147,147, 87, 87, 87,
-   87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,148,148,148,148,
-  148, 87, 87, 87,149,149,149,149,150,151,152,152, 87, 87, 87, 87,
-  153,153,154,155,156,156,156,156,156,156,156,156,156,156,156,156,
-  156,156,156,156,156,156,156,156,156,156,157,157,157,157,156, 87,
-   87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
-   87, 87, 87,158,159,160,161,162,162,162, 87, 87, 87, 87, 87, 87,
-   87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,163,164, 87, 87,
-   87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
-   87, 87,165, 56, 56, 56,166,167, 51, 56, 56, 87, 56, 56, 56, 56,
-   56, 56, 56, 56,168,168,168,168,168,168, 87, 87, 87, 87, 87, 87,
-   87, 87,  2, 87,169, 87,170, 87, 87,171, 87, 87, 87, 87, 87, 87,
-   87, 87, 87, 33,172,172,173, 87, 87, 87, 87, 87, 56, 56, 56, 87,
-   89, 89, 87, 87, 56, 56, 56, 56,174, 87, 56, 56, 56, 56, 56, 56,
-   56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 87, 87, 87, 87,
-   87, 87, 87, 87, 62, 62, 62, 62, 62, 62, 62, 62, 87, 87, 87, 87,
-   87, 87, 87, 87, 62, 62, 62, 62, 62, 87, 87, 87, 87, 87, 87, 87,
-   87, 87, 87, 87, 62, 62, 62, 62, 62, 62, 62, 87, 87, 87, 87, 87,
-   87, 87, 87, 87, 56, 87,175,175,  0,  1,  2,  2,  0,  1,  2,  2,
-    2,  3,  4,  5,  0,  0,  0,  0,  1,  2,  1,  2,  0,  0,  3,  3,
-    4,  5,  4,  5,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  6,
-    0,  0,  7,  0,  8,  8,  8,  8,  8,  8,  8,  9, 10, 11, 11, 11,
-   11, 11, 12, 11, 13, 13, 13, 13, 13, 13, 13, 13, 14, 13, 13, 13,
-   13, 13, 13, 13, 13, 13, 13, 15, 16, 16, 16, 16, 16, 17, 18, 18,
-   18, 18, 18, 18, 19, 20, 21, 21, 22, 23, 21, 24, 21, 21, 21, 21,
-   21, 25, 21, 21, 26, 26, 26, 26, 26, 21, 21, 21, 27, 27, 27, 27,
-   28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 26, 21, 21, 21, 21, 21,
-   21, 21, 31, 21, 32, 32, 32, 32, 32, 33, 34, 32, 35, 35, 35, 35,
-   35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37,
-   37, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39,
-   39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41,
-   41, 41, 41, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43,
-   43, 43, 43, 43, 44, 44, 44, 45, 44, 44, 44, 44, 46, 46, 46, 46,
-   46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
-   47, 48, 47, 47, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 50, 50,
-   50, 50, 50, 51, 52, 52, 52, 52, 52, 52, 52, 52, 53, 53, 53, 53,
-   53, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55,
-   55, 55, 55, 55, 56, 56, 57, 57, 57, 57, 58, 57, 59, 59, 60, 61,
-   62, 62, 63, 63, 64, 64, 64, 64, 64, 64, 64, 64, 65, 66, 66, 66,
-   66, 66, 66, 66, 66, 66, 66, 55, 55, 55, 55, 55, 67, 67, 67, 67,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 18,  0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,
+   12, 13, 14, 15, 16, 17, 17, 17, 18, 17, 19, 20, 21, 22, 23, 23,
+   23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 23, 23, 23, 23, 23,
+   23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+   23, 23, 23, 23, 25, 25, 26, 27, 28, 29, 30, 30, 30, 30, 30, 30,
+   30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+   31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+   32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+   48, 49, 50, 51, 52, 52, 53, 31, 31, 31, 31, 54, 55, 55, 56, 31,
+   31, 31, 31, 31, 31, 31, 57, 58, 31, 31, 31, 31, 31, 31, 31, 31,
+   31, 31, 31, 31, 31, 31, 31, 31, 59, 60, 31, 61, 62, 62, 62, 62,
+   62, 62, 62, 62, 62, 62, 62, 62, 62, 63, 64, 31, 31, 31, 31, 31,
+   31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 65, 66, 67, 31, 31,
+   31, 31, 68, 31, 31, 31, 31, 31, 31, 31, 31, 69, 70, 71, 17, 17,
+   72, 73, 31, 74, 75, 76, 77, 78, 79, 31, 80, 81, 17, 82, 17, 17,
+   17, 17, 31, 31, 23, 23, 23, 23, 23, 23, 23, 83, 31, 31, 31, 31,
+   23, 83, 31, 31, 23, 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+   31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+   31, 31, 31, 31, 84,  0,  0,  1,  0,  1,  2,  3,  0,  1,  2,  3,
+    4,  5,  6,  7,  0,  1,  2,  3,  4,  4,  4,  4,  4,  4,  5,  6,
+    7,  8,  9, 10, 11, 11, 12, 11, 13, 14, 15, 16, 17, 18, 19, 20,
+   21, 22, 23, 24, 25, 26, 19, 27, 28, 29, 30, 30, 31, 31, 32, 32,
+   33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 40, 41, 41,
+   42, 42, 42, 43, 44, 44, 45, 46, 47, 47, 47, 47, 48, 48, 48, 48,
+   48, 48, 49, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 53,
+   54, 55, 56, 56, 57, 58, 59, 51, 60, 61, 62, 63, 64, 65, 66,  7,
+   67, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,  7,  4,  4,  4,  4,
+   77, 77, 77, 77, 78, 79, 80, 81, 82, 83, 84,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 85, 85, 85, 85,  0,  0,  0,  0, 86, 87, 88, 88,
+   89, 90, 48, 91,  0,  0, 92, 92, 92, 92, 92, 93, 94, 95, 96, 97,
+   98, 47, 99,100,101,102,  0,103,104,105,  0,  0, 92, 92, 92, 92,
+   92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,  0,106,106,106,106,
+  106,106,106,106,106,106,106,107,108,108,108,108,108, 11,109,110,
+  111,  4,112,  4,113,114,115,116,117,118,119,120,121,122,123,124,
+  125,126, 50,127, 47, 47, 47, 47, 47, 47, 47, 47,128,128,128,128,
+  128,128,128,128,128,128,128,128, 92, 92, 92, 92, 92, 92, 92, 92,
+  129,130, 19, 19, 19, 19, 19, 19,131, 19, 19, 19,132,133, 19,134,
+  135,136,137,101,138,138,138,138,  0, 77,139,140,128,128,141,142,
+  143,144,145,146,147,148,149,150,151,152,153,153,154,154,154,154,
+  154,154,  4,  4,155,156,157,158,159,160,161,162,163,164,165,166,
+  167,168,169,169,170,170,171,171,172,172,128,128, 19, 19,173,174,
+  175,176,177,178,179,179,180,181,182,183,184,185,186,186,187,188,
+  189,190,128,128,191,191,192,192,128,128,193,193,194,195,196,196,
+  197,197,128,128,198,198,199,199,200,200,201,201,202,203,204,205,
+   28, 28,128,128,206,207,208,208,209,210,211,211,128,128,212,212,
+  213,213,214, 34,215,215,215,215,215,215,215,215,215,215,215,215,
+  215,215,128,128,128,128,128,128,128,128,216,216,217,217,217,217,
+  217,217,217,217,217,217,128,128,128,128,128,128,218,218,218,218,
+  218,218,218,218,218,218,128,128,128,128,128,128,110,110,110,110,
+  110,110,110,110,110,219,220,221,222,222,222,222,223,223,223,223,
+  224,224,224,225,226,226,226,226,226,226,226,226,226,226,226,226,
+  227,227,227,227,227,227,227,227,226,226,128,128,128,128,128,128,
+  128,128,104,104,228,229,229,229,230,231,232,232,232,232,232,232,
+  128,128,128,128,233,233,234,  0,128,128,128,128,128,128,128,128,
+    7,235,  0,  0,  0,  0,  0,  0,  0,236,237,  0, 77, 77,  0,  0,
+    0,  0,128,128,238,238,238,238,238,238,238,238,238,238,238,238,
+  128,128,128,128,128,128,128,128,  4,  4,128,128,239, 11, 11, 11,
+  240,240,128,128,128,128,241,242,128,128,128,128,128,128,243,243,
+  128,128,128,128,128,128,128,128,128,128, 48, 48,244,244,244,244,
+  245,245,128,128,  0,  0,  0,  0,  0,  0,128,128, 19, 19, 19, 19,
+  128,128,128,128,246,  0,128,128,  0,  0,  0,  0, 92, 92,128,128,
+  128,128,128,128,  0,  0,128,128,  7,  7,  7,  7,  0,  0,  0,  0,
+    1,  2,  1,  2,  0,  0,  3,  3,  4,  5,  4,  5,  4,  4,  4,  4,
+    4,  4,  4,  6,  0,  0,  7,  0,  8,  8,  8,  8,  8,  8,  8,  9,
+   10, 11, 11, 11, 11, 11, 12, 11, 13, 13, 13, 13, 14, 13, 13, 13,
+   13, 13, 13, 15, 16, 16, 16, 16, 16, 17, 18, 18, 18, 18, 18, 18,
+   19, 20, 21, 21, 22, 23, 21, 24, 21, 21, 21, 21, 21, 25, 21, 21,
+   26, 26, 26, 26, 26, 21, 21, 21, 27, 27, 27, 27, 28, 28, 28, 28,
+   29, 29, 29, 29, 30, 30, 26, 21, 21, 21, 31, 21, 32, 32, 32, 32,
+   32, 33, 34, 32, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
+   38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41,
+   42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 45, 44, 44, 44, 44,
+   46, 46, 46, 46, 47, 47, 47, 47, 47, 48, 47, 47, 49, 49, 49, 49,
+   49, 49, 50, 50, 50, 50, 50, 51, 52, 52, 52, 52, 53, 53, 53, 53,
+   53, 53, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 56, 56, 57, 57,
+   57, 57, 58, 57, 59, 59, 60, 61, 62, 62, 63, 63, 64, 64, 64, 64,
+   65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 55, 67, 67, 67, 67,
    67, 68, 68, 68, 69, 69, 69, 69, 69, 69, 64, 64, 70, 70, 71, 71,
-   71, 71, 71, 71, 71, 71, 71,  8,  8,  8,  8,  8, 72, 72, 72, 72,
-   72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75,
-   75, 76, 76, 76, 13, 50, 50, 50, 73, 77, 78, 79,  4,  4, 80,  4,
-    4, 81, 82, 83,  4,  4,  4, 84,  8,  8,  8,  8, 11, 11, 11, 11,
+   71, 71, 71, 71, 71, 71, 71,  8, 72, 72, 72, 72, 73, 73, 73, 73,
+   74, 74, 74, 74, 75, 75, 75, 75, 75, 76, 76, 76, 13, 50, 50, 50,
+   73, 77, 78, 79,  4,  4, 80,  4,  4, 81, 82, 83,  4,  4,  4, 84,
    11, 11, 11, 11, 85,  0,  0,  0,  0,  0,  0, 86,  0,  4,  0,  0,
     0,  8,  8,  8,  0,  0, 87, 88, 89,  0,  4,  4,  6,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 90, 90, 90, 90,
    90, 90, 90, 90, 91, 91, 91, 91, 91, 91,  4,  4, 92, 92, 92, 92,
-   92, 92, 92, 92, 50, 50, 50, 93, 93, 93, 93, 93, 53, 53, 53, 53,
-   53, 53, 13, 13, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+   50, 50, 50, 93, 93, 93, 93, 93, 53, 53, 13, 13, 94, 94, 94, 94,
    94, 94, 94,  0, 95,  0, 96, 97, 98, 99, 99, 99, 99,100,101,102,
-  102,102,102,103,104,104,104,105, 52, 52, 52, 52, 52,  0,104,104,
-    0,  0,  0,102, 52, 52,  0,  0,  0,  0, 52,106,  0,  0,  0,  0,
-    0,102,102,107,102,102,102,102,102,108,  0,  0, 94, 94, 94, 94,
-    0,  0,  0,  0,109,109,109,109,109,109,109,109,109,109,109,109,
-  109,110,110,110,111,111,111,111,111,111,111,111,111,111,111,111,
-   13, 13, 13, 13, 13, 13,112,112,112,112,112,112,  0,  0,113,  4,
-    4,  4,  4,  4,114,  4,  4,  4,  4,  4,  4,  4,115,115,115,  0,
-  116,116,116,116,117,117,117,117,117,117, 32, 32,118,118,119,120,
-  120,120, 52, 52,121,121,121,121,122,121, 49, 49,123,123,123,123,
-  123,123, 49, 49,124,124,124,124,124,124,125,125, 53, 53, 53,  4,
-    4,126,127, 54, 54, 54, 54, 54,125,125,125,125,128,128,128,128,
-  128,128,128,128,  4,129, 18, 18, 18, 21, 21, 21, 21, 21, 21, 21,
-   21, 21, 21, 21, 21, 21, 21,130, 21, 21, 21, 21,  8,  0,131,  0,
-    0,  0,  0, 21, 21, 21, 21, 21, 21, 21, 21,132,  0,  0,  1,  2,
-    1,  2,133,101,102,134, 52, 52, 52, 52,  0,  0,135,135,135,135,
-  135,135,135,135,  0,  0,  0,  0, 11, 11, 11, 11, 11,  0, 11, 11,
-   11,  0,  0,136,137,137,138,138,138,138,139,  0,140,140,140,141,
-  141,142,142,142,143,143,144,144,144,144,144,144,145,145,145,145,
-  145,146,146,146,147,147,147,148,148,148,148,148,149,149,149,150,
-  150,150,150,151,151,151,151,151,151,151,151,151,152,152,152,152,
-  152,152,152,152,153,153,153,153,154,154,155,155,156,156,156,156,
-  156,156,157,157,158,158,159,159,159,159,159,159,160,160,161,161,
-  161,161,161,161,162,162,162,162,162,162,163,163,164,164,164,164,
-  165,165,165,165,166,166,166,166,167,167,168,168,169,169,169,169,
-  169,169,169,169,170,170,170,170,170,170,170,170,171,171,171,171,
-  171,171,171,171,172,172,172,172,172,172,172,172,173,173,173,173,
-  173,173,173,173,174,174,174,175,175,175,175,176,176,176,176,177,
-  177,177,178,178,179,179,179,179,179,179,179,179,180,180,180,180,
-  180,181,181,181,182,182,182,182,182,183,183,183,184,184,184,184,
-  184,184,185, 43,186,186,186,186,186,186,186,186,187,187,187,188,
-  188,188,188,188,189,189,189,190,189,189,189,189,191,191,191,191,
-  191,191,191,191,192,192,192,192,192,192,192,192,193,193,193,193,
-  193,193,193,193,194,194,194,194,194,194, 66, 66,195,195,195,195,
-  195,195,195,195,196,196,196,196,196,196,196,196,197,197,197,197,
-  197,197,197,197,198,198,198,198,198,198,198,198,199,199,199,199,
-  199,199,199,199,200,200,200,200,200,200,200,200,201,201,201,201,
-  201,202,202,202,202,202,202, 55,203,203,203,203,204,204,204,204,
-  204,204,204,205,205,205,205,205,205,205,205,205,206,206,206,206,
-  206,206,207,207,207,207,207,207,207,207,207,207,208,208,208,208,
-  208,208,208,208,110,110,110,110, 39, 39, 39, 39,209,209,209,209,
-  209,209,209,209,210,210,210,210,210,210,210,210,211,211,211,211,
-  211,211,211,211,212,212,212,212,212,212,212,212,112,112,112,112,
-  112,112,112,112,112,112,112,112,213,213,213,214,214,214,214,214,
-  214,215,215,215,216,216,216,216,216,216,216,216,217,217,217,217,
-  217,217,217,217,218,218,218,218,218,218,218,218,218,218,218,218,
-  218,218,219, 94,220,220,220,220,220,220,220,220,221,221,221,221,
-  221,221,221,221,102,102,102,102,102,102,102,102,222, 99, 99, 99,
-   99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,102,102,
-  102, 99,223,224,224,224,224,224,224,224,224,224,225,225,225,225,
-  225,225,225,225,225,225,  0,  0,  0,  0,  0,  0,  8,  8,  8,  8,
-    8,  0,  0,  0,  0,  0,  0,  0,  0,  0,226,227,228,  0,229,  0,
-    0,  0,  0,  0,230,230,230,230,230,230,230,230, 91, 91, 91, 91,
-   91, 91, 91, 91,231,231,231,231,231,231,231,231,232,232,232,232,
-  233,233,233,233,234,234,234,234,234,234,234,234,235,235,235,235,
-  235,235,235,235,236,  0,  0,  0,  0,  0,  0,  0,  8,  8,  8,  8,
-    8,  8,  8,  8,  0,  0,  0,  0,  1,  2,  2,  2,  2,  2,  3,  0,
-    0,  0,  4,  0,  2,  2,  2,  2,  2,  3,  2,  2,  2,  2,  5,  0,
-    2,  5,  6,  0,  7,  7,  7,  7,  8,  9,  8, 10,  8, 11,  8,  8,
-    8,  8,  8,  8, 12, 13, 13, 13, 14, 14, 14, 14, 14, 15, 14, 14,
-   16, 17, 17, 17, 17, 17, 17, 17, 18, 19, 19, 19, 19, 19, 19, 19,
-   20, 21, 20, 22, 20, 20, 23, 23, 20, 20, 20, 20, 22, 20, 24,  7,
-    7, 25, 20, 20, 26, 20, 20, 20, 20, 20, 20, 21, 27, 27, 27, 27,
-   28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
-   32, 20, 20, 20, 33, 33, 33, 33, 34, 35, 33, 33, 33, 36, 33, 33,
-   37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40,
-   41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44,
-   45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 47, 48, 48, 48, 48,
-   49, 49, 49, 49, 49, 50, 51, 49, 52, 52, 52, 52, 53, 53, 53, 53,
-   53, 53, 54, 53, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57,
-   58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 61, 62,
-   63, 63, 63, 63, 64, 64, 64, 64, 64, 65,  0,  0, 66, 66, 66, 66,
-   67, 67, 67, 67, 68, 68, 68, 68, 69, 70, 71, 71, 71, 71, 71, 71,
-   72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75,
-   76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78, 78, 79, 79, 79, 79,
-   80, 80, 80, 80, 81, 81, 81, 81, 82,  7,  7,  7, 83,  7, 84, 85,
-    0, 84, 86,  0,  2, 87, 88,  2,  2,  2,  2, 89, 90, 87, 91,  2,
-    2,  2, 92,  2,  2,  2,  2, 93,  0,  0,  0, 86,  1,  0,  0, 94,
-    0, 95, 96,  0,  4,  0,  0,  0,  0,  0,  0,  4, 97, 97, 97, 97,
-   98, 98, 98, 98, 13, 13, 13, 13, 99, 99, 99, 99,100,100,100,100,
-    0,101,  0,  0,102,100,103,104,  0,  0,100,  0,105,106,106,106,
-  106,106,106,106,106,106,107,105,108,109,109,109,109,109,109,109,
-  109,109,110,108,111,111,111,111,112, 55, 55, 55, 55, 55, 55,113,
-  109,109,109,110,109,109,  0,  0,114,114,114,114,115,115,115,115,
-  116,116,116,116,117,117,117,117, 96,  2,  2,  2,  2,  2, 94,  2,
-  118,118,118,118,119,119,119,119,120,120,120,120,121,121,121,121,
-  121,121,121,122,123,123,123,123,124,124,124,124,124,124,124,125,
-  126,126,126,126,127,127,127,127,128,128,128,128,  2,  2,  3,  2,
-    2,129,130,  0,131,131,131,131,132, 17, 17, 18, 20, 20, 20,133,
-    7,  7,  7,134, 20, 20, 20, 23,  0,135,109,109,109,109,109,136,
-  137,137,137,137,  0,  0,  0,138,139,139,139,139,140,140,140,140,
-   84,  0,  0,  0,141,141,141,141,142,142,142,142,143,143,143,143,
-  144,144,144,144,145,145,145,145,146,146,146,146,147,147,147,147,
-  148,148,148,148,149,149,149,149,150,150,150,150,151,151,151,151,
-  152,152,152,152,153,153,153,153,154,154,154,154,155,155,155,155,
-  156,156,156,156,157,157,157,157,158,158,158,158,159,159,159,159,
-  160,160,160,160,161,161,161,161,162,162,162,162,163,163,163,163,
-  164,164,164,164,165,165,165,165,166,166,166,166,167,167,167,167,
-  168,168,168,168,169,169,169,169,170,170,170,170,171,171,171,171,
-  172,172,172,172,173,173,173,173,174,174,174,174,175,175,175,175,
-  176,176,176,176,177,177,177,177,178,178,178,178,179,179,179,179,
-  180,180,180,180,181,181,181,181,182,182,182,182,183,183,183,183,
-  184,184,184,184,185,185,185,185,186, 45, 45, 45,187,187,187,187,
-  188,188,188,188,189,189,189,189,190,190,190,190,190,190,191,190,
-  192,192,192,192,193,193,193,193,194,194,194,194,195,195,195,195,
-  196,196,196,196,197,197,197,197,198,198,198,198,199,199,199,199,
-  200,200,200,200,201,201,201,201,202,202,202,202,203,203,203,203,
-  204,204,204,204,205,205,205,205,206,206,206,206,207,207,207,207,
-  208,208,208,208,209,209,209,209,210,210,210,210,211,211,211,211,
-  212,212,212,212,213,213,213,213,214,214,214,214,215,215,215,215,
-  216,216,216,216,217,217,217,217,218,218,218,218,219,219,219,219,
-  220,221,221,221,222,222,222,222,221,221,221,221,223,106,106,106,
-  106,109,109,109,224,224,224,224,225,225,225,225,  0,226, 86,  0,
-    0,  0,226,  7, 82,138,  7,  0,  0,  0,227, 86,228,228,228,228,
-  229,229,229,229,230,230,230,230,231,231,231,231,232,232,232,232,
-  233,233,233,233,234,  0,  0,  0,  0,  0,  0,  0,  0, 19, 19, 19,
-   19, 19, 19, 19, 19, 19, 19,  0,  0,  0, 19,  0, 19,  0,  0,  0,
-    0,  0, 26, 26,  1,  1,  1,  1,  9,  9,  9,  9,  0,  9,  9,  9,
-    9,  9,  0,  9,  9,  0,  9,  0,  9,  9, 55, 55, 55, 55, 55, 55,
-    6,  6,  6,  6,  6,  1,  1,  6,  6,  4,  4,  4,  4,  4,  4,  4,
-    4, 14, 14, 14, 14, 14, 14, 14,  3,  3,  3,  3,  3,  0,  3,  3,
-    0,  3,  3,  3,  3,  3,  3,  0,  3,  3,  3,  1,  1,  1,  3,  3,
-    1,  3,  3,  3, 37, 37, 37, 37, 38, 38, 38, 38, 64, 64, 64, 64,
-   90, 90, 90, 90, 95, 95, 95, 95,  3,  3,  0,  3,  7,  7,  7,  7,
-    7,  1,  1,  1,  1,  7,  7,  7,  0,  0,  7,  7,  5,  5,  5,  5,
-   11, 11, 11, 11, 10, 10, 10, 10, 21, 21, 21, 21, 22, 22, 22, 22,
-   23, 23, 23, 23, 16, 16, 16, 16, 20, 20, 20, 20, 36, 36, 36, 36,
-   24, 24, 24, 24, 24, 24, 24,  0, 18, 18, 18, 18, 25, 25, 25, 25,
-   25,  0,  0,  0,  0, 25, 25, 25, 33, 33, 33, 33,  8,  8,  8,  8,
-    8,  8,  8,  0, 12, 12, 12, 12, 30, 30, 30, 30, 29, 29, 29, 29,
-   28, 28, 28, 28, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 35,  0,
-    0,  0, 35, 35, 45, 45, 45, 45, 44, 44, 44, 44, 44,  0,  0,  0,
-   43, 43, 43, 43, 46, 46, 46, 46, 31, 31, 31, 31, 32, 32,  0,  0,
-   32,  0, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 52, 52, 52, 52,
-   58, 58, 58, 58, 54, 54, 54, 54, 91, 91, 91, 91, 62, 62, 62, 62,
-   76, 76, 76, 76, 93, 93, 93, 93, 70, 70, 70, 70, 73, 73, 73, 73,
-    1,  1,  1,  0,  1,  0,  1,  1,  1,  0,  0,  0,  0,  1,  0,  0,
-    1,  1,  0,  0, 19, 19,  9,  9,  9,  9,  9,  6, 19,  9,  9,  9,
-    9,  9, 19, 19,  9,  9,  9, 19,  6, 19, 19, 19, 19, 19, 19,  9,
-    0,  0,  0, 19,  0,  0,  9,  0,  0,  0, 19, 19, 27, 27, 27, 27,
-   56, 56, 56, 56, 61, 61, 61, 61, 13, 13, 13, 13,  0, 13,  0, 13,
-    0, 13, 13, 13, 13, 13,  1,  1,  1,  1, 12, 12,  0, 15, 15, 15,
-   15, 15, 15, 15, 15,  1,  1,  0,  0, 17, 17, 17, 17, 17, 17, 17,
-   17, 17, 17,  0, 26, 26, 26, 26, 26, 12, 12, 12, 12, 12, 12,  0,
-   39, 39, 39, 39, 86, 86, 86, 86, 77, 77, 77, 77, 79, 79, 79, 79,
-   60, 60, 60, 60, 65, 65, 65, 65, 75, 75, 75, 75, 69, 69, 69, 69,
-   69, 69,  0, 69, 74, 74, 74, 74, 84, 84, 84, 84, 84, 84, 84,  0,
-   68, 68, 68, 68, 92, 92, 92, 92, 87, 87, 87, 87, 19,  9, 19, 19,
-   19, 19,  0,  0,  2,  2,  2,  2, 19, 19, 19,  4,  3,  3,  0,  0,
-    1,  1,  6,  6,  0,  0, 17, 17, 17, 17,  0,  0, 49, 49, 49, 49,
-    0,  1,  1,  1, 71, 71, 71, 71, 67, 67, 67, 67, 42, 42, 42, 42,
-   41, 41, 41, 41,118,118,118,118, 53, 53, 53, 53, 59, 59, 59, 59,
-   40, 40, 40, 40, 51, 51, 51, 51, 50, 50, 50, 50,135,135,135,135,
-  106,106,106,106,104,104,104,104,161,161,161,161,110,110,110,110,
-   47, 47, 47, 47, 81, 81, 81, 81,120,120,120,120,116,116,116,116,
-  128,128,128,128, 66, 66, 66, 66, 72, 72, 72, 72, 98, 98, 98, 98,
-   97, 97, 97, 97, 57, 57, 57, 57, 88, 88, 88, 88,117,117,117,117,
-  112,112,112,112, 78, 78, 78, 78, 83, 83, 83, 83, 82, 82, 82, 82,
-  122,122,122,122, 89, 89, 89, 89,130,130,130,130,144,144,144,144,
-  156,156,156,156,147,147,147,147,148,148,148,148,158,158,158,158,
-  153,153,153,153,149,149,149,149, 94, 94, 94, 94, 85, 85, 85, 85,
-  101,101,101,101, 96, 96, 96, 96,111,111,111,111,100,100,100,100,
-  100, 36, 36, 36,108,108,108,108,129,129,129,129,109,109,109,109,
-  107,107,107,107,107,107,107,  1,137,137,137,137,124,124,124,124,
-  123,123,123,123,114,114,114,114,102,102,102,102,126,126,126,126,
-  142,142,142,142,125,125,125,125,154,154,154,154,150,150,150,150,
-  141,141,141,141,140,140,140,140,121,121,121,121,133,133,133,133,
-  134,134,134,134,138,138,138,138,143,143,143,143,145,145,145,145,
-   63, 63, 63, 63,157,157,157,157, 80, 80, 80, 80,127,127,127,127,
-  115,115,115,115,159,159,159,159,103,103,103,103,119,119,119,119,
-  146,146,146,146, 99, 99, 99, 99,136,139, 13, 13,155,155,155,155,
-  136,136,136,136, 17, 15, 15, 15,139,139,139,139,105,105,105,105,
-    0,  0,  0,  1,  0,  0,  1,  1,131,131,131,131,151,151,151,151,
-  160,160,160,160,152,152,152,152,113,113,113,113,132,132,132,132,
-   15,  0,  0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  9,  9,
-    9, 10,  9, 11, 12, 13,  9,  9,  9, 14,  9,  9, 15,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  102,102,102,103,104,104,104,105, 52,  0,104,104,  0,  0,  0,102,
+   52, 52,  0,  0,  0,  0, 52,106,  0,102,102,107,102,102,102,102,
+  102,108,  0,  0,109,109,109,109,109,110,110,110,111,111,111,111,
+   13, 13,112,112,112,112,112,112,  0,  0,113,  4,114,  4,  4,  4,
+  115,115,115,  0,116,116,116,116,117,117,117,117,117,117, 32, 32,
+  118,118,119,120,120,120, 52, 52,121,121,121,121,122,121, 49, 49,
+  123,123,123,123,123,123, 49, 49,124,124,124,124,124,124,125,125,
+   53, 53, 53,  4,  4,126,127, 54,125,125,125,125,128,128,128,128,
+    4,129, 18, 18, 18, 21, 21, 21, 21, 21, 21,130,  8,  0,131,  0,
+    0,  0,  0, 21, 21, 21, 21,132,  0,  0,  1,  2,  1,  2,133,101,
+  102,134, 52, 52,135,135,135,135, 11,  0, 11, 11, 11,  0,  0,136,
+  137,137,138,138,138,138,139,  0,140,140,140,141,141,142,142,142,
+  143,143,144,144,144,144,144,144,145,145,145,145,145,146,146,146,
+  147,147,147,148,148,148,148,148,149,149,149,150,150,150,150,151,
+  151,151,151,151,152,152,152,152,153,153,153,153,154,154,155,155,
+  156,156,156,156,156,156,157,157,158,158,159,159,159,159,159,159,
+  160,160,161,161,161,161,161,161,162,162,162,162,162,162,163,163,
+  164,164,164,164,165,165,165,165,166,166,166,166,167,167,168,168,
+  169,169,169,169,170,170,170,170,171,171,171,171,172,172,172,172,
+  173,173,173,173,173,173,173,174,175,175,175,176,176,176,176,177,
+  177,177,177,178,178,178,179,179,180,180,180,180,181,181,181,181,
+  181,182,182,182,183,183,183,183,183,184,184,184,185,185,185,185,
+  185,185,186, 43,187,187,187,187,188,188,188,189,189,189,189,189,
+  190,190,190,191,190,190,190,190,192,192,192,192,193,193,193,193,
+  194,194,194,194,195,195,195,195,195,195, 66, 66,196,196,196,196,
+  197,197,197,197,198,198,198,198,199,199,199,199,200,200,200,200,
+  201,201,201,201,202,202,202,202,202,203,203,203,203,203,203, 55,
+  204,204,204,204,205,205,205,205,205,205,205,206,206,206,206,206,
+  207,207,207,207,207,207,208,208,208,208,208,208,209,209,209,209,
+  210,210,210,210,110,110,110,110,211,211,211,211,212,212,212,212,
+  213,213,213,213,214,214,214,214,215,215,215,216,216,216,216,216,
+  216,217,217,217,218,218,218,218,219,219,219,219,220,220,220,220,
+  220,220,221, 94,222,222,222,222,223,223,223,223,224, 99, 99, 99,
+   99, 99, 99, 99, 99, 99,102,225, 99,226,102,227,227,227,227,227,
+  228,228,228,228,228,228,  0,  0,  8,  0,  0,  0,  0,  0,229,230,
+  231,  0,232,  0,233,233,233,233, 91, 91, 91, 13,234,234,234,234,
+  235,235,235,235,236,236,236,236,237,237,237,237,238,238,238,238,
+  239,239,239,239,240,  0,  0,  0,  0,  0,  0,  0,  1,  2,  2,  2,
+    2,  2,  3,  0,  0,  0,  4,  0,  2,  2,  2,  2,  2,  3,  2,  2,
+    2,  2,  5,  0,  2,  5,  6,  0,  7,  7,  7,  7,  8,  9,  8, 10,
+    8, 11,  8,  8,  8,  8,  8,  8, 12, 13, 13, 13, 14, 14, 14, 14,
+   14, 15, 14, 14, 16, 17, 17, 17, 17, 17, 17, 17, 18, 19, 19, 19,
+   19, 19, 19, 19, 20, 21, 20, 22, 20, 20, 23, 23, 20, 20, 20, 20,
+   22, 20, 24,  7,  7, 25, 20, 20, 26, 20, 20, 20, 20, 20, 20, 21,
+   27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30,
+   31, 31, 31, 31, 32, 20, 20, 20, 33, 33, 33, 33, 34, 35, 33, 33,
+   33, 36, 33, 33, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
+   40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
+   44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 47,
+   48, 48, 48, 48, 49, 49, 49, 49, 49, 50, 51, 49, 52, 52, 52, 52,
+   53, 53, 53, 53, 53, 53, 54, 53, 55, 55, 55, 55, 56, 56, 56, 56,
+   57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60,
+   60, 60, 61, 62, 63, 63, 63, 63, 64, 64, 64, 64, 64, 65,  0,  0,
+   66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 70, 71, 71,
+   71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74,
+   75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78, 78,
+   79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82,  7,  7,  7,
+   83,  7, 84, 85,  0, 84, 86,  0,  2, 87, 88,  2,  2,  2,  2, 89,
+   90, 87, 91,  2,  2,  2, 92,  2,  2,  2,  2, 93,  0,  0,  0, 86,
+    1,  0,  0, 94,  0, 95, 96,  0,  4,  0,  0,  0,  0,  0,  0,  4,
+   97, 97, 97, 97, 98, 98, 98, 98, 13, 13, 13, 13, 99, 99, 99, 99,
+  100,100,100,100,  0,101,  0,  0,102,100,103,104,  0,  0,100,  0,
+  105,106,106,106,106,106,106,106,106,106,107,105,108,109,109,109,
+  109,109,109,109,109,109,110,108,111,111,111,111,112, 55, 55, 55,
+   55, 55, 55,113,109,109,109,110,109,109,  0,  0,114,114,114,114,
+  115,115,115,115,116,116,116,116,117,117,117,117, 96,  2,  2,  2,
+    2,  2, 94,  2,118,118,118,118,119,119,119,119,120,120,120,120,
+  121,121,121,121,121,121,121,122,123,123,123,123,124,124,124,124,
+  124,124,124,125,126,126,126,126,127,127,127,127,128,128,128,128,
+    2,  2,  3,  2,  2,129,130,  0,131,131,131,131,132, 17, 17, 18,
+   20, 20, 20,133,  7,  7,  7,134, 20, 20, 20, 23,  0,135,109,109,
+  109,109,109,136,137,137,137,137,  0,  0,  0,138,139,139,139,139,
+  140,140,140,140, 84,  0,  0,  0,141,141,141,141,142,142,142,142,
+  143,143,143,143,144,144,144,144,145,145,145,145,146,146,146,146,
+  147,147,147,147,148,148,148,148,149,149,149,149,150,150,150,150,
+  151,151,151,151,152,152,152,152,153,153,153,153,154,154,154,154,
+  155,155,155,155,156,156,156,156,157,157,157,157,158,158,158,158,
+  159,159,159,159,160,160,160,160,161,161,161,161,162,162,162,162,
+  163,163,163,163,164,164,164,164,165,165,165,165,166,166,166,166,
+  167,167,167,167,168,168,168,168,169,169,169,169,170,170,170,170,
+  171,171,171,171,172,172,172,172,173,173,173,173,174,174,174,174,
+  174,174,174,175,176,176,176,176,177,177,177,177,178,178,178,178,
+  179,179,179,179,180,180,180,180,181,181,181,181,182,182,182,182,
+  183,183,183,183,184,184,184,184,185,185,185,185,186,186,186,186,
+  187, 45, 45, 45,188,188,188,188,189,189,189,189,190,190,190,190,
+  191,191,191,191,191,191,192,191,193,193,193,193,194,194,194,194,
+  195,195,195,195,196,196,196,196,197,197,197,197,198,198,198,198,
+  199,199,199,199,200,200,200,200,201,201,201,201,202,202,202,202,
+  203,203,203,203,204,204,204,204,205,205,205,205,206,206,206,206,
+  207,207,207,207,208,208,208,208,209,209,209,209,210,210,210,210,
+  211,211,211,211,212,212,212,212,213,213,213,213,214,214,214,214,
+  215,215,215,215,216,216,216,216,217,217,217,217,218,218,218,218,
+  219,219,219,219,220,220,220,220,221,221,221,221,222,223,223,223,
+  224,224,224,224,223,223,223,223,225,106,106,106,226,106,106,106,
+  106,227,109,109,228,228,228,228,229,229,229,229,  0,230, 86,  0,
+    0,  0,230,  7, 82,138,  7,  0,  0,  0,231, 86,232,232,232,232,
+  233,233,233,233,234,234,234,234,235,235,235,235,236,236,236,236,
+  237,237,237,237,238,238,238,238,239,  0,  0,  0,  0,  0,  0,  0,
+    0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,  0,  0,  0, 19,  0,
+   19,  0,  0,  0,  0,  0, 26, 26,  1,  1,  1,  1,  9,  9,  9,  9,
+    0,  9,  9,  9,  9,  9,  0,  9,  9,  0,  9,  0,  9,  9, 55, 55,
+   55, 55, 55, 55,  6,  6,  6,  6,  6,  1,  1,  6,  6,  4,  4,  4,
+    4,  4,  4,  4,  4, 14, 14, 14, 14, 14, 14, 14,  3,  3,  3,  3,
+    3,  0,  3,  3,  0,  3,  3,  3,  3,  3,  3,  0,  3,  3,  3,  1,
+    1,  1,  3,  3,  1,  3,  3,  3, 37, 37, 37, 37, 38, 38, 38, 38,
+   64, 64, 64, 64, 90, 90, 90, 90, 95, 95, 95, 95,  3,  3,  0,  3,
+    7,  7,  7,  7,  7,  1,  1,  1,  1,  7,  7,  7,  0,  0,  7,  7,
+    5,  5,  5,  5, 11, 11, 11, 11, 10, 10, 10, 10, 21, 21, 21, 21,
+   22, 22, 22, 22, 23, 23, 23, 23, 16, 16, 16, 16, 20, 20, 20, 20,
+   36, 36, 36, 36, 24, 24, 24, 24, 24, 24, 24,  0, 18, 18, 18, 18,
+   25, 25, 25, 25, 25,  0,  0,  0,  0, 25, 25, 25, 33, 33, 33, 33,
+    8,  8,  8,  8,  8,  8,  8,  0, 12, 12, 12, 12, 30, 30, 30, 30,
+   29, 29, 29, 29, 28, 28, 28, 28, 34, 34, 34, 34, 35, 35, 35, 35,
+   35, 35, 35,  0,  0,  0, 35, 35, 45, 45, 45, 45, 44, 44, 44, 44,
+   44,  0,  0,  0, 43, 43, 43, 43, 46, 46, 46, 46, 31, 31, 31, 31,
+   32, 32,  0,  0, 32,  0, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48,
+   52, 52, 52, 52, 58, 58, 58, 58, 54, 54, 54, 54, 91, 91, 91, 91,
+   62, 62, 62, 62, 76, 76, 76, 76, 93, 93, 93, 93, 70, 70, 70, 70,
+   73, 73, 73, 73,  1,  1,  1,  0,  1,  0,  1,  1,  1,  0,  0,  0,
+    0,  1,  0,  0,  1,  1,  0,  0, 19, 19,  9,  9,  9,  9,  9,  6,
+   19,  9,  9,  9,  9,  9, 19, 19,  9,  9,  9, 19,  6, 19, 19, 19,
+   19, 19, 19,  9,  0,  0,  0, 19,  0,  0,  9,  0,  0,  0, 19, 19,
+   27, 27, 27, 27, 56, 56, 56, 56, 61, 61, 61, 61, 13, 13, 13, 13,
+    0, 13,  0, 13,  0, 13, 13, 13, 13, 13,  1,  1,  1,  1, 12, 12,
+    0, 15, 15, 15, 15, 15, 15, 15, 15,  1,  1,  0,  0, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17,  0, 26, 26, 26, 26, 26, 12, 12, 12,
+   12, 12, 12,  0, 39, 39, 39, 39, 86, 86, 86, 86, 77, 77, 77, 77,
+   79, 79, 79, 79, 60, 60, 60, 60, 65, 65, 65, 65, 75, 75, 75, 75,
+   69, 69, 69, 69, 69, 69,  0, 69, 74, 74, 74, 74, 84, 84, 84, 84,
+   84, 84, 84,  0, 68, 68, 68, 68, 92, 92, 92, 92, 87, 87, 87, 87,
+   19,  9, 19, 19, 19, 19,  0,  0,  2,  2,  2,  2, 19, 19, 19,  4,
+    3,  3,  0,  0,  1,  1,  6,  6,  0,  0, 17, 17, 17, 17,  0,  0,
+   49, 49, 49, 49,  0,  1,  1,  1, 71, 71, 71, 71, 67, 67, 67, 67,
+   42, 42, 42, 42, 41, 41, 41, 41,118,118,118,118, 53, 53, 53, 53,
+   59, 59, 59, 59, 40, 40, 40, 40, 51, 51, 51, 51, 50, 50, 50, 50,
+  135,135,135,135,106,106,106,106,104,104,104,104,161,161,161,161,
+  110,110,110,110, 47, 47, 47, 47, 81, 81, 81, 81,120,120,120,120,
+  116,116,116,116,128,128,128,128, 66, 66, 66, 66, 72, 72, 72, 72,
+   98, 98, 98, 98, 97, 97, 97, 97, 57, 57, 57, 57, 88, 88, 88, 88,
+  117,117,117,117,112,112,112,112, 78, 78, 78, 78, 83, 83, 83, 83,
+   82, 82, 82, 82,122,122,122,122, 89, 89, 89, 89,130,130,130,130,
+  144,144,144,144,156,156,156,156,156,  3,  3,  3,147,147,147,147,
+  148,148,148,148,158,158,158,158,153,153,153,153,149,149,149,149,
+   94, 94, 94, 94, 85, 85, 85, 85,101,101,101,101, 96, 96, 96, 96,
+  111,111,111,111,100,100,100,100,100, 36, 36, 36,108,108,108,108,
+  129,129,129,129,109,109,109,109,107,107,107,107,107,107,107,  1,
+  137,137,137,137,124,124,124,124,123,123,123,123,114,114,114,114,
+  102,102,102,102,126,126,126,126,142,142,142,142,125,125,125,125,
+  154,154,154,154,150,150,150,150,141,141,141,141,140,140,140,140,
+  121,121,121,121,133,133,133,133,134,134,134,134,138,138,138,138,
+  143,143,143,143,145,145,145,145,163,163,163,163, 63, 63, 63, 63,
+  157,157,157,157, 80, 80, 80, 80,127,127,127,127,115,115,115,115,
+  159,159,159,159,103,103,103,103,119,119,119,119,146,146,146,146,
+   99, 99, 99, 99,136,139, 13, 13,155,155,155,155,136,136,136,136,
+   17, 15, 15, 15, 17, 17, 15, 15, 15, 17, 17, 17,139,139,139,139,
+  105,105,105,105,  0,  0,  0,  1,  0,  0,  1,  1,131,131,131,131,
+  151,151,151,151,160,160,160,160,152,152,152,152,164,164,164,164,
+  113,113,113,113,132,132,132,132, 15,  0,  0,  0,  0,  1,  2,  3,
+    4,  5,  6,  7,  8,  9,  9,  9,  9, 10,  9, 11, 12, 13,  9,  9,
+    9, 14,  9,  9, 15,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-   16, 17,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 18, 19, 20,  9,
-   21,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9, 16, 17,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9, 18, 19, 20,  9, 21,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 22,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9, 22,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
@@ -6479,60 +5223,60 @@ _hb_ucd_u8[13602] =
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-   23, 24,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  2,
-    3,  4,  5,  6,  7,  8,  9, 10, 11, 12,  0,  0, 13, 14, 15, 16,
-   17, 18, 19, 20, 21, 22,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 23,  0,  0, 24, 25, 26, 27, 28, 29, 30,
-    0,  0, 31, 32,  0, 33,  0, 34,  0, 35,  0,  0,  0,  0, 36, 37,
-   38, 39,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0, 40,  0,  0,  0,  0,  0,  0,  0,  0,  0, 41, 42,
+    9,  9,  9,  9,  9,  9,  9,  9, 23, 24,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10,
+   11, 12,  0,  0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 23,  0,
+    0, 24, 25, 26, 27, 28, 29, 30,  0,  0, 31, 32,  0, 33,  0, 34,
+    0, 35,  0,  0,  0,  0, 36, 37, 38, 39,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 40,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 41, 42,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 43, 44,  0, 45,
+    0,  0,  0,  0,  0,  0, 46, 47,  0,  0,  0,  0,  0, 48,  0, 49,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 50, 51,
+    0,  0,  0, 52,  0,  0, 53,  0,  0,  0,  0,  0,  0,  0, 54,  0,
+    0,  0,  0,  0,  0,  0, 55,  0,  0,  0,  0,  0,  0,  0, 56,  0,
+    0,  0,  0,  0,  0,  0,  0, 57,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 58, 59,
+   60, 61, 62, 63, 64, 65,  0,  0,  0,  0,  0,  0, 66,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0, 43, 44,  0, 45,  0,  0,  0,  0,  0,  0, 46, 47,
-    0,  0,  0,  0,  0, 48,  0, 49,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 50, 51,  0,  0,  0, 52,  0,  0, 53,  0,
-    0,  0,  0,  0,  0,  0, 54,  0,  0,  0,  0,  0,  0,  0, 55,  0,
-    0,  0,  0,  0,  0,  0, 56,  0,  0,  0,  0,  0,  0,  0,  0, 57,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 58, 59, 60, 61, 62, 63, 64, 65,  0,  0,
-    0,  0,  0,  0, 66,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 67, 68,  0, 69, 70,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 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,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,104,  0,  0,  0,
+    0,  0,  0,105,106,  0,107,  0,  0,  0,108,  0,109,  0,110,  0,
+  111,112,113,  0,114,  0,  0,  0,115,  0,  0,  0,116,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,117,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,118,119,
+  120,121,  0,122,123,124,125,126,  0,127,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0, 67, 68,  0, 69, 70,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0, 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,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,104,  0,  0,  0,  0,  0,  0,105,106,  0,107,  0,
-    0,  0,108,  0,109,  0,110,  0,111,112,113,  0,114,  0,  0,  0,
-  115,  0,  0,  0,116,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,117,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,128,129,130,131,132,133,
+  134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,
+  150,151,152,153,154,155,156,157,  0,  0,  0,158,159,160,161,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,118,119,120,121,  0,122,123,124,125,126,
-    0,127,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,162,163,  0,  0,  0,  0,  0,  0,  0,164,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,128,129,130,131,132,133,134,135,136,137,138,139,140,141,
-  142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,
-    0,  0,  0,158,159,160,161,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,162,163,  0,  0,  0,
-    0,  0,  0,  0,164,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,165,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,165,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,166,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,167,  0,  0,
+    0,  0,  0,  0,  0,166,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,167,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,168,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,168,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,169,
+  170,  0,  0,  0,  0,171,172,  0,  0,  0,173,174,175,176,177,178,
+  179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,
+  195,196,197,198,199,200,201,202,203,204,205,206,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,169,170,  0,  0,  0,  0,171,172,  0,
-    0,  0,173,174,175,176,177,178,179,180,181,182,183,184,185,186,
-  187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,
-  203,204,205,206,  0,  0,  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,
+    0,  0,  0,  0,  0,  0,  1,  2,  3,  4,
 };
 static const uint16_t
-_hb_ucd_u16[4888] =
+_hb_ucd_u16[4920] =
 {
      0,   0,   1,   2,   3,   4,   5,   6,   0,   0,   7,   8,   9,  10,  11,  12,
     13,  13,  13,  14,  15,  13,  13,  16,  17,  18,  19,  20,  21,  22,  13,  23,
@@ -6599,39 +5343,41 @@ _hb_ucd_u16[4888] =
    359,  47,  47, 360, 145,  66,  47, 361,  47, 362, 145, 145, 363,  47, 364,  66,
     47,  47,  47, 365,  47, 366,  47, 366,  47, 365, 144, 145, 145, 145, 145, 145,
      9,   9,   9,   9,  11,  11,  11, 367,  47,  47, 368, 160, 160, 160, 160, 160,
-   145, 145, 145, 145, 145, 145, 145, 145,  47,  47, 369,  47,  47,  47,  47,  47,
+   145, 145, 145, 145, 145, 145, 145, 145,  47,  47, 369,  47,  47,  47,  47, 143,
     47, 362, 370,  47,  60, 371,  66,  47, 372,  66,  66,  47, 373, 145,  47,  47,
    374,  47,  47, 360, 375, 376, 377, 378, 180,  47,  47, 379, 380,  47,  47, 160,
     97,  47, 381, 382, 383,  47,  47, 384, 180,  47,  47, 385, 386, 387, 388, 145,
-    47,  47, 389, 390,  32,  32,  32,  32,  47,  47, 365,  47,  47, 391, 172, 160,
+    47,  47, 389, 390, 359,  32,  32,  32,  47,  47, 365,  47,  47, 391, 172, 160,
     92,  47,  47, 113, 392, 393, 394,  32,  47,  47,  47, 395, 396, 397,  47,  47,
     47,  47,  47, 398, 399, 160, 160, 160,  47,  47, 400, 401, 402, 403,  32,  32,
     47,  47,  47, 404, 405, 160,  66,  66,  47,  47, 406, 407, 160, 160, 160, 160,
     47, 143, 408, 409,  47,  47,  47,  47,  47,  47, 389, 410,  66,  66,  66,  66,
      9,   9,   9,   9,  11,  11, 128, 411,  47,  47,  47, 412, 413, 160, 160, 160,
     47,  47,  47,  47,  47, 414, 415, 416, 417,  47,  47, 418, 419, 420,  47,  47,
-   421, 422,  66,  47,  47,  47,  47,  47,  47,  47, 400, 423, 424, 128, 145, 425,
-    47, 156, 426, 427,  32,  32,  32,  32,  47,  47,  47, 359, 428, 160,  47,  47,
-   429, 430, 160, 160, 160, 160, 160, 160,  47,  47,  47,  47,  47,  47,  47, 431,
-    47,  47,  47,  47, 145, 432, 433, 434, 219, 219, 219, 219, 219, 219, 219,  66,
-    47,  47,  47,  47,  47,  47,  47, 424,  47,  47,  47, 208, 208, 208, 208, 208,
-    47,  47,  47,  47,  47,  47, 305,  47,  47,  47,  47,  47, 160,  47,  47, 435,
-    47,  47,  47, 436, 437, 438, 439,  47,   9,   9,   9,   9,   9,   9,  11,  11,
-   145, 440,  66,  66,  66,  66,  66,  66,  47,  47,  47,  47, 391, 441, 416, 416,
-   442, 443,  27,  27,  27,  27, 444, 416,  47, 445, 208, 208, 208, 208, 208, 208,
-    32,  32,  32,  32,  32, 146, 146, 146, 146, 146, 146, 146, 146, 146, 446, 447,
-   448, 146, 449, 146, 146, 146, 146, 146, 146, 146, 146, 146, 450, 146, 146, 146,
-     9, 451,  11, 452, 453,  11, 196,   9, 454, 455,   9, 456,  11,   9, 451,  11,
-   452, 453,  11, 196,   9, 454, 455,   9, 456,  11,   9, 451,  11, 452, 453,  11,
-   196,   9, 454, 455,   9, 456,  11,   9, 451,  11, 196,   9, 457, 458, 459, 460,
-    11, 461,   9, 462, 463, 464, 465,  11, 466,   9, 467,  11, 468, 160, 160, 160,
-    32,  32,  32, 469,  32,  32, 470, 471, 472, 473,  32,  32,  32,  32,  32,  32,
-   474,  11,  11,  11,  11,  11,  11,  11,  32,  32,  32,  32,  32,  32,  32,  32,
-    47,  47,  47, 475, 476, 146, 146, 146,  47,  47, 477,  32,  47,  47, 478, 479,
-    47,  47,  47,  47, 355,  32,  32,  32,   9,   9, 454,  11, 480, 305,  66,  66,
-   145, 145, 481, 482, 145, 145, 145, 145, 145, 145, 483, 145, 145, 145, 145, 145,
-    47,  47,  47,  47,  47,  47,  47, 226, 484, 146, 146, 146, 146, 146, 146, 146,
-   146, 146, 146, 146, 146, 146, 146, 485, 146, 146, 146, 146, 146, 146, 146, 160,
+   421, 422,  66,  47,  47,  47,  47,  47,  66,  66,  66,  66,  66,  66,  66,  66,
+    47,  47, 400, 423, 424, 128, 145, 425,  47, 156, 426, 427,  32,  32,  32,  32,
+    47,  47,  47, 359, 428, 160,  47,  47, 429, 430, 160, 160, 160, 160, 160, 160,
+    47,  47,  47,  47,  47,  47,  47, 431, 432,  47,  47, 433, 434, 160, 160, 160,
+    47,  47,  47,  47, 145, 435, 436, 437, 219, 219, 219, 219, 219, 219, 219,  66,
+    47,  47,  47,  47,  47,  47,  47, 424,  47,  47,  47, 208, 438,  32,  32,  32,
+    47,  47,  47,  47,  47,  47, 305,  47,  47,  47,  47,  47, 160,  47,  47, 439,
+    47,  47,  47, 440, 441, 442, 443,  47,   9,   9,   9,   9,   9,   9,  11,  11,
+   145, 444,  66,  66,  66,  66,  66,  66,  47,  47,  47,  47, 391, 445, 416, 416,
+   446, 447,  27,  27,  27,  27, 448, 416,  47, 449, 208, 208, 208, 208, 208, 208,
+    32,  32,  32,  32,  32, 146, 146, 146, 146, 146, 146, 146, 146, 146, 450, 451,
+   452, 146, 453, 146, 146, 146, 146, 146, 146, 146, 146, 146, 454, 146, 146, 146,
+     9, 455,  11, 456, 457,  11, 196,   9, 458, 459,   9, 460,  11,   9, 455,  11,
+   456, 457,  11, 196,   9, 458, 459,   9, 460,  11,   9, 455,  11, 456, 457,  11,
+   196,   9, 458, 459,   9, 460,  11,   9, 455,  11, 196,   9, 461, 462, 463, 464,
+    11, 465,   9, 466, 467, 468, 469,  11, 470,   9, 471,  11, 472, 160, 160, 160,
+    32,  32,  32, 473,  32,  32, 474, 475, 476, 477,  32,  32,  32,  32,  32,  32,
+   478,  11,  11,  11,  11,  11,  11,  11,  32,  32,  32,  27,  27,  27,  27,  27,
+    32,  32,  32,  32,  32,  32,  32,  32,  47,  47,  47, 479, 480, 146, 146, 146,
+    47,  47, 481,  32,  47,  47, 482, 483,  47,  47,  47,  47,  47,  47, 484, 160,
+    47,  47,  47,  47, 355,  32,  32,  32,   9,   9, 458,  11, 485, 305,  66,  66,
+   145, 145, 486, 487, 145, 145, 145, 145, 145, 145, 488, 145, 145, 145, 145, 145,
+    47,  47,  47,  47,  47,  47,  47, 226, 489, 146, 146, 146, 146, 146, 146, 146,
+   146, 146, 146, 146, 146, 146, 146, 490, 146, 146, 146, 146, 146, 146, 146, 160,
    208, 208, 208, 208, 208, 208, 208, 208,   0,   0,   0,   0,   0,   0,   0,   0,
      0,   0,   0,   0,   0,   0,   0,   0, 939, 940, 941, 942, 946, 948,   0, 962,
    969, 970, 971, 976,1001,1002,1003,1008,   0,1033,1040,1041,1042,1043,1047,   0,
@@ -6842,32 +5588,25 @@ _hb_ucd_u16[4888] =
    817, 818, 819, 820, 821, 935,   0,   0,
 };
 static const int16_t
-_hb_ucd_i16[196] =
+_hb_ucd_i16[92] =
 {
-      0,    0,    0,    0,    1,   -1,    0,    0,    2,    0,   -2,    0,    0,    0,    0,    2,
-      0,   -2,    0,    0,    0,    0,    0,   16,    0,    0,    0,  -16,    0,    0,    1,   -1,
-      0,    0,    0,    1,   -1,    0,    0,    0,    0,    1,   -1,    0,    3,    3,    3,   -3,
-     -3,   -3,    0,    0,    0, 2016,    0,    0,    0,    0,    0, 2527, 1923, 1914, 1918,    0,
-   2250,    0,    0,    0,    0,    0,    0,  138,    0,    7,    0,    0,   -7,    0,    0,    0,
-      1,   -1,    1,   -1,   -1,    1,   -1,    0, 1824,    0,    0,    0,    0,    0, 2104,    0,
-   2108, 2106,    0, 2106, 1316,    0,    0,    0,    0,    1,   -1,    1,   -1, -138,    0,    0,
-      1,   -1,    8,    8,    8,    0,    7,    7,    0,    0,   -8,   -8,   -8,   -7,   -7,    0,
-      1,   -1,    0,    2,-1316,    1,   -1,    0,   -1,    1,   -1,    1,   -1,    3,    1,   -1,
-     -3,    1,   -1,    1,   -1,    0,    0,-1914,-1918,    0,    0,-1923,-1824,    0,    0,    0,
-      0,-2016,    0,    0,    1,   -1,    0,    1,    0,    0,-2104,    0,    0,    0,    0,-2106,
-  -2108,-2106,    0,    0,    1,   -1,-2250,    0,    0,    0,-2527,    0,    0,   -2,    0,    1,
-     -1,    0,    1,   -1,
+      0,    0,    1,   -1,    2,    0,   -2,    0,    0,    2,    0,   -2,    0,   16,    0,  -16,
+      0,    1,   -1,    0,    3,    3,    3,   -3,   -3,   -3,    0, 2016,    0, 2527, 1923, 1914,
+   1918,    0, 2250,    0,    0,  138,    0,    7,   -7,    0,   -1,    1, 1824,    0, 2104,    0,
+   2108, 2106,    0, 2106, 1316,    0,   -1, -138,    8,    8,    8,    0,    7,    7,   -8,   -8,
+     -8,   -7,-1316,    1,   -1,    3,   -3,    1,    0,-1914,-1918,    0,    0,-1923,-1824,    0,
+      0,-2016,-2104,    0,    0,-2106,-2108,-2106,-2250,    0,-2527,    0,
 };
 
 static inline uint_fast8_t
 _hb_ucd_gc (unsigned u)
 {
-  return u<1114112u?_hb_ucd_u8[5056+(((_hb_ucd_u8[1168+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
+  return u<1114112u?_hb_ucd_u8[5096+(((_hb_ucd_u8[1168+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
 }
 static inline uint_fast8_t
 _hb_ucd_ccc (unsigned u)
 {
-  return u<125259u?_hb_ucd_u8[6970+(((_hb_ucd_u8[6426+(((_hb_ucd_u8[5982+(((_hb_ucd_u8[5646+(((_hb_ucd_u8[5400+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
+  return u<125259u?_hb_ucd_u8[7054+(((_hb_ucd_u8[6498+(((_hb_ucd_u8[6038+(((_hb_ucd_u8[5686+(((_hb_ucd_u8[5440+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
 }
 static inline unsigned
 _hb_ucd_b4 (const uint8_t* a, unsigned i)
@@ -6877,17 +5616,17 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i)
 static inline int_fast16_t
 _hb_ucd_bmg (unsigned u)
 {
-  return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[7714+(((_hb_ucd_u8[7594+(((_hb_ucd_b4(7466+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
+  return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[7946+(((_hb_ucd_u8[7714+(((_hb_ucd_u8[7618+(((_hb_ucd_b4(7554+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0;
 }
 static inline uint_fast8_t
 _hb_ucd_sc (unsigned u)
 {
-  return u<918016u?_hb_ucd_u8[11480+(((_hb_ucd_u8[10532+(((_hb_ucd_u8[9124+(((_hb_ucd_u8[8500+(((_hb_ucd_u8[8050+(u>>2>>2>>3>>4)])<<4)+((u>>2>>2>>3)&15u))])<<3)+((u>>2>>2)&7u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2;
+  return u<918016u?_hb_ucd_u8[11244+(((_hb_ucd_u8[10280+(((_hb_ucd_u8[9292+(((_hb_ucd_u8[8612+(((_hb_ucd_u8[8308+(((_hb_ucd_u8[8194+(u>>2>>2>>2>>3>>4)])<<4)+((u>>2>>2>>2>>3)&15u))])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2;
 }
 static inline uint_fast16_t
 _hb_ucd_dm (unsigned u)
 {
-  return u<195102u?_hb_ucd_u16[1576+(((_hb_ucd_u8[12802+(((_hb_ucd_u8[12420+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+  return u<195102u?_hb_ucd_u16[1608+(((_hb_ucd_u8[12586+(((_hb_ucd_u8[12204+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
 }
 
 #endif
index baea224..4c8b1ee 100644 (file)
@@ -129,12 +129,16 @@ hb_ucd_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
                hb_codepoint_t a, hb_codepoint_t b, hb_codepoint_t *ab,
                void *user_data HB_UNUSED)
 {
+  // Hangul is handled algorithmically.
   if (_hb_ucd_compose_hangul (a, b, ab)) return true;
 
   hb_codepoint_t u = 0;
 
   if ((a & 0xFFFFF800u) == 0x0000u && (b & 0xFFFFFF80) == 0x0300u)
   {
+    /* If "a" is small enough and "b" is in the U+0300 range,
+     * the composition data is encoded in a 32bit array sorted
+     * by "a,b" pair. */
     uint32_t k = HB_CODEPOINT_ENCODE3_11_7_14 (a, b, 0);
     const uint32_t *v = hb_bsearch (k,
                                    _hb_ucd_dm2_u32_map,
@@ -146,6 +150,8 @@ hb_ucd_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
   }
   else
   {
+    /* Otherwise it is stored in a 64bit array sorted by
+     * "a,b" pair. */
     uint64_t k = HB_CODEPOINT_ENCODE3 (a, b, 0);
     const uint64_t *v = hb_bsearch (k,
                                    _hb_ucd_dm2_u64_map,
@@ -170,15 +176,22 @@ hb_ucd_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
 
   unsigned i = _hb_ucd_dm (ab);
 
+  /* If no data, there's no decomposition. */
   if (likely (!i)) return false;
   i--;
 
+  /* Check if it's a single-character decomposition. */
   if (i < ARRAY_LENGTH (_hb_ucd_dm1_p0_map) + ARRAY_LENGTH (_hb_ucd_dm1_p2_map))
   {
+    /* Single-character decompositions currently are only in plane 0 or plane 2. */
     if (i < ARRAY_LENGTH (_hb_ucd_dm1_p0_map))
+    {
+      /* Plane 0. */
       *a = _hb_ucd_dm1_p0_map[i];
+    }
     else
     {
+      /* Plane 2. */
       i -= ARRAY_LENGTH (_hb_ucd_dm1_p0_map);
       *a = 0x20000 | _hb_ucd_dm1_p2_map[i];
     }
@@ -187,8 +200,10 @@ hb_ucd_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
   }
   i -= ARRAY_LENGTH (_hb_ucd_dm1_p0_map) + ARRAY_LENGTH (_hb_ucd_dm1_p2_map);
 
+  /* Otherwise they are encoded either in a 32bit array or a 64bit array. */
   if (i < ARRAY_LENGTH (_hb_ucd_dm2_u32_map))
   {
+    /* 32bit array. */
     uint32_t v = _hb_ucd_dm2_u32_map[i];
     *a = HB_CODEPOINT_DECODE3_11_7_14_1 (v);
     *b = HB_CODEPOINT_DECODE3_11_7_14_2 (v);
@@ -196,6 +211,7 @@ hb_ucd_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
   }
   i -= ARRAY_LENGTH (_hb_ucd_dm2_u32_map);
 
+  /* 64bit array. */
   uint64_t v = _hb_ucd_dm2_u64_map[i];
   *a = HB_CODEPOINT_DECODE3_1 (v);
   *b = HB_CODEPOINT_DECODE3_2 (v);
index c216379..e607e8c 100644 (file)
@@ -6,16 +6,16 @@
  *
  * on file with this header:
  *
- * # emoji-data-14.0.0.txt
- * # Date: 2021-08-26, 17:22:22 GMT
- * # © 2021 Unicode®, Inc.
+ * # emoji-data.txt
+ * # Date: 2023-02-01, 02:22:54 GMT
+ * # © 2023 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
+ * # For terms of use, see https://www.unicode.org/terms_of_use.html
  * #
  * # Emoji Data for UTS #51
- * # Used with Emoji Version 14.0 and subsequent minor revisions (if any)
+ * # Used with Emoji Version 15.1 and subsequent minor revisions (if any)
  * #
- * # For documentation and usage, see http://www.unicode.org/reports/tr51
+ * # For documentation and usage, see https://www.unicode.org/reports/tr51
  */
 
 #ifndef HB_UNICODE_EMOJI_TABLE_HH
 #include "hb-unicode.hh"
 
 static const uint8_t
-_hb_emoji_u8[544] =
+_hb_emoji_u8[464] =
 {
    16, 17, 17, 17, 50, 20, 21, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,118,152,
-    0,  0,  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,
-    2,  3,  0,  0,  4,  0,  5,  0,  0,  0,  0,  0,  6,  0,  7,  8,
-    0,  0,  0,  9,  0,  0, 10, 11, 12, 13, 14, 13, 15, 16, 17,  0,
-    0,  0,  0,  0, 18,  0,  0,  0,  0,  0,  0,  0, 19, 20,  0,  0,
-   21,  0,  0,  0,  0,  0,  0,  0,  0,  0, 22,  0,  0,  0,  0,  0,
-   13, 13, 13, 13, 23, 24, 25, 26, 27, 28, 13, 13, 13, 13, 13, 29,
-   13, 13, 13, 13, 30, 31, 13, 13, 13, 32, 13, 13,  0, 33,  0, 34,
-   35, 36, 37, 13, 38, 39, 13, 13, 13, 13, 13, 13,  0,  0,  0,  0,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 30,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 66,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 16,  0,  2,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  4,  0,  0,  2,  0,  0,240,  3,  0,  6,  0,  0,
-    0,  0,  0, 12,  0,  1,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,
-    0,128,  0,  0,  0,254, 15,  7,  4,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0, 12, 64,  0,  1,  0,  0,  0,  0,  0,  0,120,
-  191,255,247,255,255,255,255,255,255,255,255,255,255,255,255,255,
-   63,  0,255,255,255,255,255,255, 63,255, 87, 32,  2,  1, 24,  0,
-  144, 80,184,  0,248,  0,  0,  0,  0,  0,224,  0,  2,  0,  1,128,
-    0,  0,  0,  0,  0,  0, 48,  0,224,  0,  0, 24,  0,  0,  0,  0,
-    0,  0, 33,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1, 32,
-    0,  0,128,  2,  0,  0,  0,  0,  0,224,  0,  0,  0,128,  0,  0,
-    0,  0,  0,  0,  0,240,  3,192,  0, 64,254,  7,  0,224,255,255,
-  255,255,255,255, 63,  0,  0,  0,254,255,  0,  4,  0,128,252,247,
-    0,254,255,255,255,255,255,255,255,255,255,255,255,255,255,  7,
-  255,255,255,255,255,255,255, 63,192,255,255,255,255,255,255,255,
-  255,255,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,240,255,
-    0,  0,224,255,255,255,255,255,  0,240,  0,  0,  0,  0,  0,  0,
-    0,255,  0,252,  0,  0,  0,  0,  0,255,  0,  0,  0,192,255,255,
-    0,240,255,255,255,255,255,247,191,255,255,255,255,255,255,255,
+    0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    2,  0,  3,  4,  0,  0,  5,  6,  0,  7,  0,  8,  9, 10, 11, 12,
+    0,  0, 13,  0,  0,  0, 14,  0, 15,  0,  0,  0,  0, 16,  0,  0,
+   17, 17, 18, 19, 20, 17, 17, 21, 17, 17, 22, 17, 23, 17, 24, 25,
+   26, 27, 28, 17, 17, 17,  0,  0, 17, 17, 17, 17, 17, 17, 17, 29,
+    0,  0,  0,  0,  0,  1,  0,  0,  0,  2,  3,  0,  0,  4,  0,  0,
+    5,  6,  0,  0,  7,  8,  0,  0,  8,  0,  9, 10,  0,  0, 11,  0,
+    0, 12, 13, 14, 15, 16, 16, 16, 17, 16, 16, 16, 18, 19, 20, 21,
+   22, 23,  0,  0,  0, 24,  0,  0, 25,  0, 26,  0,  0, 27,  0,  0,
+   28,  0,  0,  0, 16, 16, 16, 16, 29,  9,  0, 30, 31, 32, 16, 33,
+   34, 35, 36, 16, 16, 16, 16, 37, 16, 38, 39, 16, 16, 16, 40,  0,
+    0,  0,  0, 41,  0,  0, 42, 16, 43,  0, 44,  0, 45, 46, 16, 16,
+   47, 48, 49, 16, 16, 16, 16, 38,  0,  0,  0,  0,  0, 66,  0,  0,
+    0,  0,  0, 16,  0,  2,  0,  0,  4,  0,  0,  2,  0,  0,240,  3,
+    0,  6,  0,  0,  0,  0,  0, 12,  0,  1,  0,  0,  0,128,  0,  0,
+    0,254, 15,  7,  4,  0,  0,  0,  0, 12, 64,  0,  1,  0,  0,  0,
+    0,  0,  0,120,191,255,247,255,255,255,255,255, 63,  0,255,255,
+   63,255, 87, 32,  2,  1, 24,  0,144, 80,184,  0,248,  0,  0,  0,
+    0,  0,224,  0,  2,  0,  1,128,  0,  0, 48,  0,224,  0,  0, 24,
+    0,  0, 33,  0,  0,  0,  1, 32,  0,  0,128,  2,  0,224,  0,  0,
+    0,240,  3,192,  0, 64,254,  7,  0,224,255,255, 63,  0,  0,  0,
+  254,255,  0,  4,  0,128,252,247,  0,254,255,255,255,255,255,  7,
+  255,255,255, 63,192,255,255,255,255,255,  0,  0,  0,  0,240,255,
+    0,  0,224,255,  0,240,  0,  0,  0,255,  0,252,  0,255,  0,  0,
+    0,192,255,255,  0,240,255,255,255,255,255,247,191,255,255,255,
 };
 
 static inline unsigned
@@ -75,7 +70,7 @@ _hb_emoji_b1 (const uint8_t* a, unsigned i)
 static inline uint_fast8_t
 _hb_emoji_is_Extended_Pictographic (unsigned u)
 {
-  return u<131070u?_hb_emoji_b1(224+_hb_emoji_u8,((_hb_emoji_u8[64+(((_hb_emoji_b4(_hb_emoji_u8,u>>6>>4))<<4)+((u>>6)&15u))])<<6)+((u)&63u)):0;
+  return u<131070u?_hb_emoji_b1(264+_hb_emoji_u8,((_hb_emoji_u8[144+(((_hb_emoji_u8[64+(((_hb_emoji_b4(_hb_emoji_u8,u>>5>>2>>3))<<3)+((u>>5>>2)&7u))])<<2)+((u>>5)&3u))])<<5)+((u)&31u)):0;
 }
 
 
index 83ead63..aa2735b 100644 (file)
@@ -165,11 +165,11 @@ hb_unicode_funcs_get_default ()
 
 #if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL)
 #error "Could not find any Unicode functions implementation, you have to provide your own"
-#error "Consider building hb-ucd.cc.  If you absolutely want to build without any, check the code."
+#error "Consider building hb-ucd.cc.  If you absolutely want to build without any, define HB_NO_UNICODE_FUNCS."
 #endif
 
 /**
- * hb_unicode_funcs_create: (Xconstructor)
+ * hb_unicode_funcs_create:
  * @parent: (nullable): Parent Unicode-functions structure
  *
  * Creates a new #hb_unicode_funcs_t structure of Unicode functions.
@@ -281,7 +281,7 @@ hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
  *
  * Attaches a user-data key/data pair to the specified Unicode-functions structure. 
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -308,8 +308,8 @@ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
  * Since: 0.9.2
  **/
 void *
-hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
-                               hb_user_data_key_t *key)
+hb_unicode_funcs_get_user_data (const hb_unicode_funcs_t *ufuncs,
+                               hb_user_data_key_t       *key)
 {
   return hb_object_get_user_data (ufuncs, key);
 }
@@ -340,7 +340,7 @@ hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
  * Tests whether the specified Unicode-functions structure
  * is immutable.
  *
- * Return value: %true if @ufuncs is immutable, %false otherwise
+ * Return value: `true` if @ufuncs is immutable, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -377,20 +377,30 @@ hb_unicode_funcs_set_##name##_func (hb_unicode_funcs_t               *ufuncs,     \
                                    hb_destroy_func_t               destroy)    \
 {                                                                              \
   if (hb_object_is_immutable (ufuncs))                                         \
-    return;                                                                    \
+    goto fail;                                                                 \
+                                                                               \
+  if (!func)                                                                   \
+  {                                                                            \
+    if (destroy)                                                               \
+      destroy (user_data);                                                     \
+    destroy = nullptr;                                                         \
+    user_data = ufuncs->parent->user_data.name;                                        \
+  }                                                                            \
                                                                                \
   if (ufuncs->destroy.name)                                                    \
     ufuncs->destroy.name (ufuncs->user_data.name);                             \
                                                                                \
-  if (func) {                                                                  \
+  if (func)                                                                    \
     ufuncs->func.name = func;                                                  \
-    ufuncs->user_data.name = user_data;                                                \
-    ufuncs->destroy.name = destroy;                                            \
-  } else {                                                                     \
+  else                                                                         \
     ufuncs->func.name = ufuncs->parent->func.name;                             \
-    ufuncs->user_data.name = ufuncs->parent->user_data.name;                   \
-    ufuncs->destroy.name = nullptr;                                            \
-  }                                                                            \
+  ufuncs->user_data.name = user_data;                                          \
+  ufuncs->destroy.name = destroy;                                              \
+  return;                                                                      \
+                                                                               \
+fail:                                                                          \
+  if (destroy)                                                                 \
+    destroy (user_data);                                                       \
 }
 
 HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
@@ -421,7 +431,7 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
  * Calls the composition function of the specified
  * Unicode-functions structure @ufuncs.
  *
- * Return value: %true if @a and @b composed, %false otherwise
+ * Return value: `true` if @a and @b composed, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -446,7 +456,7 @@ hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
  * Calls the decomposition function of the specified
  * Unicode-functions structure @ufuncs.
  *
- * Return value: %true if @ab was decomposed, %false otherwise
+ * Return value: `true` if @ab was decomposed, `false` otherwise
  *
  * Since: 0.9.2
  **/
index c04ee15..5b5c45c 100644 (file)
@@ -164,7 +164,7 @@ typedef enum
  * @HB_UNICODE_COMBINING_CLASS_CCC122: [Lao]
  * @HB_UNICODE_COMBINING_CLASS_CCC129: [Tibetan]
  * @HB_UNICODE_COMBINING_CLASS_CCC130: [Tibetan]
- * @HB_UNICODE_COMBINING_CLASS_CCC133: [Tibetan]
+ * @HB_UNICODE_COMBINING_CLASS_CCC132: [Tibetan] Since: 7.2.0
  * @HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT: Marks attached at the bottom left
  * @HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW: Marks attached directly below
  * @HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE: Marks attached directly above
@@ -246,7 +246,7 @@ typedef enum
   /* Tibetan */
   HB_UNICODE_COMBINING_CLASS_CCC129    = 129,
   HB_UNICODE_COMBINING_CLASS_CCC130    = 130,
-  HB_UNICODE_COMBINING_CLASS_CCC133    = 132,
+  HB_UNICODE_COMBINING_CLASS_CCC132    = 132,
 
 
   HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT       = 200,
@@ -317,8 +317,8 @@ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
 
 
 HB_EXTERN void *
-hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
-                               hb_user_data_key_t *key);
+hb_unicode_funcs_get_user_data (const hb_unicode_funcs_t *ufuncs,
+                               hb_user_data_key_t       *key);
 
 
 HB_EXTERN void
@@ -429,7 +429,7 @@ typedef hb_script_t                 (*hb_unicode_script_func_t)             (hb_unicode_funcs_t *ufuncs,
  * The method must return an #hb_bool_t indicating the success
  * of the composition.
  * 
- * Return value: %true is @a,@b composed, %false otherwise
+ * Return value: `true` is @a,@b composed, `false` otherwise
  *
  **/
 typedef hb_bool_t                      (*hb_unicode_compose_func_t)            (hb_unicode_funcs_t *ufuncs,
@@ -453,7 +453,7 @@ typedef hb_bool_t                   (*hb_unicode_compose_func_t)            (hb_unicode_funcs_t *ufuncs,
  * output parameters (if successful). The method must return an
  * #hb_bool_t indicating the success of the composition.
  * 
- * Return value: %true if @ab decomposed, %false otherwise
+ * Return value: `true` if @ab decomposed, `false` otherwise
  *
  **/
 typedef hb_bool_t                      (*hb_unicode_decompose_func_t)          (hb_unicode_funcs_t *ufuncs,
index 4c28bb0..39aaee5 100644 (file)
@@ -105,12 +105,9 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
   unsigned int
   modified_combining_class (hb_codepoint_t u)
   {
-    /* XXX This hack belongs to the USE shaper (for Tai Tham):
-     * Reorder SAKOT to ensure it comes after any tone marks. */
+    /* Reorder SAKOT to ensure it comes after any tone marks. */
     if (unlikely (u == 0x1A60u)) return 254;
-
-    /* XXX This hack belongs to the Tibetan shaper:
-     * Reorder PADMA to ensure it comes after any vowel marks. */
+    /* Reorder PADMA to ensure it comes after any vowel marks. */
     if (unlikely (u == 0x0FC6u)) return 254;
     /* Reorder TSA -PHRU to reorder before U+0F74 */
     if (unlikely (u == 0x0F39u)) return 127;
index 50f71ce..1b8ac36 100644 (file)
@@ -355,7 +355,7 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
     return nullptr;
   }
 
-  memcpy(new_sfnt_data, orig_sfnt_data, length);
+  hb_memcpy(new_sfnt_data, orig_sfnt_data, length);
 
   OT::name &name = StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
   name.format = 0;
@@ -478,11 +478,11 @@ populate_log_font (LOGFONTW  *lf,
                   hb_font_t *font,
                   unsigned int font_size)
 {
-  memset (lf, 0, sizeof (*lf));
+  hb_memset (lf, 0, sizeof (*lf));
   lf->lfHeight = - (int) font_size;
   lf->lfCharSet = DEFAULT_CHARSET;
 
-  memcpy (lf->lfFaceName, font->face->data.uniscribe->face_name, sizeof (lf->lfFaceName));
+  hb_memcpy (lf->lfFaceName, font->face->data.uniscribe->face_name, sizeof (lf->lfFaceName));
 
   return true;
 }
@@ -699,7 +699,7 @@ retry:
                                     script_tags,
                                     &item_count);
   if (unlikely (FAILED (hr)))
-    FAIL ("ScriptItemizeOpenType() failed: 0x%08lx", hr);
+    FAIL ("ScriptItemizeOpenType() failed: 0x%08lx", (unsigned long) hr);
 
 #undef MAX_ITEMS
 
@@ -785,7 +785,7 @@ retry:
     }
     if (unlikely (FAILED (hr)))
     {
-      FAIL ("ScriptShapeOpenType() failed: 0x%08lx", hr);
+      FAIL ("ScriptShapeOpenType() failed: 0x%08lx", (unsigned long) hr);
     }
 
     for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++)
@@ -811,7 +811,7 @@ retry:
                                     offsets + glyphs_offset,
                                     nullptr);
     if (unlikely (FAILED (hr)))
-      FAIL ("ScriptPlaceOpenType() failed: 0x%08lx", hr);
+      FAIL ("ScriptPlaceOpenType() failed: 0x%08lx", (unsigned long) hr);
 
     if (DEBUG_ENABLED (UNISCRIBE))
       fprintf (stderr, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n",
index ff5712d..1120bd1 100644 (file)
@@ -35,6 +35,7 @@
 struct hb_utf8_t
 {
   typedef uint8_t codepoint_t;
+  static constexpr unsigned max_len = 4;
 
   static const codepoint_t *
   next (const codepoint_t *text,
@@ -182,6 +183,7 @@ struct hb_utf16_xe_t
 {
   static_assert (sizeof (TCodepoint) == 2, "");
   typedef TCodepoint codepoint_t;
+  static constexpr unsigned max_len = 2;
 
   static const codepoint_t *
   next (const codepoint_t *text,
@@ -290,6 +292,7 @@ struct hb_utf32_xe_t
 {
   static_assert (sizeof (TCodepoint) == 4, "");
   typedef TCodepoint codepoint_t;
+  static constexpr unsigned max_len = 1;
 
   static const TCodepoint *
   next (const TCodepoint *text,
@@ -348,6 +351,7 @@ typedef hb_utf32_xe_t<uint32_t, false> hb_utf32_novalidate_t;
 struct hb_latin1_t
 {
   typedef uint8_t codepoint_t;
+  static constexpr unsigned max_len = 1;
 
   static const codepoint_t *
   next (const codepoint_t *text,
@@ -399,12 +403,13 @@ struct hb_latin1_t
 struct hb_ascii_t
 {
   typedef uint8_t codepoint_t;
+  static constexpr unsigned max_len = 1;
 
   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)
+       hb_codepoint_t replacement)
   {
     *unicode = *text++;
     if (*unicode >= 0x0080u)
@@ -450,4 +455,27 @@ struct hb_ascii_t
   }
 };
 
+template <typename utf_t>
+static inline const typename utf_t::codepoint_t *
+hb_utf_offset_to_pointer (const typename utf_t::codepoint_t *start,
+                         signed offset)
+{
+  hb_codepoint_t unicode;
+
+  while (offset-- > 0)
+    start = utf_t::next (start,
+                        start + utf_t::max_len,
+                        &unicode,
+                        HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT);
+
+  while (offset++ < 0)
+    start = utf_t::prev (start,
+                        start - utf_t::max_len,
+                        &unicode,
+                        HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT);
+
+  return start;
+}
+
+
 #endif /* HB_UTF_HH */
index 6c7d32e..13cfe56 100644 (file)
 
 #include "hb.hh"
 #include "hb-array.hh"
+#include "hb-meta.hh"
 #include "hb-null.hh"
 
 
 template <typename Type,
          bool sorted=false>
-struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty_t>::type
+struct hb_vector_t
 {
   typedef Type item_t;
   static constexpr unsigned item_size = hb_static_size (Type);
@@ -44,7 +45,7 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
   hb_vector_t () = default;
   hb_vector_t (std::initializer_list<Type> lst) : hb_vector_t ()
   {
-    alloc (lst.size ());
+    alloc (lst.size (), true);
     for (auto&& item : lst)
       push (item);
   }
@@ -52,14 +53,28 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
            hb_requires (hb_is_iterable (Iterable))>
   hb_vector_t (const Iterable &o) : hb_vector_t ()
   {
-    if (hb_iter (o).is_random_access_iterator)
-      alloc (hb_len (hb_iter (o)));
-    hb_copy (o, *this);
+    auto iter = hb_iter (o);
+    if (iter.is_random_access_iterator || iter.has_fast_len)
+      alloc (hb_len (iter), true);
+    hb_copy (iter, *this);
   }
   hb_vector_t (const hb_vector_t &o) : hb_vector_t ()
   {
-    alloc (o.length);
-    hb_copy (o, *this);
+    alloc (o.length, true);
+    if (unlikely (in_error ())) return;
+    copy_array (o.as_array ());
+  }
+  hb_vector_t (array_t o) : hb_vector_t ()
+  {
+    alloc (o.length, true);
+    if (unlikely (in_error ())) return;
+    copy_array (o);
+  }
+  hb_vector_t (c_array_t o) : hb_vector_t ()
+  {
+    alloc (o.length, true);
+    if (unlikely (in_error ())) return;
+    copy_array (o);
   }
   hb_vector_t (hb_vector_t &&o)
   {
@@ -70,9 +85,8 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
   }
   ~hb_vector_t () { fini (); }
 
-  private:
-  int allocated = 0; /* == -1 means allocation failed. */
   public:
+  int allocated = 0; /* < 0 means allocation failed. */
   unsigned int length = 0;
   public:
   Type *arrayZ = nullptr;
@@ -82,18 +96,27 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
     allocated = length = 0;
     arrayZ = nullptr;
   }
+  void init0 ()
+  {
+  }
 
   void fini ()
   {
-    shrink_vector (0);
-    hb_free (arrayZ);
+    /* We allow a hack to make the vector point to a foreign array
+     * by the user. In that case length/arrayZ are non-zero but
+     * allocated is zero. Don't free anything. */
+    if (allocated)
+    {
+      shrink_vector (0);
+      hb_free (arrayZ);
+    }
     init ();
   }
 
   void reset ()
   {
     if (unlikely (in_error ()))
-      allocated = length; // Big hack!
+      reset_error ();
     resize (0);
   }
 
@@ -107,8 +130,11 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
   hb_vector_t& operator = (const hb_vector_t &o)
   {
     reset ();
-    alloc (o.length);
-    hb_copy (o, *this);
+    alloc (o.length, true);
+    if (unlikely (in_error ())) return *this;
+
+    copy_array (o.as_array ());
+
     return *this;
   }
   hb_vector_t& operator = (hb_vector_t &&o)
@@ -118,7 +144,7 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
   }
 
   hb_bytes_t as_bytes () const
-  { return hb_bytes_t ((const char *) arrayZ, length * item_size); }
+  { return hb_bytes_t ((const char *) arrayZ, get_size ()); }
 
   bool operator == (const hb_vector_t &o) const { return as_array () == o.as_array (); }
   bool operator != (const hb_vector_t &o) const { return !(*this == o); }
@@ -160,14 +186,10 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
   operator   iter_t () const { return   iter (); }
   operator writer_t ()       { return writer (); }
 
-  c_array_t sub_array (unsigned int start_offset, unsigned int count) const
-  { return as_array ().sub_array (start_offset, count); }
-  c_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
-  { return as_array ().sub_array (start_offset, count); }
-  array_t sub_array (unsigned int start_offset, unsigned int count)
-  { return as_array ().sub_array (start_offset, count); }
-  array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
-  { return as_array ().sub_array (start_offset, count); }
+  /* Faster range-based for loop. */
+  Type *begin () const { return arrayZ; }
+  Type *end () const { return arrayZ + length; }
+
 
   hb_sorted_array_t<Type> as_sorted_array ()
   { return hb_sorted_array (arrayZ, length); }
@@ -183,104 +205,168 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
   Type *push ()
   {
     if (unlikely (!resize (length + 1)))
-      return &Crap (Type);
-    return &arrayZ[length - 1];
+      return std::addressof (Crap (Type));
+    return std::addressof (arrayZ[length - 1]);
   }
-  template <typename T>
-  Type *push (T&& v)
+  template <typename... Args> Type *push (Args&&... args)
   {
-    /* TODO Emplace? */
-    Type *p = push ();
-    if (p == &Crap (Type))
+    if (unlikely ((int) length >= allocated && !alloc (length + 1)))
       // If push failed to allocate then don't copy v, since this may cause
       // the created copy to leak memory since we won't have stored a
       // reference to it.
-      return p;
-    *p = std::forward<T> (v);
-    return p;
+      return std::addressof (Crap (Type));
+
+    /* Emplace. */
+    Type *p = std::addressof (arrayZ[length++]);
+    return new (p) Type (std::forward<Args> (args)...);
   }
 
   bool in_error () const { return allocated < 0; }
+  void set_error ()
+  {
+    assert (allocated >= 0);
+    allocated = -allocated - 1;
+  }
+  void reset_error ()
+  {
+    assert (allocated < 0);
+    allocated = -(allocated + 1);
+  }
 
   template <typename T = Type,
-           hb_enable_if (std::is_trivially_copy_assignable<T>::value)>
+           hb_enable_if (hb_is_trivially_copy_assignable(T))>
   Type *
-  realloc_vector (unsigned new_allocated)
+  realloc_vector (unsigned new_allocated, hb_priority<0>)
   {
+    if (!new_allocated)
+    {
+      hb_free (arrayZ);
+      return nullptr;
+    }
     return (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type));
   }
   template <typename T = Type,
-           hb_enable_if (!std::is_trivially_copy_assignable<T>::value)>
+           hb_enable_if (!hb_is_trivially_copy_assignable(T))>
   Type *
-  realloc_vector (unsigned new_allocated)
+  realloc_vector (unsigned new_allocated, hb_priority<0>)
   {
+    if (!new_allocated)
+    {
+      hb_free (arrayZ);
+      return nullptr;
+    }
     Type *new_array = (Type *) hb_malloc (new_allocated * sizeof (Type));
     if (likely (new_array))
     {
       for (unsigned i = 0; i < length; i++)
+      {
        new (std::addressof (new_array[i])) Type ();
-      for (unsigned i = 0; i < (unsigned) length; i++)
        new_array[i] = std::move (arrayZ[i]);
-      unsigned old_length = length;
-      shrink_vector (0);
-      length = old_length;
+       arrayZ[i].~Type ();
+      }
       hb_free (arrayZ);
     }
     return new_array;
   }
+  /* Specialization for hb_vector_t<hb_{vector,array}_t<U>> to speed up. */
+  template <typename T = Type,
+           hb_enable_if (hb_is_same (T, hb_vector_t<typename T::item_t>) ||
+                         hb_is_same (T, hb_array_t <typename T::item_t>))>
+  Type *
+  realloc_vector (unsigned new_allocated, hb_priority<1>)
+  {
+    if (!new_allocated)
+    {
+      hb_free (arrayZ);
+      return nullptr;
+    }
+    return (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type));
+  }
 
   template <typename T = Type,
-           hb_enable_if (std::is_trivially_constructible<T>::value ||
-                         !std::is_default_constructible<T>::value)>
+           hb_enable_if (hb_is_trivially_constructible(T))>
   void
-  grow_vector (unsigned size)
+  grow_vector (unsigned size, hb_priority<0>)
   {
-    memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ));
+    hb_memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ));
     length = size;
   }
   template <typename T = Type,
-           hb_enable_if (!std::is_trivially_constructible<T>::value &&
-                          std::is_default_constructible<T>::value)>
+           hb_enable_if (!hb_is_trivially_constructible(T))>
   void
-  grow_vector (unsigned size)
+  grow_vector (unsigned size, hb_priority<0>)
   {
-    while (length < size)
-    {
-      length++;
-      new (std::addressof (arrayZ[length - 1])) Type ();
-    }
+    for (; length < size; length++)
+      new (std::addressof (arrayZ[length])) Type ();
   }
-
+  /* Specialization for hb_vector_t<hb_{vector,array}_t<U>> to speed up. */
   template <typename T = Type,
-           hb_enable_if (std::is_trivially_destructible<T>::value)>
+           hb_enable_if (hb_is_same (T, hb_vector_t<typename T::item_t>) ||
+                         hb_is_same (T, hb_array_t <typename T::item_t>))>
   void
-  shrink_vector (unsigned size)
+  grow_vector (unsigned size, hb_priority<1>)
   {
+    hb_memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ));
     length = size;
   }
+
   template <typename T = Type,
-           hb_enable_if (!std::is_trivially_destructible<T>::value)>
+           hb_enable_if (hb_is_trivially_copyable (T))>
   void
-  shrink_vector (unsigned size)
+  copy_array (hb_array_t<const Type> other)
+  {
+    length = other.length;
+    if (!HB_OPTIMIZE_SIZE_VAL && sizeof (T) >= sizeof (long long))
+      /* This runs faster because of alignment. */
+      for (unsigned i = 0; i < length; i++)
+       arrayZ[i] = other.arrayZ[i];
+    else
+       hb_memcpy ((void *) arrayZ, (const void *) other.arrayZ, length * item_size);
+  }
+  template <typename T = Type,
+           hb_enable_if (!hb_is_trivially_copyable (T) &&
+                          std::is_copy_constructible<T>::value)>
+  void
+  copy_array (hb_array_t<const Type> other)
   {
-    while ((unsigned) length > size)
+    length = 0;
+    while (length < other.length)
     {
-      arrayZ[(unsigned) length - 1].~Type ();
-      length--;
+      length++;
+      new (std::addressof (arrayZ[length - 1])) Type (other.arrayZ[length - 1]);
     }
   }
-
   template <typename T = Type,
-           hb_enable_if (std::is_trivially_copy_assignable<T>::value)>
+           hb_enable_if (!hb_is_trivially_copyable (T) &&
+                         !std::is_copy_constructible<T>::value &&
+                         std::is_default_constructible<T>::value &&
+                         std::is_copy_assignable<T>::value)>
   void
-  shift_down_vector (unsigned i)
+  copy_array (hb_array_t<const Type> other)
   {
-    memmove (static_cast<void *> (&arrayZ[i - 1]),
-            static_cast<void *> (&arrayZ[i]),
-            (length - i) * sizeof (Type));
+    length = 0;
+    while (length < other.length)
+    {
+      length++;
+      new (std::addressof (arrayZ[length - 1])) Type ();
+      arrayZ[length - 1] = other.arrayZ[length - 1];
+    }
   }
-  template <typename T = Type,
-           hb_enable_if (!std::is_trivially_copy_assignable<T>::value)>
+
+  void
+  shrink_vector (unsigned size)
+  {
+    assert (size <= length);
+    if (!std::is_trivially_destructible<Type>::value)
+    {
+      unsigned count = length - size;
+      Type *p = arrayZ + length - 1;
+      while (count--)
+        p--->~Type ();
+    }
+    length = size;
+  }
+
   void
   shift_down_vector (unsigned i)
   {
@@ -289,31 +375,54 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
   }
 
   /* Allocate for size but don't adjust length. */
-  bool alloc (unsigned int size)
+  bool alloc (unsigned int size, bool exact=false)
   {
     if (unlikely (in_error ()))
       return false;
 
-    if (likely (size <= (unsigned) allocated))
-      return true;
+    unsigned int new_allocated;
+    if (exact)
+    {
+      /* If exact was specified, we allow shrinking the storage. */
+      size = hb_max (size, length);
+      if (size <= (unsigned) allocated &&
+         size >= (unsigned) allocated >> 2)
+       return true;
 
-    /* Reallocate */
+      new_allocated = size;
+    }
+    else
+    {
+      if (likely (size <= (unsigned) allocated))
+       return true;
+
+      new_allocated = allocated;
+      while (size > new_allocated)
+       new_allocated += (new_allocated >> 1) + 8;
+    }
 
-    unsigned int new_allocated = allocated;
-    while (size >= new_allocated)
-      new_allocated += (new_allocated >> 1) + 8;
 
-    Type *new_array = nullptr;
+    /* Reallocate */
+
     bool overflows =
       (int) in_error () ||
-      (new_allocated < (unsigned) allocated) ||
+      (new_allocated < size) ||
       hb_unsigned_mul_overflows (new_allocated, sizeof (Type));
-    if (likely (!overflows))
-      new_array = realloc_vector (new_allocated);
 
-    if (unlikely (!new_array))
+    if (unlikely (overflows))
+    {
+      set_error ();
+      return false;
+    }
+
+    Type *new_array = realloc_vector (new_allocated, hb_prioritize);
+
+    if (unlikely (new_allocated && !new_array))
     {
-      allocated = -1;
+      if (new_allocated <= (unsigned) allocated)
+        return true; // shrinking failed; it's okay; happens in our fuzzer
+
+      set_error ();
       return false;
     }
 
@@ -323,54 +432,77 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
     return true;
   }
 
-  bool resize (int size_)
+  bool resize (int size_, bool initialize = true, bool exact = false)
   {
     unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
-    if (!alloc (size))
+    if (!alloc (size, exact))
       return false;
 
     if (size > length)
-      grow_vector (size);
+    {
+      if (initialize)
+       grow_vector (size, hb_prioritize);
+    }
     else if (size < length)
-      shrink_vector (size);
+    {
+      if (initialize)
+       shrink_vector (size);
+    }
 
     length = size;
     return true;
   }
+  bool resize_exact (int size_, bool initialize = true)
+  {
+    return resize (size_, initialize, true);
+  }
 
   Type pop ()
   {
     if (!length) return Null (Type);
-    Type v = std::move (arrayZ[length - 1]);
+    Type v (std::move (arrayZ[length - 1]));
     arrayZ[length - 1].~Type ();
     length--;
     return v;
   }
 
-  void remove (unsigned int i)
+  void remove_ordered (unsigned int i)
   {
     if (unlikely (i >= length))
       return;
-    arrayZ[i].~Type ();
     shift_down_vector (i + 1);
+    arrayZ[length - 1].~Type ();
     length--;
   }
 
-  void shrink (int size_)
+  template <bool Sorted = sorted,
+           hb_enable_if (!Sorted)>
+  void remove_unordered (unsigned int i)
+  {
+    if (unlikely (i >= length))
+      return;
+    if (i != length - 1)
+      arrayZ[i] = std::move (arrayZ[length - 1]);
+    arrayZ[length - 1].~Type ();
+    length--;
+  }
+
+  void shrink (int size_, bool shrink_memory = true)
   {
     unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
     if (size >= length)
       return;
 
     shrink_vector (size);
+
+    if (shrink_memory)
+      alloc (size, true); /* To force shrinking memory if needed. */
   }
 
 
   /* Sorting API. */
-  void qsort (int (*cmp)(const void*, const void*))
+  void qsort (int (*cmp)(const void*, const void*) = Type::cmp)
   { as_array ().qsort (cmp); }
-  void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1)
-  { as_array ().qsort (start, end); }
 
   /* Unsorted search API. */
   template <typename T>
index 1f52d92..cd7257e 100644 (file)
@@ -41,26 +41,26 @@ HB_BEGIN_DECLS
  *
  * The major component of the library version available at compile-time.
  */
-#define HB_VERSION_MAJOR 3
+#define HB_VERSION_MAJOR 8
 /**
  * HB_VERSION_MINOR:
  *
  * The minor component of the library version available at compile-time.
  */
-#define HB_VERSION_MINOR 4
+#define HB_VERSION_MINOR 2
 /**
  * HB_VERSION_MICRO:
  *
  * The micro component of the library version available at compile-time.
  */
-#define HB_VERSION_MICRO 0
+#define HB_VERSION_MICRO 2
 
 /**
  * HB_VERSION_STRING:
  *
  * A string literal containing the library version available at compile-time.
  */
-#define HB_VERSION_STRING "3.4.0"
+#define HB_VERSION_STRING "8.2.2"
 
 /**
  * HB_VERSION_ATLEAST:
diff --git a/src/hb-wasm-api-blob.hh b/src/hb-wasm-api-blob.hh
new file mode 100644 (file)
index 0000000..310f402
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2023  Behdad Esfahbod
+ *
+ *  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_WASM_API_BLOB_HH
+#define HB_WASM_API_BLOB_HH
+
+#include "hb-wasm-api.hh"
+
+namespace hb {
+namespace wasm {
+
+
+HB_WASM_API (void, blob_free) (HB_WASM_EXEC_ENV
+                              ptr_d(blob_t, blob))
+{
+  HB_PTR_PARAM (blob_t, blob);
+  if (unlikely (!blob))
+    return;
+
+  module_free (blob->data);
+
+  blob->data = nullref;
+  blob->length = 0;
+}
+
+
+}}
+
+#endif /* HB_WASM_API_BLOB_HH */
diff --git a/src/hb-wasm-api-buffer.hh b/src/hb-wasm-api-buffer.hh
new file mode 100644 (file)
index 0000000..64217a0
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Copyright © 2023  Behdad Esfahbod
+ *
+ *  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_WASM_API_BUFFER_HH
+#define HB_WASM_API_BUFFER_HH
+
+#include "hb-wasm-api.hh"
+
+#include "hb-buffer.hh"
+
+namespace hb {
+namespace wasm {
+
+static_assert (sizeof (glyph_info_t) == sizeof (hb_glyph_info_t), "");
+static_assert (sizeof (glyph_position_t) == sizeof (hb_glyph_position_t), "");
+
+HB_WASM_API (bool_t, buffer_contents_realloc) (HB_WASM_EXEC_ENV
+                                              ptr_d(buffer_contents_t, contents),
+                                              uint32_t size)
+{
+  HB_PTR_PARAM (buffer_contents_t, contents);
+  if (unlikely (!contents))
+    return false;
+
+  if (size <= contents->length)
+    return true;
+
+  unsigned bytes;
+  if (hb_unsigned_mul_overflows (size, sizeof (glyph_info_t), &bytes))
+    return false;
+
+  glyph_info_t *info = HB_ARRAY_APP2NATIVE (glyph_info_t, contents->info, contents->length);
+  glyph_position_t *pos = HB_ARRAY_APP2NATIVE (glyph_position_t, contents->pos, contents->length);
+
+  if (unlikely (!info || !pos))
+    return false;
+
+  glyph_info_t *new_info = nullptr;
+  uint32_t new_inforef = module_malloc (bytes, (void **) &new_info);
+  glyph_position_t *new_pos = nullptr;
+  uint32_t new_posref = module_malloc (bytes, (void **) &new_pos);
+
+  unsigned old_bytes = contents->length * sizeof (glyph_info_t);
+  if (likely (new_inforef))
+  {
+    hb_memcpy (new_info, info, old_bytes);
+    module_free (contents->info);
+    contents->info = new_inforef;
+  }
+  if (likely (new_posref))
+  {
+    hb_memcpy (new_pos, pos, old_bytes);
+    module_free (contents->pos);
+    contents->pos = new_posref;
+  }
+
+  if (likely (new_info && new_pos))
+  {
+    contents->length = size;
+    return true;
+  }
+
+  return false;
+}
+
+HB_WASM_API (void, buffer_contents_free) (HB_WASM_EXEC_ENV
+                                         ptr_d(buffer_contents_t, contents))
+{
+  HB_PTR_PARAM (buffer_contents_t, contents);
+  if (unlikely (!contents))
+    return;
+
+  module_free (contents->info);
+  module_free (contents->pos);
+
+  contents->info = nullref;
+  contents->pos = nullref;
+  contents->length = 0;
+}
+
+HB_WASM_API (bool_t, buffer_copy_contents) (HB_WASM_EXEC_ENV
+                                           ptr_d(buffer_t, buffer),
+                                           ptr_d(buffer_contents_t, contents))
+{
+  HB_REF2OBJ (buffer);
+  HB_PTR_PARAM (buffer_contents_t, contents);
+  if (unlikely (!contents))
+    return false;
+
+  if (buffer->have_output)
+    buffer->sync ();
+  if (!buffer->have_positions)
+    buffer->clear_positions ();
+
+  unsigned length = buffer->len;
+
+  if (length <= contents->length)
+  {
+    glyph_info_t *info = HB_ARRAY_APP2NATIVE (glyph_info_t, contents->info, length);
+    glyph_position_t *pos = HB_ARRAY_APP2NATIVE (glyph_position_t, contents->pos, length);
+
+    if (unlikely (!info || !pos))
+    {
+      contents->length = 0;
+      return false;
+    }
+
+    unsigned bytes = length * sizeof (hb_glyph_info_t);
+    hb_memcpy (info, buffer->info, bytes);
+    hb_memcpy (pos, buffer->pos, bytes);
+
+    return true;
+  }
+
+  module_free (contents->info);
+  module_free (contents->pos);
+
+  contents->length = length;
+  unsigned bytes = length * sizeof (hb_glyph_info_t);
+  contents->info = wasm_runtime_module_dup_data (module_inst, (const char *) buffer->info, bytes);
+  contents->pos = wasm_runtime_module_dup_data (module_inst, (const char *) buffer->pos, bytes);
+
+  if (length && (!contents->info || !contents->pos))
+  {
+    contents->length = 0;
+    return false;
+  }
+
+  return true;
+}
+
+HB_WASM_API (bool_t, buffer_set_contents) (HB_WASM_EXEC_ENV
+                                          ptr_d(buffer_t, buffer),
+                                          ptr_d(const buffer_contents_t, contents))
+{
+  HB_REF2OBJ (buffer);
+  HB_PTR_PARAM (buffer_contents_t, contents);
+  if (unlikely (!contents))
+    return false;
+
+  unsigned length = contents->length;
+  unsigned bytes;
+  if (unlikely (hb_unsigned_mul_overflows (length, sizeof (buffer->info[0]), &bytes)))
+    return false;
+
+  if (unlikely (!buffer->resize (length)))
+    return false;
+
+  glyph_info_t *info = (glyph_info_t *) (validate_app_addr (contents->info, bytes) ? addr_app_to_native (contents->info) : nullptr);
+  glyph_position_t *pos = (glyph_position_t *) (validate_app_addr (contents->pos, bytes) ? addr_app_to_native (contents->pos) : nullptr);
+
+  if (!buffer->have_positions)
+    buffer->clear_positions (); /* This is wasteful. */
+
+  hb_memcpy (buffer->info, info, bytes);
+  hb_memcpy (buffer->pos, pos, bytes);
+  buffer->len = length;
+
+  return true;
+}
+
+HB_WASM_API (direction_t, buffer_get_direction) (HB_WASM_EXEC_ENV
+                                                ptr_d(buffer_t, buffer))
+{
+  HB_REF2OBJ (buffer);
+
+  return (direction_t) hb_buffer_get_direction (buffer);
+}
+
+HB_WASM_API (script_t, buffer_get_script) (HB_WASM_EXEC_ENV
+                                          ptr_d(buffer_t, buffer))
+{
+  HB_REF2OBJ (buffer);
+
+  return hb_script_to_iso15924_tag (hb_buffer_get_script (buffer));
+}
+
+HB_WASM_API (void, buffer_reverse) (HB_WASM_EXEC_ENV
+                                   ptr_d(buffer_t, buffer))
+{
+  HB_REF2OBJ (buffer);
+
+  hb_buffer_reverse (buffer);
+}
+
+HB_WASM_API (void, buffer_reverse_clusters) (HB_WASM_EXEC_ENV
+                                            ptr_d(buffer_t, buffer))
+{
+  HB_REF2OBJ (buffer);
+
+  hb_buffer_reverse_clusters (buffer);
+}
+
+}}
+
+#endif /* HB_WASM_API_BUFFER_HH */
similarity index 71%
rename from src/hb-subset-cff2.hh
rename to src/hb-wasm-api-common.hh
index f10556d..c38ca9c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2018 Adobe Inc.
+ * Copyright © 2023  Behdad Esfahbod
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * 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
+#ifndef HB_WASM_API_COMMON_HH
+#define HB_WASM_API_COMMON_HH
+
+#include "hb-wasm-api.hh"
+
+namespace hb {
+namespace wasm {
+
 
-#include "hb.hh"
+HB_WASM_API (direction_t, script_get_horizontal_direction) (HB_WASM_EXEC_ENV
+                                                           script_t script)
+{
+  return (direction_t)
+        hb_script_get_horizontal_direction (hb_script_from_iso15924_tag (script));
+}
 
-#include "hb-subset-plan.hh"
 
-HB_INTERNAL bool
-hb_subset_cff2 (hb_subset_context_t *c);
+}}
 
-#endif /* HB_SUBSET_CFF2_HH */
+#endif /* HB_WASM_API_COMMON_HH */
diff --git a/src/hb-wasm-api-face.hh b/src/hb-wasm-api-face.hh
new file mode 100644 (file)
index 0000000..22e50e9
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright © 2023  Behdad Esfahbod
+ *
+ *  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_WASM_API_FACE_HH
+#define HB_WASM_API_FACE_HH
+
+#include "hb-wasm-api.hh"
+
+namespace hb {
+namespace wasm {
+
+
+HB_WASM_API (ptr_t(face_t), face_create) (HB_WASM_EXEC_ENV
+                                         ptr_d(blob_t, blob),
+                                         unsigned int index)
+{
+  HB_PTR_PARAM (blob_t, blob);
+  hb_blob_t *hb_blob = hb_blob_create(
+                                     HB_ARRAY_APP2NATIVE (char, blob->data, blob->length),
+                                     blob->length,
+                                     HB_MEMORY_MODE_DUPLICATE,
+                                     NULL,
+                                     NULL);
+
+  hb_face_t *face = hb_face_create(hb_blob, index);
+
+  HB_OBJ2REF (face);
+  return faceref;
+}
+
+HB_WASM_API (bool_t, face_copy_table) (HB_WASM_EXEC_ENV
+                                      ptr_d(face_t, face),
+                                      tag_t table_tag,
+                                      ptr_d(blob_t, blob))
+{
+  HB_REF2OBJ (face);
+  HB_PTR_PARAM (blob_t, blob);
+  if (unlikely (!blob))
+    return false;
+
+  hb_blob_t *hb_blob = hb_face_reference_table (face, table_tag);
+
+  unsigned length;
+  const char *hb_data = hb_blob_get_data (hb_blob, &length);
+
+  if (length <= blob->length)
+  {
+    char *data = HB_ARRAY_APP2NATIVE (char, blob->data, length);
+
+    if (unlikely (!data))
+    {
+      blob->length = 0;
+      return false;
+    }
+
+    hb_memcpy (data, hb_data, length);
+
+    return true;
+  }
+
+  module_free (blob->data);
+
+  blob->length = length;
+  blob->data = wasm_runtime_module_dup_data (module_inst, hb_data, length);
+
+  hb_blob_destroy (hb_blob);
+
+  if (blob->length && !blob->data)
+  {
+    blob->length = 0;
+    return false;
+  }
+
+  return true;
+}
+
+HB_WASM_API (unsigned, face_get_upem) (HB_WASM_EXEC_ENV
+                                      ptr_d(face_t, face))
+{
+  HB_REF2OBJ (face);
+
+  return hb_face_get_upem (face);
+}
+
+
+}}
+
+#endif /* HB_WASM_API_FACE_HH */
diff --git a/src/hb-wasm-api-font.hh b/src/hb-wasm-api-font.hh
new file mode 100644 (file)
index 0000000..2d85db4
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Copyright © 2023  Behdad Esfahbod
+ *
+ *  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_WASM_API_FONT_HH
+#define HB_WASM_API_FONT_HH
+
+#include "hb-wasm-api.hh"
+
+#include "hb-outline.hh"
+
+namespace hb {
+namespace wasm {
+
+
+HB_WASM_API (ptr_t(font_t), font_create) (HB_WASM_EXEC_ENV
+                                         ptr_d(face_t, face))
+{
+  HB_REF2OBJ (face);
+
+  hb_font_t *font = hb_font_create (face);
+
+  HB_OBJ2REF (font);
+  return fontref;
+}
+
+HB_WASM_API (ptr_t(face_t), font_get_face) (HB_WASM_EXEC_ENV
+                                           ptr_d(font_t, font))
+{
+  HB_REF2OBJ (font);
+
+  hb_face_t *face = hb_font_get_face (font);
+
+  HB_OBJ2REF (face);
+  return faceref;
+}
+
+HB_WASM_API (void, font_get_scale) (HB_WASM_EXEC_ENV
+                                   ptr_d(font_t, font),
+                                   ptr_d(int32_t, x_scale),
+                                   ptr_d(int32_t, y_scale))
+{
+  HB_REF2OBJ (font);
+
+  HB_PTR_PARAM(int32_t, x_scale);
+  HB_PTR_PARAM(int32_t, y_scale);
+
+  hb_font_get_scale (font, x_scale, y_scale);
+}
+
+HB_WASM_API (codepoint_t, font_get_glyph) (HB_WASM_EXEC_ENV
+                                             ptr_d(font_t, font),
+                                             codepoint_t unicode,
+                                             codepoint_t variation_selector)
+{
+  HB_REF2OBJ (font);
+  codepoint_t glyph;
+
+  hb_font_get_glyph (font, unicode, variation_selector, &glyph);
+  return glyph;
+}
+
+HB_WASM_API (position_t, font_get_glyph_h_advance) (HB_WASM_EXEC_ENV
+                                                   ptr_d(font_t, font),
+                                                   codepoint_t glyph)
+{
+  HB_REF2OBJ (font);
+  return hb_font_get_glyph_h_advance (font, glyph);
+}
+
+HB_WASM_API (position_t, font_get_glyph_v_advance) (HB_WASM_EXEC_ENV
+                                                   ptr_d(font_t, font),
+                                                   codepoint_t glyph)
+{
+  HB_REF2OBJ (font);
+  return hb_font_get_glyph_v_advance (font, glyph);
+}
+
+static_assert (sizeof (glyph_extents_t) == sizeof (hb_glyph_extents_t), "");
+
+HB_WASM_API (bool_t, font_get_glyph_extents) (HB_WASM_EXEC_ENV
+                                             ptr_d(font_t, font),
+                                             codepoint_t glyph,
+                                             ptr_d(glyph_extents_t, extents))
+{
+  HB_REF2OBJ (font);
+  HB_PTR_PARAM (glyph_extents_t, extents);
+  if (unlikely (!extents))
+    return false;
+
+  return hb_font_get_glyph_extents (font, glyph,
+                                   (hb_glyph_extents_t *) extents);
+}
+
+HB_WASM_API (void, font_glyph_to_string) (HB_WASM_EXEC_ENV
+                                         ptr_d(font_t, font),
+                                         codepoint_t glyph,
+                                         char *s, uint32_t size)
+{
+  HB_REF2OBJ (font);
+
+  hb_font_glyph_to_string (font, glyph, s, size);
+}
+
+static_assert (sizeof (glyph_outline_point_t) == sizeof (hb_outline_point_t), "");
+static_assert (sizeof (uint32_t) == sizeof (hb_outline_t::contours[0]), "");
+
+HB_WASM_API (bool_t, font_copy_glyph_outline) (HB_WASM_EXEC_ENV
+                                              ptr_d(font_t, font),
+                                              codepoint_t glyph,
+                                              ptr_d(glyph_outline_t, outline))
+{
+  HB_REF2OBJ (font);
+  HB_PTR_PARAM (glyph_outline_t, outline);
+  if (unlikely (!outline))
+    return false;
+
+  hb_outline_t hb_outline;
+  auto *funcs = hb_outline_recording_pen_get_funcs ();
+
+  hb_font_draw_glyph (font, glyph, funcs, &hb_outline);
+
+  if (unlikely (hb_outline.points.in_error () ||
+               hb_outline.contours.in_error ()))
+  {
+    outline->n_points = outline->n_contours = 0;
+    return false;
+  }
+
+  // TODO Check two buffers separately
+  if (hb_outline.points.length <= outline->n_points &&
+      hb_outline.contours.length <= outline->n_contours)
+  {
+    glyph_outline_point_t *points = HB_ARRAY_APP2NATIVE (glyph_outline_point_t, outline->points, hb_outline.points.length);
+    uint32_t *contours = HB_ARRAY_APP2NATIVE (uint32_t, outline->contours, hb_outline.contours.length);
+
+    if (unlikely (!points || !contours))
+    {
+      outline->n_points = outline->n_contours = 0;
+      return false;
+    }
+
+    hb_memcpy (points, hb_outline.points.arrayZ, hb_outline.points.get_size ());
+    hb_memcpy (contours, hb_outline.contours.arrayZ, hb_outline.contours.get_size ());
+
+    return true;
+  }
+
+  outline->n_points = hb_outline.points.length;
+  outline->points = wasm_runtime_module_dup_data (module_inst,
+                                                 (const char *) hb_outline.points.arrayZ,
+                                                 hb_outline.points.get_size ());
+  outline->n_contours = hb_outline.contours.length;
+  outline->contours = wasm_runtime_module_dup_data (module_inst,
+                                                   (const char *) hb_outline.contours.arrayZ,
+                                                   hb_outline.contours.get_size ());
+
+  if ((outline->n_points && !outline->points) ||
+      (!outline->n_contours && !outline->contours))
+  {
+    outline->n_points = outline->n_contours = 0;
+    return false;
+  }
+
+  return true;
+}
+
+HB_WASM_API (void, glyph_outline_free) (HB_WASM_EXEC_ENV
+                                       ptr_d(glyph_outline_t, outline))
+{
+  HB_PTR_PARAM (glyph_outline_t, outline);
+  if (unlikely (!outline))
+    return;
+
+  module_free (outline->points);
+  module_free (outline->contours);
+
+  outline->n_points = 0;
+  outline->points = nullref;
+  outline->n_contours = 0;
+  outline->contours = nullref;
+}
+
+HB_WASM_API (bool_t, font_copy_coords) (HB_WASM_EXEC_ENV
+                                         ptr_d(font_t, font),
+                                         ptr_d(coords_t, coords))
+{
+  HB_REF2OBJ (font);
+  HB_PTR_PARAM (coords_t, coords);
+  if (unlikely (!coords))
+    return false;
+
+  unsigned our_length;
+  const int* our_coords = hb_font_get_var_coords_normalized(font, &our_length);
+
+  if (our_length <= coords->length) {
+    int *their_coords = HB_ARRAY_APP2NATIVE (int, coords->coords, our_length);
+    if (unlikely(!their_coords)) {
+       coords->length = 0;
+       return false;
+    }
+               unsigned bytes = our_length * sizeof (int);
+    hb_memcpy (their_coords, our_coords, bytes);
+
+    return true;
+  }
+
+  module_free (coords->coords);
+  coords->length = our_length;
+       unsigned bytes = our_length * sizeof (int);
+  coords->coords = wasm_runtime_module_dup_data (module_inst, (const char *) our_coords, bytes);
+       if (our_length && !coords->coords)
+         {
+    coords->length = 0;
+    return false;
+  }
+
+  return true;
+}
+
+HB_WASM_API (bool_t, font_set_coords) (HB_WASM_EXEC_ENV
+                                         ptr_d(font_t, font),
+                                         ptr_d(coords_t, coords))
+{
+  HB_REF2OBJ (font);
+  HB_PTR_PARAM (coords_t, coords);
+  if (unlikely (!coords))
+    return false;
+
+  unsigned length = coords->length;
+  unsigned bytes;
+  if (unlikely (hb_unsigned_mul_overflows (length, sizeof (int), &bytes)))
+    return false;
+
+  const int *our_coords = (const int *) (validate_app_addr (coords->coords, bytes) ? addr_app_to_native (coords->coords) : nullptr);
+  hb_font_set_var_coords_normalized(font, our_coords, length);
+  return true;
+}
+
+
+}}
+
+#endif /* HB_WASM_API_FONT_HH */
diff --git a/src/hb-wasm-api-shape.hh b/src/hb-wasm-api-shape.hh
new file mode 100644 (file)
index 0000000..622ff05
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright © 2023  Behdad Esfahbod
+ *
+ *  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_WASM_API_SHAPE_HH
+#define HB_WASM_API_SHAPE_HH
+
+#include "hb-wasm-api.hh"
+
+namespace hb {
+namespace wasm {
+
+
+static_assert (sizeof (feature_t) == sizeof (hb_feature_t), "");
+
+HB_WASM_INTERFACE (bool_t, shape_with) (HB_WASM_EXEC_ENV
+                                       ptr_d(font_t, font),
+                                       ptr_d(buffer_t, buffer),
+                                       ptr_d(const feature_t, features),
+                                       uint32_t num_features,
+                                       const char *shaper)
+{
+  if (unlikely (0 == strcmp (shaper, "wasm")))
+    return false;
+
+  HB_REF2OBJ (font);
+  HB_REF2OBJ (buffer);
+
+  /* Pre-conditions that make hb_shape_full() crash should be checked here. */
+
+  if (unlikely (!buffer->ensure_unicode ()))
+    return false;
+
+  if (unlikely (!HB_DIRECTION_IS_VALID (buffer->props.direction)))
+    return false;
+
+  HB_ARRAY_PARAM (const feature_t, features, num_features);
+  if (unlikely (!features && num_features))
+    return false;
+
+  const char * shaper_list[] = {shaper, nullptr};
+  return hb_shape_full (font, buffer,
+                       (hb_feature_t *) features, num_features,
+                       shaper_list);
+}
+
+
+}}
+
+#endif /* HB_WASM_API_SHAPE_HH */
similarity index 72%
rename from src/hb-subset-cff1.hh
rename to src/hb-wasm-api.cc
index aaf5def..1da8347 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2018 Adobe Inc.
+ * Copyright © 2023  Behdad Esfahbod
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * 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"
+#ifdef HAVE_WASM
+
+#include "hb-wasm-api.hh"
+
+#define module_inst wasm_runtime_get_module_inst (exec_env)
+
+
+#include "hb-wasm-api-blob.hh"
+#include "hb-wasm-api-buffer.hh"
+#include "hb-wasm-api-common.hh"
+#include "hb-wasm-api-face.hh"
+#include "hb-wasm-api-font.hh"
+#include "hb-wasm-api-shape.hh"
+
+
+#undef module_inst
 
-HB_INTERNAL bool
-hb_subset_cff1 (hb_subset_context_t *c);
+hb_user_data_key_t _hb_wasm_ref_type_key = {};
 
-#endif /* HB_SUBSET_CFF1_HH */
+#endif
diff --git a/src/hb-wasm-api.h b/src/hb-wasm-api.h
new file mode 100644 (file)
index 0000000..f9bd98e
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * Copyright © 2023  Behdad Esfahbod
+ *
+ *  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_WASM_API_H
+#define HB_WASM_API_H
+
+/*
+#include "hb.h"
+*/
+
+#include <stdint.h>
+
+
+#ifndef HB_WASM_BEGIN_DECLS
+# ifdef __cplusplus
+#  define HB_WASM_BEGIN_DECLS  extern "C" {
+#  define HB_WASM_END_DECLS    }
+# else /* !__cplusplus */
+#  define HB_WASM_BEGIN_DECLS
+#  define HB_WASM_END_DECLS
+# endif /* !__cplusplus */
+#endif
+
+
+HB_WASM_BEGIN_DECLS
+
+#ifndef HB_WASM_API
+#define HB_WASM_API(ret_t, name) ret_t name
+#endif
+#ifndef HB_WASM_API_COMPOUND /* compound return type */
+#define HB_WASM_API_COMPOUND(ret_t, name) HB_WASM_API(ret_t, name)
+#endif
+#ifndef HB_WASM_INTERFACE
+#define HB_WASM_INTERFACE(ret_t, name) ret_t name
+#endif
+#ifndef HB_WASM_EXEC_ENV
+#define HB_WASM_EXEC_ENV
+#endif
+#ifndef HB_WASM_EXEC_ENV_COMPOUND
+#define HB_WASM_EXEC_ENV_COMPOUND HB_WASM_EXEC_ENV
+#endif
+
+
+#ifndef bool_t
+#define bool_t uint32_t
+#endif
+#ifndef ptr_t
+#define ptr_t(type_t) type_t *
+#endif
+#ifndef ptr_d
+#define ptr_d(type_t, name) type_t *name
+#endif
+
+typedef uint32_t codepoint_t;
+typedef int32_t position_t;
+typedef uint32_t mask_t;
+typedef uint32_t tag_t;
+#define TAG(c1,c2,c3,c4) ((tag_t)((((uint32_t)(c1)&0xFF)<<24)|(((uint32_t)(c2)&0xFF)<<16)|(((uint32_t)(c3)&0xFF)<<8)|((uint32_t)(c4)&0xFF)))
+
+typedef enum {
+  DIRECTION_INVALID = 0,
+  DIRECTION_LTR = 4,
+  DIRECTION_RTL,
+  DIRECTION_TTB,
+  DIRECTION_BTT
+} direction_t;
+#define DIRECTION_IS_VALID(dir)                ((((unsigned int) (dir)) & ~3U) == 4)
+#define DIRECTION_IS_HORIZONTAL(dir)   ((((unsigned int) (dir)) & ~1U) == 4)
+#define DIRECTION_IS_VERTICAL(dir)     ((((unsigned int) (dir)) & ~1U) == 6)
+#define DIRECTION_IS_FORWARD(dir)      ((((unsigned int) (dir)) & ~2U) == 4)
+#define DIRECTION_IS_BACKWARD(dir)     ((((unsigned int) (dir)) & ~2U) == 5)
+#define DIRECTION_REVERSE(dir)         ((direction_t) (((unsigned int) (dir)) ^ 1))
+
+typedef tag_t script_t; /* ISO 15924 representation of Unicode scripts. */
+
+
+/* common */
+
+HB_WASM_API (direction_t, script_get_horizontal_direction) (HB_WASM_EXEC_ENV
+                                                           script_t script);
+
+
+/* blob */
+
+typedef struct
+{
+  uint32_t length;
+  ptr_t(char) data;
+} blob_t;
+#define BLOB_INIT {0, 0}
+
+HB_WASM_API (void, blob_free) (HB_WASM_EXEC_ENV
+                              ptr_d(blob_t, blob));
+
+/* buffer */
+
+typedef struct
+{
+  uint32_t codepoint;
+  uint32_t mask;
+  uint32_t cluster;
+  uint32_t var1;
+  uint32_t var2;
+} glyph_info_t;
+
+typedef struct
+{
+  position_t x_advance;
+  position_t y_advance;
+  position_t x_offset;
+  position_t y_offset;
+  uint32_t var;
+} glyph_position_t;
+
+typedef struct
+{
+  uint32_t length;
+  ptr_t(glyph_info_t) info;
+  ptr_t(glyph_position_t) pos;
+} buffer_contents_t;
+#define BUFFER_CONTENTS_INIT {0, 0, 0}
+
+HB_WASM_API (bool_t, buffer_contents_realloc) (HB_WASM_EXEC_ENV
+                                              ptr_d(buffer_contents_t, contents),
+                                              uint32_t size);
+
+HB_WASM_API (void, buffer_contents_free) (HB_WASM_EXEC_ENV
+                                         ptr_d(buffer_contents_t, contents));
+
+typedef struct buffer_t buffer_t;
+
+HB_WASM_API (bool_t, buffer_copy_contents) (HB_WASM_EXEC_ENV
+                                           ptr_d(buffer_t, buffer),
+                                           ptr_d(buffer_contents_t, contents));
+
+HB_WASM_API (bool_t, buffer_set_contents) (HB_WASM_EXEC_ENV
+                                          ptr_d(buffer_t, buffer),
+                                          ptr_d(const buffer_contents_t, contents));
+
+HB_WASM_API (direction_t, buffer_get_direction) (HB_WASM_EXEC_ENV
+                                                ptr_d(buffer_t, buffer));
+
+HB_WASM_API (script_t, buffer_get_script) (HB_WASM_EXEC_ENV
+                                          ptr_d(buffer_t, buffer));
+
+HB_WASM_API (void, buffer_reverse) (HB_WASM_EXEC_ENV
+                                   ptr_d(buffer_t, buffer));
+
+HB_WASM_API (void, buffer_reverse_clusters) (HB_WASM_EXEC_ENV
+                                            ptr_d(buffer_t, buffer));
+
+/* face */
+
+typedef struct face_t face_t;
+
+HB_WASM_API (ptr_t(face_t), face_create) (HB_WASM_EXEC_ENV
+                                         ptr_d(blob_t, blob),
+                                         unsigned int);
+
+HB_WASM_API (bool_t, face_copy_table) (HB_WASM_EXEC_ENV
+                                      ptr_d(face_t, face),
+                                      tag_t table_tag,
+                                      ptr_d(blob_t, blob));
+
+HB_WASM_API (unsigned, face_get_upem) (HB_WASM_EXEC_ENV
+                                      ptr_d(face_t, face));
+
+/* font */
+
+typedef struct font_t font_t;
+
+HB_WASM_API (ptr_t(font_t), font_create) (HB_WASM_EXEC_ENV
+                                         ptr_d(face_t, face));
+
+HB_WASM_API (ptr_t(face_t), font_get_face) (HB_WASM_EXEC_ENV
+                                           ptr_d(font_t, font));
+
+HB_WASM_API (void, font_get_scale) (HB_WASM_EXEC_ENV
+                                   ptr_d(font_t, font),
+                                   ptr_d(int32_t, x_scale),
+                                   ptr_d(int32_t, y_scale));
+
+HB_WASM_API (codepoint_t, font_get_glyph) (HB_WASM_EXEC_ENV
+                                             ptr_d(font_t, font),
+                                             codepoint_t unicode,
+                                             codepoint_t variation_selector);
+
+HB_WASM_API (position_t, font_get_glyph_h_advance) (HB_WASM_EXEC_ENV
+                                                   ptr_d(font_t, font),
+                                                   codepoint_t glyph);
+
+HB_WASM_API (position_t, font_get_glyph_v_advance) (HB_WASM_EXEC_ENV
+                                                   ptr_d(font_t, font),
+                                                   codepoint_t glyph);
+
+typedef struct
+{
+  position_t x_bearing;
+  position_t y_bearing;
+  position_t width;
+  position_t height;
+} glyph_extents_t;
+
+HB_WASM_API (bool_t, font_get_glyph_extents) (HB_WASM_EXEC_ENV
+                                             ptr_d(font_t, font),
+                                             codepoint_t glyph,
+                                             ptr_d(glyph_extents_t, extents));
+
+HB_WASM_API (void, font_glyph_to_string) (HB_WASM_EXEC_ENV
+                                         ptr_d(font_t, font),
+                                         codepoint_t glyph,
+                                         char *s, uint32_t size);
+
+
+typedef struct
+{
+  unsigned int length;
+  ptr_t(int) coords;
+} coords_t;
+
+HB_WASM_API (bool_t, font_copy_coords) (HB_WASM_EXEC_ENV
+                                         ptr_d(font_t, font),
+                                         ptr_d(coords_t, coords));
+
+HB_WASM_API (bool_t, font_set_coords) (HB_WASM_EXEC_ENV
+                                         ptr_d(font_t, font),
+                                         ptr_d(coords_t, coords));
+
+/* outline */
+
+enum glyph_outline_point_type_t
+{
+  MOVE_TO,
+  LINE_TO,
+  QUADRATIC_TO,
+  CUBIC_TO,
+};
+
+typedef struct
+{
+  float x;
+  float y;
+  uint32_t type;
+} glyph_outline_point_t;
+
+typedef struct
+{
+  uint32_t n_points;
+  ptr_t(glyph_outline_point_t) points;
+  uint32_t n_contours;
+  ptr_t(uint32_t) contours;
+} glyph_outline_t;
+#define GLYPH_OUTLINE_INIT {0, 0, 0, 0}
+
+HB_WASM_API (void, glyph_outline_free) (HB_WASM_EXEC_ENV
+                                       ptr_d(glyph_outline_t, outline));
+
+HB_WASM_API (bool_t, font_copy_glyph_outline) (HB_WASM_EXEC_ENV
+                                              ptr_d(font_t, font),
+                                              codepoint_t glyph,
+                                              ptr_d(glyph_outline_t, outline));
+
+
+/* shape */
+
+typedef struct
+{
+  tag_t    tag;
+  uint32_t value;
+  uint32_t start;
+  uint32_t end;
+} feature_t;
+#define FEATURE_GLOBAL_START   0
+#define FEATURE_GLOBAL_END     ((uint32_t) -1)
+
+HB_WASM_API (bool_t, shape_with) (HB_WASM_EXEC_ENV
+                                 ptr_d(font_t, font),
+                                 ptr_d(buffer_t, buffer),
+                                 ptr_d(const feature_t, features),
+                                 uint32_t num_features,
+                                 const char *shaper);
+
+/* Implement these in your shaper. */
+
+HB_WASM_INTERFACE (ptr_t(void), shape_plan_create) (ptr_d(face_t, face));
+
+HB_WASM_INTERFACE (bool_t, shape) (ptr_d(void, shape_plan),
+                                  ptr_d(font_t, font),
+                                  ptr_d(buffer_t, buffer),
+                                  ptr_d(const feature_t, features),
+                                  uint32_t num_features);
+
+HB_WASM_INTERFACE (void, shape_plan_destroy) (ptr_d(void, shape_plan));
+
+
+HB_WASM_END_DECLS
+
+#endif /* HB_WASM_API_H */
diff --git a/src/hb-wasm-api.hh b/src/hb-wasm-api.hh
new file mode 100644 (file)
index 0000000..4ead01c
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright © 2023  Behdad Esfahbod
+ *
+ *  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_WASM_API_HH
+#define HB_WASM_API_HH
+
+#include "hb.hh"
+
+#include <wasm_export.h>
+
+#define HB_WASM_BEGIN_DECLS namespace hb { namespace wasm {
+#define HB_WASM_END_DECLS }}
+
+#define HB_WASM_API(ret_t, name) HB_INTERNAL ret_t name
+#define HB_WASM_API_COMPOUND(ret_t, name) HB_INTERNAL void name
+
+#define HB_WASM_EXEC_ENV wasm_exec_env_t exec_env,
+#define HB_WASM_EXEC_ENV_COMPOUND wasm_exec_env_t exec_env, ptr_t() retptr,
+
+#define ptr_t(type_t) uint32_t
+#define ptr_d(type_t, name) uint32_t name##ptr
+
+#include "hb-wasm-api.h"
+
+#undef HB_WASM_BEGIN_DECLS
+#undef HB_WASM_END_DECLS
+
+
+enum {
+  hb_wasm_ref_type_none,
+  hb_wasm_ref_type_face,
+  hb_wasm_ref_type_font,
+  hb_wasm_ref_type_buffer,
+};
+
+HB_INTERNAL extern hb_user_data_key_t _hb_wasm_ref_type_key;
+
+#define nullref 0
+
+#define HB_REF2OBJ(obj) \
+  hb_##obj##_t *obj = nullptr; \
+  HB_STMT_START { \
+    (void) wasm_externref_ref2obj (obj##ptr, (void **) &obj); \
+    /* Check object type. */ \
+    /* This works because all our objects have the same hb_object_t layout. */ \
+    if (unlikely (hb_##obj##_get_user_data (obj, &_hb_wasm_ref_type_key) != \
+                 (void *) hb_wasm_ref_type_##obj)) \
+      obj = hb_##obj##_get_empty (); \
+  } HB_STMT_END
+
+#define HB_OBJ2REF(obj) \
+  uint32_t obj##ref = nullref; \
+  HB_STMT_START { \
+    hb_##obj##_set_user_data (obj, &_hb_wasm_ref_type_key, \
+                             (void *) hb_wasm_ref_type_##obj, \
+                             nullptr, false); \
+    (void) wasm_externref_obj2ref (module_inst, obj, &obj##ref); \
+  } HB_STMT_END
+
+#define HB_RETURN_STRUCT(type, name) \
+  type *_name_ptr = nullptr; \
+  { \
+    if (likely (wasm_runtime_validate_app_addr (module_inst, \
+                                               retptr, sizeof (type)))) \
+    { \
+      _name_ptr = (type *) wasm_runtime_addr_app_to_native (module_inst, retptr); \
+      if (unlikely (!_name_ptr)) \
+       return; \
+    } \
+  } \
+  type &name = *_name_ptr
+
+#define HB_PTR_PARAM(type, name) \
+  type *name = nullptr; \
+  HB_STMT_START { \
+    if (likely (wasm_runtime_validate_app_addr (module_inst, \
+                                               name##ptr, sizeof (type)))) \
+      name = (type *) wasm_runtime_addr_app_to_native (module_inst, name##ptr); \
+  } HB_STMT_END
+
+#define HB_ARRAY_PARAM(type, name, length) \
+  type *name = nullptr; \
+  HB_STMT_START { \
+    if (likely (!hb_unsigned_mul_overflows (length, sizeof (type)) && \
+               wasm_runtime_validate_app_addr (module_inst, \
+                                               name##ptr, length * sizeof (type)))) \
+      name = (type *) wasm_runtime_addr_app_to_native (module_inst, name##ptr); \
+  } HB_STMT_END
+
+#define HB_ARRAY_APP2NATIVE(type, name, length) \
+    ((type *) (!hb_unsigned_mul_overflows (length, sizeof (type)) && \
+              validate_app_addr (name, (length) * sizeof (type)) ? \
+              addr_app_to_native (name) : nullptr))
+
+
+#endif /* HB_WASM_API_HH */
diff --git a/src/hb-wasm-shape.cc b/src/hb-wasm-shape.cc
new file mode 100644 (file)
index 0000000..a70b766
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ * Copyright © 2011  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
+ */
+
+#undef HB_DEBUG_WASM
+#define HB_DEBUG_WASM 1
+
+#include "hb-shaper-impl.hh"
+
+#ifdef HAVE_WASM
+
+/* Compile wasm-micro-runtime with:
+ *
+ * $ cmake -DWAMR_BUILD_MULTI_MODULE=1 -DWAMR_BUILD_REF_TYPES=1 -DWAMR_BUILD_FAST_JIT=1
+ * $ make
+ *
+ * If you manage to build a wasm shared module successfully and want to use it,
+ * do the following:
+ *
+ *   - Add -DWAMR_BUILD_MULTI_MODULE=1 to your cmake build for wasm-micro-runtime,
+ *
+ *   - Remove the #define HB_WASM_NO_MODULES line below,
+ *
+ *   - Install your shared module with name ending in .wasm in
+ *     $(prefix)/$(libdir)/harfbuzz/wasm/
+ *
+ *   - Build your font's wasm code importing the shared modules with the desired
+ *     name. This can be done eg.: __attribute__((import_module("graphite2")))
+ *     before each symbol in the shared-module's headers.
+ *
+ *   - Try shaping your font and hope for the best...
+ *
+ * I haven't been able to get this to work since emcc's support for shared libraries
+ * requires support from the host that seems to be missing from wasm-micro-runtime?
+ */
+
+#include "hb-wasm-api.hh"
+#include "hb-wasm-api-list.hh"
+
+#ifndef HB_WASM_NO_MODULES
+#define HB_WASM_NO_MODULES
+#endif
+
+
+#ifndef HB_WASM_NO_MODULES
+static bool HB_UNUSED
+_hb_wasm_module_reader (const char *module_name,
+                      uint8_t **p_buffer, uint32_t *p_size)
+{
+  char path[sizeof (HB_WASM_MODULE_DIR) + 64] = HB_WASM_MODULE_DIR "/";
+  strncat (path, module_name, sizeof (path) - sizeof (HB_WASM_MODULE_DIR) - 16);
+  strncat (path, ".wasm", 6);
+
+  auto *blob = hb_blob_create_from_file (path);
+
+  unsigned length;
+  auto *data = hb_blob_get_data (blob, &length);
+
+  *p_buffer = (uint8_t *) hb_malloc (length);
+
+  if (length && !p_buffer)
+    return false;
+
+  memcpy (*p_buffer, data, length);
+  *p_size = length;
+
+  hb_blob_destroy (blob);
+
+  return true;
+}
+
+static void HB_UNUSED
+_hb_wasm_module_destroyer (uint8_t *buffer, uint32_t size)
+{
+  hb_free (buffer);
+}
+#endif
+
+/*
+ * shaper face data
+ */
+
+#define HB_WASM_TAG_WASM HB_TAG('W','a','s','m')
+
+struct hb_wasm_shape_plan_t {
+  wasm_module_inst_t module_inst;
+  wasm_exec_env_t exec_env;
+  ptr_d(void, wasm_shape_plan);
+};
+
+struct hb_wasm_face_data_t {
+  hb_blob_t *wasm_blob;
+  wasm_module_t wasm_module;
+  mutable hb_atomic_ptr_t<hb_wasm_shape_plan_t> plan;
+};
+
+static bool
+_hb_wasm_init ()
+{
+  /* XXX
+   *
+   * Umm. Make this threadsafe. How?!
+   * It's clunky that we can't allocate a static mutex.
+   * So we have to first allocate one on the heap atomically...
+   *
+   * Do we also need to lock around module creation?
+   *
+   * Also, wasm-micro-runtime uses a singleton instance. So if
+   * another library or client uses it, all bets are off. :-(
+   * If nothing else, around HB_REF2OBJ().
+   */
+
+  static bool initialized;
+  if (initialized)
+    return true;
+
+  RuntimeInitArgs init_args;
+  hb_memset (&init_args, 0, sizeof (RuntimeInitArgs));
+
+  init_args.mem_alloc_type = Alloc_With_Allocator;
+  init_args.mem_alloc_option.allocator.malloc_func = (void *) hb_malloc;
+  init_args.mem_alloc_option.allocator.realloc_func = (void *) hb_realloc;
+  init_args.mem_alloc_option.allocator.free_func = (void *) hb_free;
+
+  // Native symbols need below registration phase
+  init_args.n_native_symbols = ARRAY_LENGTH (_hb_wasm_native_symbols);
+  init_args.native_module_name = "env";
+  init_args.native_symbols = _hb_wasm_native_symbols;
+
+  if (unlikely (!wasm_runtime_full_init (&init_args)))
+  {
+    DEBUG_MSG (WASM, nullptr, "Init runtime environment failed.");
+    return false;
+  }
+
+#ifndef HB_WASM_NO_MODULES
+  wasm_runtime_set_module_reader (_hb_wasm_module_reader,
+                                 _hb_wasm_module_destroyer);
+#endif
+
+  initialized = true;
+  return true;
+}
+
+hb_wasm_face_data_t *
+_hb_wasm_shaper_face_data_create (hb_face_t *face)
+{
+  char error[128];
+  hb_wasm_face_data_t *data = nullptr;
+  hb_blob_t *wasm_blob = nullptr;
+  wasm_module_t wasm_module = nullptr;
+
+  wasm_blob = hb_face_reference_table (face, HB_WASM_TAG_WASM);
+  unsigned length = hb_blob_get_length (wasm_blob);
+  if (!length)
+    goto fail;
+
+  if (!_hb_wasm_init ())
+    goto fail;
+
+  wasm_module = wasm_runtime_load ((uint8_t *) hb_blob_get_data_writable (wasm_blob, nullptr),
+                                  length, error, sizeof (error));
+  if (unlikely (!wasm_module))
+  {
+    DEBUG_MSG (WASM, nullptr, "Load wasm module failed: %s", error);
+    goto fail;
+  }
+
+  data = (hb_wasm_face_data_t *) hb_calloc (1, sizeof (hb_wasm_face_data_t));
+  if (unlikely (!data))
+    goto fail;
+
+  data->wasm_blob = wasm_blob;
+  data->wasm_module = wasm_module;
+
+  return data;
+
+fail:
+  if (wasm_module)
+      wasm_runtime_unload (wasm_module);
+  hb_blob_destroy (wasm_blob);
+  hb_free (data);
+  return nullptr;
+}
+
+static hb_wasm_shape_plan_t *
+acquire_shape_plan (hb_face_t *face,
+                   const hb_wasm_face_data_t *face_data)
+{
+  char error[128];
+
+  /* Fetch cached one if available. */
+  hb_wasm_shape_plan_t *plan = face_data->plan.get_acquire ();
+  if (likely (plan && face_data->plan.cmpexch (plan, nullptr)))
+    return plan;
+
+  plan = (hb_wasm_shape_plan_t *) hb_calloc (1, sizeof (hb_wasm_shape_plan_t));
+
+  wasm_module_inst_t module_inst = nullptr;
+  wasm_exec_env_t exec_env = nullptr;
+  wasm_function_inst_t func = nullptr;
+
+  constexpr uint32_t stack_size = 32 * 1024, heap_size = 2 * 1024 * 1024;
+
+  module_inst = plan->module_inst = wasm_runtime_instantiate (face_data->wasm_module,
+                                                             stack_size, heap_size,
+                                                             error, sizeof (error));
+  if (unlikely (!module_inst))
+  {
+    DEBUG_MSG (WASM, face_data, "Create wasm module instance failed: %s", error);
+    goto fail;
+  }
+
+  exec_env = plan->exec_env = wasm_runtime_create_exec_env (module_inst,
+                                                           stack_size);
+  if (unlikely (!exec_env)) {
+    DEBUG_MSG (WASM, face_data, "Create wasm execution environment failed.");
+    goto fail;
+  }
+
+  func = wasm_runtime_lookup_function (module_inst, "shape_plan_create", nullptr);
+  if (func)
+  {
+    wasm_val_t results[1];
+    wasm_val_t arguments[1];
+
+    HB_OBJ2REF (face);
+    if (unlikely (!faceref))
+    {
+      DEBUG_MSG (WASM, face_data, "Failed to register face object.");
+      goto fail;
+    }
+
+    results[0].kind = WASM_I32;
+    arguments[0].kind = WASM_I32;
+    arguments[0].of.i32 = faceref;
+    bool ret = wasm_runtime_call_wasm_a (exec_env, func,
+                                        ARRAY_LENGTH (results), results,
+                                        ARRAY_LENGTH (arguments), arguments);
+
+    if (unlikely (!ret))
+    {
+      DEBUG_MSG (WASM, module_inst, "Calling shape_plan_create() failed: %s",
+                wasm_runtime_get_exception (module_inst));
+      goto fail;
+    }
+    plan->wasm_shape_planptr = results[0].of.i32;
+  }
+
+  return plan;
+
+fail:
+
+  if (exec_env)
+    wasm_runtime_destroy_exec_env (exec_env);
+  if (module_inst)
+    wasm_runtime_deinstantiate (module_inst);
+  hb_free (plan);
+  return nullptr;
+}
+
+static void
+release_shape_plan (const hb_wasm_face_data_t *face_data,
+                   hb_wasm_shape_plan_t *plan,
+                   bool cache = false)
+{
+  if (cache && face_data->plan.cmpexch (nullptr, plan))
+    return;
+
+  auto *module_inst = plan->module_inst;
+  auto *exec_env = plan->exec_env;
+
+  /* Is there even any point to having a shape_plan_destroy function
+   * and calling it? */
+  if (plan->wasm_shape_planptr)
+  {
+
+    auto *func = wasm_runtime_lookup_function (module_inst, "shape_plan_destroy", nullptr);
+    if (func)
+    {
+      wasm_val_t arguments[1];
+
+      arguments[0].kind = WASM_I32;
+      arguments[0].of.i32 = plan->wasm_shape_planptr;
+      bool ret = wasm_runtime_call_wasm_a (exec_env, func,
+                                          0, nullptr,
+                                          ARRAY_LENGTH (arguments), arguments);
+
+      if (unlikely (!ret))
+      {
+       DEBUG_MSG (WASM, module_inst, "Calling shape_plan_destroy() failed: %s",
+                  wasm_runtime_get_exception (module_inst));
+      }
+    }
+  }
+
+  wasm_runtime_destroy_exec_env (exec_env);
+  wasm_runtime_deinstantiate (module_inst);
+  hb_free (plan);
+}
+
+void
+_hb_wasm_shaper_face_data_destroy (hb_wasm_face_data_t *data)
+{
+  if (data->plan.get_relaxed ())
+    release_shape_plan (data, data->plan);
+  wasm_runtime_unload (data->wasm_module);
+  hb_blob_destroy (data->wasm_blob);
+  hb_free (data);
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_wasm_font_data_t {};
+
+hb_wasm_font_data_t *
+_hb_wasm_shaper_font_data_create (hb_font_t *font HB_UNUSED)
+{
+  return (hb_wasm_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_wasm_shaper_font_data_destroy (hb_wasm_font_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper
+ */
+
+hb_bool_t
+_hb_wasm_shape (hb_shape_plan_t    *shape_plan,
+               hb_font_t          *font,
+               hb_buffer_t        *buffer,
+               const hb_feature_t *features,
+               unsigned int        num_features)
+{
+  if (unlikely (buffer->in_error ()))
+    return false;
+
+  bool ret = true;
+  hb_face_t *face = font->face;
+  const hb_wasm_face_data_t *face_data = face->data.wasm;
+
+  bool retried = false;
+  if (0)
+  {
+retry:
+    DEBUG_MSG (WASM, font, "Retrying...");
+  }
+
+  wasm_function_inst_t func = nullptr;
+
+  hb_wasm_shape_plan_t *plan = acquire_shape_plan (face, face_data);
+  if (unlikely (!plan))
+  {
+    DEBUG_MSG (WASM, face_data, "Acquiring shape-plan failed.");
+    return false;
+  }
+
+  auto *module_inst = plan->module_inst;
+  auto *exec_env = plan->exec_env;
+
+  HB_OBJ2REF (font);
+  HB_OBJ2REF (buffer);
+  if (unlikely (!fontref || !bufferref))
+  {
+    DEBUG_MSG (WASM, module_inst, "Failed to register objects.");
+    goto fail;
+  }
+
+  func = wasm_runtime_lookup_function (module_inst, "shape", nullptr);
+  if (unlikely (!func))
+  {
+    DEBUG_MSG (WASM, module_inst, "Shape function not found.");
+    goto fail;
+  }
+
+  wasm_val_t results[1];
+  wasm_val_t arguments[5];
+
+  results[0].kind = WASM_I32;
+  arguments[0].kind = WASM_I32;
+  arguments[0].of.i32 = plan->wasm_shape_planptr;
+  arguments[1].kind = WASM_I32;
+  arguments[1].of.i32 = fontref;
+  arguments[2].kind = WASM_I32;
+  arguments[2].of.i32 = bufferref;
+  arguments[3].kind = WASM_I32;
+  arguments[3].of.i32 = num_features ? wasm_runtime_module_dup_data (module_inst,
+                                                                    (const char *) features,
+                                                                    num_features * sizeof (features[0])) : 0;
+  arguments[4].kind = WASM_I32;
+  arguments[4].of.i32 = num_features;
+
+  ret = wasm_runtime_call_wasm_a (exec_env, func,
+                                 ARRAY_LENGTH (results), results,
+                                 ARRAY_LENGTH (arguments), arguments);
+
+  if (num_features)
+    wasm_runtime_module_free (module_inst, arguments[2].of.i32);
+
+  if (unlikely (!ret || !results[0].of.i32))
+  {
+    DEBUG_MSG (WASM, module_inst, "Calling shape() failed: %s",
+              wasm_runtime_get_exception (module_inst));
+    if (!buffer->ensure_unicode ())
+    {
+      DEBUG_MSG (WASM, font, "Shape failed but buffer is not in Unicode; failing...");
+      goto fail;
+    }
+    if (retried)
+    {
+      DEBUG_MSG (WASM, font, "Giving up...");
+      goto fail;
+    }
+    buffer->successful = true;
+    retried = true;
+    release_shape_plan (face_data, plan);
+    plan = nullptr;
+    goto retry;
+  }
+
+  /* TODO Regularize clusters according to direction & cluster level,
+   * such that client doesn't crash with unmet expectations. */
+
+  if (!results[0].of.i32)
+  {
+fail:
+    ret = false;
+  }
+
+  release_shape_plan (face_data, plan, ret);
+
+  if (ret)
+  {
+    buffer->clear_glyph_flags ();
+    buffer->unsafe_to_break ();
+  }
+
+  return ret;
+}
+
+#endif
index 360686c..5a6ae66 100644 (file)
--- a/src/hb.h
+++ b/src/hb.h
@@ -36,6 +36,7 @@
 #include "hb-face.h"
 #include "hb-font.h"
 #include "hb-map.h"
+#include "hb-paint.h"
 #include "hb-set.h"
 #include "hb-shape.h"
 #include "hb-shape-plan.h"
index b9f5f71..972608d 100644 (file)
--- a/src/hb.hh
+++ b/src/hb.hh
@@ -29,7 +29,6 @@
 #ifndef HB_HH
 #define HB_HH
 
-
 #ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC
 #ifdef _MSC_VER
 #pragma warning( disable: 4068 ) /* Unknown pragma */
@@ -65,6 +64,8 @@
 #pragma GCC diagnostic error   "-Wbitwise-instead-of-logical"
 #pragma GCC diagnostic error   "-Wcast-align"
 #pragma GCC diagnostic error   "-Wcast-function-type"
+#pragma GCC diagnostic error   "-Wconstant-conversion"
+#pragma GCC diagnostic error   "-Wcomma"
 #pragma GCC diagnostic error   "-Wdelete-non-virtual-dtor"
 #pragma GCC diagnostic error   "-Wembedded-directive"
 #pragma GCC diagnostic error   "-Wextra-semi-stmt"
 #pragma GCC diagnostic warning "-Wdisabled-optimization"
 #pragma GCC diagnostic warning "-Wdouble-promotion"
 #pragma GCC diagnostic warning "-Wformat=2"
+#pragma GCC diagnostic warning "-Wformat-signedness"
 #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"
+#pragma GCC diagnostic warning "-Wunsafe-loop-optimizations"
 #pragma GCC diagnostic warning "-Wunused-but-set-variable"
 #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
 #if defined(__GNUC__) && !defined(__clang__)
 #pragma GCC diagnostic ignored "-Wunused-result"               // TODO fix
 /* Ignored intentionally. */
 #ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_IGNORED
 #pragma GCC diagnostic ignored "-Wclass-memaccess"
+#pragma GCC diagnostic ignored "-Wcast-function-type-strict" // https://github.com/harfbuzz/harfbuzz/pull/3859#issuecomment-1295409126
+#pragma GCC diagnostic ignored "-Wdangling-reference" // https://github.com/harfbuzz/harfbuzz/issues/4043
 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
 #pragma GCC diagnostic ignored "-Wformat-zero-length"
 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
 
 
 #include "hb-config.hh"
+#include "hb-limits.hh"
 
 
 /*
 #include <cassert>
 #include <cfloat>
 #include <climits>
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && !defined(_USE_MATH_DEFINES)
 # define _USE_MATH_DEFINES
 #endif
 #include <cmath>
@@ -243,9 +247,17 @@ extern "C" void  hb_free_impl(void *ptr);
  * Compiler attributes
  */
 
-#if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__)
-#define likely(expr) (__builtin_expect (!!(expr), 1))
-#define unlikely(expr) (__builtin_expect (!!(expr), 0))
+// gcc 10 has __has_builtin but not earlier versions. Sanction any gcc >= 5
+// clang defines it so no need.
+#ifdef __has_builtin
+#define hb_has_builtin __has_builtin
+#else
+#define hb_has_builtin(x) ((defined(__GNUC__) && __GNUC__ >= 5))
+#endif
+
+#if defined(__OPTIMIZE__) && hb_has_builtin(__builtin_expect)
+#define likely(expr) __builtin_expect (bool(expr), 1)
+#define unlikely(expr) __builtin_expect (bool(expr), 0)
 #else
 #define likely(expr) (expr)
 #define unlikely(expr) (expr)
@@ -304,6 +316,14 @@ extern "C" void  hb_free_impl(void *ptr);
 #define __restrict
 #endif
 
+#ifndef HB_ALWAYS_INLINE
+#if defined(_MSC_VER)
+#define HB_ALWAYS_INLINE __forceinline
+#else
+#define HB_ALWAYS_INLINE __attribute__((always_inline)) inline
+#endif
+#endif
+
 /*
  * Borrowed from https://bugzilla.mozilla.org/show_bug.cgi?id=1215411
  * HB_FALLTHROUGH is an annotation to suppress compiler warnings about switch
@@ -460,6 +480,37 @@ static int HB_UNUSED _hb_errno = 0;
 #endif
 #endif
 
+
+// Locale business
+
+#if !defined(HB_NO_SETLOCALE) && (!defined(HAVE_NEWLOCALE) || !defined(HAVE_USELOCALE))
+#define HB_NO_SETLOCALE 1
+#endif
+
+#ifndef HB_NO_SETLOCALE
+
+#include <locale.h>
+#ifdef HAVE_XLOCALE_H
+#include <xlocale.h> // Needed on BSD/OS X for uselocale
+#endif
+
+#ifdef WIN32
+#define hb_locale_t _locale_t
+#else
+#define hb_locale_t locale_t
+#endif
+#define hb_setlocale setlocale
+#define hb_uselocale uselocale
+
+#else
+
+#define hb_locale_t void *
+#define hb_setlocale(Category, Locale) "C"
+#define hb_uselocale(Locale) ((hb_locale_t) 0)
+
+#endif
+
+
 /* Lets assert int types.  Saves trouble down the road. */
 static_assert ((sizeof (hb_codepoint_t) == 4), "");
 static_assert ((sizeof (hb_position_t) == 4), "");
@@ -467,9 +518,16 @@ static_assert ((sizeof (hb_mask_t) == 4), "");
 static_assert ((sizeof (hb_var_int_t) == 4), "");
 
 
+/* Pie time. */
+// https://github.com/harfbuzz/harfbuzz/issues/4166
+#define HB_PI 3.14159265358979f
+#define HB_2_PI (2.f * HB_PI)
+
+
 /* 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-cplusplus.hh"
 #include "hb-meta.hh"
 #include "hb-mutex.hh"
 #include "hb-number.hh"
index 1ab013c..4af9569 100644 (file)
@@ -42,7 +42,7 @@
 #define hb_blob_create_from_file_or_fail(x)  hb_blob_get_empty ()
 #endif
 
-#if !defined(HB_NO_COLOR) && !defined(HB_NO_DRAW) && defined(HB_EXPERIMENTAL_API)
+#if !defined(HB_NO_COLOR) && !defined(HB_NO_DRAW)
 static void
 svg_dump (hb_face_t *face, unsigned face_index)
 {
@@ -58,7 +58,8 @@ svg_dump (hb_face_t *face, unsigned face_index)
     const char *data = hb_blob_get_data (blob, &length);
 
     char output_path[255];
-    sprintf (output_path, "out/svg-%u-%u.svg%s",
+    snprintf (output_path, sizeof output_path,
+            "out/svg-%u-%u.svg%s",
             glyph_id,
             face_index,
             // append "z" if the content is gzipped, https://stackoverflow.com/a/6059405
@@ -112,7 +113,7 @@ png_dump (hb_face_t *face, unsigned face_index)
        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);
+       snprintf (output_path, sizeof output_path, "out/png-%u-%u-%u.png", glyph_id, strike, face_index);
 
        FILE *f = fopen (output_path, "wb");
        fwrite (data, 1, length, f);
@@ -129,48 +130,60 @@ png_dump (hb_face_t *face, unsigned face_index)
   hb_font_destroy (font);
 }
 
-struct user_data_t
+struct draw_data_t
 {
   FILE *f;
   hb_position_t ascender;
 };
 
 static void
-move_to (hb_position_t to_x, hb_position_t to_y, user_data_t &user_data)
+move_to (hb_draw_funcs_t *, draw_data_t *draw_data,
+        hb_draw_state_t *,
+        float to_x, float to_y,
+        void *)
 {
-  fprintf (user_data.f, "M%d,%d", to_x, user_data.ascender - to_y);
+  fprintf (draw_data->f, "M%g,%g", to_x, draw_data->ascender - to_y);
 }
 
 static void
-line_to (hb_position_t to_x, hb_position_t to_y, user_data_t &user_data)
+line_to (hb_draw_funcs_t *, draw_data_t *draw_data,
+        hb_draw_state_t *,
+        float to_x, float to_y,
+        void *)
 {
-  fprintf (user_data.f, "L%d,%d", to_x, user_data.ascender - to_y);
+  fprintf (draw_data->f, "L%g,%g", to_x, draw_data->ascender - to_y);
 }
 
 static void
-quadratic_to (hb_position_t control_x, hb_position_t control_y,
-             hb_position_t to_x, hb_position_t to_y,
-             user_data_t &user_data)
+quadratic_to (hb_draw_funcs_t *, draw_data_t *draw_data,
+             hb_draw_state_t *,
+             float control_x, float control_y,
+             float to_x, float to_y,
+             void *)
 {
-  fprintf (user_data.f, "Q%d,%d %d,%d", control_x, user_data.ascender - control_y,
-                                       to_x, user_data.ascender - to_y);
+  fprintf (draw_data->f, "Q%g,%g %g,%g", control_x, draw_data->ascender - control_y,
+                                       to_x, draw_data->ascender - to_y);
 }
 
 static void
-cubic_to (hb_position_t control1_x, hb_position_t control1_y,
-         hb_position_t control2_x, hb_position_t control2_y,
-         hb_position_t to_x, hb_position_t to_y,
-         user_data_t &user_data)
+cubic_to (hb_draw_funcs_t *, draw_data_t *draw_data,
+         hb_draw_state_t *,
+         float control1_x, float control1_y,
+         float control2_x, float control2_y,
+         float to_x, float to_y,
+         void *)
 {
-  fprintf (user_data.f, "C%d,%d %d,%d %d,%d", control1_x, user_data.ascender - control1_y,
-                                              control2_x, user_data.ascender - control2_y,
-                                              to_x, user_data.ascender - to_y);
+  fprintf (draw_data->f, "C%g,%g %g,%g %g,%g", control1_x, draw_data->ascender - control1_y,
+                                              control2_x, draw_data->ascender - control2_y,
+                                              to_x, draw_data->ascender - to_y);
 }
 
 static void
-close_path (user_data_t &user_data)
+close_path (hb_draw_funcs_t *, draw_data_t *draw_data,
+           hb_draw_state_t *,
+           void *)
 {
-  fprintf (user_data.f, "Z");
+  fprintf (draw_data->f, "Z");
 }
 
 static void
@@ -207,20 +220,20 @@ layered_glyph_dump (hb_font_t *font, hb_draw_funcs_t *funcs, unsigned face_index
        hb_glyph_extents_t extents = {0};
        if (!hb_font_get_glyph_extents (font, gid, &extents))
        {
-         printf ("Skip gid: %d\n", gid);
+         printf ("Skip gid: %u\n", gid);
          continue;
        }
 
        char output_path[255];
-       sprintf (output_path, "out/colr-%u-%u-%u.svg", gid, palette, face_index);
+       snprintf (output_path, sizeof output_path, "out/colr-%u-%u-%u.svg", gid, palette, face_index);
        FILE *f = fopen (output_path, "wb");
        fprintf (f, "<svg xmlns=\"http://www.w3.org/2000/svg\""
                    " viewBox=\"%d %d %d %d\">\n",
                    extents.x_bearing, 0,
                    extents.x_bearing + extents.width, -extents.height);
-       user_data_t user_data;
-       user_data.ascender = extents.y_bearing;
-       user_data.f = f;
+       draw_data_t draw_data;
+       draw_data.ascender = extents.y_bearing;
+       draw_data.f = f;
 
        for (unsigned layer = 0; layer < num_layers; ++layer)
        {
@@ -232,8 +245,7 @@ layered_glyph_dump (hb_font_t *font, hb_draw_funcs_t *funcs, unsigned face_index
          if (hb_color_get_alpha (color) != 255)
            fprintf (f, "fill-opacity=\"%.3f\"", (double) hb_color_get_alpha (color) / 255.);
          fprintf (f, "d=\"");
-         if (!hb_font_draw_glyph (font, layers[layer].glyph, funcs, &user_data))
-           printf ("Failed to decompose layer %d while %d\n", layers[layer].glyph, gid);
+         hb_font_draw_glyph (font, layers[layer].glyph, funcs, &draw_data);
          fprintf (f, "\"/>\n");
        }
 
@@ -258,22 +270,21 @@ dump_glyphs (hb_font_t *font, hb_draw_funcs_t *funcs, unsigned face_index)
     hb_glyph_extents_t extents = {0};
     if (!hb_font_get_glyph_extents (font, gid, &extents))
     {
-      printf ("Skip gid: %d\n", gid);
+      printf ("Skip gid: %u\n", gid);
       continue;
     }
 
     char output_path[255];
-    sprintf (output_path, "out/%u-%u.svg", face_index, gid);
+    snprintf (output_path, sizeof output_path, "out/%u-%u.svg", face_index, gid);
     FILE *f = fopen (output_path, "wb");
     fprintf (f, "<svg xmlns=\"http://www.w3.org/2000/svg\""
                " viewBox=\"%d %d %d %d\"><path d=\"",
                extents.x_bearing, 0,
                extents.x_bearing + extents.width, font_extents.ascender - font_extents.descender);
-    user_data_t user_data;
-    user_data.ascender = font_extents.ascender;
-    user_data.f = f;
-    if (!hb_font_draw_glyph (font, gid, funcs, &user_data))
-      printf ("Failed to decompose gid: %d\n", gid);
+    draw_data_t draw_data;
+    draw_data.ascender = font_extents.ascender;
+    draw_data.f = f;
+    hb_font_draw_glyph (font, gid, funcs, &draw_data);
     fprintf (f, "\"/></svg>");
     fclose (f);
   }
@@ -300,11 +311,11 @@ dump_glyphs (hb_blob_t *blob, const char *font_name)
   fclose (font_name_file);
 
   hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
-  hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) move_to);
-  hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) line_to);
-  hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) quadratic_to);
-  hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) cubic_to);
-  hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) close_path);
+  hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) move_to, nullptr, nullptr);
+  hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) line_to, nullptr, nullptr);
+  hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) quadratic_to, nullptr, nullptr);
+  hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) cubic_to, nullptr, nullptr);
+  hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) close_path, nullptr, nullptr);
 
   unsigned num_faces = hb_face_count (blob);
   for (unsigned face_index = 0; face_index < num_faces; ++face_index)
@@ -382,18 +393,18 @@ print_layout_info_using_private_api (hb_blob_t *blob)
   }
 
   unsigned num_faces = hb_face_count (blob);
-  printf ("%d font(s) found in file\n", num_faces);
+  printf ("%u font(s) found in file\n", num_faces);
   for (unsigned n_font = 0; n_font < num_faces; ++n_font)
   {
     const OpenTypeFontFace &font = ot.get_face (n_font);
-    printf ("Font %d of %d:\n", n_font, num_faces);
+    printf ("Font %u of %u:\n", n_font, num_faces);
 
     unsigned num_tables = font.get_table_count ();
-    printf ("  %d table(s) found in font\n", num_tables);
+    printf ("  %u table(s) found in font\n", num_tables);
     for (unsigned n_table = 0; n_table < num_tables; ++n_table)
     {
       const OpenTypeTable &table = font.get_table (n_table);
-      printf ("  Table %2d of %2d: %.4s (0x%08x+0x%08x)\n", n_table, num_tables,
+      printf ("  Table %2u of %2u: %.4s (0x%08x+0x%08x)\n", n_table, num_tables,
              (const char *) table.tag,
              (unsigned) table.offset,
              (unsigned) table.length);
@@ -408,11 +419,11 @@ print_layout_info_using_private_api (hb_blob_t *blob)
        const GSUBGPOS &g = *reinterpret_cast<const GSUBGPOS *> (font_data + table.offset);
 
        unsigned num_scripts = g.get_script_count ();
-       printf ("    %d script(s) found in table\n", num_scripts);
+       printf ("    %u script(s) found in table\n", num_scripts);
        for (unsigned n_script = 0; n_script < num_scripts; ++n_script)
        {
          const Script &script = g.get_script (n_script);
-         printf ("    Script %2d of %2d: %.4s\n", n_script, num_scripts,
+         printf ("    Script %2u of %2u: %.4s\n", n_script, num_scripts,
                  (const char *) g.get_script_tag (n_script));
 
          if (!script.has_default_lang_sys ())
@@ -432,41 +443,41 @@ print_layout_info_using_private_api (hb_blob_t *blob)
            if (!langsys.has_required_feature ())
              printf ("        No required feature\n");
            else
-             printf ("        Required feature index: %d\n",
+             printf ("        Required feature index: %u\n",
                      langsys.get_required_feature_index ());
 
            unsigned num_features = langsys.get_feature_count ();
-           printf ("        %d feature(s) found in language system\n", num_features);
+           printf ("        %u feature(s) found in language system\n", num_features);
            for (unsigned n_feature = 0; n_feature < num_features; ++n_feature)
            {
-             printf ("        Feature index %2d of %2d: %d\n", n_feature, num_features,
+             printf ("        Feature index %2u of %2u: %u\n", n_feature, num_features,
                      langsys.get_feature_index (n_feature));
            }
          }
        }
 
        unsigned num_features = g.get_feature_count ();
-       printf ("    %d feature(s) found in table\n", num_features);
+       printf ("    %u feature(s) found in table\n", num_features);
        for (unsigned n_feature = 0; n_feature < num_features; ++n_feature)
        {
          const Feature &feature = g.get_feature (n_feature);
          unsigned num_lookups = feature.get_lookup_count ();
-         printf ("    Feature %2d of %2d: %c%c%c%c\n", n_feature, num_features,
+         printf ("    Feature %2u of %2u: %c%c%c%c\n", n_feature, num_features,
                  HB_UNTAG (g.get_feature_tag (n_feature)));
 
-         printf ("        %d lookup(s) found in feature\n", num_lookups);
+         printf ("        %u lookup(s) found in feature\n", num_lookups);
          for (unsigned n_lookup = 0; n_lookup < num_lookups; ++n_lookup) {
-           printf ("        Lookup index %2d of %2d: %d\n", n_lookup, num_lookups,
+           printf ("        Lookup index %2u of %2u: %u\n", n_lookup, num_lookups,
                    feature.get_lookup_index (n_lookup));
          }
        }
 
        unsigned num_lookups = g.get_lookup_count ();
-       printf ("    %d lookup(s) found in table\n", num_lookups);
+       printf ("    %u lookup(s) found in table\n", num_lookups);
        for (unsigned n_lookup = 0; n_lookup < num_lookups; ++n_lookup)
        {
          const Lookup &lookup = g.get_lookup (n_lookup);
-         printf ("    Lookup %2d of %2d: type %d, props 0x%04X\n", n_lookup, num_lookups,
+         printf ("    Lookup %2u of %2u: type %u, props 0x%04X\n", n_lookup, num_lookups,
                  lookup.get_type (), lookup.get_props ());
        }
 
@@ -482,12 +493,12 @@ print_layout_info_using_private_api (hb_blob_t *blob)
                  gdef.has_glyph_classes () ? "" : "no ");
        printf ("    Has %smark attachment types\n",
                  gdef.has_mark_attachment_types () ? "" : "no ");
-       printf ("    Has %sattach points\n",
-                 gdef.has_attach_points () ? "" : "no ");
+       printf ("    Has %sattach list\n",
+                 gdef.has_attach_list () ? "" : "no ");
        printf ("    Has %slig carets\n",
                  gdef.has_lig_carets () ? "" : "no ");
-       printf ("    Has %smark sets\n",
-                 gdef.has_mark_sets () ? "" : "no ");
+       printf ("    Has %smark glyph sets\n",
+                 gdef.has_mark_glyph_sets () ? "" : "no ");
        break;
        }
       }
@@ -508,11 +519,11 @@ main (int argc, char **argv)
 
   hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
   assert (blob);
-  printf ("Opened font file %s: %d bytes long\n", argv[1], hb_blob_get_length (blob));
+  printf ("Opened font file %s: %u bytes long\n", argv[1], hb_blob_get_length (blob));
 #ifndef MAIN_CC_NO_PRIVATE_API
   print_layout_info_using_private_api (blob);
 #endif
-#if !defined(HB_NO_COLOR) && !defined(HB_NO_DRAW) && defined(HB_EXPERIMENTAL_API)
+#if !defined(HB_NO_COLOR) && !defined(HB_NO_DRAW)
   dump_glyphs (blob, argv[1]);
 #endif
   hb_blob_destroy (blob);
index c9d3f17..5401e5d 100644 (file)
@@ -1,3 +1,5 @@
+fs = import('fs')
+
 hb_version_h = configure_file(
                command: [find_program('gen-hb-version.py'), meson.project_version(), '@OUTPUT@', '@INPUT@'],
                input: 'hb-version.h.in',
@@ -44,18 +46,25 @@ hb_base_sources = files(
   'hb-dispatch.hh',
   'hb-draw.cc',
   'hb-draw.hh',
+  'hb-paint.cc',
+  'hb-paint.hh',
+  'hb-paint-extents.cc',
+  'hb-paint-extents.hh',
   'hb-face.cc',
   'hb-face.hh',
+  'hb-face-builder.cc',
   'hb-fallback-shape.cc',
   'hb-font.cc',
   'hb-font.hh',
   'hb-iter.hh',
   'hb-kern.hh',
+  'hb-limits.hh',
   'hb-machinery.hh',
   'hb-map.cc',
   'hb-map.hh',
   'hb-meta.hh',
   'hb-ms-feature-ranges.hh',
+  'hb-multimap.hh',
   'hb-mutex.hh',
   'hb-null.hh',
   'hb-number.cc',
@@ -70,11 +79,6 @@ hb_base_sources = files(
   '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-table-list.hh',
   'hb-ot-face.cc',
@@ -92,6 +96,83 @@ hb_base_sources = files(
   'hb-ot-layout-gdef-table.hh',
   'hb-ot-layout-gpos-table.hh',
   'hb-ot-layout-gsub-table.hh',
+  'hb-outline.hh',
+  'hb-outline.cc',
+  'OT/Color/CBDT/CBDT.hh',
+  'OT/Color/COLR/COLR.hh',
+  'OT/Color/CPAL/CPAL.hh',
+  'OT/Color/sbix/sbix.hh',
+  'OT/Color/svg/svg.hh',
+  'OT/glyf/glyf.hh',
+  'OT/glyf/glyf-helpers.hh',
+  'OT/glyf/loca.hh',
+  'OT/glyf/path-builder.hh',
+  'OT/glyf/Glyph.hh',
+  'OT/glyf/GlyphHeader.hh',
+  'OT/glyf/SimpleGlyph.hh',
+  'OT/glyf/CompositeGlyph.hh',
+  'OT/glyf/SubsetGlyph.hh',
+  'OT/Layout/types.hh',
+  'OT/Layout/Common/Coverage.hh',
+  'OT/Layout/Common/CoverageFormat1.hh',
+  'OT/Layout/Common/CoverageFormat2.hh',
+  'OT/Layout/Common/RangeRecord.hh',
+  'OT/Layout/GDEF/GDEF.hh',
+  'OT/Layout/GPOS/AnchorFormat1.hh',
+  'OT/Layout/GPOS/AnchorFormat2.hh',
+  'OT/Layout/GPOS/AnchorFormat3.hh',
+  'OT/Layout/GPOS/Anchor.hh',
+  'OT/Layout/GPOS/AnchorMatrix.hh',
+  'OT/Layout/GPOS/ChainContextPos.hh',
+  'OT/Layout/GPOS/Common.hh',
+  'OT/Layout/GPOS/ContextPos.hh',
+  'OT/Layout/GPOS/CursivePosFormat1.hh',
+  'OT/Layout/GPOS/CursivePos.hh',
+  'OT/Layout/GPOS/ExtensionPos.hh',
+  'OT/Layout/GPOS/GPOS.hh',
+  'OT/Layout/GPOS/LigatureArray.hh',
+  'OT/Layout/GPOS/MarkArray.hh',
+  'OT/Layout/GPOS/MarkBasePosFormat1.hh',
+  'OT/Layout/GPOS/MarkBasePos.hh',
+  'OT/Layout/GPOS/MarkLigPosFormat1.hh',
+  'OT/Layout/GPOS/MarkLigPos.hh',
+  'OT/Layout/GPOS/MarkMarkPosFormat1.hh',
+  'OT/Layout/GPOS/MarkMarkPos.hh',
+  'OT/Layout/GPOS/MarkRecord.hh',
+  'OT/Layout/GPOS/PairPosFormat1.hh',
+  'OT/Layout/GPOS/PairPosFormat2.hh',
+  'OT/Layout/GPOS/PairPos.hh',
+  'OT/Layout/GPOS/PairSet.hh',
+  'OT/Layout/GPOS/PairValueRecord.hh',
+  'OT/Layout/GPOS/PosLookup.hh',
+  'OT/Layout/GPOS/PosLookupSubTable.hh',
+  'OT/Layout/GPOS/SinglePosFormat1.hh',
+  'OT/Layout/GPOS/SinglePosFormat2.hh',
+  'OT/Layout/GPOS/SinglePos.hh',
+  'OT/Layout/GPOS/ValueFormat.hh',
+  'OT/Layout/GSUB/AlternateSet.hh',
+  'OT/Layout/GSUB/AlternateSubstFormat1.hh',
+  'OT/Layout/GSUB/AlternateSubst.hh',
+  'OT/Layout/GSUB/ChainContextSubst.hh',
+  'OT/Layout/GSUB/Common.hh',
+  'OT/Layout/GSUB/ContextSubst.hh',
+  'OT/Layout/GSUB/ExtensionSubst.hh',
+  'OT/Layout/GSUB/GSUB.hh',
+  'OT/Layout/GSUB/Ligature.hh',
+  'OT/Layout/GSUB/LigatureSet.hh',
+  'OT/Layout/GSUB/LigatureSubstFormat1.hh',
+  'OT/Layout/GSUB/LigatureSubst.hh',
+  'OT/Layout/GSUB/MultipleSubstFormat1.hh',
+  'OT/Layout/GSUB/MultipleSubst.hh',
+  'OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh',
+  'OT/Layout/GSUB/ReverseChainSingleSubst.hh',
+  'OT/Layout/GSUB/Sequence.hh',
+  'OT/Layout/GSUB/SingleSubstFormat1.hh',
+  'OT/Layout/GSUB/SingleSubstFormat2.hh',
+  'OT/Layout/GSUB/SingleSubst.hh',
+  'OT/Layout/GSUB/SubstLookup.hh',
+  'OT/Layout/GSUB/SubstLookupSubTable.hh',
+  'OT/name/name.hh',
   'hb-ot-layout-gsubgpos.hh',
   'hb-ot-layout-jstf-table.hh',
   'hb-ot-layout.cc',
@@ -113,30 +194,29 @@ hb_base_sources = files(
   '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-joining-list.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-syllabic.cc',
-  'hb-ot-shape-complex-syllabic.hh',
-  'hb-ot-shape-complex-thai.cc',
-  'hb-ot-shape-complex-use-table.hh',
-  'hb-ot-shape-complex-use.cc',
-  'hb-ot-shape-complex-vowel-constraints.cc',
-  'hb-ot-shape-complex-vowel-constraints.hh',
-  'hb-ot-shape-complex.hh',
+  'hb-ot-shaper-arabic-fallback.hh',
+  'hb-ot-shaper-arabic-joining-list.hh',
+  'hb-ot-shaper-arabic-pua.hh',
+  'hb-ot-shaper-arabic-table.hh',
+  'hb-ot-shaper-arabic-win1256.hh',
+  'hb-ot-shaper-arabic.cc',
+  'hb-ot-shaper-arabic.hh',
+  'hb-ot-shaper-default.cc',
+  'hb-ot-shaper-hangul.cc',
+  'hb-ot-shaper-hebrew.cc',
+  'hb-ot-shaper-indic-table.cc',
+  'hb-ot-shaper-indic.cc',
+  'hb-ot-shaper-indic.hh',
+  'hb-ot-shaper-khmer.cc',
+  'hb-ot-shaper-myanmar.cc',
+  'hb-ot-shaper-syllabic.cc',
+  'hb-ot-shaper-syllabic.hh',
+  'hb-ot-shaper-thai.cc',
+  'hb-ot-shaper-use-table.hh',
+  'hb-ot-shaper-use.cc',
+  'hb-ot-shaper-vowel-constraints.cc',
+  'hb-ot-shaper-vowel-constraints.hh',
+  'hb-ot-shaper.hh',
   'hb-ot-shape-fallback.cc',
   'hb-ot-shape-fallback.hh',
   'hb-ot-shape-normalize.cc',
@@ -148,6 +228,7 @@ hb_base_sources = files(
   'hb-ot-tag.cc',
   'hb-ot-var-avar-table.hh',
   'hb-ot-var-common.hh',
+  'hb-ot-var-cvar-table.hh',
   'hb-ot-var-fvar-table.hh',
   'hb-ot-var-gvar-table.hh',
   'hb-ot-var-hvar-table.hh',
@@ -182,21 +263,23 @@ hb_base_sources = files(
 
 hb_base_ragel_generated_sources = files(
   'hb-buffer-deserialize-json.hh',
-  'hb-buffer-deserialize-text.hh',
+  'hb-buffer-deserialize-text-glyphs.hh',
+  'hb-buffer-deserialize-text-unicode.hh',
   'hb-number-parser.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-ot-shaper-indic-machine.hh',
+  'hb-ot-shaper-khmer-machine.hh',
+  'hb-ot-shaper-myanmar-machine.hh',
+  'hb-ot-shaper-use-machine.hh',
 )
 hb_base_ragel_sources = [
   'hb-buffer-deserialize-json.rl',
-  'hb-buffer-deserialize-text.rl',
+  'hb-buffer-deserialize-text-glyphs.rl',
+  'hb-buffer-deserialize-text-unicode.rl',
   'hb-number-parser.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',
+  'hb-ot-shaper-indic-machine.rl',
+  'hb-ot-shaper-khmer-machine.rl',
+  'hb-ot-shaper-myanmar-machine.rl',
+  'hb-ot-shaper-use-machine.rl',
 ]
 
 hb_base_headers = files(
@@ -205,8 +288,10 @@ hb_base_headers = files(
   'hb-blob.h',
   'hb-buffer.h',
   'hb-common.h',
+  'hb-cplusplus.hh',
   'hb-deprecated.h',
   'hb-draw.h',
+  'hb-paint.h',
   'hb-face.h',
   'hb-font.h',
   'hb-map.h',
@@ -232,7 +317,7 @@ hb_base_headers += hb_version_h
 
 # Optional Sources and Headers with external deps
 
-hb_ft_sources = files('hb-ft.cc')
+hb_ft_sources = files('hb-ft.cc', 'hb-ft-colr.hh')
 hb_ft_headers = files('hb-ft.h')
 
 hb_glib_sources = files('hb-glib.cc')
@@ -241,6 +326,19 @@ hb_glib_headers = files('hb-glib.h')
 hb_graphite2_sources = files('hb-graphite2.cc')
 hb_graphite2_headers = files('hb-graphite2.h')
 
+hb_wasm_sources = files(
+  'hb-wasm-api.cc',
+  'hb-wasm-api.hh',
+  'hb-wasm-api-blob.hh',
+  'hb-wasm-api-buffer.hh',
+  'hb-wasm-api-common.hh',
+  'hb-wasm-api-face.hh',
+  'hb-wasm-api-font.hh',
+  'hb-wasm-api-shape.hh',
+  'hb-wasm-shape.cc',
+)
+hb_wasm_headers = files()
+
 # System-dependent sources and headers
 
 hb_coretext_sources = files('hb-coretext.cc')
@@ -266,21 +364,35 @@ hb_subset_sources = files(
   'hb-ot-cff1-table.cc',
   'hb-ot-cff2-table.cc',
   'hb-static.cc',
+  'hb-subset-accelerator.hh',
   '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-input.cc',
   'hb-subset-input.hh',
+  'hb-subset-instancer-solver.hh',
+  'hb-subset-instancer-solver.cc',
   'hb-subset-plan.cc',
   'hb-subset-plan.hh',
+  'hb-subset-plan-member-list.hh',
+  'hb-subset-repacker.cc',
+  'graph/gsubgpos-context.cc',
+  'graph/gsubgpos-context.hh',
+  'graph/gsubgpos-graph.hh',
+  'graph/pairpos-graph.hh',
+  'graph/markbasepos-graph.hh',
+  'graph/coverage-graph.hh',
+  'graph/classdef-graph.hh',
+  'graph/split-helpers.hh',
   'hb-subset.cc',
   'hb-subset.hh',
 )
 
-hb_subset_headers = files('hb-subset.h')
+hb_subset_headers = files(
+  'hb-subset.h',
+  'hb-subset-repacker.h'
+)
 
 hb_gobject_sources = files(
   'hb-gobject-structs.cc'
@@ -298,7 +410,9 @@ if not has_ragel and get_option('ragel_subproject')
     has_ragel = true
 endif
 if not has_ragel
-  warning('You have to install ragel if you are going to develop HarfBuzz itself')
+  if not meson.is_subproject()
+    warning('You have to install ragel if you are going to develop HarfBuzz itself')
+  endif
 else
   ragel_helper = find_program('gen-ragel-artifacts.py')
   foreach rl : hb_base_ragel_sources
@@ -317,7 +431,7 @@ custom_target('harfbuzz.cc',
   output: 'harfbuzz.cc',
   input: hb_base_sources + hb_glib_sources + hb_ft_sources +
          hb_graphite2_sources + hb_uniscribe_sources + hb_gdi_sources +
-         hb_directwrite_sources + hb_coretext_sources,
+         hb_directwrite_sources + hb_coretext_sources + hb_wasm_sources,
   command: [find_program('gen-harfbuzzcc.py'),
             '@OUTPUT@', meson.current_source_dir(), '@INPUT@'],
 )
@@ -337,6 +451,17 @@ if conf.get('HAVE_FREETYPE', 0) == 1
   harfbuzz_deps += [freetype_dep]
 endif
 
+if conf.get('HAVE_GLIB', 0) == 1
+  hb_sources += hb_glib_sources
+  hb_headers += hb_glib_headers
+  harfbuzz_deps += [glib_dep]
+endif
+
+# We set those here to not include the sources below that are of no use to
+# GObject Introspection
+gir_sources = hb_sources + hb_gobject_sources
+gir_headers = hb_headers + hb_gobject_headers
+
 if conf.get('HAVE_GDI', 0) == 1
   hb_sources += hb_gdi_sources
   hb_headers += hb_gdi_headers
@@ -349,10 +474,11 @@ if conf.get('HAVE_GRAPHITE2', 0) == 1
   harfbuzz_deps += [graphite2_dep, graphite_dep]
 endif
 
-if conf.get('HAVE_GLIB', 0) == 1
-  hb_sources += hb_glib_sources
-  hb_headers += hb_glib_headers
-  harfbuzz_deps += [glib_dep]
+if conf.get('HAVE_WASM', 0) == 1
+  hb_sources += hb_wasm_sources
+  hb_headers += hb_wasm_headers
+  harfbuzz_deps += wasm_dep
+  #harfbuzz_deps += llvm_dep
 endif
 
 if conf.get('HAVE_UNISCRIBE', 0) == 1
@@ -363,7 +489,6 @@ endif
 if conf.get('HAVE_DIRECTWRITE', 0) == 1
   hb_sources += hb_directwrite_sources
   hb_headers += hb_directwrite_headers
-  harfbuzz_deps += directwrite_dep
   # hb-directwrite needs a C++ linker
   libharfbuzz_link_language = 'cpp'
 endif
@@ -376,23 +501,60 @@ endif
 
 have_icu = conf.get('HAVE_ICU', 0) == 1
 have_icu_builtin = conf.get('HAVE_ICU_BUILTIN', 0) == 1
-
 if have_icu and have_icu_builtin
   hb_sources += hb_icu_sources
   hb_headers += hb_icu_headers
   harfbuzz_deps += [icu_dep]
 endif
 
-# harfbuzz
-gen_def = find_program('gen-def.py')
+features = [
+  'CAIRO',
+  'CORETEXT',
+  'DIRECTWRITE',
+  'FREETYPE',
+  'GDI',
+  'GLIB',
+  'GOBJECT',
+  'GRAPHITE',
+  'ICU',
+  'UNISCRIBE',
+  'WASM',
+]
+
+hb_enabled_features = configuration_data()
+hb_supported_features = configuration_data()
+foreach feature : features
+  key = 'HB_HAS_@0@'.format(feature)
+  hb_enabled_features.set(key, conf.get('HAVE_@0@'.format(feature), false))
+  hb_supported_features.set(key, 1)
+endforeach
+
+# The enabled features. This file is installed.
+hb_features_h = configure_file(input: 'hb-features.h.in',
+                               output: 'hb-features.h',
+                               configuration: hb_enabled_features,
+                               install: true,
+                               install_dir: get_option('includedir') / meson.project_name())
+
+# This file is generated to convince gtk-doc to generate documentation for all
+# HB_HAS_* macros, whether they are enabled for the current build or not.
+# This file should not be installed.
+hb_supported_features_h = configure_file(input: 'hb-features.h.in',
+                               output: 'hb-supported-features.h',
+                               configuration: hb_supported_features,
+                               install: false)
 
-harfbuzz_def_command_args = [gen_def, '@OUTPUT@', '@INPUT@']
+# Base and default-included sources and headers
+
+gen_def = find_program('gen-def.py')
+gen_def_cmd = [gen_def, '@OUTPUT@', '@INPUT@']
 if get_option('experimental_api')
-  harfbuzz_def_command_args += '--experimental-api'
+  gen_def_cmd += '--experimental-api'
 endif
 
+# harfbuzz
 harfbuzz_def = custom_target('harfbuzz.def',
-    command: harfbuzz_def_command_args,
+    command: gen_def_cmd,
     input: hb_headers,
     output: 'harfbuzz.def')
 defs_list = [harfbuzz_def]
@@ -400,7 +562,7 @@ defs_list = [harfbuzz_def]
 version = '0.@0@.0'.format(hb_version_int)
 
 extra_hb_cpp_args = []
-if cpp.get_id() == 'msvc'
+if cpp.get_define('_MSC_FULL_VER') != ''
   if get_option('default_library') != 'static'
     extra_hb_cpp_args += '-DHB_DLL_EXPORT'
   endif
@@ -434,10 +596,11 @@ libharfbuzz_dep = declare_dependency(
   link_with: libharfbuzz,
   include_directories: incsrc,
   dependencies: harfbuzz_deps)
+meson.override_dependency('harfbuzz', libharfbuzz_dep)
 
 # harfbuzz-subset
 harfbuzz_subset_def = custom_target('harfbuzz-subset.def',
-    command: [gen_def, '@OUTPUT@', '@INPUT@'],
+    command: gen_def_cmd,
     input: hb_subset_headers,
     output: 'harfbuzz-subset.def')
 defs_list += [harfbuzz_subset_def]
@@ -454,29 +617,102 @@ libharfbuzz_subset = library('harfbuzz-subset', hb_subset_sources,
   link_language: 'c',
 )
 
+custom_target('harfbuzz-subset.cc',
+  build_by_default: true,
+  output: 'harfbuzz-subset.cc',
+  input: hb_base_sources + hb_subset_sources,
+  command: [find_program('gen-harfbuzzcc.py'),
+            '@OUTPUT@', meson.current_source_dir(), '@INPUT@'],
+)
+
 libharfbuzz_subset_dep = declare_dependency(
   link_with: libharfbuzz_subset,
   include_directories: incsrc,
   dependencies: [m_dep])
+meson.override_dependency('harfbuzz-subset', libharfbuzz_subset_dep)
+
+libharfbuzz_cairo_dep = null_dep
+if conf.get('HAVE_CAIRO', 0) == 1
+  hb_cairo_sources = [
+    'hb-cairo.cc',
+    'hb-cairo-utils.cc',
+    'hb-static.cc'
+  ]
+
+  hb_cairo_headers = [
+    'hb-cairo.h',
+  ]
+
+  cairo_dep = dependency('cairo')
+
+  libharfbuzz_cairo = library('harfbuzz-cairo', hb_cairo_sources,
+    include_directories: incconfig,
+    dependencies: [m_dep, cairo_dep],
+    link_with: [libharfbuzz],
+     cpp_args: cpp_args + extra_hb_cpp_args,
+    soversion: hb_so_version,
+    version: version,
+    install: true,
+    darwin_versions: darwin_versions,
+    link_language: 'c',
+  )
+
+  install_headers(hb_cairo_headers, subdir: meson.project_name())
+
+  libharfbuzz_cairo_dep = declare_dependency(
+    link_with: libharfbuzz_cairo,
+    include_directories: incsrc,
+    dependencies: [m_dep, cairo_dep])
+  meson.override_dependency('harfbuzz-cairo', libharfbuzz_cairo_dep)
+
+  harfbuzz_cairo_def = custom_target('harfbuzz-cairo.def',
+    command: gen_def_cmd,
+    input: hb_cairo_headers,
+    output: 'harfbuzz-cairo.def')
+  defs_list += [harfbuzz_cairo_def]
+
+  pkgmod.generate(libharfbuzz_cairo,
+    description: 'HarfBuzz cairo support',
+    requires: ['harfbuzz = @0@'.format(meson.project_version())],
+    subdirs: [meson.project_name()],
+    version: meson.project_version(),
+  )
+endif
 
 if get_option('tests').enabled()
   # TODO: MSVC gives the following,
   # error LNK2019: unresolved external symbol "unsigned __int64 const * const _hb_NullPool"
-  if cpp.get_id() != 'msvc'
+  if cpp.get_define('_MSC_FULL_VER') == ''
     noinst_programs = {
       'main': 'main.cc',
+      'test-algs': ['test-algs.cc', 'hb-static.cc'],
       'test-basics': 'test.cc',
+      'test-bimap': ['test-bimap.cc', 'hb-static.cc'],
       'test-buffer-serialize': 'test-buffer-serialize.cc',
+      'test-classdef-graph': ['graph/test-classdef-graph.cc', 'hb-static.cc', 'graph/gsubgpos-context.cc'],
+      'test-instancer-solver': ['test-subset-instancer-solver.cc', 'hb-subset-instancer-solver.cc', 'hb-static.cc'],
+      'test-iter': ['test-iter.cc', 'hb-static.cc'],
+      'test-map': ['test-map.cc', 'hb-static.cc'],
+      'test-multimap': ['test-multimap.cc', 'hb-static.cc'],
       'test-ot-meta': 'test-ot-meta.cc',
       'test-ot-name': 'test-ot-name.cc',
       'test-ot-glyphname': 'test-ot-glyphname.cc',
       'test-ot-gpos-size-params': 'test-gpos-size-params.cc',
+      'test-ot-gsub-get-alternates': 'test-gsub-get-alternates.cc',
       'test-ot-gsub-would-substitute': 'test-gsub-would-substitute.cc',
+      'test-priority-queue': ['test-priority-queue.cc', 'hb-static.cc'],
+      'test-repacker': ['test-repacker.cc', 'hb-static.cc', 'graph/gsubgpos-context.cc'],
+      'test-serialize': ['test-serialize.cc', 'hb-static.cc'],
+      'test-set': ['test-set.cc', 'hb-static.cc'],
+      'test-tuple-varstore': ['test-tuple-varstore.cc', 'hb-subset-instancer-solver.cc', 'hb-static.cc'],
+      'test-item-varstore': ['test-item-varstore.cc', 'hb-subset-instancer-solver.cc', 'hb-static.cc'],
+      'test-use-table': 'test-use-table.cc',
+      'test-vector': ['test-vector.cc', 'hb-static.cc'],
     }
     foreach name, source : noinst_programs
       executable(name, source,
         include_directories: incconfig,
-        cpp_args: cpp_args,
+        cpp_args: cpp_args + ['-UNDEBUG'],
         dependencies: libharfbuzz_dep,
         install: false,
       )
@@ -484,23 +720,14 @@ if get_option('tests').enabled()
   endif
 
   compiled_tests = {
-    'test-algs': ['test-algs.cc', 'hb-static.cc'],
     'test-array': ['test-array.cc'],
-    'test-iter': ['test-iter.cc', 'hb-static.cc'],
     'test-machinery': ['test-machinery.cc', 'hb-static.cc'],
-    'test-map': ['test-map.cc', 'hb-static.cc'],
     'test-number': ['test-number.cc', 'hb-number.cc'],
     'test-ot-tag': ['hb-ot-tag.cc'],
-    'test-priority-queue': ['test-priority-queue.cc', 'hb-static.cc'],
-    'test-repacker': ['test-repacker.cc', 'hb-static.cc'],
-    'test-set': ['test-set.cc', 'hb-static.cc'],
-    'test-serialize': ['test-serialize.cc', 'hb-static.cc'],
     'test-unicode-ranges': ['test-unicode-ranges.cc'],
-    'test-vector': ['test-vector.cc', 'hb-static.cc'],
-    'test-bimap': ['test-bimap.cc', 'hb-static.cc'],
   }
   foreach name, source : compiled_tests
-    if cpp.get_id() == 'msvc' and source.contains('hb-static.cc')
+    if cpp.get_argument_syntax() == 'msvc' and source.contains('hb-static.cc')
       # TODO: MSVC doesn't like tests having hb-static.cc, fix them
       continue
     endif
@@ -529,7 +756,7 @@ pkgmod.generate(libharfbuzz_subset,
 libharfbuzz_icu_dep = null_dep
 if have_icu and not have_icu_builtin
   harfbuzz_icu_def = custom_target('harfbuzz-icu.def',
-    command: [gen_def, '@OUTPUT@', '@INPUT@'],
+    command: gen_def_cmd,
     input: [hb_icu_headers],
     output: 'harfbuzz-icu.def')
   defs_list += [harfbuzz_icu_def]
@@ -551,6 +778,7 @@ if have_icu and not have_icu_builtin
     link_with: libharfbuzz_icu,
     include_directories: incsrc,
     dependencies: icu_dep)
+  meson.override_dependency('harfbuzz-icu', libharfbuzz_icu_dep)
 
   pkgmod.generate(libharfbuzz_icu,
     description: 'HarfBuzz text shaping library ICU integration',
@@ -564,17 +792,99 @@ endif
 
 have_gobject = conf.get('HAVE_GOBJECT', 0) == 1
 
+# This code (especially PACKAGE_INIT) kept similar to what CMake's own
+# configure_package_config_file() generates, see
+# https://cmake.org/cmake/help/latest/module/CMakePackageConfigHelpers.html#command:configure_package_config_file
+
 cmake_config = configuration_data()
-cmake_config.set('libdir', '${prefix}/@0@'.format(get_option('libdir')))
-cmake_config.set('includedir', '${prefix}/@0@'.format(get_option('includedir')))
-cmake_config.set('HB_LIBTOOL_VERSION_INFO', hb_libtool_version_info)
-cmake_config.set('have_gobject', '@0@'.format(have_gobject))
+cmake_config_dir = cmake_package_install_dir / 'harfbuzz'
+
+have_fs_relative_to = meson.version().version_compare('>=1.3.0')
+
+if not have_fs_relative_to
+  relative_to = find_program('relative_to.py')
+endif
+
+if have_fs_relative_to
+  cmake_package_prefix_dir = fs.relative_to(get_option('prefix'), get_option('prefix') / cmake_config_dir)
+else
+  cmake_package_prefix_dir = run_command(relative_to, get_option('prefix'), get_option('prefix') / cmake_config_dir, check: true).stdout().strip()
+endif
+
+cmake_package_prefix_dir = '${CMAKE_CURRENT_LIST_DIR}/@0@'.format(cmake_package_prefix_dir)
+
+# Make all the relevant paths relative to our prefix, so we can later append
+# them onto ${PACKAGE_PREFIX_DIR} to get the correct paths.
+
+cmake_install_includedir = get_option('includedir')
+
+if fs.is_absolute(cmake_install_includedir)
+  if have_fs_relative_to
+    cmake_install_includedir = fs.relative_to(cmake_install_includedir, get_option('prefix'))
+  else
+    cmake_install_includedir = run_command(relative_to, cmake_install_includedir, get_option('prefix'), check: true).stdout().strip()
+  endif
+endif
+
+cmake_install_libdir = get_option('libdir')
+
+if fs.is_absolute(cmake_install_libdir)
+  if have_fs_relative_to
+    cmake_install_libdir = fs.relative_to(cmake_install_libdir, get_option('prefix'))
+  else
+    cmake_install_libdir = run_command(relative_to, cmake_install_libdir, get_option('prefix'), check: true).stdout().strip()
+  endif
+endif
+
+cmake_config.set('PACKAGE_INIT', '''
+get_filename_component(PACKAGE_PREFIX_DIR "@0@" ABSOLUTE)
+
+macro(set_and_check _var _file)
+  set(${_var} "${_file}")
+  if(NOT EXISTS "${_file}")
+    message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
+  endif()
+endmacro()
+
+macro(check_required_components _NAME)
+  foreach(comp ${${_NAME}_FIND_COMPONENTS})
+    if(NOT ${_NAME}_${comp}_FOUND)
+      if(${_NAME}_FIND_REQUIRED_${comp})
+        set(${_NAME}_FOUND FALSE)
+      endif()
+    endif()
+  endforeach()
+endmacro()
+'''.format(cmake_package_prefix_dir))
+
+cmake_config.set('PACKAGE_CMAKE_INSTALL_INCLUDEDIR', '${PACKAGE_PREFIX_DIR}/@0@'.format(cmake_install_includedir))
+cmake_config.set('PACKAGE_CMAKE_INSTALL_LIBDIR', '${PACKAGE_PREFIX_DIR}/@0@'.format(cmake_install_libdir))
+cmake_config.set('PACKAGE_INCLUDE_INSTALL_DIR', '${PACKAGE_PREFIX_DIR}/@0@/@1@'.format(cmake_install_includedir, meson.project_name()))
+cmake_config.set('HB_HAVE_GOBJECT', have_gobject ? 'YES' : 'NO')
+cmake_config.set('HB_LIBRARY_TYPE', get_option('default_library') == 'static' ? 'STATIC' : 'SHARED')
+
+if get_option('default_library') == 'static'
+  cmake_config.set('HB_LIB_PREFIX', '${CMAKE_STATIC_LIBRARY_PREFIX}')
+  cmake_config.set('HB_LIB_SUFFIX', '${CMAKE_STATIC_LIBRARY_SUFFIX}')
+elif host_machine.system() == 'darwin'
+  cmake_config.set('HB_LIB_PREFIX', '${CMAKE_SHARED_LIBRARY_PREFIX}')
+  cmake_config.set('HB_LIB_SUFFIX', '.@0@.${CMAKE_SHARED_LIBRARY_SUFFIX}'.format(hb_so_version))
+elif host_machine.system() == 'windows'
+  cmake_config.set('HB_LIB_PREFIX', '${CMAKE_IMPORT_LIBRARY_PREFIX}')
+  cmake_config.set('HB_LIB_SUFFIX', '${CMAKE_IMPORT_LIBRARY_SUFFIX}')
+else
+  cmake_config.set('HB_LIB_PREFIX', '${CMAKE_SHARED_LIBRARY_PREFIX}')
+  cmake_config.set('HB_LIB_SUFFIX', '${CMAKE_SHARED_LIBRARY_SUFFIX}.@0@'.format(version))
+endif
+
 configure_file(input: 'harfbuzz-config.cmake.in',
   output: 'harfbuzz-config.cmake',
   configuration: cmake_config,
-  install_dir: get_option('libdir') / 'cmake' / 'harfbuzz',
+  install_dir: cmake_config_dir,
 )
 
+gobject_enums_c = []
+gobject_enums_h = []
 libharfbuzz_gobject_dep = null_dep
 if have_gobject
   gnome = import('gnome')
@@ -597,13 +907,13 @@ if have_gobject
     symbol_prefix: 'hb_gobject',
   )
 
-  enum_c = custom_target('hb-gobject-enums.cc',
+  gobject_enums_c = custom_target('hb-gobject-enums.cc',
     input: enums[0],
     output: 'hb-gobject-enums.cc',
     command: [find_program('fix_get_types.py'), '@INPUT@', '@OUTPUT@']
   )
 
-  enum_h = custom_target('hb-gobject-enums.h',
+  gobject_enums_h = custom_target('hb-gobject-enums.h',
     input: enums[1],
     output: 'hb-gobject-enums.h',
     command: [find_program('fix_get_types.py'), '@INPUT@', '@OUTPUT@'],
@@ -611,15 +921,15 @@ if have_gobject
     install_dir: get_option('prefix') / get_option('includedir') / meson.project_name(),
   )
 
-  hb_gobject_sources += [enum_c]
+  hb_gobject_sources += [gobject_enums_c]
 
   harfbuzz_gobject_def = custom_target('harfbuzz-gobject.def',
-    command: [gen_def, '@OUTPUT@', '@INPUT@'],
-    input: [hb_gobject_headers, enum_h],
+    command: gen_def_cmd,
+    input: [hb_gobject_headers, gobject_enums_h],
     output: 'harfbuzz-gobject.def')
   defs_list += [harfbuzz_gobject_def]
 
-  libharfbuzz_gobject = library('harfbuzz-gobject', [hb_gobject_sources, enum_c, enum_h],
+  libharfbuzz_gobject = library('harfbuzz-gobject', [hb_gobject_sources, gobject_enums_c, gobject_enums_h],
     include_directories: incconfig,
     dependencies: [glib_dep, gobject_dep],
     link_with: [libharfbuzz],
@@ -641,15 +951,15 @@ if have_gobject
 
   if build_gir
     conf.set('HAVE_INTROSPECTION', 1)
-    hb_gen_files_gir = gnome.generate_gir(libharfbuzz_gobject,
-      sources: [hb_headers, hb_sources, hb_gobject_headers, hb_gobject_sources, enum_h],
+    hb_gen_files_gir = gnome.generate_gir([libharfbuzz_gobject, libharfbuzz],
+      sources: [gir_headers, gir_sources, gobject_enums_h],
       dependencies: libharfbuzz_dep,
       namespace: 'HarfBuzz',
       nsversion: '0.0',
       identifier_prefix: 'hb_',
       symbol_prefix: ['hb', 'hb_gobject'],
-      includes: ['GObject-2.0'],
-      export_packages: ['harfbuzz-gobject'],
+      includes: ['GObject-2.0', 'freetype2-2.0'],
+      export_packages: ['harfbuzz-gobject', 'harfbuzz'],
       header: 'hb-gobject.h',
       install: true,
       extra_args:  ['--cflags-begin',
@@ -664,6 +974,7 @@ if have_gobject
     include_directories: incsrc,
     sources: build_gir ? hb_gen_files_gir : hb_gobject_sources,
     dependencies: [glib_dep, gobject_dep])
+  meson.override_dependency('harfbuzz-gobject', libharfbuzz_gobject_dep)
 
   pkgmod.generate(libharfbuzz_gobject,
     description: 'HarfBuzz text shaping library GObject integration',
@@ -689,6 +1000,7 @@ if get_option('tests').enabled()
 
   env = environment()
   env.set('srcdir', meson.current_source_dir())
+  env.set('base_srcdir', meson.source_root())
   env.set('builddir', meson.current_build_dir())
   env.set('libs', meson.current_build_dir()) # TODO: Merge this with builddir after autotools removal
   HBSOURCES = []
@@ -702,8 +1014,11 @@ if get_option('tests').enabled()
   endforeach
   env.set('HBHEADERS', ' '.join(HBHEADERS))
 
-  if cpp.get_id() != 'msvc' and not meson.is_cross_build() # ensure the local tools are usable
-    dist_check_script += ['check-libstdc++', 'check-static-inits', 'check-symbols']
+  if cpp.get_argument_syntax() != 'msvc' and not meson.is_cross_build() # ensure the local tools are usable
+    dist_check_script += ['check-static-inits', 'check-symbols']
+    if get_option('wasm').disabled()
+      dist_check_script += ['check-libstdc++']
+    endif
   endif
 
   foreach name : dist_check_script
diff --git a/src/relative_to.py b/src/relative_to.py
new file mode 100755 (executable)
index 0000000..8a676bf
--- /dev/null
@@ -0,0 +1,6 @@
+#!/usr/bin/python3
+
+import sys
+from os import path
+
+print(path.relpath(sys.argv[1], sys.argv[2]))
index f8b8ff6..450a7c4 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "hb.hh"
 #include "hb-algs.hh"
+#include "hb-set.hh"
 
 
 static char *
@@ -91,5 +92,19 @@ main (int argc, char **argv)
   assert (++hb_inc (x) == 3);
   assert (x == 3);
 
+  hb_set_t set1 {1};
+  hb_set_t set2 {2};
+
+  assert (hb_hash (set1) != hb_hash (set2));
+  assert (hb_hash (set1) == hb_hash (hb_set_t {1}));
+  assert (hb_hash (set1) != hb_hash (hb_set_t {}));
+  assert (hb_hash (set1) != hb_hash (hb_set_t {2}));
+  assert (hb_hash (set2) == hb_hash (hb_set_t {2}));
+
+  /* hb_hash, unlike std::hash, dereferences pointers. */
+  assert (hb_hash (set1) == hb_hash (&set1));
+  assert (hb_hash (set1) == hb_hash (hb::shared_ptr<hb_set_t> {hb_set_reference (&set1)}));
+  assert (hb_hash (set1) == hb_hash (hb::unique_ptr<hb_set_t> {hb_set_reference (&set1)}));
+
   return 0;
 }
index 6c88813..28cd023 100644 (file)
@@ -70,6 +70,9 @@ test_reverse_invalid ()
 int
 main (int argc, char **argv)
 {
+  /* The following fails on MSVC. */
+  // assert (sizeof (hb_array_t<int>) == sizeof (hb_sorted_array_t<int>));
+
   test_reverse ();
   test_reverse_range ();
   test_reverse_invalid ();
index 8d5a694..aced1c8 100644 (file)
@@ -43,10 +43,8 @@ main (int argc, char **argv)
 
 #ifndef HB_NO_BUFFER_SERIALIZE
 
-  if (argc != 2) {
-    fprintf (stderr, "usage: %s font-file\n", argv[0]);
-    exit (1);
-  }
+  if (argc < 2)
+    argv[1] = (char *) "/dev/null";
 
   hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
   assert (blob);
@@ -58,10 +56,6 @@ main (int argc, char **argv)
   hb_font_t *font = hb_font_create (face);
   hb_face_destroy (face);
   hb_font_set_scale (font, upem, upem);
-  hb_ot_font_set_funcs (font);
-#ifdef HAVE_FREETYPE
-  //hb_ft_font_set_funcs (font);
-#endif
 
   hb_buffer_t *buf;
   buf = hb_buffer_create ();
@@ -71,20 +65,43 @@ main (int argc, char **argv)
   {
     hb_buffer_clear_contents (buf);
 
-    const char *p = line;
-    while (hb_buffer_deserialize_glyphs (buf,
+    while (true)
+    {
+      const char *p = line;
+      if (!hb_buffer_deserialize_glyphs (buf,
                                         p, -1, &p,
                                         font,
-                                        HB_BUFFER_SERIALIZE_FORMAT_JSON))
-      ;
-    if (*p && *p != '\n')
-      ret = false;
-
-    hb_buffer_serialize_glyphs (buf, 0, hb_buffer_get_length (buf),
-                               out, sizeof (out), nullptr,
-                               font, HB_BUFFER_SERIALIZE_FORMAT_JSON,
-                               HB_BUFFER_SERIALIZE_FLAG_DEFAULT);
-    puts (out);
+                                        HB_BUFFER_SERIALIZE_FORMAT_TEXT))
+      {
+        ret = false;
+        break;
+      }
+
+      if (*p == '\n')
+        break;
+      if (p == line)
+      {
+       ret = false;
+       break;
+      }
+
+      unsigned len = strlen (p);
+      memmove (line, p, len);
+      if (!fgets (line + len, sizeof(line) - len, stdin))
+        line[len] = '\0';
+    }
+
+    unsigned count = hb_buffer_get_length (buf);
+    for (unsigned offset = 0; offset < count;)
+    {
+      unsigned len;
+      offset += hb_buffer_serialize_glyphs (buf, offset, count,
+                                           out, sizeof (out), &len,
+                                           font, HB_BUFFER_SERIALIZE_FORMAT_TEXT,
+                                           HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS);
+      fwrite (out, 1, len, stdout);
+    }
+    fputs ("\n", stdout);
   }
 
   hb_buffer_destroy (buf);
diff --git a/src/test-gsub-get-alternates.cc b/src/test-gsub-get-alternates.cc
new file mode 100644 (file)
index 0000000..555440c
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright © 2010,2011  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.h>
+#include <hb-ot.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+  if (argc != 3) {
+    fprintf (stderr, "usage: %s font-file text\n", argv[0]);
+    exit (1);
+  }
+
+  /* Create the face */
+  hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
+  hb_face_t *face = hb_face_create (blob, 0 /* first face */);
+  hb_blob_destroy (blob);
+  blob = nullptr;
+
+  hb_font_t *font = hb_font_create (face);
+  hb_buffer_t *buffer = hb_buffer_create ();
+
+  hb_buffer_add_utf8 (buffer, argv[2], -1, 0, -1);
+  hb_buffer_guess_segment_properties (buffer);
+  hb_shape (font, buffer, NULL, 0);
+
+  hb_tag_t features[] = {HB_TAG('a','a','l','t'), HB_TAG_NONE};
+  hb_set_t *lookup_indexes = hb_set_create ();
+  hb_ot_layout_collect_lookups (face,
+                               HB_OT_TAG_GSUB,
+                               NULL, NULL,
+                               features,
+                               lookup_indexes);
+  printf ("lookups %u\n", hb_set_get_population (lookup_indexes));
+
+  unsigned count;
+  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &count);
+  for (unsigned i = 0; i < count; i++)
+  {
+    unsigned alt_count = 0;
+    for (hb_codepoint_t lookup_index = HB_SET_VALUE_INVALID;
+        hb_set_next (lookup_indexes, &lookup_index);)
+      if ((alt_count = hb_ot_layout_lookup_get_glyph_alternates (face,
+                                                                lookup_index,
+                                                                info[i].codepoint,
+                                                                0,
+                                                                NULL,
+                                                                NULL)))
+        break;
+    printf ("glyph %u alt count %u\n", info[i].codepoint, alt_count);
+  }
+
+  hb_set_destroy (lookup_indexes);
+  hb_buffer_destroy (buffer);
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+
+  return 0;
+}
diff --git a/src/test-item-varstore.cc b/src/test-item-varstore.cc
new file mode 100644 (file)
index 0000000..3e0875e
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2020  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.
+ *
+ */
+#include "hb-ot-var-common.hh"
+#include "hb-ot-var-hvar-table.hh"
+// HVAR table data from SourceSerif4Variable-Roman_subset.otf
+const char hvar_data[] = "\x0\x1\x0\x0\x0\x0\x0\x14\x0\x0\x0\xc4\x0\x0\x0\x0\x0\x0\x0\x0\x0\x1\x0\x0\x0\x10\x0\x2\x0\x0\x0\x74\x0\x0\x0\x7a\x0\x2\x0\x8\xc0\x0\xc0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x40\x0\x40\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\xc0\x0\xc0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x40\x0\x40\x0\xc0\x0\xc0\x0\x0\x0\xc0\x0\xc0\x0\x0\x0\xc0\x0\xc0\x0\x0\x0\x0\x0\x40\x0\x40\x0\x0\x0\x40\x0\x40\x0\xc0\x0\xc0\x0\x0\x0\x0\x0\x40\x0\x40\x0\x0\x0\x40\x0\x40\x0\x0\x1\x0\x0\x0\x0\x0\x4\x0\x0\x0\x8\x0\x0\x0\x1\x0\x2\x0\x3\x0\x4\x0\x5\x0\x6\x0\x7\xf9\xf\x2f\xbf\xfb\xfb\x35\xf9\x4\x4\xf3\xb4\xf2\xfb\x2e\xf3\x4\x4\xe\xad\xfa\x1\x1a\x1\x15\x22\x59\xd6\xe3\xf6\x6\xf5\x0\x1\x0\x5\x0\x4\x7\x5\x6";
+
+static void
+test_item_variations ()
+{
+  const OT::HVAR* hvar_table = reinterpret_cast<const OT::HVAR*> (hvar_data);
+
+  hb_tag_t axis_tag = HB_TAG ('w', 'g', 'h', 't');
+  hb_map_t axis_idx_tag_map;
+  axis_idx_tag_map.set (0, axis_tag);
+
+  axis_tag = HB_TAG ('o', 'p', 's', 'z');
+  axis_idx_tag_map.set (1, axis_tag);
+
+  OT::item_variations_t item_vars;
+  const OT::VariationStore& src_var_store = hvar_table+(hvar_table->varStore);
+  bool result = item_vars.create_from_item_varstore (src_var_store, axis_idx_tag_map);
+      
+  assert (result);
+
+  /* partial instancing wght=300:800 */
+  hb_hashmap_t<hb_tag_t, Triple> normalized_axes_location;
+  normalized_axes_location.set (axis_tag, Triple (-0.512817f, 0.f, 0.700012f));
+
+  hb_hashmap_t<hb_tag_t, TripleDistances> axes_triple_distances;
+  axes_triple_distances.set (axis_tag, TripleDistances (200.f, 500.f));
+
+  result = item_vars.instantiate_tuple_vars (normalized_axes_location, axes_triple_distances);
+  assert (result);
+  result = item_vars.as_item_varstore (false);
+  assert (result);
+  assert (item_vars.get_region_list().length == 8);
+}
+
+int
+main (int argc, char **argv)
+{
+  test_item_variations ();
+}
index dc85b72..bb966d4 100644 (file)
@@ -31,7 +31,6 @@
 #include "hb-set.hh"
 #include "hb-ot-layout-common.hh"
 
-
 template <typename T>
 struct array_iter_t : hb_iter_with_fallback_t<array_iter_t<T>, T&>
 {
@@ -226,7 +225,7 @@ main (int argc, char **argv)
   test_iterable<hb_sorted_array_t<const int>> ();
   test_iterable<hb_vector_t<float>> ();
   test_iterable<hb_set_t> ();
-  test_iterable<OT::Coverage> ();
+  test_iterable<OT::Array16Of<OT::HBUINT16>> ();
 
   test_iterator (hb_zip (st, v));
   test_iterator_non_default_constructable (hb_enumerate (st));
@@ -320,13 +319,36 @@ main (int argc, char **argv)
   ;
   /* The result should be something like 0->10, 1->11, ..., 9->19 */
   assert (hb_map_get (result, 9) == 19);
+  hb_map_destroy (result);
+
+  /* Like above, but passing hb_set_t instead of hb_set_t * */
+  temp1 = 10;
+  temp2 = 0;
+  result =
+  + hb_iter (src)
+  | hb_map ([&] (int i) -> hb_set_t
+           {
+             hb_set_t set;
+             for (unsigned int i = 0; i < temp1; ++i)
+               hb_set_add (&set, i);
+             temp1++;
+             return set;
+           })
+  | hb_reduce ([&] (hb_map_t *acc, hb_set_t value) -> hb_map_t *
+              {
+                hb_map_set (acc, temp2++, hb_set_get_population (&value));
+                return acc;
+              }, hb_map_create ())
+  ;
+  /* The result should be something like 0->10, 1->11, ..., 9->19 */
+  assert (hb_map_get (result, 9) == 19);
+  hb_map_destroy (result);
 
   unsigned int temp3 = 0;
   + hb_iter(src)
   | hb_map([&] (int i) { return ++temp3; })
   | hb_reduce([&] (float acc, int value) { return acc + value; }, 0)
   ;
-  hb_map_destroy (result);
 
   + hb_iter (src)
   | hb_drain
index fd2b2f0..cb722eb 100644 (file)
  * 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.hh"
 #include "hb-map.hh"
+#include "hb-set.hh"
 #include <string>
 
-static const std::string invalid{"invalid"};
-
 int
 main (int argc, char **argv)
 {
@@ -57,13 +55,21 @@ main (int argc, char **argv)
 
   /* Test move constructor. */
   {
-    hb_map_t v {hb_map_t {}};
+    hb_map_t s {};
+    s.set (1, 2);
+    hb_map_t v (std::move (s));
+    assert (s.get_population () == 0);
+    assert (v.get_population () == 1);
   }
 
   /* Test move assignment. */
   {
+    hb_map_t s {};
+    s.set (1, 2);
     hb_map_t v;
-    v = hb_map_t {};
+    v = std::move (s);
+    assert (s.get_population () == 0);
+    assert (v.get_population () == 1);
   }
 
   /* Test initializing from iterable. */
@@ -73,9 +79,15 @@ main (int argc, char **argv)
     s.set (1, 2);
     s.set (3, 4);
 
-    hb_map_t v (s);
+    hb_vector_t<hb_codepoint_pair_t> v (s);
+    hb_map_t v0 (v);
+    hb_map_t v1 (s);
+    hb_map_t v2 (std::move (s));
 
-    assert (v.get_population () == 2);
+    assert (s.get_population () == 0);
+    assert (v0.get_population () == 2);
+    assert (v1.get_population () == 2);
+    assert (v2.get_population () == 2);
   }
 
   /* Test call fini() twice. */
@@ -100,7 +112,7 @@ main (int argc, char **argv)
 
   /* Test initializing from initializer list and swapping. */
   {
-    using pair_t = hb_pair_t<hb_codepoint_t, hb_codepoint_t>;
+    using pair_t = hb_codepoint_pair_t;
     hb_map_t v1 {pair_t{1,2}, pair_t{4,5}};
     hb_map_t v2 {pair_t{3,4}};
     hb_swap (v1, v2);
@@ -110,19 +122,19 @@ main (int argc, char **argv)
 
   /* Test class key / value types. */
   {
-    hb_hashmap_t<hb_bytes_t, int, std::nullptr_t, int, nullptr, 0> m1;
-    hb_hashmap_t<int, hb_bytes_t, int, std::nullptr_t, 0, nullptr> m2;
-    hb_hashmap_t<hb_bytes_t, hb_bytes_t, std::nullptr_t, std::nullptr_t, nullptr, nullptr> m3;
+    hb_hashmap_t<hb_bytes_t, int> m1;
+    hb_hashmap_t<int, hb_bytes_t> m2;
+    hb_hashmap_t<hb_bytes_t, hb_bytes_t> m3;
     assert (m1.get_population () == 0);
     assert (m2.get_population () == 0);
     assert (m3.get_population () == 0);
   }
 
   {
-    hb_hashmap_t<int, int, int, int, 0, 0> m0;
-    hb_hashmap_t<std::string, int, const std::string*, int, &invalid, 0> m1;
-    hb_hashmap_t<int, std::string, int, const std::string*, 0, &invalid> m2;
-    hb_hashmap_t<std::string, std::string, const std::string*, const std::string*, &invalid, &invalid> m3;
+    hb_hashmap_t<int, int> m0;
+    hb_hashmap_t<std::string, int> m1;
+    hb_hashmap_t<int, std::string> m2;
+    hb_hashmap_t<std::string, std::string> m3;
 
     std::string s;
     for (unsigned i = 1; i < 1000; i++)
@@ -135,5 +147,212 @@ main (int argc, char **argv)
     }
   }
 
+  /* Test hashing maps. */
+  {
+    using pair = hb_codepoint_pair_t;
+
+    hb_hashmap_t<hb_map_t, hb_map_t> m1;
+
+    m1.set (hb_map_t (), hb_map_t {});
+    m1.set (hb_map_t (), hb_map_t {pair (1u, 2u)});
+    m1.set (hb_map_t {pair (1u, 2u)}, hb_map_t {pair (2u, 3u)});
+
+    assert (m1.get (hb_map_t ()) == hb_map_t {pair (1u, 2u)});
+    assert (m1.get (hb_map_t {pair (1u, 2u)}) == hb_map_t {pair (2u, 3u)});
+  }
+
+  /* Test hashing sets. */
+  {
+    hb_hashmap_t<hb_set_t, hb_set_t> m1;
+
+    m1.set (hb_set_t (), hb_set_t ());
+    m1.set (hb_set_t (), hb_set_t {1});
+    m1.set (hb_set_t {1, 1000}, hb_set_t {2});
+
+    assert (m1.get (hb_set_t ()) == hb_set_t {1});
+    assert (m1.get (hb_set_t {1000, 1}) == hb_set_t {2});
+  }
+
+  /* Test hashing vectors. */
+  {
+    using vector_t = hb_vector_t<unsigned>;
+
+    hb_hashmap_t<vector_t, vector_t> m1;
+
+    m1.set (vector_t (), vector_t {1});
+    m1.set (vector_t {1}, vector_t {2});
+
+    m1 << hb_pair_t<vector_t, vector_t> {vector_t {2}, vector_t ()};
+
+    assert (m1.get (vector_t ()) == vector_t {1});
+    assert (m1.get (vector_t {1}) == vector_t {2});
+  }
+
+  /* Test moving values */
+  {
+    using vector_t = hb_vector_t<unsigned>;
+
+    hb_hashmap_t<vector_t, vector_t> m1;
+    vector_t v {3};
+    assert (v.length == 1);
+    m1 << hb_pair_t<vector_t, vector_t> {vector_t {3}, v};
+    assert (v.length == 1);
+    m1 << hb_pair_t<vector_t, vector_t&&> {vector_t {4}, std::move (v)};
+    assert (v.length == 0);
+    m1 << hb_pair_t<vector_t&&, vector_t> {vector_t {4}, vector_t {5}};
+    m1 << hb_pair_t<vector_t&&, vector_t&&> {vector_t {4}, vector_t {5}};
+
+    hb_hashmap_t<vector_t, vector_t> m2;
+    vector_t v2 {3};
+    m2.set (vector_t {4}, v2);
+    assert (v2.length == 1);
+    m2.set (vector_t {5}, std::move (v2));
+    assert (v2.length == 0);
+  }
+
+  /* Test hb::shared_ptr. */
+  {
+    hb_hashmap_t<hb::shared_ptr<hb_set_t>, hb::shared_ptr<hb_set_t>> m;
+
+    m.set (hb::shared_ptr<hb_set_t> (hb_set_get_empty ()),
+          hb::shared_ptr<hb_set_t> (hb_set_get_empty ()));
+    m.get (hb::shared_ptr<hb_set_t> (hb_set_get_empty ()));
+    m.iter ();
+    m.keys ();
+    m.values ();
+    m.iter_ref ();
+    m.keys_ref ();
+    m.values_ref ();
+  }
+  /* Test hb::unique_ptr. */
+  {
+    hb_hashmap_t<hb::unique_ptr<hb_set_t>, hb::unique_ptr<hb_set_t>> m;
+
+    m.set (hb::unique_ptr<hb_set_t> (hb_set_get_empty ()),
+           hb::unique_ptr<hb_set_t> (hb_set_get_empty ()));
+    m.get (hb::unique_ptr<hb_set_t> (hb_set_get_empty ()));
+    hb::unique_ptr<hb_set_t> *v;
+    m.has (hb::unique_ptr<hb_set_t> (hb_set_get_empty ()), &v);
+    m.iter_ref ();
+    m.keys_ref ();
+    m.values_ref ();
+  }
+  /* Test hashmap with complex shared_ptrs as keys. */
+  {
+    hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> m;
+
+    hb_map_t *m1 = hb_map_create ();
+    hb_map_t *m2 = hb_map_create ();
+    m1->set (1,3);
+    m2->set (1,3);
+
+    hb::shared_ptr<hb_map_t> p1 {m1};
+    hb::shared_ptr<hb_map_t> p2 {m2};
+    m.set (p1,1);
+
+    assert (m.has (p2));
+
+    m1->set (2,4);
+    assert (!m.has (p2));
+  }
+  /* Test value type with hb_bytes_t. */
+  {
+    hb_hashmap_t<int, hb_bytes_t> m;
+    char c_str[] = "Test";
+    hb_bytes_t bytes (c_str);
+
+    m.set (1, bytes);
+    assert (m.has (1));
+    assert (m.get (1) == hb_bytes_t {"Test"});
+  }
+  /* Test operators. */
+  {
+    hb_map_t m1, m2, m3;
+    m1.set (1, 2);
+    m1.set (2, 4);
+    m2.set (1, 2);
+    m2.set (2, 4);
+    m3.set (1, 3);
+    m3.set (3, 5);
+
+    assert (m1 == m2);
+    assert (m1 != m3);
+    assert (!(m2 == m3));
+
+    m2 = m3;
+    assert (m2.has (1));
+    assert (!m2.has (2));
+    assert (m2.has (3));
+
+    assert (m3.has (3));
+  }
+  /* Test reset. */
+  {
+    hb_hashmap_t<int, hb_set_t> m;
+    m.set (1, hb_set_t {1, 2, 3});
+    m.reset ();
+  }
+  /* Test iteration. */
+  {
+    hb_map_t m;
+    m.set (1, 1);
+    m.set (4, 3);
+    m.set (5, 5);
+    m.set (2, 1);
+    m.set (3, 2);
+    m.set (6, 8);
+
+    hb_codepoint_t k;
+    hb_codepoint_t v;
+    unsigned pop = 0;
+    for (signed i = -1;
+        m.next (&i, &k, &v);)
+    {
+      pop++;
+           if (k == 1) assert (v == 1);
+      else if (k == 2) assert (v == 1);
+      else if (k == 3) assert (v == 2);
+      else if (k == 4) assert (v == 3);
+      else if (k == 5) assert (v == 5);
+      else if (k == 6) assert (v == 8);
+      else assert (false);
+    }
+    assert (pop == m.get_population ());
+  }
+  /* Test update */
+  {
+    hb_map_t m1, m2;
+    m1.set (1, 2);
+    m1.set (2, 4);
+    m2.set (1, 3);
+
+    m1.update (m2);
+    assert (m1.get_population () == 2);
+    assert (m1[1] == 3);
+    assert (m1[2] == 4);
+  }
+  /* Test keys / values */
+  {
+    hb_map_t m;
+    m.set (1, 1);
+    m.set (4, 3);
+    m.set (5, 5);
+    m.set (2, 1);
+    m.set (3, 2);
+    m.set (6, 8);
+
+    hb_set_t keys;
+    hb_set_t values;
+
+    hb_copy (m.keys (), keys);
+    hb_copy (m.values (), values);
+
+    assert (keys.is_equal (hb_set_t ({1, 2, 3, 4, 5, 6})));
+    assert (values.is_equal (hb_set_t ({1, 1, 2, 3, 5, 8})));
+
+    assert (keys.is_equal (hb_set_t (m.keys ())));
+    assert (values.is_equal (hb_set_t (m.values ())));
+  }
+
   return 0;
 }
diff --git a/src/test-multimap.cc b/src/test-multimap.cc
new file mode 100644 (file)
index 0000000..8cd8f52
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright © 2022  Behdad Esfahbod
+ *
+ *  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.hh"
+#include "hb-multimap.hh"
+
+int
+main (int argc, char **argv)
+{
+  hb_multimap_t m;
+
+  assert (m.get (10).length == 0);
+
+  m.add (10, 11);
+  assert (m.get (10).length == 1);
+
+  m.add (10, 12);
+  assert (m.get (10).length == 2);
+
+  m.add (10, 13);
+  assert (m.get (10).length == 3);
+  assert (m.get (10)[0] == 11);
+  assert (m.get (10)[1] == 12);
+  assert (m.get (10)[2] == 13);
+
+  assert (m.get (11).length == 0);
+  m.add (11, 14);
+  assert (m.get (10).length == 3);
+  assert (m.get (11).length == 1);
+  assert (m.get (12).length == 0);
+  assert (m.get (10)[0] == 11);
+  assert (m.get (10)[1] == 12);
+  assert (m.get (10)[2] == 13);
+  assert (m.get (11)[0] == 14);
+  assert (m.get (12)[0] == 0); // Array fallback value
+
+  return 0;
+}
index 50d0231..ec6e149 100644 (file)
@@ -85,5 +85,5 @@ main (int argc, char **argv)
   hb_font_destroy (font);
   hb_face_destroy (face);
 
-  return result;
+  return !result;
 }
index 7cf69db..6daacc4 100644 (file)
@@ -54,9 +54,9 @@ main (int argc, char **argv)
   for (unsigned i = 0; i < count; ++i)
   {
     hb_blob_t *entry = hb_ot_meta_reference_entry (face, tags[i]);
-    printf ("%c%c%c%c, size: %d: %.*s\n",
+    printf ("%c%c%c%c, size: %u: %.*s\n",
            HB_UNTAG (tags[i]), hb_blob_get_length (entry),
-           hb_blob_get_length (entry), hb_blob_get_data (entry, nullptr));
+           (int) hb_blob_get_length (entry), hb_blob_get_data (entry, nullptr));
     hb_blob_destroy (entry);
   }
   free (tags);
index fab63ac..67ee5ee 100644 (file)
@@ -30,7 +30,7 @@
 static void
 test_insert ()
 {
-  hb_priority_queue_t queue;
+  hb_priority_queue_t<int64_t> queue;
   assert (queue.is_empty ());
 
   queue.insert (10, 0);
@@ -53,7 +53,7 @@ test_insert ()
 static void
 test_extract ()
 {
-  hb_priority_queue_t queue;
+  hb_priority_queue_t<int32_t> queue;
   queue.insert (0, 0);
   queue.insert (60, 6);
   queue.insert (30, 3);
@@ -73,17 +73,9 @@ test_extract ()
   assert (queue.is_empty ());
 }
 
-static void
-test_extract_empty ()
-{
-  hb_priority_queue_t queue;
-  assert (queue.pop_minimum () == hb_pair (0, 0));
-}
-
 int
 main (int argc, char **argv)
 {
   test_insert ();
   test_extract ();
-  test_extract_empty ();
 }
index 3a2536a..950e7d2 100644 (file)
 
 #include "hb-repacker.hh"
 #include "hb-open-type.hh"
+#include "graph/serialize.hh"
+
+static void extend (const char* value,
+                    unsigned len,
+                    hb_serialize_context_t* c)
+{
+  char* obj = c->allocate_size<char> (len);
+  hb_memcpy (obj, value, len);
+}
 
 static void start_object(const char* tag,
                          unsigned len,
                          hb_serialize_context_t* c)
 {
   c->push ();
-  char* obj = c->allocate_size<char> (len);
-  strncpy (obj, tag, len);
+  extend (tag, len, c);
 }
 
-
 static unsigned add_object(const char* tag,
                            unsigned len,
                            hb_serialize_context_t* c)
@@ -56,6 +63,14 @@ static void add_offset (unsigned id,
   c->add_link (*offset, id);
 }
 
+static void add_24_offset (unsigned id,
+                           hb_serialize_context_t* c)
+{
+  OT::Offset24* offset = c->start_embed<OT::Offset24> ();
+  c->extend_min (offset);
+  c->add_link (*offset, id);
+}
+
 static void add_wide_offset (unsigned id,
                              hb_serialize_context_t* c)
 {
@@ -64,35 +79,408 @@ static void add_wide_offset (unsigned id,
   c->add_link (*offset, id);
 }
 
+static void add_gsubgpos_header (unsigned lookup_list,
+                                 hb_serialize_context_t* c)
+{
+  char header[] = {
+    0, 1, // major
+    0, 0, // minor
+    0, 0, // script list
+    0, 0, // feature list
+  };
+
+  start_object (header, 8, c);
+  add_offset (lookup_list, c);
+  c->pop_pack (false);
+}
+
+static unsigned add_lookup_list (const unsigned* lookups,
+                                 char count,
+                                 hb_serialize_context_t* c)
+{
+  char lookup_count[] = {0, count};
+  start_object  ((char *) &lookup_count, 2, c);
+
+  for (int i = 0; i < count; i++)
+    add_offset (lookups[i], c);
+
+  return c->pop_pack (false);
+}
+
+static void start_lookup (int8_t type,
+                          int8_t num_subtables,
+                          hb_serialize_context_t* c)
+{
+  char lookup[] = {
+    0, (char)type, // type
+    0, 0, // flag
+    0, (char)num_subtables, // num subtables
+  };
+
+  start_object (lookup, 6, c);
+}
+
+static unsigned finish_lookup (hb_serialize_context_t* c)
+{
+  char filter[] = {0, 0};
+  extend (filter, 2, c);
+  return c->pop_pack (false);
+}
+
+static unsigned add_extension (unsigned child,
+                               uint8_t type,
+                               hb_serialize_context_t* c)
+{
+  char ext[] = {
+    0, 1,
+    0, (char) type,
+  };
+
+  start_object (ext, 4, c);
+  add_wide_offset (child, c);
+
+  return c->pop_pack (false);
+
+}
+
+// Adds coverage table fro [start, end]
+static unsigned add_coverage (unsigned start, unsigned end,
+                              hb_serialize_context_t* c)
+{
+  if (end - start == 1)
+  {
+    uint8_t coverage[] = {
+      0, 1, // format
+      0, 2, // count
+
+      (uint8_t) ((start >> 8) & 0xFF),
+      (uint8_t) (start & 0xFF), // glyph[0]
+
+      (uint8_t) ((end >> 8) & 0xFF),
+      (uint8_t) (end & 0xFF), // glyph[1]
+    };
+    return add_object ((char*) coverage, 8, c);
+  }
+
+  uint8_t coverage[] = {
+    0, 2, // format
+    0, 1, // range count
+
+    (uint8_t) ((start >> 8) & 0xFF),
+    (uint8_t) (start & 0xFF), // start
+
+    (uint8_t) ((end >> 8) & 0xFF),
+    (uint8_t) (end & 0xFF), // end
+
+    0, 0,
+  };
+  return add_object ((char*) coverage, 10, c);
+}
+
+
+template<typename It>
+static unsigned add_coverage (It it,
+                              hb_serialize_context_t* c)
+{
+  c->push ();
+  OT::Layout::Common::Coverage_serialize (c, it);
+  return c->pop_pack (false);
+}
+
+// Adds a class that maps glyphs from [start_glyph, end_glyph)
+// to classes 1...n
+static unsigned add_class_def (uint16_t start_glyph,
+                               uint16_t end_glyph,
+                               hb_serialize_context_t* c)
+{
+  unsigned count = end_glyph - start_glyph;
+  uint8_t header[] = {
+    0, 1, // format
+
+    (uint8_t) ((start_glyph >> 8) & 0xFF),
+    (uint8_t) (start_glyph & 0xFF), // start_glyph
+
+    (uint8_t) ((count >> 8) & 0xFF),
+    (uint8_t) (count & 0xFF), // count
+  };
+
+  start_object ((char*) header, 6, c);
+  for (uint16_t i = 1; i <= count; i++)
+  {
+    uint8_t class_value[] = {
+      (uint8_t) ((i >> 8) & 0xFF),
+      (uint8_t) (i & 0xFF), // count
+    };
+    extend ((char*) class_value, 2, c);
+  }
+
+  return c->pop_pack (false);
+}
+
+static unsigned add_pair_pos_1 (unsigned* pair_sets,
+                                char count,
+                                unsigned coverage,
+                                hb_serialize_context_t* c)
+{
+  char format[] = {
+    0, 1
+  };
+
+  start_object (format, 2, c);
+  add_offset (coverage, c);
+
+  char value_format[] = {
+    0, 0,
+    0, 0,
+    0, count,
+  };
+  extend (value_format, 6, c);
+
+  for (char i = 0; i < count; i++)
+    add_offset (pair_sets[(unsigned) i], c);
+
+  return c->pop_pack (false);
+}
+
+static unsigned add_pair_pos_2 (unsigned starting_class,
+                                unsigned coverage,
+                                unsigned class_def_1, uint16_t class_def_1_count,
+                                unsigned class_def_2, uint16_t class_def_2_count,
+                                unsigned* device_tables,
+                                hb_serialize_context_t* c)
+{
+  uint8_t format[] = {
+    0, 2
+  };
+
+  start_object ((char*) format, 2, c);
+  add_offset (coverage, c);
+
+  unsigned num_values = 4;
+  uint8_t format1 = 0x01 | 0x02 | 0x08;
+  uint8_t format2 = 0x04;
+  if (device_tables) {
+    format2 |= 0x20;
+    num_values += 1;
+  }
+  uint8_t value_format[] = {
+    0, format1,
+    0, format2,
+  };
+
+  extend ((char*) value_format, 4, c);
+
+  add_offset (class_def_1, c);
+  add_offset (class_def_2, c);
+
+  uint8_t class_counts[] = {
+    (uint8_t) ((class_def_1_count >> 8) & 0xFF),
+    (uint8_t) (class_def_1_count & 0xFF),
+    (uint8_t) ((class_def_2_count >> 8) & 0xFF),
+    (uint8_t) (class_def_2_count & 0xFF),
+  };
+  extend ((char*) class_counts, 4, c);
+
+  unsigned num_bytes_per_record = class_def_2_count * num_values * 2;
+  uint8_t* record = (uint8_t*) calloc (1, num_bytes_per_record);
+  int device_index = 0;
+  for (uint16_t i = 0; i < class_def_1_count; i++)
+  {
+
+    for (uint16_t j = 0; j < class_def_2_count; j++)
+    {
+      for (int k = 0; k < 4; k++) {
+        uint8_t value[] = {
+          (uint8_t) (i + starting_class),
+          (uint8_t) (i + starting_class),
+        };
+        extend ((char*) value, 2, c);
+      }
+
+      if (device_tables) {
+        add_offset (device_tables[device_index++], c);
+      }
+    }
+  }
+  free (record);
+
+  return c->pop_pack (false);
+}
+
+static unsigned add_mark_base_pos_1 (unsigned mark_coverage,
+                                     unsigned base_coverage,
+                                     unsigned mark_array,
+                                     unsigned base_array,
+                                     unsigned class_count,
+                                     hb_serialize_context_t* c)
+{
+  uint8_t format[] = {
+    0, 1
+  };
+
+  start_object ((char*) format, 2, c);
+  add_offset (mark_coverage, c);
+  add_offset (base_coverage, c);
+
+  uint8_t count[] = {
+    (uint8_t) ((class_count >> 8) & 0xFF),
+    (uint8_t) (class_count & 0xFF),
+  };
+  extend ((char*) count, 2, c);
+
+  add_offset (mark_array, c);
+  add_offset (base_array, c);
+
+  return c->pop_pack (false);
+}
+
+template<int mark_count,
+    int class_count,
+    int base_count,
+    int table_count>
+struct MarkBasePosBuffers
+{
+  unsigned base_anchors[class_count * base_count];
+  unsigned mark_anchors[mark_count];
+  uint8_t anchor_buffers[class_count * base_count + 100];
+  uint8_t class_buffer[class_count * 2];
+
+  MarkBasePosBuffers(hb_serialize_context_t* c)
+  {
+    for (unsigned i = 0; i < sizeof(anchor_buffers) / 2; i++)
+    {
+      OT::HBUINT16* value = (OT::HBUINT16*) (&anchor_buffers[2*i]);
+      *value = i;
+    }
+
+    for (unsigned i = 0; i < class_count * base_count; i++)
+    {
+      base_anchors[i] = add_object ((char*) &anchor_buffers[i], 100, c);
+      if (i < class_count) {
+        class_buffer[i*2] = (uint8_t) ((i >> 8) & 0xFF);
+        class_buffer[i*2 + 1] = (uint8_t) (i & 0xFF);
+      }
+    }
+
+    for (unsigned i = 0; i < mark_count; i++)
+    {
+      mark_anchors[i] = add_object ((char*) &anchor_buffers[i], 4, c);
+    }
+  }
+
+  unsigned create_mark_base_pos_1 (unsigned table_index, hb_serialize_context_t* c)
+  {
+    unsigned class_per_table = class_count / table_count;
+    unsigned mark_per_class = mark_count / class_count;
+    unsigned start_class = class_per_table * table_index;
+    unsigned end_class = class_per_table * (table_index + 1) - 1;
+
+    // baseArray
+    uint8_t base_count_buffer[] = {
+      (uint8_t) ((base_count >> 8) & 0xFF),
+      (uint8_t) (base_count & 0xFF),
+
+    };
+    start_object ((char*) base_count_buffer, 2, c);
+    for (unsigned base = 0; base < base_count; base++)
+    {
+      for (unsigned klass = start_class; klass <= end_class; klass++)
+      {
+        unsigned i = base * class_count + klass;
+        add_offset (base_anchors[i], c);
+      }
+    }
+    unsigned base_array = c->pop_pack (false);
+
+    // markArray
+    unsigned num_marks = class_per_table * mark_per_class;
+    uint8_t mark_count_buffer[] = {
+      (uint8_t) ((num_marks >> 8) & 0xFF),
+      (uint8_t) (num_marks & 0xFF),
+    };
+    start_object ((char*) mark_count_buffer, 2, c);
+    for (unsigned mark = 0; mark < mark_count; mark++)
+    {
+      unsigned klass = mark % class_count;
+      if (klass < start_class || klass > end_class) continue;
+      klass -= start_class;
+
+      extend ((char*) &class_buffer[2 * klass], 2, c);
+      add_offset (mark_anchors[mark], c);
+    }
+    unsigned mark_array = c->pop_pack (false);
+
+    // markCoverage
+    auto it =
+        + hb_range ((hb_codepoint_t) mark_count)
+        | hb_filter ([&] (hb_codepoint_t mark) {
+          unsigned klass = mark % class_count;
+          return klass >= class_per_table * table_index &&
+              klass < class_per_table * (table_index + 1);
+        })
+        ;
+    unsigned mark_coverage = add_coverage (it, c);
+
+    // baseCoverage
+    unsigned base_coverage = add_coverage (10, 10 + base_count - 1, c);
+
+    return add_mark_base_pos_1 (mark_coverage,
+                                base_coverage,
+                                mark_array,
+                                base_array,
+                                class_per_table,
+                                c);
+  }
+};
+
+
+
+
+
 static void run_resolve_overflow_test (const char* name,
                                        hb_serialize_context_t& overflowing,
                                        hb_serialize_context_t& expected,
-                                       unsigned num_iterations = 0)
+                                       unsigned num_iterations = 0,
+                                       bool recalculate_extensions = false,
+                                       hb_tag_t tag = HB_TAG ('G', 'S', 'U', 'B'))
 {
   printf (">>> Testing overflowing resolution for %s\n",
           name);
 
   graph_t graph (overflowing.object_graph ());
 
+  graph_t expected_graph (expected.object_graph ());
+  if (graph::will_overflow (expected_graph))
+  {
+    expected_graph.assign_spaces ();
+    expected_graph.sort_shortest_distance ();
+  }
 
+  // Check that overflow resolution succeeds
   assert (overflowing.offset_overflow ());
-  hb_blob_t* out = hb_resolve_overflows (overflowing.object_graph (),
-                                         HB_TAG ('G', 'S', 'U', 'B'), num_iterations);
-  assert (out);
+  assert (hb_resolve_graph_overflows (tag,
+                                      num_iterations,
+                                      recalculate_extensions,
+                                      graph));
 
-  hb_bytes_t result = out->as_bytes ();
-
-  assert (!expected.offset_overflow ());
-  hb_bytes_t expected_result = expected.copy_bytes ();
+  // Check the graphs can be serialized.
+  hb_blob_t* out = graph::serialize (graph);
+  assert (out);
+  hb_blob_destroy (out);
+  out = graph::serialize (expected_graph);
+  assert (out);
+  hb_blob_destroy (out);
 
-  assert (result.length == expected_result.length);
-  for (unsigned i = 0; i < expected_result.length; i++)
-  {
-    assert (result[i] == expected_result[i]);
+  // Check the graphs are equivalent
+  graph.normalize ();
+  expected_graph.normalize ();
+  if (!(graph == expected_graph)) {
+    printf("## Expected:\n");
+    expected_graph.print();
+    printf("## Result:\n");
+    graph.print();
   }
-
-  expected_result.fini ();
-  hb_blob_destroy (out);
+  assert (graph == expected_graph);
 }
 
 static void add_virtual_offset (unsigned id,
@@ -729,26 +1117,6 @@ populate_serializer_with_split_spaces_expected_2 (hb_serialize_context_t* c)
 }
 
 static void
-populate_serializer_complex_1 (hb_serialize_context_t* c)
-{
-  c->start_serialize<char> ();
-
-  unsigned obj_4 = add_object ("jkl", 3, c);
-  unsigned obj_3 = add_object ("ghi", 3, c);
-
-  start_object ("def", 3, c);
-  add_offset (obj_3, c);
-  unsigned obj_2 = c->pop_pack (false);
-
-  start_object ("abc", 3, c);
-  add_offset (obj_2, c);
-  add_offset (obj_4, c);
-  c->pop_pack (false);
-
-  c->end_serialize();
-}
-
-static void
 populate_serializer_complex_2 (hb_serialize_context_t* c)
 {
   c->start_serialize<char> ();
@@ -831,66 +1199,284 @@ populate_serializer_virtual_link (hb_serialize_context_t* c)
   c->end_serialize();
 }
 
-static void test_sort_kahn_1 ()
+static void
+populate_serializer_with_24_and_32_bit_offsets (hb_serialize_context_t* c)
 {
-  size_t buffer_size = 100;
-  void* buffer = malloc (buffer_size);
-  hb_serialize_context_t c (buffer, buffer_size);
-  populate_serializer_complex_1 (&c);
+  std::string large_string(60000, 'a');
+  c->start_serialize<char> ();
 
-  graph_t graph (c.object_graph ());
-  graph.sort_kahn ();
+  unsigned obj_f = add_object ("f", 1, c);
+  unsigned obj_g = add_object ("g", 1, c);
+  unsigned obj_j = add_object ("j", 1, c);
+  unsigned obj_k = add_object ("k", 1, c);
 
-  assert(strncmp (graph.object (3).head, "abc", 3) == 0);
-  assert(graph.object (3).real_links.length == 2);
-  assert(graph.object (3).real_links[0].objidx == 2);
-  assert(graph.object (3).real_links[1].objidx == 1);
+  start_object (large_string.c_str (), 40000, c);
+  add_offset (obj_f, c);
+  unsigned obj_c = c->pop_pack (false);
 
-  assert(strncmp (graph.object (2).head, "def", 3) == 0);
-  assert(graph.object (2).real_links.length == 1);
-  assert(graph.object (2).real_links[0].objidx == 0);
+  start_object (large_string.c_str (), 40000, c);
+  add_offset (obj_g, c);
+  unsigned obj_d = c->pop_pack (false);
 
-  assert(strncmp (graph.object (1).head, "jkl", 3) == 0);
-  assert(graph.object (1).real_links.length == 0);
+  start_object (large_string.c_str (), 40000, c);
+  add_offset (obj_j, c);
+  unsigned obj_h = c->pop_pack (false);
 
-  assert(strncmp (graph.object (0).head, "ghi", 3) == 0);
-  assert(graph.object (0).real_links.length == 0);
+  start_object (large_string.c_str (), 40000, c);
+  add_offset (obj_k, c);
+  unsigned obj_i = c->pop_pack (false);
 
-  free (buffer);
+  start_object ("e", 1, c);
+  add_wide_offset (obj_h, c);
+  add_wide_offset (obj_i, c);
+  unsigned obj_e = c->pop_pack (false);
+
+  start_object ("b", 1, c);
+  add_24_offset (obj_c, c);
+  add_24_offset (obj_d, c);
+  add_24_offset (obj_e, c);
+  unsigned obj_b = c->pop_pack (false);
+
+  start_object ("a", 1, c);
+  add_24_offset (obj_b, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
 }
 
-static void test_sort_kahn_2 ()
+static void
+populate_serializer_with_extension_promotion (hb_serialize_context_t* c,
+                                              int num_extensions = 0,
+                                              bool shared_subtables = false)
 {
-  size_t buffer_size = 100;
-  void* buffer = malloc (buffer_size);
-  hb_serialize_context_t c (buffer, buffer_size);
-  populate_serializer_complex_2 (&c);
+  constexpr int num_lookups = 5;
+  constexpr int num_subtables = num_lookups * 2;
+  unsigned int lookups[num_lookups];
+  unsigned int subtables[num_subtables];
+  unsigned int extensions[num_subtables];
 
-  graph_t graph (c.object_graph ());
-  graph.sort_kahn ();
+  std::string large_string(60000, 'a');
+  c->start_serialize<char> ();
 
 
-  assert(strncmp (graph.object (4).head, "abc", 3) == 0);
-  assert(graph.object (4).real_links.length == 3);
-  assert(graph.object (4).real_links[0].objidx == 3);
-    assert(graph.object (4).real_links[1].objidx == 0);
-  assert(graph.object (4).real_links[2].objidx == 2);
+  for (int i = num_subtables - 1; i >= 0; i--)
+    subtables[i] = add_object(large_string.c_str (), 15000 + i, c);
 
-  assert(strncmp (graph.object (3).head, "def", 3) == 0);
-  assert(graph.object (3).real_links.length == 1);
-  assert(graph.object (3).real_links[0].objidx == 1);
+  for (int i = num_subtables - 1;
+       i >= (num_lookups - num_extensions) * 2;
+       i--)
+  {
+    extensions[i] = add_extension (subtables[i], 5, c);
+  }
 
-  assert(strncmp (graph.object (2).head, "mn", 2) == 0);
-  assert(graph.object (2).real_links.length == 0);
+  for (int i = num_lookups - 1; i >= 0; i--)
+  {
+    bool is_ext = (i >= (num_lookups - num_extensions));
+
+    start_lookup (is_ext ? (char) 7 : (char) 5,
+                  shared_subtables && i > 2 ? 3 : 2,
+                  c);
+
+    if (is_ext) {
+      if (shared_subtables && i > 2) {
+        add_offset (extensions[i * 2 - 1], c);
+      }
+      add_offset (extensions[i * 2], c);
+      add_offset (extensions[i * 2 + 1], c);
+    } else {
+      if (shared_subtables && i > 2) {
+        add_offset (subtables[i * 2 - 1], c);
+      }
+      add_offset (subtables[i * 2], c);
+      add_offset (subtables[i * 2 + 1], c);
+    }
+
+    lookups[i] = finish_lookup (c);
+  }
 
-  assert(strncmp (graph.object (1).head, "ghi", 3) == 0);
-  assert(graph.object (1).real_links.length == 1);
-  assert(graph.object (1).real_links[0].objidx == 0);
+  unsigned lookup_list = add_lookup_list (lookups, num_lookups, c);
 
-  assert(strncmp (graph.object (0).head, "jkl", 3) == 0);
-  assert(graph.object (0).real_links.length == 0);
+  add_gsubgpos_header (lookup_list, c);
 
-  free (buffer);
+  c->end_serialize();
+}
+
+template<int num_pair_pos_1, int num_pair_set>
+static void
+populate_serializer_with_large_pair_pos_1 (hb_serialize_context_t* c,
+                                           bool as_extension = false)
+{
+  std::string large_string(60000, 'a');
+  c->start_serialize<char> ();
+
+  constexpr int total_pair_set = num_pair_pos_1 * num_pair_set;
+  unsigned pair_set[total_pair_set];
+  unsigned coverage[num_pair_pos_1];
+  unsigned pair_pos_1[num_pair_pos_1];
+
+  for (int i = num_pair_pos_1 - 1; i >= 0; i--)
+  {
+    for (int j = (i + 1) * num_pair_set - 1; j >= i * num_pair_set; j--)
+      pair_set[j] = add_object (large_string.c_str (), 30000 + j, c);
+
+    coverage[i] = add_coverage (i * num_pair_set,
+                                (i + 1) * num_pair_set - 1, c);
+
+    pair_pos_1[i] = add_pair_pos_1 (&pair_set[i * num_pair_set],
+                                    num_pair_set,
+                                    coverage[i],
+                                    c);
+  }
+
+  unsigned pair_pos_2 = add_object (large_string.c_str(), 200, c);
+
+  if (as_extension) {
+    pair_pos_2 = add_extension (pair_pos_2, 2, c);
+    for (int i = num_pair_pos_1 - 1; i >= 0; i--)
+      pair_pos_1[i] = add_extension (pair_pos_1[i], 2, c);
+  }
+
+  start_lookup (as_extension ? 9 : 2, 1 + num_pair_pos_1, c);
+
+  for (int i = 0; i < num_pair_pos_1; i++)
+    add_offset (pair_pos_1[i], c);
+  add_offset (pair_pos_2, c);
+
+  unsigned lookup = finish_lookup (c);
+
+  unsigned lookup_list = add_lookup_list (&lookup, 1, c);
+
+  add_gsubgpos_header (lookup_list, c);
+
+  c->end_serialize();
+}
+
+template<int num_pair_pos_2, int num_class_1, int num_class_2>
+static void
+populate_serializer_with_large_pair_pos_2 (hb_serialize_context_t* c,
+                                           bool as_extension = false,
+                                           bool with_device_tables = false,
+                                           bool extra_table = true)
+{
+  std::string large_string(100000, 'a');
+  c->start_serialize<char> ();
+
+  unsigned coverage[num_pair_pos_2];
+  unsigned class_def_1[num_pair_pos_2];
+  unsigned class_def_2[num_pair_pos_2];
+  unsigned pair_pos_2[num_pair_pos_2];
+
+  unsigned* device_tables = (unsigned*) calloc (num_pair_pos_2 * num_class_1 * num_class_2,
+                                                sizeof(unsigned));
+
+  // Total glyphs = num_class_1 * num_pair_pos_2
+  for (int i = num_pair_pos_2 - 1; i >= 0; i--)
+  {
+    unsigned start_glyph = 5 + i * num_class_1;
+    if (num_class_2 >= num_class_1)
+    {
+      class_def_2[i] = add_class_def (11,
+                                      10 + num_class_2, c);
+      class_def_1[i] = add_class_def (start_glyph + 1,
+                                      start_glyph + num_class_1,
+                                      c);
+    } else {
+      class_def_1[i] = add_class_def (start_glyph + 1,
+                                      start_glyph + num_class_1,
+                                      c);
+      class_def_2[i] = add_class_def (11,
+                                      10 + num_class_2, c);
+    }
+
+    coverage[i] = add_coverage (start_glyph,
+                                start_glyph + num_class_1 - 1,
+                                c);
+
+    if (with_device_tables)
+    {
+      for(int j = (i + 1) * num_class_1 * num_class_2 - 1;
+          j >= i * num_class_1 * num_class_2;
+          j--)
+      {
+        uint8_t table[] = {
+          (uint8_t) ((j >> 8) & 0xFF),
+          (uint8_t) (j & 0xFF),
+        };
+        device_tables[j] = add_object ((char*) table, 2, c);
+      }
+    }
+
+    pair_pos_2[i] = add_pair_pos_2 (1 + i * num_class_1,
+                                    coverage[i],
+                                    class_def_1[i], num_class_1,
+                                    class_def_2[i], num_class_2,
+                                    with_device_tables
+                                    ? &device_tables[i * num_class_1 * num_class_2]
+                                    : nullptr,
+                                    c);
+  }
+
+
+  unsigned pair_pos_1 = 0;
+  if (extra_table) pair_pos_1 = add_object (large_string.c_str(), 100000, c);
+
+  if (as_extension) {
+    for (int i = num_pair_pos_2 - 1; i >= 0; i--)
+      pair_pos_2[i] = add_extension (pair_pos_2[i], 2, c);
+
+    if (extra_table)
+      pair_pos_1 = add_extension (pair_pos_1, 2, c);
+  }
+
+  start_lookup (as_extension ? 9 : 2, 1 + num_pair_pos_2, c);
+
+  if (extra_table)
+    add_offset (pair_pos_1, c);
+
+  for (int i = 0; i < num_pair_pos_2; i++)
+    add_offset (pair_pos_2[i], c);
+
+  unsigned lookup = finish_lookup (c);
+
+  unsigned lookup_list = add_lookup_list (&lookup, 1, c);
+
+  add_gsubgpos_header (lookup_list, c);
+
+  c->end_serialize();
+
+  free (device_tables);
+}
+
+template<int mark_count,
+    int class_count,
+    int base_count,
+    int table_count>
+static void
+populate_serializer_with_large_mark_base_pos_1 (hb_serialize_context_t* c)
+{
+  c->start_serialize<char> ();
+
+  MarkBasePosBuffers<mark_count, class_count, base_count, table_count> buffers (c);
+
+  unsigned mark_base_pos[table_count];
+  for (unsigned i = 0; i < table_count; i++)
+    mark_base_pos[i] = buffers.create_mark_base_pos_1 (i, c);
+
+  for (int i = 0; i < table_count; i++)
+    mark_base_pos[i] = add_extension (mark_base_pos[i], 4, c);
+
+  start_lookup (9, table_count, c);
+
+  for (int i = 0; i < table_count; i++)
+    add_offset (mark_base_pos[i], c);
+
+  unsigned lookup = finish_lookup (c);
+
+  unsigned lookup_list = add_lookup_list (&lookup, 1, c);
+
+  add_gsubgpos_header (lookup_list, c);
+
+  c->end_serialize();
 }
 
 static void test_sort_shortest ()
@@ -902,6 +1488,7 @@ static void test_sort_shortest ()
 
   graph_t graph (c.object_graph ());
   graph.sort_shortest_distance ();
+  assert (!graph.in_error ());
 
   assert(strncmp (graph.object (4).head, "abc", 3) == 0);
   assert(graph.object (4).real_links.length == 3);
@@ -1013,7 +1600,7 @@ test_serialize ()
   hb_bytes_t expected = c1.copy_bytes ();
 
   graph_t graph (c1.object_graph ());
-  hb_blob_t* out = graph.serialize ();
+  hb_blob_t* out = graph::serialize (graph);
   free (buffer_1);
 
   hb_bytes_t actual = out->as_bytes ();
@@ -1030,7 +1617,7 @@ static void test_will_overflow_1 ()
   populate_serializer_complex_2 (&c);
   graph_t graph (c.object_graph ());
 
-  assert (!graph.will_overflow (nullptr));
+  assert (!graph::will_overflow (graph, nullptr));
 
   free (buffer);
 }
@@ -1043,7 +1630,7 @@ static void test_will_overflow_2 ()
   populate_serializer_with_overflow (&c);
   graph_t graph (c.object_graph ());
 
-  assert (graph.will_overflow (nullptr));
+  assert (graph::will_overflow (graph, nullptr));
 
   free (buffer);
 }
@@ -1056,7 +1643,7 @@ static void test_will_overflow_3 ()
   populate_serializer_with_dedup_overflow (&c);
   graph_t graph (c.object_graph ());
 
-  assert (graph.will_overflow (nullptr));
+  assert (graph::will_overflow (graph, nullptr));
 
   free (buffer);
 }
@@ -1210,6 +1797,218 @@ static void test_resolve_overflows_via_isolation_spaces ()
   hb_blob_destroy (out);
 }
 
+static void test_resolve_mixed_overflows_via_isolation_spaces ()
+{
+  size_t buffer_size = 200000;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_24_and_32_bit_offsets (&c);
+  graph_t graph (c.object_graph ());
+
+  assert (c.offset_overflow ());
+  hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), 0);
+  assert (out);
+  hb_bytes_t result = out->as_bytes ();
+
+  unsigned expected_length =
+      // Objects
+      7 +
+      4 * 40000;
+
+  expected_length +=
+      // Links
+      2 * 4 +  // 32
+      4 * 3 +  // 24
+      4 * 2;   // 16
+
+  assert (result.length == expected_length);
+
+  free (buffer);
+  hb_blob_destroy (out);
+}
+
+static void test_resolve_with_extension_promotion ()
+{
+  size_t buffer_size = 200000;
+  void* buffer = malloc (buffer_size);
+  assert (buffer);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_extension_promotion (&c);
+
+  void* expected_buffer = malloc (buffer_size);
+  assert (expected_buffer);
+  hb_serialize_context_t e (expected_buffer, buffer_size);
+  populate_serializer_with_extension_promotion (&e, 3);
+
+  run_resolve_overflow_test ("test_resolve_with_extension_promotion",
+                             c,
+                             e,
+                             20,
+                             true);
+  free (buffer);
+  free (expected_buffer);
+}
+
+static void test_resolve_with_shared_extension_promotion ()
+{
+  size_t buffer_size = 200000;
+  void* buffer = malloc (buffer_size);
+  assert (buffer);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_extension_promotion (&c, 0, true);
+
+  void* expected_buffer = malloc (buffer_size);
+  assert (expected_buffer);
+  hb_serialize_context_t e (expected_buffer, buffer_size);
+  populate_serializer_with_extension_promotion (&e, 3, true);
+
+  run_resolve_overflow_test ("test_resolve_with_extension_promotion",
+                             c,
+                             e,
+                             20,
+                             true);
+  free (buffer);
+  free (expected_buffer);
+}
+
+static void test_resolve_with_basic_pair_pos_1_split ()
+{
+  size_t buffer_size = 200000;
+  void* buffer = malloc (buffer_size);
+  assert (buffer);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_large_pair_pos_1 <1, 4>(&c);
+
+  void* expected_buffer = malloc (buffer_size);
+  assert (expected_buffer);
+  hb_serialize_context_t e (expected_buffer, buffer_size);
+  populate_serializer_with_large_pair_pos_1 <2, 2>(&e, true);
+
+  run_resolve_overflow_test ("test_resolve_with_basic_pair_pos_1_split",
+                             c,
+                             e,
+                             20,
+                             true,
+                             HB_TAG('G', 'P', 'O', 'S'));
+  free (buffer);
+  free (expected_buffer);
+}
+
+static void test_resolve_with_extension_pair_pos_1_split ()
+{
+  size_t buffer_size = 200000;
+  void* buffer = malloc (buffer_size);
+  assert (buffer);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_large_pair_pos_1 <1, 4>(&c, true);
+
+  void* expected_buffer = malloc (buffer_size);
+  assert (expected_buffer);
+  hb_serialize_context_t e (expected_buffer, buffer_size);
+  populate_serializer_with_large_pair_pos_1 <2, 2>(&e, true);
+
+  run_resolve_overflow_test ("test_resolve_with_extension_pair_pos_1_split",
+                             c,
+                             e,
+                             20,
+                             true,
+                             HB_TAG('G', 'P', 'O', 'S'));
+  free (buffer);
+  free (expected_buffer);
+}
+
+static void test_resolve_with_basic_pair_pos_2_split ()
+{
+  size_t buffer_size = 300000;
+  void* buffer = malloc (buffer_size);
+  assert (buffer);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_large_pair_pos_2 <1, 4, 3000>(&c);
+
+  void* expected_buffer = malloc (buffer_size);
+  assert (expected_buffer);
+  hb_serialize_context_t e (expected_buffer, buffer_size);
+  populate_serializer_with_large_pair_pos_2 <2, 2, 3000>(&e, true);
+
+  run_resolve_overflow_test ("test_resolve_with_basic_pair_pos_2_split",
+                             c,
+                             e,
+                             20,
+                             true,
+                             HB_TAG('G', 'P', 'O', 'S'));
+  free (buffer);
+  free (expected_buffer);
+}
+
+static void test_resolve_with_close_to_limit_pair_pos_2_split ()
+{
+  size_t buffer_size = 300000;
+  void* buffer = malloc (buffer_size);
+  assert (buffer);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_large_pair_pos_2 <1, 1596, 10>(&c, true, false, false);
+
+  void* expected_buffer = malloc (buffer_size);
+  assert (expected_buffer);
+  hb_serialize_context_t e (expected_buffer, buffer_size);
+  populate_serializer_with_large_pair_pos_2 <2, 798, 10>(&e, true, false, false);
+
+  run_resolve_overflow_test ("test_resolve_with_close_to_limit_pair_pos_2_split",
+                             c,
+                             e,
+                             20,
+                             true,
+                             HB_TAG('G', 'P', 'O', 'S'));
+  free (buffer);
+  free (expected_buffer);
+}
+
+static void test_resolve_with_pair_pos_2_split_with_device_tables ()
+{
+  size_t buffer_size = 300000;
+  void* buffer = malloc (buffer_size);
+  assert (buffer);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_large_pair_pos_2 <1, 4, 2000>(&c, false, true);
+
+  void* expected_buffer = malloc (buffer_size);
+  assert (expected_buffer);
+  hb_serialize_context_t e (expected_buffer, buffer_size);
+  populate_serializer_with_large_pair_pos_2 <2, 2, 2000>(&e, true, true);
+
+  run_resolve_overflow_test ("test_resolve_with_pair_pos_2_split_with_device_tables",
+                             c,
+                             e,
+                             20,
+                             true,
+                             HB_TAG('G', 'P', 'O', 'S'));
+  free (buffer);
+  free (expected_buffer);
+}
+
+static void test_resolve_with_basic_mark_base_pos_1_split ()
+{
+  size_t buffer_size = 200000;
+  void* buffer = malloc (buffer_size);
+  assert (buffer);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_large_mark_base_pos_1 <40, 10, 110, 1>(&c);
+
+  void* expected_buffer = malloc (buffer_size);
+  assert (expected_buffer);
+  hb_serialize_context_t e (expected_buffer, buffer_size);
+  populate_serializer_with_large_mark_base_pos_1 <40, 10, 110, 2>(&e);
+
+  run_resolve_overflow_test ("test_resolve_with_basic_mark_base_pos_1_split",
+                             c,
+                             e,
+                             20,
+                             true,
+                             HB_TAG('G', 'P', 'O', 'S'));
+  free (buffer);
+  free (expected_buffer);
+}
+
 static void test_resolve_overflows_via_splitting_spaces ()
 {
   size_t buffer_size = 160000;
@@ -1336,8 +2135,6 @@ int
 main (int argc, char **argv)
 {
   test_serialize ();
-  test_sort_kahn_1 ();
-  test_sort_kahn_2 ();
   test_sort_shortest ();
   test_will_overflow_1 ();
   test_will_overflow_2 ();
@@ -1353,8 +2150,24 @@ main (int argc, char **argv)
   test_resolve_overflows_via_isolating_16bit_space_2 ();
   test_resolve_overflows_via_splitting_spaces ();
   test_resolve_overflows_via_splitting_spaces_2 ();
+  test_resolve_mixed_overflows_via_isolation_spaces ();
   test_duplicate_leaf ();
   test_duplicate_interior ();
   test_virtual_link ();
   test_shared_node_with_virtual_links ();
+  test_resolve_with_extension_promotion ();
+  test_resolve_with_shared_extension_promotion ();
+  test_resolve_with_basic_pair_pos_1_split ();
+  test_resolve_with_extension_pair_pos_1_split ();
+  test_resolve_with_basic_pair_pos_2_split ();
+  test_resolve_with_pair_pos_2_split_with_device_tables ();
+  test_resolve_with_close_to_limit_pair_pos_2_split ();
+  test_resolve_with_basic_mark_base_pos_1_split ();
+
+  // TODO(grieger): have run overflow tests compare graph equality not final packed binary.
+  // TODO(grieger): split test where multiple subtables in one lookup are split to test link ordering.
+  // TODO(grieger): split test where coverage table in subtable that is being split is shared.
+  // TODO(grieger): test with extensions already mixed in as well.
+  // TODO(grieger): test two layer ext promotion setup.
+  // TODO(grieger): test sorting by subtables per byte in ext. promotion.
 }
index 44a2e0f..4c90abb 100644 (file)
@@ -27,6 +27,7 @@
 #include "hb-serialize.hh"
 #include "hb-ot-layout-common.hh"
 
+using OT::Layout::Common::Coverage;
 
 int
 main (int argc, char **argv)
@@ -37,7 +38,7 @@ main (int argc, char **argv)
 
   hb_sorted_vector_t<hb_codepoint_t> v{1, 2, 5};
 
-  auto c = s.start_serialize<OT::Coverage> ();
+  auto c = s.start_serialize<Coverage> ();
 
   c->serialize (&s, hb_iter (v));
 
index 286f1a9..853aed4 100644 (file)
  * 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.hh"
 #include "hb-set.hh"
 
-
 int
 main (int argc, char **argv)
 {
@@ -36,27 +34,34 @@ main (int argc, char **argv)
     hb_set_t v1 {1, 2};
     hb_set_t v2 {v1};
     assert (v1.get_population () == 2);
+    assert (hb_len (hb_iter (v1)) == 2);
     assert (v2.get_population () == 2);
   }
 
   /* Test copy assignment. */
   {
     hb_set_t v1 {1, 2};
-    hb_set_t v2 = v1;
+    hb_set_t v2;
+    v2 = v1;
     assert (v1.get_population () == 2);
     assert (v2.get_population () == 2);
   }
 
   /* Test move constructor. */
   {
-    hb_set_t v {hb_set_t {1, 2}};
+    hb_set_t s {1, 2};
+    hb_set_t v (std::move (s));
+    assert (s.get_population () == 0);
+    assert (hb_len (hb_iter (s)) == 0);
     assert (v.get_population () == 2);
   }
 
   /* Test move assignment. */
   {
+    hb_set_t s = hb_set_t {1, 2};
     hb_set_t v;
-    v = hb_set_t {1, 2};
+    v = std::move (s);
+    assert (s.get_population () == 0);
     assert (v.get_population () == 2);
   }
 
@@ -67,9 +72,15 @@ main (int argc, char **argv)
     s.add (18);
     s.add (12);
 
-    hb_set_t v (s);
+    hb_vector_t<hb_codepoint_t> v (s);
+    hb_set_t v0 (v);
+    hb_set_t v1 (s);
+    hb_set_t v2 (std::move (s));
 
-    assert (v.get_population () == 2);
+    assert (s.get_population () == 0);
+    assert (v0.get_population () == 2);
+    assert (v1.get_population () == 2);
+    assert (v2.get_population () == 2);
   }
 
   /* Test initializing from iterator. */
@@ -77,11 +88,14 @@ main (int argc, char **argv)
     hb_set_t s;
 
     s.add (18);
-    s.add (12);
+    s << 12;
+
+    /* Sink a range. */
+    s << hb_codepoint_pair_t {1, 3};
 
     hb_set_t v (hb_iter (s));
 
-    assert (v.get_population () == 2);
+    assert (v.get_population () == 5);
   }
 
   /* Test initializing from initializer list and swapping. */
@@ -93,5 +107,59 @@ main (int argc, char **argv)
     assert (v2.get_population () == 3);
   }
 
+  /* Test inverted sets. */
+  {
+    hb_set_t s;
+    s.invert();
+    s.del (5);
+
+    hb_codepoint_t start = HB_SET_VALUE_INVALID, last = HB_SET_VALUE_INVALID;
+    assert (s.next_range (&start, &last));
+    assert (start == 0);
+    assert (last == 4);
+    assert (s.next_range (&start, &last));
+    assert (start == 6);
+    assert (last == HB_SET_VALUE_INVALID - 1);
+    assert (!s.next_range (&start, &last));
+
+    start = HB_SET_VALUE_INVALID;
+    last = HB_SET_VALUE_INVALID;
+    assert (s.previous_range (&start, &last));
+    assert (start == 6);
+    assert (last == HB_SET_VALUE_INVALID - 1);
+    assert (s.previous_range (&start, &last));
+    assert (start == 0);
+    assert (last == 4);
+    assert (!s.previous_range (&start, &last));
+
+    assert (s.is_inverted ());
+    /* Inverted set returns true for invalid value; oh well. */
+    assert (s.has (HB_SET_VALUE_INVALID));
+  }
+
+  /* Adding HB_SET_VALUE_INVALID */
+  {
+    hb_set_t s;
+
+    s.add(HB_SET_VALUE_INVALID);
+    assert(!s.has(HB_SET_VALUE_INVALID));
+
+    s.clear();
+    assert(!s.add_range(HB_SET_VALUE_INVALID - 2, HB_SET_VALUE_INVALID));
+    assert(!s.has(HB_SET_VALUE_INVALID));
+
+    hb_codepoint_t array[] = {(unsigned) HB_SET_VALUE_INVALID, 0, 2};
+    s.clear();
+    s.add_array(array, 3);
+    assert(!s.has(HB_SET_VALUE_INVALID));
+    assert(s.has(2));
+
+    hb_codepoint_t sorted_array[] = {0, 2, (unsigned) HB_SET_VALUE_INVALID};
+    s.clear();
+    s.add_sorted_array(sorted_array, 3);
+    assert(!s.has(HB_SET_VALUE_INVALID));
+    assert(s.has(2));
+  }
+
   return 0;
 }
diff --git a/src/test-subset-instancer-solver.cc b/src/test-subset-instancer-solver.cc
new file mode 100644 (file)
index 0000000..e8294cf
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * Copyright © 2023  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): Qunxin Liu
+ */
+
+#include "hb-subset-instancer-solver.hh"
+
+static inline bool approx (Triple a, Triple b)
+{
+  return fabsf (a.minimum - b.minimum) < 0.000001f &&
+         fabsf (a.middle - b.middle) < 0.000001f &&
+         fabsf (a.maximum - b.maximum) < 0.000001f;
+}
+
+static inline bool approx (float a, float b)
+{ return fabsf (a - b) < 0.000001f; }
+
+/* tests ported from
+ * https://github.com/fonttools/fonttools/blob/main/Tests/varLib/instancer/solver_test.py */
+int
+main (int argc, char **argv)
+{
+  TripleDistances default_axis_distances{1.f, 1.f};
+  /* Case 1 */
+  {
+    /* pin axis*/
+    Triple tent (0.f, 1.f, 1.f);
+    Triple axis_range (0.f, 0.f, 0.f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 0);
+  }
+
+  {
+    /* pin axis*/
+    Triple tent (0.f, 1.f, 1.f);
+    Triple axis_range (0.5f, 0.5f, 0.5f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 1);
+    assert (out[0].first == 0.5f);
+    assert (out[0].second == Triple ());
+  }
+
+  {
+    /* tent falls outside the new axis range */
+    Triple tent (0.3f, 0.5f, 0.8f);
+    Triple axis_range (0.1f, 0.2f, 0.3f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 0);
+  }
+
+  /* Case 2 */
+  {
+    Triple tent (0.f, 1.f, 1.f);
+    Triple axis_range (-1.f, 0.f, 0.5f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 1);
+    assert (out[0].first == 0.5f);
+    assert (out[0].second == Triple (0.f, 1.f, 1.f));
+  }
+
+  /* Case 2 */
+  {
+    Triple tent (0.f, 1.f, 1.f);
+    Triple axis_range (-1.f, 0.f, 0.75f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 1);
+    assert (out[0].first == 0.75f);
+    assert (out[0].second == Triple (0.f, 1.f, 1.f));
+  }
+
+  /* Without gain: */
+  /* Case 3 */
+  {
+    Triple tent (0.f, 0.2f, 1.f);
+    Triple axis_range (-1.f, 0.f, 0.8f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 1);
+    assert (out[0].first == 1.f);
+    assert (out[0].second == Triple (0.f, 0.25f, 1.25f));
+  }
+
+  /* Case 3 boundary */
+  {
+    Triple tent (0.f, 0.4f, 1.f);
+    Triple axis_range (-1.f, 0.f, 0.5f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 1);
+    assert (out[0].first == 1.f);
+    assert (out[0].second == Triple (0.f, 0.8f, 32767/(float) (1 << 14)));
+  }
+
+  /* Case 4 */
+  {
+    Triple tent (0.f, 0.25f, 1.f);
+    Triple axis_range (-1.f, 0.f, 0.4f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 2);
+    assert (out[0].first == 1.f);
+    assert (out[0].second == Triple (0.f, 0.625f, 1.f));
+    assert (approx (out[1].first, 0.8f));
+    assert (out[1].second == Triple (0.625f, 1.f, 1.f));
+  }
+
+  /* Case 4 */
+  {
+    Triple tent (0.25f, 0.3f, 1.05f);
+    Triple axis_range (0.f, 0.2f, 0.4f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 2);
+    assert (out[0].first == 1.f);
+    assert (approx (out[0].second, Triple (0.25f, 0.5f, 1.f)));
+    assert (approx (out[1].first, 2.6f/3));
+    assert (approx (out[1].second, Triple (0.5f, 1.f, 1.f)));
+  }
+
+  /* Case 4 boundary */
+  {
+    Triple tent (0.25f, 0.5f, 1.f);
+    Triple axis_range (0.f, 0.25f, 0.5f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 1);
+    assert (out[0].first == 1.f);
+    assert (out[0].second == Triple (0.f, 1.f, 1.f));
+  }
+
+  /* With gain */
+  /* Case 3a/1neg */
+  {
+    Triple tent (0.f, 0.5f, 1.f);
+    Triple axis_range (0.f, 0.5f, 1.f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 3);
+    assert (out[0].first == 1.f);
+    assert (out[0].second == Triple ());
+    assert (out[1].first == -1.f);
+    assert (out[1].second == Triple (0.f, 1.f, 1.f));
+    assert (out[2].first == -1.f);
+    assert (out[2].second == Triple (-1.f, -1.f, 0.f));
+  }
+
+  {
+    Triple tent (0.f, 0.5f, 1.f);
+    Triple axis_range (0.f, 0.5f, 0.75f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 3);
+    assert (out[0].first == 1.f);
+    assert (out[0].second == Triple ());
+    assert (out[1].first == -0.5f);
+    assert (out[1].second == Triple (0.f, 1.f, 1.f));
+    assert (out[2].first == -1.f);
+    assert (out[2].second == Triple (-1.f, -1.f, 0.f));
+  }
+
+  {
+    Triple tent (0.f, 0.5f, 1.f);
+    Triple axis_range (0.f, 0.25f, 0.8f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 4);
+    assert (out[0].first == 0.5f);
+    assert (out[0].second == Triple ());
+    assert (out[1].first == 0.5f);
+    assert (approx (out[1].second, Triple (0.f, 0.454545f, 0.909091f)));
+    assert (approx (out[2].first, -0.1f));
+    assert (approx (out[2].second, Triple (0.909091f, 1.f, 1.f)));
+    assert (out[3].first == -0.5f);
+    assert (out[3].second == Triple (-1.f, -1.f, 0.f));
+  }
+
+  /* Case 3a/1neg */
+  {
+    Triple tent (0.f, 0.5f, 2.f);
+    Triple axis_range (0.2f, 0.5f, 0.8f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 3);
+    assert (out[0].first == 1.f);
+    assert (out[0].second == Triple ());
+    assert (approx (out[1].first, -0.2f));
+    assert (out[1].second == Triple (0.f, 1.f, 1.f));
+    assert (approx (out[2].first, -0.6f));
+    assert (out[2].second == Triple (-1.f, -1.f, 0.f));
+  }
+
+  /* Case 3a/1neg */
+  {
+    Triple tent (0.f, 0.5f, 2.f);
+    Triple axis_range (0.2f, 0.5f, 1.f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 3);
+    assert (out[0].first == 1.f);
+    assert (out[0].second == Triple ());
+    assert (approx (out[1].first, -1.f/3));
+    assert (out[1].second == Triple (0.f, 1.f, 1.f));
+    assert (approx (out[2].first, -0.6f));
+    assert (out[2].second == Triple (-1.f, -1.f, 0.f));
+  }
+
+  /* Case 3 */
+  {
+    Triple tent (0.f, 0.5f, 1.f);
+    Triple axis_range (0.25f, 0.25f, 0.75f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 2);
+    assert (out[0].first == 0.5f);
+    assert (out[0].second == Triple ());
+    assert (out[1].first == 0.5f);
+    assert (out[1].second == Triple (0.f, 0.5f, 1.0f));
+  }
+
+  /* Case 1neg */
+  {
+    Triple tent (0.f, 0.5f, 1.f);
+    Triple axis_range (0.f, 0.25f, 0.5f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 3);
+    assert (out[0].first == 0.5f);
+    assert (out[0].second == Triple ());
+    assert (out[1].first == 0.5f);
+    assert (out[1].second == Triple (0.f, 1.f, 1.f));
+    assert (out[2].first == -0.5f);
+    assert (out[2].second == Triple (-1.f, -1.f, 0.f));
+  }
+
+  /* Case 2neg */
+  {
+    Triple tent (0.05f, 0.55f, 1.f);
+    Triple axis_range (0.f, 0.25f, 0.5f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 4);
+    assert (approx (out[0].first, 0.4f));
+    assert (out[0].second == Triple ());
+    assert (approx (out[1].first, 0.5f));
+    assert (out[1].second == Triple (0.f, 1.f, 1.f));
+    assert (approx (out[2].first, -0.4f));
+    assert (out[2].second == Triple (-1.f, -0.8f, 0.f));
+    assert (approx (out[3].first, -0.4f));
+    assert (out[3].second == Triple (-1.f, -1.f, -0.8f));
+  }
+
+  /* Case 2neg, other side */
+  {
+    Triple tent (-1.f, -0.55f, -0.05f);
+    Triple axis_range (-0.5f, -0.25f, 0.f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 4);
+    assert (approx (out[0].first, 0.4f));
+    assert (out[0].second == Triple ());
+    assert (approx (out[1].first, 0.5f));
+    assert (out[1].second == Triple (-1.f, -1.f, 0.f));
+    assert (approx (out[2].first, -0.4f));
+    assert (out[2].second == Triple (0.f, 0.8f, 1.f));
+    assert (approx (out[3].first, -0.4f));
+    assert (out[3].second == Triple (0.8f, 1.f, 1.f));
+  }
+
+  /* Misc corner cases */
+  {
+    Triple tent (0.5f, 0.5f, 0.5f);
+    Triple axis_range (0.5f, 0.5f, 0.5f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 1);
+    assert (out[0].first == 1.f);
+    assert (out[0].second == Triple ());
+  }
+
+  {
+    Triple tent (0.3f, 0.5f, 0.7f);
+    Triple axis_range (0.1f, 0.5f, 0.9f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 5);
+    assert (out[0].first == 1.f);
+    assert (out[0].second == Triple ());
+    assert (out[1].first == -1.f);
+    assert (out[1].second == Triple (0.f, 0.5f, 1.f));
+    assert (out[2].first == -1.f);
+    assert (out[2].second == Triple (0.5f, 1.f, 1.f));
+    assert (out[3].first == -1.f);
+    assert (approx (out[3].second, Triple (-1.f, -0.5f, 0.f)));
+    assert (out[4].first == -1.f);
+    assert (approx (out[4].second, Triple (-1.f, -1.f, -0.5f)));
+  }
+
+  {
+    Triple tent (0.5f, 0.5f, 0.5f);
+    Triple axis_range (0.25f, 0.25f, 0.5f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 1);
+    assert (out[0].first == 1.f);
+    assert (out[0].second == Triple (1.f, 1.f, 1.f));
+  }
+
+  {
+    Triple tent (0.5f, 0.5f, 0.5f);
+    Triple axis_range (0.25f, 0.35f, 0.5f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 1);
+    assert (out[0].first == 1.f);
+    assert (out[0].second == Triple (1.f, 1.f, 1.f));
+  }
+
+  {
+    Triple tent (0.5f, 0.5f, 0.55f);
+    Triple axis_range (0.25f, 0.35f, 0.5f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 1);
+    assert (out[0].first == 1.f);
+    assert (out[0].second == Triple (1.f, 1.f, 1.f));
+  }
+
+  {
+    Triple tent (0.5f, 0.5f, 1.f);
+    Triple axis_range (0.5f, 0.5f, 1.f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 2);
+    assert (out[0].first == 1.f);
+    assert (out[0].second == Triple ());
+    assert (out[1].first == -1.f);
+    assert (out[1].second == Triple (0.f, 1.f, 1.f));
+  }
+
+  {
+    Triple tent (0.25f, 0.5f, 1.f);
+    Triple axis_range (0.5f, 0.5f, 1.f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 2);
+    assert (out[0].first == 1.f);
+    assert (out[0].second == Triple ());
+    assert (out[1].first == -1.f);
+    assert (out[1].second == Triple (0.f, 1.f, 1.f));
+  }
+
+  {
+    Triple tent (0.f, 0.2f, 1.f);
+    Triple axis_range (0.f, 0.f, 0.5f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 1);
+    assert (out[0].first == 1.f);
+    assert (out[0].second == Triple (0.f, 0.4f, 32767/(float) (1 << 14)));
+  }
+
+
+  {
+    Triple tent (0.f, 0.5f, 1.f);
+    Triple axis_range (-1.f, 0.25f, 1.f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 5);
+    assert (out[0].first == 0.5f);
+    assert (out[0].second == Triple ());
+    assert (out[1].first == 0.5f);
+    assert (out[1].second == Triple (0.f, 1.f/3, 2.f/3));
+    assert (out[2].first == -0.5f);
+    assert (out[2].second == Triple (2.f/3, 1.f, 1.f));
+    assert (out[3].first == -0.5f);
+    assert (out[3].second == Triple (-1.f, -0.2f, 0.f));
+    assert (out[4].first == -0.5f);
+    assert (out[4].second == Triple (-1.f, -1.f, -0.2f));
+  }
+
+  {
+    Triple tent (0.5f, 0.5f, 0.5f);
+    Triple axis_range (0.f, 0.5f, 1.f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 5);
+    assert (out[0].first == 1.f);
+    assert (out[0].second == Triple ());
+    assert (out[1].first == -1.f);
+    assert (out[1].second == Triple (0.f, 2/(float) (1 << 14), 1.f));
+    assert (out[2].first == -1.f);
+    assert (out[2].second == Triple (2/(float) (1 << 14), 1.f, 1.f));
+    assert (out[3].first == -1.f);
+    assert (out[3].second == Triple (-1.f, -2/(float) (1 << 14), 0.f));
+    assert (out[4].first == -1.f);
+    assert (out[4].second == Triple (-1.f, -1.f, -2/(float) (1 << 14)));
+  }
+
+  {
+    Triple tent (0.f, 1.f, 1.f);
+    Triple axis_range (-1.f, -0.5f, 1.f);
+    result_t out = rebase_tent (tent, axis_range, default_axis_distances);
+    assert (out.length == 1);
+    assert (out[0].first == 1.f);
+    assert (out[0].second == Triple (1.f/3, 1.f, 1.f));
+  }
+
+  {
+    Triple tent (0.f, 1.f, 1.f);
+    Triple axis_range (-1.f, -0.5f, 1.f);
+    TripleDistances axis_distances{2.f, 1.f};
+    result_t out = rebase_tent (tent, axis_range, axis_distances);
+    assert (out.length == 1);
+    assert (out[0].first == 1.f);
+    assert (out[0].second == Triple (0.5f, 1.f, 1.f));
+  }
+}
+
diff --git a/src/test-tuple-varstore.cc b/src/test-tuple-varstore.cc
new file mode 100644 (file)
index 0000000..97fec25
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright © 2020  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.
+ *
+ */
+#include "hb-ot-var-cvar-table.hh"
+
+// cvar table data from Multi-ABC.ttf
+const char cvar_data[] = "\x0\x1\x0\x0\x0\x2\x0\x14\x0\x51\xa0\x0\xc0\x0\x0\x54\xa0\x0\x40\x0\x2a\x29\x17\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\xd\xff\x0\xfd\x1\x0\xff\x0\xfd\x1\x0\xdb\xdb\xe6\xe6\x82\x0\xfd\x84\x6\xfd\x0\x2\xe3\xe3\xec\xec\x82\x4\x1\xe3\xe3\xec\xec\x82\x0\x1\x2a\x29\x17\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\xd\x1\x0\x5\xfd\x0\x1\x0\x5\xfd\x0\x61\x61\x44\x44\x82\x0\x5\x81\x9\x1\xff\x1\x7\xff\xfb\x49\x49\x35\x35\x82\x4\xff\x49\x49\x35\x35\x82\x0\xff";
+
+static void
+test_decompile_cvar ()
+{
+  const OT::cvar* cvar_table = reinterpret_cast<const OT::cvar*> (cvar_data);
+  unsigned point_count = 65;
+  unsigned axis_count = 1;
+
+  hb_tag_t axis_tag = HB_TAG ('w', 'g', 'h', 't');
+  hb_map_t axis_idx_tag_map;
+  axis_idx_tag_map.set (0, axis_tag);
+
+  OT::TupleVariationData::tuple_variations_t tuple_variations;
+  hb_vector_t<unsigned> shared_indices;
+  OT::TupleVariationData::tuple_iterator_t iterator;
+
+  const OT::TupleVariationData* tuple_var_data = reinterpret_cast<const OT::TupleVariationData*> (cvar_data + 4);
+
+  unsigned len = sizeof (cvar_data);
+  hb_bytes_t var_data_bytes{cvar_data+4, len - 4};
+  bool result = OT::TupleVariationData::get_tuple_iterator (var_data_bytes, axis_count, cvar_table,
+                                                            shared_indices, &iterator);
+  assert (result);
+
+  result = tuple_var_data->decompile_tuple_variations (point_count, false, iterator, &axis_idx_tag_map,
+                                                       shared_indices, hb_array<const OT::F2DOT14> (),
+                                                       tuple_variations);
+
+  assert (result);
+  assert (tuple_variations.tuple_vars.length == 2);
+  for (unsigned i = 0; i < 2; i++)
+  {
+    assert (tuple_variations.tuple_vars[i].axis_tuples.get_population () == 1);
+    assert (!tuple_variations.tuple_vars[i].deltas_y);
+    assert (tuple_variations.tuple_vars[i].indices.length == 65);
+    assert (tuple_variations.tuple_vars[i].indices.length == tuple_variations.tuple_vars[i].deltas_x.length);
+  }
+  assert (tuple_variations.tuple_vars[0].axis_tuples.get (axis_tag) == Triple (-1.f, -1.f, 0.f));
+  assert (tuple_variations.tuple_vars[1].axis_tuples.get (axis_tag) == Triple (0.f, 1.f, 1.f));
+  
+  hb_vector_t<float> deltas_1 {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, -1.f, 0.f, -3.f, 1.f, 0.f, -1.f, 0.f, -3.f, 1.f, 0.f, -37.f, -37.f, -26.f, -26.f, 0.f, 0.f, 0.f, -3.f, 0.f, 0.f, 0.f, 0.f, 0.f, -3.f, 0.f, 2.f, -29.f, -29.f, -20.f, -20.f, 0.f, 0.f, 0.f, 1.f, -29.f, -29.f, -20.f, -20.f, 0.f, 0.f, 0.f, 1.f};
+  for (unsigned i = 0; i < 65; i++)
+  {
+    if (i < 23)
+      assert (tuple_variations.tuple_vars[0].indices[i] == 0);
+    else
+    {
+      assert (tuple_variations.tuple_vars[0].indices[i] == 1);
+      assert (tuple_variations.tuple_vars[0].deltas_x[i] == deltas_1[i]);
+    }
+  }
+
+  hb_vector_t<float> deltas_2 {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 5.f, -3.f, 0.f, 1.f, 0.f, 5.f, -3.f, 0.f, 97.f, 97.f, 68.f, 68.f, 0.f, 0.f, 0.f, 5.f, 0.f, 0.f, 1.f, -1.f, 1.f, 7.f, -1.f, -5.f, 73.f, 73.f, 53.f, 53.f, 0.f, 0.f, 0.f, -1.f, 73.f, 73.f, 53.f, 53.f, 0.f, 0.f, 0.f, -1.f};
+  for (unsigned i = 0 ; i < 65; i++)
+  {
+    if (i < 23)
+      assert (tuple_variations.tuple_vars[1].indices[i] == 0);
+    else
+    {
+      assert (tuple_variations.tuple_vars[1].indices[i] == 1);
+      assert (tuple_variations.tuple_vars[1].deltas_x[i] == deltas_2[i]);
+    }
+  }
+
+  /* partial instancing wght=300:800 */
+  hb_hashmap_t<hb_tag_t, Triple> normalized_axes_location;
+  normalized_axes_location.set (axis_tag, Triple (-0.512817f, 0.f, 0.700012f));
+
+  hb_hashmap_t<hb_tag_t, TripleDistances> axes_triple_distances;
+  axes_triple_distances.set (axis_tag, TripleDistances (1.f, 1.f));
+
+  tuple_variations.instantiate (normalized_axes_location, axes_triple_distances);
+
+  assert (tuple_variations.tuple_vars[0].indices.length == 65);
+  assert (tuple_variations.tuple_vars[1].indices.length == 65);
+  assert (!tuple_variations.tuple_vars[0].deltas_y);
+  assert (!tuple_variations.tuple_vars[1].deltas_y);
+  assert (tuple_variations.tuple_vars[0].axis_tuples.get (axis_tag) == Triple (-1.f, -1.f, 0.f));
+  assert (tuple_variations.tuple_vars[1].axis_tuples.get (axis_tag) == Triple (0.f, 1.f, 1.f));
+
+  hb_vector_t<float> rounded_deltas_1 {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, -1, 0.f, -2, 1, 0.f, -1, 0.f, -2, 1, 0.f, -19, -19, -13, -13, 0.f, 0.f, 0.f, -2, 0.f, 0.f, 0.f, 0.f, 0.f, -2, 0.f, 1, -15, -15, -10.f, -10.f, 0.f, 0.f, 0.f, 1, -15, -15, -10.f, -10.f, 0.f, 0.f, 0.f, 1};
+
+  hb_vector_t<float> rounded_deltas_2 {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1, 0.f, 4, -2, 0.f, 1, 0.f, 4, -2, 0.f, 68, 68, 48, 48, 0.f, 0.f, 0.f, 4, 0.f, 0.f, 1, -1, 1, 5, -1, -4, 51, 51, 37, 37, 0.f, 0.f, 0.f, -1, 51, 51, 37, 37, 0.f, 0.f, 0.f, -1};
+
+  for (unsigned i = 0; i < 65; i++)
+  {
+    if (i < 23)
+    {
+      assert (tuple_variations.tuple_vars[0].indices[i] == 0);
+      assert (tuple_variations.tuple_vars[1].indices[i] == 0);
+    }
+    else
+    {
+      assert (tuple_variations.tuple_vars[0].indices[i] == 1);
+      assert (tuple_variations.tuple_vars[1].indices[i] == 1);
+      assert (roundf (tuple_variations.tuple_vars[0].deltas_x[i]) == rounded_deltas_1[i]);
+      assert (roundf (tuple_variations.tuple_vars[1].deltas_x[i]) == rounded_deltas_2[i]);
+    }
+  }
+
+  hb_map_t axes_index_map;
+  axes_index_map.set (0, 0);
+  bool res = tuple_variations.compile_bytes (axes_index_map, axis_idx_tag_map, false);
+  assert (res);
+  assert (tuple_variations.tuple_vars[0].compiled_tuple_header.length == 6);
+  const char tuple_var_header_1[] = "\x0\x51\xa0\x0\xc0\x0";
+  for (unsigned i = 0; i < 6; i++)
+    assert(tuple_variations.tuple_vars[0].compiled_tuple_header.arrayZ[i] == tuple_var_header_1[i]);
+
+  assert (tuple_variations.tuple_vars[1].compiled_tuple_header.length == 6);
+  const char tuple_var_header_2[] = "\x0\x54\xa0\x0\x40\x0";
+  for (unsigned i = 0; i < 6; i++)
+    assert(tuple_variations.tuple_vars[1].compiled_tuple_header.arrayZ[i] == tuple_var_header_2[i]);
+
+  assert (tuple_variations.tuple_vars[0].compiled_deltas.length == 37);
+  assert (tuple_variations.tuple_vars[1].compiled_deltas.length == 40);
+  const char compiled_deltas_1[] = "\x0d\xff\x00\xfe\x01\x00\xff\x00\xfe\x01\x00\xed\xed\xf3\xf3\x82\x00\xfe\x84\x06\xfe\x00\x01\xf1\xf1\xf6\xf6\x82\x04\x01\xf1\xf1\xf6\xf6\x82\x00\x01";
+  for (unsigned i = 0; i < 37; i++)
+    assert (tuple_variations.tuple_vars[0].compiled_deltas.arrayZ[i] == compiled_deltas_1[i]);
+
+  const char compiled_deltas_2[] = "\x0d\x01\x00\x04\xfe\x00\x01\x00\x04\xfe\x00\x44\x44\x30\x30\x82\x00\x04\x81\x09\x01\xff\x01\x05\xff\xfc\x33\x33\x25\x25\x82\x04\xff\x33\x33\x25\x25\x82\x00\xff";
+  for (unsigned i = 0; i < 40; i++)
+    assert (tuple_variations.tuple_vars[1].compiled_deltas.arrayZ[i] == compiled_deltas_2[i]);
+}
+
+int
+main (int argc, char **argv)
+{
+  test_decompile_cvar ();
+}
index 33cac6b..27b5b9e 100644 (file)
@@ -32,7 +32,7 @@ test (hb_codepoint_t cp, unsigned int 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.",
+    fprintf (stderr, "got incorrect bit (%u) for cp 0x%X. Should have been %u.",
             OT::_hb_ot_os2_get_unicode_range_bit (cp),
             cp,
             bit);
diff --git a/src/test-use-table.cc b/src/test-use-table.cc
new file mode 100644 (file)
index 0000000..70d2d41
--- /dev/null
@@ -0,0 +1,18 @@
+#include "hb-ot-shaper-use-table.hh"
+
+int main (int argc, char **argv)
+{
+  if (argc != 2)
+  {
+    for (unsigned u = 0; u < 0x10FFFFu; u++)
+      printf ("U+%04X %d\n", u, hb_use_get_category (u));
+    return 0;
+  }
+
+  hb_codepoint_t u;
+  sscanf (argv[1], "%x", &u);
+
+  printf ("%d\n", hb_use_get_category (u));
+
+  return 0;
+}
index 521f2a1..cc8ceab 100644 (file)
 #include "hb.hh"
 #include "hb-vector.hh"
 #include "hb-set.hh"
+#include "hb-map.hh"
 #include <string>
 
 
 int
 main (int argc, char **argv)
 {
+  assert (sizeof (hb_vector_t<int>) == sizeof (hb_sorted_vector_t<int>));
 
   /* Test copy constructor. */
   {
@@ -61,8 +63,12 @@ main (int argc, char **argv)
 
   /* Test move constructor. */
   {
-    hb_vector_t<int> v {hb_vector_t<int> {1, 2}};
-    hb_vector_t<int> V {hb_vector_t<int> {1, 2}};
+    hb_vector_t<int> s {1, 2};
+    hb_sorted_vector_t<int> S {1, 2};
+    hb_vector_t<int> v (std::move (s));
+    hb_sorted_vector_t<int> V (std::move (S));
+    assert (s.length == 0);
+    assert (S.length == 0);
     assert (v.length == 2);
     assert (v[0] == 1);
     assert (v[1] == 2);
@@ -70,11 +76,16 @@ main (int argc, char **argv)
 
   /* Test move assignment. */
   {
+    hb_vector_t<int> s {1, 2};
+    hb_sorted_vector_t<int> S {1, 2};
     hb_vector_t<int> v;
     hb_sorted_vector_t<int> V;
-    v = hb_vector_t<int> {1, 2};
-    V = hb_sorted_vector_t<int> {1, 2};
+    v = std::move (s);
+    V = std::move (S);
+    assert (s.length == 0);
+    assert (S.length == 0);
     assert (v.length == 2);
+    assert (V.length == 2);
     assert (v[0] == 1);
     assert (v[1] == 2);
   }
@@ -137,7 +148,6 @@ main (int argc, char **argv)
     assert (v2[2] == 3);
   }
 
-#if 0
   {
     hb_vector_t<std::string> v;
 
@@ -147,8 +157,35 @@ main (int argc, char **argv)
       s += "x";
       v.push (s);
     }
+
+    hb_vector_t<std::string> v2;
+
+    v2 = v;
+
+    v2.remove_ordered (50);
+    v2.remove_unordered (50);
+  }
+
+  {
+    hb_vector_t<hb_set_t> v;
+    hb_set_t s {1, 5, 7};
+    v.push (s);
+    v << s;
+    assert (s.get_population () == 3);
+    v << std::move (s);
+    assert (s.get_population () == 0);
+  }
+
+  {
+    hb_vector_t<hb_map_t> v;
+    hb_map_t m;
+    v.push (m);
+  }
+  {
+    hb_vector_t<hb_map_t> v;
+    hb_map_t m;
+    v.push (m);
   }
-#endif
 
   return 0;
 }
index d848cf1..f7e4e7e 100644 (file)
@@ -75,7 +75,7 @@ main (int argc, char **argv)
     hb_glyph_info_t *info = &infos[i];
     hb_glyph_position_t *pos = &positions[i];
 
-    printf ("cluster %d        glyph 0x%x at   (%d,%d)+(%d,%d)\n",
+    printf ("cluster %u        glyph 0x%x at   (%d,%d)+(%d,%d)\n",
            info->cluster,
            info->codepoint,
            pos->x_offset,
index 7a7d18c..36e8043 100644 (file)
@@ -2,7 +2,7 @@
 directory=cairo
 url=https://gitlab.freedesktop.org/cairo/cairo.git
 depth=1
-revision=1.17.4
+revision=1.17.8
 
 [provide]
-dependency_names = cairo, cairo-ft
+dependency_names = cairo
index cf8f307..fe325d8 100644 (file)
@@ -1,7 +1,10 @@
-[wrap-git]
-directory=freetype
-url=https://gitlab.freedesktop.org/freetype/freetype.git
-revision=VER-2-11-0
+[wrap-file]
+directory = freetype-2.13.0
+source_url = https://download.savannah.gnu.org/releases/freetype/freetype-2.13.0.tar.xz
+source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/freetype2_2.13.0-1/freetype-2.13.0.tar.xz
+source_filename = freetype-2.13.0.tar.xz
+source_hash = 5ee23abd047636c24b2d43c6625dcafc66661d1aca64dec9e0d05df29592624c
 
 [provide]
 freetype2 = freetype_dep
+freetype = freetype_dep
index 9143090..2ea0dbf 100644 (file)
@@ -1,10 +1,11 @@
-[wrap-git]
-directory=glib
-url=https://gitlab.gnome.org/GNOME/glib.git
-depth=1
-push-url=git@gitlab.gnome.org:GNOME/glib.git
-revision=2.58.1
+[wrap-file]
+directory = glib-2.74.4
+source_url = https://download.gnome.org/sources/glib/2.74/glib-2.74.4.tar.xz
+source_fallback_url = https://ftp.acc.umu.se/pub/gnome/sources/glib/2.74/glib-2.74.4.tar.xz
+source_filename = glib-2.74.4.tar.xz
+source_hash = 0e82da5ea129b4444227c7e4a9e598f7288d1994bf63f129c44b90cfd2432172
+wrapdb_version = 2.74.4-1
 
 [provide]
-glib-2.0 = libglib_dep
-gobject-2.0 = libgobject_dep
+dependency_names = gthread-2.0, gobject-2.0, gmodule-no-export-2.0, gmodule-export-2.0, gmodule-2.0, glib-2.0, gio-2.0, gio-windows-2.0, gio-unix-2.0
+program_names = glib-genmarshal, glib-mkenums, glib-compile-schemas, glib-compile-resources, gio-querymodules, gdbus-codegen
index 876927d..6205cd7 100644 (file)
@@ -1,9 +1,12 @@
 [wrap-file]
-directory = benchmark-1.5.2
-source_url = https://github.com/google/benchmark/archive/v1.5.2.zip
-source_filename = benchmark-1.5.2.zip
-source_hash = 21e6e096c9a9a88076b46bd38c33660f565fa050ca427125f64c4a8bf60f336b
-patch_url = https://wrapdb.mesonbuild.com/v1/projects/google-benchmark/1.5.2/1/get_zip
-patch_filename = google-benchmark-1.5.2-1-wrap.zip
-patch_hash = 49f41e4a7e68ac258b6509b9de9857441903be4fb473454c4cba8be885f0c6c3
+directory = benchmark-1.7.1
+source_url = https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+source_filename = benchmark-1.7.1.tar.gz
+source_hash = 6430e4092653380d9dc4ccb45a1e2dc9259d581f4866dc0759713126056bc1d7
+patch_filename = google-benchmark_1.7.1-1_patch.zip
+patch_url = https://wrapdb.mesonbuild.com/v2/google-benchmark_1.7.1-1/get_patch
+patch_hash = 9c6694328ac971cd781aa67c45c64291c087f118e23b75946f52670caacf49b7
+wrapdb_version = 1.7.1-1
 
+[provide]
+benchmark = google_benchmark_dep
index cd317c2..4123ef2 100644 (file)
@@ -1,7 +1,15 @@
 project('ragel', 'c', 'cpp',
-  version : '6.10'
+  version : '6.10',
+  default_options: [
+    'cpp_eh=default',
+  ],
 )
 
+cpp = meson.get_compiler('cpp')
+add_project_arguments(cpp.get_supported_arguments([
+  '-fexceptions',
+]), language: 'cpp')
+
 conf = configuration_data()
 conf.set_quoted('PACKAGE', meson.project_name())
 conf.set_quoted('VERSION', meson.project_version())
diff --git a/subprojects/ttf-parser.wrap b/subprojects/ttf-parser.wrap
deleted file mode 100644 (file)
index 11cda54..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-[wrap-git]
-directory=ttf-parser
-url=https://github.com/RazrFalcon/ttf-parser.git
-depth=1
-revision=master
index 01d542a..a945055 100644 (file)
@@ -1,8 +1,8 @@
 # Process this file with automake to produce Makefile.in
 
 NULL =
-EXTRA_DIST =
-SUBDIRS = api shape subset fuzzing
+EXTRA_DIST = COPYING
+SUBDIRS = api shape subset fuzzing threads
 
 EXTRA_DIST += \
        meson.build \
index b3e97a2..9d0f0ca 100644 (file)
@@ -160,7 +160,7 @@ am__define_uniq_tagged_files = \
 ETAGS = etags
 CTAGS = ctags
 DIST_SUBDIRS = $(SUBDIRS)
-am__DIST_COMMON = $(srcdir)/Makefile.in
+am__DIST_COMMON = $(srcdir)/Makefile.in COPYING
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -221,8 +221,6 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
-DIRECTWRITE_CXXFLAGS = @DIRECTWRITE_CXXFLAGS@
-DIRECTWRITE_LIBS = @DIRECTWRITE_LIBS@
 DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -320,6 +318,8 @@ STRIP = @STRIP@
 UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
 UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
 VERSION = @VERSION@
+WASM_CFLAGS = @WASM_CFLAGS@
+WASM_LIBS = @WASM_LIBS@
 _GI_EXP_DATADIR = @_GI_EXP_DATADIR@
 _GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@
 abs_builddir = @abs_builddir@
@@ -379,8 +379,8 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 NULL = 
-EXTRA_DIST = meson.build $(NULL)
-SUBDIRS = api shape subset fuzzing
+EXTRA_DIST = COPYING meson.build $(NULL)
+SUBDIRS = api shape subset fuzzing threads
 all: all-recursive
 
 .SUFFIXES:
index 883464c..efeecb4 100644 (file)
@@ -14,7 +14,10 @@ libs:
 
 EXTRA_DIST += meson.build
 
-EXTRA_DIST += fonts
+EXTRA_DIST += \
+       fonts \
+       results \
+       $(NULL)
 
 LINK = $(CXXLINK)
 
@@ -30,6 +33,9 @@ noinst_PROGRAMS = $(TEST_PROGS)
 TEST_PROGS = \
        test-aat-layout \
        test-baseline \
+       test-base-minmax \
+       test-be-glyph-advance \
+       test-be-num-glyphs \
        test-blob \
        test-buffer \
        test-c \
@@ -37,8 +43,11 @@ TEST_PROGS = \
        test-cplusplus \
        test-common \
        test-draw \
+       test-extents \
        test-font \
        test-font-scale \
+       test-glyph-names \
+       test-instance-cff2 \
        test-map \
        test-object \
        test-ot-alternates \
@@ -54,6 +63,7 @@ TEST_PROGS = \
        test-ot-tag \
        test-ot-extents-cff \
        test-ot-metrics-tt-var \
+       test-paint \
        test-set \
        test-shape \
        test-style \
@@ -76,11 +86,19 @@ TEST_PROGS = \
        test-subset-gpos \
        test-subset-colr \
        test-subset-cbdt \
+       test-subset-repacker \
        test-unicode \
        test-var-coords \
        test-version \
        $(NULL)
 
+test_draw_CPPFLAGS = $(AM_CPPFLAGS)
+test_draw_LDADD = $(LDADD)
+
+test_paint_CPPFLAGS = $(AM_CPPFLAGS)
+test_paint_LDADD = $(LDADD)
+
+test_instance_cff2_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 test_subset_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 test_subset_cmap_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 test_subset_drop_tables_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
@@ -100,6 +118,7 @@ test_subset_cbdt_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 test_subset_nameids_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 test_subset_gpos_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 test_subset_colr_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
+test_subset_repacker_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 
 test_unicode_CPPFLAGS = \
        $(AM_CPPFLAGS) \
@@ -123,13 +142,29 @@ endif
 endif
 
 if HAVE_FREETYPE
+test_draw_CPPFLAGS += $(FREETYPE_CFLAGS)
+test_draw_LDADD += $(FREETYPE_LIBS)
+
+test_paint_CPPFLAGS += $(FREETYPE_CFLAGS)
+test_paint_LDADD += $(FREETYPE_LIBS)
+
 TEST_PROGS += \
        test-ot-math \
+       test-ft \
        $(NULL)
 test_ot_math_LDADD = $(LDADD) $(FREETYPE_LIBS)
 test_ot_math_CPPFLAGS = $(AM_CPPFLAGS) $(FREETYPE_CFLAGS)
+
+test_ft_LDADD = $(LDADD) $(FREETYPE_LIBS)
+test_ft_CPPFLAGS = $(AM_CPPFLAGS) $(FREETYPE_CFLAGS)
 endif # HAVE_FREETYPE
 
+if HAVE_CORETEXT
+TEST_PROGS += \
+       test-coretext \
+       $(NULL)
+endif # HAVE_CORETEXT
+
 # Tests for header compilation
 test_cplusplus_SOURCES = test-cplusplus.cc
 test_c_CPPFLAGS = $(AM_CPPFLAGS)
index b02077f..6bc8629 100644 (file)
@@ -91,22 +91,31 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 @HAVE_GLIB_TRUE@am__append_1 = hb-test.h hb-subset-test.h
-@HAVE_GLIB_TRUE@check_PROGRAMS = $(am__EXEEXT_4)
-@HAVE_GLIB_TRUE@noinst_PROGRAMS = $(am__EXEEXT_4)
+@HAVE_GLIB_TRUE@check_PROGRAMS = $(am__EXEEXT_5)
+@HAVE_GLIB_TRUE@noinst_PROGRAMS = $(am__EXEEXT_5)
 @HAVE_GLIB_TRUE@@HAVE_ICU_TRUE@am__append_2 = $(ICU_CFLAGS)
 @HAVE_GLIB_TRUE@@HAVE_ICU_TRUE@am__append_3 = $(top_builddir)/src/libharfbuzz-icu.la $(ICU_LIBS)
 @HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@@HAVE_PTHREAD_TRUE@am__append_4 = test-multithread
-@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am__append_5 = \
+@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am__append_5 = $(FREETYPE_CFLAGS)
+@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am__append_6 = $(FREETYPE_LIBS)
+@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am__append_7 = $(FREETYPE_CFLAGS)
+@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am__append_8 = $(FREETYPE_LIBS)
+@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am__append_9 = \
 @HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@   test-ot-math \
+@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@   test-ft \
 @HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@   $(NULL)
 
-@HAVE_GLIB_TRUE@@HAVE_ICU_TRUE@am__append_6 = $(ICU_CFLAGS)
-@HAVE_GLIB_TRUE@@HAVE_ICU_TRUE@am__append_7 = $(ICU_CFLAGS)
-@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am__append_8 = $(FREETYPE_CFLAGS)
-@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am__append_9 = $(FREETYPE_CFLAGS)
-@HAVE_GLIB_TRUE@TESTS = $(am__EXEEXT_4)
+@HAVE_CORETEXT_TRUE@@HAVE_GLIB_TRUE@am__append_10 = \
+@HAVE_CORETEXT_TRUE@@HAVE_GLIB_TRUE@   test-coretext \
+@HAVE_CORETEXT_TRUE@@HAVE_GLIB_TRUE@   $(NULL)
+
+@HAVE_GLIB_TRUE@@HAVE_ICU_TRUE@am__append_11 = $(ICU_CFLAGS)
+@HAVE_GLIB_TRUE@@HAVE_ICU_TRUE@am__append_12 = $(ICU_CFLAGS)
+@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am__append_13 = $(FREETYPE_CFLAGS)
+@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am__append_14 = $(FREETYPE_CFLAGS)
+@HAVE_GLIB_TRUE@TESTS = $(am__EXEEXT_5)
 #      Can't do for now: --show-reachable=yes
-@HAVE_GLIB_TRUE@am__append_10 = log-valgrind.txt symbols-tested.txt \
+@HAVE_GLIB_TRUE@am__append_15 = log-valgrind.txt symbols-tested.txt \
 @HAVE_GLIB_TRUE@       symbols-exported.txt symbols-untested.txt \
 @HAVE_GLIB_TRUE@       symbols-tested-or-deprecated.txt
 subdir = test/api
@@ -129,14 +138,23 @@ am__EXEEXT_1 =
 @HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@@HAVE_PTHREAD_TRUE@am__EXEEXT_2 = test-multithread$(EXEEXT)
 @HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am__EXEEXT_3 =  \
 @HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@   test-ot-math$(EXEEXT) \
+@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@   test-ft$(EXEEXT) \
 @HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@   $(am__EXEEXT_1)
-@HAVE_GLIB_TRUE@am__EXEEXT_4 = test-aat-layout$(EXEEXT) \
-@HAVE_GLIB_TRUE@       test-baseline$(EXEEXT) test-blob$(EXEEXT) \
+@HAVE_CORETEXT_TRUE@@HAVE_GLIB_TRUE@am__EXEEXT_4 =  \
+@HAVE_CORETEXT_TRUE@@HAVE_GLIB_TRUE@   test-coretext$(EXEEXT) \
+@HAVE_CORETEXT_TRUE@@HAVE_GLIB_TRUE@   $(am__EXEEXT_1)
+@HAVE_GLIB_TRUE@am__EXEEXT_5 = test-aat-layout$(EXEEXT) \
+@HAVE_GLIB_TRUE@       test-baseline$(EXEEXT) \
+@HAVE_GLIB_TRUE@       test-base-minmax$(EXEEXT) \
+@HAVE_GLIB_TRUE@       test-be-glyph-advance$(EXEEXT) \
+@HAVE_GLIB_TRUE@       test-be-num-glyphs$(EXEEXT) test-blob$(EXEEXT) \
 @HAVE_GLIB_TRUE@       test-buffer$(EXEEXT) test-c$(EXEEXT) \
 @HAVE_GLIB_TRUE@       test-collect-unicodes$(EXEEXT) \
 @HAVE_GLIB_TRUE@       test-cplusplus$(EXEEXT) test-common$(EXEEXT) \
-@HAVE_GLIB_TRUE@       test-draw$(EXEEXT) test-font$(EXEEXT) \
-@HAVE_GLIB_TRUE@       test-font-scale$(EXEEXT) test-map$(EXEEXT) \
+@HAVE_GLIB_TRUE@       test-draw$(EXEEXT) test-extents$(EXEEXT) \
+@HAVE_GLIB_TRUE@       test-font$(EXEEXT) test-font-scale$(EXEEXT) \
+@HAVE_GLIB_TRUE@       test-glyph-names$(EXEEXT) \
+@HAVE_GLIB_TRUE@       test-instance-cff2$(EXEEXT) test-map$(EXEEXT) \
 @HAVE_GLIB_TRUE@       test-object$(EXEEXT) \
 @HAVE_GLIB_TRUE@       test-ot-alternates$(EXEEXT) \
 @HAVE_GLIB_TRUE@       test-ot-color$(EXEEXT) \
@@ -149,9 +167,9 @@ am__EXEEXT_1 =
 @HAVE_GLIB_TRUE@       test-ot-tag$(EXEEXT) \
 @HAVE_GLIB_TRUE@       test-ot-extents-cff$(EXEEXT) \
 @HAVE_GLIB_TRUE@       test-ot-metrics-tt-var$(EXEEXT) \
-@HAVE_GLIB_TRUE@       test-set$(EXEEXT) test-shape$(EXEEXT) \
-@HAVE_GLIB_TRUE@       test-style$(EXEEXT) test-subset$(EXEEXT) \
-@HAVE_GLIB_TRUE@       test-subset-cmap$(EXEEXT) \
+@HAVE_GLIB_TRUE@       test-paint$(EXEEXT) test-set$(EXEEXT) \
+@HAVE_GLIB_TRUE@       test-shape$(EXEEXT) test-style$(EXEEXT) \
+@HAVE_GLIB_TRUE@       test-subset$(EXEEXT) test-subset-cmap$(EXEEXT) \
 @HAVE_GLIB_TRUE@       test-subset-drop-tables$(EXEEXT) \
 @HAVE_GLIB_TRUE@       test-subset-glyf$(EXEEXT) \
 @HAVE_GLIB_TRUE@       test-subset-hdmx$(EXEEXT) \
@@ -169,9 +187,11 @@ am__EXEEXT_1 =
 @HAVE_GLIB_TRUE@       test-subset-gpos$(EXEEXT) \
 @HAVE_GLIB_TRUE@       test-subset-colr$(EXEEXT) \
 @HAVE_GLIB_TRUE@       test-subset-cbdt$(EXEEXT) \
+@HAVE_GLIB_TRUE@       test-subset-repacker$(EXEEXT) \
 @HAVE_GLIB_TRUE@       test-unicode$(EXEEXT) test-var-coords$(EXEEXT) \
 @HAVE_GLIB_TRUE@       test-version$(EXEEXT) $(am__EXEEXT_1) \
-@HAVE_GLIB_TRUE@       $(am__EXEEXT_2) $(am__EXEEXT_3)
+@HAVE_GLIB_TRUE@       $(am__EXEEXT_2) $(am__EXEEXT_3) \
+@HAVE_GLIB_TRUE@       $(am__EXEEXT_4)
 PROGRAMS = $(noinst_PROGRAMS)
 test_aat_layout_SOURCES = test-aat-layout.c
 test_aat_layout_OBJECTS = test-aat-layout.$(OBJEXT)
@@ -184,12 +204,30 @@ AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
 am__v_lt_0 = --silent
 am__v_lt_1 = 
+test_base_minmax_SOURCES = test-base-minmax.c
+test_base_minmax_OBJECTS = test-base-minmax.$(OBJEXT)
+test_base_minmax_LDADD = $(LDADD)
+@HAVE_GLIB_TRUE@test_base_minmax_DEPENDENCIES =  \
+@HAVE_GLIB_TRUE@       $(top_builddir)/src/libharfbuzz.la \
+@HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_1)
 test_baseline_SOURCES = test-baseline.c
 test_baseline_OBJECTS = test-baseline.$(OBJEXT)
 test_baseline_LDADD = $(LDADD)
 @HAVE_GLIB_TRUE@test_baseline_DEPENDENCIES =  \
 @HAVE_GLIB_TRUE@       $(top_builddir)/src/libharfbuzz.la \
 @HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_1)
+test_be_glyph_advance_SOURCES = test-be-glyph-advance.c
+test_be_glyph_advance_OBJECTS = test-be-glyph-advance.$(OBJEXT)
+test_be_glyph_advance_LDADD = $(LDADD)
+@HAVE_GLIB_TRUE@test_be_glyph_advance_DEPENDENCIES =  \
+@HAVE_GLIB_TRUE@       $(top_builddir)/src/libharfbuzz.la \
+@HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_1)
+test_be_num_glyphs_SOURCES = test-be-num-glyphs.c
+test_be_num_glyphs_OBJECTS = test-be-num-glyphs.$(OBJEXT)
+test_be_num_glyphs_LDADD = $(LDADD)
+@HAVE_GLIB_TRUE@test_be_num_glyphs_DEPENDENCIES =  \
+@HAVE_GLIB_TRUE@       $(top_builddir)/src/libharfbuzz.la \
+@HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_1)
 test_blob_SOURCES = test-blob.c
 test_blob_OBJECTS = test-blob.$(OBJEXT)
 test_blob_LDADD = $(LDADD)
@@ -220,6 +258,12 @@ test_common_LDADD = $(LDADD)
 @HAVE_GLIB_TRUE@test_common_DEPENDENCIES =  \
 @HAVE_GLIB_TRUE@       $(top_builddir)/src/libharfbuzz.la \
 @HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_1)
+test_coretext_SOURCES = test-coretext.c
+test_coretext_OBJECTS = test-coretext.$(OBJEXT)
+test_coretext_LDADD = $(LDADD)
+@HAVE_GLIB_TRUE@test_coretext_DEPENDENCIES =  \
+@HAVE_GLIB_TRUE@       $(top_builddir)/src/libharfbuzz.la \
+@HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_1)
 am__test_cplusplus_SOURCES_DIST = test-cplusplus.cc
 @HAVE_GLIB_TRUE@am_test_cplusplus_OBJECTS =  \
 @HAVE_GLIB_TRUE@       test_cplusplus-test-cplusplus.$(OBJEXT)
@@ -229,9 +273,18 @@ test_cplusplus_LDADD = $(LDADD)
 @HAVE_GLIB_TRUE@       $(top_builddir)/src/libharfbuzz.la \
 @HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_1)
 test_draw_SOURCES = test-draw.c
-test_draw_OBJECTS = test-draw.$(OBJEXT)
-test_draw_LDADD = $(LDADD)
-@HAVE_GLIB_TRUE@test_draw_DEPENDENCIES =  \
+test_draw_OBJECTS = test_draw-test-draw.$(OBJEXT)
+@HAVE_GLIB_TRUE@am__DEPENDENCIES_2 =  \
+@HAVE_GLIB_TRUE@       $(top_builddir)/src/libharfbuzz.la \
+@HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_1)
+@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am__DEPENDENCIES_3 =  \
+@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@   $(am__DEPENDENCIES_1)
+@HAVE_GLIB_TRUE@test_draw_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+@HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_3)
+test_extents_SOURCES = test-extents.c
+test_extents_OBJECTS = test-extents.$(OBJEXT)
+test_extents_LDADD = $(LDADD)
+@HAVE_GLIB_TRUE@test_extents_DEPENDENCIES =  \
 @HAVE_GLIB_TRUE@       $(top_builddir)/src/libharfbuzz.la \
 @HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_1)
 test_font_SOURCES = test-font.c
@@ -246,6 +299,22 @@ test_font_scale_LDADD = $(LDADD)
 @HAVE_GLIB_TRUE@test_font_scale_DEPENDENCIES =  \
 @HAVE_GLIB_TRUE@       $(top_builddir)/src/libharfbuzz.la \
 @HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_1)
+test_ft_SOURCES = test-ft.c
+test_ft_OBJECTS = test_ft-test-ft.$(OBJEXT)
+@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@test_ft_DEPENDENCIES =  \
+@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@   $(am__DEPENDENCIES_2) \
+@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@   $(am__DEPENDENCIES_1)
+test_glyph_names_SOURCES = test-glyph-names.c
+test_glyph_names_OBJECTS = test-glyph-names.$(OBJEXT)
+test_glyph_names_LDADD = $(LDADD)
+@HAVE_GLIB_TRUE@test_glyph_names_DEPENDENCIES =  \
+@HAVE_GLIB_TRUE@       $(top_builddir)/src/libharfbuzz.la \
+@HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_1)
+test_instance_cff2_SOURCES = test-instance-cff2.c
+test_instance_cff2_OBJECTS = test-instance-cff2.$(OBJEXT)
+@HAVE_GLIB_TRUE@test_instance_cff2_DEPENDENCIES =  \
+@HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_2) \
+@HAVE_GLIB_TRUE@       $(top_builddir)/src/libharfbuzz-subset.la
 test_map_SOURCES = test-map.c
 test_map_OBJECTS = test-map.$(OBJEXT)
 test_map_LDADD = $(LDADD)
@@ -255,9 +324,6 @@ test_map_LDADD = $(LDADD)
 test_multithread_SOURCES = test-multithread.c
 test_multithread_OBJECTS =  \
        test_multithread-test-multithread.$(OBJEXT)
-@HAVE_GLIB_TRUE@am__DEPENDENCIES_2 =  \
-@HAVE_GLIB_TRUE@       $(top_builddir)/src/libharfbuzz.la \
-@HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_1)
 @HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@@HAVE_PTHREAD_TRUE@test_multithread_DEPENDENCIES = $(am__DEPENDENCIES_2) \
 @HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@@HAVE_PTHREAD_TRUE@        $(am__DEPENDENCIES_1) \
 @HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@@HAVE_PTHREAD_TRUE@        $(am__DEPENDENCIES_1)
@@ -350,6 +416,10 @@ test_ot_tag_LDADD = $(LDADD)
 @HAVE_GLIB_TRUE@test_ot_tag_DEPENDENCIES =  \
 @HAVE_GLIB_TRUE@       $(top_builddir)/src/libharfbuzz.la \
 @HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_1)
+test_paint_SOURCES = test-paint.c
+test_paint_OBJECTS = test_paint-test-paint.$(OBJEXT)
+@HAVE_GLIB_TRUE@test_paint_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+@HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_3)
 test_set_SOURCES = test-set.c
 test_set_OBJECTS = test-set.$(OBJEXT)
 test_set_LDADD = $(LDADD)
@@ -434,6 +504,11 @@ test_subset_post_SOURCES = test-subset-post.c
 test_subset_post_OBJECTS = test-subset-post.$(OBJEXT)
 @HAVE_GLIB_TRUE@test_subset_post_DEPENDENCIES = $(am__DEPENDENCIES_2) \
 @HAVE_GLIB_TRUE@       $(top_builddir)/src/libharfbuzz-subset.la
+test_subset_repacker_SOURCES = test-subset-repacker.c
+test_subset_repacker_OBJECTS = test-subset-repacker.$(OBJEXT)
+@HAVE_GLIB_TRUE@test_subset_repacker_DEPENDENCIES =  \
+@HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_2) \
+@HAVE_GLIB_TRUE@       $(top_builddir)/src/libharfbuzz-subset.la
 test_subset_sbix_SOURCES = test-subset-sbix.c
 test_subset_sbix_OBJECTS = test-subset-sbix.$(OBJEXT)
 @HAVE_GLIB_TRUE@test_subset_sbix_DEPENDENCIES = $(am__DEPENDENCIES_2) \
@@ -448,10 +523,10 @@ test_subset_vvar_OBJECTS = test-subset-vvar.$(OBJEXT)
 @HAVE_GLIB_TRUE@       $(top_builddir)/src/libharfbuzz-subset.la
 test_unicode_SOURCES = test-unicode.c
 test_unicode_OBJECTS = test_unicode-test-unicode.$(OBJEXT)
-@HAVE_GLIB_TRUE@@HAVE_ICU_TRUE@am__DEPENDENCIES_3 = $(top_builddir)/src/libharfbuzz-icu.la \
+@HAVE_GLIB_TRUE@@HAVE_ICU_TRUE@am__DEPENDENCIES_4 = $(top_builddir)/src/libharfbuzz-icu.la \
 @HAVE_GLIB_TRUE@@HAVE_ICU_TRUE@        $(am__DEPENDENCIES_1)
 @HAVE_GLIB_TRUE@test_unicode_DEPENDENCIES = $(am__DEPENDENCIES_2) \
-@HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_3)
+@HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_4)
 test_var_coords_SOURCES = test-var-coords.c
 test_var_coords_OBJECTS = test-var-coords.$(OBJEXT)
 test_var_coords_LDADD = $(LDADD)
@@ -480,13 +555,16 @@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
 depcomp = $(SHELL) $(top_srcdir)/depcomp
 am__maybe_remake_depfiles = depfiles
 am__depfiles_remade = ./$(DEPDIR)/test-aat-layout.Po \
-       ./$(DEPDIR)/test-baseline.Po ./$(DEPDIR)/test-blob.Po \
+       ./$(DEPDIR)/test-base-minmax.Po ./$(DEPDIR)/test-baseline.Po \
+       ./$(DEPDIR)/test-be-glyph-advance.Po \
+       ./$(DEPDIR)/test-be-num-glyphs.Po ./$(DEPDIR)/test-blob.Po \
        ./$(DEPDIR)/test-buffer.Po \
        ./$(DEPDIR)/test-collect-unicodes.Po \
-       ./$(DEPDIR)/test-common.Po ./$(DEPDIR)/test-draw.Po \
-       ./$(DEPDIR)/test-font-scale.Po ./$(DEPDIR)/test-font.Po \
-       ./$(DEPDIR)/test-map.Po ./$(DEPDIR)/test-object.Po \
-       ./$(DEPDIR)/test-ot-alternates.Po \
+       ./$(DEPDIR)/test-common.Po ./$(DEPDIR)/test-coretext.Po \
+       ./$(DEPDIR)/test-extents.Po ./$(DEPDIR)/test-font-scale.Po \
+       ./$(DEPDIR)/test-font.Po ./$(DEPDIR)/test-glyph-names.Po \
+       ./$(DEPDIR)/test-instance-cff2.Po ./$(DEPDIR)/test-map.Po \
+       ./$(DEPDIR)/test-object.Po ./$(DEPDIR)/test-ot-alternates.Po \
        ./$(DEPDIR)/test-ot-collect-glyphs.Po \
        ./$(DEPDIR)/test-ot-color.Po \
        ./$(DEPDIR)/test-ot-extents-cff.Po ./$(DEPDIR)/test-ot-face.Po \
@@ -511,14 +589,18 @@ am__depfiles_remade = ./$(DEPDIR)/test-aat-layout.Po \
        ./$(DEPDIR)/test-subset-hvar.Po \
        ./$(DEPDIR)/test-subset-nameids.Po \
        ./$(DEPDIR)/test-subset-os2.Po ./$(DEPDIR)/test-subset-post.Po \
+       ./$(DEPDIR)/test-subset-repacker.Po \
        ./$(DEPDIR)/test-subset-sbix.Po \
        ./$(DEPDIR)/test-subset-vmtx.Po \
        ./$(DEPDIR)/test-subset-vvar.Po ./$(DEPDIR)/test-subset.Po \
        ./$(DEPDIR)/test-var-coords.Po ./$(DEPDIR)/test-version.Po \
        ./$(DEPDIR)/test_c-test-c.Po \
        ./$(DEPDIR)/test_cplusplus-test-cplusplus.Po \
+       ./$(DEPDIR)/test_draw-test-draw.Po \
+       ./$(DEPDIR)/test_ft-test-ft.Po \
        ./$(DEPDIR)/test_multithread-test-multithread.Po \
        ./$(DEPDIR)/test_ot_math-test-ot-math.Po \
+       ./$(DEPDIR)/test_paint-test-paint.Po \
        ./$(DEPDIR)/test_unicode-test-unicode.Po
 am__mv = mv -f
 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
@@ -554,40 +636,48 @@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
 am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
 am__v_CXXLD_0 = @echo "  CXXLD   " $@;
 am__v_CXXLD_1 = 
-SOURCES = test-aat-layout.c test-baseline.c test-blob.c test-buffer.c \
-       test-c.c test-collect-unicodes.c test-common.c \
-       $(test_cplusplus_SOURCES) test-draw.c test-font.c \
-       test-font-scale.c test-map.c test-multithread.c test-object.c \
-       test-ot-alternates.c test-ot-collect-glyphs.c test-ot-color.c \
-       test-ot-extents-cff.c test-ot-face.c test-ot-glyphname.c \
-       test-ot-layout.c test-ot-ligature-carets.c test-ot-math.c \
-       test-ot-meta.c test-ot-metrics.c test-ot-metrics-tt-var.c \
-       test-ot-name.c test-ot-tag.c test-set.c test-shape.c \
+SOURCES = test-aat-layout.c test-base-minmax.c test-baseline.c \
+       test-be-glyph-advance.c test-be-num-glyphs.c test-blob.c \
+       test-buffer.c test-c.c test-collect-unicodes.c test-common.c \
+       test-coretext.c $(test_cplusplus_SOURCES) test-draw.c \
+       test-extents.c test-font.c test-font-scale.c test-ft.c \
+       test-glyph-names.c test-instance-cff2.c test-map.c \
+       test-multithread.c test-object.c test-ot-alternates.c \
+       test-ot-collect-glyphs.c test-ot-color.c test-ot-extents-cff.c \
+       test-ot-face.c test-ot-glyphname.c test-ot-layout.c \
+       test-ot-ligature-carets.c test-ot-math.c test-ot-meta.c \
+       test-ot-metrics.c test-ot-metrics-tt-var.c test-ot-name.c \
+       test-ot-tag.c test-paint.c test-set.c test-shape.c \
        test-style.c test-subset.c test-subset-cbdt.c \
        test-subset-cff1.c test-subset-cff2.c test-subset-cmap.c \
        test-subset-colr.c test-subset-drop-tables.c \
        test-subset-glyf.c test-subset-gpos.c test-subset-gvar.c \
        test-subset-hdmx.c test-subset-hmtx.c test-subset-hvar.c \
        test-subset-nameids.c test-subset-os2.c test-subset-post.c \
-       test-subset-sbix.c test-subset-vmtx.c test-subset-vvar.c \
-       test-unicode.c test-var-coords.c test-version.c
-DIST_SOURCES = test-aat-layout.c test-baseline.c test-blob.c \
+       test-subset-repacker.c test-subset-sbix.c test-subset-vmtx.c \
+       test-subset-vvar.c test-unicode.c test-var-coords.c \
+       test-version.c
+DIST_SOURCES = test-aat-layout.c test-base-minmax.c test-baseline.c \
+       test-be-glyph-advance.c test-be-num-glyphs.c test-blob.c \
        test-buffer.c test-c.c test-collect-unicodes.c test-common.c \
-       $(am__test_cplusplus_SOURCES_DIST) test-draw.c test-font.c \
-       test-font-scale.c test-map.c test-multithread.c test-object.c \
-       test-ot-alternates.c test-ot-collect-glyphs.c test-ot-color.c \
-       test-ot-extents-cff.c test-ot-face.c test-ot-glyphname.c \
-       test-ot-layout.c test-ot-ligature-carets.c test-ot-math.c \
-       test-ot-meta.c test-ot-metrics.c test-ot-metrics-tt-var.c \
-       test-ot-name.c test-ot-tag.c test-set.c test-shape.c \
+       test-coretext.c $(am__test_cplusplus_SOURCES_DIST) test-draw.c \
+       test-extents.c test-font.c test-font-scale.c test-ft.c \
+       test-glyph-names.c test-instance-cff2.c test-map.c \
+       test-multithread.c test-object.c test-ot-alternates.c \
+       test-ot-collect-glyphs.c test-ot-color.c test-ot-extents-cff.c \
+       test-ot-face.c test-ot-glyphname.c test-ot-layout.c \
+       test-ot-ligature-carets.c test-ot-math.c test-ot-meta.c \
+       test-ot-metrics.c test-ot-metrics-tt-var.c test-ot-name.c \
+       test-ot-tag.c test-paint.c test-set.c test-shape.c \
        test-style.c test-subset.c test-subset-cbdt.c \
        test-subset-cff1.c test-subset-cff2.c test-subset-cmap.c \
        test-subset-colr.c test-subset-drop-tables.c \
        test-subset-glyf.c test-subset-gpos.c test-subset-gvar.c \
        test-subset-hdmx.c test-subset-hmtx.c test-subset-hvar.c \
        test-subset-nameids.c test-subset-os2.c test-subset-post.c \
-       test-subset-sbix.c test-subset-vmtx.c test-subset-vvar.c \
-       test-unicode.c test-var-coords.c test-version.c
+       test-subset-repacker.c test-subset-sbix.c test-subset-vmtx.c \
+       test-subset-vvar.c test-unicode.c test-var-coords.c \
+       test-version.c
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -853,8 +943,6 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
-DIRECTWRITE_CXXFLAGS = @DIRECTWRITE_CXXFLAGS@
-DIRECTWRITE_LIBS = @DIRECTWRITE_LIBS@
 DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -952,6 +1040,8 @@ STRIP = @STRIP@
 UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
 UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
 VERSION = @VERSION@
+WASM_CFLAGS = @WASM_CFLAGS@
+WASM_LIBS = @WASM_LIBS@
 _GI_EXP_DATADIR = @_GI_EXP_DATADIR@
 _GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@
 abs_builddir = @abs_builddir@
@@ -1011,35 +1101,45 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 NULL = 
-EXTRA_DIST = meson.build fonts $(am__append_1)
-CLEANFILES = $(am__append_10)
+EXTRA_DIST = meson.build fonts results $(NULL) $(am__append_1)
+CLEANFILES = $(am__append_15)
 DISTCLEANFILES = 
 MAINTAINERCLEANFILES = 
 LINK = $(CXXLINK)
 @HAVE_GLIB_TRUE@AM_CPPFLAGS = -DSRCDIR="\"$(srcdir)\"" -I$(top_srcdir)/src/ -I$(top_builddir)/src/ $(GLIB_CFLAGS)
 @HAVE_GLIB_TRUE@LDADD = $(top_builddir)/src/libharfbuzz.la $(GLIB_LIBS)
-@HAVE_GLIB_TRUE@TEST_PROGS = test-aat-layout test-baseline test-blob \
-@HAVE_GLIB_TRUE@       test-buffer test-c test-collect-unicodes \
-@HAVE_GLIB_TRUE@       test-cplusplus test-common test-draw test-font \
-@HAVE_GLIB_TRUE@       test-font-scale test-map test-object \
+@HAVE_GLIB_TRUE@TEST_PROGS = test-aat-layout test-baseline \
+@HAVE_GLIB_TRUE@       test-base-minmax test-be-glyph-advance \
+@HAVE_GLIB_TRUE@       test-be-num-glyphs test-blob test-buffer \
+@HAVE_GLIB_TRUE@       test-c test-collect-unicodes test-cplusplus \
+@HAVE_GLIB_TRUE@       test-common test-draw test-extents test-font \
+@HAVE_GLIB_TRUE@       test-font-scale test-glyph-names \
+@HAVE_GLIB_TRUE@       test-instance-cff2 test-map test-object \
 @HAVE_GLIB_TRUE@       test-ot-alternates test-ot-color \
 @HAVE_GLIB_TRUE@       test-ot-collect-glyphs test-ot-face \
 @HAVE_GLIB_TRUE@       test-ot-glyphname test-ot-ligature-carets \
 @HAVE_GLIB_TRUE@       test-ot-layout test-ot-name test-ot-meta \
 @HAVE_GLIB_TRUE@       test-ot-metrics test-ot-tag \
 @HAVE_GLIB_TRUE@       test-ot-extents-cff test-ot-metrics-tt-var \
-@HAVE_GLIB_TRUE@       test-set test-shape test-style test-subset \
-@HAVE_GLIB_TRUE@       test-subset-cmap test-subset-drop-tables \
-@HAVE_GLIB_TRUE@       test-subset-glyf test-subset-hdmx \
-@HAVE_GLIB_TRUE@       test-subset-hmtx test-subset-nameids \
-@HAVE_GLIB_TRUE@       test-subset-os2 test-subset-post \
-@HAVE_GLIB_TRUE@       test-subset-vmtx test-subset-cff1 \
-@HAVE_GLIB_TRUE@       test-subset-cff2 test-subset-gvar \
-@HAVE_GLIB_TRUE@       test-subset-hvar test-subset-vvar \
-@HAVE_GLIB_TRUE@       test-subset-sbix test-subset-gpos \
-@HAVE_GLIB_TRUE@       test-subset-colr test-subset-cbdt test-unicode \
-@HAVE_GLIB_TRUE@       test-var-coords test-version $(NULL) \
-@HAVE_GLIB_TRUE@       $(am__append_4) $(am__append_5)
+@HAVE_GLIB_TRUE@       test-paint test-set test-shape test-style \
+@HAVE_GLIB_TRUE@       test-subset test-subset-cmap \
+@HAVE_GLIB_TRUE@       test-subset-drop-tables test-subset-glyf \
+@HAVE_GLIB_TRUE@       test-subset-hdmx test-subset-hmtx \
+@HAVE_GLIB_TRUE@       test-subset-nameids test-subset-os2 \
+@HAVE_GLIB_TRUE@       test-subset-post test-subset-vmtx \
+@HAVE_GLIB_TRUE@       test-subset-cff1 test-subset-cff2 \
+@HAVE_GLIB_TRUE@       test-subset-gvar test-subset-hvar \
+@HAVE_GLIB_TRUE@       test-subset-vvar test-subset-sbix \
+@HAVE_GLIB_TRUE@       test-subset-gpos test-subset-colr \
+@HAVE_GLIB_TRUE@       test-subset-cbdt test-subset-repacker \
+@HAVE_GLIB_TRUE@       test-unicode test-var-coords test-version \
+@HAVE_GLIB_TRUE@       $(NULL) $(am__append_4) $(am__append_9) \
+@HAVE_GLIB_TRUE@       $(am__append_10)
+@HAVE_GLIB_TRUE@test_draw_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_5)
+@HAVE_GLIB_TRUE@test_draw_LDADD = $(LDADD) $(am__append_6)
+@HAVE_GLIB_TRUE@test_paint_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_7)
+@HAVE_GLIB_TRUE@test_paint_LDADD = $(LDADD) $(am__append_8)
+@HAVE_GLIB_TRUE@test_instance_cff2_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 @HAVE_GLIB_TRUE@test_subset_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 @HAVE_GLIB_TRUE@test_subset_cmap_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 @HAVE_GLIB_TRUE@test_subset_drop_tables_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
@@ -1059,6 +1159,7 @@ LINK = $(CXXLINK)
 @HAVE_GLIB_TRUE@test_subset_nameids_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 @HAVE_GLIB_TRUE@test_subset_gpos_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 @HAVE_GLIB_TRUE@test_subset_colr_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
+@HAVE_GLIB_TRUE@test_subset_repacker_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 @HAVE_GLIB_TRUE@test_unicode_CPPFLAGS = $(AM_CPPFLAGS) $(GLIB_CFLAGS) \
 @HAVE_GLIB_TRUE@       $(NULL) $(am__append_2)
 @HAVE_GLIB_TRUE@test_unicode_LDADD = $(LDADD) $(am__append_3)
@@ -1069,13 +1170,15 @@ LINK = $(CXXLINK)
 @HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@@HAVE_PTHREAD_TRUE@test_multithread_LINK = $(LINK) $(PTHREAD_CFLAGS)
 @HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@test_ot_math_LDADD = $(LDADD) $(FREETYPE_LIBS)
 @HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@test_ot_math_CPPFLAGS = $(AM_CPPFLAGS) $(FREETYPE_CFLAGS)
+@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@test_ft_LDADD = $(LDADD) $(FREETYPE_LIBS)
+@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@test_ft_CPPFLAGS = $(AM_CPPFLAGS) $(FREETYPE_CFLAGS)
 
 # Tests for header compilation
 @HAVE_GLIB_TRUE@test_cplusplus_SOURCES = test-cplusplus.cc
-@HAVE_GLIB_TRUE@test_c_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_6) \
-@HAVE_GLIB_TRUE@       $(am__append_8)
+@HAVE_GLIB_TRUE@test_c_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_11) \
+@HAVE_GLIB_TRUE@       $(am__append_13)
 @HAVE_GLIB_TRUE@test_cplusplus_CPPFLAGS = $(AM_CPPFLAGS) \
-@HAVE_GLIB_TRUE@       $(am__append_7) $(am__append_9)
+@HAVE_GLIB_TRUE@       $(am__append_12) $(am__append_14)
 @HAVE_GLIB_TRUE@TESTS_ENVIRONMENT = \
 @HAVE_GLIB_TRUE@       MALLOC_CHECK_=2 \
 @HAVE_GLIB_TRUE@       MALLOC_PERTURB_=$$(($${RANDOM:-256} % 256)) \
@@ -1158,10 +1261,22 @@ test-aat-layout$(EXEEXT): $(test_aat_layout_OBJECTS) $(test_aat_layout_DEPENDENC
        @rm -f test-aat-layout$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(test_aat_layout_OBJECTS) $(test_aat_layout_LDADD) $(LIBS)
 
+test-base-minmax$(EXEEXT): $(test_base_minmax_OBJECTS) $(test_base_minmax_DEPENDENCIES) $(EXTRA_test_base_minmax_DEPENDENCIES) 
+       @rm -f test-base-minmax$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(test_base_minmax_OBJECTS) $(test_base_minmax_LDADD) $(LIBS)
+
 test-baseline$(EXEEXT): $(test_baseline_OBJECTS) $(test_baseline_DEPENDENCIES) $(EXTRA_test_baseline_DEPENDENCIES) 
        @rm -f test-baseline$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(test_baseline_OBJECTS) $(test_baseline_LDADD) $(LIBS)
 
+test-be-glyph-advance$(EXEEXT): $(test_be_glyph_advance_OBJECTS) $(test_be_glyph_advance_DEPENDENCIES) $(EXTRA_test_be_glyph_advance_DEPENDENCIES) 
+       @rm -f test-be-glyph-advance$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(test_be_glyph_advance_OBJECTS) $(test_be_glyph_advance_LDADD) $(LIBS)
+
+test-be-num-glyphs$(EXEEXT): $(test_be_num_glyphs_OBJECTS) $(test_be_num_glyphs_DEPENDENCIES) $(EXTRA_test_be_num_glyphs_DEPENDENCIES) 
+       @rm -f test-be-num-glyphs$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(test_be_num_glyphs_OBJECTS) $(test_be_num_glyphs_LDADD) $(LIBS)
+
 test-blob$(EXEEXT): $(test_blob_OBJECTS) $(test_blob_DEPENDENCIES) $(EXTRA_test_blob_DEPENDENCIES) 
        @rm -f test-blob$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(test_blob_OBJECTS) $(test_blob_LDADD) $(LIBS)
@@ -1182,6 +1297,10 @@ test-common$(EXEEXT): $(test_common_OBJECTS) $(test_common_DEPENDENCIES) $(EXTRA
        @rm -f test-common$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(test_common_OBJECTS) $(test_common_LDADD) $(LIBS)
 
+test-coretext$(EXEEXT): $(test_coretext_OBJECTS) $(test_coretext_DEPENDENCIES) $(EXTRA_test_coretext_DEPENDENCIES) 
+       @rm -f test-coretext$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(test_coretext_OBJECTS) $(test_coretext_LDADD) $(LIBS)
+
 test-cplusplus$(EXEEXT): $(test_cplusplus_OBJECTS) $(test_cplusplus_DEPENDENCIES) $(EXTRA_test_cplusplus_DEPENDENCIES) 
        @rm -f test-cplusplus$(EXEEXT)
        $(AM_V_CXXLD)$(CXXLINK) $(test_cplusplus_OBJECTS) $(test_cplusplus_LDADD) $(LIBS)
@@ -1190,6 +1309,10 @@ test-draw$(EXEEXT): $(test_draw_OBJECTS) $(test_draw_DEPENDENCIES) $(EXTRA_test_
        @rm -f test-draw$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(test_draw_OBJECTS) $(test_draw_LDADD) $(LIBS)
 
+test-extents$(EXEEXT): $(test_extents_OBJECTS) $(test_extents_DEPENDENCIES) $(EXTRA_test_extents_DEPENDENCIES) 
+       @rm -f test-extents$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(test_extents_OBJECTS) $(test_extents_LDADD) $(LIBS)
+
 test-font$(EXEEXT): $(test_font_OBJECTS) $(test_font_DEPENDENCIES) $(EXTRA_test_font_DEPENDENCIES) 
        @rm -f test-font$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(test_font_OBJECTS) $(test_font_LDADD) $(LIBS)
@@ -1198,6 +1321,18 @@ test-font-scale$(EXEEXT): $(test_font_scale_OBJECTS) $(test_font_scale_DEPENDENC
        @rm -f test-font-scale$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(test_font_scale_OBJECTS) $(test_font_scale_LDADD) $(LIBS)
 
+test-ft$(EXEEXT): $(test_ft_OBJECTS) $(test_ft_DEPENDENCIES) $(EXTRA_test_ft_DEPENDENCIES) 
+       @rm -f test-ft$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(test_ft_OBJECTS) $(test_ft_LDADD) $(LIBS)
+
+test-glyph-names$(EXEEXT): $(test_glyph_names_OBJECTS) $(test_glyph_names_DEPENDENCIES) $(EXTRA_test_glyph_names_DEPENDENCIES) 
+       @rm -f test-glyph-names$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(test_glyph_names_OBJECTS) $(test_glyph_names_LDADD) $(LIBS)
+
+test-instance-cff2$(EXEEXT): $(test_instance_cff2_OBJECTS) $(test_instance_cff2_DEPENDENCIES) $(EXTRA_test_instance_cff2_DEPENDENCIES) 
+       @rm -f test-instance-cff2$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(test_instance_cff2_OBJECTS) $(test_instance_cff2_LDADD) $(LIBS)
+
 test-map$(EXEEXT): $(test_map_OBJECTS) $(test_map_DEPENDENCIES) $(EXTRA_test_map_DEPENDENCIES) 
        @rm -f test-map$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(test_map_OBJECTS) $(test_map_LDADD) $(LIBS)
@@ -1266,6 +1401,10 @@ test-ot-tag$(EXEEXT): $(test_ot_tag_OBJECTS) $(test_ot_tag_DEPENDENCIES) $(EXTRA
        @rm -f test-ot-tag$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(test_ot_tag_OBJECTS) $(test_ot_tag_LDADD) $(LIBS)
 
+test-paint$(EXEEXT): $(test_paint_OBJECTS) $(test_paint_DEPENDENCIES) $(EXTRA_test_paint_DEPENDENCIES) 
+       @rm -f test-paint$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(test_paint_OBJECTS) $(test_paint_LDADD) $(LIBS)
+
 test-set$(EXEEXT): $(test_set_OBJECTS) $(test_set_DEPENDENCIES) $(EXTRA_test_set_DEPENDENCIES) 
        @rm -f test-set$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(test_set_OBJECTS) $(test_set_LDADD) $(LIBS)
@@ -1342,6 +1481,10 @@ test-subset-post$(EXEEXT): $(test_subset_post_OBJECTS) $(test_subset_post_DEPEND
        @rm -f test-subset-post$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(test_subset_post_OBJECTS) $(test_subset_post_LDADD) $(LIBS)
 
+test-subset-repacker$(EXEEXT): $(test_subset_repacker_OBJECTS) $(test_subset_repacker_DEPENDENCIES) $(EXTRA_test_subset_repacker_DEPENDENCIES) 
+       @rm -f test-subset-repacker$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(test_subset_repacker_OBJECTS) $(test_subset_repacker_LDADD) $(LIBS)
+
 test-subset-sbix$(EXEEXT): $(test_subset_sbix_OBJECTS) $(test_subset_sbix_DEPENDENCIES) $(EXTRA_test_subset_sbix_DEPENDENCIES) 
        @rm -f test-subset-sbix$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(test_subset_sbix_OBJECTS) $(test_subset_sbix_LDADD) $(LIBS)
@@ -1373,14 +1516,20 @@ distclean-compile:
        -rm -f *.tab.c
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-aat-layout.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-base-minmax.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-baseline.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-be-glyph-advance.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-be-num-glyphs.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-blob.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-buffer.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-collect-unicodes.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-common.Po@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-draw.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-coretext.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-extents.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-font-scale.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-font.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-glyph-names.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-instance-cff2.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-map.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-object.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-ot-alternates.Po@am__quote@ # am--include-marker
@@ -1414,6 +1563,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-subset-nameids.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-subset-os2.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-subset-post.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-subset-repacker.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-subset-sbix.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-subset-vmtx.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-subset-vvar.Po@am__quote@ # am--include-marker
@@ -1422,8 +1572,11 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-version.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_c-test-c.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_cplusplus-test-cplusplus.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_draw-test-draw.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_ft-test-ft.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_multithread-test-multithread.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_ot_math-test-ot-math.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_paint-test-paint.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_unicode-test-unicode.Po@am__quote@ # am--include-marker
 
 $(am__depfiles_remade):
@@ -1467,6 +1620,34 @@ test_c-test-c.obj: test-c.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_c_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_c-test-c.obj `if test -f 'test-c.c'; then $(CYGPATH_W) 'test-c.c'; else $(CYGPATH_W) '$(srcdir)/test-c.c'; fi`
 
+test_draw-test-draw.o: test-draw.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_draw_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_draw-test-draw.o -MD -MP -MF $(DEPDIR)/test_draw-test-draw.Tpo -c -o test_draw-test-draw.o `test -f 'test-draw.c' || echo '$(srcdir)/'`test-draw.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/test_draw-test-draw.Tpo $(DEPDIR)/test_draw-test-draw.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='test-draw.c' object='test_draw-test-draw.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_draw_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_draw-test-draw.o `test -f 'test-draw.c' || echo '$(srcdir)/'`test-draw.c
+
+test_draw-test-draw.obj: test-draw.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_draw_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_draw-test-draw.obj -MD -MP -MF $(DEPDIR)/test_draw-test-draw.Tpo -c -o test_draw-test-draw.obj `if test -f 'test-draw.c'; then $(CYGPATH_W) 'test-draw.c'; else $(CYGPATH_W) '$(srcdir)/test-draw.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/test_draw-test-draw.Tpo $(DEPDIR)/test_draw-test-draw.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='test-draw.c' object='test_draw-test-draw.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_draw_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_draw-test-draw.obj `if test -f 'test-draw.c'; then $(CYGPATH_W) 'test-draw.c'; else $(CYGPATH_W) '$(srcdir)/test-draw.c'; fi`
+
+test_ft-test-ft.o: test-ft.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_ft_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_ft-test-ft.o -MD -MP -MF $(DEPDIR)/test_ft-test-ft.Tpo -c -o test_ft-test-ft.o `test -f 'test-ft.c' || echo '$(srcdir)/'`test-ft.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/test_ft-test-ft.Tpo $(DEPDIR)/test_ft-test-ft.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='test-ft.c' object='test_ft-test-ft.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_ft_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_ft-test-ft.o `test -f 'test-ft.c' || echo '$(srcdir)/'`test-ft.c
+
+test_ft-test-ft.obj: test-ft.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_ft_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_ft-test-ft.obj -MD -MP -MF $(DEPDIR)/test_ft-test-ft.Tpo -c -o test_ft-test-ft.obj `if test -f 'test-ft.c'; then $(CYGPATH_W) 'test-ft.c'; else $(CYGPATH_W) '$(srcdir)/test-ft.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/test_ft-test-ft.Tpo $(DEPDIR)/test_ft-test-ft.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='test-ft.c' object='test_ft-test-ft.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_ft_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_ft-test-ft.obj `if test -f 'test-ft.c'; then $(CYGPATH_W) 'test-ft.c'; else $(CYGPATH_W) '$(srcdir)/test-ft.c'; fi`
+
 test_multithread-test-multithread.o: test-multithread.c
 @am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_multithread_CFLAGS) $(CFLAGS) -MT test_multithread-test-multithread.o -MD -MP -MF $(DEPDIR)/test_multithread-test-multithread.Tpo -c -o test_multithread-test-multithread.o `test -f 'test-multithread.c' || echo '$(srcdir)/'`test-multithread.c
 @am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/test_multithread-test-multithread.Tpo $(DEPDIR)/test_multithread-test-multithread.Po
@@ -1495,6 +1676,20 @@ test_ot_math-test-ot-math.obj: test-ot-math.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_ot_math_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_ot_math-test-ot-math.obj `if test -f 'test-ot-math.c'; then $(CYGPATH_W) 'test-ot-math.c'; else $(CYGPATH_W) '$(srcdir)/test-ot-math.c'; fi`
 
+test_paint-test-paint.o: test-paint.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_paint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_paint-test-paint.o -MD -MP -MF $(DEPDIR)/test_paint-test-paint.Tpo -c -o test_paint-test-paint.o `test -f 'test-paint.c' || echo '$(srcdir)/'`test-paint.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/test_paint-test-paint.Tpo $(DEPDIR)/test_paint-test-paint.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='test-paint.c' object='test_paint-test-paint.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_paint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_paint-test-paint.o `test -f 'test-paint.c' || echo '$(srcdir)/'`test-paint.c
+
+test_paint-test-paint.obj: test-paint.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_paint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_paint-test-paint.obj -MD -MP -MF $(DEPDIR)/test_paint-test-paint.Tpo -c -o test_paint-test-paint.obj `if test -f 'test-paint.c'; then $(CYGPATH_W) 'test-paint.c'; else $(CYGPATH_W) '$(srcdir)/test-paint.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/test_paint-test-paint.Tpo $(DEPDIR)/test_paint-test-paint.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='test-paint.c' object='test_paint-test-paint.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_paint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_paint-test-paint.obj `if test -f 'test-paint.c'; then $(CYGPATH_W) 'test-paint.c'; else $(CYGPATH_W) '$(srcdir)/test-paint.c'; fi`
+
 test_unicode-test-unicode.o: test-unicode.c
 @am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_unicode_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_unicode-test-unicode.o -MD -MP -MF $(DEPDIR)/test_unicode-test-unicode.Tpo -c -o test_unicode-test-unicode.o `test -f 'test-unicode.c' || echo '$(srcdir)/'`test-unicode.c
 @am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/test_unicode-test-unicode.Tpo $(DEPDIR)/test_unicode-test-unicode.Po
@@ -1757,6 +1952,27 @@ test-baseline.log: test-baseline$(EXEEXT)
        --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-base-minmax.log: test-base-minmax$(EXEEXT)
+       @p='test-base-minmax$(EXEEXT)'; \
+       b='test-base-minmax'; \
+       $(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-be-glyph-advance.log: test-be-glyph-advance$(EXEEXT)
+       @p='test-be-glyph-advance$(EXEEXT)'; \
+       b='test-be-glyph-advance'; \
+       $(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-be-num-glyphs.log: test-be-num-glyphs$(EXEEXT)
+       @p='test-be-num-glyphs$(EXEEXT)'; \
+       b='test-be-num-glyphs'; \
+       $(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-blob.log: test-blob$(EXEEXT)
        @p='test-blob$(EXEEXT)'; \
        b='test-blob'; \
@@ -1806,6 +2022,13 @@ test-draw.log: test-draw$(EXEEXT)
        --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-extents.log: test-extents$(EXEEXT)
+       @p='test-extents$(EXEEXT)'; \
+       b='test-extents'; \
+       $(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-font.log: test-font$(EXEEXT)
        @p='test-font$(EXEEXT)'; \
        b='test-font'; \
@@ -1820,6 +2043,20 @@ test-font-scale.log: test-font-scale$(EXEEXT)
        --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-glyph-names.log: test-glyph-names$(EXEEXT)
+       @p='test-glyph-names$(EXEEXT)'; \
+       b='test-glyph-names'; \
+       $(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-instance-cff2.log: test-instance-cff2$(EXEEXT)
+       @p='test-instance-cff2$(EXEEXT)'; \
+       b='test-instance-cff2'; \
+       $(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-map.log: test-map$(EXEEXT)
        @p='test-map$(EXEEXT)'; \
        b='test-map'; \
@@ -1925,6 +2162,13 @@ test-ot-metrics-tt-var.log: test-ot-metrics-tt-var$(EXEEXT)
        --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-paint.log: test-paint$(EXEEXT)
+       @p='test-paint$(EXEEXT)'; \
+       b='test-paint'; \
+       $(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-set.log: test-set$(EXEEXT)
        @p='test-set$(EXEEXT)'; \
        b='test-set'; \
@@ -2079,6 +2323,13 @@ test-subset-cbdt.log: test-subset-cbdt$(EXEEXT)
        --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-subset-repacker.log: test-subset-repacker$(EXEEXT)
+       @p='test-subset-repacker$(EXEEXT)'; \
+       b='test-subset-repacker'; \
+       $(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-unicode.log: test-unicode$(EXEEXT)
        @p='test-unicode$(EXEEXT)'; \
        b='test-unicode'; \
@@ -2114,6 +2365,20 @@ test-ot-math.log: test-ot-math$(EXEEXT)
        --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-ft.log: test-ft$(EXEEXT)
+       @p='test-ft$(EXEEXT)'; \
+       b='test-ft'; \
+       $(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-coretext.log: test-coretext$(EXEEXT)
+       @p='test-coretext$(EXEEXT)'; \
+       b='test-coretext'; \
+       $(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.log:
        @p='$<'; \
        $(am__set_b); \
@@ -2211,14 +2476,20 @@ clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
 
 distclean: distclean-am
                -rm -f ./$(DEPDIR)/test-aat-layout.Po
+       -rm -f ./$(DEPDIR)/test-base-minmax.Po
        -rm -f ./$(DEPDIR)/test-baseline.Po
+       -rm -f ./$(DEPDIR)/test-be-glyph-advance.Po
+       -rm -f ./$(DEPDIR)/test-be-num-glyphs.Po
        -rm -f ./$(DEPDIR)/test-blob.Po
        -rm -f ./$(DEPDIR)/test-buffer.Po
        -rm -f ./$(DEPDIR)/test-collect-unicodes.Po
        -rm -f ./$(DEPDIR)/test-common.Po
-       -rm -f ./$(DEPDIR)/test-draw.Po
+       -rm -f ./$(DEPDIR)/test-coretext.Po
+       -rm -f ./$(DEPDIR)/test-extents.Po
        -rm -f ./$(DEPDIR)/test-font-scale.Po
        -rm -f ./$(DEPDIR)/test-font.Po
+       -rm -f ./$(DEPDIR)/test-glyph-names.Po
+       -rm -f ./$(DEPDIR)/test-instance-cff2.Po
        -rm -f ./$(DEPDIR)/test-map.Po
        -rm -f ./$(DEPDIR)/test-object.Po
        -rm -f ./$(DEPDIR)/test-ot-alternates.Po
@@ -2252,6 +2523,7 @@ distclean: distclean-am
        -rm -f ./$(DEPDIR)/test-subset-nameids.Po
        -rm -f ./$(DEPDIR)/test-subset-os2.Po
        -rm -f ./$(DEPDIR)/test-subset-post.Po
+       -rm -f ./$(DEPDIR)/test-subset-repacker.Po
        -rm -f ./$(DEPDIR)/test-subset-sbix.Po
        -rm -f ./$(DEPDIR)/test-subset-vmtx.Po
        -rm -f ./$(DEPDIR)/test-subset-vvar.Po
@@ -2260,8 +2532,11 @@ distclean: distclean-am
        -rm -f ./$(DEPDIR)/test-version.Po
        -rm -f ./$(DEPDIR)/test_c-test-c.Po
        -rm -f ./$(DEPDIR)/test_cplusplus-test-cplusplus.Po
+       -rm -f ./$(DEPDIR)/test_draw-test-draw.Po
+       -rm -f ./$(DEPDIR)/test_ft-test-ft.Po
        -rm -f ./$(DEPDIR)/test_multithread-test-multithread.Po
        -rm -f ./$(DEPDIR)/test_ot_math-test-ot-math.Po
+       -rm -f ./$(DEPDIR)/test_paint-test-paint.Po
        -rm -f ./$(DEPDIR)/test_unicode-test-unicode.Po
        -rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
@@ -2309,14 +2584,20 @@ installcheck-am:
 
 maintainer-clean: maintainer-clean-am
                -rm -f ./$(DEPDIR)/test-aat-layout.Po
+       -rm -f ./$(DEPDIR)/test-base-minmax.Po
        -rm -f ./$(DEPDIR)/test-baseline.Po
+       -rm -f ./$(DEPDIR)/test-be-glyph-advance.Po
+       -rm -f ./$(DEPDIR)/test-be-num-glyphs.Po
        -rm -f ./$(DEPDIR)/test-blob.Po
        -rm -f ./$(DEPDIR)/test-buffer.Po
        -rm -f ./$(DEPDIR)/test-collect-unicodes.Po
        -rm -f ./$(DEPDIR)/test-common.Po
-       -rm -f ./$(DEPDIR)/test-draw.Po
+       -rm -f ./$(DEPDIR)/test-coretext.Po
+       -rm -f ./$(DEPDIR)/test-extents.Po
        -rm -f ./$(DEPDIR)/test-font-scale.Po
        -rm -f ./$(DEPDIR)/test-font.Po
+       -rm -f ./$(DEPDIR)/test-glyph-names.Po
+       -rm -f ./$(DEPDIR)/test-instance-cff2.Po
        -rm -f ./$(DEPDIR)/test-map.Po
        -rm -f ./$(DEPDIR)/test-object.Po
        -rm -f ./$(DEPDIR)/test-ot-alternates.Po
@@ -2350,6 +2631,7 @@ maintainer-clean: maintainer-clean-am
        -rm -f ./$(DEPDIR)/test-subset-nameids.Po
        -rm -f ./$(DEPDIR)/test-subset-os2.Po
        -rm -f ./$(DEPDIR)/test-subset-post.Po
+       -rm -f ./$(DEPDIR)/test-subset-repacker.Po
        -rm -f ./$(DEPDIR)/test-subset-sbix.Po
        -rm -f ./$(DEPDIR)/test-subset-vmtx.Po
        -rm -f ./$(DEPDIR)/test-subset-vvar.Po
@@ -2358,8 +2640,11 @@ maintainer-clean: maintainer-clean-am
        -rm -f ./$(DEPDIR)/test-version.Po
        -rm -f ./$(DEPDIR)/test_c-test-c.Po
        -rm -f ./$(DEPDIR)/test_cplusplus-test-cplusplus.Po
+       -rm -f ./$(DEPDIR)/test_draw-test-draw.Po
+       -rm -f ./$(DEPDIR)/test_ft-test-ft.Po
        -rm -f ./$(DEPDIR)/test_multithread-test-multithread.Po
        -rm -f ./$(DEPDIR)/test_ot_math-test-ot-math.Po
+       -rm -f ./$(DEPDIR)/test_paint-test-paint.Po
        -rm -f ./$(DEPDIR)/test_unicode-test-unicode.Po
        -rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
diff --git a/test/api/fonts/AdobeVFPrototype.abc.static.otf b/test/api/fonts/AdobeVFPrototype.abc.static.otf
new file mode 100644 (file)
index 0000000..c5774cc
Binary files /dev/null and b/test/api/fonts/AdobeVFPrototype.abc.static.otf differ
index 8ff99c6..50b5be6 100644 (file)
Binary files a/test/api/fonts/AdobeVFPrototype.ac.retaingids.otf and b/test/api/fonts/AdobeVFPrototype.ac.retaingids.otf differ
diff --git a/test/api/fonts/RocherColorGX.abc.ttf b/test/api/fonts/RocherColorGX.abc.ttf
new file mode 100644 (file)
index 0000000..35fce09
Binary files /dev/null and b/test/api/fonts/RocherColorGX.abc.ttf differ
index dbbc388..01fb89e 100644 (file)
Binary files a/test/api/fonts/SourceSansVariable-Roman.abc.ttf and b/test/api/fonts/SourceSansVariable-Roman.abc.ttf differ
index 9f9ecd6..50b5be6 100644 (file)
Binary files a/test/api/fonts/SourceSansVariable-Roman.ac.retaingids.ttf and b/test/api/fonts/SourceSansVariable-Roman.ac.retaingids.ttf differ
index c12daf2..28ca0bd 100644 (file)
Binary files a/test/api/fonts/SourceSansVariable-Roman.ac.ttf and b/test/api/fonts/SourceSansVariable-Roman.ac.ttf differ
index 271dc4b..581ef6d 100644 (file)
Binary files a/test/api/fonts/TestGVAREight.ttf and b/test/api/fonts/TestGVAREight.ttf differ
diff --git a/test/api/fonts/adwaita.ttf b/test/api/fonts/adwaita.ttf
new file mode 100644 (file)
index 0000000..6415611
Binary files /dev/null and b/test/api/fonts/adwaita.ttf differ
diff --git a/test/api/fonts/bad_colrv1.ttf b/test/api/fonts/bad_colrv1.ttf
new file mode 100644 (file)
index 0000000..df548ef
Binary files /dev/null and b/test/api/fonts/bad_colrv1.ttf differ
diff --git a/test/api/fonts/base-minmax.ttf b/test/api/fonts/base-minmax.ttf
new file mode 100644 (file)
index 0000000..9661b59
Binary files /dev/null and b/test/api/fonts/base-minmax.ttf differ
diff --git a/test/api/fonts/base2.ttf b/test/api/fonts/base2.ttf
new file mode 100644 (file)
index 0000000..5cb0d35
Binary files /dev/null and b/test/api/fonts/base2.ttf differ
diff --git a/test/api/fonts/nameID.override.expected.ttf b/test/api/fonts/nameID.override.expected.ttf
new file mode 100644 (file)
index 0000000..d17ea83
Binary files /dev/null and b/test/api/fonts/nameID.override.expected.ttf differ
diff --git a/test/api/fonts/noto_handwriting-cff2_colr_1.otf b/test/api/fonts/noto_handwriting-cff2_colr_1.otf
new file mode 100644 (file)
index 0000000..dfb3058
Binary files /dev/null and b/test/api/fonts/noto_handwriting-cff2_colr_1.otf differ
diff --git a/test/api/fonts/notosansitalic.ttf b/test/api/fonts/notosansitalic.ttf
new file mode 100644 (file)
index 0000000..26a80c5
Binary files /dev/null and b/test/api/fonts/notosansitalic.ttf differ
diff --git a/test/api/fonts/repacker_expected.otf b/test/api/fonts/repacker_expected.otf
new file mode 100644 (file)
index 0000000..f96fde0
Binary files /dev/null and b/test/api/fonts/repacker_expected.otf differ
diff --git a/test/api/fonts/test_glyphs-glyf_colr_1.ttf b/test/api/fonts/test_glyphs-glyf_colr_1.ttf
new file mode 100644 (file)
index 0000000..982ccc0
Binary files /dev/null and b/test/api/fonts/test_glyphs-glyf_colr_1.ttf differ
diff --git a/test/api/fonts/test_glyphs-glyf_colr_1_variable.ttf b/test/api/fonts/test_glyphs-glyf_colr_1_variable.ttf
new file mode 100644 (file)
index 0000000..9cc7230
Binary files /dev/null and b/test/api/fonts/test_glyphs-glyf_colr_1_variable.ttf differ
index 7390e57..2be47be 100644 (file)
@@ -27,9 +27,7 @@
 #ifndef HB_TEST_H
 #define HB_TEST_H
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include <hb-config.hh>
 
 #include <hb-glib.h>
 
@@ -52,6 +50,17 @@ HB_BEGIN_DECLS
                                  ((const char *) s)[2], \
                                  ((const char *) s)[3]))
 
+#define HB_FACE_ADD_TABLE(face, tag, data) \
+       do { \
+         hb_blob_t *blob = hb_blob_create_or_fail ((data), \
+                                                   sizeof (data), \
+                                                   HB_MEMORY_MODE_READONLY, \
+                                                   NULL, NULL); \
+         hb_face_builder_add_table ((face), \
+                                    HB_TAG_CHAR4(tag), \
+                                    blob); \
+         hb_blob_destroy (blob); \
+       } while (0)
 
 static inline const char *
 srcdir (void)
index 7ea2954..64d7797 100644 (file)
@@ -6,6 +6,9 @@ endif
 tests = [
   'test-aat-layout.c',
   'test-baseline.c',
+  'test-base-minmax.c',
+  'test-be-glyph-advance.c',
+  'test-be-num-glyphs.c',
   'test-blob.c',
   'test-buffer.c',
   'test-c.c',
@@ -13,8 +16,11 @@ tests = [
   'test-cplusplus.cc',
   'test-common.c',
   'test-draw.c',
+  'test-extents.c',
   'test-font.c',
   'test-font-scale.c',
+  'test-glyph-names.c',
+  'test-instance-cff2.c',
   'test-map.c',
   'test-object.c',
   'test-ot-alternates.c',
@@ -30,6 +36,8 @@ tests = [
   'test-ot-tag.c',
   'test-ot-extents-cff.c',
   'test-ot-metrics-tt-var.c',
+  'test-paint.c',
+  'test-subset-repacker.c',
   'test-set.c',
   'test-shape.c',
   'test-style.c',
@@ -58,7 +66,16 @@ tests = [
 ]
 
 if conf.get('HAVE_FREETYPE', 0) == 1
-  tests += 'test-ot-math.c'
+  tests += [
+    'test-ot-math.c',
+    'test-ft.c',
+  ]
+endif
+
+if conf.get('HAVE_CORETEXT', 0) == 1
+  tests += [
+    'test-coretext.c',
+  ]
 endif
 
 if conf.get('HAVE_FREETYPE', 0) == 1 and conf.get('HAVE_PTHREAD', 0) == 1
@@ -74,16 +91,22 @@ env.set('G_TEST_SRCDIR', meson.current_source_dir())
 env.set('G_TEST_BUILDDIR', meson.current_build_dir())
 
 foreach source : tests
+  cpp_args = []
   test_name = source.split('.')[0]
 
   deps = [glib_dep, freetype_dep, thread_dep, libharfbuzz_dep, libharfbuzz_icu_dep]
   suite = ['api']
-  if test_name.contains('-subset')
+  if test_name.contains('-subset') or test_name.contains('-instance')
     deps += libharfbuzz_subset_dep
     suite += 'subset'
   endif
 
+  if test_name.contains('-instance')
+    cpp_args += '-DHB_EXPERIMENTAL_API'
+  endif
+
   test(test_name, executable(test_name, source,
+    cpp_args:  cpp_args,
     include_directories: [incconfig],
     dependencies: deps,
     install: false,
diff --git a/test/api/results/bad-154 b/test/api/results/bad-154
new file mode 100644 (file)
index 0000000..5f88e03
--- /dev/null
@@ -0,0 +1,17 @@
+# random seed: R02S13f44c97ec7b03f792b3b9650a81b62a
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 0 500 500 1e+03
+  start transform 1 0 0 1 0 0
+    push group
+      start transform 1 0 -0 1 0 0
+        start clip glyph 159
+          start transform 1 0 0 1 0 0
+            solid 128 128 128 102
+          end transform
+        end clip
+      end transform
+    pop group mode 3
+  end transform
+end clip
diff --git a/test/api/results/hand-10 b/test/api/results/hand-10
new file mode 100644 (file)
index 0000000..10410e6
--- /dev/null
@@ -0,0 +1,121 @@
+# random seed: R02Se2b1d61d9c4fd31724517ef138cff8f6
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 64 -224 1.22e+03 928
+  start transform 1 0 0 1 0 0
+    push group
+      start transform 1 0 -0 1 0 0
+        start clip glyph 13
+          start transform 1 0 0 1 0 0
+            start transform 1 0 0 0.977 0 0
+              radial gradient
+                p0 280 440 radius 0
+                p1 280 440 radius 467
+                colors 0
+                  0 186 141 104 255
+                  0.449 183 138 103 255
+                  0.809 173 130 100 255
+                  1 164 123 98 255
+            end transform
+          end transform
+        end clip
+      end transform
+    pop group mode 3
+    push group
+      start transform 1 0 -0 1 0 0
+        start clip glyph 14
+          start transform 1 0 0 1 0 0
+            linear gradient
+              p0 231 -27
+              p1 1.02e+03 -27
+              p2 231 -815
+              colors 0
+                0 164 123 98 255
+                1 164 123 98 255
+          end transform
+        end clip
+      end transform
+    pop group mode 3
+    push group
+      start transform 1 0 -0 1 0 0
+        start clip glyph 15
+          start transform 1 0 0 1 0 0
+            solid 145 103 77 255
+          end transform
+        end clip
+      end transform
+    pop group mode 3
+    push group
+      start transform 1 0 -0 1 0 0
+        start clip glyph 16
+          start transform 1 0 0 1 0 0
+            solid 30 136 229 255
+          end transform
+        end clip
+      end transform
+    pop group mode 3
+    push group
+      start transform 1 0 -0 1 0 0
+        start clip glyph 21
+          start transform 1 0 0 1 0 0
+            solid 145 103 77 255
+          end transform
+        end clip
+      end transform
+    pop group mode 3
+    push group
+      push group
+        start transform 1 0 -0 1 0 0
+          start clip glyph 16
+            start transform 1 0 0 1 0 0
+              linear gradient
+                p0 669 776
+                p1 180 -106
+                p2 -212 1.26e+03
+                colors 0
+                  0 100 181 246 255
+                  1 33 150 243 255
+            end transform
+          end clip
+        end transform
+      pop group mode 3
+      push group
+        start transform 1 0 -0 1 0 0
+          start clip glyph 18
+            start transform 1 0 0 1 0 0
+              solid 66 66 66 51
+            end transform
+          end clip
+        end transform
+      pop group mode 3
+    pop group mode 3
+    push group
+      start transform 1 0 -0 1 0 0
+        start clip glyph 19
+          start transform 1 0 0 1 0 0
+            start transform 1 0 0 0.969 0 0
+              radial gradient
+                p0 588 198 radius 0
+                p1 588 198 radius 342
+                colors 0
+                  0 186 141 104 255
+                  0.449 183 138 103 255
+                  0.809 173 130 100 255
+                  1 164 123 98 255
+            end transform
+          end transform
+        end clip
+      end transform
+    pop group mode 3
+    push group
+      start transform 1 0 -0 1 0 0
+        start clip glyph 20
+          start transform 1 0 0 1 0 0
+            solid 145 103 77 255
+          end transform
+        end clip
+      end transform
+    pop group mode 3
+  end transform
+end clip
diff --git a/test/api/results/hand-10.2 b/test/api/results/hand-10.2
new file mode 100644 (file)
index 0000000..2076624
--- /dev/null
@@ -0,0 +1,121 @@
+# random seed: R02S962715a93cddae2d3121a44b0e86cc22
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 19 -224 1.4e+03 928
+  start transform 1 0 0.2 1 0 0
+    push group
+      start transform 1 0 -0.2 1 0 0
+        start clip glyph 13
+          start transform 1 0 0.2 1 0 0
+            start transform 1 0 0 0.977 0 0
+              radial gradient
+                p0 280 440 radius 0
+                p1 280 440 radius 467
+                colors 0
+                  0 186 141 104 255
+                  0.449 183 138 103 255
+                  0.809 173 130 100 255
+                  1 164 123 98 255
+            end transform
+          end transform
+        end clip
+      end transform
+    pop group mode 3
+    push group
+      start transform 1 0 -0.2 1 0 0
+        start clip glyph 14
+          start transform 1 0 0.2 1 0 0
+            linear gradient
+              p0 231 -27
+              p1 1.02e+03 -27
+              p2 231 -815
+              colors 0
+                0 164 123 98 255
+                1 164 123 98 255
+          end transform
+        end clip
+      end transform
+    pop group mode 3
+    push group
+      start transform 1 0 -0.2 1 0 0
+        start clip glyph 15
+          start transform 1 0 0.2 1 0 0
+            solid 145 103 77 255
+          end transform
+        end clip
+      end transform
+    pop group mode 3
+    push group
+      start transform 1 0 -0.2 1 0 0
+        start clip glyph 16
+          start transform 1 0 0.2 1 0 0
+            solid 30 136 229 255
+          end transform
+        end clip
+      end transform
+    pop group mode 3
+    push group
+      start transform 1 0 -0.2 1 0 0
+        start clip glyph 21
+          start transform 1 0 0.2 1 0 0
+            solid 145 103 77 255
+          end transform
+        end clip
+      end transform
+    pop group mode 3
+    push group
+      push group
+        start transform 1 0 -0.2 1 0 0
+          start clip glyph 16
+            start transform 1 0 0.2 1 0 0
+              linear gradient
+                p0 669 776
+                p1 180 -106
+                p2 -212 1.26e+03
+                colors 0
+                  0 100 181 246 255
+                  1 33 150 243 255
+            end transform
+          end clip
+        end transform
+      pop group mode 3
+      push group
+        start transform 1 0 -0.2 1 0 0
+          start clip glyph 18
+            start transform 1 0 0.2 1 0 0
+              solid 66 66 66 51
+            end transform
+          end clip
+        end transform
+      pop group mode 3
+    pop group mode 3
+    push group
+      start transform 1 0 -0.2 1 0 0
+        start clip glyph 19
+          start transform 1 0 0.2 1 0 0
+            start transform 1 0 0 0.969 0 0
+              radial gradient
+                p0 588 198 radius 0
+                p1 588 198 radius 342
+                colors 0
+                  0 186 141 104 255
+                  0.449 183 138 103 255
+                  0.809 173 130 100 255
+                  1 164 123 98 255
+            end transform
+          end transform
+        end clip
+      end transform
+    pop group mode 3
+    push group
+      start transform 1 0 -0.2 1 0 0
+        start clip glyph 20
+          start transform 1 0 0.2 1 0 0
+            solid 145 103 77 255
+          end transform
+        end clip
+      end transform
+    pop group mode 3
+  end transform
+end clip
diff --git a/test/api/results/rocher-1 b/test/api/results/rocher-1
new file mode 100644 (file)
index 0000000..bcd871f
--- /dev/null
@@ -0,0 +1,16 @@
+# random seed: R02Sbe08283e5db998c0ef8db485be24c9ce
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip glyph 8
+  solid 81 61 50 255
+end clip
+start clip glyph 9
+  solid 245 185 68 255
+end clip
+start clip glyph 10
+  solid 224 142 55 255
+end clip
+start clip glyph 11
+  solid 245 202 86 255
+end clip
diff --git a/test/api/results/rocher-2 b/test/api/results/rocher-2
new file mode 100644 (file)
index 0000000..0b840ab
--- /dev/null
@@ -0,0 +1,16 @@
+# random seed: R02S44e738ad8b5a9b0616dbb5ed381f9fd9
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip glyph 12
+  solid 81 61 50 255
+end clip
+start clip glyph 13
+  solid 245 185 68 255
+end clip
+start clip glyph 14
+  solid 224 142 55 255
+end clip
+start clip glyph 15
+  solid 245 202 86 255
+end clip
diff --git a/test/api/results/rocher-3 b/test/api/results/rocher-3
new file mode 100644 (file)
index 0000000..7d1e1d1
--- /dev/null
@@ -0,0 +1,16 @@
+# random seed: R02Sf5cb8d4e67af171b27fea99802b3c8e6
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip glyph 16
+  solid 81 61 50 255
+end clip
+start clip glyph 17
+  solid 245 185 68 255
+end clip
+start clip glyph 18
+  solid 224 142 55 255
+end clip
+start clip glyph 19
+  solid 245 202 86 255
+end clip
diff --git a/test/api/results/test-10 b/test/api/results/test-10
new file mode 100644 (file)
index 0000000..78d3e23
--- /dev/null
@@ -0,0 +1,22 @@
+# random seed: R02S730db577e65f80492e3e3eacc21152fa
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 0 0 1e+03 1e+03
+  start transform 1 0 0 1 0 0
+    start transform 1 0 -0 1 0 0
+      start clip glyph 174
+        start transform 1 0 0 1 0 0
+          sweep gradient
+            center 500 600
+            angles 0 6.28
+            colors 0
+              0.25 250 240 230 255
+              0.417 0 0 255 255
+              0.583 255 0 0 255
+              0.75 47 79 79 255
+        end transform
+      end clip
+    end transform
+  end transform
+end clip
diff --git a/test/api/results/test-106 b/test/api/results/test-106
new file mode 100644 (file)
index 0000000..2e04261
--- /dev/null
@@ -0,0 +1,30 @@
+# random seed: R02S33079790f9ab4f19e7151add3612840f
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 118 -22.9 750 750
+  start transform 1 0 0 1 0 0
+    start transform 1 0 -0 1 0 0
+      start clip glyph 3
+        start transform 1 0 0 1 0 0
+          solid 0 0 255 127
+        end transform
+      end clip
+    end transform
+    push group
+      start transform 1 0 0 1 1e+03 1e+03
+        start transform 1 0.364 0.176 1 0 0
+          start transform 1 0 0 1 -1e+03 -1e+03
+            start transform 1 0 -0 1 0 0
+              start clip glyph 3
+                start transform 1 0 0 1 0 0
+                  solid 255 165 0 178
+                end transform
+              end clip
+            end transform
+          end transform
+        end transform
+      end transform
+    pop group mode 4
+  end transform
+end clip
diff --git a/test/api/results/test-116 b/test/api/results/test-116
new file mode 100644 (file)
index 0000000..3cb18d3
--- /dev/null
@@ -0,0 +1,26 @@
+# random seed: R02S7f8abf2d360ae53f6acb756fc1d06756
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 250 250 950 950
+  start transform 1 0 0 1 0 0
+    start transform 1 0 -0 1 0 0
+      start clip glyph 3
+        start transform 1 0 0 1 0 0
+          solid 0 0 255 127
+        end transform
+      end clip
+    end transform
+    push group
+      start transform 1 0 0 1 200 200
+        start transform 1 0 -0 1 0 0
+          start clip glyph 3
+            start transform 1 0 0 1 0 0
+              solid 255 165 0 178
+            end transform
+          end clip
+        end transform
+      end transform
+    pop group mode 4
+  end transform
+end clip
diff --git a/test/api/results/test-123 b/test/api/results/test-123
new file mode 100644 (file)
index 0000000..21f2411
--- /dev/null
@@ -0,0 +1,47 @@
+# random seed: R02Sa683270814db638bd7dc3f8fc211d03f
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 0 0 1e+03 1e+03
+  start transform 1 0 0 1 0 0
+    push group
+      start transform 1 0 -0 1 0 0
+        start clip glyph 3
+          start transform 1 0 0 1 0 0
+            solid 0 0 0 255
+          end transform
+        end clip
+      end transform
+    pop group mode 3
+    push group
+      start transform 1 0 0 1 333 667
+        start transform 0.5 0 0 0.5 0 0
+          start transform 1 0 0 1 -333 -667
+            start transform 1 0 -0 1 0 0
+              start clip glyph 2
+                start transform 1 0 0 1 0 0
+                  solid 255 220 1 255
+                end transform
+              end clip
+            end transform
+          end transform
+        end transform
+      end transform
+      push group
+        start transform 1 0 0 1 667 333
+          start transform 0.5 0 0 0.5 0 0
+            start transform 1 0 0 1 -667 -333
+              start transform 1 0 -0 1 0 0
+                start clip glyph 2
+                  start transform 1 0 0 1 0 0
+                    solid 104 199 232 255
+                  end transform
+                end clip
+              end transform
+            end transform
+          end transform
+        end transform
+      pop group mode 5
+    pop group mode 3
+  end transform
+end clip
diff --git a/test/api/results/test-154 b/test/api/results/test-154
new file mode 100644 (file)
index 0000000..f108da8
--- /dev/null
@@ -0,0 +1,40 @@
+# random seed: R02S46170a7a8abc3ad07d2b70fd08efc176
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 0 500 500 1e+03
+  start transform 1 0 0 1 0 0
+    start transform 1 0 -0 1 0 0
+      paint color glyph 164; acting as failed
+    end transform
+    start clip rectangle 100 100 900 900
+      start transform 1 0 -0 1 0 0
+        paint color glyph 93; acting as failed
+      end transform
+      start clip rectangle 0 0 1e+03 1e+03
+        start transform 1 0 -0 1 0 0
+          start clip glyph 2
+            start transform 1 0 0 1 0 0
+              radial gradient
+                p0 166 768 radius 0
+                p1 166 768 radius 256
+                colors 2
+                  0 0 128 0 255
+                  0.5 255 255 255 255
+                  1 255 0 0 255
+            end transform
+          end clip
+        end transform
+      end clip
+    end clip
+    push group
+      start transform 1 0 -0 1 0 0
+        start clip glyph 159
+          start transform 1 0 0 1 0 0
+            solid 128 128 128 102
+          end transform
+        end clip
+      end transform
+    pop group mode 3
+  end transform
+end clip
diff --git a/test/api/results/test-165 b/test/api/results/test-165
new file mode 100644 (file)
index 0000000..b122f66
--- /dev/null
@@ -0,0 +1,22 @@
+# random seed: R02Sd7e42dc5034eae428f9fdf486603e319
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 100 250 1.2e+03 950
+  start transform 1 0 0 1 0 0
+    start transform 1 0 -0 1 0 0
+      start clip glyph 165
+        start transform 1 0 0 1 0 0
+          linear gradient
+            p0 100 950
+            p1 2.3e+03 950
+            p2 -1e+03 250
+            colors 0
+              0 255 0 0 255
+              0.5 0 0 255 255
+              1 255 255 0 255
+        end transform
+      end clip
+    end transform
+  end transform
+end clip
diff --git a/test/api/results/test-175 b/test/api/results/test-175
new file mode 100644 (file)
index 0000000..be14b81
--- /dev/null
@@ -0,0 +1,36 @@
+# random seed: R02Se9d7defb0878dc8a90f62d9f42a715f3
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 0 0 1e+03 1e+03
+  start transform 1 0 0 1 0 0
+    push group
+      start transform 1 0 0 1 150 0
+        start transform 1 0 -0 1 0 0
+          start clip glyph 174
+            start transform 1 0 0 1 0 0
+              solid 0 128 0 255
+            end transform
+          end clip
+        end transform
+      end transform
+    pop group mode 3
+    push group
+      start transform 1 0 0 1 -150 0
+        start transform 1 0 -0 1 0 0
+          start clip glyph 174
+            start transform 1 0 0 1 0 0
+              linear gradient
+                p0 500 250
+                p1 500 950
+                p2 600 250
+                colors 1
+                  0 255 0 0 255
+                  1 0 0 255 255
+            end transform
+          end clip
+        end transform
+      end transform
+    pop group mode 3
+  end transform
+end clip
diff --git a/test/api/results/test-6 b/test/api/results/test-6
new file mode 100644 (file)
index 0000000..94b543e
--- /dev/null
@@ -0,0 +1,21 @@
+# random seed: R02S68886e711ff0007004bb488f8b8c3904
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 100 250 900 950
+  start transform 1 0 0 1 0 0
+    start transform 1 0 -0 1 0 0
+      start clip glyph 6
+        start transform 1 0 0 1 0 0
+          linear gradient
+            p0 100 250
+            p1 900 250
+            p2 100 300
+            colors 1
+              0 255 0 0 255
+              1 0 0 255 255
+        end transform
+      end clip
+    end transform
+  end transform
+end clip
diff --git a/test/api/results/test-92 b/test/api/results/test-92
new file mode 100644 (file)
index 0000000..422e917
--- /dev/null
@@ -0,0 +1,21 @@
+# random seed: R02Se8a9546dc34a7e4d4f5c5e997ddcf0d8
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 0 0 1e+03 1e+03
+  start transform 1 0 0 1 0 0
+    start transform 1 0 -0 1 0 0
+      start clip glyph 2
+        start transform 1 0 0 1 0 0
+          radial gradient
+            p0 166 768 radius 0
+            p1 166 768 radius 256
+            colors 1
+              0 0 128 0 255
+              0.5 255 255 255 255
+              1 255 0 0 255
+        end transform
+      end clip
+    end transform
+  end transform
+end clip
diff --git a/test/api/results/testvf-10 b/test/api/results/testvf-10
new file mode 100644 (file)
index 0000000..9b399db
--- /dev/null
@@ -0,0 +1,22 @@
+# random seed: R02S4cc6a292019f2eefbbaf24127cc6b053
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 0 0 1e+03 1e+03
+  start transform 1 0 0 1 0 0
+    start transform 1 0 -0 1 0 0
+      start clip glyph 174
+        start transform 1 0 0 1 0 0
+          sweep gradient
+            center 500 600
+            angles 0 6.28
+            colors 0
+              0.25 250 240 230 255
+              0.417 0 0 255 255
+              0.583 255 0 0 255
+              0.75 47 79 79 255
+        end transform
+      end clip
+    end transform
+  end transform
+end clip
diff --git a/test/api/results/testvf-106 b/test/api/results/testvf-106
new file mode 100644 (file)
index 0000000..7ab6569
--- /dev/null
@@ -0,0 +1,30 @@
+# random seed: R02S2b4bb33484e694adbb383b09d19251a7
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 118 -22.9 750 750
+  start transform 1 0 0 1 0 0
+    start transform 1 0 -0 1 0 0
+      start clip glyph 3
+        start transform 1 0 0 1 0 0
+          solid 0 0 255 127
+        end transform
+      end clip
+    end transform
+    push group
+      start transform 1 0 0 1 1e+03 1e+03
+        start transform 1 0.364 0.176 1 0 0
+          start transform 1 0 0 1 -1e+03 -1e+03
+            start transform 1 0 -0 1 0 0
+              start clip glyph 3
+                start transform 1 0 0 1 0 0
+                  solid 255 165 0 178
+                end transform
+              end clip
+            end transform
+          end transform
+        end transform
+      end transform
+    pop group mode 4
+  end transform
+end clip
diff --git a/test/api/results/testvf-116 b/test/api/results/testvf-116
new file mode 100644 (file)
index 0000000..9ac2926
--- /dev/null
@@ -0,0 +1,26 @@
+# random seed: R02S5710187ea075c431f16412c38d1f7407
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 250 250 950 950
+  start transform 1 0 0 1 0 0
+    start transform 1 0 -0 1 0 0
+      start clip glyph 3
+        start transform 1 0 0 1 0 0
+          solid 0 0 255 127
+        end transform
+      end clip
+    end transform
+    push group
+      start transform 1 0 0 1 200 200
+        start transform 1 0 -0 1 0 0
+          start clip glyph 3
+            start transform 1 0 0 1 0 0
+              solid 255 165 0 178
+            end transform
+          end clip
+        end transform
+      end transform
+    pop group mode 4
+  end transform
+end clip
diff --git a/test/api/results/testvf-123 b/test/api/results/testvf-123
new file mode 100644 (file)
index 0000000..d2d8b67
--- /dev/null
@@ -0,0 +1,47 @@
+# random seed: R02S486e6425a6369f1d079b0c273210d642
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 0 0 1e+03 1e+03
+  start transform 1 0 0 1 0 0
+    push group
+      start transform 1 0 -0 1 0 0
+        start clip glyph 3
+          start transform 1 0 0 1 0 0
+            solid 0 0 0 255
+          end transform
+        end clip
+      end transform
+    pop group mode 3
+    push group
+      start transform 1 0 0 1 333 667
+        start transform 0.5 0 0 0.5 0 0
+          start transform 1 0 0 1 -333 -667
+            start transform 1 0 -0 1 0 0
+              start clip glyph 2
+                start transform 1 0 0 1 0 0
+                  solid 255 220 1 255
+                end transform
+              end clip
+            end transform
+          end transform
+        end transform
+      end transform
+      push group
+        start transform 1 0 0 1 667 333
+          start transform 0.5 0 0 0.5 0 0
+            start transform 1 0 0 1 -667 -333
+              start transform 1 0 -0 1 0 0
+                start clip glyph 2
+                  start transform 1 0 0 1 0 0
+                    solid 104 199 232 255
+                  end transform
+                end clip
+              end transform
+            end transform
+          end transform
+        end transform
+      pop group mode 5
+    pop group mode 3
+  end transform
+end clip
diff --git a/test/api/results/testvf-154 b/test/api/results/testvf-154
new file mode 100644 (file)
index 0000000..cd6e9b9
--- /dev/null
@@ -0,0 +1,40 @@
+# random seed: R02Sd6c6e6b574cffce42448b4c7ec9ed3b1
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 0 500 500 1e+03
+  start transform 1 0 0 1 0 0
+    start transform 1 0 -0 1 0 0
+      paint color glyph 164; acting as failed
+    end transform
+    start clip rectangle 100 100 900 900
+      start transform 1 0 -0 1 0 0
+        paint color glyph 93; acting as failed
+      end transform
+      start clip rectangle 0 0 1e+03 1e+03
+        start transform 1 0 -0 1 0 0
+          start clip glyph 2
+            start transform 1 0 0 1 0 0
+              radial gradient
+                p0 166 768 radius 0
+                p1 166 768 radius 256
+                colors 2
+                  0 0 128 0 255
+                  0.5 255 255 255 255
+                  1 255 0 0 255
+            end transform
+          end clip
+        end transform
+      end clip
+    end clip
+    push group
+      start transform 1 0 -0 1 0 0
+        start clip glyph 159
+          start transform 1 0 0 1 0 0
+            solid 128 128 128 102
+          end transform
+        end clip
+      end transform
+    pop group mode 3
+  end transform
+end clip
diff --git a/test/api/results/testvf-165 b/test/api/results/testvf-165
new file mode 100644 (file)
index 0000000..94de0b7
--- /dev/null
@@ -0,0 +1,22 @@
+# random seed: R02S4f2af10d205b3b3052f5a575490a2686
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 100 250 1.2e+03 950
+  start transform 1 0 0 1 0 0
+    start transform 1 0 -0 1 0 0
+      start clip glyph 165
+        start transform 1 0 0 1 0 0
+          linear gradient
+            p0 100 950
+            p1 2.3e+03 950
+            p2 -1e+03 250
+            colors 0
+              0 255 0 0 255
+              0.5 0 0 255 255
+              1 255 255 0 255
+        end transform
+      end clip
+    end transform
+  end transform
+end clip
diff --git a/test/api/results/testvf-175 b/test/api/results/testvf-175
new file mode 100644 (file)
index 0000000..f0b6e9a
--- /dev/null
@@ -0,0 +1,36 @@
+# random seed: R02S4c022e014005a52e2898416210be4ddf
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 0 0 1e+03 1e+03
+  start transform 1 0 0 1 0 0
+    push group
+      start transform 1 0 0 1 150 0
+        start transform 1 0 -0 1 0 0
+          start clip glyph 174
+            start transform 1 0 0 1 0 0
+              solid 0 128 0 255
+            end transform
+          end clip
+        end transform
+      end transform
+    pop group mode 3
+    push group
+      start transform 1 0 0 1 -150 0
+        start transform 1 0 -0 1 0 0
+          start clip glyph 174
+            start transform 1 0 0 1 0 0
+              linear gradient
+                p0 500 250
+                p1 500 950
+                p2 600 250
+                colors 1
+                  0 255 0 0 255
+                  1 0 0 255 255
+            end transform
+          end clip
+        end transform
+      end transform
+    pop group mode 3
+  end transform
+end clip
diff --git a/test/api/results/testvf-6 b/test/api/results/testvf-6
new file mode 100644 (file)
index 0000000..73c70ed
--- /dev/null
@@ -0,0 +1,21 @@
+# random seed: R02Sc96e8c0cb2d824e493d9a1088730d188
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 100 250 900 950
+  start transform 1 0 0 1 0 0
+    start transform 1 0 -0 1 0 0
+      start clip glyph 6
+        start transform 1 0 0 1 0 0
+          linear gradient
+            p0 100 250
+            p1 900 250
+            p2 100 300
+            colors 1
+              0 255 0 0 255
+              1 0 0 255 255
+        end transform
+      end clip
+    end transform
+  end transform
+end clip
diff --git a/test/api/results/testvf-92 b/test/api/results/testvf-92
new file mode 100644 (file)
index 0000000..382d1ac
--- /dev/null
@@ -0,0 +1,21 @@
+# random seed: R02See3981a17ce77670e1392178e6b57952
+# Start of hb tests
+# Start of paint tests
+# Start of ot tests
+start clip rectangle 0 0 1e+03 1e+03
+  start transform 1 0 0 1 0 0
+    start transform 1 0 -0 1 0 0
+      start clip glyph 2
+        start transform 1 0 0 1 0 0
+          radial gradient
+            p0 166 768 radius 0
+            p1 166 768 radius 256
+            colors 1
+              0 0 128 0 255
+              0.5 255 255 255 255
+              1 255 0 0 255
+        end transform
+      end clip
+    end transform
+  end transform
+end clip
diff --git a/test/api/test-base-minmax.c b/test/api/test-base-minmax.c
new file mode 100644 (file)
index 0000000..332c266
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2023  Behdad Esfahbod
+ *
+ *  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-test.h"
+
+#include <hb-ot.h>
+
+/* Unit tests for hb-ot-layout.h font extents */
+
+static void
+test_ot_layout_font_extents (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/base-minmax.ttf");
+  hb_font_t *font = hb_font_create (face);
+
+  hb_font_extents_t extents;
+
+  g_assert (hb_ot_layout_get_font_extents2 (font, HB_DIRECTION_LTR,
+                                           HB_SCRIPT_LATIN, HB_LANGUAGE_INVALID,
+                                           &extents));
+  g_assert_cmpint (extents.ascender, ==, 2000);
+
+  g_assert (hb_ot_layout_get_font_extents2 (font, HB_DIRECTION_LTR,
+                                           HB_SCRIPT_LATIN, hb_language_from_string ("xx", -1),
+                                           &extents));
+  g_assert_cmpint (extents.ascender, ==, 2000);
+
+  g_assert (!hb_ot_layout_get_font_extents2 (font, HB_DIRECTION_LTR,
+                                            HB_SCRIPT_ARABIC, HB_LANGUAGE_INVALID,
+                                            &extents));
+  g_assert_cmpint (extents.ascender, ==, 3000);
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_ot_layout_font_extents);
+
+  return hb_test_run();
+}
index 982c683..4e02cd0 100644 (file)
@@ -41,6 +41,70 @@ test_ot_layout_base (void)
                                       &position));
   g_assert_cmpint (46, ==, position);
 
+  g_assert (hb_ot_layout_get_baseline2 (font, HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT, HB_DIRECTION_TTB,
+                                       HB_SCRIPT_HAN,
+                                       hb_language_from_string ("en", -1),
+                                       &position));
+  g_assert_cmpint (46, ==, position);
+
+  g_assert (!hb_ot_layout_get_baseline (font, HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT, HB_DIRECTION_TTB,
+                                       HB_TAG ('h','a','n','i'),
+                                       HB_TAG ('E','N','G',' '),
+                                       &position));
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+}
+
+static void
+test_ot_layout_base_with_fallback (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/base.ttf");
+  hb_font_t *font = hb_font_create (face);
+
+  hb_position_t position;
+  hb_ot_layout_get_baseline_with_fallback (font, HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT, HB_DIRECTION_TTB,
+                                          HB_TAG ('h','a','n','i'),
+                                          HB_TAG ('E','N','G',' '),
+                                          &position);
+  g_assert_cmpint (46, ==, position);
+
+  hb_ot_layout_get_baseline_with_fallback2 (font, HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT, HB_DIRECTION_TTB,
+                                           HB_SCRIPT_HAN,
+                                           hb_language_from_string ("en", -1),
+                                           &position);
+  g_assert_cmpint (46, ==, position);
+
+  hb_ot_layout_get_baseline_with_fallback (font, HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT, HB_DIRECTION_TTB,
+                                          HB_TAG ('h','a','n','i'),
+                                          HB_TAG ('E','N','G',' '),
+                                          &position);
+  g_assert_cmpint (1000, ==, position);
+
+  hb_ot_layout_get_baseline_with_fallback (font, HB_OT_LAYOUT_BASELINE_TAG_MATH, HB_DIRECTION_LTR,
+                                          HB_TAG ('h','a','n','i'),
+                                          HB_TAG ('E','N','G',' '),
+                                          &position);
+  g_assert_cmpint (271, ==, position);
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+
+  face = hb_test_open_font_file ("fonts/base2.ttf");
+  font = hb_font_create (face);
+
+  hb_ot_layout_get_baseline_with_fallback (font, HB_OT_LAYOUT_BASELINE_TAG_HANGING, HB_DIRECTION_LTR,
+                                          HB_SCRIPT_BENGALI,
+                                          HB_TAG ('E','N','G',' '),
+                                          &position);
+  g_assert_cmpint (622, ==, position);
+
+  hb_ot_layout_get_baseline_with_fallback (font, HB_OT_LAYOUT_BASELINE_TAG_HANGING, HB_DIRECTION_LTR,
+                                          HB_SCRIPT_TIBETAN,
+                                          HB_TAG ('E','N','G',' '),
+                                          &position);
+  g_assert_cmpint (600, ==, position);
+
   hb_font_destroy (font);
   hb_face_destroy (face);
 }
@@ -51,6 +115,7 @@ main (int argc, char **argv)
   hb_test_init (&argc, &argv);
 
   hb_test_add (test_ot_layout_base);
+  hb_test_add (test_ot_layout_base_with_fallback);
 
   return hb_test_run();
 }
diff --git a/test/api/test-be-glyph-advance.c b/test/api/test-be-glyph-advance.c
new file mode 100644 (file)
index 0000000..300746d
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright © 2022  Behdad Esfahbod
+ *
+ *  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-test.h"
+
+#include <hb.h>
+
+static void
+test_maxp_and_hmtx (void)
+{
+  hb_face_t *face;
+  hb_font_t *font;
+
+  const char maxp_data[] = "\x00\x00\x50\x00" // version
+                          "\x00\x05" // numGlyphs
+                          ;
+  const char loca_data[18] = "";
+  const char hhea_data[36] =
+    "\x00\x01\x00\x00" /* FixedVersion<>version;        * 0x00010000u for version 1.0. */
+    "\x02\x00" /* FWORD                ascender;        * Typographic ascent. */
+    "\x00\x10" /* FWORD                descender;       * Typographic descent. */
+    "\x00\x00" /* FWORD                lineGap;         * Typographic line gap. */
+    "\x00\x00" /* UFWORD       advanceMax;      * Maximum advance width/height value in metrics table. */
+    "\x00\x00" /* FWORD                minLeadingBearing;  * Minimum left/top sidebearing value in metrics table. */
+    "\x00\x00" /* FWORD                minTrailingBearing;  * Minimum right/bottom sidebearing value; */
+    "\x01\x00" /* FWORD                maxExtent;       * horizontal: Max(lsb + (xMax - xMin)), */
+    "\x00\x00" /* HBINT16      caretSlopeRise;  * Used to calculate the slope of the,*/
+    "\x00\x00" /* HBINT16      caretSlopeRun;   * 0 for vertical caret, 1 for horizontal. */
+    "\x00\x00" /* HBINT16      caretOffset;     * The amount by which a slanted */
+    "\x00\x00" /* HBINT16      reserved1;       * Set to 0. */
+    "\x00\x00" /* HBINT16      reserved2;       * Set to 0. */
+    "\x00\x00" /* HBINT16      reserved3;       * Set to 0. */
+    "\x00\x00" /* HBINT16      reserved4;       * Set to 0. */
+    "\x00\x00" /* HBINT16      metricDataFormat; * 0 for current format. */
+    "\x00\x02" /* HBUINT16     numberOfLongMetrics;  * Number of LongMetric entries in metric table. */
+    ;
+  const char hmtx_data[18] =
+    "\x00\x01\x00\x02" /* glyph 0 advance lsb */
+    "\x00\x03\x00\x04" /* glyph 1 advance lsb */
+    "\x00\x05"         /* glyph 2         lsb */
+    "\x00\x06"         /* glyph 3         lsb */
+    "\x00\x07"         /* glyph 4         lsb */
+    "\x00\x08"         /* glyph 5 advance */
+    "\x00\x09"         /* glyph 6 advance */
+    ;
+
+  face = hb_face_builder_create ();
+  HB_FACE_ADD_TABLE (face, "maxp", maxp_data);
+  HB_FACE_ADD_TABLE (face, "loca", loca_data);
+  HB_FACE_ADD_TABLE (face, "hhea", hhea_data);
+  HB_FACE_ADD_TABLE (face, "hmtx", hmtx_data);
+  font = hb_font_create (face);
+  hb_face_destroy (face);
+  g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 0), ==, 1);
+  g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 1), ==, 3);
+  g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 2), ==, 3);
+  g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 3), ==, 3);
+  g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 4), ==, 3);
+#ifndef HB_NO_BEYOND_64K
+  g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 5), ==, 8);
+  g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 6), ==, 9);
+  g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 7), ==, 9);
+#endif
+  g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 8), ==, 0);
+  g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 9), ==, 0);
+  g_assert_cmpuint (hb_font_get_glyph_h_advance (font,10), ==, 0);
+  g_assert_cmpuint (hb_font_get_glyph_h_advance (font,11), ==, 0);
+  hb_font_destroy (font);
+}
+
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_maxp_and_hmtx);
+
+  return hb_test_run();
+}
diff --git a/test/api/test-be-num-glyphs.c b/test/api/test-be-num-glyphs.c
new file mode 100644 (file)
index 0000000..866343f
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright © 2022  Behdad Esfahbod
+ *
+ *  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-test.h"
+
+#include <hb.h>
+
+static void
+test_maxp_and_loca (void)
+{
+  hb_face_t *face;
+
+  const char maxp_data[] = "\x00\x00\x50\x00" // version
+                          "\x00\x05" // numGlyphs
+                          ;
+#ifndef HB_NO_BEYOND_64K
+  const char loca_data[18] = "";
+#endif
+
+  face = hb_face_builder_create ();
+  g_assert_cmpuint (hb_face_get_glyph_count (face), ==, 0);
+  hb_face_destroy (face);
+
+  face = hb_face_builder_create ();
+  HB_FACE_ADD_TABLE (face, "maxp", maxp_data);
+  g_assert_cmpuint (hb_face_get_glyph_count (face), ==, 5);
+  hb_face_destroy (face);
+
+#ifndef HB_NO_BEYOND_64K
+  face = hb_face_builder_create ();
+  HB_FACE_ADD_TABLE (face, "maxp", maxp_data);
+  HB_FACE_ADD_TABLE (face, "loca", loca_data);
+  g_assert_cmpuint (hb_face_get_glyph_count (face), ==, 8);
+  hb_face_destroy (face);
+
+  face = hb_face_builder_create ();
+  HB_FACE_ADD_TABLE (face, "loca", loca_data);
+  g_assert_cmpuint (hb_face_get_glyph_count (face), ==, 8);
+  hb_face_destroy (face);
+#endif
+}
+
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_maxp_and_loca);
+
+  return hb_test_run();
+}
index b4518ad..59eef42 100644 (file)
@@ -24,7 +24,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-/* This file tests that all headers can be included from .c files */
+/* This file tests that all headers can be included from C files */
 
 
 #ifdef HAVE_CONFIG_H
index 8a857e1..b6c5814 100644 (file)
@@ -97,20 +97,32 @@ test_collect_unicodes (void)
 {
   hb_face_t *face = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
   hb_set_t *codepoints = hb_set_create();
+  hb_set_t *codepoints2 = hb_set_create();
+  hb_map_t *mapping = hb_map_create();
   hb_codepoint_t cp;
 
   hb_face_collect_unicodes (face, codepoints);
+  hb_face_collect_nominal_glyph_mapping (face, mapping, codepoints2);
+
+  g_assert (hb_set_is_equal (codepoints, codepoints2));
+  g_assert_cmpuint (hb_set_get_population (codepoints), ==, 3);
+  g_assert_cmpuint (hb_map_get_population (mapping), ==, 3);
 
   cp = HB_SET_VALUE_INVALID;
   g_assert (hb_set_next (codepoints, &cp));
+  g_assert (hb_map_has (mapping, cp));
   g_assert_cmpuint (0x61, ==, cp);
   g_assert (hb_set_next (codepoints, &cp));
+  g_assert (hb_map_has (mapping, cp));
   g_assert_cmpuint (0x62, ==, cp);
   g_assert (hb_set_next (codepoints, &cp));
+  g_assert (hb_map_has (mapping, cp));
   g_assert_cmpuint (0x63, ==, cp);
   g_assert (!hb_set_next (codepoints, &cp));
 
   hb_set_destroy (codepoints);
+  hb_set_destroy (codepoints2);
+  hb_map_destroy (mapping);
   hb_face_destroy (face);
 }
 
index e9fae13..f2ca82f 100644 (file)
@@ -210,6 +210,113 @@ test_types_language (void)
   g_assert (HB_LANGUAGE_INVALID != hb_language_get_default ());
 }
 
+static void
+test_types_feature (void)
+{
+  hb_feature_t feature;
+  char buf[100];
+
+  g_assert (hb_feature_from_string ("abcd", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd", buf));
+
+  g_assert (hb_feature_from_string ("abcd=1", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd", buf));
+
+  g_assert (hb_feature_from_string ("+abcd", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd", buf));
+
+  g_assert (hb_feature_from_string ("abcd=0", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("-abcd", buf));
+
+  g_assert (hb_feature_from_string ("-abcd", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("-abcd", buf));
+
+  g_assert (hb_feature_from_string ("abcd=2", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd=2", buf));
+
+  g_assert (hb_feature_from_string ("+abcd=2", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd=2", buf));
+
+  g_assert (hb_feature_from_string ("-abcd=2", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd=2", buf));
+
+  g_assert (hb_feature_from_string ("\"abcd\" on", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd", buf));
+
+  g_assert (hb_feature_from_string ("\"abcd\" off", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("-abcd", buf));
+
+  g_assert (hb_feature_from_string ("\"abcd\" 1", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd", buf));
+
+  g_assert (hb_feature_from_string ("\"abcd\" 0", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("-abcd", buf));
+
+  g_assert (hb_feature_from_string ("\"abcd\" 2", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd=2", buf));
+
+  g_assert (hb_feature_from_string ("abcd[0]", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd[]", buf));
+
+  g_assert (hb_feature_from_string ("abcd[1]", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd[1]", buf));
+
+  g_assert (hb_feature_from_string ("abcd[1]=1", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd[1]", buf));
+
+  g_assert (hb_feature_from_string ("abcd[1]=2", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd[1]=2", buf));
+
+  g_assert (hb_feature_from_string ("abcd[1]=0", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("-abcd[1]", buf));
+
+  g_assert (hb_feature_from_string ("abcd[]", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd", buf));
+
+  g_assert (hb_feature_from_string ("abcd[:]", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd", buf));
+
+  g_assert (hb_feature_from_string ("abcd[1:]", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd[1:]", buf));
+
+  g_assert (hb_feature_from_string ("abcd[:1]", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd[]", buf));
+
+  g_assert (hb_feature_from_string ("abcd[1:3]", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd[1:3]", buf));
+
+  g_assert (hb_feature_from_string ("abcd[1:2]=1", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd[1]", buf));
+
+  g_assert (hb_feature_from_string ("abcd[1:4]=2", -1, &feature));
+  hb_feature_to_string (&feature, buf, 100);
+  g_assert (0 == strcmp ("abcd[1:4]=2", buf));
+}
+
 int
 main (int argc, char **argv)
 {
@@ -220,6 +327,7 @@ main (int argc, char **argv)
   hb_test_add (test_types_tag);
   hb_test_add (test_types_script);
   hb_test_add (test_types_language);
+  hb_test_add (test_types_feature);
 
   return hb_test_run();
 }
diff --git a/test/api/test-coretext.c b/test/api/test-coretext.c
new file mode 100644 (file)
index 0000000..3a67d49
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2022 Red Hat, 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.
+ *
+ * Author: Matthias Clasen
+ */
+
+
+#include "hb-test.h"
+
+#include "hb-coretext.h"
+
+CTFontRef
+get_ctfont (void)
+{
+  CTFontCollectionRef collection;
+  CFArrayRef ctfaces;
+  CTFontDescriptorRef desc;
+  CTFontRef ctfont;
+
+  collection = CTFontCollectionCreateFromAvailableFonts (0);
+  ctfaces = CTFontCollectionCreateMatchingFontDescriptors (collection);
+
+  desc = CFArrayGetValueAtIndex (ctfaces, 0);
+  ctfont = CTFontCreateWithFontDescriptor (desc, 0.0, NULL);
+
+  return ctfont;
+}
+
+static void
+test_native_coretext_basic (void)
+{
+  CTFontRef ctfont;
+  hb_font_t *font;
+  CTFontRef ctfont2;
+
+  ctfont = get_ctfont ();
+
+  g_assert_nonnull (ctfont);
+
+  font = hb_coretext_font_create (ctfont);
+
+  ctfont2 = hb_coretext_font_get_ct_font (font);
+
+  g_assert_true (ctfont2 == ctfont);
+
+  hb_font_destroy (font);
+
+  CFRelease (ctfont);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_native_coretext_basic);
+
+  return hb_test_run ();
+}
index 3313d74..01b0002 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2011  Google, Inc.
+ * Copyright © 2022  Behdad Esfahbod
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Google Author(s): Behdad Esfahbod
  */
 
-/* This file tests that all headers can be included from .cc files */
+/* This file tests that all headers can be included from C++ files,
+ * as well as test the C++ API. */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
 
-#include "test-c.c"
+#include <hb.h>
+#include <hb-subset.h>
+#include <hb-ot.h>
+#include <hb-aat.h>
+
+#ifdef HAVE_GLIB
+#include <hb-glib.h>
+#endif
+
+#ifdef HAVE_ICU
+#include <hb-icu.h>
+#endif
+
+#ifdef HAVE_FREETYPE
+#include <hb-ft.h>
+#endif
+
+#ifdef HAVE_UNISCRIBE
+#include <hb-uniscribe.h>
+#endif
+
+#ifdef HAVE_CORETEXT
+#include <hb-coretext.h>
+#endif
+
+
+/* Test C++ API. */
+
+#include "hb-cplusplus.hh"
+
+#include <cassert>
+#include <functional>
+#include <utility>
+
+int
+main ()
+{
+  hb_buffer_t *b = hb_buffer_create ();
+  hb::shared_ptr<hb_buffer_t> pb {b};
+
+  /* Test copy-construction. */
+  assert (bool (pb));
+  hb::shared_ptr<hb_buffer_t> pb2 {pb};
+  assert (bool (pb2));
+  assert (bool (pb));
+
+  /* Test move-construction. */
+  assert (bool (pb2));
+  hb::shared_ptr<hb_buffer_t> pb4 {std::move (pb2)};
+  assert (!bool (pb2));
+  assert (bool (pb4));
+
+  /* Test copy-assignment. */
+  hb::shared_ptr<hb_buffer_t> pb3;
+  assert (!bool (pb3));
+  pb3 = pb;
+  assert (bool (pb3));
+  assert (bool (pb));
+
+  /* Test move-assignment. */
+  assert (bool (pb));
+  pb2 = std::move (pb);
+  assert (!bool (pb));
+
+  pb.reference ();
+  pb.destroy ();
+
+  pb3.reference ();
+  pb3.destroy ();
+
+  pb3.swap (pb4);
+
+  hb_user_data_key_t key;
+  pb.set_user_data (&key, b, nullptr, true);
+  (void) pb.get_user_data (&key);
+
+  hb::unique_ptr<hb_buffer_t> pb5 {pb3.reference ()};
+
+
+  /* Test that shared_ptr / unique_ptr are std::hash'able, and that they
+   * return the same hash (which is the underlying pointer's hash. */
+  std::hash<hb_buffer_t *> hash {};
+  std::hash<hb::shared_ptr<hb_buffer_t>> hash2 {};
+  std::hash<hb::unique_ptr<hb_buffer_t>> hash3 {};
+
+  assert (hash (b) == hash2 (pb4));
+  assert (hash2 (pb4) == hash2 (pb2));
+  assert (hash (b) == hash3 (pb5));
+
+  return pb == pb.get_empty () || pb == pb2;
+}
index c502f7d..051bbef 100644 (file)
  */
 
 #include "hb-test.h"
+#include <math.h>
 
 #include <hb.h>
+#ifdef HAVE_FREETYPE
+#include <hb-ft.h>
+#endif
 
-#ifdef HB_EXPERIMENTAL_API
-typedef struct user_data_t
+typedef struct draw_data_t
 {
   char *str;
   unsigned size;
   unsigned consumed;
-} user_data_t;
+} draw_data_t;
 
 /* Our modified itoa, why not using libc's? it is going to be used
    in harfbuzzjs where libc isn't available */
@@ -47,8 +50,9 @@ static void _hb_reverse (char *buf, unsigned int len)
     start++; end--;
   }
 }
-static unsigned _hb_itoa (int32_t num, char *buf)
+static unsigned _hb_itoa (float fnum, char *buf)
 {
+  int32_t num = (int32_t) floorf (fnum + .5f);
   unsigned int i = 0;
   hb_bool_t is_negative = num < 0;
   if (is_negative) num = -num;
@@ -95,69 +99,81 @@ test_itoa (void)
 }
 
 static void
-move_to (hb_position_t to_x, hb_position_t to_y, user_data_t *user_data)
+move_to (hb_draw_funcs_t *dfuncs, draw_data_t *draw_data,
+        hb_draw_state_t *st,
+        float to_x, float to_y,
+        void *user_data)
 {
   /* 4 = command character space + comma + array starts with 0 index + nul character space */
-  if (user_data->consumed + 2 * ITOA_BUF_SIZE + 4 > user_data->size) return;
-  user_data->str[user_data->consumed++] = 'M';
-  user_data->consumed += _hb_itoa (to_x, user_data->str + user_data->consumed);
-  user_data->str[user_data->consumed++] = ',';
-  user_data->consumed += _hb_itoa (to_y, user_data->str + user_data->consumed);
+  if (draw_data->consumed + 2 * ITOA_BUF_SIZE + 4 > draw_data->size) return;
+  draw_data->str[draw_data->consumed++] = 'M';
+  draw_data->consumed += _hb_itoa (to_x, draw_data->str + draw_data->consumed);
+  draw_data->str[draw_data->consumed++] = ',';
+  draw_data->consumed += _hb_itoa (to_y, draw_data->str + draw_data->consumed);
 }
 
 static void
-line_to (hb_position_t to_x, hb_position_t to_y, user_data_t *user_data)
+line_to (hb_draw_funcs_t *dfuncs, draw_data_t *draw_data,
+        hb_draw_state_t *st,
+        float to_x, float to_y,
+        void *user_data)
 {
-  if (user_data->consumed + 2 * ITOA_BUF_SIZE + 4 > user_data->size) return;
-  user_data->str[user_data->consumed++] = 'L';
-  user_data->consumed += _hb_itoa (to_x, user_data->str + user_data->consumed);
-  user_data->str[user_data->consumed++] = ',';
-  user_data->consumed += _hb_itoa (to_y, user_data->str + user_data->consumed);
+  if (draw_data->consumed + 2 * ITOA_BUF_SIZE + 4 > draw_data->size) return;
+  draw_data->str[draw_data->consumed++] = 'L';
+  draw_data->consumed += _hb_itoa (to_x, draw_data->str + draw_data->consumed);
+  draw_data->str[draw_data->consumed++] = ',';
+  draw_data->consumed += _hb_itoa (to_y, draw_data->str + draw_data->consumed);
 }
 
 static void
-quadratic_to (hb_position_t control_x, hb_position_t control_y,
-             hb_position_t to_x, hb_position_t to_y,
-             user_data_t *user_data)
+quadratic_to (hb_draw_funcs_t *dfuncs, draw_data_t *draw_data,
+             hb_draw_state_t *st,
+             float control_x, float control_y,
+             float to_x, float to_y,
+             void *user_data)
 {
 
-  if (user_data->consumed + 4 * ITOA_BUF_SIZE + 6 > user_data->size) return;
-  user_data->str[user_data->consumed++] = 'Q';
-  user_data->consumed += _hb_itoa (control_x, user_data->str + user_data->consumed);
-  user_data->str[user_data->consumed++] = ',';
-  user_data->consumed += _hb_itoa (control_y, user_data->str + user_data->consumed);
-  user_data->str[user_data->consumed++] = ' ';
-  user_data->consumed += _hb_itoa (to_x, user_data->str + user_data->consumed);
-  user_data->str[user_data->consumed++] = ',';
-  user_data->consumed += _hb_itoa (to_y, user_data->str + user_data->consumed);
+  if (draw_data->consumed + 4 * ITOA_BUF_SIZE + 6 > draw_data->size) return;
+  draw_data->str[draw_data->consumed++] = 'Q';
+  draw_data->consumed += _hb_itoa (control_x, draw_data->str + draw_data->consumed);
+  draw_data->str[draw_data->consumed++] = ',';
+  draw_data->consumed += _hb_itoa (control_y, draw_data->str + draw_data->consumed);
+  draw_data->str[draw_data->consumed++] = ' ';
+  draw_data->consumed += _hb_itoa (to_x, draw_data->str + draw_data->consumed);
+  draw_data->str[draw_data->consumed++] = ',';
+  draw_data->consumed += _hb_itoa (to_y, draw_data->str + draw_data->consumed);
 }
 
 static void
-cubic_to (hb_position_t control1_x, hb_position_t control1_y,
-         hb_position_t control2_x, hb_position_t control2_y,
-         hb_position_t to_x, hb_position_t to_y,
-         user_data_t *user_data)
+cubic_to (hb_draw_funcs_t *dfuncs, draw_data_t *draw_data,
+         hb_draw_state_t *st,
+         float control1_x, float control1_y,
+         float control2_x, float control2_y,
+         float to_x, float to_y,
+         void *user_data)
 {
-  if (user_data->consumed + 6 * ITOA_BUF_SIZE + 8 > user_data->size) return;
-  user_data->str[user_data->consumed++] = 'C';
-  user_data->consumed += _hb_itoa (control1_x, user_data->str + user_data->consumed);
-  user_data->str[user_data->consumed++] = ',';
-  user_data->consumed += _hb_itoa (control1_y, user_data->str + user_data->consumed);
-  user_data->str[user_data->consumed++] = ' ';
-  user_data->consumed += _hb_itoa (control2_x, user_data->str + user_data->consumed);
-  user_data->str[user_data->consumed++] = ',';
-  user_data->consumed += _hb_itoa (control2_y, user_data->str + user_data->consumed);
-  user_data->str[user_data->consumed++] = ' ';
-  user_data->consumed += _hb_itoa (to_x, user_data->str + user_data->consumed);
-  user_data->str[user_data->consumed++] = ',';
-  user_data->consumed += _hb_itoa (to_y, user_data->str + user_data->consumed);
+  if (draw_data->consumed + 6 * ITOA_BUF_SIZE + 8 > draw_data->size) return;
+  draw_data->str[draw_data->consumed++] = 'C';
+  draw_data->consumed += _hb_itoa (control1_x, draw_data->str + draw_data->consumed);
+  draw_data->str[draw_data->consumed++] = ',';
+  draw_data->consumed += _hb_itoa (control1_y, draw_data->str + draw_data->consumed);
+  draw_data->str[draw_data->consumed++] = ' ';
+  draw_data->consumed += _hb_itoa (control2_x, draw_data->str + draw_data->consumed);
+  draw_data->str[draw_data->consumed++] = ',';
+  draw_data->consumed += _hb_itoa (control2_y, draw_data->str + draw_data->consumed);
+  draw_data->str[draw_data->consumed++] = ' ';
+  draw_data->consumed += _hb_itoa (to_x, draw_data->str + draw_data->consumed);
+  draw_data->str[draw_data->consumed++] = ',';
+  draw_data->consumed += _hb_itoa (to_y, draw_data->str + draw_data->consumed);
 }
 
 static void
-close_path (user_data_t *user_data)
+close_path (hb_draw_funcs_t *dfuncs, draw_data_t *draw_data,
+           hb_draw_state_t *st,
+           void *user_data)
 {
-  if (user_data->consumed + 2 > user_data->size) return;
-  user_data->str[user_data->consumed++] = 'Z';
+  if (draw_data->consumed + 2 > draw_data->size) return;
+  draw_data->str[draw_data->consumed++] = 'Z';
 }
 
 static hb_draw_funcs_t *funcs;
@@ -166,7 +182,7 @@ static hb_draw_funcs_t *funcs2; /* this one translates quadratic calls to cubic
 static void
 test_hb_draw_empty (void)
 {
-  g_assert (!hb_font_draw_glyph (hb_font_get_empty (), 3, funcs, NULL));
+  hb_font_draw_glyph (hb_font_get_empty (), 3, funcs, NULL);
 }
 
 static void
@@ -177,17 +193,17 @@ test_hb_draw_glyf (void)
   hb_face_destroy (face);
 
   char str[1024];
-  user_data_t user_data = {
+  draw_data_t draw_data = {
     .str = str,
     .size = sizeof (str),
     .consumed = 0
   };
 
-  user_data.consumed = 0;
-  g_assert (!hb_font_draw_glyph (font, 4, funcs, &user_data));
+  draw_data.consumed = 0;
+  hb_font_draw_glyph (font, 4, funcs, &draw_data);
 
-  user_data.consumed = 0;
-  g_assert (hb_font_draw_glyph (font, 3, funcs, &user_data));
+  draw_data.consumed = 0;
+  hb_font_draw_glyph (font, 3, funcs, &draw_data);
   char expected[] = "M275,442Q232,442 198,420Q164,397 145,353Q126,309 126,245"
                    "Q126,182 147,139Q167,95 204,73Q240,50 287,50Q330,50 367,70"
                    "Q404,90 427,128L451,116Q431,54 384,21Q336,-13 266,-13"
@@ -195,11 +211,11 @@ test_hb_draw_glyf (void)
                    "Q108,427 160,457Q212,487 272,487Q316,487 354,470Q392,453 417,424"
                    "Q442,395 448,358Q441,321 403,321Q378,321 367,334"
                    "Q355,347 350,366L325,454L371,417Q346,430 321,436Q296,442 275,442Z";
-  g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+  g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
 
   /* Test translating quadratic calls to cubic by a _draw_funcs_t that doesn't set the callback */
-  user_data.consumed = 0;
-  g_assert (hb_font_draw_glyph (font, 3, funcs2, &user_data));
+  draw_data.consumed = 0;
+  hb_font_draw_glyph (font, 3, funcs2, &draw_data);
   char expected2[] = "M275,442C246,442 221,435 198,420C175,405 158,382 145,353"
                     "C132,324 126,288 126,245C126,203 133,168 147,139C160,110 179,88 204,73"
                     "C228,58 256,50 287,50C316,50 342,57 367,70C392,83 412,103 427,128"
@@ -209,15 +225,15 @@ test_hb_draw_glyf (void)
                     "C379,459 400,443 417,424C434,405 444,383 448,358C443,333 428,321 403,321"
                     "C386,321 374,325 367,334C359,343 353,353 350,366L325,454L371,417"
                     "C354,426 338,432 321,436C304,440 289,442 275,442Z";
-  g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1);
+  g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
 
   hb_variation_t var;
   var.tag = HB_TAG ('w','g','h','t');
   var.value = 800;
   hb_font_set_variations (font, &var, 1);
 
-  user_data.consumed = 0;
-  g_assert (hb_font_draw_glyph (font, 3, funcs, &user_data));
+  draw_data.consumed = 0;
+  hb_font_draw_glyph (font, 3, funcs, &draw_data);
   char expected3[] = "M323,448Q297,448 271,430Q244,412 226,371Q209,330 209,261"
                     "Q209,204 225,166Q242,127 272,107Q303,86 344,86Q378,86 404,101"
                     "Q430,115 451,137L488,103Q458,42 404,13Q350,-16 279,-16"
@@ -225,7 +241,7 @@ test_hb_draw_glyf (void)
                     "Q99,440 163,470Q226,501 303,501Q357,501 399,480Q440,460 464,426"
                     "Q488,392 492,352Q475,297 420,297Q390,297 366,319Q342,342 339,401"
                     "L333,469L411,427Q387,438 367,443Q348,448 323,448Z";
-  g_assert_cmpmem (str, user_data.consumed, expected3, sizeof (expected3) - 1);
+  g_assert_cmpmem (str, draw_data.consumed, expected3, sizeof (expected3) - 1);
 
   hb_font_destroy (font);
 }
@@ -238,16 +254,16 @@ test_hb_draw_cff1 (void)
   hb_face_destroy (face);
 
   char str[1024];
-  user_data_t user_data = {
+  draw_data_t draw_data = {
     .str = str,
     .size = sizeof (str),
     .consumed = 0
   };
-  g_assert (hb_font_draw_glyph (font, 3, funcs, &user_data));
+  hb_font_draw_glyph (font, 3, funcs, &draw_data);
   char expected[] = "M203,367C227,440 248,512 268,588L272,588C293,512 314,440 338,367L369,267L172,267L203,367Z"
                    "M3,0L88,0L151,200L390,200L452,0L541,0L319,656L225,656L3,0Z"
                    "M300,653L342,694L201,861L143,806L300,653Z";
-  g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+  g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
 
   hb_font_destroy (font);
 }
@@ -261,18 +277,18 @@ test_hb_draw_cff1_rline (void)
   hb_face_destroy (face);
 
   char str[1024];
-  user_data_t user_data = {
+  draw_data_t draw_data = {
     .str = str,
     .size = sizeof (str),
     .consumed = 0
   };
-  g_assert (hb_font_draw_glyph (font, 1, funcs, &user_data));
+  hb_font_draw_glyph (font, 1, funcs, &draw_data);
   char expected[] = "M775,400C705,400 650,343 650,274L650,250L391,250L713,572L392,893"
                    "L287,1000C311,942 296,869 250,823C250,823 286,858 321,823L571,572"
                    "L150,150L750,150L750,276C750,289 761,300 775,300C789,300 800,289 800,276"
                    "L800,100L150,100C100,100 100,150 100,150C100,85 58,23 0,0L900,0L900,274"
                    "C900,343 844,400 775,400Z";
-  g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+  g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
 
   hb_font_destroy (font);
 }
@@ -285,33 +301,33 @@ test_hb_draw_cff2 (void)
   hb_face_destroy (face);
 
   char str[1024];
-  user_data_t user_data = {
+  draw_data_t draw_data = {
     .str = str,
     .size = sizeof (str)
   };
 
-  user_data.consumed = 0;
-  g_assert (hb_font_draw_glyph (font, 3, funcs, &user_data));
+  draw_data.consumed = 0;
+  hb_font_draw_glyph (font, 3, funcs, &draw_data);
   char expected[] = "M275,442C303,442 337,435 371,417L325,454L350,366"
                    "C357,341 370,321 403,321C428,321 443,333 448,358"
                    "C435,432 361,487 272,487C153,487 43,393 43,236"
                    "C43,83 129,-13 266,-13C360,-13 424,33 451,116L427,128"
                    "C396,78 345,50 287,50C193,50 126,119 126,245C126,373 188,442 275,442Z";
-  g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+  g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
 
   hb_variation_t var;
   var.tag = HB_TAG ('w','g','h','t');
   var.value = 800;
   hb_font_set_variations (font, &var, 1);
 
-  user_data.consumed = 0;
-  g_assert (hb_font_draw_glyph (font, 3, funcs, &user_data));
+  draw_data.consumed = 0;
+  hb_font_draw_glyph (font, 3, funcs, &draw_data);
   char expected2[] = "M323,448C356,448 380,441 411,427L333,469L339,401"
                     "C343,322 379,297 420,297C458,297 480,314 492,352"
                     "C486,433 412,501 303,501C148,501 25,406 25,241"
                     "C25,70 143,-16 279,-16C374,-16 447,22 488,103L451,137"
                     "C423,107 390,86 344,86C262,86 209,148 209,261C209,398 271,448 323,448Z";
-  g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1);
+  g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
 
   hb_font_destroy (font);
 }
@@ -321,7 +337,7 @@ test_hb_draw_ttf_parser_tests (void)
 {
   /* https://github.com/RazrFalcon/ttf-parser/blob/337e7d1c/tests/tests.rs#L50-L133 */
   char str[1024];
-  user_data_t user_data = {
+  draw_data_t draw_data = {
     .str = str,
     .size = sizeof (str)
   };
@@ -330,20 +346,20 @@ test_hb_draw_ttf_parser_tests (void)
     hb_font_t *font = hb_font_create (face);
     hb_face_destroy (face);
     {
-      user_data.consumed = 0;
-      g_assert (hb_font_draw_glyph (font, 0, funcs, &user_data));
+      draw_data.consumed = 0;
+      hb_font_draw_glyph (font, 0, funcs, &draw_data);
       char expected[] = "M50,0L50,750L450,750L450,0L50,0Z";
-      g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+      g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
     }
     {
-      user_data.consumed = 0;
-      g_assert (hb_font_draw_glyph (font, 1, funcs, &user_data));
+      draw_data.consumed = 0;
+      hb_font_draw_glyph (font, 1, funcs, &draw_data);
       char expected[] = "M56,416L56,487L514,487L514,416L56,416ZM56,217L56,288L514,288L514,217L56,217Z";
-      g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+      g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
     }
     {
-      user_data.consumed = 0;
-      g_assert (hb_font_draw_glyph (font, 4, funcs, &user_data));
+      draw_data.consumed = 0;
+      hb_font_draw_glyph (font, 4, funcs, &draw_data);
       char expected[] = "M332,468L197,468L197,0L109,0L109,468L15,468L15,509L109,539"
                        "L109,570Q109,674 155,720Q201,765 283,765Q315,765 342,760"
                        "Q368,754 387,747L364,678Q348,683 327,688Q306,693 284,693"
@@ -351,22 +367,23 @@ test_hb_draw_ttf_parser_tests (void)
                        "M474,737Q494,737 510,724Q525,710 525,681Q525,653 510,639"
                        "Q494,625 474,625Q452,625 437,639Q422,653 422,681"
                        "Q422,710 437,724Q452,737 474,737ZM517,536L517,0L429,0L429,536L517,536Z";
-      g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+      g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
     }
     {
-      user_data.consumed = 0;
-      g_assert (hb_font_draw_glyph (font, 5, funcs, &user_data));
-      char expected[] = "";
-      g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+      draw_data.consumed = 0;
+      hb_font_draw_glyph (font, 5, funcs, &draw_data);
+      char expected[] = "M15,0Q15,0 15,0Z";
+      g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
     }
     {
-      user_data.consumed = 0;
-      g_assert (hb_font_draw_glyph (font, 6, funcs, &user_data));
+      draw_data.consumed = 0;
+      hb_font_draw_glyph (font, 6, funcs, &draw_data);
       char expected[] = "M346,468L211,468L211,0L123,0L123,468L29,468L29,509L123,539"
                        "L123,570Q123,674 169,720Q215,765 297,765Q329,765 356,760"
                        "Q382,754 401,747L378,678Q362,683 341,688Q320,693 298,693"
-                       "Q254,693 233,664Q211,634 211,571L211,536L346,536L346,468Z";
-      g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+                       "Q254,693 233,664Q211,634 211,571L211,536L346,536L346,468Z"
+                       "M15,0Q15,0 15,0Z";
+      g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
     }
 
     hb_font_destroy (font);
@@ -376,15 +393,15 @@ test_hb_draw_ttf_parser_tests (void)
     hb_font_t *font = hb_font_create (face);
     hb_face_destroy (face);
 
-    user_data.consumed = 0;
-    g_assert (hb_font_draw_glyph (font, 1, funcs, &user_data));
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, 1, funcs, &draw_data);
     char expected[] = "M0,0C100,0 150,-20 250,-20C350,-20 400,0 500,0C500,100 520,150 520,250"
                      "C520,350 500,400 500,500C400,500 350,520 250,520C150,520 100,500 0,500"
                      "C0,400 -20,350 -20,250C-20,150 0,100 0,0ZM50,50C50,130 34,170 34,250"
                      "C34,330 50,370 50,450C130,450 170,466 250,466C330,466 370,450 450,450"
                      "C450,370 466,330 466,250C466,170 450,130 450,50C370,50 330,34 250,34"
                      "C170,34 130,50 50,50Z";
-    g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+    g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
 
     hb_font_destroy (font);
   }
@@ -393,12 +410,12 @@ test_hb_draw_ttf_parser_tests (void)
     hb_font_t *font = hb_font_create (face);
     hb_face_destroy (face);
 
-    user_data.consumed = 0;
-    g_assert (hb_font_draw_glyph (font, 1, funcs, &user_data));
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, 1, funcs, &draw_data);
     char expected[] = "M82,0L164,0L164,486L82,486L82,0Z"
                      "M124,586C156,586 181,608 181,639C181,671 156,692 124,692"
                      "C92,692 67,671 67,639C67,608 92,586 124,586Z";
-    g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+    g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
 
     hb_font_destroy (font);
   }
@@ -409,7 +426,7 @@ test_hb_draw_font_kit_glyphs_tests (void)
 {
   /* https://github.com/foliojs/fontkit/blob/master/test/glyphs.js */
   char str[2048];
-  user_data_t user_data = {
+  draw_data_t draw_data = {
     .str = str,
     .size = sizeof (str)
   };
@@ -420,26 +437,26 @@ test_hb_draw_font_kit_glyphs_tests (void)
     hb_face_destroy (face);
 
     /* should get a path for the glyph */
-    user_data.consumed = 0;
-    g_assert (hb_font_draw_glyph (font, 37, funcs, &user_data));
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, 37, funcs, &draw_data);
     char expected[] = "M201,1462L614,1462Q905,1462 1035,1375Q1165,1288 1165,1100"
                      "Q1165,970 1093,886Q1020,801 881,776L881,766Q1214,709 1214,416"
                      "Q1214,220 1082,110Q949,0 711,0L201,0L201,1462ZM371,836L651,836"
                      "Q831,836 910,893Q989,949 989,1083Q989,1206 901,1261"
                      "Q813,1315 621,1315L371,1315L371,836ZM371,692L371,145L676,145"
                      "Q853,145 943,214Q1032,282 1032,428Q1032,564 941,628Q849,692 662,692L371,692Z";
-    g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+    g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
 
     /* should get a path for the glyph */
-    user_data.consumed = 0;
-    g_assert (hb_font_draw_glyph (font, 171, funcs, &user_data));
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, 171, funcs, &draw_data);
     char expected2[] = "M639,-20Q396,-20 256,128Q115,276 115,539Q115,804 246,960Q376,1116 596,1116"
                       "Q802,1116 922,981Q1042,845 1042,623L1042,518L287,518Q292,325 385,225"
                       "Q477,125 645,125Q822,125 995,199L995,51Q907,13 829,-3Q750,-20 639,-20Z"
                       "M594,977Q462,977 384,891Q305,805 291,653L864,653Q864,810 794,894"
                       "Q724,977 594,977ZM471,1266Q519,1328 575,1416Q630,1504 662,1569"
                       "L864,1569L864,1548Q820,1483 733,1388Q646,1293 582,1241L471,1241L471,1266Z";
-    g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1);
+    g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
 
     hb_font_destroy (font);
   }
@@ -457,8 +474,8 @@ test_hb_draw_font_kit_glyphs_tests (void)
     hb_buffer_destroy (buffer);
 
     /* should resolve composite glyphs recursively */
-    user_data.consumed = 0;
-    g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data));
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, codepoint, funcs, &draw_data);
     char expected[] = "M581,274L443,274Q409,274 384,259Q359,243 348,219Q336,194 340,166"
                      "Q343,138 365,111L468,-13Q470,-10 473,-6Q475,-3 477,0L253,0Q225,0 203,8"
                      "Q180,15 168,32Q155,48 155,73L155,269L50,269L50,73Q50,24 69,-10"
@@ -470,16 +487,16 @@ test_hb_draw_font_kit_glyphs_tests (void)
                      "M360,-194Q360,-216 375,-231Q390,-246 412,-246Q434,-246 449,-231"
                      "Q464,-216 464,-194Q464,-172 449,-157Q434,-142 412,-142"
                      "Q390,-142 375,-157Q360,-172 360,-194Z";
-    g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+    g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
 
     /* should transform points of a composite glyph */
-    user_data.consumed = 0;
-    g_assert (hb_font_draw_glyph (font, 2, funcs, &user_data)); /* 2 == arAlef.fina */
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, 2, funcs, &draw_data); /* 2 == arAlef.fina */
     char expected2[] = "M155,624L155,84Q150,90 146,95Q141,99 136,105"
                       "L292,105L292,0L156,0Q128,0 104,14Q79,27 65,51"
                       "Q50,74 50,104L50,624L155,624ZM282,105L312,105"
                       "L312,0L282,0L282,105Z";
-    g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1);
+    g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
 
     hb_font_destroy (font);
   }
@@ -489,11 +506,11 @@ test_hb_draw_font_kit_glyphs_tests (void)
     hb_font_t *font = hb_font_create (face);
     hb_face_destroy (face);
 
-    user_data.consumed = 0;
-    g_assert (hb_font_draw_glyph (font, 5, funcs, &user_data));
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, 5, funcs, &draw_data);
     char expected[] = "M90,0L258,0C456,0 564,122 564,331C564,539 456,656 254,656L90,656L90,0Z"
                      "M173,68L173,588L248,588C401,588 478,496 478,331C478,165 401,68 248,68L173,68Z";
-    g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+    g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
 
     hb_font_destroy (font);
   }
@@ -504,12 +521,12 @@ test_hb_draw_font_kit_glyphs_tests (void)
     hb_font_t *font = hb_font_create (face);
     hb_face_destroy (face);
 
-    user_data.consumed = 0;
-    g_assert (hb_font_draw_glyph (font, 1, funcs, &user_data));
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, 1, funcs, &draw_data);
     char expected[] = "M139,390C175,390 205,419 205,459C205,501 175,530 139,530C103,530 73,501 73,459"
                      "C73,419 103,390 139,390ZM139,-13C175,-13 205,15 205,56C205,97 175,127 139,127"
                      "C103,127 73,97 73,56C73,15 103,-13 139,-13Z";
-    g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+    g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
 
     hb_font_destroy (font);
   }
@@ -521,7 +538,7 @@ test_hb_draw_font_kit_variations_tests (void)
 {
   /* https://github.com/foliojs/fontkit/blob/b310db5/test/variations.js */
   char str[2048];
-  user_data_t user_data = {
+  draw_data_t draw_data = {
     .str = str,
     .size = sizeof (str)
   };
@@ -549,8 +566,8 @@ test_hb_draw_font_kit_variations_tests (void)
     codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint;
     hb_buffer_destroy (buffer);
 
-    user_data.consumed = 0;
-    g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data));
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, codepoint, funcs, &draw_data);
     char expected[] = "M371,-102L371,539L914,539L914,-27Q914,-102 840,-102"
                      "Q796,-102 755,-98L742,-59Q790,-66 836,-66Q871,-66 871,-31L871,504"
                      "L414,504L414,-102L371,-102ZM203,-94Q138,-94 86,-90L74,-52"
@@ -571,7 +588,7 @@ test_hb_draw_font_kit_variations_tests (void)
                      "Q754,410 775,381Q794,407 813,453L848,434Q826,387 801,352Q823,321 848,281"
                      "L813,262Q791,301 775,323Q749,288 715,258ZM348,719L348,754L941,754L941,719"
                      "L348,719ZM936,570Q870,602 817,622Q764,641 727,652L749,688Q852,655 957,605L936,570Z";
-    g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+    g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
 
     hb_font_destroy (font);
   }
@@ -594,8 +611,8 @@ test_hb_draw_font_kit_variations_tests (void)
     codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint;
     hb_buffer_destroy (buffer);
 
-    user_data.consumed = 0;
-    g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data));
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, codepoint, funcs, &draw_data);
     char expected[] = "M371,-102L371,539L914,539L914,-27Q914,-102 840,-102Q796,-102 755,-98"
                      "L742,-59Q790,-66 836,-66Q871,-66 871,-31L871,504L414,504L414,-102"
                      "L371,-102ZM203,-94Q138,-94 86,-90L74,-52Q137,-59 188,-59Q211,-59 222,-46"
@@ -615,7 +632,7 @@ test_hb_draw_font_kit_variations_tests (void)
                      "L848,434Q826,387 801,352Q823,321 848,281L813,262Q791,301 775,323Q749,288 715,258Z"
                      "M348,719L348,754L941,754L941,719L348,719ZM936,570Q870,602 817,622"
                      "Q764,641 727,652L749,688Q852,655 957,605L936,570Z";
-    g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+    g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
 
     hb_font_destroy (font);
   }
@@ -638,8 +655,8 @@ test_hb_draw_font_kit_variations_tests (void)
     codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint;
     hb_buffer_destroy (buffer);
 
-    user_data.consumed = 0;
-    g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data));
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, codepoint, funcs, &draw_data);
     char expected[] = "M371,-102L371,539L914,539L914,-27Q914,-102 840,-102Q796,-102 755,-98"
                      "L742,-59Q790,-66 836,-66Q871,-66 871,-31L871,504L414,504L414,-102"
                      "L371,-102ZM203,-94Q138,-94 86,-90L74,-52Q137,-59 188,-59Q211,-59 222,-46"
@@ -659,7 +676,7 @@ test_hb_draw_font_kit_variations_tests (void)
                      "Q823,321 848,281L813,262Q791,301 775,323Q749,288 715,258ZM348,719L348,754"
                      "L941,754L941,719L348,719ZM936,570Q870,602 817,622"
                      "Q764,641 727,652L749,688Q852,655 957,605L936,570Z";
-    g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+    g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
 
     hb_font_destroy (font);
   }
@@ -685,8 +702,8 @@ test_hb_draw_font_kit_variations_tests (void)
       codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint;
       hb_buffer_destroy (buffer);
 
-      user_data.consumed = 0;
-      g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data));
+      draw_data.consumed = 0;
+      hb_font_draw_glyph (font, codepoint, funcs, &draw_data);
       char expected[] = "M246,15C188,15 147,27 101,68L142,23L117,117C111,143 96,149 81,149"
                        "C65,149 56,141 52,126C71,40 137,-13 244,-13C348,-13 436,46 436,156"
                        "C436,229 405,295 271,349L247,359C160,393 119,439 119,506"
@@ -695,7 +712,7 @@ test_hb_draw_font_kit_variations_tests (void)
                        "C161,665 78,606 78,500C78,414 128,361 224,321L261,305C367,259 395,217 395,152"
                        "C395,65 334,15 246,15ZM267,331L267,759L240,759L240,331L267,331ZM240,-115"
                        "L267,-115L267,331L240,331L240,-115Z";
-      g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+      g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
     }
     {
       var.value = 500;
@@ -709,8 +726,8 @@ test_hb_draw_font_kit_variations_tests (void)
       codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint;
       hb_buffer_destroy (buffer);
 
-      user_data.consumed = 0;
-      g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data));
+      draw_data.consumed = 0;
+      hb_font_draw_glyph (font, codepoint, funcs, &draw_data);
       char expected[] = "M251,36C206,36 165,42 118,61L176,21L161,99C151,152 129,167 101,167"
                        "C78,167 61,155 51,131C54,43 133,-14 247,-14C388,-14 474,64 474,171"
                        "C474,258 430,321 294,370L257,383C188,406 150,438 150,499"
@@ -719,7 +736,7 @@ test_hb_draw_font_kit_variations_tests (void)
                        "C450,597 370,656 264,656C140,656 57,576 57,474C57,373 119,318 227,279"
                        "L263,266C345,236 379,208 379,145C379,76 329,36 251,36ZM289,320"
                        "L289,746L242,746L242,320L289,320ZM240,-115L286,-115L286,320L240,320L240,-115Z";
-      g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+      g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
     }
     /* substitutes GSUB features depending on variations */
     {
@@ -734,8 +751,8 @@ test_hb_draw_font_kit_variations_tests (void)
       codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint;
       hb_buffer_destroy (buffer);
 
-      user_data.consumed = 0;
-      g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data));
+      draw_data.consumed = 0;
+      hb_font_draw_glyph (font, codepoint, funcs, &draw_data);
       char expected[] = "M258,38C197,38 167,48 118,71L192,19L183,103C177,155 155,174 115,174"
                        "C89,174 64,161 51,125C52,36 124,-16 258,-16C417,-16 513,67 513,175"
                        "C513,278 457,328 322,388L289,403C232,429 203,452 203,500C203,562 244,589 301,589"
@@ -743,7 +760,7 @@ test_hb_draw_font_kit_variations_tests (void)
                        "C491,590 408,643 290,643C141,643 57,563 57,460C57,357 122,307 233,256L265,241"
                        "C334,209 363,186 363,130C363,77 320,38 258,38ZM318,616L318,734L252,734L252,616"
                        "L318,616ZM253,-115L319,-115L319,14L253,14L253,-115Z";
-      g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+      g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
     }
 
     hb_font_destroy (font);
@@ -755,7 +772,7 @@ test_hb_draw_estedad_vf (void)
 {
   /* https://github.com/harfbuzz/harfbuzz/issues/2215 */
   char str[2048];
-  user_data_t user_data = {
+  draw_data_t draw_data = {
     .str = str,
     .size = sizeof (str)
   };
@@ -769,18 +786,18 @@ test_hb_draw_estedad_vf (void)
     hb_variation_from_string ("wght=100", -1, &var);
     hb_font_set_variations (font, &var, 1);
 
-    user_data.consumed = 0;
-    g_assert (hb_font_draw_glyph (font, 156, funcs, &user_data));
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, 156, funcs, &draw_data);
     /* Skip empty path where all the points of a path are equal */
     char expected[] = "M150,1158L182,1158Q256,1158 317,1170Q377,1182 421,1213L421,430L521,430"
                      "L521,1490L421,1490L421,1320Q393,1279 344,1262Q294,1244 182,1244L150,1244"
                      "L150,1158ZM1815,-122L1669,-122L1669,642L1552,642L1055,-117L1055,-206"
                      "L1569,-206L1569,-458L1669,-458L1669,-206L1815,-206L1815,-122ZM1569,-122"
                      "L1166,-122L1569,494L1569,-122ZM609,-79L1639,1288L1555,1334L525,-33L609,-79Z";
-    g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+    g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
 
-    user_data.consumed = 0;
-    g_assert (hb_font_draw_glyph (font, 180, funcs, &user_data));
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, 180, funcs, &draw_data);
     /* Skip empty path where all the points of a path are equal */
     char expected2[] = "M120,693Q120,545 177,414Q233,282 333,182Q433,81 567,24"
                       "Q701,-33 856,-33Q1010,-33 1144,24Q1277,81 1377,182Q1477,282 1534,414"
@@ -797,17 +814,17 @@ test_hb_draw_estedad_vf (void)
                       "M1165,334L973,568Q1065,591 1126,658Q1187,725 1187,819"
                       "Q1187,896 1147,956Q1106,1015 1037,1049Q969,1083 886,1083"
                       "L590,1083L590,310L690,310L690,557L860,557L1083,286L1165,334Z";
-    g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1);
+    g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
 
-    user_data.consumed = 0;
-    g_assert (hb_font_draw_glyph (font, 262, funcs, &user_data));
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, 262, funcs, &draw_data);
     /* Skip empty path where all the points of a path are equal */
     char expected3[] = "M422,598Q495,598 545,548Q595,498 595,426Q595,353 545,303Q494,252 422,252"
                       "Q350,252 300,303Q250,353 250,426Q250,499 300,549Q349,598 422,598ZM422,698"
                       "Q347,698 285,662Q223,625 187,564Q150,502 150,426Q150,351 187,289"
                       "Q223,226 285,189Q346,152 422,152Q498,152 560,189Q622,226 658,288"
                       "Q695,351 695,426Q695,502 658,563Q621,625 559,661Q498,698 422,698Z";
-    g_assert_cmpmem (str, user_data.consumed, expected3, sizeof (expected3) - 1);
+    g_assert_cmpmem (str, draw_data.consumed, expected3, sizeof (expected3) - 1);
 
     hb_font_destroy (font);
   }
@@ -819,7 +836,7 @@ test_hb_draw_stroking (void)
   /* https://skia-review.googlesource.com/c/skia/+/266945
      https://savannah.nongnu.org/bugs/index.php?57701 */
   char str[2048];
-  user_data_t user_data = {
+  draw_data_t draw_data = {
     .str = str,
     .size = sizeof (str)
   };
@@ -829,8 +846,8 @@ test_hb_draw_stroking (void)
     hb_font_t *font = hb_font_create (face);
     hb_face_destroy (face);
 
-    user_data.consumed = 0;
-    g_assert (hb_font_draw_glyph (font, 6, funcs, &user_data));
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, 6, funcs, &draw_data);
     /* Skip empty path where all the points of a path are equal */
     char expected[] = "M436,1522Q436,1280 531,1060Q625,839 784,680Q943,521 1164,427Q1384,332 1626,332"
                      "Q1868,332 2089,427Q2309,521 2468,680Q2627,839 2722,1060Q2816,1280 2816,1522"
@@ -842,10 +859,10 @@ test_hb_draw_stroking (void)
                      "Q2996,1342 2947,1165Q2897,987 2809,837Q2721,686 2595,560Q2468,433 2318,345"
                      "Q2167,257 1990,208Q1812,158 1626,158Q1440,158 1263,208Q1085,257 935,345"
                      "Q784,433 658,560Q531,686 443,837Q355,987 306,1165Q256,1342 256,1528Z";
-    g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+    g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
 
-    user_data.consumed = 0;
-    g_assert (hb_font_draw_glyph (font, 7, funcs, &user_data));
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, 7, funcs, &draw_data);
     char expected2[] = "M436,1522Q436,1280 531,1060Q625,839 784,680Q943,521 1164,427"
                       "Q1384,332 1626,332Q1868,332 2089,427Q2309,521 2468,680"
                       "Q2627,839 2722,1060Q2816,1280 2816,1522Q2816,1764 2722,1985"
@@ -860,7 +877,7 @@ test_hb_draw_stroking (void)
                       "Q1812,158 1626,158Q1440,158 1263,208Q1085,257 935,345"
                       "Q784,433 658,560Q531,686 443,837Q355,987 306,1165"
                       "Q256,1342 256,1528Z";
-    g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1);
+    g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
 
     hb_font_destroy (font);
   }
@@ -870,27 +887,184 @@ test_hb_draw_stroking (void)
     hb_font_t *font = hb_font_create (face);
     hb_face_destroy (face);
 
-    user_data.consumed = 0;
-    g_assert (hb_font_draw_glyph (font, 4, funcs, &user_data));
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, 4, funcs, &draw_data);
     /* Skip empty path in CFF */
     char expected[] = "M106,372C106,532 237,662 397,662C557,662 688,532 688,372C688,212 557,81 397,81C237,81 106,212 106,372Z"
                      "M62,373C62,188 212,39 397,39C582,39 731,188 731,373C731,558 582,708 397,708C212,708 62,558 62,373Z";
-    g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+    g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
 
-    user_data.consumed = 0;
-    g_assert (hb_font_draw_glyph (font, 5, funcs, &user_data));
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, 5, funcs, &draw_data);
     /* Fold consequent move-to commands */
     char expected2[] = "M106,372C106,532 237,662 397,662C557,662 688,532 688,372"
                       "C688,212 557,81 397,81C237,81 106,212 106,372ZM62,373"
                       "C62,188 212,39 397,39C582,39 731,188 731,373"
                       "C731,558 582,708 397,708C212,708 62,558 62,373Z";
-    g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1);
+    g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
 
     hb_font_destroy (font);
   }
 }
 
 static void
+test_hb_draw_drawing_funcs (void)
+{
+  char str[2048];
+  draw_data_t draw_data = {
+    .str = str,
+    .size = sizeof (str)
+  };
+
+  {
+    hb_draw_state_t st = HB_DRAW_STATE_DEFAULT;
+    draw_data.consumed = 0;
+    hb_draw_move_to (funcs, &draw_data, &st, 90.f, 0.f);
+    hb_draw_line_to (funcs, &draw_data, &st, 258.f, 0.f);
+    hb_draw_cubic_to (funcs, &draw_data, &st, 456.f, 0.f, 564.f, 122.f, 564.f, 331.f);
+    hb_draw_cubic_to (funcs, &draw_data, &st, 564.f, 539.f, 456.f, 656.f, 254.f, 656.f);
+    hb_draw_line_to (funcs, &draw_data, &st, 90.f, 656.f);
+    hb_draw_line_to (funcs, &draw_data, &st, 90.f, 0.f);
+    hb_draw_close_path (funcs, &draw_data, &st);
+
+    char expected[] = "M90,0L258,0C456,0 564,122 564,331C564,539 456,656 254,656L90,656L90,0Z";
+    g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
+  }
+
+  {
+    hb_draw_state_t st = HB_DRAW_STATE_DEFAULT;
+    draw_data.consumed = 0;
+    hb_draw_move_to (funcs, &draw_data, &st, 155.f, 624.f);
+    hb_draw_line_to (funcs, &draw_data, &st, 155.f, 84.f);
+    hb_draw_quadratic_to (funcs, &draw_data, &st, 150.f, 90.f, 146.f, 95.f);
+    hb_draw_quadratic_to (funcs, &draw_data, &st, 141.f, 99.f, 136.f, 105.f);
+    hb_draw_line_to (funcs, &draw_data, &st, 292.f, 105.f);
+    hb_draw_line_to (funcs, &draw_data, &st, 292.f, 0.f);
+    hb_draw_line_to (funcs, &draw_data, &st, 156.f, 0.f);
+    hb_draw_quadratic_to (funcs, &draw_data, &st, 128.f, 0.f, 104.f, 14.f);
+    hb_draw_quadratic_to (funcs, &draw_data, &st, 79.f, 27.f, 65.f, 51.f);
+    hb_draw_quadratic_to (funcs, &draw_data, &st, 50.f, 74.f, 50.f, 104.f);
+    hb_draw_line_to (funcs, &draw_data, &st, 50.f, 624.f);
+    hb_draw_line_to (funcs, &draw_data, &st, 155.f, 624.f);
+    hb_draw_close_path (funcs, &draw_data, &st);
+
+    char expected[] = "M155,624L155,84Q150,90 146,95Q141,99 136,105"
+                      "L292,105L292,0L156,0Q128,0 104,14Q79,27 65,51"
+                      "Q50,74 50,104L50,624L155,624Z";
+    g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
+  }
+}
+
+static void
+test_hb_draw_synthetic_slant (void)
+{
+  char str[2048];
+  draw_data_t draw_data = {
+    .str = str,
+    .size = sizeof (str)
+  };
+  {
+    hb_face_t *face = hb_test_open_font_file ("fonts/OpenSans-Regular.ttf");
+    hb_font_t *font = hb_font_create (face);
+    hb_face_destroy (face);
+    hb_font_set_synthetic_slant (font, 0.2f);
+
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, 37, funcs, &draw_data);
+    char expected[] = "M493,1462L906,1462Q1197,1462 1310,1375Q1423,1288 1385,1100"
+                     "Q1359,970 1270,886Q1180,801 1036,776L1034,766Q1356,709 1297,416"
+                     "Q1258,220 1104,110Q949,0 711,0L201,0L493,1462ZM538,836L818,836"
+                     "Q998,836 1089,893Q1179,949 1206,1083Q1230,1206 1153,1261"
+                     "Q1076,1315 884,1315L634,1315L538,836ZM509,692L400,145L705,145"
+                     "Q882,145 985,214Q1088,282 1118,428Q1145,564 1066,628Q987,692 800,692L509,692Z";
+    g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
+
+    hb_font_destroy (font);
+  }
+  {
+    hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansPro-Regular.otf");
+    hb_font_t *font = hb_font_create (face);
+    hb_face_destroy (face);
+    hb_font_set_synthetic_slant (font, 0.2f);
+
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, 5, funcs, &draw_data);
+    char expected[] = "M90,0L258,0C456,0 588,122 630,331C672,539 587,656 385,656L221,656L90,0Z"
+                     "M187,68L291,588L366,588C519,588 577,496 544,331C511,165 415,68 262,68L187,68Z";
+    g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
+
+    hb_font_destroy (font);
+  }
+}
+
+static void
+test_hb_draw_subfont_scale (void)
+{
+  char str[2048];
+  draw_data_t draw_data = {
+    .str = str,
+    .size = sizeof (str)
+  };
+  signed x, y;
+  {
+    hb_face_t *face = hb_test_open_font_file ("fonts/OpenSans-Regular.ttf");
+    hb_font_t *font1 = hb_font_create (face);
+    hb_font_t *font2 = hb_font_create_sub_font (font1);
+
+    hb_font_get_scale (font1, &x, &y);
+    hb_font_set_scale (font2, x*2, y*2);
+
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font1, 37, funcs, &draw_data);
+    char expected1[] = "M201,1462L614,1462Q905,1462 1035,1375Q1165,1288 1165,1100"
+                      "Q1165,970 1093,886Q1020,801 881,776L881,766Q1214,709 1214,416"
+                      "Q1214,220 1082,110Q949,0 711,0L201,0L201,1462ZM371,836L651,836"
+                      "Q831,836 910,893Q989,949 989,1083Q989,1206 901,1261"
+                      "Q813,1315 621,1315L371,1315L371,836ZM371,692L371,145L676,145"
+                      "Q853,145 943,214Q1032,282 1032,428Q1032,564 941,628Q849,692 662,692L371,692Z";
+    g_assert_cmpmem (str, draw_data.consumed, expected1, sizeof (expected1) - 1);
+
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font2, 37, funcs, &draw_data);
+    char expected2[] = "M402,2924L1228,2924Q1810,2924 2070,2750Q2330,2576 2330,2200"
+                      "Q2330,1940 2185,1771Q2040,1602 1762,1552L1762,1532Q2428,1418 2428,832"
+                      "Q2428,440 2163,220Q1898,0 1422,0L402,0L402,2924ZM742,1672L1302,1672"
+                      "Q1662,1672 1820,1785Q1978,1898 1978,2166Q1978,2412 1802,2521"
+                      "Q1626,2630 1242,2630L742,2630L742,1672ZM742,1384L742,290L1352,290"
+                      "Q1706,290 1885,427Q2064,564 2064,856Q2064,1128 1881,1256Q1698,1384 1324,1384L742,1384Z";
+    g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
+
+    hb_font_destroy (font1);
+    hb_font_destroy (font2);
+    hb_face_destroy (face);
+  }
+  {
+    hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansPro-Regular.otf");
+    hb_font_t *font1 = hb_font_create (face);
+    hb_font_t *font2 = hb_font_create_sub_font (font1);
+
+    hb_font_get_scale (font1, &x, &y);
+    hb_font_set_scale (font2, x*2, y*2);
+
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font1, 5, funcs, &draw_data);
+    char expected1[] = "M90,0L258,0C456,0 564,122 564,331C564,539 456,656 254,656L90,656L90,0Z"
+                      "M173,68L173,588L248,588C401,588 478,496 478,331C478,165 401,68 248,68L173,68Z";
+    g_assert_cmpmem (str, draw_data.consumed, expected1, sizeof (expected1) - 1);
+
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font2, 5, funcs, &draw_data);
+    char expected2[] = "M180,0L516,0C912,0 1128,244 1128,662C1128,1078 912,1312 508,1312L180,1312L180,0Z"
+                      "M346,136L346,1176L496,1176C802,1176 956,992 956,662C956,330 802,136 496,136L346,136Z";
+    g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
+
+    hb_font_destroy (font1);
+    hb_font_destroy (font2);
+    hb_face_destroy (face);
+  }
+}
+
+static void
 test_hb_draw_immutable (void)
 {
   hb_draw_funcs_t *draw_funcs = hb_draw_funcs_create ();
@@ -900,22 +1074,105 @@ test_hb_draw_immutable (void)
   hb_draw_funcs_destroy (draw_funcs);
 }
 
+#ifdef HAVE_FREETYPE
+static void test_hb_draw_ft (void)
+{
+  char str[1024];
+  draw_data_t draw_data = {
+    .str = str,
+    .size = sizeof (str)
+  };
+  {
+    hb_face_t *face = hb_test_open_font_file ("fonts/glyphs.ttf");
+    hb_font_t *font = hb_font_create (face);
+    hb_ft_font_set_funcs (font);
+    hb_face_destroy (face);
+    {
+      draw_data.consumed = 0;
+      hb_font_draw_glyph (font, 0, funcs, &draw_data);
+      char expected[] = "M50,0L50,750L450,750L450,0L50,0Z";
+      g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
+    }
+    {
+      draw_data.consumed = 0;
+      hb_font_draw_glyph (font, 5, funcs, &draw_data);
+      char expected[] = "M15,0Q15,0 15,0Z";
+      g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
+    }
+    hb_font_destroy (font);
+  }
+  {
+    hb_face_t *face = hb_test_open_font_file ("fonts/cff1_flex.otf");
+    hb_font_t *font = hb_font_create (face);
+    hb_ft_font_set_funcs (font);
+    hb_face_destroy (face);
+
+    draw_data.consumed = 0;
+    hb_font_draw_glyph (font, 1, funcs, &draw_data);
+    char expected[] = "M0,0C100,0 150,-20 250,-20C350,-20 400,0 500,0C500,100 520,150 520,250"
+                     "C520,350 500,400 500,500C400,500 350,520 250,520C150,520 100,500 0,500"
+                     "C0,400 -20,350 -20,250C-20,150 0,100 0,0ZM50,50C50,130 34,170 34,250"
+                     "C34,330 50,370 50,450C130,450 170,466 250,466C330,466 370,450 450,450"
+                     "C450,370 466,330 466,250C466,170 450,130 450,50C370,50 330,34 250,34"
+                     "C170,34 130,50 50,50Z";
+    g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
+
+    hb_font_destroy (font);
+  }
+}
+
+static void
+test_hb_draw_compare_ot_ft (void)
+{
+  char str[1024];
+  draw_data_t draw_data = {
+    .str = str,
+    .size = sizeof (str),
+    .consumed = 0
+  };
+  char str2[1024];
+  draw_data_t draw_data2 = {
+    .str = str2,
+    .size = sizeof (str2),
+    .consumed = 0
+  };
+
+  hb_face_t *face = hb_test_open_font_file ("fonts/cff1_flex.otf");
+  hb_font_t *font = hb_font_create (face);
+
+  hb_font_set_scale (font, 100, 100);
+
+  hb_font_draw_glyph (font, 1, funcs, &draw_data);
+  draw_data.str[draw_data.consumed] = '\0';
+
+  hb_ft_font_set_funcs (font);
+
+  hb_font_draw_glyph (font, 1, funcs, &draw_data2);
+  draw_data2.str[draw_data2.consumed] = '\0';
+
+  g_assert_cmpstr (draw_data.str, ==, draw_data2.str);
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+}
+#endif
+
 int
 main (int argc, char **argv)
 {
   funcs = hb_draw_funcs_create ();
-  hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) move_to);
-  hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) line_to);
-  hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) quadratic_to);
-  hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) cubic_to);
-  hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) close_path);
+  hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) move_to, NULL, NULL);
+  hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) line_to, NULL, NULL);
+  hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) quadratic_to, NULL, NULL);
+  hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) cubic_to, NULL, NULL);
+  hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) close_path, NULL, NULL);
   hb_draw_funcs_make_immutable (funcs);
 
   funcs2 = hb_draw_funcs_create ();
-  hb_draw_funcs_set_move_to_func (funcs2, (hb_draw_move_to_func_t) move_to);
-  hb_draw_funcs_set_line_to_func (funcs2, (hb_draw_line_to_func_t) line_to);
-  hb_draw_funcs_set_cubic_to_func (funcs2, (hb_draw_cubic_to_func_t) cubic_to);
-  hb_draw_funcs_set_close_path_func (funcs2, (hb_draw_close_path_func_t) close_path);
+  hb_draw_funcs_set_move_to_func (funcs2, (hb_draw_move_to_func_t) move_to, NULL, NULL);
+  hb_draw_funcs_set_line_to_func (funcs2, (hb_draw_line_to_func_t) line_to, NULL, NULL);
+  hb_draw_funcs_set_cubic_to_func (funcs2, (hb_draw_cubic_to_func_t) cubic_to, NULL, NULL);
+  hb_draw_funcs_set_close_path_func (funcs2, (hb_draw_close_path_func_t) close_path, NULL, NULL);
   hb_draw_funcs_make_immutable (funcs2);
 
   hb_test_init (&argc, &argv);
@@ -929,17 +1186,18 @@ main (int argc, char **argv)
   hb_test_add (test_hb_draw_font_kit_glyphs_tests);
   hb_test_add (test_hb_draw_font_kit_variations_tests);
   hb_test_add (test_hb_draw_estedad_vf);
-  hb_test_add (test_hb_draw_stroking);
+ if(0) hb_test_add (test_hb_draw_stroking);
+  hb_test_add (test_hb_draw_drawing_funcs);
+  hb_test_add (test_hb_draw_synthetic_slant);
+  hb_test_add (test_hb_draw_subfont_scale);
   hb_test_add (test_hb_draw_immutable);
+#ifdef HAVE_FREETYPE
+  hb_test_add (test_hb_draw_ft);
+  hb_test_add (test_hb_draw_compare_ot_ft);
+#endif
   unsigned result = hb_test_run ();
 
   hb_draw_funcs_destroy (funcs);
   hb_draw_funcs_destroy (funcs2);
   return result;
 }
-#else
-int main (int argc HB_UNUSED, char **argv HB_UNUSED)
-{
-  return 0;
-}
-#endif
diff --git a/test/api/test-extents.c b/test/api/test-extents.c
new file mode 100644 (file)
index 0000000..8600751
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright © 2023 Red Hat, 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.
+ *
+ * Author(s): Matthias Clasen
+ */
+
+#include "hb-test.h"
+
+
+static void
+test_glyph_extents (void)
+{
+  hb_face_t *face;
+  hb_font_t *font;
+  hb_glyph_extents_t extents;
+  hb_bool_t ret;
+
+  /* This font contains a COLRv1 glyph with a ClipBox,
+   * and various components without. The main thing
+   * we test here is that glyphs with no paint return
+   * 0,0,0,0 and not meaningless numbers.
+   */
+
+  face = hb_test_open_font_file ("fonts/adwaita.ttf");
+  font = hb_font_create (face);
+
+  ret = hb_font_get_glyph_extents (font, 0, &extents);
+  g_assert_true (ret);
+  g_assert_true (extents.x_bearing == 0 &&
+                 extents.y_bearing == 0 &&
+                 extents.width     == 0 &&
+                 extents.height    == 0);
+
+  ret = hb_font_get_glyph_extents (font, 1, &extents);
+  g_assert_true (ret);
+  g_assert_true (extents.x_bearing == 0 &&
+                 extents.y_bearing == 0 &&
+                 extents.width     == 0 &&
+                 extents.height    == 0);
+
+  ret = hb_font_get_glyph_extents (font, 2, &extents);
+  g_assert_true (ret);
+  g_assert_true (extents.x_bearing ==   180 &&
+                 extents.y_bearing ==   960 &&
+                 extents.width     ==  1060 &&
+                 extents.height    == -1220);
+
+  ret = hb_font_get_glyph_extents (font, 3, &extents);
+  g_assert_true (ret);
+  g_assert_true (extents.x_bearing ==   188 &&
+                 extents.y_bearing ==   950 &&
+                 extents.width     ==   900 &&
+                 extents.height    == -1200);
+
+  ret = hb_font_get_glyph_extents (font, 4, &extents);
+  g_assert_true (ret);
+  g_assert_true (extents.x_bearing ==   413 &&
+                 extents.y_bearing ==    50 &&
+                 extents.width     ==   150 &&
+                 extents.height    ==   -75);
+
+  ret = hb_font_get_glyph_extents (font, 5, &extents);
+  g_assert_true (ret);
+  g_assert_true (extents.x_bearing ==   638 &&
+                 extents.y_bearing ==   350 &&
+                 extents.width     ==   600 &&
+                 extents.height    ==  -600);
+
+  ret = hb_font_get_glyph_extents (font, 1000, &extents);
+  g_assert_false (ret);
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_glyph_extents);
+
+  return hb_test_run();
+}
diff --git a/test/api/test-ft.c b/test/api/test-ft.c
new file mode 100644 (file)
index 0000000..8154ff4
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright © 2022 Red Hat, 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.
+ *
+ * Author: Matthias Clasen
+ */
+
+
+#include "hb-test.h"
+
+#include "hb-ft.h"
+
+#include FT_FONT_FORMATS_H
+
+static FT_Library ft_library;
+
+static void
+init_freetype (void)
+{
+  FT_Error ft_error;
+  if ((ft_error = FT_Init_FreeType (&ft_library)))
+    abort ();
+}
+
+static void
+cleanup_freetype (void)
+{
+  FT_Done_FreeType (ft_library);
+}
+
+static FT_Face
+get_ft_face (const char *file)
+{
+  FT_Face ft_face;
+
+#if GLIB_CHECK_VERSION(2,37,2)
+  char* path = g_test_build_filename (G_TEST_DIST, file, NULL);
+#else
+  char* path = g_strdup (file);
+#endif
+
+  FT_Error ft_error;
+  if ((ft_error = FT_New_Face (ft_library, path, 0, &ft_face))) {
+    g_free (path);
+    abort();
+  }
+  g_free (path);
+
+  if ((ft_error = FT_Set_Char_Size (ft_face, 2000, 1000, 0, 0)))
+    abort ();
+
+  return ft_face;
+}
+
+static void
+test_native_ft_basic (void)
+{
+  FT_Face ft_face;
+  hb_font_t *font;
+  FT_Face ft_face2;
+
+  init_freetype ();
+
+  ft_face = get_ft_face ("fonts/Cantarell.A.otf");
+
+  g_assert_nonnull (ft_face);
+  g_assert_nonnull (FT_Get_Font_Format (ft_face));
+
+  font = hb_ft_font_create_referenced (ft_face);
+
+  ft_face2 = hb_ft_font_get_face (font);
+
+  g_assert_true (ft_face2 == ft_face);
+
+  ft_face2 = hb_ft_font_lock_face (font);
+
+  g_assert_true (ft_face2 == ft_face);
+
+  hb_ft_font_unlock_face (font);
+
+  hb_ft_font_set_load_flags (font, FT_LOAD_NO_SCALE | FT_LOAD_NO_AUTOHINT);
+  int load_flags = hb_ft_font_get_load_flags (font);
+
+  g_assert_true (load_flags == (FT_LOAD_NO_SCALE | FT_LOAD_NO_AUTOHINT));
+
+  hb_font_destroy (font);
+
+  FT_Done_Face (ft_face);
+
+  cleanup_freetype ();
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_native_ft_basic);
+
+  return hb_test_run ();
+}
diff --git a/test/api/test-glyph-names.c b/test/api/test-glyph-names.c
new file mode 100644 (file)
index 0000000..48ca06b
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright © 2023 Red Hat, 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.
+ *
+ * Author(s): Matthias Clasen
+ */
+
+#include "hb-test.h"
+
+static void
+test_glyph_names_post (void)
+{
+  hb_face_t *face;
+  hb_font_t *font;
+  hb_bool_t ret;
+  char name [64];
+
+  face = hb_test_open_font_file ("fonts/adwaita.ttf");
+  font = hb_font_create (face);
+
+  ret = hb_font_get_glyph_name (font, 0, name, 64);
+  g_assert_true (ret);
+  g_assert_cmpstr (name, ==, ".notdef");
+
+  ret = hb_font_get_glyph_name (font, 1, name, 64);
+  g_assert_true (ret);
+  g_assert_cmpstr (name, ==, ".space");
+
+  ret = hb_font_get_glyph_name (font, 2, name, 64);
+  g_assert_true (ret);
+  g_assert_cmpstr (name, ==, "icon0");
+
+  ret = hb_font_get_glyph_name (font, 3, name, 64);
+  g_assert_true (ret);
+  g_assert_cmpstr (name, ==, "icon0.0");
+
+  ret = hb_font_get_glyph_name (font, 4, name, 64);
+  g_assert_true (ret);
+  g_assert_cmpstr (name, ==, "icon0.1");
+
+  ret = hb_font_get_glyph_name (font, 5, name, 64);
+  g_assert_true (ret);
+  g_assert_cmpstr (name, ==, "icon0.2");
+
+  /* beyond last glyph */
+  ret = hb_font_get_glyph_name (font, 100, name, 64);
+  g_assert_false (ret);
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+}
+
+static void
+test_glyph_names_cff (void)
+{
+  hb_face_t *face;
+  hb_font_t *font;
+  hb_bool_t ret;
+  char name [64];
+
+  face = hb_test_open_font_file ("fonts/SourceSansPro-Regular.otf");
+  font = hb_font_create (face);
+
+  ret = hb_font_get_glyph_name (font, 0, name, 64);
+  g_assert_true (ret);
+  g_assert_cmpstr (name, ==, ".notdef");
+
+  ret = hb_font_get_glyph_name (font, 1, name, 64);
+  g_assert_true (ret);
+  g_assert_cmpstr (name, ==, "space");
+
+  ret = hb_font_get_glyph_name (font, 2, name, 64);
+  g_assert_true (ret);
+  g_assert_cmpstr (name, ==, "A");
+
+  /* beyond last glyph */
+  ret = hb_font_get_glyph_name (font, 2000, name, 64);
+  g_assert_false (ret);
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_glyph_names_post);
+  hb_test_add (test_glyph_names_cff);
+
+  return hb_test_run();
+}
diff --git a/test/api/test-instance-cff2.c b/test/api/test-instance-cff2.c
new file mode 100644 (file)
index 0000000..32b7f13
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright © 2022  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
+ */
+
+#include "hb-test.h"
+#include "hb-subset-test.h"
+
+
+static void
+test_instance_cff2 (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/AdobeVFPrototype.abc.otf");
+  hb_face_t *expected = hb_test_open_font_file ("fonts/AdobeVFPrototype.abc.static.otf");
+
+  hb_set_t *codepoints = hb_set_create();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 97);
+  hb_set_add (codepoints, 98);
+  hb_set_add (codepoints, 99);
+
+  hb_subset_input_t* input = hb_subset_test_create_input (codepoints);
+  hb_subset_input_pin_axis_location (input,
+                                     face_abc,
+                                     HB_TAG ('w', 'g', 'h', 't'),
+                                     250);
+  hb_subset_input_pin_axis_location (input,
+                                     face_abc,
+                                     HB_TAG ('C', 'N', 'T', 'R'),
+                                     0);
+
+  face_abc_subset = hb_subset_test_create_subset (face_abc, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (expected, face_abc_subset, HB_TAG ('C','F','F', '2'));
+  g_assert (hb_face_reference_table (face_abc_subset, HB_TAG ('f', 'v', 'a', 'r'))
+            == hb_blob_get_empty ());
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (expected);
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_instance_cff2);
+
+  return hb_test_run();
+}
index c2bbad2..b5440ef 100644 (file)
@@ -102,6 +102,7 @@ static hb_face_t *cbdt = NULL;
 static hb_face_t *sbix = NULL;
 static hb_face_t *svg = NULL;
 static hb_face_t *empty = NULL;
+static hb_face_t *colrv1 = NULL;
 
 #define assert_color_rgba(colors, i, r, g, b, a) G_STMT_START {        \
   const hb_color_t *_colors = (colors); \
@@ -354,6 +355,7 @@ test_hb_ot_color_has_data (void)
   g_assert (hb_ot_color_has_layers (cbdt) == FALSE);
   g_assert (hb_ot_color_has_layers (sbix) == FALSE);
   g_assert (hb_ot_color_has_layers (svg) == FALSE);
+  g_assert (hb_ot_color_has_layers (colrv1) == FALSE);
 
   g_assert (hb_ot_color_has_palettes (empty) == FALSE);
   g_assert (hb_ot_color_has_palettes (cpal_v0) == TRUE);
@@ -362,6 +364,7 @@ test_hb_ot_color_has_data (void)
   g_assert (hb_ot_color_has_palettes (cbdt) == FALSE);
   g_assert (hb_ot_color_has_palettes (sbix) == FALSE);
   g_assert (hb_ot_color_has_palettes (svg) == FALSE);
+  g_assert (hb_ot_color_has_palettes (colrv1) == TRUE);
 
   g_assert (hb_ot_color_has_svg (empty) == FALSE);
   g_assert (hb_ot_color_has_svg (cpal_v0) == FALSE);
@@ -370,6 +373,7 @@ test_hb_ot_color_has_data (void)
   g_assert (hb_ot_color_has_svg (cbdt) == FALSE);
   g_assert (hb_ot_color_has_svg (sbix) == FALSE);
   g_assert (hb_ot_color_has_svg (svg) == TRUE);
+  g_assert (hb_ot_color_has_svg (colrv1) == FALSE);
 
   g_assert (hb_ot_color_has_png (empty) == FALSE);
   g_assert (hb_ot_color_has_png (cpal_v0) == FALSE);
@@ -378,6 +382,24 @@ test_hb_ot_color_has_data (void)
   g_assert (hb_ot_color_has_png (cbdt) == TRUE);
   g_assert (hb_ot_color_has_png (sbix) == TRUE);
   g_assert (hb_ot_color_has_png (svg) == FALSE);
+  g_assert (hb_ot_color_has_png (colrv1) == FALSE);
+
+  g_assert (hb_ot_color_has_paint (empty) == FALSE);
+  g_assert (hb_ot_color_has_paint (cpal_v0) == FALSE);
+  g_assert (hb_ot_color_has_paint (cpal_v1) == FALSE);
+  g_assert (hb_ot_color_has_paint (cpal) == FALSE);
+  g_assert (hb_ot_color_has_paint (cbdt) == FALSE);
+  g_assert (hb_ot_color_has_paint (sbix) == FALSE);
+  g_assert (hb_ot_color_has_paint (svg) == FALSE);
+  g_assert (hb_ot_color_has_paint (colrv1) == TRUE);
+}
+
+static void
+test_hb_ot_color_glyph_has_paint (void)
+{
+  g_assert (hb_ot_color_has_paint (colrv1));
+  g_assert (hb_ot_color_glyph_has_paint (colrv1, 10));
+  g_assert (!hb_ot_color_glyph_has_paint (colrv1, 20));
 }
 
 static void
@@ -464,6 +486,7 @@ main (int argc, char **argv)
   cbdt = hb_test_open_font_file ("fonts/chromacheck-cbdt.ttf");
   sbix = hb_test_open_font_file ("fonts/chromacheck-sbix.ttf");
   svg = hb_test_open_font_file ("fonts/chromacheck-svg.ttf");
+  colrv1 = hb_test_open_font_file ("fonts/noto_handwriting-cff2_colr_1.otf");
   empty = hb_face_get_empty ();
   hb_test_add (test_hb_ot_color_palette_get_count);
   hb_test_add (test_hb_ot_color_palette_get_name_id_empty);
@@ -480,6 +503,8 @@ main (int argc, char **argv)
   hb_test_add (test_hb_ot_color_has_data);
   hb_test_add (test_hb_ot_color_png);
   hb_test_add (test_hb_ot_color_svg);
+  hb_test_add (test_hb_ot_color_glyph_has_paint);
+
   status = hb_test_run();
   hb_face_destroy (cpal_v0);
   hb_face_destroy (cpal_v1);
@@ -487,5 +512,6 @@ main (int argc, char **argv)
   hb_face_destroy (cbdt);
   hb_face_destroy (sbix);
   hb_face_destroy (svg);
+  hb_face_destroy (colrv1);
   return status;
 }
index e5c9b86..ba3cfd3 100644 (file)
@@ -126,15 +126,39 @@ test_font (hb_font_t *font, hb_codepoint_t cp)
   }
 
   hb_ot_math_has_data (face);
-  hb_ot_math_get_constant (font, HB_OT_MATH_CONSTANT_MATH_LEADING);
+  for (unsigned constant = HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN; constant <= HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT; constant++) {
+    hb_ot_math_get_constant (font, (hb_ot_math_constant_t)constant);
+  }
+
   hb_ot_math_get_glyph_italics_correction (font, cp);
   hb_ot_math_get_glyph_top_accent_attachment (font, cp);
   hb_ot_math_is_glyph_extended_shape (face, cp);
-  hb_ot_math_get_glyph_kerning (font, cp, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0);
-  hb_ot_math_get_glyph_kernings (font, cp, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0, NULL, NULL);
-  hb_ot_math_get_glyph_variants (font, cp, HB_DIRECTION_TTB, 0, NULL, NULL);
-  hb_ot_math_get_min_connector_overlap (font, HB_DIRECTION_RTL);
-  hb_ot_math_get_glyph_assembly (font, cp, HB_DIRECTION_BTT, 0, NULL, NULL, NULL);
+
+  {
+    hb_ot_math_get_glyph_kerning (font, cp, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0);
+    hb_ot_math_get_glyph_kernings (font, cp, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0, NULL, NULL);
+    hb_ot_math_kern_entry_t entries[5];
+    unsigned count = sizeof (entries) / sizeof (entries[0]);
+    hb_ot_math_get_glyph_kernings (font, cp, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0, &count, entries);
+  }
+
+  {
+    hb_ot_math_get_glyph_variants (font, cp, HB_DIRECTION_LTR, 0, NULL, NULL);
+    hb_ot_math_get_glyph_variants (font, cp, HB_DIRECTION_TTB, 0, NULL, NULL);
+    hb_ot_math_glyph_variant_t entries[5];
+    unsigned count = sizeof (entries) / sizeof (entries[0]);
+    hb_ot_math_get_glyph_variants (font, cp, HB_DIRECTION_LTR, 0, &count, entries);
+  }
+
+  {
+    hb_ot_math_get_min_connector_overlap (font, HB_DIRECTION_LTR);
+    hb_ot_math_get_glyph_assembly (font, cp, HB_DIRECTION_LTR, 0, NULL, NULL, NULL);
+    hb_ot_math_get_glyph_assembly (font, cp, HB_DIRECTION_TTB, 0, NULL, NULL, NULL);
+    hb_ot_math_glyph_part_t entries[5];
+    unsigned count = sizeof (entries) / sizeof (entries[0]);
+    hb_position_t corr;
+    hb_ot_math_get_glyph_assembly (font, cp, HB_DIRECTION_LTR, 0, &count, entries, &corr);
+  }
 
   hb_ot_meta_get_entry_tags (face, 0, NULL, NULL);
   hb_blob_destroy (hb_ot_meta_reference_entry (face, HB_OT_META_TAG_DESIGN_LANGUAGES));
@@ -163,11 +187,9 @@ test_font (hb_font_t *font, hb_codepoint_t cp)
   hb_ot_var_normalize_variations (face, NULL, 0, NULL, 0);
   hb_ot_var_normalize_coords (face, 0, NULL, NULL);
 
-#ifdef HB_EXPERIMENTAL_API
   hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
   hb_font_draw_glyph (font, cp, funcs, NULL);
   hb_draw_funcs_destroy (funcs);
-#endif
 
   hb_set_destroy (set);
 
index 9871c08..f2587d8 100644 (file)
@@ -80,7 +80,7 @@ test_advance_tt_var_nohvar (void)
   hb_font_get_glyph_advance_for_direction(font, 2, HB_DIRECTION_TTB, &x, &y);
 
   g_assert_cmpint (x, ==, 0);
-  g_assert_cmpint (y, ==, -1000);
+  g_assert_cmpint (y, ==, -1257);
 
   float coords[1] = { 500.0f };
   hb_font_set_var_coords_design (font, coords, 1);
@@ -92,7 +92,7 @@ test_advance_tt_var_nohvar (void)
   hb_font_get_glyph_advance_for_direction(font, 2, HB_DIRECTION_TTB, &x, &y);
 
   g_assert_cmpint (x, ==, 0);
-  g_assert_cmpint (y, ==, -1000);
+  g_assert_cmpint (y, ==, -1257);
 
   hb_font_destroy (font);
 }
index d688eb3..f3989f7 100644 (file)
@@ -93,10 +93,17 @@ test_ot_name (void)
   name_id = entries[3].name_id;
   g_assert_cmpuint (3, ==, name_id);
   lang = entries[3].language;
+
   g_assert_cmpstr (hb_language_to_string (lang), ==, "en");
   g_assert_cmpuint (27, ==, hb_ot_name_get_utf8 (face, name_id, lang, &text_size, text));
   g_assert_cmpuint (9, ==, text_size);
   g_assert_cmpstr (text, ==, "FontForge");
+
+  g_assert_cmpuint (27, ==, hb_ot_name_get_utf8 (face, name_id, hb_language_from_string ("en_US", -1), &text_size, text));
+  g_assert_cmpuint (8, ==, text_size);
+  g_assert_cmpstr (text, ==, "FontForg");
+
+  g_assert_cmpuint (0, ==, hb_ot_name_get_utf8 (face, name_id, hb_language_from_string ("fa_IR", -1), &text_size, text));
 }
 
 int
diff --git a/test/api/test-paint.c b/test/api/test-paint.c
new file mode 100644 (file)
index 0000000..810b7ac
--- /dev/null
@@ -0,0 +1,682 @@
+/*
+ * Copyright © 2022 Matthias Clasen
+ *
+ *  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-test.h"
+
+#include <hb-features.h>
+#include <hb-ot.h>
+
+#ifdef HB_HAS_FREETYPE
+#include <hb-ft.h>
+
+#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300
+#include FT_COLOR_H
+#endif
+#endif
+
+static inline hb_bool_t
+have_ft_colrv1 (void)
+{
+#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300
+  return TRUE;
+#else
+  return FALSE;
+#endif
+}
+
+/* Unit tests for hb-paint.h */
+
+/* ---- */
+
+typedef struct {
+  int level;
+  GString *string;
+} paint_data_t;
+
+static void print (paint_data_t *data, const char *format, ...) G_GNUC_PRINTF (2, 3);
+
+static void
+print (paint_data_t *data,
+       const char *format,
+       ...)
+{
+  va_list args;
+
+  g_string_append_printf (data->string, "%*s", 2 * data->level, "");
+
+  va_start (args, format);
+  g_string_append_vprintf (data->string, format, args);
+  va_end (args);
+
+  g_string_append (data->string, "\n");
+}
+
+static void
+push_transform (hb_paint_funcs_t *funcs,
+                void *paint_data,
+                float xx, float yx,
+                float xy, float yy,
+                float dx, float dy,
+                void *user_data)
+{
+  paint_data_t *data = paint_data;
+
+  print (data, "start transform %.3g %.3g %.3g %.3g %.3g %.3g", xx, yx, xy, yy, dx, dy);
+  data->level++;
+}
+
+static void
+pop_transform (hb_paint_funcs_t *funcs,
+               void *paint_data,
+               void *user_data)
+{
+  paint_data_t *data = paint_data;
+
+  data->level--;
+  print (data, "end transform");
+}
+
+static hb_bool_t
+paint_color_glyph (hb_paint_funcs_t *funcs,
+                   void *paint_data,
+                   hb_codepoint_t glyph,
+                   hb_font_t *font,
+                   void *user_data)
+{
+  paint_data_t *data = paint_data;
+
+  print (data, "paint color glyph %u; acting as failed", glyph);
+
+  return FALSE;
+}
+
+static void
+push_clip_glyph (hb_paint_funcs_t *funcs,
+                 void *paint_data,
+                 hb_codepoint_t glyph,
+                 hb_font_t *font,
+                 void *user_data)
+{
+  paint_data_t *data = paint_data;
+
+  print (data, "start clip glyph %u", glyph);
+  data->level++;
+}
+
+static void
+push_clip_rectangle (hb_paint_funcs_t *funcs,
+                     void *paint_data,
+                     float xmin, float ymin, float xmax, float ymax,
+                     void *user_data)
+{
+  paint_data_t *data = paint_data;
+
+  print (data, "start clip rectangle %.3g %.3g %.3g %.3g", xmin, ymin, xmax, ymax);
+  data->level++;
+}
+
+static void
+pop_clip (hb_paint_funcs_t *funcs,
+          void *paint_data,
+          void *user_data)
+{
+  paint_data_t *data = paint_data;
+
+  data->level--;
+  print (data, "end clip");
+}
+
+static void
+paint_color (hb_paint_funcs_t *funcs,
+             void *paint_data,
+             hb_bool_t use_foreground,
+             hb_color_t color,
+             void *user_data)
+{
+  paint_data_t *data = paint_data;
+
+  print (data, "solid %d %d %d %d",
+         hb_color_get_red (color),
+         hb_color_get_green (color),
+         hb_color_get_blue (color),
+         hb_color_get_alpha (color));
+}
+
+static hb_bool_t
+paint_image (hb_paint_funcs_t *funcs,
+             void *paint_data,
+             hb_blob_t *blob,
+             unsigned int width,
+             unsigned int height,
+             hb_tag_t format,
+             float slant,
+             hb_glyph_extents_t *extents,
+             void *user_data)
+{
+  paint_data_t *data = paint_data;
+  char buf[5] = { 0, };
+
+  hb_tag_to_string (format, buf);
+  print (data, "image type %s size %u %u slant %.3g extents %d %d %d %d\n",
+         buf, width, height, slant,
+         extents->x_bearing, extents->y_bearing, extents->width, extents->height);
+
+  return TRUE;
+}
+
+static void
+print_color_line (paint_data_t *data,
+                  hb_color_line_t *color_line)
+{
+  hb_color_stop_t *stops;
+  unsigned int len;
+
+  len = hb_color_line_get_color_stops (color_line, 0, NULL, NULL);
+  stops = alloca (len * sizeof (hb_color_stop_t));
+  hb_color_line_get_color_stops (color_line, 0, &len, stops);
+
+  print (data, "colors %d", hb_color_line_get_extend (color_line));
+  data->level += 1;
+  for (unsigned int i = 0; i < len; i++)
+    print (data, "%.3g %d %d %d %d",
+           stops[i].offset,
+           hb_color_get_red (stops[i].color),
+           hb_color_get_green (stops[i].color),
+           hb_color_get_blue (stops[i].color),
+           hb_color_get_alpha (stops[i].color));
+  data->level -= 1;
+}
+
+static void
+paint_linear_gradient (hb_paint_funcs_t *funcs,
+                       void *paint_data,
+                       hb_color_line_t *color_line,
+                       float x0, float y0,
+                       float x1, float y1,
+                       float x2, float y2,
+                       void *user_data)
+{
+  paint_data_t *data = paint_data;
+
+  print (data, "linear gradient");
+  data->level += 1;
+  print (data, "p0 %.3g %.3g", x0, y0);
+  print (data, "p1 %.3g %.3g", x1, y1);
+  print (data, "p2 %.3g %.3g", x2, y2);
+
+  print_color_line (data, color_line);
+  data->level -= 1;
+}
+
+static void
+paint_radial_gradient (hb_paint_funcs_t *funcs,
+                       void *paint_data,
+                       hb_color_line_t *color_line,
+                       float x0, float y0, float r0,
+                       float x1, float y1, float r1,
+                       void *user_data)
+{
+  paint_data_t *data = paint_data;
+
+  print (data, "radial gradient");
+  data->level += 1;
+  print (data, "p0 %.3g %.3g radius %.3g", x0, y0, r0);
+  print (data, "p1 %.3g %.3g radius %.3g", x1, y1, r1);
+
+  print_color_line (data, color_line);
+  data->level -= 1;
+}
+
+static void
+paint_sweep_gradient (hb_paint_funcs_t *funcs,
+                      void *paint_data,
+                      hb_color_line_t *color_line,
+                      float cx, float cy,
+                      float start_angle,
+                      float end_angle,
+                      void *user_data)
+{
+  paint_data_t *data = paint_data;
+
+  print (data, "sweep gradient");
+  data->level++;
+  print (data, "center %.3g %.3g", cx, cy);
+  print (data, "angles %.3g %.3g", start_angle, end_angle);
+
+  print_color_line (data, color_line);
+  data->level -= 1;
+}
+
+static void
+push_group (hb_paint_funcs_t *funcs,
+            void *paint_data,
+            void *user_data)
+{
+  paint_data_t *data = paint_data;
+  print (data, "push group");
+  data->level++;
+}
+
+static void
+pop_group (hb_paint_funcs_t *funcs,
+           void *paint_data,
+           hb_paint_composite_mode_t mode,
+           void *user_data)
+{
+  paint_data_t *data = paint_data;
+  data->level--;
+  print (data, "pop group mode %d", mode);
+}
+
+static hb_paint_funcs_t *
+get_test_paint_funcs (void)
+{
+  static hb_paint_funcs_t *funcs = NULL;
+
+  if (!funcs)
+  {
+    funcs = hb_paint_funcs_create ();
+
+    hb_paint_funcs_set_push_transform_func (funcs, push_transform, NULL, NULL);
+    hb_paint_funcs_set_pop_transform_func (funcs, pop_transform, NULL, NULL);
+    hb_paint_funcs_set_color_glyph_func (funcs, paint_color_glyph, NULL, NULL);
+    hb_paint_funcs_set_push_clip_glyph_func (funcs, push_clip_glyph, NULL, NULL);
+    hb_paint_funcs_set_push_clip_rectangle_func (funcs, push_clip_rectangle, NULL, NULL);
+    hb_paint_funcs_set_pop_clip_func (funcs, pop_clip, NULL, NULL);
+    hb_paint_funcs_set_push_group_func (funcs, push_group, NULL, NULL);
+    hb_paint_funcs_set_pop_group_func (funcs, pop_group, NULL, NULL);
+    hb_paint_funcs_set_color_func (funcs, paint_color, NULL, NULL);
+    hb_paint_funcs_set_image_func (funcs, paint_image, NULL, NULL);
+    hb_paint_funcs_set_linear_gradient_func (funcs, paint_linear_gradient, NULL, NULL);
+    hb_paint_funcs_set_radial_gradient_func (funcs, paint_radial_gradient, NULL, NULL);
+    hb_paint_funcs_set_sweep_gradient_func (funcs, paint_sweep_gradient, NULL, NULL);
+
+    hb_paint_funcs_make_immutable (funcs);
+  }
+
+  return funcs;
+}
+
+typedef struct {
+  const char *font_file;
+  float slant;
+  hb_codepoint_t glyph;
+  unsigned int palette;
+  const char *output;
+} paint_test_t;
+
+#define NOTO_HAND   "fonts/noto_handwriting-cff2_colr_1.otf"
+#define TEST_GLYPHS "fonts/test_glyphs-glyf_colr_1.ttf"
+#define TEST_GLYPHS_VF "fonts/test_glyphs-glyf_colr_1_variable.ttf"
+#define BAD_COLRV1  "fonts/bad_colrv1.ttf"
+#define ROCHER_ABC  "fonts/RocherColorGX.abc.ttf"
+
+/* To verify the rendering visually, use
+ *
+ * hb-view --font-slant SLANT --font-palette PALETTE FONT --glyphs [gidGID=0+1000]
+ *
+ * where GID is the glyph value of the test.
+ */
+static paint_test_t paint_tests[] = {
+  /* COLRv1 */
+  { NOTO_HAND,   0.,  10,   0, "hand-10" },
+  { NOTO_HAND,   0.2f,10,   0, "hand-10.2" },
+
+  { TEST_GLYPHS, 0,    6,   0, "test-6" },   // linear gradient
+  { TEST_GLYPHS, 0,   10,   0, "test-10" },  // sweep gradient
+  { TEST_GLYPHS, 0,   92,   0, "test-92" },  // radial gradient
+  { TEST_GLYPHS, 0,  106,   0, "test-106" },
+  { TEST_GLYPHS, 0,  116,   0, "test-116" }, // compositing
+  { TEST_GLYPHS, 0,  123,   0, "test-123" },
+  { TEST_GLYPHS, 0,  154,   0, "test-154" },
+  { TEST_GLYPHS, 0,  165,   0, "test-165" }, // linear gradient
+  { TEST_GLYPHS, 0,  175,   0, "test-175" }, // layers
+
+  { TEST_GLYPHS_VF, 0,    6,   0, "testvf-6" },
+  { TEST_GLYPHS_VF, 0,   10,   0, "testvf-10" },
+  { TEST_GLYPHS_VF, 0,   92,   0, "testvf-92" },
+  { TEST_GLYPHS_VF, 0,  106,   0, "testvf-106" },
+  { TEST_GLYPHS_VF, 0,  116,   0, "testvf-116" },
+  { TEST_GLYPHS_VF, 0,  123,   0, "testvf-123" },
+  { TEST_GLYPHS_VF, 0,  154,   0, "testvf-154" },
+  { TEST_GLYPHS_VF, 0,  165,   0, "testvf-165" },
+  { TEST_GLYPHS_VF, 0,  175,   0, "testvf-175" },
+
+  { BAD_COLRV1,  0,  154,   0, "bad-154" },  // recursion
+
+  /* COLRv0 */
+  { ROCHER_ABC, 0.3f, 1,   0, "rocher-1" },
+  { ROCHER_ABC, 0.3f, 2,   2, "rocher-2" },
+  { ROCHER_ABC, 0,    3, 200, "rocher-3" },
+};
+
+static void
+test_hb_paint (gconstpointer d,
+               hb_bool_t     use_ft)
+{
+  const paint_test_t *test = d;
+  hb_face_t *face;
+  hb_font_t *font;
+  hb_paint_funcs_t *funcs;
+  paint_data_t data;
+  char *file;
+  char *buffer;
+  gsize len;
+  GError *error = NULL;
+
+  face = hb_test_open_font_file (test->font_file);
+  font = hb_font_create (face);
+
+  hb_font_set_synthetic_slant (font, test->slant);
+
+#ifdef HB_HAS_FREETYPE
+  if (use_ft)
+    hb_ft_font_set_funcs (font);
+#endif
+
+  funcs = get_test_paint_funcs ();
+
+  data.string = g_string_new ("");
+  data.level = 0;
+
+  hb_font_paint_glyph (font, test->glyph, funcs, &data, 0, HB_COLOR (0, 0, 0, 255));
+
+  /* Run
+   *
+   * GENERATE_DATA=1 G_TEST_SRCDIR=./test/api ./build/test/api/test-paint -p TESTCASE > test/api/results/OUTPUT
+   *
+   * to produce the expected results file.
+   */
+  if (getenv ("GENERATE_DATA"))
+    {
+      g_print ("%s", data.string->str);
+      exit (0);
+    }
+
+  file = g_test_build_filename (G_TEST_DIST, "results", test->output, NULL);
+  if (!g_file_get_contents (file, &buffer, &len, &error))
+  {
+    g_test_message ("File %s not found.", file);
+    g_test_fail ();
+    return;
+  }
+
+  char **lines = g_strsplit (data.string->str, "\n", 0);
+  char **expected;
+  if (strstr (buffer, "\r\n"))
+    expected = g_strsplit (buffer, "\r\n", 0);
+  else
+    expected = g_strsplit (buffer, "\n", 0);
+
+  /* Strip initial comments */
+  int i;
+  for (i = 0; expected[i]; i++)
+    {
+      if (expected[i][0] != '#')
+        {
+          if (i > 0)
+            {
+              char **tmp = g_strdupv (expected + i);
+              g_strfreev (expected);
+              expected = tmp;
+            }
+          break;
+        }
+    }
+
+  if (g_strv_length (lines) != g_strv_length (expected))
+  {
+    g_test_message ("Unexpected number of lines in output (%d instead of %d):\n%s", g_strv_length (lines), g_strv_length (expected), data.string->str);
+    g_test_fail ();
+  }
+  else
+  {
+    unsigned int length = g_strv_length (lines);
+    for (unsigned int i = 0; i < length; i++)
+    {
+      if (strcmp (lines[i], expected[i]) != 0)
+      {
+        int pos;
+        for (pos = 0; lines[i][pos]; pos++)
+          if (lines[i][pos] != expected[i][pos])
+            break;
+
+        g_test_message ("Unexpected output at %d:%d (%c instead of %c):\n%s", i, pos, lines[i][pos], expected[i][pos], data.string->str);
+        g_test_fail ();
+      }
+    }
+  }
+
+  g_strfreev (lines);
+  g_strfreev (expected);
+
+  g_free (buffer);
+  g_free (file);
+
+  g_string_free (data.string, TRUE);
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+}
+
+static void
+test_compare_ot_ft (const char *file, hb_codepoint_t glyph)
+{
+  hb_face_t *face;
+  hb_font_t *font;
+  hb_paint_funcs_t *funcs;
+  GString *ot_str;
+  paint_data_t data;
+
+  face = hb_test_open_font_file (file);
+  font = hb_font_create (face);
+
+  funcs = get_test_paint_funcs ();
+
+  data.string = g_string_new ("");
+  data.level = 0;
+
+  hb_font_paint_glyph (font, glyph, funcs, &data, 0, HB_COLOR (0, 0, 0, 255));
+
+  g_assert_true (data.level == 0);
+
+  ot_str = data.string;
+
+#ifdef HB_HAS_FREETYPE
+  hb_ft_font_set_funcs (font);
+#endif
+
+  data.string = g_string_new ("");
+  data.level = 0;
+
+  hb_font_paint_glyph (font, glyph, funcs, &data, 0, HB_COLOR (0, 0, 0, 255));
+
+  g_assert_true (data.level == 0);
+
+  g_assert_cmpstr (ot_str->str, ==, data.string->str);
+
+  g_string_free (data.string, TRUE);
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+
+  g_string_free (ot_str, TRUE);
+}
+
+static void
+test_hb_paint_ot (gconstpointer data)
+{
+  test_hb_paint (data, 0);
+}
+
+static void
+test_hb_paint_ft (gconstpointer data)
+{
+  if (have_ft_colrv1 ())
+    test_hb_paint (data, 1);
+  else
+    g_test_skip ("FreeType COLRv1 support not present");
+}
+
+static void
+test_compare_ot_ft_novf (gconstpointer d)
+{
+  if (have_ft_colrv1 ())
+    test_compare_ot_ft (TEST_GLYPHS, GPOINTER_TO_UINT (d));
+  else
+    g_test_skip ("FreeType COLRv1 support not present");
+}
+
+static void
+test_compare_ot_ft_vf (gconstpointer d)
+{
+  if (have_ft_colrv1 ())
+    test_compare_ot_ft (TEST_GLYPHS_VF, GPOINTER_TO_UINT (d));
+  else
+    g_test_skip ("FreeType COLRv1 support not present");
+}
+
+static void
+scrutinize_linear_gradient (hb_paint_funcs_t *funcs,
+                            void *paint_data,
+                            hb_color_line_t *color_line,
+                            float x0, float y0,
+                            float x1, float y1,
+                            float x2, float y2,
+                            void *user_data)
+{
+  hb_bool_t *result = paint_data;
+  hb_color_stop_t *stops;
+  unsigned int len;
+  hb_color_stop_t *stops2;
+  unsigned int len2;
+
+  *result = FALSE;
+
+  len = hb_color_line_get_color_stops (color_line, 0, NULL, NULL);
+  if (len == 0)
+    return;
+
+  stops = malloc (len * sizeof (hb_color_stop_t));
+  stops2 = malloc (len * sizeof (hb_color_stop_t));
+
+  hb_color_line_get_color_stops (color_line, 0, &len, stops);
+  hb_color_line_get_color_stops (color_line, 0, &len, stops2);
+
+  // check that we can get stops twice
+  if (memcmp (stops, stops2, len * sizeof (hb_color_stop_t)) != 0)
+  {
+    free (stops);
+    free (stops2);
+    return;
+  }
+
+  // check that we can get a single stop in the middle
+  len2 = 1;
+  hb_color_line_get_color_stops (color_line, len - 1, &len2, stops2);
+  if (memcmp (&stops[len - 1], stops2, sizeof (hb_color_stop_t)) != 0)
+  {
+    free (stops);
+    free (stops2);
+    return;
+  }
+
+  free (stops);
+  free (stops2);
+
+  *result = TRUE;
+}
+
+static void
+test_color_stops (hb_bool_t use_ft)
+{
+  hb_face_t *face;
+  hb_font_t *font;
+  hb_paint_funcs_t *funcs;
+  hb_bool_t result = FALSE;
+
+  face = hb_test_open_font_file (NOTO_HAND);
+  font = hb_font_create (face);
+
+#ifdef HB_HAS_FREETYPE
+  if (use_ft)
+    hb_ft_font_set_funcs (font);
+#endif
+
+  funcs = hb_paint_funcs_create ();
+  hb_paint_funcs_set_linear_gradient_func (funcs, scrutinize_linear_gradient, NULL, NULL);
+
+  hb_font_paint_glyph (font, 10, funcs, &result, 0, HB_COLOR (0, 0, 0, 255));
+
+  g_assert_true (result);
+
+  hb_paint_funcs_destroy (funcs);
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+}
+
+static void
+test_color_stops_ot (void)
+{
+  test_color_stops (0);
+}
+
+static void
+test_color_stops_ft (void)
+{
+  if (have_ft_colrv1 ())
+    test_color_stops (1);
+  else
+    g_test_skip ("FreeType COLRv1 support not present");
+}
+
+int
+main (int argc, char **argv)
+{
+  int status = 0;
+
+  hb_test_init (&argc, &argv);
+  for (unsigned int i = 0; i < G_N_ELEMENTS (paint_tests); i++)
+  {
+    hb_test_add_data_flavor (&paint_tests[i], paint_tests[i].output, test_hb_paint_ot);
+    hb_test_add_data_flavor (&paint_tests[i], paint_tests[i].output, test_hb_paint_ft);
+  }
+
+  hb_face_t *face = hb_test_open_font_file (TEST_GLYPHS);
+  unsigned glyph_count = hb_face_get_glyph_count (face);
+  for (unsigned int i = 1; i < glyph_count; i++)
+  {
+    char buf[20];
+    snprintf (buf, 20, "test-%u", i);
+    hb_test_add_data_flavor (GUINT_TO_POINTER (i), buf, test_compare_ot_ft_novf);
+    hb_test_add_data_flavor (GUINT_TO_POINTER (i), buf, test_compare_ot_ft_vf);
+  }
+  hb_face_destroy (face);
+
+  hb_test_add (test_color_stops_ot);
+  hb_test_add (test_color_stops_ft);
+
+  status = hb_test_run();
+
+  return status;
+}
index f2f9419..6ad11d3 100644 (file)
@@ -1067,6 +1067,130 @@ test_set_inverted_operations (void)
   g_assert (all_succeeded);
 }
 
+static void
+test_hb_set_add_sorted_array (void)
+{
+  hb_set_t *set = hb_set_create ();
+  hb_codepoint_t array[7] = {1, 2, 3, 1000, 2000, 2001, 2002};
+  hb_set_add_sorted_array (set, array, 7);
+  g_assert_cmpint (hb_set_get_population (set), ==, 7);
+  g_assert (hb_set_has (set, 1));
+  g_assert (hb_set_has (set, 2));
+  g_assert (hb_set_has (set, 3));
+  g_assert (hb_set_has (set, 1000));
+  g_assert (hb_set_has (set, 2000));
+  g_assert (hb_set_has (set, 2001));
+  g_assert (hb_set_has (set, 2002));
+  hb_set_destroy (set);
+}
+
+static void
+test_set_next_many (void)
+{
+  hb_set_t *set = hb_set_create ();
+  for (unsigned i=0; i<600; i++)
+    hb_set_add (set, i);
+  for (unsigned i=6000; i<6100; i++)
+    hb_set_add (set, i);
+  g_assert (hb_set_get_population (set) == 700);
+  hb_codepoint_t array[700];
+
+  unsigned int n = hb_set_next_many (set, HB_SET_VALUE_INVALID, array, 700);
+
+  g_assert_cmpint(n, ==, 700);
+  for (unsigned i=0; i<600; i++)
+    g_assert_cmpint (array[i], ==, i);
+  for (unsigned i=0; i<100; i++)
+    g_assert (array[600 + i] == 6000u + i);
+
+  // Try skipping initial values.
+  for (unsigned i = 0; i < 700; i++)
+    array[i] = 0;
+
+  n = hb_set_next_many (set, 42, array, 700);
+
+  g_assert_cmpint (n, ==, 657);
+  g_assert_cmpint (array[0], ==, 43);
+  g_assert_cmpint (array[n - 1], ==, 6099);
+
+  hb_set_destroy (set);
+}
+
+static void
+test_set_next_many_restricted (void)
+{
+  hb_set_t *set = hb_set_create ();
+  for (int i=0; i<600; i++)
+    hb_set_add (set, i);
+  for (int i=6000; i<6100; i++)
+    hb_set_add (set, i);
+  g_assert (hb_set_get_population (set) == 700);
+  hb_codepoint_t array[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+  hb_set_next_many (set, HB_SET_VALUE_INVALID, array, 9);
+
+  for (int i=0; i<9; i++)
+    g_assert_cmpint (array[i], ==, i);
+  g_assert_cmpint (array[9], ==, 0);
+  hb_set_destroy (set);
+}
+
+static void
+test_set_next_many_inverted (void)
+{
+  hb_set_t *set = hb_set_create ();
+  hb_set_add (set, 1);
+  hb_set_add (set, 3);
+  hb_set_invert (set);
+
+  hb_codepoint_t array[] = {0, 0, 0, 0, 0, 999};
+
+  // Single page.
+  hb_set_next_many (set, HB_SET_VALUE_INVALID, array, 5);
+
+  g_assert_cmpint (array[0], ==, 0);
+  g_assert_cmpint (array[1], ==, 2);
+  g_assert_cmpint (array[2], ==, 4);
+  g_assert_cmpint (array[3], ==, 5);
+  g_assert_cmpint (array[4], ==, 6);
+  g_assert_cmpint (array[5], ==, 999);
+
+  // Multiple pages.
+  hb_set_invert (set);
+  hb_set_add (set, 1000);
+  hb_set_invert (set);
+
+  hb_codepoint_t array2[1000];
+  hb_set_next_many (set, HB_SET_VALUE_INVALID, array2, 1000);
+  g_assert_cmpint (array2[0], ==, 0);
+  g_assert_cmpint (array2[1], ==, 2);
+  g_assert_cmpint (array2[2], ==, 4);
+  g_assert_cmpint (array2[3], ==, 5);
+  for (int i=4; i<997; i++)
+  {
+    g_assert_cmpint (array2[i], ==, i + 2);
+  }
+  g_assert_cmpint (array2[997], ==, 999);
+  // Value 1000 skipped.
+  g_assert_cmpint (array2[998], ==, 1001);
+  g_assert_cmpint (array2[999], ==, 1002);
+
+  hb_set_destroy (set);
+}
+
+static void
+test_set_next_many_out_of_order_pages (void) {
+  hb_set_t* set = hb_set_create();
+  hb_set_add(set, 1957);
+  hb_set_add(set, 69);
+  hb_codepoint_t results[2];
+  unsigned int result_size = hb_set_next_many(set, HB_SET_VALUE_INVALID, results, 2);
+  g_assert_cmpint(result_size, == , 2);
+  g_assert_cmpint(results[0], == , 69);
+  g_assert_cmpint(results[1], == , 1957);
+  hb_set_destroy(set);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -1090,5 +1214,11 @@ main (int argc, char **argv)
   hb_test_add (test_set_inverted_equality);
   hb_test_add (test_set_inverted_operations);
 
+  hb_test_add (test_hb_set_add_sorted_array);
+  hb_test_add (test_set_next_many);
+  hb_test_add (test_set_next_many_restricted);
+  hb_test_add (test_set_next_many_inverted);
+  hb_test_add (test_set_next_many_out_of_order_pages);
+
   return hb_test_run();
 }
index 73accfb..27b135f 100644 (file)
@@ -147,6 +147,34 @@ test_face_user_setting (void)
   hb_face_destroy (face);
 }
 
+static void
+test_synthetic_slant (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/AdobeVFPrototype_vsindex.otf");
+  hb_font_t *font = hb_font_create (face);
+
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT_RATIO), 0);
+
+  hb_font_set_synthetic_slant (font, 0.2);
+
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT_RATIO), 0.2);
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+
+  face = hb_test_open_font_file ("fonts/notosansitalic.ttf");
+  font = hb_font_create (face);
+
+  /* We expect a negative angle for a typical italic font,
+   * which should give us a positive ratio
+   */
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT_ANGLE), -12);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT_RATIO), 0.21);
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -155,6 +183,7 @@ main (int argc, char **argv)
   hb_test_add (test_empty_face);
   hb_test_add (test_regular_face);
   hb_test_add (test_face_user_setting);
+  hb_test_add (test_synthetic_slant);
 
   return hb_test_run ();
 }
index b58a86c..6d4f81c 100644 (file)
@@ -67,6 +67,44 @@ test_subset_nameids_with_dup_strs (void)
   hb_face_destroy (face_expected);
 }
 
+#ifdef HB_EXPERIMENTAL_API
+static void
+test_subset_name_overrides (void)
+{
+  hb_face_t *face_origin = hb_test_open_font_file ("fonts/nameID.origin.ttf");
+  hb_face_t *face_expected = hb_test_open_font_file ("fonts/nameID.override.expected.ttf");
+
+  char str1[] = "Roboto Test";
+  char str1_3[] = "Roboto Test unicode platform";
+  char str2[] = "Bold";
+  char str6[] = "Roboto-Bold";
+  char str12[] = "Non ascii test Ü";
+  char str16[] = "Roboto-test-inserting";
+  hb_set_t *name_ids = hb_set_create();
+  hb_face_t *face_subset;
+  hb_set_add_range (name_ids, 0, 13);
+
+  hb_subset_input_t *subset_input = hb_subset_test_create_input_from_nameids (name_ids);
+  hb_subset_input_override_name_table (subset_input, 1, 1, 0, 0, str1, -1);
+  hb_subset_input_override_name_table (subset_input, 1, 3, 1, 0x409, str1_3, -1);
+  hb_subset_input_override_name_table (subset_input, 2, 1, 0, 0, str2, 4);
+  hb_subset_input_override_name_table (subset_input, 6, 1, 0, 0, str6, -1);
+  hb_subset_input_override_name_table (subset_input, 12, 1, 0, 0, str12, -1);
+  hb_subset_input_override_name_table (subset_input, 14, 1, 0, 0, NULL, -1);
+  hb_subset_input_override_name_table (subset_input, 16, 1, 0, 0, str16, -1);
+
+  face_subset = hb_subset_test_create_subset (face_origin, subset_input);
+  hb_set_destroy (name_ids);
+
+  hb_subset_test_check (face_expected, face_subset, HB_TAG ('n','a','m','e'));
+
+  hb_face_destroy (face_subset);
+  hb_face_destroy (face_origin);
+  hb_face_destroy (face_expected);
+}
+#endif
+
 int
 main (int argc, char **argv)
 {
@@ -74,6 +112,9 @@ main (int argc, char **argv)
 
   hb_test_add (test_subset_nameids);
   hb_test_add (test_subset_nameids_with_dup_strs);
+#ifdef HB_EXPERIMENTAL_API
+  hb_test_add (test_subset_name_overrides);
+#endif
 
   return hb_test_run();
 }
diff --git a/test/api/test-subset-repacker.c b/test/api/test-subset-repacker.c
new file mode 100644 (file)
index 0000000..d1779b6
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright © 2022  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.
+ *
+ */
+
+#include "hb-test.h"
+#include "hb-subset-test.h"
+
+#ifdef HB_EXPERIMENTAL_API
+#include "hb-subset-repacker.h"
+
+char test_gsub_data[106] = "\x0\x1\x0\x0\x0\xa\x0\x1e\x0\x2c\x0\x1\x6c\x61\x74\x6e\x0\x8\x0\x4\x0\x0\x0\x0\xff\xff\x0\x1\x0\x0\x0\x1\x74\x65\x73\x74\x0\x8\x0\x0\x0\x1\x0\x1\x0\x2\x0\x2a\x0\x6\x0\x5\x0\x0\x0\x1\x0\x8\x0\x1\x0\x8\x0\x1\x0\xe\x0\x1\x0\x1\x0\x1\x0\x1\x0\x4\x0\x2\x0\x1\x0\x2\x0\x1\x0\x0\x0\x1\x0\x0\x0\x1\x0\x8\x0\x1\x0\x6\x0\x1\x0\x1\x0\x1\x0\x2";
+
+static void
+test_hb_repack_with_cy_struct (void)
+{
+  hb_object_t *hb_objs = calloc (15, sizeof (hb_object_t));
+
+  hb_objs[0].head = &(test_gsub_data[100]);
+  hb_objs[0].tail = &(test_gsub_data[105]) + 1;
+  hb_objs[0].num_real_links = 0;
+  hb_objs[0].num_virtual_links = 0;
+  hb_objs[0].real_links = NULL;
+  hb_objs[0].virtual_links = NULL;
+
+  hb_objs[1].head = &(test_gsub_data[94]);
+  hb_objs[1].tail = &(test_gsub_data[100]);
+  hb_objs[1].num_real_links = 1;
+  hb_objs[1].num_virtual_links = 0;
+  hb_objs[1].real_links = malloc (sizeof (hb_link_t));
+  hb_objs[1].real_links[0].width = 2;
+  hb_objs[1].real_links[0].position = 2;
+  hb_objs[1].real_links[0].objidx = 1;
+  hb_objs[1].virtual_links = NULL;
+
+
+  hb_objs[2].head = &(test_gsub_data[86]);
+  hb_objs[2].tail = &(test_gsub_data[94]);
+  hb_objs[2].num_real_links = 1;
+  hb_objs[2].num_virtual_links = 0;
+  hb_objs[2].real_links = malloc (sizeof (hb_link_t));
+  hb_objs[2].real_links[0].width = 2;
+  hb_objs[2].real_links[0].position = 6;
+  hb_objs[2].real_links[0].objidx = 2;
+  hb_objs[2].virtual_links = NULL;
+
+  hb_objs[3].head = &(test_gsub_data[76]);
+  hb_objs[3].tail = &(test_gsub_data[86]);
+  hb_objs[3].num_real_links = 0;
+  hb_objs[3].num_virtual_links = 0;
+  hb_objs[3].real_links = NULL;
+  hb_objs[3].virtual_links = NULL;
+
+  hb_objs[4].head = &(test_gsub_data[72]);
+  hb_objs[4].tail = &(test_gsub_data[76]);
+  hb_objs[4].num_real_links = 1;
+  hb_objs[4].num_virtual_links = 0;
+  hb_objs[4].real_links = malloc (sizeof (hb_link_t));
+  hb_objs[4].real_links[0].width = 2;
+  hb_objs[4].real_links[0].position = 2;
+  hb_objs[4].real_links[0].objidx = 4;
+  hb_objs[4].virtual_links = NULL;
+
+  hb_objs[5].head = &(test_gsub_data[66]);
+  hb_objs[5].tail = &(test_gsub_data[72]);
+  hb_objs[5].num_real_links = 0;
+  hb_objs[5].num_virtual_links = 0;
+  hb_objs[5].real_links = NULL;
+  hb_objs[5].virtual_links = NULL;
+
+  hb_objs[6].head = &(test_gsub_data[58]);
+  hb_objs[6].tail = &(test_gsub_data[66]);
+  hb_objs[6].num_real_links = 2;
+  hb_objs[6].num_virtual_links = 0;
+  hb_objs[6].real_links = calloc (2, sizeof (hb_link_t));
+  hb_objs[6].real_links[0].width = 2;
+  hb_objs[6].real_links[0].position = 6;
+  hb_objs[6].real_links[0].objidx = 5;
+  hb_objs[6].real_links[1].width = 2;
+  hb_objs[6].real_links[1].position = 2;
+  hb_objs[6].real_links[1].objidx = 6;
+  hb_objs[6].virtual_links = NULL;
+
+  hb_objs[7].head = &(test_gsub_data[50]);
+  hb_objs[7].tail = &(test_gsub_data[58]);
+  hb_objs[7].num_real_links = 1;
+  hb_objs[7].num_virtual_links = 0;
+  hb_objs[7].real_links = malloc (sizeof (hb_link_t));
+  hb_objs[7].real_links[0].width = 2;
+  hb_objs[7].real_links[0].position = 6;
+  hb_objs[7].real_links[0].objidx = 7;
+  hb_objs[7].virtual_links = NULL;
+
+  hb_objs[8].head = &(test_gsub_data[44]);
+  hb_objs[8].tail = &(test_gsub_data[50]);
+  hb_objs[8].num_real_links = 2;
+  hb_objs[8].num_virtual_links = 0;
+  hb_objs[8].real_links = calloc (2, sizeof (hb_link_t));
+  hb_objs[8].real_links[0].width = 2;
+  hb_objs[8].real_links[0].position = 2;
+  hb_objs[8].real_links[0].objidx = 3;
+  hb_objs[8].real_links[1].width = 2;
+  hb_objs[8].real_links[1].position = 4;
+  hb_objs[8].real_links[1].objidx = 8;
+  hb_objs[8].virtual_links = NULL;
+
+  hb_objs[9].head = &(test_gsub_data[38]);
+  hb_objs[9].tail = &(test_gsub_data[44]);
+  hb_objs[9].num_real_links = 0;
+  hb_objs[9].num_virtual_links = 0;
+  hb_objs[9].real_links = NULL;
+  hb_objs[9].virtual_links = NULL;
+
+  hb_objs[10].head = &(test_gsub_data[30]);
+  hb_objs[10].tail = &(test_gsub_data[38]);
+  hb_objs[10].num_real_links = 1;
+  hb_objs[10].num_virtual_links = 0;
+  hb_objs[10].real_links = malloc (sizeof (hb_link_t));
+  hb_objs[10].real_links[0].width = 2;
+  hb_objs[10].real_links[0].position = 6;
+  hb_objs[10].real_links[0].objidx = 10;
+  hb_objs[10].virtual_links = NULL;
+
+  hb_objs[11].head = &(test_gsub_data[22]);
+  hb_objs[11].tail = &(test_gsub_data[30]);
+  hb_objs[11].num_real_links = 0;
+  hb_objs[11].num_virtual_links = 0;
+  hb_objs[11].real_links = NULL;
+  hb_objs[11].virtual_links = NULL;
+
+  hb_objs[12].head = &(test_gsub_data[18]);
+  hb_objs[12].tail = &(test_gsub_data[22]);
+  hb_objs[12].num_real_links = 1;
+  hb_objs[12].num_virtual_links = 0;
+  hb_objs[12].real_links = malloc (sizeof (hb_link_t));
+  hb_objs[12].real_links[0].width = 2;
+  hb_objs[12].real_links[0].position = 0;
+  hb_objs[12].real_links[0].objidx = 12;
+  hb_objs[12].virtual_links = NULL;
+
+  hb_objs[13].head = &(test_gsub_data[10]);
+  hb_objs[13].tail = &(test_gsub_data[18]);
+  hb_objs[13].num_real_links = 1;
+  hb_objs[13].num_virtual_links = 0;
+  hb_objs[13].real_links = malloc (sizeof (hb_link_t));
+  hb_objs[13].real_links[0].width = 2;
+  hb_objs[13].real_links[0].position = 6;
+  hb_objs[13].real_links[0].objidx = 13;
+  hb_objs[13].virtual_links = NULL;
+
+  hb_objs[14].head = &(test_gsub_data[0]);
+  hb_objs[14].tail = &(test_gsub_data[10]);
+  hb_objs[14].num_real_links = 3;
+  hb_objs[14].num_virtual_links = 0;
+  hb_objs[14].real_links = calloc (3, sizeof (hb_link_t));
+  hb_objs[14].real_links[0].width = 2;
+  hb_objs[14].real_links[0].position = 8;
+  hb_objs[14].real_links[0].objidx = 9;
+  hb_objs[14].real_links[1].width = 2;
+  hb_objs[14].real_links[1].position = 6;
+  hb_objs[14].real_links[1].objidx = 11;
+  hb_objs[14].real_links[2].width = 2;
+  hb_objs[14].real_links[2].position = 4;
+  hb_objs[14].real_links[2].objidx = 14;
+  hb_objs[14].virtual_links = NULL;
+
+  hb_blob_t *result = hb_subset_repack_or_fail (HB_TAG_NONE, hb_objs, 15);
+
+  hb_face_t *face_expected = hb_test_open_font_file ("fonts/repacker_expected.otf");
+  hb_blob_t *expected_blob = hb_face_reference_table (face_expected, HB_TAG ('G','S','U','B'));
+  fprintf(stderr, "expected %d bytes, actual %d bytes\n", hb_blob_get_length(expected_blob), hb_blob_get_length (result));
+
+  if (hb_blob_get_length (expected_blob) != 0 ||
+      hb_blob_get_length (result) != 0)
+    hb_test_assert_blobs_equal (expected_blob, result);
+
+  hb_face_destroy (face_expected);
+  hb_blob_destroy (expected_blob);
+  hb_blob_destroy (result);
+
+  for (unsigned i = 0 ; i < 15; i++)
+  {
+    if (hb_objs[i].real_links != NULL)
+      free (hb_objs[i].real_links);
+  }
+
+  free (hb_objs);
+}
+
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_hb_repack_with_cy_struct);
+
+  return hb_test_run();
+}
+#else
+int main (int argc HB_UNUSED, char **argv HB_UNUSED)
+{
+  return 0;
+}
+#endif
index 27bf73c..08c9110 100644 (file)
@@ -155,6 +155,80 @@ test_subset_sets (void)
   hb_subset_input_destroy (input);
 }
 
+static void
+test_subset_plan (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
+  hb_face_t *face_ac = hb_test_open_font_file ("fonts/Roboto-Regular.ac.ttf");
+
+  hb_set_t *codepoints = hb_set_create();
+  hb_set_add (codepoints, 97);
+  hb_set_add (codepoints, 99);
+  hb_subset_input_t* input = hb_subset_test_create_input (codepoints);
+  hb_set_destroy (codepoints);
+
+  hb_subset_plan_t* plan = hb_subset_plan_create_or_fail (face_abc, input);
+  g_assert (plan);
+
+  const hb_map_t* mapping = hb_subset_plan_old_to_new_glyph_mapping (plan);
+  g_assert (hb_map_get (mapping, 1) == 1);
+  g_assert (hb_map_get (mapping, 3) == 2);
+
+  mapping = hb_subset_plan_new_to_old_glyph_mapping (plan);
+  g_assert (hb_map_get (mapping, 1) == 1);
+  g_assert (hb_map_get (mapping, 2) == 3);
+
+  mapping = hb_subset_plan_unicode_to_old_glyph_mapping (plan);
+  g_assert (hb_map_get (mapping, 0x63) == 3);
+
+  hb_face_t* face_abc_subset = hb_subset_plan_execute_or_fail (plan);
+
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f'));
+
+  hb_subset_input_destroy (input);
+  hb_subset_plan_destroy (plan);
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_ac);
+}
+
+static hb_blob_t*
+_ref_table (hb_face_t *face, hb_tag_t tag, void *user_data)
+{
+  return hb_face_reference_table ((hb_face_t*) user_data, tag);
+}
+
+static void
+test_subset_create_for_tables_face (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
+  hb_face_t *face_ac = hb_test_open_font_file ("fonts/Roboto-Regular.ac.ttf");
+  hb_face_t *face_create_for_tables = hb_face_create_for_tables (
+      _ref_table,
+      face_abc,
+      NULL);
+
+  hb_set_t *codepoints = hb_set_create();
+  hb_set_add (codepoints, 97);
+  hb_set_add (codepoints, 99);
+
+  hb_subset_input_t* input = hb_subset_test_create_input (codepoints);
+  hb_set_destroy (codepoints);
+
+  hb_face_t* face_abc_subset = hb_subset_or_fail (face_create_for_tables, input);
+
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f'));
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','a','s','p'));
+
+  hb_subset_input_destroy (input);
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_create_for_tables);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_ac);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -165,6 +239,8 @@ main (int argc, char **argv)
   hb_test_add (test_subset_crash);
   hb_test_add (test_subset_set_flags);
   hb_test_add (test_subset_sets);
+  hb_test_add (test_subset_plan);
+  hb_test_add (test_subset_create_for_tables_face);
 
   return hb_test_run();
 }
index dd1e3d0..f16eb53 100644 (file)
@@ -184,6 +184,9 @@ static const test_pair_t combining_class_tests_more[] =
   /* Unicode-14.0 character additions */
   {   0x1DFA, 218 },
 
+  /* Unicode-15.0 character additions */
+  {  0x10EFD, 220 },
+
   { 0x111111, 0 }
 };
 
@@ -267,6 +270,12 @@ static const test_pair_t general_category_tests_more[] =
   /* Unicode-14.0 character additions */
   {   0x20C0, HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL },
 
+  /* Unicode-15.0 character additions */
+  {   0x0CF3, HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK },
+
+  /* Unicode-15.1 character additions */
+  {   0x31EF, HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL },
+
   { 0x111111, HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED }
 };
 
@@ -524,6 +533,10 @@ static const test_pair_t script_tests_more[] =
   {  0x16A70, HB_SCRIPT_TANGSA },
   {  0x1E290, HB_SCRIPT_TOTO },
 
+  /* Unicode-15.0 additions */
+  {  0x11F00, HB_SCRIPT_KAWI },
+  {  0x1E4D0, HB_SCRIPT_NAG_MUNDARI },
+
   { 0x111111, HB_SCRIPT_UNKNOWN }
 };
 
@@ -744,9 +757,9 @@ test_unicode_setters (void)
     /* Since uf is immutable now, the following setter should do nothing. */
     p->func_setter (uf, (get_func_t) a_is_for_arabic_get_script, &data[1], free_up);
 
-    g_assert (data[0].freed && !data[1].freed);
+    g_assert (data[0].freed && data[1].freed);
     hb_unicode_funcs_destroy (uf);
-    g_assert (data[0].freed && !data[1].freed);
+    g_assert (data[0].freed && data[1].freed);
   }
 }
 
index aa152e3..490e5fc 100644 (file)
@@ -31,7 +31,6 @@
 static void
 test_get_var_coords (void)
 {
-#ifdef HB_EXPERIMENTAL_API
 #ifndef G_APPROX_VALUE
 #define G_APPROX_VALUE(a, b, epsilon) \
   (((a) > (b) ? (a) - (b) : (b) - (a)) < (epsilon))
@@ -66,7 +65,6 @@ test_get_var_coords (void)
 
   hb_font_destroy (font);
   hb_face_destroy (face);
-#endif
 }
 
 static void
index 2e2b2c9..187e088 100644 (file)
@@ -15,13 +15,20 @@ libs:
 $(top_builddir)/src/libharfbuzz.la: lib
 $(top_builddir)/src/libharfbuzz-subset.la: libs
 
+# seems autotools builds do not support builds with experimental APIs, so
+# EXTRA_DIST hb-repacker-fuzzer.cc
+
 EXTRA_DIST += \
-       README \
+       README.md \
+       hb-repacker-fuzzer.cc \
        run-shape-fuzzer-tests.py \
        run-subset-fuzzer-tests.py \
        run-draw-fuzzer-tests.py \
+       run-repacker-fuzzer-tests.py \
        meson.build \
        fonts \
+       graphs \
+       sets \
        $(NULL)
 
 check_PROGRAMS = \
index f15e22c..9688b98 100644 (file)
@@ -215,7 +215,7 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
-am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp README
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -251,8 +251,6 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
-DIRECTWRITE_CXXFLAGS = @DIRECTWRITE_CXXFLAGS@
-DIRECTWRITE_LIBS = @DIRECTWRITE_LIBS@
 DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -350,6 +348,8 @@ STRIP = @STRIP@
 UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
 UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
 VERSION = @VERSION@
+WASM_CFLAGS = @WASM_CFLAGS@
+WASM_LIBS = @WASM_LIBS@
 _GI_EXP_DATADIR = @_GI_EXP_DATADIR@
 _GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@
 abs_builddir = @abs_builddir@
@@ -409,9 +409,13 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 NULL = 
-EXTRA_DIST = README run-shape-fuzzer-tests.py \
+
+# seems autotools builds do not support builds with experimental APIs, so
+# EXTRA_DIST hb-repacker-fuzzer.cc
+EXTRA_DIST = README.md hb-repacker-fuzzer.cc run-shape-fuzzer-tests.py \
        run-subset-fuzzer-tests.py run-draw-fuzzer-tests.py \
-       meson.build fonts $(NULL)
+       run-repacker-fuzzer-tests.py meson.build fonts graphs sets \
+       $(NULL)
 CLEANFILES = 
 DISTCLEANFILES = 
 MAINTAINERCLEANFILES = 
diff --git a/test/fuzzing/README b/test/fuzzing/README
deleted file mode 100644 (file)
index af99cf9..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-In order to build the fuzzer one needs to build HarfBuzz and
-harfbuzz/test/fuzzing/hb-fuzzer.cc with:
-  - Using the most recent Clang
-  - With -fsanitize=address (or =undefined, or a combination)
-  - With -fsanitize-coverage=edge[,8bit-counters,trace-cmp]
-  - With various defines that limit worst case exponential behavior.
-    See FUZZING_CPPFLAGS in harfbuzz/src/Makefile.am for the list.
-  - link against libFuzzer
-
-To run the fuzzer one needs to first obtain a test corpus as a directory
-containing interesting fonts.  A good starting point is inside
-harfbuzz/test/shaping/fonts/fonts/.
-Then, run the fuzzer like this:
-   ./hb-fuzzer -max_len=2048 CORPUS_DIR
-Where max_len specifies the maximal length of font files to handle.
-The smaller the faster.
-
-For more details consult the following locations:
-  - http://llvm.org/docs/LibFuzzer.html or
-  - https://github.com/google/libfuzzer-bot/tree/master/harfbuzz
-  - https://github.com/harfbuzz/harfbuzz/issues/139
diff --git a/test/fuzzing/README.md b/test/fuzzing/README.md
new file mode 100644 (file)
index 0000000..8529a0c
--- /dev/null
@@ -0,0 +1,17 @@
+To build the fuzzers with libFuzzer to perform actual fuzzing, build with:
+
+```shell
+CXX=clang++ CXXFLAGS="-fsanitize=address,fuzzer-no-link" meson fuzzbuild --default-library=static -Dfuzzer_ldflags="-fsanitize=address,fuzzer"
+
+ninja -Cfuzzbuild
+```
+
+Then, run the fuzzer like this:
+
+fuzzbuild/test/fuzzing/hb-{shape,draw,subset,set}-fuzzer [-max_len=2048] [CORPUS_DIR]
+
+Where max_len specifies the maximal length of font files to handle.
+The smaller the faster.
+
+For more details consult the following locations:
+  - http://llvm.org/docs/LibFuzzer.html
diff --git a/test/fuzzing/fonts/AdobeVFPrototype.ABC.otf b/test/fuzzing/fonts/AdobeVFPrototype.ABC.otf
new file mode 100644 (file)
index 0000000..ab1c925
Binary files /dev/null and b/test/fuzzing/fonts/AdobeVFPrototype.ABC.otf differ
diff --git a/test/fuzzing/fonts/Roboto-Variable.ABC.ttf b/test/fuzzing/fonts/Roboto-Variable.ABC.ttf
new file mode 100644 (file)
index 0000000..6cf001f
Binary files /dev/null and b/test/fuzzing/fonts/Roboto-Variable.ABC.ttf differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5446125635633152 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5446125635633152
new file mode 100644 (file)
index 0000000..98c2fb7
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5446125635633152 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5508865908670464 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5508865908670464
new file mode 100644 (file)
index 0000000..1404810
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5508865908670464 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5979721620652032 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5979721620652032
new file mode 100644 (file)
index 0000000..6e54cba
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5979721620652032 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5667125715927040 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5667125715927040
new file mode 100644 (file)
index 0000000..1791225
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5667125715927040 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5692635449524224 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5692635449524224
new file mode 100644 (file)
index 0000000..14cdfde
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5692635449524224 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-4579249263345664 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-4579249263345664
new file mode 100644 (file)
index 0000000..636a867
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-4579249263345664 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-4877513265119232 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-4877513265119232
new file mode 100644 (file)
index 0000000..e91513d
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-4877513265119232 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6490945267564544 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6490945267564544
new file mode 100644 (file)
index 0000000..20dc975
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6490945267564544 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6697168080338944 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6697168080338944
new file mode 100644 (file)
index 0000000..1859841
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6697168080338944 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-4523349576908800 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-4523349576908800
new file mode 100644 (file)
index 0000000..d66fb2a
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-4523349576908800 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-4787105656864768 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-4787105656864768
new file mode 100644 (file)
index 0000000..beb4031
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-4787105656864768 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5114131137822720 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5114131137822720
new file mode 100644 (file)
index 0000000..7a37e98
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5114131137822720 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5349416110784512 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5349416110784512
new file mode 100644 (file)
index 0000000..7c71ada
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5349416110784512 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5965759719538688 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5965759719538688
new file mode 100644 (file)
index 0000000..a3e1a10
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5965759719538688 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-6377756666757120 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-6377756666757120
new file mode 100644 (file)
index 0000000..718e169
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-6377756666757120 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-6635625931735040 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-6635625931735040
new file mode 100644 (file)
index 0000000..333ebaa
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-6635625931735040 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4549472192692224 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4549472192692224
new file mode 100644 (file)
index 0000000..14ce218
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4549472192692224 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4549523149553664 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4549523149553664
new file mode 100644 (file)
index 0000000..4b2f3cb
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4549523149553664 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4552226966994944 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4552226966994944
new file mode 100644 (file)
index 0000000..246e4c9
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4552226966994944 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4575222591520768 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4575222591520768
new file mode 100644 (file)
index 0000000..a225a27
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4575222591520768 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4801020053291008 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4801020053291008
new file mode 100644 (file)
index 0000000..5758a65
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4801020053291008 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4875306193518592.fuzz b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4875306193518592.fuzz
new file mode 100644 (file)
index 0000000..20fc62e
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4875306193518592.fuzz differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4877336988483584 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4877336988483584
new file mode 100644 (file)
index 0000000..73d4e5d
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4877336988483584 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4916785942757376 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4916785942757376
new file mode 100644 (file)
index 0000000..15b49ce
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4916785942757376 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5029952234586112 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5029952234586112
new file mode 100644 (file)
index 0000000..39d6514
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5029952234586112 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5120246288875520 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5120246288875520
new file mode 100644 (file)
index 0000000..12d40b0
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5120246288875520 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5145429829877760 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5145429829877760
new file mode 100644 (file)
index 0000000..81bd991
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5145429829877760 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5191907895279616 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5191907895279616
new file mode 100644 (file)
index 0000000..a1936d0
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5191907895279616 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5192684970311680 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5192684970311680
new file mode 100644 (file)
index 0000000..0896b6b
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5192684970311680 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5234369031176192 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5234369031176192
new file mode 100644 (file)
index 0000000..8cd77ea
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5234369031176192 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5388270411579392 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5388270411579392
new file mode 100644 (file)
index 0000000..d39badd
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5388270411579392 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5417800474165248 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5417800474165248
new file mode 100644 (file)
index 0000000..f5f3cff
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5417800474165248 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5419002026131456 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5419002026131456
new file mode 100644 (file)
index 0000000..5f7fd63
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5419002026131456 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5458896606855168 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5458896606855168
new file mode 100644 (file)
index 0000000..213b60f
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5458896606855168 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5568200165687296 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5568200165687296
new file mode 100644 (file)
index 0000000..b2038a6
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5568200165687296 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5693568490012672 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5693568490012672
new file mode 100644 (file)
index 0000000..19521a1
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5693568490012672 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5793182905663488 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5793182905663488
new file mode 100644 (file)
index 0000000..2577001
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5793182905663488 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5842152921628672 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5842152921628672
new file mode 100644 (file)
index 0000000..c33e2b9
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5842152921628672 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5844352760152064 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5844352760152064
new file mode 100644 (file)
index 0000000..0228414
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5844352760152064 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5845846876356608 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5845846876356608
new file mode 100644 (file)
index 0000000..faf2e85
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5845846876356608 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5855710991482880.fuzz b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5855710991482880.fuzz
new file mode 100644 (file)
index 0000000..93c5adc
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5855710991482880.fuzz differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6032126569742336 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6032126569742336
new file mode 100644 (file)
index 0000000..0bc881d
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6032126569742336 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6164014466203648 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6164014466203648
new file mode 100644 (file)
index 0000000..3a15ab2
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6164014466203648 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6169920089227264 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6169920089227264
new file mode 100644 (file)
index 0000000..56dc798
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6169920089227264 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6187272924692480 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6187272924692480
new file mode 100644 (file)
index 0000000..db9f11b
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6187272924692480 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6292420615340032 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6292420615340032
new file mode 100644 (file)
index 0000000..62cfbb2
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6292420615340032 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6362213417353216 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6362213417353216
new file mode 100644 (file)
index 0000000..c5bd724
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6362213417353216 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6365271012540416 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6365271012540416
new file mode 100644 (file)
index 0000000..6da6a1c
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6365271012540416 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6442117271257088 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6442117271257088
new file mode 100644 (file)
index 0000000..8d6284c
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6442117271257088 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6521393809588224 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6521393809588224
new file mode 100644 (file)
index 0000000..bf7b8bb
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6521393809588224 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6525813890875392 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6525813890875392
new file mode 100644 (file)
index 0000000..0ece6d7
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6525813890875392 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6608005089853440 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6608005089853440
new file mode 100644 (file)
index 0000000..6702919
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6608005089853440 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6681253479579648 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6681253479579648
new file mode 100644 (file)
index 0000000..b6239d6
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6681253479579648 differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6742230974201856 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6742230974201856
new file mode 100644 (file)
index 0000000..5b91493
Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6742230974201856 differ
diff --git a/test/fuzzing/fonts/sbix-extents.ttf b/test/fuzzing/fonts/sbix-extents.ttf
new file mode 100644 (file)
index 0000000..6f792df
Binary files /dev/null and b/test/fuzzing/fonts/sbix-extents.ttf differ
diff --git a/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-5196242811748352 b/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-5196242811748352
new file mode 100644 (file)
index 0000000..9665e79
Binary files /dev/null and b/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-5196242811748352 differ
diff --git a/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-5390364397928448 b/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-5390364397928448
new file mode 100644 (file)
index 0000000..54ee816
Binary files /dev/null and b/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-5390364397928448 differ
diff --git a/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-5475787333828608 b/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-5475787333828608
new file mode 100644 (file)
index 0000000..af2a850
Binary files /dev/null and b/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-5475787333828608 differ
diff --git a/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6014493291577344 b/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6014493291577344
new file mode 100644 (file)
index 0000000..a29d1e2
Binary files /dev/null and b/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6014493291577344 differ
diff --git a/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6419865171525632 b/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6419865171525632
new file mode 100644 (file)
index 0000000..2deb99f
Binary files /dev/null and b/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6419865171525632 differ
diff --git a/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6714085985353728 b/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6714085985353728
new file mode 100644 (file)
index 0000000..aeee90b
Binary files /dev/null and b/test/fuzzing/graphs/clusterfuzz-testcase-minimized-hb-repacker-fuzzer-6714085985353728 differ
diff --git a/test/fuzzing/graphs/crash-3bf72494aa4c9f8cbbcbf887fdc2a2858c87feb4 b/test/fuzzing/graphs/crash-3bf72494aa4c9f8cbbcbf887fdc2a2858c87feb4
new file mode 100644 (file)
index 0000000..ff8da7b
Binary files /dev/null and b/test/fuzzing/graphs/crash-3bf72494aa4c9f8cbbcbf887fdc2a2858c87feb4 differ
diff --git a/test/fuzzing/graphs/crash-442bfac994a3d9929cf06262ae9fb00f6ee1f774 b/test/fuzzing/graphs/crash-442bfac994a3d9929cf06262ae9fb00f6ee1f774
new file mode 100644 (file)
index 0000000..0160ce5
Binary files /dev/null and b/test/fuzzing/graphs/crash-442bfac994a3d9929cf06262ae9fb00f6ee1f774 differ
diff --git a/test/fuzzing/graphs/leak-a77f29b25edb873729f3ab120148fdb213cfa527 b/test/fuzzing/graphs/leak-a77f29b25edb873729f3ab120148fdb213cfa527
new file mode 100644 (file)
index 0000000..58b4075
Binary files /dev/null and b/test/fuzzing/graphs/leak-a77f29b25edb873729f3ab120148fdb213cfa527 differ
diff --git a/test/fuzzing/graphs/noto_nastaliq_urdu b/test/fuzzing/graphs/noto_nastaliq_urdu
new file mode 100644 (file)
index 0000000..2e3cab8
Binary files /dev/null and b/test/fuzzing/graphs/noto_nastaliq_urdu differ
index 772a358..782db35 100644 (file)
@@ -5,77 +5,81 @@
 
 #include "hb-fuzzer.hh"
 
-#ifdef HB_EXPERIMENTAL_API
-struct _user_data_t
+struct _draw_data_t
 {
-  bool is_open;
   unsigned path_len;
-  hb_position_t path_start_x;
-  hb_position_t path_start_y;
-  hb_position_t path_last_x;
-  hb_position_t path_last_y;
+  float path_start_x;
+  float path_start_y;
+  float path_last_x;
+  float path_last_y;
 };
 
+#include <cstdio>
 static void
-_move_to (hb_position_t to_x, hb_position_t to_y, void *user_data_)
+_move_to (hb_draw_funcs_t *dfuncs, void *draw_data_,
+         hb_draw_state_t *st,
+         float to_x, float to_y,
+         void *user_data)
 {
-  _user_data_t *user_data = (_user_data_t *) user_data_;
-  assert (!user_data->is_open);
-  user_data->is_open = true;
-  user_data->path_start_x = user_data->path_last_x = to_x;
-  user_data->path_start_y = user_data->path_last_y = to_y;
+  _draw_data_t *draw_data = (_draw_data_t *) draw_data_;
+  assert (!st->path_open);
+  draw_data->path_start_x = draw_data->path_last_x = to_x;
+  draw_data->path_start_y = draw_data->path_last_y = to_y;
 }
 
 static void
-_line_to (hb_position_t to_x, hb_position_t to_y, void *user_data_)
+_line_to (hb_draw_funcs_t *dfuncs, void *draw_data_,
+         hb_draw_state_t *st,
+         float to_x, float to_y,
+         void *user_data)
 {
-  _user_data_t *user_data = (_user_data_t *) user_data_;
-  assert (user_data->is_open);
-  assert (user_data->path_last_x != to_x || user_data->path_last_y != to_y);
-  ++user_data->path_len;
-  user_data->path_last_x = to_x;
-  user_data->path_last_y = to_y;
+  _draw_data_t *draw_data = (_draw_data_t *) draw_data_;
+  assert (st->path_open);
+  ++draw_data->path_len;
+  draw_data->path_last_x = to_x;
+  draw_data->path_last_y = to_y;
 }
 
 static void
-_quadratic_to (hb_position_t control_x, hb_position_t control_y,
-              hb_position_t to_x, hb_position_t to_y, void *user_data_)
+_quadratic_to (hb_draw_funcs_t *dfuncs, void *draw_data_,
+              hb_draw_state_t *st,
+              float control_x, float control_y,
+              float to_x, float to_y,
+              void *user_data)
 {
-  _user_data_t *user_data = (_user_data_t *) user_data_;
-  assert (user_data->is_open);
-  assert (user_data->path_last_x != control_x || user_data->path_last_y != control_y ||
-         user_data->path_last_x != to_x || user_data->path_last_y != to_y);
-  ++user_data->path_len;
-  user_data->path_last_x = to_x;
-  user_data->path_last_y = to_y;
+  _draw_data_t *draw_data = (_draw_data_t *) draw_data_;
+  assert (st->path_open);
+  ++draw_data->path_len;
+  draw_data->path_last_x = to_x;
+  draw_data->path_last_y = to_y;
 }
 
 static void
-_cubic_to (hb_position_t control1_x, hb_position_t control1_y,
-          hb_position_t control2_x, hb_position_t control2_y,
-          hb_position_t to_x, hb_position_t to_y, void *user_data_)
+_cubic_to (hb_draw_funcs_t *dfuncs, void *draw_data_,
+          hb_draw_state_t *st,
+          float control1_x, float control1_y,
+          float control2_x, float control2_y,
+          float to_x, float to_y,
+          void *user_data)
 {
-  _user_data_t *user_data = (_user_data_t *) user_data_;
-  assert (user_data->is_open);
-  assert (user_data->path_last_x != control1_x || user_data->path_last_y != control1_y ||
-         user_data->path_last_x != control2_x || user_data->path_last_y != control2_y ||
-         user_data->path_last_x != to_x || user_data->path_last_y != to_y);
-  ++user_data->path_len;
-  user_data->path_last_x = to_x;
-  user_data->path_last_y = to_y;
+  _draw_data_t *draw_data = (_draw_data_t *) draw_data_;
+  assert (st->path_open);
+  ++draw_data->path_len;
+  draw_data->path_last_x = to_x;
+  draw_data->path_last_y = to_y;
 }
 
 static void
-_close_path (void *user_data_)
+_close_path (hb_draw_funcs_t *dfuncs, void *draw_data_,
+            hb_draw_state_t *st,
+            void *user_data)
 {
-  _user_data_t *user_data = (_user_data_t *) user_data_;
-  assert (user_data->is_open && user_data->path_len != 0);
-  user_data->path_len = 0;
-  user_data->is_open = false;
-  assert (user_data->path_start_x == user_data->path_last_x &&
-         user_data->path_start_y == user_data->path_last_y);
+  _draw_data_t *draw_data = (_draw_data_t *) draw_data_;
+  assert (st->path_open && draw_data->path_len != 0);
+  draw_data->path_len = 0;
+  assert (draw_data->path_start_x == draw_data->path_last_x &&
+         draw_data->path_start_y == draw_data->path_last_y);
 }
-#endif
 
 /* Similar to test-ot-face.c's #test_font() */
 static void misc_calls_for_gid (hb_face_t *face, hb_font_t *font, hb_set_t *set, hb_codepoint_t cp)
@@ -115,7 +119,7 @@ static void misc_calls_for_gid (hb_face_t *face, hb_font_t *font, hb_set_t *set,
 
 extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
 {
-  alloc_state = size; /* see src/failing-alloc.c */
+  alloc_state = _fuzzing_alloc_state (data, size);
 
   hb_blob_t *blob = hb_blob_create ((const char *) data, size,
                                    HB_MEMORY_MODE_READONLY, nullptr, nullptr);
@@ -135,24 +139,19 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
   unsigned glyph_count = hb_face_get_glyph_count (face);
   glyph_count = glyph_count > 16 ? 16 : glyph_count;
 
-#ifdef HB_EXPERIMENTAL_API
-  _user_data_t user_data = {false, 0, 0, 0, 0, 0};
+  _draw_data_t draw_data = {0, 0, 0, 0, 0};
 
   hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
-  hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) _move_to);
-  hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) _line_to);
-  hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) _quadratic_to);
-  hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) _cubic_to);
-  hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) _close_path);
-#endif
+  hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) _move_to, nullptr, nullptr);
+  hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) _line_to, nullptr, nullptr);
+  hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) _quadratic_to, nullptr, nullptr);
+  hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) _cubic_to, nullptr, nullptr);
+  hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) _close_path, nullptr, nullptr);
   volatile unsigned counter = !glyph_count;
   hb_set_t *set = hb_set_create ();
   for (unsigned gid = 0; gid < glyph_count; ++gid)
   {
-#ifdef HB_EXPERIMENTAL_API
-    hb_font_draw_glyph (font, gid, funcs, &user_data);
-    assert (!user_data.is_open);
-#endif
+    hb_font_draw_glyph (font, gid, funcs, &draw_data);
 
     /* Glyph extents also may practices the similar path, call it now that is related */
     hb_glyph_extents_t extents;
@@ -166,9 +165,7 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
   }
   hb_set_destroy (set);
   assert (counter);
-#ifdef HB_EXPERIMENTAL_API
   hb_draw_funcs_destroy (funcs);
-#endif
 
   hb_font_destroy (font);
   hb_face_destroy (face);
index 52e00dd..b7090a9 100644 (file)
@@ -10,9 +10,25 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size);
 #endif
 
 #ifdef HB_IS_IN_FUZZER
+
 /* See src/failing-alloc.c */
 extern "C" int alloc_state;
+
 #else
+
 /* Just a dummy global variable */
 static int HB_UNUSED alloc_state = 0;
+
 #endif
+
+static inline int
+_fuzzing_alloc_state (const uint8_t *data, size_t size)
+{
+  /* https://github.com/harfbuzz/harfbuzz/pull/2764#issuecomment-1172589849 */
+
+  /* In 50% of the runs, don't fail the allocator. */
+  if (size && data[size - 1] < 0x80)
+    return 0;
+
+  return size;
+}
diff --git a/test/fuzzing/hb-repacker-fuzzer.cc b/test/fuzzing/hb-repacker-fuzzer.cc
new file mode 100644 (file)
index 0000000..0b06fd2
--- /dev/null
@@ -0,0 +1,145 @@
+#include "hb-fuzzer.hh"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "hb-subset-repacker.h"
+
+typedef struct
+{
+  uint16_t parent;
+  uint16_t child;
+  uint16_t position;
+  uint8_t width;
+} link_t;
+
+/* The fuzzer seed contains a serialized representation of a object graph which forms
+ * the input graph to the repacker call. The binary format is:
+ *
+ * table tag: 4 bytes
+ * number of objects: 2 bytes
+ * objects[number of objects]:
+ *   blob size: 2 bytes
+ *   blob: blob size bytes
+ * num of real links: 2 bytes
+ * links[number of real links]: link_t struct
+ *
+ * TODO(garretrieger): add optional virtual links
+ */
+
+template <typename T>
+bool read(const uint8_t** data, size_t* size, T* out)
+{
+  if (*size < sizeof (T)) return false;
+
+  memcpy(out, *data, sizeof (T));
+
+  *data += sizeof (T);
+  *size -= sizeof (T);
+
+  return true;
+}
+
+void cleanup (hb_object_t* objects, uint16_t num_objects)
+{
+  for (uint32_t i = 0; i < num_objects; i++)
+  {
+    free (objects[i].head);
+    free (objects[i].real_links);
+  }
+}
+
+void add_links_to_objects (hb_object_t* objects, uint16_t num_objects,
+                           link_t* links, uint16_t num_links)
+{
+  unsigned* link_count = (unsigned*) calloc (num_objects, sizeof (unsigned));
+
+  for (uint32_t i = 0; i < num_links; i++)
+  {
+    uint16_t parent_idx = links[i].parent;
+    link_count[parent_idx]++;
+  }
+
+  for (uint32_t i = 0; i < num_objects; i++)
+  {
+    objects[i].num_real_links = link_count[i];
+    objects[i].real_links = (hb_link_t*) calloc (link_count[i], sizeof (hb_link_t));
+    objects[i].num_virtual_links = 0;
+    objects[i].virtual_links = nullptr;
+  }
+
+  for (uint32_t i = 0; i < num_links; i++)
+  {
+    uint16_t parent_idx = links[i].parent;
+    uint16_t child_idx = links[i].child + 1; // All indices are shifted by 1 by the null object.
+    hb_link_t* link = &(objects[parent_idx].real_links[link_count[parent_idx] - 1]);
+
+    link->width = links[i].width;
+    link->position = links[i].position;
+    link->objidx = child_idx;
+    link_count[parent_idx]--;
+  }
+
+  free (link_count);
+}
+
+extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
+{
+  // TODO(garretrieger): move graph validity checks into repacker graph creation.
+  alloc_state = _fuzzing_alloc_state (data, size);
+
+  uint16_t num_objects = 0;
+  hb_object_t* objects = nullptr;
+
+  uint16_t num_real_links = 0;
+  link_t* links = nullptr;
+
+  hb_tag_t table_tag;
+  if (!read<hb_tag_t> (&data, &size, &table_tag)) goto end;
+  if (!read<uint16_t> (&data, &size, &num_objects)) goto end;
+
+  objects = (hb_object_t*) calloc (num_objects, sizeof (hb_object_t));
+  for (uint32_t i = 0; i < num_objects; i++)
+  {
+    uint16_t blob_size;
+    if (!read<uint16_t> (&data, &size, &blob_size)) goto end;
+    if (size < blob_size) goto end;
+
+    char* copy = (char*) calloc (1, blob_size);
+    memcpy (copy, data, blob_size);
+    objects[i].head = (char*) copy;
+    objects[i].tail = (char*) (copy + blob_size);
+
+    size -= blob_size;
+    data += blob_size;
+  }
+
+  if (!read<uint16_t> (&data, &size, &num_real_links)) goto end;
+  links = (link_t*) calloc (num_real_links, sizeof (link_t));
+  for (uint32_t i = 0; i < num_real_links; i++)
+  {
+    if (!read<link_t> (&data, &size, &links[i])) goto end;
+
+    if (links[i].parent >= num_objects)
+      goto end;
+  }
+
+  add_links_to_objects (objects, num_objects,
+                        links, num_real_links);
+
+  hb_blob_destroy (hb_subset_repack_or_fail (table_tag,
+                                             objects,
+                                             num_objects));
+
+end:
+  if (objects)
+  {
+    cleanup (objects, num_objects);
+    free (objects);
+  }
+  free (links);
+
+  return 0;
+}
index 613699f..065e549 100644 (file)
@@ -38,7 +38,7 @@ static hb_set_t *create_set (const uint32_t *value_array, int count)
 
 extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
 {
-  alloc_state = size; /* see src/failing-alloc.c */
+  alloc_state = _fuzzing_alloc_state (data, size);
 
   if (size < sizeof (instructions_t))
     return 0;
index 0022a89..f14f651 100644 (file)
@@ -11,7 +11,7 @@
 
 extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
 {
-  alloc_state = size; /* see src/failing-alloc.c */
+  alloc_state = _fuzzing_alloc_state (data, size);
 
   hb_blob_t *blob = hb_blob_create ((const char *)data, size,
                                    HB_MEMORY_MODE_READONLY, nullptr, nullptr);
@@ -33,7 +33,7 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
   {
     const char text[] = "ABCDEXYZ123@_%&)*$!";
     hb_buffer_t *buffer = hb_buffer_create ();
//   hb_buffer_set_flags (buffer, HB_BUFFER_FLAG_VERIFY);
   hb_buffer_set_flags (buffer, (hb_buffer_flags_t) (HB_BUFFER_FLAG_VERIFY /* | HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT */));
     hb_buffer_add_utf8 (buffer, text, -1, 0, -1);
     hb_buffer_guess_segment_properties (buffer);
     hb_shape (font, buffer, nullptr, 0);
@@ -51,7 +51,7 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
   text32[10] = test_font (font, text32[15]) % 256;
 
   hb_buffer_t *buffer = hb_buffer_create ();
-//  hb_buffer_set_flags (buffer, HB_BUFFER_FLAG_VERIFY);
+ // hb_buffer_set_flags (buffer, (hb_buffer_flags_t) (HB_BUFFER_FLAG_VERIFY | HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT));
   hb_buffer_add_utf32 (buffer, text32, sizeof (text32) / sizeof (text32[0]), 0, -1);
   hb_buffer_guess_segment_properties (buffer);
   hb_shape (font, buffer, nullptr, 0);
index fa95c87..93153ed 100644 (file)
@@ -11,9 +11,9 @@ static void
 trySubset (hb_face_t *face,
           const hb_codepoint_t text[],
           int text_length,
-           unsigned flag_bits)
+           unsigned flag_bits,
+           hb_subset_input_t *input)
 {
-  hb_subset_input_t *input = hb_subset_input_create_or_fail ();
   if (!input) return;
 
   hb_subset_input_set_flags (input, (hb_subset_flags_t) flag_bits);
@@ -45,7 +45,7 @@ trySubset (hb_face_t *face,
 
 extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
 {
-  alloc_state = size; /* see src/failing-alloc.c */
+  alloc_state = _fuzzing_alloc_state (data, size);
 
   hb_blob_t *blob = hb_blob_create ((const char *) data, size,
                                    HB_MEMORY_MODE_READONLY, nullptr, nullptr);
@@ -63,20 +63,65 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
        '3', '@', '_', '%', '&', ')', '*', '$', '!'
       };
 
-  trySubset (face, text, sizeof (text) / sizeof (hb_codepoint_t), flags);
+  hb_subset_input_t *input = hb_subset_input_create_or_fail ();
+  if (!input)
+  {
+    hb_face_destroy (face);
+    hb_blob_destroy (blob);
+    return 0;
+  }
+  trySubset (face, text, sizeof (text) / sizeof (hb_codepoint_t), flags, input);
 
+  unsigned num_axes;
   hb_codepoint_t text_from_data[16];
-  if (size > sizeof (text_from_data) + sizeof (flags)) {
+  if (size > sizeof (text_from_data) + sizeof (flags) + sizeof(num_axes)) {
+    hb_subset_input_t *input = hb_subset_input_create_or_fail ();
+    if (!input)
+    {
+      hb_face_destroy (face);
+      hb_blob_destroy (blob);
+      return 0;
+    }
+    size -= sizeof (text_from_data);
     memcpy (text_from_data,
-           data + size - sizeof (text_from_data),
+           data + size,
            sizeof (text_from_data));
 
+    size -= sizeof (flags);
     memcpy (&flags,
-           data + size - sizeof (text_from_data) - sizeof (flags),
+           data + size,
            sizeof (flags));
-    unsigned int text_size = sizeof (text_from_data) / sizeof (hb_codepoint_t);
 
-    trySubset (face, text_from_data, text_size, flags);
+    size -= sizeof (num_axes);
+    memcpy (&num_axes,
+           data + size,
+           sizeof (num_axes));
+
+    if (num_axes > 0 && num_axes < 8 && size > num_axes * (sizeof(hb_tag_t) + sizeof(int)))
+    {
+      for (unsigned i = 0; i < num_axes; i++) {
+        hb_tag_t tag;
+        int value;
+        size -= sizeof (tag);
+        memcpy (&tag,
+                data + size,
+                sizeof (tag));
+        size -= sizeof (value);
+        memcpy (&value,
+                data + size,
+                sizeof (value));
+
+        hb_subset_input_pin_axis_location(input,
+                                          face,
+                                          tag,
+                                          (float) value);
+      }
+    }
+
+
+
+    unsigned int text_size = sizeof (text_from_data) / sizeof (hb_codepoint_t);
+    trySubset (face, text_from_data, text_size, flags, input);
   }
 
   hb_face_destroy (face);
index 3aba9eb..d38ca8f 100644 (file)
@@ -5,6 +5,10 @@ tests = [
   'hb-draw-fuzzer.cc',
 ]
 
+if get_option('experimental_api')
+  tests += 'hb-repacker-fuzzer.cc'
+endif
+
 foreach file_name : tests
   test_name = file_name.split('.')[0]
 
@@ -19,6 +23,10 @@ foreach file_name : tests
     extra_cpp_args += '-DHB_IS_IN_FUZZER'
   endif
 
+  if get_option('experimental_api')
+    extra_cpp_args += '-DHB_EXPERIMENTAL_API'
+  endif
+
   exe = executable(test_name, sources,
     cpp_args: cpp_args + extra_cpp_args,
     include_directories: [incconfig, incsrc],
@@ -55,6 +63,20 @@ test('subset_fuzzer', find_program('run-subset-fuzzer-tests.py'),
   suite: ['fuzzing', 'slow'],
 )
 
+if get_option('experimental_api')
+  test('repacker_fuzzer', find_program('run-repacker-fuzzer-tests.py'),
+    args: [
+      hb_repacker_fuzzer_exe,
+    ],
+    # as the tests are ran concurrently let's raise acceptable time here
+    # ideally better to break and let meson handles them in parallel
+    timeout: 300,
+    workdir: meson.current_build_dir() / '..' / '..',
+    env: env,
+    suite: ['fuzzing', 'slow'],
+  )
+endif
+
 test('draw_fuzzer', find_program('run-draw-fuzzer-tests.py'),
   args: [
     hb_draw_fuzzer_exe,
diff --git a/test/fuzzing/run-repacker-fuzzer-tests.py b/test/fuzzing/run-repacker-fuzzer-tests.py
new file mode 100644 (file)
index 0000000..85a23e1
--- /dev/null
@@ -0,0 +1,68 @@
+#!/usr/bin/env python3
+
+import sys, os, subprocess, tempfile, shutil
+
+
+def cmd (command):
+       # https://stackoverflow.com/a/4408409 as we might have huge output sometimes
+       with tempfile.TemporaryFile () as tempf:
+               p = subprocess.Popen (command, stderr=tempf)
+
+               try:
+                       p.wait ()
+                       tempf.seek (0)
+                       text = tempf.read ()
+
+                       #TODO: Detect debug mode with a better way
+                       is_debug_mode = b"SANITIZE" in text
+
+                       return ("" if is_debug_mode else text.decode ("utf-8").strip ()), p.returncode
+               except subprocess.TimeoutExpired:
+                       return 'error: timeout, ' + ' '.join (command), 1
+
+
+srcdir = os.getenv ("srcdir", ".")
+EXEEXT = os.getenv ("EXEEXT", "")
+top_builddir = os.getenv ("top_builddir", ".")
+hb_repacker_fuzzer = os.path.join (top_builddir, "hb-repacker-fuzzer" + EXEEXT)
+
+if not os.path.exists (hb_repacker_fuzzer):
+        if len (sys.argv) < 2 or not os.path.exists (sys.argv[1]):
+                sys.exit ("""Failed to find hb-repacker-fuzzer binary automatically,
+please provide it as the first argument to the tool""")
+
+        hb_repacker_fuzzer = sys.argv[1]
+
+print ('hb_repacker_fuzzer:', hb_repacker_fuzzer)
+fails = 0
+
+valgrind = None
+if os.getenv ('RUN_VALGRIND', ''):
+       valgrind = shutil.which ('valgrind')
+       if valgrind is None:
+               sys.exit ("""Valgrind requested but not found.""")
+
+def run_dir (parent_path):
+       global fails
+       for file in os.listdir (parent_path):
+               path = os.path.join(parent_path, file)
+               print ("running repacker fuzzer against %s" % path)
+               if valgrind:
+                       text, returncode = cmd ([valgrind, '--leak-check=full', '--error-exitcode=1', hb_repacker_fuzzer, path])
+               else:
+                       text, returncode = cmd ([hb_repacker_fuzzer, path])
+                       if 'error' in text:
+                               returncode = 1
+
+               if (not valgrind or returncode) and text.strip ():
+                       print (text)
+
+               if returncode != 0:
+                       print ("failed for %s" % path)
+                       fails = fails + 1
+
+
+run_dir (os.path.join (srcdir, "graphs"))
+
+if fails:
+       sys.exit ("%d repacker fuzzer related tests failed." % fails)
diff --git a/test/fuzzing/sets/clusterfuzz-testcase-minimized-hb-set-fuzzer-6255224052514816 b/test/fuzzing/sets/clusterfuzz-testcase-minimized-hb-set-fuzzer-6255224052514816
new file mode 100644 (file)
index 0000000..d8a3989
--- /dev/null
@@ -0,0 +1 @@
+       
\ No newline at end of file
diff --git a/test/fuzzing/sets/intersect_01 b/test/fuzzing/sets/intersect_01
new file mode 100644 (file)
index 0000000..5b1e7e3
Binary files /dev/null and b/test/fuzzing/sets/intersect_01 differ
diff --git a/test/fuzzing/sets/subtract_01 b/test/fuzzing/sets/subtract_01
new file mode 100644 (file)
index 0000000..1c60ac6
Binary files /dev/null and b/test/fuzzing/sets/subtract_01 differ
diff --git a/test/fuzzing/sets/symmetric_diff_01 b/test/fuzzing/sets/symmetric_diff_01
new file mode 100644 (file)
index 0000000..70801a7
Binary files /dev/null and b/test/fuzzing/sets/symmetric_diff_01 differ
diff --git a/test/fuzzing/sets/union_01 b/test/fuzzing/sets/union_01
new file mode 100644 (file)
index 0000000..5a13eb0
Binary files /dev/null and b/test/fuzzing/sets/union_01 differ
index 8b4b83f..371b7ef 100644 (file)
@@ -2,3 +2,4 @@ subdir('api')
 subdir('shape')
 subdir('subset')
 subdir('fuzzing')
+subdir('threads')
index 316b173..bb4d919 100644 (file)
@@ -25,7 +25,6 @@ EXTRA_DIST += \
        hb-unicode-prettyname \
        record-test.sh \
        run-tests.py \
-       texts/in-house \
        $(NULL)
 
 # TODO Figure out Python stuff
index 463e19f..ce33586 100644 (file)
@@ -221,8 +221,6 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
-DIRECTWRITE_CXXFLAGS = @DIRECTWRITE_CXXFLAGS@
-DIRECTWRITE_LIBS = @DIRECTWRITE_LIBS@
 DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -320,6 +318,8 @@ STRIP = @STRIP@
 UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
 UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
 VERSION = @VERSION@
+WASM_CFLAGS = @WASM_CFLAGS@
+WASM_LIBS = @WASM_LIBS@
 _GI_EXP_DATADIR = @_GI_EXP_DATADIR@
 _GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@
 abs_builddir = @abs_builddir@
@@ -384,7 +384,7 @@ NULL =
 EXTRA_DIST = README.md meson.build hb-diff hb-diff-colorize \
        hb-diff-filter-failures hb-diff-stat hb-unicode-decode \
        hb-unicode-encode hb-unicode-prettyname record-test.sh \
-       run-tests.py texts/in-house $(NULL) hb_test_tools.py $(NULL)
+       run-tests.py $(NULL) hb_test_tools.py $(NULL)
 CLEANFILES = hb_test_tools.py[co] $(NULL)
 DISTCLEANFILES = 
 MAINTAINERCLEANFILES = 
index f386fb9..08cdcdc 100644 (file)
@@ -14,7 +14,7 @@ FontTools from <https://github.com/behdad/fonttools>.
 
 To use `record-test.sh`, just put it right before the `hb-shape` invocation:
 ```sh
-$ ./hb-unicode-encode 41 42 43 627 | ./record-test.sh ../../util/hb-shape font.ttf
+$ ./hb-unicode-encode 41 42 43 627 | ./record-test.sh ../../util/hb-subset ../../util/hb-shape font.ttf
 ```
 what this does is:
   * Subset the font for the sequence of Unicode characters requested,
@@ -28,7 +28,7 @@ what this does is:
     to an existing or new test file in `data/in-house/tests` using `-o`,
     e.g.:
 ```sh
-$ ./hb-unicode-encode 41 42 43 627 | ./record-test.sh -o data/in-house/tests/test-name.test ../../util/hb-shape font.ttf
+$ ./hb-unicode-encode 41 42 43 627 | ./record-test.sh -o data/in-house/tests/test-name.tests ../../util/hb-subset ../../util/hb-shape font.ttf
 ```
 
 If you created a new test file, add it to `data/in-house/Makefile.sources`
index 28fade0..1fa1ba1 100644 (file)
@@ -221,8 +221,6 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
-DIRECTWRITE_CXXFLAGS = @DIRECTWRITE_CXXFLAGS@
-DIRECTWRITE_LIBS = @DIRECTWRITE_LIBS@
 DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -320,6 +318,8 @@ STRIP = @STRIP@
 UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
 UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
 VERSION = @VERSION@
+WASM_CFLAGS = @WASM_CFLAGS@
+WASM_LIBS = @WASM_LIBS@
 _GI_EXP_DATADIR = @_GI_EXP_DATADIR@
 _GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@
 abs_builddir = @abs_builddir@
index 27e8731..dd56bf0 100644 (file)
@@ -467,8 +467,6 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
-DIRECTWRITE_CXXFLAGS = @DIRECTWRITE_CXXFLAGS@
-DIRECTWRITE_LIBS = @DIRECTWRITE_LIBS@
 DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -566,6 +564,8 @@ STRIP = @STRIP@
 UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
 UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
 VERSION = @VERSION@
+WASM_CFLAGS = @WASM_CFLAGS@
+WASM_LIBS = @WASM_LIBS@
 _GI_EXP_DATADIR = @_GI_EXP_DATADIR@
 _GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@
 abs_builddir = @abs_builddir@
index a284578..608f9be 100644 (file)
@@ -7,17 +7,24 @@ lib:
        @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
 
 EXTRA_DIST = \
-       COPYING \
        fonts \
        meson.build \
        $(TESTS) \
        $(NULL)
 
 TEST_EXTENSIONS = .tests
+TESTS_ENVIRONMENT = 
 if HAVE_FREETYPE
-TESTS_ENVIRONMENT = HAVE_FREETYPE=1
-else
-TESTS_ENVIRONMENT = HAVE_FREETYPE=0
+TESTS_ENVIRONMENT += HAVE_FREETYPE=1
+endif
+if HAVE_CORETEXT
+TESTS_ENVIRONMENT += HAVE_CORETEXT=1
+endif
+if HAVE_DIRECTWRITE
+TESTS_ENVIRONMENT += HAVE_DIRECTWRITE=1
+endif
+if HAVE_UNISCRIBE
+TESTS_ENVIRONMENT += HAVE_UNISCRIBE=1
 endif
 TESTS_LOG_COMPILER = $(srcdir)/../../run-tests.py $(top_builddir)/util/hb-shape$(EXEEXT)
 
index 8b05d38..40c3613 100644 (file)
@@ -89,21 +89,28 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
+@HAVE_FREETYPE_TRUE@am__append_1 = HAVE_FREETYPE=1
+@HAVE_CORETEXT_TRUE@am__append_2 = HAVE_CORETEXT=1
+@HAVE_DIRECTWRITE_TRUE@am__append_3 = HAVE_DIRECTWRITE=1
+@HAVE_UNISCRIBE_TRUE@am__append_4 = HAVE_UNISCRIBE=1
 TESTS = tests/aat-morx.tests tests/aat-trak.tests \
        tests/arabic-fallback-shaping.tests \
        tests/arabic-feature-order.tests \
-       tests/arabic-like-joining.tests tests/arabic-mark-attach.tests \
-       tests/arabic-mark-order.tests tests/arabic-normalization.tests \
+       tests/arabic-like-joining.tests tests/arabic-mark-order.tests \
+       tests/arabic-normalization.tests tests/arabic-phags-pa.tests \
        tests/arabic-stch.tests tests/automatic-fractions.tests \
        tests/cluster.tests tests/collections.tests \
        tests/color-fonts.tests tests/context-matching.tests \
-       tests/cursive-positioning.tests tests/default-ignorables.tests \
-       tests/digits.tests tests/emoji.tests \
+       tests/coretext.tests tests/cursive-positioning.tests \
+       tests/default-ignorables.tests tests/digits.tests \
+       tests/directwrite.tests tests/emoji.tests \
        tests/emoji-clusters.tests tests/fallback-positioning.tests \
        tests/glyph-props-no-gdef.tests tests/hangul-jamo.tests \
-       tests/hyphens.tests tests/indic-consonant-with-stacker.tests \
-       tests/indic-decompose.tests tests/indic-init.tests \
-       tests/indic-joiner-candrabindu.tests tests/indic-joiners.tests \
+       tests/hebrew-diacritics.tests tests/hyphens.tests \
+       tests/indic-consonant-with-stacker.tests \
+       tests/indic-decompose.tests tests/indic-feature-order.tests \
+       tests/indic-init.tests tests/indic-joiner-candrabindu.tests \
+       tests/indic-joiners.tests tests/indic-malayalam-dot-reph.tests \
        tests/indic-old-spec.tests tests/indic-pref-blocking.tests \
        tests/indic-script-extensions.tests \
        tests/indic-special-cases.tests tests/indic-syllable.tests \
@@ -119,11 +126,12 @@ TESTS = tests/aat-morx.tests tests/aat-trak.tests \
        tests/nested-mark-filtering-sets.tests \
        tests/none-directional.tests tests/positioning-features.tests \
        tests/rand.tests tests/reverse-sub.tests tests/rotation.tests \
-       tests/simple.tests tests/sinhala.tests tests/spaces.tests \
-       tests/tibetan-contractions-1.tests \
+       tests/sara-am.tests tests/simple.tests tests/sinhala.tests \
+       tests/spaces.tests tests/tibetan-contractions-1.tests \
        tests/tibetan-contractions-2.tests tests/tibetan-vowels.tests \
-       tests/tt-kern-gpos.tests tests/unsafe-to-concat.tests \
-       tests/use-indic3.tests tests/use-marchen.tests \
+       tests/tt-kern-gpos.tests tests/uniscribe.tests \
+       tests/unsafe-to-concat.tests tests/use-indic3.tests \
+       tests/use-javanese.tests tests/use-marchen.tests \
        tests/use-syllable.tests tests/use-vowel-letter-spoofing.tests \
        tests/use.tests tests/variations.tests \
        tests/variations-rvrn.tests tests/vertical.tests \
@@ -367,7 +375,7 @@ am__set_b = \
       b='$*';; \
   esac
 am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.sources \
-       $(top_srcdir)/test-driver COPYING
+       $(top_srcdir)/test-driver
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -403,8 +411,6 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
-DIRECTWRITE_CXXFLAGS = @DIRECTWRITE_CXXFLAGS@
-DIRECTWRITE_LIBS = @DIRECTWRITE_LIBS@
 DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -502,6 +508,8 @@ STRIP = @STRIP@
 UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
 UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
 VERSION = @VERSION@
+WASM_CFLAGS = @WASM_CFLAGS@
+WASM_LIBS = @WASM_LIBS@
 _GI_EXP_DATADIR = @_GI_EXP_DATADIR@
 _GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@
 abs_builddir = @abs_builddir@
@@ -562,15 +570,14 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 NULL = 
 EXTRA_DIST = \
-       COPYING \
        fonts \
        meson.build \
        $(TESTS) \
        $(NULL)
 
 TEST_EXTENSIONS = .tests
-@HAVE_FREETYPE_FALSE@TESTS_ENVIRONMENT = HAVE_FREETYPE=0
-@HAVE_FREETYPE_TRUE@TESTS_ENVIRONMENT = HAVE_FREETYPE=1
+TESTS_ENVIRONMENT = $(am__append_1) $(am__append_2) $(am__append_3) \
+       $(am__append_4)
 TESTS_LOG_COMPILER = $(srcdir)/../../run-tests.py $(top_builddir)/util/hb-shape$(EXEEXT)
 DISABLED_TESTS = \
        $(NULL)
index 02c9e91..08e9d7f 100644 (file)
@@ -4,29 +4,34 @@ TESTS = \
        tests/arabic-fallback-shaping.tests \
        tests/arabic-feature-order.tests \
        tests/arabic-like-joining.tests \
-       tests/arabic-mark-attach.tests \
        tests/arabic-mark-order.tests \
        tests/arabic-normalization.tests \
+       tests/arabic-phags-pa.tests \
        tests/arabic-stch.tests \
        tests/automatic-fractions.tests \
        tests/cluster.tests \
        tests/collections.tests \
        tests/color-fonts.tests \
        tests/context-matching.tests \
+       tests/coretext.tests \
        tests/cursive-positioning.tests \
        tests/default-ignorables.tests \
        tests/digits.tests \
+       tests/directwrite.tests \
        tests/emoji.tests \
        tests/emoji-clusters.tests \
        tests/fallback-positioning.tests \
        tests/glyph-props-no-gdef.tests \
        tests/hangul-jamo.tests \
+       tests/hebrew-diacritics.tests \
        tests/hyphens.tests \
        tests/indic-consonant-with-stacker.tests \
        tests/indic-decompose.tests \
+       tests/indic-feature-order.tests \
        tests/indic-init.tests \
        tests/indic-joiner-candrabindu.tests \
        tests/indic-joiners.tests \
+       tests/indic-malayalam-dot-reph.tests \
        tests/indic-old-spec.tests \
        tests/indic-pref-blocking.tests \
        tests/indic-script-extensions.tests \
@@ -52,6 +57,7 @@ TESTS = \
        tests/rand.tests \
        tests/reverse-sub.tests \
        tests/rotation.tests \
+       tests/sara-am.tests \
        tests/simple.tests \
        tests/sinhala.tests \
        tests/spaces.tests \
@@ -59,8 +65,10 @@ TESTS = \
        tests/tibetan-contractions-2.tests \
        tests/tibetan-vowels.tests \
        tests/tt-kern-gpos.tests \
+       tests/uniscribe.tests \
        tests/unsafe-to-concat.tests \
        tests/use-indic3.tests \
+       tests/use-javanese.tests \
        tests/use-marchen.tests \
        tests/use-syllable.tests \
        tests/use-vowel-letter-spoofing.tests \
diff --git a/test/shape/data/in-house/fonts/086d83239e8f958391ff6cdd8fda9376a4bd3673.ttf b/test/shape/data/in-house/fonts/086d83239e8f958391ff6cdd8fda9376a4bd3673.ttf
new file mode 100644 (file)
index 0000000..134e7dd
Binary files /dev/null and b/test/shape/data/in-house/fonts/086d83239e8f958391ff6cdd8fda9376a4bd3673.ttf differ
diff --git a/test/shape/data/in-house/fonts/190a621e48d4af1fffd8144bd41d2027e9a32fbf.ttf b/test/shape/data/in-house/fonts/190a621e48d4af1fffd8144bd41d2027e9a32fbf.ttf
new file mode 100644 (file)
index 0000000..3c8d448
Binary files /dev/null and b/test/shape/data/in-house/fonts/190a621e48d4af1fffd8144bd41d2027e9a32fbf.ttf differ
diff --git a/test/shape/data/in-house/fonts/23406a60ab081c4fb15e1596ea1cd4f27ae8443e.ttf b/test/shape/data/in-house/fonts/23406a60ab081c4fb15e1596ea1cd4f27ae8443e.ttf
new file mode 100644 (file)
index 0000000..e88a9af
Binary files /dev/null and b/test/shape/data/in-house/fonts/23406a60ab081c4fb15e1596ea1cd4f27ae8443e.ttf differ
diff --git a/test/shape/data/in-house/fonts/41071178fbce4956d151f50967af458dbf555f7b.ttf b/test/shape/data/in-house/fonts/41071178fbce4956d151f50967af458dbf555f7b.ttf
new file mode 100644 (file)
index 0000000..ebb6f64
Binary files /dev/null and b/test/shape/data/in-house/fonts/41071178fbce4956d151f50967af458dbf555f7b.ttf differ
diff --git a/test/shape/data/in-house/fonts/507637795ce4f2975593da54d12b46f76c7cc4cc.ttf b/test/shape/data/in-house/fonts/507637795ce4f2975593da54d12b46f76c7cc4cc.ttf
new file mode 100644 (file)
index 0000000..e25dcca
Binary files /dev/null and b/test/shape/data/in-house/fonts/507637795ce4f2975593da54d12b46f76c7cc4cc.ttf differ
diff --git a/test/shape/data/in-house/fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf b/test/shape/data/in-house/fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf
new file mode 100644 (file)
index 0000000..9834a2e
Binary files /dev/null and b/test/shape/data/in-house/fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf differ
diff --git a/test/shape/data/in-house/fonts/5bbf3712e6f79775c66a4407837a90e591efbef2.ttf b/test/shape/data/in-house/fonts/5bbf3712e6f79775c66a4407837a90e591efbef2.ttf
new file mode 100644 (file)
index 0000000..2d2bf19
Binary files /dev/null and b/test/shape/data/in-house/fonts/5bbf3712e6f79775c66a4407837a90e591efbef2.ttf differ
diff --git a/test/shape/data/in-house/fonts/5f73fff1ffc07b5a99a90c0909609f2b09fef274.ttf b/test/shape/data/in-house/fonts/5f73fff1ffc07b5a99a90c0909609f2b09fef274.ttf
new file mode 100644 (file)
index 0000000..f94d2aa
Binary files /dev/null and b/test/shape/data/in-house/fonts/5f73fff1ffc07b5a99a90c0909609f2b09fef274.ttf differ
diff --git a/test/shape/data/in-house/fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf b/test/shape/data/in-house/fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf
new file mode 100644 (file)
index 0000000..055a836
Binary files /dev/null and b/test/shape/data/in-house/fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf differ
diff --git a/test/shape/data/in-house/fonts/641ca9d7808b01cafa9a666c13811c9b56eb9c52.ttf b/test/shape/data/in-house/fonts/641ca9d7808b01cafa9a666c13811c9b56eb9c52.ttf
deleted file mode 100644 (file)
index 1328e13..0000000
Binary files a/test/shape/data/in-house/fonts/641ca9d7808b01cafa9a666c13811c9b56eb9c52.ttf and /dev/null differ
diff --git a/test/shape/data/in-house/fonts/7c24183f26d60df414578a0a9f5e79ab9d32a22b.ttf b/test/shape/data/in-house/fonts/7c24183f26d60df414578a0a9f5e79ab9d32a22b.ttf
new file mode 100644 (file)
index 0000000..af8052d
Binary files /dev/null and b/test/shape/data/in-house/fonts/7c24183f26d60df414578a0a9f5e79ab9d32a22b.ttf differ
diff --git a/test/shape/data/in-house/fonts/8339c821814d9bad7c77169332327ad8b0f33c81.ttf b/test/shape/data/in-house/fonts/8339c821814d9bad7c77169332327ad8b0f33c81.ttf
new file mode 100644 (file)
index 0000000..cc60a07
Binary files /dev/null and b/test/shape/data/in-house/fonts/8339c821814d9bad7c77169332327ad8b0f33c81.ttf differ
diff --git a/test/shape/data/in-house/fonts/9d8c53cb64b8747abdd2b70755cce2ee0eb42ef7.ttf b/test/shape/data/in-house/fonts/9d8c53cb64b8747abdd2b70755cce2ee0eb42ef7.ttf
new file mode 100644 (file)
index 0000000..9c9f942
Binary files /dev/null and b/test/shape/data/in-house/fonts/9d8c53cb64b8747abdd2b70755cce2ee0eb42ef7.ttf differ
diff --git a/test/shape/data/in-house/fonts/SimpArabicTest.ttf b/test/shape/data/in-house/fonts/SimpArabicTest.ttf
new file mode 100644 (file)
index 0000000..d560f6a
Binary files /dev/null and b/test/shape/data/in-house/fonts/SimpArabicTest.ttf differ
diff --git a/test/shape/data/in-house/fonts/TradArabicTest.ttf b/test/shape/data/in-house/fonts/TradArabicTest.ttf
new file mode 100644 (file)
index 0000000..a82ed35
Binary files /dev/null and b/test/shape/data/in-house/fonts/TradArabicTest.ttf differ
diff --git a/test/shape/data/in-house/fonts/a232bb734d4c6c898a44506547d19768f0eba6a6.ttf b/test/shape/data/in-house/fonts/a232bb734d4c6c898a44506547d19768f0eba6a6.ttf
new file mode 100644 (file)
index 0000000..e0325bb
Binary files /dev/null and b/test/shape/data/in-house/fonts/a232bb734d4c6c898a44506547d19768f0eba6a6.ttf differ
diff --git a/test/shape/data/in-house/fonts/a56745bac8449d0ad94918b2bb5930716ba02fe3.ttf b/test/shape/data/in-house/fonts/a56745bac8449d0ad94918b2bb5930716ba02fe3.ttf
new file mode 100644 (file)
index 0000000..31f8731
Binary files /dev/null and b/test/shape/data/in-house/fonts/a56745bac8449d0ad94918b2bb5930716ba02fe3.ttf differ
diff --git a/test/shape/data/in-house/fonts/a59fd13f1525a91cbe529c882e93d9d1fbb80463.ttf b/test/shape/data/in-house/fonts/a59fd13f1525a91cbe529c882e93d9d1fbb80463.ttf
new file mode 100644 (file)
index 0000000..da5255f
Binary files /dev/null and b/test/shape/data/in-house/fonts/a59fd13f1525a91cbe529c882e93d9d1fbb80463.ttf differ
diff --git a/test/shape/data/in-house/fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf b/test/shape/data/in-house/fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf
new file mode 100644 (file)
index 0000000..ff0129b
Binary files /dev/null and b/test/shape/data/in-house/fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf differ
diff --git a/test/shape/data/in-house/fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf b/test/shape/data/in-house/fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf
new file mode 100644 (file)
index 0000000..8197869
Binary files /dev/null and b/test/shape/data/in-house/fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf differ
diff --git a/test/shape/data/in-house/fonts/bef923f4ccb474f961c43b63a9c74b7d9b7a023f.ttf b/test/shape/data/in-house/fonts/bef923f4ccb474f961c43b63a9c74b7d9b7a023f.ttf
new file mode 100644 (file)
index 0000000..7dff0cc
Binary files /dev/null and b/test/shape/data/in-house/fonts/bef923f4ccb474f961c43b63a9c74b7d9b7a023f.ttf differ
diff --git a/test/shape/data/in-house/fonts/d0430ea499348c420946f6abc2efc84fdf8f00e3.ttf b/test/shape/data/in-house/fonts/d0430ea499348c420946f6abc2efc84fdf8f00e3.ttf
new file mode 100644 (file)
index 0000000..5ecda48
Binary files /dev/null and b/test/shape/data/in-house/fonts/d0430ea499348c420946f6abc2efc84fdf8f00e3.ttf differ
diff --git a/test/shape/data/in-house/fonts/e716f6bd00a108d186b7e9f47b4515565f784f36.ttf b/test/shape/data/in-house/fonts/e716f6bd00a108d186b7e9f47b4515565f784f36.ttf
new file mode 100644 (file)
index 0000000..6786f7c
Binary files /dev/null and b/test/shape/data/in-house/fonts/e716f6bd00a108d186b7e9f47b4515565f784f36.ttf differ
diff --git a/test/shape/data/in-house/fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf b/test/shape/data/in-house/fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf
new file mode 100644 (file)
index 0000000..80c97d3
Binary files /dev/null and b/test/shape/data/in-house/fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf differ
diff --git a/test/shape/data/in-house/fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf b/test/shape/data/in-house/fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf
new file mode 100644 (file)
index 0000000..c9311cf
Binary files /dev/null and b/test/shape/data/in-house/fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf differ
index 2da9dab..976cf15 100644 (file)
@@ -1,32 +1,37 @@
-in_house_tests_base = [
+in_house_tests = [
   'aat-morx.tests',
   'aat-trak.tests',
   'arabic-fallback-shaping.tests',
   'arabic-feature-order.tests',
   'arabic-like-joining.tests',
-  'arabic-mark-attach.tests',
   'arabic-mark-order.tests',
   'arabic-normalization.tests',
+  'arabic-phags-pa.tests',
   'arabic-stch.tests',
   'automatic-fractions.tests',
   'cluster.tests',
   'collections.tests',
   'color-fonts.tests',
   'context-matching.tests',
+  'coretext.tests',
   'cursive-positioning.tests',
   'default-ignorables.tests',
   'digits.tests',
+  'directwrite.tests',
   'emoji.tests',
   'emoji-clusters.tests',
   'fallback-positioning.tests',
   'glyph-props-no-gdef.tests',
   'hangul-jamo.tests',
+  'hebrew-diacritics.tests',
   'hyphens.tests',
   'indic-consonant-with-stacker.tests',
   'indic-decompose.tests',
+  'indic-feature-order.tests',
   'indic-init.tests',
   'indic-joiner-candrabindu.tests',
   'indic-joiners.tests',
+  'indic-malayalam-dot-reph.tests',
   'indic-old-spec.tests',
   'indic-pref-blocking.tests',
   'indic-script-extensions.tests',
@@ -52,6 +57,7 @@ in_house_tests_base = [
   'rand.tests',
   'reverse-sub.tests',
   'rotation.tests',
+  'sara-am.tests',
   'simple.tests',
   'sinhala.tests',
   'spaces.tests',
@@ -59,8 +65,10 @@ in_house_tests_base = [
   'tibetan-contractions-2.tests',
   'tibetan-vowels.tests',
   'tt-kern-gpos.tests',
+  'uniscribe.tests',
   'unsafe-to-concat.tests',
   'use-indic3.tests',
+  'use-javanese.tests',
   'use-marchen.tests',
   'use-syllable.tests',
   'use-vowel-letter-spoofing.tests',
@@ -70,15 +78,3 @@ in_house_tests_base = [
   'vertical.tests',
   'zero-width-marks.tests',
 ]
-
-in_house_tests_coretext = [
-  'coretext.tests',
-]
-
-in_house_tests_uniscribe = [
-  'uniscribe.tests',
-]
-
-in_house_tests_directwrite = [
-  'directwrite.tests',
-]
index 14f8919..ac08789 100644 (file)
@@ -1 +1,11 @@
 ../fonts/df768b9c257e0c9c35786c47cae15c46571d56be.ttf;;U+0633,U+064F,U+0644,U+064E,U+0651,U+0627,U+0651,U+0650,U+0645,U+062A,U+06CC;[uni06CC.fina=10+1655|uni062A.medi=9+868|uni0645.init=8+1098|uni0650=2@148,0+0|uni0651=2@187,736+0|uni064E=2@883,1259+0|uni0651=2@922,736+0|uni06440627.fina=2+1470|uni064F=0@629,-10+0|uni0633.init=0+1585]
+../fonts/SimpArabicTest.ttf;--no-positions;U+0628,U+0650,U+0633,U+0652,U+0645,U+0650,U+0020,U+0020,U+0627,U+0644,U+0644,U+0647,U+0020,U+0627,U+0644,U+0631,U+0651,U+064E,U+062D,U+0652,U+0645,U+064E,U+0646,U+0650,U+0020,U+0627,U+0644,U+0631,U+062D,U+0650,U+064A,U+0645;[daggerdbl=31|c142=30|twosuperior=28|bracketleft=28|c=27|quotedblbase=26|J=25|parenright=24|twosuperior=22|Eacute=22|logicalnot=20|dagger=20|registered=18|bracketleft=18|logicalnot=15|plusminus=15|c=15|quotedblbase=14|J=13|parenright=12|guilsinglleft=11|quotedblbase=10|quotedblbase=9|J=8|parenright=7|parenright=6|twosuperior=4|daggerdbl=4|registered=2|j=2|twosuperior=0|R=0]
+../fonts/SimpArabicTest.ttf;;U+0020,U+0644,U+0627,U+0020,U+0644,U+0623,U+0020,U+0644,U+064E,U+0623,U+064E,U+0020,U+0623,U+064E,U+0646,U+062A;[U=15+693|DEL=14+227|logicalnot=12@17,307+0|L=12+289|parenright=11+391|logicalnot=7@41,267+0|logicalnot=7@378,267+0|brokenbar=7+674|parenright=6+391|brokenbar=4+674|parenright=3+391|yen=1+709|parenright=0+391]
+../fonts/SimpArabicTest.ttf;;U+0021,U+0022,U+00AB,U+00BB,U+0025,U+00D7,U+00F7,U+0028,U+0020,U+0029,U+002A,U+002B,U+060C,U+002E,U+002F,U+003A,U+061B,U+2018,U+003D,U+2019,U+061F,U+005B,U+005D,U+002D,U+0022;[asterisk=0+269|plus=1+408|comma=2+509|hyphen=3+509|period=4+573|slash=5+572|zero=6+572|one=7+300|parenright=8+391|two=9+300|three=10+551|four=11+572|five=12+283|seven=13+268|eight=14+372|C=15+268|D=16+295|E=17+175|F=18+572|G=19+175|H=20+485|d=21+329|f=22+329|six=23+322|plus=24+408]
+../fonts/SimpArabicTest.ttf;;U+061F,U+003F,U+0640;[H=0+485|H=1+485|h=2+171]
+../fonts/SimpArabicTest.ttf;;U+0628,U+0644,U+0627,U+0020,U+0628,U+0644,U+0625;[ordfeminine=5+674|R=4+232|parenright=3+391|yen=1+709|R=0+232]
+../fonts/TradArabicTest.ttf;;U+0628,U+0650,U+0633,U+0652,U+0645,U+0650,U+0020,U+0020,U+0627,U+0644,U+0644,U+0647,U+0020,U+0627,U+0644,U+0631,U+0651,U+064E,U+062D,U+0652,U+0645,U+064E,U+0646,U+0650,U+0020,U+0627,U+0644,U+0631,U+062D,U+0650,U+064A,U+0645;[fnmeem=31+1069|midya=30+499|kasrah2=28@151,0+0|inhaa=28+1341|fnra=27+702|inlam=26+358|alef=25+444|righttoleftspace=24+468|kasrah2=22@110,-604+0|fnnoon=22+1259|fathah2=18@-145,-168+0|sukun2=18@760,-166+0|f29b=18+1497|fahtanonshaddah2=15@-51,-416+0|fnra=15+702|inlam=14+358|alef=13+444|righttoleftspace=12+468|Allah=9+1513|alef=8+444|righttoleftspace=7+468|righttoleftspace=6+468|kasrah2=4@15,-1102+0|fnmeem=4+1069|sukun2=2@220,-386+0|midseen=2+1163|kasrah2=0@-324,-403+0|inbaa=0+389]
+../fonts/TradArabicTest.ttf;;U+0020,U+0644,U+0627,U+0020,U+0644,U+0623,U+0020,U+0644,U+064E,U+0623,U+064E,U+0020,U+0623,U+064E,U+0646,U+062A;[fntaa=15+1808|innoon=14+389|fathah2=12@-279,883+0|hamzahonalef=12+479|righttoleftspace=11+468|fathah2=7@-190,862+0|fathah2=7@468,862+0|hamzahonlamelef=7+1316|righttoleftspace=6+468|hamzahonlamelef=4+1316|righttoleftspace=3+468|lamelef=1+1316|righttoleftspace=0+468]
+../fonts/TradArabicTest.ttf;;U+0021,U+0022,U+00AB,U+00BB,U+0025,U+00D7,U+00F7,U+0028,U+0020,U+0029,U+002A,U+002B,U+060C,U+002E,U+002F,U+003A,U+061B,U+2018,U+003D,U+2019,U+061F,U+005B,U+005D,U+002D,U+0022;[greater=0+481|question=1+559|at=2+849|A=3+849|percentarabic=4+1353|C=5+927|D=6+1196|E=7+855|righttoleftspace=8+468|F=9+855|G=10+884|H=11+1083|commaarabic=12+755|K=13+649|L=14+704|W=15+450|semicolonarabic=16+755|.notdef=17+745|Z=18+1128|.notdef=19+745|questionarabic=20+845|x=21+739|z=22+739|J=23+753|question=24+559]
+../fonts/TradArabicTest.ttf;;U+061F,U+003F,U+0640;[questionarabic=0+845|questionarabic=1+845|tatweelnarrow=2+378]
+../fonts/TradArabicTest.ttf;;U+0644,U+0645,U+0020,U+0628,U+0645,U+0627;[fnalef=5+468|f296=3+897|righttoleftspace=2+468|f205=0+903]
diff --git a/test/shape/data/in-house/tests/arabic-mark-attach.tests b/test/shape/data/in-house/tests/arabic-mark-attach.tests
deleted file mode 100644 (file)
index 906fbf6..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/641ca9d7808b01cafa9a666c13811c9b56eb9c52.ttf;;U+064A,U+0633,U+06E1,U+200D,U+0654,U+064E,U+0644;[afii57444.zz04=6+1091|afii57454=1@75,925+0|uni0654=1+0|space=1+0|uni06E1=1@950,1115+0|afii57427.zz03_calt=1+1847|afii57450.zz21=0+345]
diff --git a/test/shape/data/in-house/tests/arabic-phags-pa.tests b/test/shape/data/in-house/tests/arabic-phags-pa.tests
new file mode 100644 (file)
index 0000000..76e0b28
--- /dev/null
@@ -0,0 +1,14 @@
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A873,U+A861;[uniA873=0+563|uniA861=1+463]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A861,U+A873,U+A861;[uniA861=0+463|uniA873=1+563|uniA861=2+463]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A85E,U+A85E,U+A85E,U+0020,U+A85E;[uniA85E.ini=0+761|uniA85E.med=1+536|uniA85E.fin=2+446|space=3+260|uniA85E=4+671]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A85F,U+A85F,U+A85F,U+0020,U+A85F;[uniA85F.ini=0+945|uniA85F.med=1+558|uniA85F.fin=2+502|space=3+260|uniA85F=4+842]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A860,U+A860,U+A860,U+0020,U+A860;[uniA860.ini=0+820|uniA860.med=1+510|uniA860.fin=2+420|space=3+260|uniA860=4+730]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A861,U+A861,U+A861,U+0020,U+A861;[uniA861.ini=0+553|uniA861.med=1+449|uniA861.fin=2+337|space=3+260|uniA861=4+463]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+200D,U+A861,U+200D;[space=0+0|uniA861.med=1+449|space=1+0]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+200D,U+A861;[space=0+0|uniA861.fin=1+337]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A861,U+200D;[uniA861.ini=0+553|space=0+0]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A85E,U+200C,U+A85F,U+200C,U+A860,U+200C,U+A861;[uniA85E=0+671|space=1+0|uniA85F=2+842|space=3+0|uniA860=4+730|space=5+0|uniA861=6+463]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A849,U+A85E;[uniA849.ini=0+798|uniA85E.fin=1+446]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A849,U+A85E,U+FE00;[uniA849.ini=0+798|uniA85E.mir.fin=1+446]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A86A,U+A85E;[uniA86A.ini=0+798|uniA85E.mir.fin=1+446]
+../fonts/ec404b8524cd56efa5d25524cc8541a0b6604b4f.ttf;;U+A86A,U+A85E,U+FE00;[uniA86A.ini.unmir=0+766|uniA85E.fin=1+446]
index 491b242..890d8bf 100644 (file)
@@ -1 +1,3 @@
 ../fonts/d9b8bc10985f24796826c29f7ccba3d0ae11ec02.ttf;--no-glyph-names;U+0718,U+070F,U+0718,U+0718,U+002E;[1=4+168|3=3+502|3=2+502|4=1@-1004,0+0|5=1@-876,0+0|5=1@-799,0+0|5=1@-722,0+0|5=1@-645,0+0|4=1@-566,0+0|5=1@-438,0+0|5=1@-361,0+0|5=1@-284,0+0|5=1@-207,0+0|4=1@-128,0+0|3=0+502]
+../fonts/507637795ce4f2975593da54d12b46f76c7cc4cc.ttf;--direction=l;U+0891,U+0661,U+0662,U+0663,U+0664,U+066B;[piastre-ar.head=0+0|piastre-ar.repeat=0@644,0+0|piastre-ar.repeat=0@778,0+0|piastre-ar.repeat=0@897,0+0|piastre-ar.repeat=0@1016,0+0|piastre-ar.repeat=0@1135,0+0|piastre-ar.repeat=0@1254,0+0|piastre-ar.repeat=0@1373,0+0|piastre-ar.repeat=0@1492,0+0|piastre-ar.tail=0@1611,0+0|one-ar=1+449|two-ar=2+449|three-ar=3+449|four-ar=4+449|decimalseparator-ar=5+222]
+../fonts/507637795ce4f2975593da54d12b46f76c7cc4cc.ttf;--direction=l;U+0661,U+0662,U+0663,U+0891,U+0664,U+066B;[one-ar=0+449|two-ar=1+449|three-ar=2+449|piastre-ar.head=3@-192,0+0|piastre-ar.repeat=3@452,0+0|piastre-ar.tail=3@586,0+0|four-ar=4+449|decimalseparator-ar=5+222]
index 36f5796..5bc393e 100644 (file)
@@ -1,3 +1,7 @@
 ../fonts/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf;;U+0031,U+0032,U+0033,U+2044,U+0034,U+0035,U+0036;[one.numr=0+600|two.numr=1+600|three.numr=2+600|fraction=3+252|four.small=4+600|five.small=5+600|six.small=6+600]
 ../fonts/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf;--direction=l --script=arab;U+0031,U+0032,U+0033,U+2044,U+0034,U+0035,U+0036;[one.numr=0+600|two.numr=1+600|three.numr=2+600|fraction=3+252|four.small=4+600|five.small=5+600|six.small=6+600]
 ../fonts/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf;--direction=l;U+0661,U+0662,U+0663,U+2044,U+0664,U+0665,U+0666;[uni0661.numr=0+600|uni0662.numr=1+600|uni0663.numr=2+600|fraction=3+252|uni0664.small=4+600|uni0665.small=5+600|uni0666.small=6+600]
+../fonts/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf;;U+0031,U+0032,U+0033,U+2044;[one=0+1090|two=1+1090|three=2+1090|fraction=3+252]
+../fonts/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf;--direction=l;U+0661,U+0662,U+0663,U+2044;[uni0661=0+1200|uni0662=1+1200|uni0663=2+1200|fraction=3+252]
+../fonts/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf;;U+2044,U+0034,U+0035,U+0036;[fraction=0+252|four=1+1090|five=2+1090|six=3+1090]
+../fonts/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf;--direction=l;U+2044,U+0664,U+0665,U+0666;[fraction=0+252|uni0664=1+1200|uni0665=2+1200|uni0666=3+1200]
index 50d6d92..defdb2b 100644 (file)
@@ -1,6 +1,6 @@
 ../fonts/DFONT.dfont;--face-index=0 --font-funcs=ot;U+2026,U+0020,U+002E;[ellipsis=0+723|space=1+250|period=2+241]
-../fonts/DFONT.dfont;--face-index=1 --font-funcs=ot;U+2026,U+0020,U+002E;[gid0=0+1000|gid0=1+1000|gid0=2+1000]
-../fonts/DFONT.dfont;--face-index=2 --font-funcs=ot;U+2026,U+0020,U+002E;[gid0=0+1000|gid0=1+1000|gid0=2+1000]
+../fonts/DFONT.dfont;--face-index=1 --font-funcs=ot;U+2026,U+0020,U+002E;[gid0=0+500|gid0=1+500|gid0=2+500]
+../fonts/DFONT.dfont;--face-index=2 --font-funcs=ot;U+2026,U+0020,U+002E;[gid0=0+500|gid0=1+500|gid0=2+500]
 ../fonts/TTC.ttc;--face-index=0 --font-funcs=ot;U+2026,U+0020,U+002E;[ellipsis=0+723|space=1+250|period=2+241]
 ../fonts/TTC.ttc;--face-index=1 --font-funcs=ot;U+2026,U+0020,U+002E;[ellipsis=0+723|space=1+250|period=2+241]
-../fonts/TTC.ttc;--face-index=2 --font-funcs=ot;U+2026,U+0020,U+002E;[gid0=0+1000|gid0=1+1000|gid0=2+1000]
+../fonts/TTC.ttc;--face-index=2 --font-funcs=ot;U+2026,U+0020,U+002E;[gid0=0+500|gid0=1+500|gid0=2+500]
index ad71721..a006736 100644 (file)
@@ -1,3 +1,6 @@
 ../fonts/4cce528e99f600ed9c25a2b69e32eb94a03b4ae8.ttf;;U+1A48,U+1A58,U+1A25,U+1A48,U+1A58,U+1A25,U+1A6E,U+1A63;[uni1A48=0+1212|uni1A25=0+1912|uni1A58=0+0|uni1A48=3+1212|uni1A6E=3+0|uni1A25=3+1912|uni1A58=3+0|uni1A63=3+1212]
 ../fonts/d629e7fedc0b350222d7987345fe61613fa3929a.ttf;;U+0915,U+093F,U+0915,U+093F;[ivowelsign03deva=0+530|kadeva=0+1561|ivowelsign03deva=2+530|kadeva=2+1561]
 ../fonts/f499fbc23865022234775c43503bba2e63978fe1.ttf;;U+09B0,U+09CD,U+09A5,U+09CD,U+09AF,U+09C0;[gid1=0+1320|gid13=0+523|gid18=0+545]
+../fonts/5bbf3712e6f79775c66a4407837a90e591efbef2.ttf;;U+1F1FA,U+1F1FC;[gid3=0+2550]
+../fonts/a59fd13f1525a91cbe529c882e93d9d1fbb80463.ttf;;U+0041,U+0042;[gid4=0+1366|gid4=0+1366|gid4=0+1366|gid4=0+1366|gid5=1+1366]
+../fonts/bef923f4ccb474f961c43b63a9c74b7d9b7a023f.ttf;;U+0061,U+002E,U+002E,U+002E;[a=0+600|SPC=1+600|SPC=2+600|period_period_period.liga=3+600]
diff --git a/test/shape/data/in-house/tests/coretext.tests b/test/shape/data/in-house/tests/coretext.tests
new file mode 100644 (file)
index 0000000..4cecf47
--- /dev/null
@@ -0,0 +1 @@
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;--shaper=coretext;U+0628,U+0628,U+0628;[uni0628.fina=2+883|uni0628.medi_High=1+244|uni0628.init_High=0+233]
index aca4fba..4d77098 100644 (file)
@@ -3,3 +3,14 @@
 #../fonts/706c5d7b625f207bc0d874c67237aad6f1e9cd6f.ttf;;U+0B1F,U+0B4D,U+0B1A,U+0B4D,U+0B1A;[ttaorya=0+1307|casubscriptorya=0@-242,104+-231|casubscriptnarroworya=0@20,104+507]
 ../fonts/07f054357ff8638bac3711b422a1e31180bba863.ttf;--font-funcs=ot --no-glyph-names;U+0606,U+06E1;[2=0@40,502+0|1=0+1000]
 ../fonts/9fc3e6960b3520e5304033ef5fd540285f72f14d.ttf;;U+16F0A,U+16F57,U+16F8F;[u16F0A=0+422|u16F57=0@0,209+338|u16F8F=0+0]
+
+# These are different from what Uniscribe does.
+# https://github.com/harfbuzz/harfbuzz/issues/2469
+../fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf;;U+002E,U+1BC36,U+1BC36,U+1BC36,U+1BC36;[period=0+100|u1BC36=1+313|u1BC36=2+313|u1BC36=3+313|u1BC36=4+313]
+../fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf;--features=ltr1;U+002E,U+1BC36,U+1BC36,U+1BC36,U+1BC36;[period=0+100|u1BC36=1+218|u1BC36=2@-82,-144+136|u1BC36=3@-82,-288+136|u1BC36=4@-82,-432+231]
+../fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf;--features=rtl1;U+002E,U+1BC36,U+1BC36,U+1BC36,U+1BC36;[period=0+100|u1BC36=1@0,432+218|u1BC36=2@-82,288+136|u1BC36=3@-82,144+136|u1BC36=4@-82,0+231]
+../fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf;--features=ltr1,rtl1;U+002E,U+1BC36,U+1BC36,U+1BC36,U+1BC36;[period=0+100|u1BC36=1@0,432+218|u1BC36=2@-82,288+136|u1BC36=3@-82,144+136|u1BC36=4@-82,0+231]
+../fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf;--features=ltr2;U+002E,U+1BC36,U+1BC36,U+1BC36,U+1BC36;[period=0+100|u1BC36=1+218|u1BC36=2@-82,-144+136|u1BC36=3@-82,-288+136|u1BC36=4@-82,-432+231]
+../fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf;--features=ltr1,ltr2;U+002E,U+1BC36,U+1BC36,U+1BC36,U+1BC36;[period=0+100|u1BC36=1+218|u1BC36=2@-82,-144+136|u1BC36=3@-82,-288+136|u1BC36=4@-82,-432+231]
+../fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf;--features=rtl1,ltr2;U+002E,U+1BC36,U+1BC36,U+1BC36,U+1BC36;[period=0+100|u1BC36=1+218|u1BC36=2@-82,-144+136|u1BC36=3@-82,-288+136|u1BC36=4@-82,-432+231]
+../fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf;--features=ltr1,rtl1,ltr2;U+002E,U+1BC36,U+1BC36,U+1BC36,U+1BC36;[period=0+100|u1BC36=1+218|u1BC36=2@-82,-144+136|u1BC36=3@-82,-288+136|u1BC36=4@-82,-432+231]
diff --git a/test/shape/data/in-house/tests/directwrite.tests b/test/shape/data/in-house/tests/directwrite.tests
new file mode 100644 (file)
index 0000000..334f234
--- /dev/null
@@ -0,0 +1 @@
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;--shaper=directwrite;U+0628,U+0628,U+0628;[uni0628.fina=2+883|uni0628.medi_High=1+244|uni0628.init_High=0+233]
index be6a4e1..817ee2a 100644 (file)
@@ -2,6 +2,10 @@
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F636,200D,1F32B,FE0F;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F636,200D,1F32B;[1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F62E,200D,1F4A8;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F642,200D,2194,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F642,200D,2194;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F642,200D,2195,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F642,200D,2195;[1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F635,200D,1F4AB;[1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2639,FE0F;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2620,FE0F;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F596,1F3FD;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F596,1F3FE;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F596,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF2,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF2,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF2,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF2,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF2,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF3,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF3,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF3,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF3,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF3,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF4,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF4,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF4,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF4,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF4,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF7,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF7,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF7,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF7,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF7,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF8,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF8,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF8,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF8,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF8,1F3FF;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44C,1F3FB;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44C,1F3FC;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44C,1F3FD;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91E,1F3FD;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91E,1F3FE;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91E,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF0,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF0,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF0,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF0,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF0,1F3FF;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91F,1F3FB;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91F,1F3FC;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91F,1F3FD;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;261D,1F3FD;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;261D,1F3FE;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;261D,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF5,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF5,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF5,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF5,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF5,1F3FF;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44D,1F3FB;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44D,1F3FC;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44D,1F3FD;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64C,1F3FD;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64C,1F3FE;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64C,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF6,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF6,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF6,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF6,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF6,1F3FF;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F450,1F3FB;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F450,1F3FC;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F450,1F3FD;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F932,1F3FD;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F932,1F3FE;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F932,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91D,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91D,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91D,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91D,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91D,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FB,200D,1FAF2,1F3FC;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FB,200D,1FAF2,1F3FD;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FB,200D,1FAF2,1F3FE;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FB,200D,1FAF2,1F3FF;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FC,200D,1FAF2,1F3FB;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FC,200D,1FAF2,1F3FD;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FC,200D,1FAF2,1F3FE;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FC,200D,1FAF2,1F3FF;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FD,200D,1FAF2,1F3FB;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FD,200D,1FAF2,1F3FC;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FD,200D,1FAF2,1F3FE;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FD,200D,1FAF2,1F3FF;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FE,200D,1FAF2,1F3FB;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FE,200D,1FAF2,1F3FC;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FE,200D,1FAF2,1F3FD;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FE,200D,1FAF2,1F3FF;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FF,200D,1FAF2,1F3FB;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FF,200D,1FAF2,1F3FC;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FF,200D,1FAF2,1F3FD;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAF1,1F3FF,200D,1FAF2,1F3FE;[1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64F,1F3FB;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64F,1F3FC;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64F,1F3FD;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FF,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC5,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC5,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC5,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC5,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC5,1F3FF;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F934,1F3FB;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F934,1F3FC;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F934,1F3FD;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F930,1F3FD;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F930,1F3FE;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F930,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC3,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC3,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC3,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC3,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC3,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC4,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC4,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC4,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC4,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1FAC4,1F3FF;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F931,1F3FB;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F931,1F3FC;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F931,1F3FD;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FF,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,200D,27A1,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,200D,27A1;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FB,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FB,200D,27A1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FC,200D,27A1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FD,200D,27A1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FE,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FE,200D,27A1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FF,200D,27A1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,200D,2640,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,200D,2640,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,200D,2640,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,200D,2640,200D,27A1;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FB,200D,2640,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FB,200D,2640,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FB,200D,2640,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FB,200D,2640,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FC,200D,2640,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FC,200D,2640,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FC,200D,2640,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FC,200D,2640,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FD,200D,2640,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FD,200D,2640,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FD,200D,2640,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FD,200D,2640,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FE,200D,2640,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FE,200D,2640,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FE,200D,2640,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FE,200D,2640,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FF,200D,2640,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FF,200D,2640,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FF,200D,2640,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FF,200D,2640,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,200D,2642,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,200D,2642,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,200D,2642,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,200D,2642,200D,27A1;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FB,200D,2642,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FB,200D,2642,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FB,200D,2642,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FB,200D,2642,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FC,200D,2642,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FC,200D,2642,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FC,200D,2642,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FC,200D,2642,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FD,200D,2642,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FD,200D,2642,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FD,200D,2642,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FD,200D,2642,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FE,200D,2642,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FE,200D,2642,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FE,200D,2642,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FE,200D,2642,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FF,200D,2642,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FF,200D,2642,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FF,200D,2642,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FF,200D,2642,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FB;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FC;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FD;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FF,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,200D,27A1,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,200D,27A1;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FB,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FB,200D,27A1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FC,200D,27A1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FD,200D,27A1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FE,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FE,200D,27A1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FF,200D,27A1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,200D,2640,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,200D,2640,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,200D,2640,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,200D,2640,200D,27A1;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FB,200D,2640,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FB,200D,2640,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FB,200D,2640,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FB,200D,2640,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FC,200D,2640,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FC,200D,2640,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FC,200D,2640,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FC,200D,2640,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FD,200D,2640,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FD,200D,2640,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FD,200D,2640,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FD,200D,2640,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FE,200D,2640,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FE,200D,2640,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FE,200D,2640,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FE,200D,2640,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FF,200D,2640,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FF,200D,2640,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FF,200D,2640,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FF,200D,2640,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,200D,2642,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,200D,2642,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,200D,2642,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,200D,2642,200D,27A1;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FB,200D,2642,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FB,200D,2642,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FB,200D,2642,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FB,200D,2642,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FC,200D,2642,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FC,200D,2642,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FC,200D,2642,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FC,200D,2642,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FD,200D,2642,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FD,200D,2642,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FD,200D,2642,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FD,200D,2642,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FE,200D,2642,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FE,200D,2642,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FE,200D,2642,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FE,200D,2642,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FF,200D,2642,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FF,200D,2642,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FF,200D,2642,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FF,200D,2642,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F9AF;[1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F9AF;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F9AF;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F9AF;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F9AF;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F9AF;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F9AF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F9AF,200D,27A1;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F9AF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F9AF,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F9AF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F9AF,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F9AF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F9AF,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F9AF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F9AF,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F9AF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F9AF,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F9AF;[1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F9AF;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F9AF;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F9AF;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F9AF;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F9AF;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F9AF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F9AF,200D,27A1;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F9AF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F9AF,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F9AF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F9AF,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F9AF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F9AF,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F9AF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F9AF,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F9AF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F9AF,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F9AF;[1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F9AF;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F9AF;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F9AF;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F9AF;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F9AF;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F9AF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F9AF,200D,27A1;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F9AF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F9AF,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F9AF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F9AF,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F9AF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F9AF,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F9AF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F9AF,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F9AF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F9AF,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F9BC;[1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F9BC;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F9BC;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F9BC;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F9BC;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F9BC;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F9BC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F9BC,200D,27A1;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F9BC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F9BC,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F9BC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F9BC,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F9BC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F9BC,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F9BC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F9BC,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F9BC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F9BC,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F9BC;[1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F9BC;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F9BC;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F9BC;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F9BC;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F9BC;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F9BC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F9BC,200D,27A1;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F9BC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F9BC,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F9BC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F9BC,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F9BC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F9BC,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F9BC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F9BC,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F9BC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F9BC,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F9BC;[1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F9BC;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F9BC;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F9BC;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F9BC;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F9BC;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F9BC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F9BC,200D,27A1;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F9BC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F9BC,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F9BC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F9BC,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F9BC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F9BC,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F9BC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F9BC,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F9BC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F9BC,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F9BD;[1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F9BD;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F9BD;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F9BD;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F9BD;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F9BD;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F9BD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F9BD,200D,27A1;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F9BD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F9BD,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F9BD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F9BD,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F9BD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F9BD,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F9BD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F9BD,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F9BD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F9BD,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F9BD;[1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F9BD;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F9BD;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F9BD;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F9BD;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F9BD;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F9BD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F9BD,200D,27A1;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F9BD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F9BD,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F9BD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F9BD,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F9BD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F9BD,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F9BD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F9BD,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F9BD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F9BD,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F9BD;[1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F9BD;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F9BD;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F9BD;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F9BD;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F9BD;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F9BD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F9BD,200D,27A1;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F9BD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F9BD,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F9BD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F9BD,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F9BD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F9BD,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F9BD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F9BD,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F9BD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F9BD,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FB;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FC;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FD;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FF,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,200D,27A1,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,200D,27A1;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FB,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FB,200D,27A1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FC,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FC,200D,27A1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FD,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FD,200D,27A1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FE,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FE,200D,27A1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FF,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FF,200D,27A1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,200D,2640,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,200D,2640,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,200D,2640,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,200D,2640,200D,27A1;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FB,200D,2640,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FB,200D,2640,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FB,200D,2640,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FB,200D,2640,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FC,200D,2640,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FC,200D,2640,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FC,200D,2640,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FC,200D,2640,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FD,200D,2640,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FD,200D,2640,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FD,200D,2640,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FD,200D,2640,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FE,200D,2640,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FE,200D,2640,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FE,200D,2640,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FE,200D,2640,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FF,200D,2640,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FF,200D,2640,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FF,200D,2640,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FF,200D,2640,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,200D,2642,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,200D,2642,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,200D,2642,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,200D,2642,200D,27A1;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FB,200D,2642,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FB,200D,2642,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FB,200D,2642,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FB,200D,2642,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FC,200D,2642,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FC,200D,2642,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FC,200D,2642,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FC,200D,2642,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FD,200D,2642,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FD,200D,2642,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FD,200D,2642,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FD,200D,2642,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FE,200D,2642,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FE,200D,2642,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FE,200D,2642,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FE,200D,2642,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FF,200D,2642,FE0F,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FF,200D,2642,200D,27A1,FE0F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FF,200D,2642,FE0F,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FF,200D,2642,200D,27A1;[1=0|1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F483,1F3FB;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F483,1F3FC;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F483,1F3FD;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F467,200D,1F466;[1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F467,200D,1F467;[1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5E3,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F9D1,200D,1F9D2;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F9D1,200D,1F9D2,200D,1F9D2;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F9D2;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F9D2,200D,1F9D2;[1=0|1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F415,200D,1F9BA;[1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F408,200D,2B1B;[1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F43F,FE0F;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F43B,200D,2744,FE0F;[1=0|1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F43B,200D,2744;[1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F54A,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F426,200D,2B1B;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F426,200D,1F525;[1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F577,FE0F;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F578,FE0F;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3F5,FE0F;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2618,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F34B,200D,1F7E9;[1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F336,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F344,200D,1F7EB;[1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F37D,FE0F;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5FA,FE0F;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3D4,FE0F;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2699,FE0F;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5DC,FE0F;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2696,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26D3,FE0F,200D,1F4A5;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26D3,200D,1F4A5;[1=0|1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26D3,FE0F;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2697,FE0F;[1=0|1=0]
 ../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6CF,FE0F;[1=0|1=0]
diff --git a/test/shape/data/in-house/tests/hebrew-diacritics.tests b/test/shape/data/in-house/tests/hebrew-diacritics.tests
new file mode 100644 (file)
index 0000000..6f6aaf6
--- /dev/null
@@ -0,0 +1,31 @@
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05E7,U+05D5,U+05DC;[lamed=2+901|vav=1+484|kof=0+997]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D3,U+05D5,U+05D3,U+05D9;[yod=3+454|dalet=2+879|vav=1+484|dalet=0+879]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D4,U+05E0,U+05D4,U+05BE,U+05D6,U+05D4;[he=5+1071|zain=4+549|makaf=3+631|he=2+1071|nun=1+614|he=0+1071]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D1,U+05D0;[alef=1+1048|bet=0+967]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05DE,U+05D3,U+05DC,U+05D2;[gimel=3+665|lamed=2+901|dalet=1+879|mem=0+1094]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05E2,U+05DC,U+05BE,U+05D4,U+05D4,U+05E8,U+05D9,U+05DD;[finalmem=7+1004|yod=6+454|resh=5+883|he=4+1071|he=3+1071|makaf=2+631|lamed=1+901|ayin=0+920]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05DE,U+05E7,U+05E4,U+05E5;[finaltsadi=3+990|pe=2+912|kof=1+997|mem=0+1094]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05E2,U+05DC,U+05BE,U+05D4,U+05D2,U+05D1,U+05E2,U+05D5,U+05EA;[tav=8+1026|vav=7+484|ayin=6+920|bet=5+967|gimel=4+665|he=3+1071|makaf=2+631|lamed=1+901|ayin=0+920]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D4,U+05B2,U+05D1,U+05B5,U+05DC;[lamed=4+901|tsere=2@512,0+0|bet=2+967|hatafpatah=0@600,0+0|he=0+1071]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D4,U+05B2,U+05D1,U+05B8,U+05DC,U+05B4,U+05D9,U+05DD;[finalmem=7+1004|yod=6+454|hiriq=4@499,0+0|lamed=4+901|qamats=2@512,0+0|bet=2+967|hatafpatah=0@600,0+0|he=0+1071]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D0,U+05B8,U+05DE,U+05B7,U+05E8;[resh=4+883|patah=2@573,0+0|mem=2+1094|qamats=0@591,0+0|alef=0+1048]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05E7,U+05B9,U+05D4,U+05B6,U+05DC,U+05B6,U+05EA;[tav=6+1026|segol=4@499,0+0|lamed=4+901|segol=2@597,0+0|he=2+1071|holam=0@482,0+0|kof=0+997]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05DC,U+05B0,U+05D4,U+05B7,U+05D2,U+05BC,U+05B4,U+05D9,U+05D3;[dalet=8+879|yod=7+454|hiriq=4@360,0+0|gimeldagesh=4+665|patah=2@597,0+0|he=2+1071|sheva=0@499,0+0|lamed=0+901]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D1,U+05BC,U+05B7,U+05D1,U+05BC,U+05B9,U+05E7,U+05B6,U+05E8;[resh=8+883|segol=6@618,0+0|kof=6+997|holam=3@422,0+0|betdagesh=3+967|patah=0@505,0+0|betdagesh=0+967]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D7,U+05B7,U+05E1,U+05B0,U+05D3,U+05BC,U+05B6,U+05DA,U+05B8;[finalkafqamats=7+846|segol=4@685,0+0|daleddagesh=4+879|sheva=2@581,0+0|samekh=2+1038|patah=0@594,0+0|het=0+1065]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D5,U+05B6,U+05D0,U+05B1,U+05DE,U+05D5,U+05BC,U+05E0,U+05B8,U+05EA,U+05B0,U+05DA,U+05B8;[finalkafqamats=11+846|sheva=9@587,0+0|tav=9+1026|qamats=7@316,0+0|nun=7+614|vavdagesh=5+510|mem=4+1094|hatafsegol=2@591,0+0|alef=2+1048|segol=0@349,0+0|vav=0+484]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D1,U+05BC,U+05B7,U+05DC,U+05BC,U+05B5,U+05D9,U+05DC,U+05D5,U+05B9,U+05EA;[tav=10+1026|vavholam=8+484|lamed=7+901|yod=6+454|tsere=3@430,0+0|lameddagesh=3+901|patah=0@505,0+0|betdagesh=0+967]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D9,U+05B0,U+05E8,U+05D5,U+05BC,U+05E9,U+05C1,U+05B8,U+05DC,U+05B7,U+05B4,U+05DD;[finalmem=11+1004|hiriq=8@-97,0+0|patah=8@499,0+0|lamed=8+901|qamats=5@665,0+0|shinshindot=5+1292|vavdagesh=3+510|resh=2+883|sheva=0@239,0+0|yod=0+454]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D9,U+05B0,U+05E8,U+05D5,U+05BC,U+05E9,U+05C1,U+05B8,U+05DC,U+05B8,U+05B4,U+05DD;[finalmem=11+1004|hiriq=8@-97,0+0|qamats=8@499,0+0|lamed=8+901|qamats=5@665,0+0|shinshindot=5+1292|vavdagesh=3+510|resh=2+883|sheva=0@239,0+0|yod=0+454]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D9,U+05B0,U+05E8,U+05D5,U+05BC,U+05E9,U+05C1,U+05B8,U+05DC,U+05B7,U+05B0,U+05DE,U+05B8,U+05D4;[he=13+1071|qamats=11@573,0+0|mem=11+1094|sheva=8@177,0+0|patah=8@499,0+0|lamed=8+901|qamats=5@665,0+0|shinshindot=5+1292|vavdagesh=3+510|resh=2+883|sheva=0@239,0+0|yod=0+454]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D9,U+05B0,U+05E8,U+05D5,U+05BC,U+05E9,U+05C1,U+05B8,U+05DC,U+05B8,U+05B0,U+05DE,U+05B8,U+05D4;[he=13+1071|qamats=11@573,0+0|mem=11+1094|sheva=8@176,0+0|qamats=8@499,0+0|lamed=8+901|qamats=5@665,0+0|shinshindot=5+1292|vavdagesh=3+510|resh=2+883|sheva=0@239,0+0|yod=0+454]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05E0,U+05B0,U+05D1,U+05BB,U+05BD,U+05DB,U+05B7,U+05D3,U+05B0,U+05E0,U+05B6,U+05D0,U+05E6,U+05BC,U+05B7,U+05A3,U+05E8;[resh=16+883|munah=12@203,0+0|patah=12@588,0+0|tsadidagesh=12+968|alef=11+1048|segol=9@316,0+0|nun=9+614|sheva=7@621,0+0|dalet=7+879|patah=5@469,0+0|kaf=5+942|meteg=2@338,0+0|qubuts=2@673,0+0|bet=2+967|sheva=0@316,0+0|nun=0+614]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05DE,U+05B4,U+05EA,U+05BC,U+05B8,U+0591,U+034F,U+05B7,U+059C,U+05D7,U+05B7,U+05EA;[tav=11+1026|patah=9@594,0+0|het=9+1065|gereshaccent=2+0|patah=2+0|space=2+0|atnah=2@437,0+0|qamats=2@794,0+0|tavdagesh=2+1026|hiriq=0@573,0+0|mem=0+1094]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D0,U+05B2,U+200D,U+05BD,U+05AD,U+05D3,U+05B7,U+05D1,U+05BC,U+05B0,U+05E8,U+05B8,U+05D4;[he=12+1071|qamats=10@719,0+0|resh=10+883|sheva=7@505,0+0|betdagesh=7+967|patah=5@621,0+0|dalet=5+879|dehi=0@1063,0+0|hatafpatah_meteg=0@593,0+0|alef=0+1048]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D5,U+05BD,U+034F,U+05B7,U+05D9,U+05B0,U+05D4,U+05B4,U+05D9,U+05BE,U+05AF,U+05DB,U+05B5,U+05BD,U+05DF;[finalnun=14+459|meteg=11@311,0+0|tsere=11@617,0+0|kaf=11+942|masoracircle=9@320,0+0|makaf=9+631|yod=8+454|hiriq=6@597,0+0|he=6+1071|sheva=4@239,0+0|yod=4+454|patah=0+0|space=0+0|meteg=0@349,0+0|vav=0+484]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05DC,U+05C5,U+05C4,U+05D5,U+05BC,U+05DC,U+05B5,U+05C5,U+0597,U+05C4,U+05D0,U+05C5,U+05C4;[upperdot=10@594,0+0|lowerdot=10@594,0+0|alef=10+1048|upperdot=5@519,0+0|revia=5@601,0+0|lowerdot=5@519,0+0|tsere=5@499,0+0|lamed=5+901|vavdagesh=3+510|upperdot=0@519,0+0|lowerdot=0@519,0+0|lamed=0+901]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D0,U+05B8,U+05E0,U+05BC,U+05B8,U+05BD,U+05D4;[he=6+1071|meteg=2@205,0+0|qamats=2@469,0+0|nundagesh=2+614|qamats=0@591,0+0|alef=0+1048]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D0,U+05B8,U+05E0,U+05B8,U+05BC,U+05BD,U+05D4;[he=6+1071|meteg=2@205,0+0|qamats=2@469,0+0|nundagesh=2+614|qamats=0@591,0+0|alef=0+1048]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05EA,U+05B7,U+05E2,U+05B2,U+05E9,U+05B6,U+05C2,U+05A6,U+05D4;[he=8+1071|merkhakefula=4@353,0+0|segol=4@813,0+0|shinsindot=4+1292|hatafpatah=2@435,0+0|ayin.alt=2+920|patah=0@587,0+0|tav=0+1026]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05E9,U+05B9,U+05BD,U+05C1,U+05D8,U+05B0,U+05E8,U+05B5,U+05D9,U+0599;[pashta=8@161,0+0|yod=8+454|tsere=6@719,0+0|resh=6+883|sheva=4@548,0+0|tet=4+1015|meteg=0@665,0+0|holam=0@362,0+0|shinshindot=0+1292]
+../fonts/b895f8ff06493cc893ec44de380690ca0074edfa.ttf;;U+05D0,U+05B2,U+200D,U+05BD,U+05AD;[dehi=0@1063,0+0|hatafpatah_meteg=0@593,0+0|alef=0+1048]
index 132011f..c06dd35 100644 (file)
@@ -1 +1 @@
-../fonts/932ad5132c2761297c74e9976fe25b08e5ffa10b.ttf;--font-funcs=ot;U+09DC,U+0020,U+09DD,U+0020,U+09A1,U+09BC,U+0020,U+09A2,U+09BC;[bn_rha=0+1024|space=1+1024|bn_yya=2+1024|space=3+1024|bn_dda=4+1024|bn_nukta=4+1024|space=6+1024|bn_ddha=7+1024|bn_nukta=7+1024]
+../fonts/932ad5132c2761297c74e9976fe25b08e5ffa10b.ttf;--font-funcs=ot;U+09DC,U+0020,U+09DD,U+0020,U+09A1,U+09BC,U+0020,U+09A2,U+09BC;[bn_rha=0+512|space=1+512|bn_yya=2+512|space=3+512|bn_dda=4+512|bn_nukta=4+512|space=6+512|bn_ddha=7+512|bn_nukta=7+512]
diff --git a/test/shape/data/in-house/tests/indic-feature-order.tests b/test/shape/data/in-house/tests/indic-feature-order.tests
new file mode 100644 (file)
index 0000000..5d5de98
--- /dev/null
@@ -0,0 +1 @@
+../fonts/190a621e48d4af1fffd8144bd41d2027e9a32fbf.ttf;--features=ss03;U+0B95,U+0BC1;[uni0B95.ss03=0+1000|uni0BC1=0+0]
diff --git a/test/shape/data/in-house/tests/indic-malayalam-dot-reph.tests b/test/shape/data/in-house/tests/indic-malayalam-dot-reph.tests
new file mode 100644 (file)
index 0000000..c09caf1
--- /dev/null
@@ -0,0 +1,15 @@
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D15;[kamlym=0+1038|rephmlym=0@-363,0+0]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D15,U+0D4D,U+0D15,U+0D4D,U+0D30;[rapostmlym=0+200|kakamlym=0+1506|rephmlym=0@-657,0+0]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D28,U+0D4D,U+0D28;[nanamlym=0+1257|rephmlym=0@-507,0+0]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D17,U+0D4D,U+0D17,U+0D4D,U+0D30,U+0D4B;[eevowelsignmlym=0+595|rapostmlym=0+239|gagamlym=0+897|rephmlym=0@-278,0+0|aavowelsignmlym=0+504]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D17,U+0D4D,U+0D30,U+0D4B;[eevowelsignmlym=0+595|rapostmlym=0+239|gamlym=0+897|rephmlym=0@-278,0+0|aavowelsignmlym=0+504]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D17,U+0D4B;[eevowelsignmlym=0+595|gamlym=0+897|rephmlym=0@-278,0+0|aavowelsignmlym=0+504]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D17;[gamlym=0+897|rephmlym=0@-278,0+0]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D17,U+0D4D,U+0D17,U+0D4D,U+0D30,U+0D4B;[eevowelsignmlym=0+595|rapostmlym=0+239|gagamlym=0+897|aavowelsignmlym=0+504]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D17,U+0D4D,U+0D17,U+0D4D,U+0D30;[rapostmlym=0+239|gagamlym=0+897]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D17,U+0D4D,U+0D17,U+0D4B;[eevowelsignmlym=0+595|gagamlym=0+897|aavowelsignmlym=0+504]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D17,U+0D4D,U+0D17;[gagamlym=0+897]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D17,U+0D4D,U+0D30,U+0D4B;[eevowelsignmlym=0+595|rapostmlym=0+239|gamlym=0+897|aavowelsignmlym=0+504]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D15,U+0D41;[kamlym=0+1038|rephmlym=0@-363,0+0|uvowelsignmlym=0+332]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D15,U+0D4D,U+0D15,U+0D41;[kakamlym=0+1506|rephmlym=0@-657,0+0|uvowelsignmlym=0+332]
+../fonts/55e2910dbc9ef5dd89f4e146e7e0152169545b6a.ttf;;U+0D4E,U+0D1A,U+0D4D,U+0D1A,U+0D4D;[cacamlym=0+933|viramamlym=0+0|rephmlym=0@-300,0+0]
index 8610658..d563dec 100644 (file)
@@ -1,3 +1,8 @@
 ../fonts/3cae6bfe5b57c07ba81ddbd54c02fe4f3a1e3bf6.ttf;;U+0CB0,U+0CCD,U+0C95;[gid1=0+1176|gid5=0+1161]
 ../fonts/3cae6bfe5b57c07ba81ddbd54c02fe4f3a1e3bf6.ttf;;U+0CB0,U+200D,U+0CCD,U+0C95;[gid2=0+1334|gid6=0+358]
 ../fonts/3cae6bfe5b57c07ba81ddbd54c02fe4f3a1e3bf6.ttf;;U+0CB0,U+0CCD,U+200D,U+0C95;[gid2=0+1334|gid6=0+358]
+../fonts/e716f6bd00a108d186b7e9f47b4515565f784f36.ttf;;U+0C1A,U+0C3F,U+0C32,U+0C4D,U+0C15,U+0C42,U+0C30,U+0C4D;[civoweltelu=0+766|latelu=2+709|uuvowelsigntelu=2+661|kasubscripttelu=2+483|rahalanttelu=6+593]
+../fonts/9d8c53cb64b8747abdd2b70755cce2ee0eb42ef7.ttf;;U+0915,U+093F,U+094E,U+093C;[uni094E=0+273|uni093C=0+0|ivowelsign03deva=0+259|uni0915=0+762]
+../fonts/9d8c53cb64b8747abdd2b70755cce2ee0eb42ef7.ttf;;U+0915,U+093F,U+093C,U+094E;[uni094E=0+273|ivowelsign00deva=0+259|uni093C=0+0|uni0915=0+762]
+../fonts/5f73fff1ffc07b5a99a90c0909609f2b09fef274.ttf;;U+0A15,U+0A40,U+0A02;[uni0A15=0+505|uni0A40=0+427|uni0A02=0+0]
+../fonts/5f73fff1ffc07b5a99a90c0909609f2b09fef274.ttf;;U+0A15,U+0A02,U+0A40;[uni0A15=0+505|uni0A02=0+0|uni0A40=0+427]
index 275fb13..cc5c882 100644 (file)
@@ -11,3 +11,4 @@
 ../fonts/b3075ca42b27dde7341c2d0ae16703c5b6640df0.ttf;;U+0B2C,U+0B55,U+0B3E;[uni0B2C=0+641|uni0B55=0+0|uni0B3E=0+253]
 ../fonts/b3075ca42b27dde7341c2d0ae16703c5b6640df0.ttf;;U+0B2C,U+0B3E,U+0B55;[uni0B2C=0+641|uni0B3E=0+253|uni0B55=0+0]
 ../fonts/e2b17207c4b7ad78d843e1b0c4d00b09398a1137.ttf;;U+0BAA,U+0BAA,U+0BCD;[pa-tamil=0+778|pa-tamil.001=1+778|pulli-tamil=1@-385,0+0]
+../fonts/41071178fbce4956d151f50967af458dbf555f7b.ttf;;U+0926,U+093F,U+0938,U+0902,U+092C,U+0930;[isigndeva=0+266|dadeva=0+541|sadeva=2+709|anusvaradeva=2@0,-1+0|badeva=4+537|radeva=5+436]
index dff4fc1..4a7a580 100644 (file)
@@ -88,3 +88,5 @@
 ../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+17A0,U+17D2,U+179A,U+17D2,U+179C,U+1784,U+17D2,U+1780;[uni17D2179A=0+287|uni17A0=0+928|uni17D2179C=0@20,-26+0|uni1784=5+635|uni17D21780=5@0,-26+0]
 ../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+17A0,U+17D2,U+179A,U+17D2,U+179C,U+17B6,U+17C6,U+1784;[uni17D2179A=0+287|uni17A017B6=0+1216|uni17D2179C=0@-268,-26+0|uni17C6=0@47,-29+0|uni1784=7+635]
 ../fonts/ad01ab2ea1cb1a4d3a2783e2675112ef11ae6404.ttf;;U+17D2,U+17D2;[uni25CC=0+635|uni17D2=0+0|uni25CC=0+635|uni17D2=0+0]
+../fonts/086d83239e8f958391ff6cdd8fda9376a4bd3673.ttf;;U+17C9;[uni25CC=0+655|uni17C9=0+0]
+../fonts/086d83239e8f958391ff6cdd8fda9376a4bd3673.ttf;;U+17D9,U+17C9;[uni17D9=0+655|uni17C9=0+0]
index 5fd5825..be4d232 100644 (file)
@@ -35,3 +35,4 @@
 ../fonts/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf;;U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0020,U+0995,U+09CD,U+09B0,U+0995,U+09CD,U+09B2;[u0995_u09CD.half_u0995.pres=0+566|u0995_u09CD.half_u0995.pres=3+566|u0995_u09CD.half_u0995.pres=6+566|u0995_u09CD.half_u0995.pres=9+566|u0995_u09CD.half_u0995.pres=12+566|u0995_u09CD.half_u0995.pres=15+566|u0995_u09CD.half_u0995.pres=18+566|u0995_u09CD.half_u0995.pres=21+566|u0995_u09CD.half_u0995.pres=24+566|u0995_u09CD.half_u0995.pres=27+566|u0995_u09CD.half_u0995.pres=30+566|u0995_u09CD.half_u0995.pres=33+566|u0995_u09CD.half_u0995.pres=36+566|u0995_u09CD.half_u0995.pres=39+566|u0995_u09CD.half_u0995.pres=42+566|u0995_u09CD.half_u0995.pres=45+566|u0995_u09CD.half_u0995.pres=48+566|u0995_u09CD.half_u0995.pres=51+566|u0995_u09CD.half_u0995.pres=54+566|u0995_u09CD.half_u0995.pres=57+566|u0995_u09CD.half_u0995.pres=60+566|u0995_u09CD.half_u0995.pres=63+566|u0995_u09CD.half_u0995.pres=66+566|u0995_u09CD.half_u0995.pres=69+566|u0995_u09CD.half_u0995.pres=72+566|u0995_u09CD.half_u0995.pres=75+566|u0995_u09CD.half_u0995.pres=78+566|u0995_u09CD.half_u0995.pres=81+566|u0995_u09CD.half_u0995.pres=84+566|u0995_u09CD.half_u0995.pres=87+566|u0995_u09CD.half_u0995.pres=90+566|u0995_u09CD.half_u0995.pres=93+566|u0995_u09CD.half_u0995.pres=96+566|u0995_u09CD.half_u0995.pres=99+566|u0995_u09CD.half_u0995.pres=102+566|space=105+213|u0995_u09B0_u09CD.blwf.vatu=106+643|u0995_u09CD.half_u09B2.pres=109+602]
 ../fonts/a6c76d1bafde4a0b1026ebcc932d2e5c6fd02442.ttf;;U+1004,U+103A,U+1039,U+101B,U+103D,U+102D;[uni101B103D=0+450|uni1004103A1039102D=0@-50,0+0]
 ../fonts/b31e6c52a31edadc16f1bec9efe6019e2d59824a.ttf;;U+0644,U+064E,U+0644,U+064F,U+0647;[LIG=0+1200|uni064F=0@-216,196+0|uni064E=0@233,46+0|lam_lam_hehar=0+1200]
+../fonts/8339c821814d9bad7c77169332327ad8b0f33c81.ttf;;U+0641,U+0627,U+0020,U+0641,U+0627,U+0020,U+0641,U+0627,U+0020,U+0641,U+0627,U+0020,U+0641,U+0627,U+0020,U+0641,U+0627,U+0020,U+0641,U+0627,U+0020,U+0641,U+0627,U+0020,U+0641,U+0627;[dotabove-ar=24@188,546+0|fehDotless_alef-ar=24+752|space=23+0|dotabove-ar=21@588,546+0|fehDotless_alef-ar=21@400,0+1152|space=20+0|dotabove-ar=18@588,546+0|fehDotless_alef-ar=18@400,0+1152|space=17+0|dotabove-ar=15@588,546+0|fehDotless_alef-ar=15@400,0+1152|space=14+0|dotabove-ar=12@588,546+0|fehDotless_alef-ar=12@400,0+1152|space=11+0|dotabove-ar=9@588,546+0|fehDotless_alef-ar=9@400,0+1152|space=8+0|dotabove-ar=6@588,546+0|fehDotless_alef-ar=6@400,0+1152|space=5+0|dotabove-ar=3@588,546+0|fehDotless_alef-ar=3@400,0+1152|space=2+0|dotabove-ar=0@588,546+0|fehDotless_alef-ar=0@400,0+1152]
index 2bf221a..44e1ce0 100644 (file)
@@ -1,11 +1,24 @@
+# https://github.com/harfbuzz/harfbuzz/issues/4020
+/System/Library/Fonts/LucidaGrande.ttc;--features=-liga[3:5];U+0066,U+0066,U+0020,U+0066,U+0066,U+0066,U+0020,U+0066,U+0066;[ff=0+1443|space=2+648|f=3+753|f=4+753|f=5+753|space=6+648|ff=7+1443]
+
+# https://github.com/harfbuzz/harfbuzz/issues/1373
+/System/Library/Fonts/Supplemental/BigCaslon.ttf;;U+0107;[cacute=0+432]
+/System/Library/Fonts/Supplemental/BigCaslon.ttf;--language=pl;U+0107;[cacute.polish=0+432]
+
 # https://github.com/harfbuzz/harfbuzz/issues/3314
-/System/Library/Fonts/Apple\ Color\ Emoji.ttc;;U+05D0,U+1F1FA,U+1F1F8,U+1F1EE,U+1F1F1;[u1F1EE_u1F1F1=3+800|u1F1FA_u1F1F8=1+800|.notdef=0+800]
+/System/Library/Fonts/Apple\ Color\ Emoji.ttc;--script=hebrew --direction ltr;U+1F1FA,U+1F1F8,U+1F1EE,U+1F1F1;[u1F1FA_u1F1F8=0+800|u1F1EE_u1F1F1=2+800]
+
+# https://github.com/harfbuzz/harfbuzz/issues/3528
+/System/Library/Fonts/Supplemental/Bangla MN.ttc;;U+09AC,U+09BF;[bn_ikaar=0+474|bn_ba=0+998]
 
-# https;//github.com/harfbuzz/harfbuzz/issues/3008
+# https://github.com/harfbuzz/harfbuzz/issues/3535
+/System/Library/Fonts/LucidaGrande.ttc;;U+20DD,U+1F174,U+1F175;[circlecmb=0+0|.notdef=1+1536|.notdef=2+1536]
+
+# https://github.com/harfbuzz/harfbuzz/issues/3008
 /System/Library/Fonts/ヒラギノ丸ゴ\ ProN\ W4.ttc;--features=palt;U+FF11;[gid781=0@-78,0+842]
 
-# https;//github.com/harfbuzz/harfbuzz/pull/2871
-/System/Library/Fonts/LucidaGrande.ttc;--font-funcs ot --show-flags;U+0041,U+0042,U+0043,U+0044;[A=0+1413|B=1+1178|C=2+1417|D=3+1534]
+# https://github.com/harfbuzz/harfbuzz/pull/2871
+/System/Library/Fonts/LucidaGrande.ttc;--font-funcs ot --show-flags;U+0041,U+0042,U+0043,U+0044;[A=0+1413#2|B=1+1178#2|C=2+1417#2|D=3+1534#2]
 
 # 10.12.6 https;//gist.github.com/ebraminio/1704341fa16b06979e605aafd88198cf
 /System/Library/Fonts/Helvetica.dfont@c7bec2785a4c402b7809b5e35337c3d24c18e281;--font-funcs ot;U+006D,U+0300;[m=0+1706|gravecmb=0@-284,10+0]
 /System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0631,U+0628;[u0628.beh=1+1415|u0631.reh=0@-202,0+700]
 /System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0628,U+064F;[u064f.damma=0@250,-250+250|u0628.beh=0@-250,0+1165]
 /System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0644,U+064E,U+0645,U+064E,U+0651,U+0627;[u0627.final.alef=5+647|u064e.fatha=0@-80,160+-80|u064e_u0651.shaddaFatha=0@490,250+490|u0644_u0645.initial.lamMeem=0@-410,0+415]
+/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0644,U+0627;[u0644_u0627.isolated.lamAlef=0+1162]
+/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot --features rlig=0;U+0644,U+0627;[u0627.final.alef=1+647|u0644.initial.lam=0+515]
 # SFNS uses opsz variation axis which isn't invoked here, see https;//crbug.com/1005969#c37
 /System/Library/Fonts/SFNS.ttf@253b4b28662acc1de4a86350fd2b26d620ea213c;--font-funcs ot;U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064;[T=0+920|e=1+1049|space=2+420|A=3+1162|V=4+1292|space=5+420|T=6+960|r=7+631|space=8+420|V=9+1142|a=10+1028|space=11+420|r=12+461|T=13+1190|space=14+420|e=15+779|T=16+1190|space=17+420|T=18+920|d=19+1134]
 /System/Library/Fonts/SFNS.ttf@253b4b28662acc1de4a86350fd2b26d620ea213c;--font-ptem 9 --font-funcs ot;U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064;[T=0@19,0+958|e=1@19,0+1087|space=2@19,0+458|A=3@19,0+1200|V=4@19,0+1330|space=5@19,0+458|T=6@19,0+998|r=7@19,0+669|space=8@19,0+458|V=9@19,0+1180|a=10@19,0+1066|space=11@19,0+458|r=12@19,0+499|T=13@19,0+1228|space=14@19,0+458|e=15@19,0+817|T=16@19,0+1228|space=17@19,0+458|T=18@19,0+958|d=19@19,0+1172]
 
 # 11.1
 /System/Library/Fonts/Apple Color Emoji.ttc@6b0fa4926a1c8a32267e93e18c5eff21558de83a;--font-funcs ot;U+1F469,U+1F3FD,U+200D,U+1F91D,U+200D,U+1F468,U+1F3FE;[u1F469.3.L=0+0|space=0+0|space=0+0|u1F468.4.RA=0+800]
+
+# 12.3
+/System/Library/Fonts/Apple Color Emoji.ttc@8fa6ac4564651899da0b37d310d980db4de967d6;--font-funcs ot;1FAF1,1F3FF,200D,1FAF2,1F3FC;[u1FAF1.5.L=0+800|u1FAF2.2.R=0@-800,0+0]
index 5273863..8ba0be4 100644 (file)
@@ -1 +1,2 @@
 ../fonts/065b01e54f35f0d849fd43bd5b936212739a50cb.ttf;;U+101A,U+1035;[ya_e_above=0+1000]
+../fonts/a232bb734d4c6c898a44506547d19768f0eba6a6.ttf;;U+1000,U+1031,U+1084;[e_shn=0+592|_e=0+618|ka=0+1124]
diff --git a/test/shape/data/in-house/tests/sara-am.tests b/test/shape/data/in-house/tests/sara-am.tests
new file mode 100644 (file)
index 0000000..32d749a
--- /dev/null
@@ -0,0 +1,52 @@
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E31,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E31=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E34,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E34=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E35,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E35=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E36,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E36=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E37,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E37=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E47,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E47=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E48,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E48=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E49,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E49=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4A,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E4A=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4B,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E4B=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4C,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E4C=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4D,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E4D=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4E,U+0E33;[uni0E01=0+500|uni0E4D=0+0|uni0E4E=0+0|uni0E32=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E31,U+0E4D,U+0E32;[uni0E01=0+500|uni0E31=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E34,U+0E4D,U+0E32;[uni0E01=0+500|uni0E34=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E35,U+0E4D,U+0E32;[uni0E01=0+500|uni0E35=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E36,U+0E4D,U+0E32;[uni0E01=0+500|uni0E36=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E37,U+0E4D,U+0E32;[uni0E01=0+500|uni0E37=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E47,U+0E4D,U+0E32;[uni0E01=0+500|uni0E47=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E48,U+0E4D,U+0E32;[uni0E01=0+500|uni0E48=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E49,U+0E4D,U+0E32;[uni0E01=0+500|uni0E49=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4A,U+0E4D,U+0E32;[uni0E01=0+500|uni0E4A=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4B,U+0E4D,U+0E32;[uni0E01=0+500|uni0E4B=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4C,U+0E4D,U+0E32;[uni0E01=0+500|uni0E4C=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4D,U+0E4D,U+0E32;[uni0E01=0+500|uni0E4D=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E01,U+0E4E,U+0E4D,U+0E32;[uni0E01=0+500|uni0E4E=0+0|uni0E4D=0+0|uni0E32=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB1,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0EB1=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB4,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0EB4=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB5,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0EB5=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB5,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0EB5=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB7,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0EB7=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EBB,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0EBB=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EC8,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0EC8=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EC9,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0EC9=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECA,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0ECA=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECB,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0ECB=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECC,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0ECC=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECD,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0ECD=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECE,U+0EB3;[uni0E81=0+500|uni0ECD=0+0|uni0ECE=0+0|uni0EB2=0+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB1,U+0ECD,U+0EB2;[uni0E81=0+500|uni0EB1=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB4,U+0ECD,U+0EB2;[uni0E81=0+500|uni0EB4=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB5,U+0ECD,U+0EB2;[uni0E81=0+500|uni0EB5=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB5,U+0ECD,U+0EB2;[uni0E81=0+500|uni0EB5=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EB7,U+0ECD,U+0EB2;[uni0E81=0+500|uni0EB7=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EBB,U+0ECD,U+0EB2;[uni0E81=0+500|uni0EBB=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EC8,U+0ECD,U+0EB2;[uni0E81=0+500|uni0EC8=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0EC9,U+0ECD,U+0EB2;[uni0E81=0+500|uni0EC9=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECA,U+0ECD,U+0EB2;[uni0E81=0+500|uni0ECA=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECB,U+0ECD,U+0EB2;[uni0E81=0+500|uni0ECB=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECC,U+0ECD,U+0EB2;[uni0E81=0+500|uni0ECC=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECD,U+0ECD,U+0EB2;[uni0E81=0+500|uni0ECD=0+0|uni0ECD=0+0|uni0EB2=3+500]
+../fonts/63a539a90a371ccf028dc2dcced9b63b07163be7.ttf;;U+0E81,U+0ECE,U+0ECD,U+0EB2;[uni0E81=0+500|uni0ECE=0+0|uni0ECD=0+0|uni0EB2=3+500]
index 36cfc0f..a73ab14 100644 (file)
 ../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+202F;[gid1=0+280]
 ../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+205F;[gid1=0+455]
 ../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+3000;[gid1=0+2048]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+0020;[gid1=0@-280,0+0,-2048]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+00A0;[gid1=0@-280,0+0,-2048]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+1680;[gid0=0@-346,0+0,-2048]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2000;[gid1=0@-280,0+0,-1024]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2001;[gid1=0@-280,0+0,-2048]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2002;[gid1=0@-280,0+0,-1024]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2003;[gid1=0@-280,0+0,-2048]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2004;[gid1=0@-280,0+0,-683]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2005;[gid1=0@-280,0+0,-512]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2006;[gid1=0@-280,0+0,-341]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2007;[gid1=0@-280,0+0,-2048]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2008;[gid1=0@-280,0+0,-2048]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2009;[gid1=0@-280,0+0,-410]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+200A;[gid1=0@-280,0+0,-128]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+202F;[gid1=0@-280,0+0,-1024]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+205F;[gid1=0@-280,0+0,-455]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+3000;[gid1=0@-280,0+0,-2048]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+0020;[gid1=0@-280,-1263+0,-2526]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+00A0;[gid1=0@-280,-1263+0,-2526]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+1680;[gid0=0@-346,-1263+0,-2526]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2000;[gid1=0@-280,-1263+0,-1024]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2001;[gid1=0@-280,-1263+0,-2048]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2002;[gid1=0@-280,-1263+0,-1024]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2003;[gid1=0@-280,-1263+0,-2048]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2004;[gid1=0@-280,-1263+0,-683]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2005;[gid1=0@-280,-1263+0,-512]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2006;[gid1=0@-280,-1263+0,-341]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2007;[gid1=0@-280,-1263+0,-2526]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2008;[gid1=0@-280,-1263+0,-2526]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+2009;[gid1=0@-280,-1263+0,-410]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+200A;[gid1=0@-280,-1263+0,-128]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+202F;[gid1=0@-280,-1263+0,-1263]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+205F;[gid1=0@-280,-1263+0,-455]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot --direction=ttb;U+3000;[gid1=0@-280,-1263+0,-2048]
diff --git a/test/shape/data/in-house/tests/uniscribe.tests b/test/shape/data/in-house/tests/uniscribe.tests
new file mode 100644 (file)
index 0000000..9b563db
--- /dev/null
@@ -0,0 +1 @@
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;--shaper=uniscribe;U+0628,U+0628,U+0628;[uni0628.fina=2+883|uni0628.medi_High=1+244|uni0628.init_High=0+233]
index 24906fa..64381a3 100644 (file)
@@ -1 +1 @@
-../fonts/34da9aab7bee86c4dfc3b85e423435822fdf4b62.ttf;--show-flags;U+0628,U+200C,U+0628;[uni0628=1+993#2|uni0628=0+993#2]
+../fonts/34da9aab7bee86c4dfc3b85e423435822fdf4b62.ttf;--show-flags --unsafe-to-concat;U+0628,U+200C,U+0628;[uni0628=1+993#2|uni0628=0+993#2]
diff --git a/test/shape/data/in-house/tests/use-javanese.tests b/test/shape/data/in-house/tests/use-javanese.tests
new file mode 100644 (file)
index 0000000..bfebc73
--- /dev/null
@@ -0,0 +1,54 @@
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A5,U+A9BA;[taling=0+677|pa=0+963]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A99F,U+A9C0,U+A9A2,U+A9BF;[da.pas_cakra=0+238|nna=0+1198]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A5,U+A9BA,U+A9B4,U+A982,U+A9A0,U+A9B8,U+A992,U+A9AD,U+A9C0;[taling=0+677|pa=0+963|layar.ns=0@-267,10+0|tarung=0+413|ta=4+1183|u.ns=4@-1,0+0|ga=6+938|la=7+1194|pangkon=7+391]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9CB;[uniA9CB=0+439]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+200B,U+A9C5;[space=0+0|uniA9C5=1+1981]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9D1,U+A9D0,U+A9C7;[oneJV=0+938|zeroJV=1+605|uniA9C7=2+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9D2,U+A9D0,U+A9D0,U+A9D4;[twoJV=0+977|zeroJV=1+605|zeroJV=2+605|fourJV=3+590]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9D1,U+A9D8,U+A9D8,U+A9D5,U+A9C7;[oneJV=0+938|eightJV=1+1027|eightJV=2+1027|fiveJV=3+741|uniA9C7=4+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A5,U+A9A4,U+A9B6,U+A9A0,U+A9BF,U+A9C7;[pa=0+963|na=1+989|i.ns=1@-71,10+0|ta_cakra=3+1416|uniA9C7=5+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A98F,U+A9A0,U+A9BF,U+A981,U+A994,U+A9A4,U+A9C0;[ka=0+1221|ta_cakra=1+1416|cecak.ns=1@-306,10+0|nga=4+976|na=5+989|pangkon=5+391]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9C5,U+A9C9,U+A99F,U+A9C0,U+A9A2,U+A9BF,U+A9C9,U+A9C5;[uniA9C5=0+1981|uniA9C9=1+687|da.pas_cakra=2+238|nna=2+1198|uniA9C9=6+687|uniA9C5=7+1981]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A5,U+A9BA,U+A994,U+A9BC,U+A9A0,U+A9C0,U+A9A0,U+A9A4,U+A9C0;[taling=0+677|pa=0+963|nga=2+976|ae.ns=2@-63,10+0|ta=4+1183|ta.pas=4@-1,0+0|na=7+989|pangkon=7+391]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A984,U+A992,U+A9B8,U+A9B1,U+A9C0,U+A9A0,U+A9B8,U+A9B1,U+A9C0,U+A9C7;[akara=0+1338|ga=1+1221|u.ns=1@-283,0+0|sa=3+1088|ta.pas.alt=3+0|u.ns.pas=3+0|sa=7+1088|pangkon=7+391|uniA9C7=9+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9AE,U+A9B8,U+A9AD,U+A9A4,U+A9C0,U+A997,U+A9A4,U+A9B8,U+A9AE,U+A9AB,U+A9B6;[wa=0+967|u.ns=0@-1,0+0|la=2+1194|na=3+989|ja.pas=3@200,0+0|na=6+989|u.ns=6+0|wa=8+967|ra=9+915|i.ns=9@-62,10+0]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A0,U+A9B8,U+A9AE,U+A9A4,U+A9C0,U+200B,U+A9AF,U+A9B6,U+A98F,U+A9BA,U+A995,U+A9B6;[ta=0+1183|u.ns=0@-1,0+0|wa=2+967|na=3+989|pangkon=3+391|space=5+0|sha=6+938|i.ns=6@8,10+0|taling=8+677|ka=8+1221|ca=10+1043|i.ns=10@-1,10+0]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B2,U+A9B6,U+A981,U+200B,U+A9B1,U+A9B8,U+A982,U+A9AA,U+200B,U+A98F,U+A9A5,U+A9B6,U+A981,U+A9C7;[ha=0+1195|i.ns_cecak.ns=0@-182,10+0|space=3+0|sa=4+1088|u.ns=4+0|layar.ns=4@-208,10+0|ya=7+1383|space=8+0|ka=9+1221|pa=10+963|i.ns_cecak.ns=10@-170,10+0|uniA9C7=13+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9AF,U+A9BA,U+A99F,U+A9A6,U+A9A1,U+A9B6,U+200B,U+A9B2,U+A9B6,U+A981,U+200B,U+A994,U+A9AD,U+A993,U+A9C8;[taling=0+677|sha=0+938|nna=2+1198|pha=3+1027|tha=4+967|i.ns=4@-61,10+0|space=6+0|ha=7+1195|i.ns_cecak.ns=7@-182,10+0|space=10+0|nga=11+976|la=12+1194|gha=13+1258|uniA9C8=14+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B2,U+A9B8,U+A9A0,U+A9AE,U+A9B6,U+200B,U+A9AF,U+A9B8,U+A982,U+A9AA,U+200B,U+A98F,U+A9A5,U+A9B6,U+A981,U+A9C7;[ha=0+1195|u.ns=0@-1,0+0|ta=2+1183|wa=3+967|i.ns=3@-61,10+0|space=5+0|sha=6+938|u.ns=6+0|layar.ns=6@-200,10+0|ya=9+1383|space=10+0|ka=11+1221|pa=12+963|i.ns_cecak.ns=12@-170,10+0|uniA9C7=15+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A5,U+A9A9,U+A9BC,U+A981,U+A98F,U+A9B8,U+A9A4,U+A9B6,U+A9AB,U+A9BA,U+A981,U+200B,U+A9A8,U+A9B8,U+A9AE,U+A9A4,U+A9C8;[pa=0+963|ma=1+970|ae.ns_cecak.ns=1@-62,10+0|ka=4+1221|u.ns=4@-1,0+0|na=6+989|i.ns=6@-71,10+0|taling=8+677|ra=8+915|cecak.ns=8@-321,10+0|space=11+0|bha=12+879|u.ns=12@-37,0+0|wa=14+967|na=15+989|uniA9C8=16+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A9,U+A981,U+A98F,U+A9BE,U+200B,U+A9B2,U+A9B6,U+A981,U+200B,U+A994,U+A9AA,U+A9B8,U+A993,U+A9BE,U+A98F,U+A982,U+A9A1,U+A9C8;[ma=0+970|cecak.ns=0@-321,10+0|ka=2+1221|pengkal=2+376|space=4+0|ha=5+1195|i.ns_cecak.ns=5@-182,10+0|space=8+0|nga=9+976|ya=10+1383|u.ns=10@-1,0+0|gha=12+1258|pengkal=12+376|ka=14+1221|layar.ns=14@-250,10+0|tha=16+967|uniA9C8=17+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A0,U+A9A4,U+A9C0,U+A9A7,U+A981,U+A98F,U+A9B6,U+A9A0,U+A9C0,U+A9B2,U+A994,U+A9B8,U+A995,U+A9A5,U+A9C0,U+A9A5,U+A9BC,U+A9A4,U+A9C8;[ta=0+1183|na=1+989|ba.pas=1+0|cecak.ns=1@-330,10+0|ka=5+1221|i.ns=5@-42,10+0|ta=7+1183|ha.pas=7+1090|nga=10+976|u.ns=10+0|ca=12+1043|pa=13+963|pa.pas=13+830|ae.ns=13@52,10+0|na=17+989|uniA9C8=18+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A0,U+A9B8,U+A9AE,U+A9A4,U+A9C0,U+200B,U+A988,U+A9A4,U+A9C0,U+200B,U+A995,U+A9B8,U+A9A4,U+A9C0,U+200B,U+A9B2,U+A9BA,U+A9B4,U+A98F,U+A9C0;[ta=0+1183|u.ns=0@-1,0+0|wa=2+967|na=3+989|pangkon=3+391|space=5+0|ukara=6+976|na=7+989|pangkon=7+391|space=9+0|ca=10+1043|u.ns=10+0|na=12+989|pangkon=12+391|space=14+0|taling=15+677|ha=15+1195|tarung=15+413|ka=18+1221|pangkon=18+391]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B2,U+A9A2,U+A9B6,U+A9A4,U+A9B6,U+A981,U+A994,U+A9BF,U+A9A0,U+A9C0,U+A98F,U+A9BF,U+A9A1,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A9B2,U+A997,U+A9B6,U+A9C8;[ha=0+1195|da=1+1063|i.ns=1@-11,10+0|na=3+989|i.ns_cecak.ns=3@-182,10+0|nga_cakra=6+1221|ka.pas_cakra=8+253|ta=8+1183|taling=12+677|tha=12+967|tarung=12+413|na=15+989|ha.pas=15+1090|ja=18+991|i.ns=18@-24,10+0|uniA9C8=20+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A5,U+A994,U+A9BF,U+A9BA,U+A983,U+A9B2,U+A9B6,U+A981,U+A9A9,U+A9B1,U+A9C0,U+A997,U+A9B6,U+A9A2,U+A9C0,U+A9B1,U+A9AD,U+A9B6,U+A98F,U+A9B6,U+A9A4,U+A9C0;[pa=0+963|taling=1+677|nga_cakra=1+1221|wignyan=1+353|ha=5+1195|i.ns_cecak.ns=5@-182,10+0|ma=8+970|sa=9+1088|ja.pas=9@200,0+0|i.ns=9@0,10+0|da=13+1063|sa.pas=13+830|la=16+1194|i.ns=16@-70,10+0|ka=18+1221|i.ns=18@-42,10+0|na=20+989|pangkon=20+391]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A0,U+A9BC,U+A9A4,U+A9C0,U+A9A0,U+A9BD,U+A9A9,U+A9C0,U+A9A5,U+A9BF,U+A9A2,U+A9B1,U+A9B6,U+A983,U+200B,U+A992,U+A9BC,U+A981,U+A9B2,U+A9AD,U+A9B6,U+A9A0,U+A9C0;[ta=0+1183|ae.ns=0@-44,10+0|na=2+989|ta.pas.alt=2+0|keret.ns.alt=2+0|ma=6+970|pa.pas_cakra=6+1074|da=10+1063|sa=11+1088|i.ns=11@0,10+0|wignyan=11+353|space=14+0|ga=15+938|ae.ns_cecak.ns=15@9,10+0|ha=18+1195|la=19+1194|i.ns=19@-70,10+0|ta=21+1183|pangkon=21+391]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B2,U+A9B6,U+A981,U+A98F,U+A981,U+200B,U+A9B2,U+A981,U+A992,U+A9AB,U+A9A5,U+A9C0,U+200B,U+A9AB,U+A9A2,U+A9BA,U+A9A4,U+A9C0,U+200B,U+A9AF,U+A9B8,U+A9B0,U+A9BA,U+A997;[ha=0+1195|i.ns_cecak.ns=0@-182,10+0|ka=3+1221|cecak.ns=3@-301,10+0|space=5+0|ha=6+1195|cecak.ns=6@-330,10+0|ga=8+938|ra=9+915|pa=10+963|pangkon=10+391|space=12+0|ra=13+915|taling=14+677|da=14+1063|na=16+989|pangkon=16+391|space=18+0|sha=19+938|u.ns=19+0|taling=21+677|ssa=21+1012|ja=23+991]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9AB,U+A9A2,U+A9BA,U+A9A4,U+A9C0,U+A9B2,U+A997,U+A9B6,U+A9A9,U+A9B3,U+A9B8,U+A983,U+A98F,U+A9B3,U+A9A9,U+A9B3,U+A9A2,U+A9C0,U+200C,U+A994,U+A9A2,U+A9C0,U+A9A4,U+A9A4,U+A9C0;[ra=0+915|taling=1+677|da=1+1063|na=3+989|ha.pas=3+1090|ja=6+991|i.ns=6@-24,10+0|ma=8+970|cecaktelu.ns=8@-126,10+0|u.ns=8@-1,0+0|wignyan=8+353|ka=12+1221|cecaktelu.ns=12@-252,10+0|ma=14+970|cecaktelu.ns=14@-126,10+0|da=16+1063|pangkon=16+391|space=18+0|nga=19+976|da=20+1063|na.pas=20@-1,0+0|na=23+989|pangkon=23+391]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9AE,U+A9B8,U+A9AD,U+A9A4,U+A9C0,U+A997,U+A9B8,U+A9A9,U+A9A2,U+A9B6,U+A9AD,U+A9AE,U+A9AD,U+A9C0,U+A9A0,U+A9B2,U+A9B8,U+A9A4,U+A9C0,U+A997,U+A9B6,U+A9A9,U+A9C0,U+A9A9,U+A9AE,U+A9AD,U+A9C0;[wa=0+967|u.ns=0@-1,0+0|la=2+1194|na=3+989|ja.pas.alt=3+0|u.ns.pas=3+0|ma=7+970|da=8+1063|i.ns=8@-11,10+0|la=10+1194|wa=11+967|la=12+1194|ta.pas=12+0|ha=15+1317|u.ns=15@-123,0+0|na=17+989|ja.pas=17@200,0+0|i.ns=17@-71,10+0|ma=21+970|ma.pas=21@-1,0+0|wa=24+967|la=25+1194|pangkon=25+391]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A991,U+A9AD,U+A9B6,U+A9A6,U+A9A1,U+A9B8,U+A9AD,U+A9C0,U+A9AD,U+A983,U+200B,U+A9B2,U+A9B6,U+A981,U+A98F,U+A981,U+200B,U+A997,U+A9B8,U+A9A9,U+A9BC,U+A9A4,U+A9BC,U+A981,U+200B,U+A98F,U+A9A5,U+A9B6,U+A981;[kha=0+1289|la=1+1194|i.ns=1@-70,10+0|pha=3+1027|tha=4+967|u.ns=4@-1,0+0|la=6+1194|la.pas=6@-278,0+0|wignyan=6+353|space=10+0|ha=11+1195|i.ns_cecak.ns=11@-182,10+0|ka=14+1221|cecak.ns=14@-301,10+0|space=16+0|ja=17+991|u.ns=17@-4,0+0|ma=19+970|ae.ns=19@-59,10+0|na=21+989|ae.ns_cecak.ns=21@-71,10+0|space=24+0|ka=25+1221|pa=26+963|i.ns_cecak.ns=26@-170,10+0]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A0,U+A9A4,U+A9C0,U+A99D,U+A9B6,U+A981,U+A994,U+A9A4,U+A9C0,U+A9A4,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+A9B1,U+A9AE,U+A9B8,U+A981,U+200B,U+A9A7,U+A9AD,U+A9C0,U+A9A7,U+A9AD,U+A9C0,U+A9AD,U+A9A4,U+A9C0,U+A9C8;[ta=0+1183|na=1+989|dda.pas=1+0|i.ns_cecak.ns=1@-182,10+0|nga=6+976|na=7+989|na.pas=7+0|i.ns=7@-71,10+0|pa=11+963|u.ns=11+0|na=13+989|sa.pas=13+830|wa=16+967|u.ns=16@-1,0+0|cecak.ns=16@-320,10+0|space=19+0|ba=20+1207|la=21+1194|ba.pas=21+0|la=24+1194|la.pas=24@-278,0+0|na=27+989|pangkon=27+391|uniA9C8=29+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A9,U+A9B6,U+A9A4,U+A9BA,U+A9B4,U+A981,U+A98F,U+200B,U+A9A5,U+A9BA,U+A994,U+A9BC,U+A9A0,U+A9C0,U+A9A0,U+A9A4,U+A9C0,U+A997,U+A9B8,U+A9A9,U+A9BC,U+A9A4,U+A9BC,U+A981,U+200B,U+A9A2,U+A98A,U+A9A9,U+A9C0,U+A99F,U+A9A1,U+A9C8;[ma=0+970|i.ns=0@-62,10+0|taling=2+677|na=2+989|cecak.ns=2@-330,10+0|tarung=2+413|ka=6+1221|space=7+0|taling=8+677|pa=8+963|nga=10+976|ae.ns=10@-63,10+0|ta=12+1344|ta.pas=12@-162,0+0|na=15+989|ja.pas.alt=15+0|u.ns.pas=15+0|ma=19+970|ae.ns=19@-59,10+0|na=21+989|ae.ns_cecak.ns=21@-71,10+0|space=24+0|da=25+1063|ngalelet=26+1294|ma=27+970|nna.pas=27@-1,0+0|tha=30+967|uniA9C8=31+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A98F,U+A991,U+A992,U+A993,U+A994,U+A995,U+A996,U+A997,U+A999,U+A99A,U+A99B,U+A99C,U+A99D,U+A99E,U+A99F,U+A9A0,U+A9A1,U+A9A2,U+A9A3,U+A9A4,U+A9A5,U+A9A6,U+A9A7,U+A9A8,U+A9A9,U+A9AA,U+A9AB,U+A9AD,U+A9AE,U+A9AF,U+A9B0,U+A9B1,U+A9B2;[ka=0+1221|kha=1+1289|ga=2+938|gha=3+1258|nga=4+976|ca=5+1043|cha=6+1479|ja=7+991|jha=8+1159|nya=9+1439|tta=10+976|ttha=11+976|dda=12+1071|ddha=13+841|nna=14+1198|ta=15+1183|tha=16+967|da=17+1063|dha=18+1027|na=19+989|pa=20+963|pha=21+1027|ba=22+1207|bha=23+879|ma=24+970|ya=25+1383|ra=26+915|la=27+1194|wa=28+967|sha=29+938|ssa=30+1012|sa=31+1088|ha=32+1195]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A2,U+A9BA,U+A9A4,U+A9C0,U+A9A4,U+A9B6,U+A981,U+200B,U+A9AB,U+A9A2,U+A9BA,U+A9A4,U+A9C0,U+A994,U+A9A4,U+A9C0,U+A9A0,U+A9BA,U+A9A4,U+A9C0,U+A9A1,U+A9B8,U+A9A9,U+A9BC,U+A981,U+A992,U+A9B8,U+A981,U+200B,U+A9A6,U+A9BF,U+A9AE,U+A9B6,U+A9AB,U+A9A2,U+A9B6,U+A982,U+A997,U+A9C9;[taling=0+677|da=0+1063|na=2+989|na.pas=2+0|i.ns_cecak.ns=2@-182,10+0|space=7+0|ra=8+915|taling=9+677|da=9+1063|na=11+989|nga.pas=11+0|taling=14+677|na=14+989|ta.pas=14+0|na=18+989|tha.pas.alt=18+0|u.ns.pas=18@225,0+0|ma=22+970|ae.ns_cecak.ns=22@-62,10+0|ga=25+1060|u.ns=25@-122,0+0|cecak.ns=25@-372,10+0|space=28+0|pha_cakra=29+1318|wa=31+967|i.ns=31@-61,10+0|ra=33+915|da=34+1063|i.ns_layar.ns=34@-122,10+0|ja=37+991|uniA9C9=38+687]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B2,U+A9B6,U+A981,U+A9A9,U+A9A1,U+A9AB,U+A9A9,U+A9C0,U+A9A2,U+A9B8,U+A98F,U+A9C0,U+A9AB,U+A9B8,U+A9A9,U+A9B8,U+A9B2,U+A9B8,U+A9A4,U+A9C0,U+200B,U+A9A0,U+A9BC,U+A98A,U+A981,U+A994,U+A9B6,U+A981,U+200B,U+A98F,U+A9AB,U+A9A1,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A997,U+A9AE,U+A9B6,U+A9C8;[ha=0+1195|i.ns_cecak.ns=0@-182,10+0|ma=3+970|tha=4+967|ra=5+915|ma=6+970|da.pas_u.ns=6@-1,0+0|ka=10+1221|ra.pas=10@-1,0+0|u.ns.pas=10@-1,0+0|ma=14+970|u.ns=14@-1,0+0|ha=16+1195|u.ns=16@-1,0+0|na=18+989|pangkon=18+391|space=20+0|ta=21+1183|ae.ns=21@-44,10+0|ngalelet=23+977|cecak.ns=23@-324,10+0|nga=25+976|i.ns_cecak.ns=25@-177,10+0|space=28+0|ka=29+1221|ra=30+915|taling=31+677|tha=31+967|tarung=31+413|na=34+989|ja.pas=34@200,0+0|wa=37+967|i.ns=37@-61,10+0|uniA9C8=39+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9AE,U+A9BC,U+A99D,U+A9B6,U+200B,U+A992,U+A9A9,U+A9C0,U+A9A5,U+A9B6,U+A981,U+200B,U+A98F,U+A997,U+A9BC,U+A981,U+200B,U+A9AD,U+A9A4,U+A9C0,U+A9B1,U+A9A4,U+A9C0,U+A9A4,U+A9BA,U+A9B1,U+A9C0,U+A9B1,U+A9A4,U+A9C0,U+A9A4,U+A9BA,U+A9B1,U+A9C0,U+A9B1,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+200B;[wa=0+967|ae.ns=0@-58,10+0|dda=2+1071|i.ns=2@9,10+0|space=4+0|ga=5+938|ma=6+970|pa.pas=6+830|i.ns_cecak.ns=6@-62,10+0|space=11+0|ka=12+1221|ja=13+991|ae.ns_cecak.ns=13@-24,10+0|space=16+0|la=17+1194|na=18+989|sa.pas=18+830|taling=21+677|na=21+989|na.pas=21+0|sa=25+1088|sa.pas=25+830|taling=28+677|na=28+989|na.pas=28+0|sa=32+1088|sa.pas=32+830|i.ns=32@49,10+0|pa=36+963|u.ns=36+0|na=38+989|pangkon=38+391|space=40+0]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A9,U+A9BA,U+A9B4,U+A981,U+A98F,U+200B,U+A9B1,U+A9AB,U+A9AE,U+A9BA,U+A9A2,U+A9B6,U+A9A4,U+A9B6,U+A981,U+A9AB,U+A9A0,U+A9C0,U+200B,U+A9A2,U+A9BA,U+A9AB,U+A9A4,U+A9BF,U+A9B8,U+A9B1,U+A9C0,U+A98F,U+A9BC,U+A9A4,U+A9C0,U+A9B2,U+A9B8,U+A997,U+A9C0,U+A9AE,U+A9AD,U+A9A4,U+A9C0,U+A9A4,U+A9B6,U+A981,U+A9C8;[taling=0+677|ma=0+970|cecak.ns=0@-321,10+0|tarung=0+413|ka=4+1221|space=5+0|sa=6+1088|ra=7+915|taling=8+677|wa=8+967|da=10+1063|i.ns=10@-11,10+0|na=12+989|i.ns_cecak.ns=12@-182,10+0|ra=15+915|ta=16+1183|pangkon=16+391|space=18+0|taling=19+677|da=19+1063|ra=21+915|na_cakra_u.ns=22+1343|sa=25+1088|ka.pas=25+0|ae.ns=25@3,10+0|na=29+989|ha.pas=29+1090|u.ns=29+0|ja_wa.pas=33+987|la=36+1194|na=37+989|na.pas=37+0|i.ns_cecak.ns=37@-182,10+0|uniA9C8=42+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A9,U+A9B6,U+A9A4,U+A9BA,U+A9B4,U+A981,U+A98F,U+200B,U+A9AE,U+A98F,U+A9B6,U+A9AD,U+A9C0,U+A9AA,U+A9AA,U+A9B1,U+A9A4,U+A9C0,U+A98F,U+A9AD,U+A9C0,U+A9AD,U+A9BA,U+A9B4,U+A9B2,U+A9B8,U+A9B1,U+A9C0,U+A9A0,U+A9BC,U+200B,U+A992,U+A9B8,U+A9AD,U+A9C0,U+A9A7,U+A9BA,U+A9A4,U+A98F,U+A9B6,U+A9B2,U+A9A4,U+A9C0,U+A9C7;[ma=0+970|i.ns=0@-62,10+0|taling=2+677|na=2+989|cecak.ns=2@-330,10+0|tarung=2+413|ka=6+1221|space=7+0|wa=8+967|ka=9+1221|i.ns=9@-42,10+0|la=11+1194|ya.pas=11+0|ya=14+1383|sa=15+1088|na=16+989|ka.pas=16+0|taling=19+677|la=19+1194|la.pas=19@-278,0+0|tarung=19+413|ha=24+1195|u.ns=24@-1,0+0|sa=26+1088|ta.pas=26+0|ae.ns=26@3,10+0|space=30+0|ga=31+938|u.ns=31+0|taling=33+677|la=33+1194|ba.pas=33+0|na=37+989|ka=38+1221|i.ns=38@-42,10+0|ha=40+1195|na=41+989|pangkon=41+391|uniA9C7=43+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A5,U+A9B6,U+A9A4,U+A9BD,U+A9A4,U+A983,U+A98F,U+A9BC,U+A9A4,U+A9C0,U+A9A9,U+A981,U+A992,U+A9BA,U+A9A4,U+A9C0,U+A9A4,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+200B,U+A9B2,U+A9B6,U+A981,U+200B,U+A9A5,U+A9A5,U+A9A4,U+A9C0,U+A9B2,U+A9B6,U+A981,U+A98F,U+A981,U+200B,U+A9A5,U+A98F,U+A9BA,U+A9B4,U+A9AD,U+A9B6,U+A983,U+A9C8;[pa=0+963|i.ns=0@-59,10+0|na=2+989|keret.ns=2+0|na=4+989|wignyan=4+353|ka=6+1221|ae.ns=6@-39,10+0|na=8+989|ma.pas=8+0|cecak.ns=8@-330,10+0|taling=12+677|ga=12+938|na=14+989|na.pas=14+0|i.ns=14@-71,10+0|pa=18+963|u.ns=18+0|na=20+989|pangkon=20+391|space=22+0|ha=23+1195|i.ns_cecak.ns=23@-182,10+0|space=26+0|pa=27+963|pa=28+963|na=29+989|ha.pas=29+1090|i.ns_cecak.ns=29@-71,10+0|ka=34+1221|cecak.ns=34@-301,10+0|space=36+0|pa=37+963|taling=38+677|ka=38+1221|tarung=38+413|la=41+1194|i.ns=41@-70,10+0|wignyan=41+353|uniA9C8=44+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A0,U+A9B8,U+A9A9,U+A9B8,U+A997,U+A9C0,U+A9AE,U+A9BA,U+A981,U+200B,U+A98A,U+A989,U+A9B1,U+A9C0,U+A9A4,U+A9BC,U+A982,U+A9AB,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+200B,U+A9B1,U+A9B8,U+A9B1,U+A9A0,U+A9BE,U+200B,U+A9A0,U+A9BC,U+A9A9,U+A9BC,U+A9A4,U+A9C0,U+A9A4,U+A9B8,U+A9B2,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A9A4,U+A9B6,U+A9C8;[ta=0+1183|u.ns=0@-1,0+0|ma=2+970|u.ns=2@-1,0+0|taling=4+677|ja_wa.pas=4+987|cecak.ns=4@-230,10+0|space=9+0|ngalelet=10+977|pacerek=11+963|sa=12+1088|na.pas=12+0|ae.ns_layar.ns=12@-59,10+0|ra=17+915|i.ns=17@-62,10+0|pa=19+963|u.ns=19+0|na=21+989|pangkon=21+391|space=23+0|sa=24+1088|u.ns=24+0|sa=26+1088|ta=27+1183|pengkal=27+376|space=29+0|ta=30+1183|ae.ns=30@-44,10+0|ma=32+970|ae.ns=32@-59,10+0|na=34+989|na.pas.alt=34+0|u.ns.pas=34@166,0+0|taling=38+677|ha=38+1195|tarung=38+413|na=41+989|na.pas=41+0|i.ns=41@-71,10+0|uniA9C8=45+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B2,U+A9B6,U+A981,U+A98F,U+A981,U+200B,U+A9B2,U+A994,U+A9BD,U+A981,U+A992,U+A9A4,U+A9C0,U+A9A4,U+A9B6,U+200B,U+A991,U+A9AB,U+A9A1,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A9A2,U+A98A,U+A9A9,U+A9C0,U+A9B2,U+A9B6,U+A981,U+200B,U+A994,U+A9AA,U+A9B8,U+A993,U+A9BE,U+A98F,U+A982,U+A9A1,U+200B,U+A9B2,U+A9A2,U+A9B6,U+A99F,U+A9B6,U+A981,U+A994,U+A9BF,U+A9A0,U+A9C0,U+A9C8;[ha=0+1195|i.ns_cecak.ns=0@-182,10+0|ka=3+1221|cecak.ns=3@-301,10+0|space=5+0|ha=6+1195|nga=7+976|keret.ns=7+0|cecak.ns=7@-325,10+0|ga=10+938|na=11+989|na.pas=11+0|i.ns=11@-71,10+0|space=15+0|kha=16+1289|ra=17+915|taling=18+677|tha=18+967|tarung=18+413|na=21+989|da.pas=21+0|ngalelet=24+977|ma=25+970|ha.pas=25+1090|i.ns_cecak.ns=25@-71,10+0|space=30+0|nga=31+976|ya=32+1383|u.ns=32@-1,0+0|gha=34+1258|pengkal=34+376|ka=36+1221|layar.ns=36@-250,10+0|tha=38+967|space=39+0|ha=40+1195|da=41+1063|i.ns=41@-11,10+0|nna=43+1198|i.ns_cecak.ns=43@-137,10+0|nga_cakra=46+1221|ta=48+1183|pangkon=48+391|uniA9C8=50+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A997,U+A9B8,U+A9A9,U+A9BC,U+A9A4,U+A9BC,U+A981,U+200B,U+A9A2,U+A98A,U+A9A9,U+A9C0,U+A99F,U+A9A1,U+200B,U+A9B2,U+A9A9,U+A989,U+A981,U+A994,U+A9B6,U+200B,U+A9A2,U+A9B6,U+A9A4,U+A9C0,U+A9A0,U+A9BC,U+A9A4,U+A9C0,U+A9B1,U+A9BC,U+A9A4,U+A9BA,U+A9A4,U+A9C0,U+A9A5,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+200B,U+A9A0,U+A981,U+A992,U+A9AD,U+A9C0,U+A98F,U+A9A5,U+A9B6,U+A981,U+A9C7;[ja=0+991|u.ns=0@-4,0+0|ma=2+970|ae.ns=2@-59,10+0|na=4+989|ae.ns_cecak.ns=4@-71,10+0|space=7+0|da=8+1063|ngalelet=9+1294|ma=10+970|nna.pas=10@-1,0+0|tha=13+967|space=14+0|ha=15+1195|ma=16+970|pacerek=17+963|cecak.ns=17@-318,10+0|nga=19+976|i.ns=19@-66,10+0|space=21+0|da=22+1063|i.ns=22@-11,10+0|na=24+989|ta.pas=24+0|ae.ns=24@-68,10+0|na=28+989|sa.pas=28+830|ae.ns=28@52,10+0|taling=32+677|na=32+989|taling=34+677|na=34+989|pa.pas=34+830|tarung=34+413|na=39+989|pangkon=39+391|space=41+0|ta=42+1183|cecak.ns=42@-306,10+0|ga=44+938|la=45+1194|ka.pas=45+0|pa=48+963|i.ns_cecak.ns=48@-170,10+0|uniA9C7=51+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9CB,U+A9B1,U+A9A7,U+A9BC,U+A9A4,U+A9C0,U+A9B2,U+A9B8,U+A9AE,U+A9BA,U+A9B4,U+A981,U+A98F,U+A9AD,U+A9B2,U+A9B6,U+A9AB,U+A98F,U+A9BA,U+A98F,U+A9A4,U+A9C0,U+A99B,U+A9B6,U+A9A9,U+A982,U+A9A2,U+A9B6,U+A98F,U+A9AD,U+A9A4,U+A9C0,U+A9A2,U+A982,U+A9A7,U+A9BA,U+A9A9,U+A982,U+A9A0,U+A9A7,U+A9A0,U+A9C0,U+A9AD,U+A9A4,U+A9C0,U+A9B2,U+A98F,U+A9C0,U+A9B2,U+A98F,U+A9C0,U+A98F,U+A981,U+A9A5,U+A99D,U+A9C9;[uniA9CB=0+439|sa=1+1088|ba=2+1207|ae.ns=2@-13,10+0|na=4+989|ha.pas=4+1090|u.ns=4+0|taling=8+677|wa=8+967|cecak.ns=8@-320,10+0|tarung=8+413|ka=12+1221|la=13+1194|ha=14+1195|i.ns=14@-71,10+0|ra=16+915|taling=17+677|ka=17+1221|ka=19+1221|na=20+989|tta.pas=20+0|i.ns=20@-71,10+0|ma=24+970|layar.ns=24@-270,10+0|da=26+1063|i.ns=26@-11,10+0|ka=28+1221|la=29+1194|na=30+989|da.pas=30+0|layar.ns=30@-279,10+0|taling=34+677|ba=34+1207|ma=36+970|layar.ns=36@-270,10+0|ta=38+1183|ba=39+1207|ta=40+1183|la.pas=40@-273,0+0|na=43+989|ha.pas=43+1090|ka=46+1221|ha.pas=46+1090|ka=49+1221|ka.pas=49@-1,0+0|cecak.ns=49@-301,10+0|pa=53+963|dda=54+1071|uniA9C9=55+687]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B1,U+A981,U+A98F,U+A9B6,U+A981,U+200B,U+A9A5,U+A9AB,U+200B,U+A9A7,U+A9BA,U+A9B4,U+A981,U+A9B1,U+200B,U+A9A1,U+A9BE,U+A9BA,U+A9B4,U+A981,U+A9B2,U+A9C0,U+A9AE,U+200B,U+A992,U+A9BA,U+A9B4,U+A9AD,U+A9BA,U+A9B4,U+A981,U+A994,U+A9A4,U+A9C0,U+A9B2,U+A9B6,U+A981,U+200B,U+A994,U+A9AA,U+A9B8,U+A993,U+A9BE,U+A98F,U+A982,U+A9A1,U+200B,U+A9B2,U+A9A2,U+A9B6,U+A9A4,U+A9B6,U+A981,U+A994,U+A9BF,U+A9A0,U+A9C0;[sa=0+1088|cecak.ns=0@-259,10+0|ka=2+1221|i.ns_cecak.ns=2@-153,10+0|space=5+0|pa=6+963|ra=7+915|space=8+0|taling=9+677|ba=9+1207|cecak.ns=9@-275,10+0|tarung=9+413|sa=13+1088|space=14+0|taling=15+677|tha=15+967|pengkal=15+376|cecak.ns=15+0|tarung=15+413|ha=20+1195|wa.pas=20@-1,0+0|space=23+0|taling=24+677|ga=24+938|tarung=24+413|taling=27+677|la=27+1194|cecak.ns=27@-329,10+0|tarung=27+413|nga=31+976|na=32+989|ha.pas=32+1090|i.ns_cecak.ns=32@-71,10+0|space=37+0|nga=38+976|ya=39+1383|u.ns=39@-1,0+0|gha=41+1258|pengkal=41+376|ka=43+1221|layar.ns=43@-250,10+0|tha=45+967|space=46+0|ha=47+1195|da=48+1063|i.ns=48@-11,10+0|na=50+989|i.ns_cecak.ns=50@-182,10+0|nga_cakra=53+1221|ta=55+1183|pangkon=55+391]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A994,U+A982,U+A9B0,U+200B,U+A9A2,U+A98A,U+A9A9,U+A9C0,U+200B,U+A9AF,U+A9A9,U+A9C0,U+A9A6,U+A9BA,U+A9AA,U+A9A4,U+A9C0,U+A9A2,U+A98A,U+A9A9,U+A9C0,U+200B,U+A9B2,U+A9B6,U+A981,U+A991,U+A981,U+200B,U+A9AF,U+A9B6,U+A99F,U+A9B8,U+A9AE,U+A9B8,U+A9A4,U+A9C0,U+A98F,U+A997,U+A9BC,U+A981,U+200B,U+A9AF,U+A9B8,U+A9AD,U+A9C0,U+A9A1,U+A9A4,U+A9C0,U+200B,U+A9B2,U+A9A9,U+A9BC,U+A981,U+A991,U+A9B8,U+A9A8,U+A9B8,U+A9AE,U+A99F,U+A9C8;[nga=0+976|layar.ns=0@-274,10+0|ssa=2+1012|space=3+0|da=4+1063|ngalelet=5+977|ma=6+970|pangkon=6+391|space=8+0|sha=9+938|taling=10+677|ma=10+970|pha.pas=10+1054|ya=14+1383|na=15+989|da.pas=15+0|ngalelet=18+977|ma=19+970|pangkon=19+391|space=21+0|ha=22+1195|i.ns_cecak.ns=22@-182,10+0|kha=25+1289|cecak.ns=25@-359,10+0|space=27+0|sha=28+938|i.ns=28@8,10+0|nna=30+1198|u.ns=30+0|wa=32+1126|u.ns=32@-160,0+0|na=34+989|ka.pas=34+0|ja=37+991|ae.ns_cecak.ns=37@-24,10+0|space=40+0|sha=41+938|u.ns=41+0|la=43+1194|tha.pas=43+0|na=46+989|pangkon=46+391|space=48+0|ha=49+1195|ma=50+970|ae.ns_cecak.ns=50@-62,10+0|kha=53+1289|u.ns=53@-300,0+0|bha=55+879|u.ns=55@-37,0+0|wa=57+967|nna=58+1198|uniA9C8=59+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B2,U+A9A2,U+A9BC,U+A992,U+A9C0,U+A992,U+A9B6,U+A981,U+200B,U+A9A9,U+A9B1,U+A9C0,U+A997,U+A9B6,U+A9A2,U+A9C0,U+A9B1,U+A9AD,U+A9B6,U+A98F,U+A9B6,U+A9A4,U+A9C0,U+200B,U+A9AA,U+A9B1,U+A9A4,U+A9C0,U+A9A4,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+A9AB,U+A9A2,U+A9BA,U+A9A4,U+A9C0,U+A994,U+A9A4,U+A9C0,U+A9A0,U+A9BA,U+A9A4,U+A9C0,U+A9A1,U+A9B8,U+A9A9,U+A9BC,U+A981,U+A992,U+A9B8,U+A981,U+200B,U+A9A6,U+A9BF,U+A9AE,U+A9B6,U+A9AB,U+A9A2,U+A9B6,U+A982,U+A997,U+A9C8;[ha=0+1195|da=1+1063|ae.ns=1@-8,10+0|ga=3+938|ga.pas=3+0|i.ns_cecak.ns=3@-102,10+0|space=8+0|ma=9+970|sa=10+1088|ja.pas=10@200,0+0|i.ns=10@0,10+0|da=14+1063|sa.pas=14+830|la=17+1194|i.ns=17@-70,10+0|ka=19+1221|i.ns=19@-42,10+0|na=21+989|pangkon=21+391|space=23+0|ya=24+1383|sa=25+1088|na=26+989|na.pas=26+0|i.ns=26@-71,10+0|pa=30+1085|u.ns=30@-122,0+0|na=32+989|ra.pas=32+0|taling=35+677|da=35+1063|na=37+989|nga.pas=37+0|taling=40+677|na=40+989|ta.pas=40+0|na=44+989|tha.pas.alt=44+0|u.ns.pas=44@225,0+0|ma=48+970|ae.ns_cecak.ns=48@-62,10+0|ga=51+1060|u.ns=51@-122,0+0|cecak.ns=51@-372,10+0|space=54+0|pha_cakra=55+1318|wa=57+967|i.ns=57@-61,10+0|ra=59+915|da=60+1063|i.ns_layar.ns=60@-122,10+0|ja=63+991|uniA9C8=64+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A992,U+A9B8,U+A9A7,U+A9BC,U+A982,U+A9A4,U+A9B8,U+A982,U+200B,U+A99D,U+A983,U+A9B2,U+A9BA,U+A9AB,U+A983,U+200B,U+A986,U+A9B1,U+A9C0,U+A9A0,U+A9B6,U+A9A9,U+A9BA,U+A9AE,U+A983,U+200B,U+A9AA,U+A9BA,U+A9B4,U+A992,U+A9BE,U+A98F,U+A982,U+A9A0,U+200B,U+A9A0,U+A9B8,U+A9AE,U+A9B6,U+A9A4,U+A9C0,U+A9B2,U+A9B6,U+A981,U+A98F,U+A981,U+200B,U+A9A9,U+A9B6,U+A9A4,U+A9B8,U+A9AD,U+A9C0,U+A9AA,U+200B,U+A9A0,U+A9B8,U+A9AE,U+A9A4,U+A9C0,U+A9AA,U+A9BA,U+A9B4,U+A9B1,U+A9BA,U+200B,U+A9A7,U+A9C0,U+A9AD,U+A9A4,U+A9C0,U+A995,U+A9BA,U+A9B4,U+A9C8;[ga=0+938|u.ns=0+0|ba=2+1207|ae.ns_layar.ns=2@-75,10+0|na=5+989|u.ns=5+0|layar.ns=5@-279,10+0|space=8+0|dda=9+1071|wignyan=9+353|taling=11+677|ha=11+1195|ra=13+915|wignyan=13+353|space=15+0|ikara=16+1207|sa=17+1088|ta.pas=17+0|i.ns=17@0,10+0|taling=21+677|ma=21+970|wa=23+967|wignyan=23+353|space=25+0|taling=26+677|ya=26+1383|tarung=26+413|ga=29+938|pengkal=29+376|ka=31+1221|layar.ns=31@-250,10+0|ta=33+1183|space=34+0|ta=35+1183|u.ns=35@-1,0+0|wa=37+967|i.ns=37@-61,10+0|na=39+989|ha.pas=39+1090|i.ns_cecak.ns=39@-71,10+0|ka=44+1221|cecak.ns=44@-301,10+0|space=46+0|ma=47+970|i.ns=47@-62,10+0|na=49+1148|u.ns=49@-159,0+0|la=51+1194|ya.pas=51+0|space=54+0|ta=55+1183|u.ns=55@-1,0+0|wa=57+967|taling=58+838|na=58+989|ya.pas=58+0|tarung=58+413|taling=63+677|sa=63+1088|space=65+0|ba=66+1207|la.pas=66@-270,0+0|taling=69+838|na=69+989|ca.pas=69+0|tarung=69+413|uniA9C8=74+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B2,U+A9B6,U+A981,U+A992,U+A9B6,U+A983,U+200B,U+A9A5,U+A9B8,U+A9A4,U+A9B6,U+A98F,U+200B,U+A9A7,U+A9A7,U+A9C0,U+A9AE,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A9A0,U+A9BC,U+A9A4,U+A9C0,U+A9A4,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+A9B1,U+A9AE,U+A9B8,U+A981,U+200B,U+A9A7,U+A9AD,U+A9C0,U+A9A7,U+A9AD,U+A9C0,U+A9AD,U+A9A4,U+A9C0,U+A9A0,U+A9A4,U+A983,U+200B,U+A994,U+A9BF,U+A9B6,U+A98F,U+A9B6,U+200B,U+A9B2,U+A9B6,U+A981,U+A98F,U+A981,U+200B,U+A9B1,U+A9A9,U+A9B6,U+200B,U+A994,U+A9C0,U+A9AD,U+A9B8,U+A9AB,U+A9B8,U+A992,U+A9C0,U+A99D,U+A9A0,U+A9BC,U+A981,U+200B,U+A98C,U+A9AB,U+A9BA,U+A9B4,U+A9A6,U+A983,U+A9C8;[ha=0+1195|i.ns_cecak.ns=0@-182,10+0|ga=3+938|i.ns=3@9,10+0|wignyan=3+353|space=6+0|pa=7+963|u.ns=7+0|na=9+989|i.ns=9@-71,10+0|ka=11+1221|space=12+0|ba=13+1207|taling=14+677|ba=14+1207|wa.pas=14+0|tarung=14+413|na=19+989|ta.pas=19+0|ae.ns=19@-68,10+0|na=23+989|na.pas=23+0|i.ns=23@-71,10+0|pa=27+963|u.ns=27+0|na=29+989|sa.pas=29+830|wa=32+967|u.ns=32@-1,0+0|cecak.ns=32@-320,10+0|space=35+0|ba=36+1207|la=37+1194|ba.pas=37+0|la=40+1194|la.pas=40@-278,0+0|na=43+989|ta.pas=43+0|na=46+989|wignyan=46+490|space=48+0|nga_cakra=49+1221|i.ns=49@-18,10+0|ka=52+1221|i.ns=52@-42,10+0|space=54+0|ha=55+1195|i.ns_cecak.ns=55@-182,10+0|ka=58+1221|cecak.ns=58@-301,10+0|space=60+0|sa=61+1088|ma=62+970|i.ns=62@-62,10+0|space=64+0|nga=65+976|la.pas.alt=65+0|u.ns.pas=65+0|ra=69+1049|u.ns=69@-134,0+0|ga=71+938|dda.pas=71+0|ta=74+1183|ae.ns_cecak.ns=74@-47,10+0|space=77+0|ekara=78+781|taling=79+677|ra=79+915|tarung=79+413|pha=82+1027|wignyan=82+353|uniA9C8=84+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B1,U+A9BA,U+A9B4,U+A98F,U+A9BA,U+A9B4,U+A981,U+A994,U+A9A4,U+A9C0,U+A9B1,U+A98F,U+A9B6,U+A981,U+200B,U+A9A5,U+A9AB,U+200B,U+A9A9,U+A9B8,U+A9B1,U+A9C0,U+A9AD,U+A9B6,U+A9A9,U+A9B6,U+A9A4,U+A9C0,U+200B,U+A9A2,U+A9BA,U+A9A4,U+A9C0,U+A9A4,U+A9BA,U+200B,U+A9B2,U+A9B6,U+A981,U+A98F,U+A981,U+200B,U+A994,U+A9BF,U+A99A,U+A9C0,U+A995,U+A981,U+200B,U+A9B1,U+A9B2,U+200B,U+A994,U+A9AE,U+A9A0,U+A9C0,U+A9B2,U+A9AE,U+A9A0,U+A9C0,U+A9A0,U+A9B6,U+200B,U+A9A5,U+A981,U+A992,U+A9AB,U+A9A5,U+A9C0,U+A9A5,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+A9A9,U+A9B1,U+A9C0,U+A997,U+A9B6,U+A9A2,U+A9C0,U+200B,U+A9AB,U+A9A2,U+A9BA,U+A9A4,U+A9C0,U+A994,U+A9A7,U+A9BA,U+A9B2,U+A9B6,U+200B,U+A995,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A9A2,U+A9BF,U+A9A2,U+A9B6,U+A9A5,U+A9BF,U+A997,U+A9C8;[taling=0+677|sa=0+1088|tarung=0+413|taling=3+677|ka=3+1221|cecak.ns=3@-301,10+0|tarung=3+413|nga=7+976|na=8+989|sa.pas=8+830|ka=11+1221|i.ns_cecak.ns=11@-153,10+0|space=14+0|pa=15+963|ra=16+915|space=17+0|ma=18+970|u.ns=18@-1,0+0|sa=20+1088|la.pas=20@-225,0+0|i.ns=20@0,10+0|ma=24+970|i.ns=24@-62,10+0|na=26+989|pangkon=26+391|space=28+0|taling=29+677|da=29+1063|taling=31+677|na=31+989|na.pas=31+0|space=35+0|ha=36+1195|i.ns_cecak.ns=36@-182,10+0|ka=39+1221|cecak.ns=39@-301,10+0|space=41+0|nga_cakra=42+1221|nya=44+1439|ca.pas=44@-1,0+0|cecak.ns=44@-361,10+0|space=48+0|sa=49+1088|ha=50+1195|space=51+0|nga=52+976|wa=53+967|ta=54+1183|ha.pas=54+1090|wa=57+967|ta=58+1183|ta.pas=58@-1,0+0|i.ns=58@-47,10+0|space=62+0|pa=63+963|cecak.ns=63@-318,10+0|ga=65+938|ra=66+915|pa=67+963|pa.pas=67+830|i.ns=67@49,10+0|pa=71+963|u.ns=71+0|na=73+989|ma.pas=73+0|sa=76+1088|ja.pas=76@200,0+0|i.ns=76@0,10+0|da=80+1063|pangkon=80+391|space=82+0|ra=83+915|taling=84+677|da=84+1063|na=86+989|nga.pas=86+0|taling=89+677|ba=89+1207|ha=91+1195|i.ns=91@-71,10+0|space=93+0|taling=94+677|ca=94+1043|tarung=94+413|da.pas_cakra=97+238|na=97+989|da=101+1063|i.ns=101@-11,10+0|pa_cakra=103+1221|ja=105+991|uniA9C8=106+470]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9AD,U+A997,U+A9BC,U+A981,U+200B,U+A98F,U+A9AE,U+A98F,U+A9A5,U+A9C0,U+A9A5,U+A98F,U+A9BC,U+A9A4,U+A9C0,U+A98F,U+A981,U+A992,U+A9BA,U+200B,U+A9A5,U+A982,U+A9AD,U+A9B8,U+A9A4,U+A9B6,U+A981,U+200B,U+A986,U+A9B1,U+A9C0,U+A9AD,U+A9A9,U+A9C0,U+A9AD,U+A9A4,U+A9C0,U+A9A9,U+A9B8,U+A9B1,U+A9C0,U+A9AD,U+A9B6,U+A9A9,U+A9B6,U+A9A4,U+A9C0,U+A9B2,U+A9B6,U+A981,U+200B,U+A9B1,U+A9AD,U+A9A9,U+A9B6,U+A9AD,U+A9A9,U+A9B6,U+A9A4,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+200B,U+A9A5,U+A9A9,U+A9C0,U+A9A7,U+A9B6,U+A98F,U+A98F,U+A9C0,U+A98F,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+A9B2,U+A9B6,U+A981,U+200B,U+A9A2,U+A9B6,U+A9A4,U+A9C0,U+A9A0,U+A9BC,U+A9A4,U+A9C0,U+A98F,U+A9BC,U+A9A9,U+A9B6,U+A9B1,U+A9C0,U+A98F,U+A9AD,U+A9B6,U+A9AE,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A9A0,U+A981,U+A992,U+A9AD,U+A9C0,U+A98F,U+A9A5,U+A9B6,U+A981,U+A9C7;[la=0+1194|ja=1+991|ae.ns_cecak.ns=1@-24,10+0|space=4+0|ka=5+1221|wa=6+967|ka=7+1221|pa=8+963|pa.pas=8+830|ka=11+1221|ae.ns=11@-39,10+0|na=13+989|ka.pas=13+0|cecak.ns=13@-330,10+0|taling=17+677|ga=17+938|space=19+0|pa=20+963|layar.ns=20@-267,10+0|la=22+1194|u.ns=22+0|na=24+989|i.ns_cecak.ns=24@-182,10+0|space=27+0|ikara=28+1207|sa=29+1088|la.pas=29@-225,0+0|ma=32+970|la.pas=32@-167,0+0|na=35+989|ma.pas.alt=35+0|u.ns.pas=35+0|sa=39+1088|la.pas=39@-225,0+0|i.ns=39@0,10+0|ma=43+970|i.ns=43@-62,10+0|na=45+989|ha.pas=45+1090|i.ns_cecak.ns=45@-71,10+0|space=50+0|sa=51+1088|la=52+1194|ma=53+970|i.ns=53@-62,10+0|la=55+1194|ma=56+970|i.ns=56@-62,10+0|na=58+989|i.ns=58@-71,10+0|pa=60+963|u.ns=60+0|na=62+989|pangkon=62+391|space=64+0|pa=65+963|ma=66+970|ba.pas=66@-1,0+0|i.ns=66@-62,10+0|ka=70+1221|ka=71+1221|ka.pas=71@-1,0+0|i.ns=71@-42,10+0|pa=75+963|u.ns=75+0|na=77+989|ha.pas=77+1090|i.ns_cecak.ns=77@-71,10+0|space=82+0|da=83+1063|i.ns=83@-11,10+0|na=85+1150|ta.pas=85@-161,0+0|ae.ns=85@-229,10+0|na=89+989|ka.pas=89+0|ae.ns=89@-68,10+0|ma=93+970|i.ns=93@-62,10+0|sa=95+1088|ka.pas=95+0|la=98+1194|i.ns=98@-70,10+0|taling=100+677|wa=100+967|tarung=100+413|na=103+989|ta.pas=103+0|cecak.ns=103@-330,10+0|ga=107+938|la=108+1194|ka.pas=108+0|pa=111+963|i.ns_cecak.ns=111@-170,10+0|uniA9C7=114+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B2,U+A9B6,U+A981,U+200B,U+A994,U+A9BF,U+A9B6,U+A98F,U+A9B6,U+200B,U+A994,U+A9BC,U+A995,U+A9BF,U+A9A0,U+A9C0,U+A992,U+A9A9,U+A9C0,U+A9A7,U+A982,U+A9AB,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+A9B1,U+A9AE,U+A9B8,U+A981,U+200B,U+A9B1,U+A9AE,U+A9B8,U+A981,U+200B,U+A9AE,U+A9B2,U+A9B8,U+200B,U+A9A4,U+A9AD,U+A9B6,U+A98F,U+200B,U+A9A4,U+A9B8,U+A997,U+A9B8,U+200B,U+A9A0,U+A9A4,U+A9C0,U+A99D,U+A9B6,U+A981,U+A994,U+A9A4,U+A9C0,U+A98F,U+A9AD,U+A9B6,U+A9AA,U+A9A4,U+A9C0,U+A9B1,U+A9AE,U+A9B8,U+A981,U+200B,U+A9A7,U+A9AD,U+A9C0,U+A9A7,U+A9AD,U+A9C0,U+A9AD,U+A9A4,U+A9C0,U+A9B1,U+A98F,U+A9B6,U+A981,U+200B,U+A9B2,U+A9BA,U+A9B4,U+A981,U+A993,U+A9AB,U+A9B6,U+A9AA,U+A9BC,U+200B,U+A9AE,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A9A0,U+A9BC,U+A9A4,U+A9C0,U+A9B2,U+A9B6,U+A981,U+200B,U+A9B2,U+A9AD,U+A9B8,U+A9A4,U+A9C0,U+A9B2,U+A9AD,U+A9B8,U+A9A4,U+A9C0,U+A9C7;[ha=0+1195|i.ns_cecak.ns=0@-182,10+0|space=3+0|nga_cakra=4+1221|i.ns=4@-18,10+0|ka=7+1221|i.ns=7@-42,10+0|space=9+0|nga=10+976|ae.ns=10@-63,10+0|ca_cakra=12+1318|ta=14+1183|ga.pas=14@-1,0+0|ma=17+970|ba.pas=17@-1,0+0|layar.ns=17@-270,10+0|ra=21+915|i.ns=21@-62,10+0|pa=23+963|u.ns=23+0|na=25+989|sa.pas=25+830|wa=28+967|u.ns=28@-1,0+0|cecak.ns=28@-320,10+0|space=31+0|sa=32+1088|wa=33+967|u.ns=33@-1,0+0|cecak.ns=33@-320,10+0|space=36+0|wa=37+967|ha=38+1195|u.ns=38@-1,0+0|space=40+0|na=41+989|la=42+1194|i.ns=42@-70,10+0|ka=44+1221|space=45+0|na=46+989|u.ns=46+0|ja=48+991|u.ns=48@-4,0+0|space=50+0|ta=51+1183|na=52+989|dda.pas=52+0|i.ns_cecak.ns=52@-182,10+0|nga=57+976|na=58+989|ka.pas=58+0|la=61+1194|i.ns=61@-70,10+0|ya=63+1383|na=64+989|sa.pas=64+830|wa=67+967|u.ns=67@-1,0+0|cecak.ns=67@-320,10+0|space=70+0|ba=71+1207|la=72+1194|ba.pas=72+0|la=75+1194|la.pas=75@-278,0+0|na=78+989|sa.pas=78+830|ka=81+1221|i.ns_cecak.ns=81@-153,10+0|space=84+0|taling=85+677|ha=85+1195|cecak.ns=85@-330,10+0|tarung=85+413|gha=89+1258|ra=90+915|i.ns=90@-62,10+0|ya=92+1383|ae.ns=92@-71,10+0|space=94+0|taling=95+677|wa=95+967|tarung=95+413|na=98+989|ta.pas=98+0|ae.ns=98@-68,10+0|na=102+989|ha.pas=102+1090|i.ns_cecak.ns=102@-71,10+0|space=107+0|ha=108+1195|la=109+1194|u.ns=109+0|na=111+989|ha.pas=111+1090|la=114+1194|u.ns=114+0|na=116+989|pangkon=116+391|uniA9C7=118+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9B1,U+A9A2,U+A9BA,U+A9AB,U+A9BA,U+A981,U+A994,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+A9A9,U+A9B1,U+A9C0,U+A997,U+A9B6,U+A9A2,U+A9C0,U+A9B1,U+A9AD,U+A9B6,U+A98F,U+A9B6,U+A9A4,U+A9C0,U+A98F,U+A992,U+A9AB,U+A9A5,U+A9C0,U+200B,U+A9B1,U+A9A9,U+A9C0,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+A9AE,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A9A0,U+A9BC,U+A9A4,U+A9C0,U+A9A9,U+A9B2,U+A9B8,U+A997,U+A9B8,U+A9A2,U+A9C0,U+A9A5,U+A9A4,U+A9C0,U+A99D,U+A9BC,U+A9A9,U+A9BA,U+A9A4,U+A9C0,U+A9A4,U+A9B6,U+A981,U+200B,U+A9A9,U+A9B1,U+A9C0,U+A997,U+A9B6,U+A9A2,U+A9C0,U+200B,U+A9AF,U+A9B8,U+A9AB,U+A9A9,U+A9C0,U+A9A7,U+A9B6,U+200B,U+A9B1,U+A9B2,U+200B,U+A9A5,U+A9AD,U+A9A9,U+A9C0,U+A9A5,U+A983,U+A9B2,U+A9A4,U+A9C0,U+200B,U+A9B1,U+A982,U+A9A0,U+200B,U+A9A7,U+A9BA,U+A9B4,U+A9A4,U+A9C0,U+A99D,U+A9B1,U+A9AE,U+A9A0,U+A9AE,U+A9B6,U+A9B1,U+A9C0,U+200B,U+A98F,U+A9A2,U+A9BA,U+A9B4,U+A9B1,U+A9C0,U+A9A0,U+A9C7;[sa=0+1088|taling=1+677|da=1+1063|taling=3+677|ra=3+915|cecak.ns=3@-321,10+0|nga=6+976|i.ns=6@-66,10+0|pa=8+963|u.ns=8+0|na=10+989|ma.pas=10+0|sa=13+1088|ja.pas=13@200,0+0|i.ns=13@0,10+0|da=17+1063|sa.pas=17+830|la=20+1194|i.ns=20@-70,10+0|ka=22+1221|i.ns=22@-42,10+0|na=24+989|ka.pas=24+0|ga=27+938|ra=28+915|pa=29+963|pangkon=29+391|space=31+0|sa=32+1088|ma=33+970|pa.pas=33+830|u.ns=33+0|taling=37+677|na=37+989|wa.pas=37+0|tarung=37+413|na=42+989|ta.pas=42+0|ae.ns=42@-68,10+0|na=46+989|ma.pas=46+0|ha=49+1195|u.ns=49@-1,0+0|ja=51+991|u.ns=51@-4,0+0|da=53+1063|pa.pas=53+830|na=56+989|dda.pas=56+0|ae.ns=56@-68,10+0|taling=60+677|ma=60+970|na=62+989|na.pas=62+0|i.ns_cecak.ns=62@-182,10+0|space=67+0|ma=68+970|sa=69+1088|ja.pas=69@200,0+0|i.ns=69@0,10+0|da=73+1063|pangkon=73+391|space=75+0|sha=76+938|u.ns=76+0|ra=78+915|ma=79+970|ba.pas=79@-1,0+0|i.ns=79@-62,10+0|space=83+0|sa=84+1088|ha=85+1195|space=86+0|pa=87+963|la=88+1194|ma=89+970|pa.pas=89+830|wignyan=89+353|ha=93+1195|na=94+989|pangkon=94+391|space=96+0|sa=97+1088|layar.ns=97@-208,10+0|ta=99+1183|space=100+0|taling=101+677|ba=101+1207|tarung=101+413|na=104+989|dda.pas=104+0|sa=107+1088|wa=108+967|ta=109+1183|wa=110+967|i.ns=110@-61,10+0|sa=112+1088|pangkon=112+391|space=114+0|ka=115+1221|taling=116+677|da=116+1063|tarung=116+413|sa=119+1088|ta.pas=119+0|uniA9C7=122+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A9,U+A9B8,U+A9AD,U+A9C0,U+A9AA,U+A98F,U+A9C0,U+A98F,U+A98F,U+A9BA,U+200B,U+A988,U+A9A9,U+A9C0,U+A9A7,U+A9B8,U+A9AD,U+A9C0,U+A9A7,U+A9B6,U+A9A4,U+A981,U+A994,U+A9B8,U+A9A4,U+A9C0,U+A9A0,U+A9A9,U+A9C0,U+A9A9,U+A9A4,U+A9C0,U+A9B1,U+A982,U+A9AB,U+A9B6,U+200B,U+A98F,U+A98A,U+A98F,U+A9C0,U+A9B1,U+A9A4,U+A9C0,U+A9A4,U+A98F,U+A9C0,U+A98F,U+A98F,U+A9BC,U+A9A4,U+A9C0,U+A98F,U+A9A4,U+A9C0,U+A99B,U+A9B6,U+200B,U+A9A5,U+A99A,U+A9BC,U+A981,U+A98F,U+A9B8,U+A9AA,U+A9B8,U+A981,U+A994,U+A9B6,U+A9A5,U+A9B8,U+A9A4,U+A9C0,U+A9AA,U+A9AA,U+A9B1,U+A9C0,U+A9B1,U+A9A4,U+A9C0,U+A98F,U+A9AD,U+A9C0,U+A9AD,U+A9B2,U+A9B8,U+A9B1,U+A9C0,U+A9A0,U+A9BC,U+200B,U+A992,U+A9B8,U+A9AD,U+A9C0,U+A9A7,U+A9BC,U+A9A4,U+A9C0,U+A98F,U+A9B6,U+A9B2,U+A9A4,U+A9C0,U+A9B1,U+A9B2,U+200B,U+A98F,U+A982,U+A989,U+A9B1,U+A9C0,U+A9A9,U+A9BA,U+A98F,U+A9C0,U+A98F,U+A98F,U+A9BC,U+A9A4,U+A9C0,U+A9A2,U+A9B6,U+A9A4,U+A9B6,U+A981,U+200B,U+A9B2,U+A9B6,U+A981,U+A98F,U+A981,U+200B,U+A9A9,U+A9B6,U+A9A4,U+A9B8,U+A9AD,U+A9C0,U+A9AA,U+200B,U+A9AF,U+A9BF,U+A9B6,U+200B,U+A9AF,U+A9B8,U+A9AD,U+A9C0,U+A9A0,U+A9A4,U+A9C0,U+A9B2,U+A9A9,U+A981,U+A98F,U+A9B8,U+A9A8,U+A9B8,U+A9AE,U+A9A4,U+A9C7;[ma=0+1129|u.ns=0@-160,0+0|la=2+1194|ya.pas=2+0|ka=5+1221|ka.pas=5@-1,0+0|taling=8+677|ka=8+1221|space=10+0|ukara=11+976|ma=12+970|ba.pas=12@-1,0+0|u.ns.pas=12@-1,0+0|la=16+1194|ba.pas=16+0|i.ns=16@-70,10+0|na=20+989|cecak.ns=20@-330,10+0|nga=22+1098|u.ns=22@-122,0+0|na=24+989|ta.pas=24+0|ma=27+970|ma.pas=27@-1,0+0|na=30+989|sa.pas=30+830|layar.ns=30@-159,10+0|ra=34+915|i.ns=34@-62,10+0|space=36+0|ka=37+1221|ngalelet=38+977|ka=39+1221|sa.pas=39+830|na=42+1150|na.pas=42@-161,0+0|ka=45+1221|ka.pas=45@-1,0+0|ka=48+1221|ae.ns=48@-39,10+0|na=50+1150|ka.pas=50@-161,0+0|na=53+989|tta.pas=53+0|i.ns=53@-71,10+0|space=57+0|pa=58+963|nya=59+1439|ae.ns_cecak.ns=59@-102,10+0|ka=62+1221|u.ns=62@-1,0+0|ya=64+1383|u.ns=64@-1,0+0|cecak.ns=64@-333,10+0|nga=67+976|i.ns=67@-66,10+0|pa=69+1246|u.ns=69@-283,0+0|na=71+989|ya.pas=71+0|ya=74+1383|sa=75+1088|sa.pas=75+830|na=78+989|ka.pas=78+0|la=81+1194|la.pas=81@-278,0+0|ha=84+1195|u.ns=84@-1,0+0|sa=86+1088|ta.pas=86+0|ae.ns=86@3,10+0|space=90+0|ga=91+938|u.ns=91+0|la=93+1194|ba.pas=93+0|ae.ns=93@-67,10+0|na=97+989|ka.pas=97+0|i.ns=97@-71,10+0|ha=101+1195|na=102+989|sa.pas=102+830|ha=105+1195|space=106+0|ka=107+1221|layar.ns=107@-250,10+0|pacerek=109+963|taling=110+677|sa=110+1088|ma.pas=110+0|ka=114+1221|ka.pas=114@-1,0+0|ka=117+1221|ae.ns=117@-39,10+0|na=119+989|da.pas=119+0|i.ns=119@-71,10+0|na=123+989|i.ns_cecak.ns=123@-182,10+0|space=126+0|ha=127+1195|i.ns_cecak.ns=127@-182,10+0|ka=130+1221|cecak.ns=130@-301,10+0|space=132+0|ma=133+970|i.ns=133@-62,10+0|na=135+1148|u.ns=135@-159,0+0|la=137+1194|ya.pas=137+0|space=140+0|sha_cakra=141+1221|i.ns=141@58,10+0|space=144+0|sha=145+938|u.ns=145+0|la=147+1194|ta.pas=147+0|na=150+989|ha.pas=150+1090|ma=153+970|cecak.ns=153@-321,10+0|ka=155+1221|u.ns=155@-1,0+0|bha=157+879|u.ns=157@-37,0+0|wa=159+967|na=160+989|uniA9C7=161+269]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A0,U+A9B8,U+A9AE,U+A9A4,U+A9C0,U+0044,U+0072,U+A9C7,U+A9AF,U+A9B6,U+A9A9,U+A9C0,U+200B,U+A98F,U+A9B6,U+A984,U+A98C;[ta=0+1183|u.ns=0@-1,0+0|wa=2+967|na=3+989|pangkon=3+391|.notdef=5+600|.notdef=6+600|uniA9C7=7+269|sha=8+938|i.ns=8@8,10+0|ma=10+970|pangkon=10+391|space=12+0|ka=13+1221|i.ns=13@-42,10+0|akara=15+1338|ekara=16+781]
+../fonts/f70f345188472b93f565d1d7fae8c668dd6a3244.ttf;;U+A9A0,U+A9B8,U+A9AE,U+A9A4,U+A9C0,U+0049,U+0072,U+A9C7,U+A9AD,U+A9B6,U+A9A9,U+A9C0,U+200B,U+A986,U+A981,U+A9B2,U+A9C0,U+A9AE,U+A9B6;[ta=0+1183|u.ns=0@-1,0+0|wa=2+967|na=3+989|pangkon=3+391|.notdef=5+600|.notdef=6+600|uniA9C7=7+269|la=8+1194|i.ns=8@-70,10+0|ma=10+970|pangkon=10+391|space=12+0|ikara=13+1207|cecak.ns=13@-293,10+0|ha=15+1195|wa.pas=15@-1,0+0|i.ns=15@-71,10+0]
index 1cc52fd..8e5bd3d 100644 (file)
@@ -3,6 +3,7 @@
 ../fonts/e68a88939e0f06e34d2bc911f09b70890289c8fd.ttf;;U+AA00,U+AA35,U+AA33;[a_cham=0+1121|laMedial_cham=0@-32,0+0|yaMedial_cham=0+542]
 ../fonts/e68a88939e0f06e34d2bc911f09b70890289c8fd.ttf;;U+AA00,U+AA35,U+AA36;[a_cham=0+1121|laMedial_waMedial_cham=0@43,0+0]
 ../fonts/074a5ae6b19de8f29772fdd5df2d3d833f81f5e6.ttf;--no-glyph-names;U+11320,U+20F0,U+11367;[3=0+502|1=0@33,0+0|4=0@300,8+0]
+../fonts/23406a60ab081c4fb15e1596ea1cd4f27ae8443e.ttf;;U+A8AC,U+A8B4,U+A8C4;[uniA8AC=0+586|uniA8B4=0+316|uniA8C4=0+0]
 ../fonts/373e67bf41ca264e260a9716162b71a23549e885.ttf;--no-glyph-names;U+A8AC,U+A8B4,U+A8B5;[2=0+377|3=0+242|4=0+210]
 ../fonts/59a585a63b3df608fbeef00956c8c108deec7de6.ttf;--no-glyph-names;U+1BC7,U+1BEA,U+1BF3;[1=0+749|2=0+402|4=0+535|3=0+401]
 ../fonts/1ed7e9064f008f62de6ff0207bb4dd29409597a5.ttf;;U+11064,U+1107F,U+11052,U+11065,U+1107F,U+11053;[brm_num100.1=0+2224|brm_num1000.2=3+1834]
@@ -20,3 +21,5 @@
 ../fonts/e68a88939e0f06e34d2bc911f09b70890289c8fd.ttf;;U+AA00,U+200C,U+AA34;[raMedial_cham_pre=0+400|a_cham=0+1121]
 ../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf;;U+11124,U+200D,U+11127;[u11124=0+514|u11127=0+0]
 ../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf;;U+11124,U+2060,U+11127;[u11124=0+514|uni25CC=1+547|u11127=1+0]
+../fonts/a56745bac8449d0ad94918b2bb5930716ba02fe3.ttf;;U+1142C,U+11442,U+200C,U+1142E;[u1142C=0+547|u11442=0+0|u1142E=3+547]
+../fonts/d0430ea499348c420946f6abc2efc84fdf8f00e3.ttf;;U+1142C,U+11442,U+1140E,U+1145E;[u1140E=0+736|u1142C_u11442=0+0|u1145E=0+0]
index ebeda47..acbd59d 100644 (file)
@@ -9,7 +9,9 @@
 ../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf;;U+11124,U+11131,U+11134;[u11124=0+514|u11131=0+0|uni25CC=0+547|u11134=0+0]
 ../fonts/573d3a3177c9a8646e94c8a0d7b224334340946a.ttf;;U+11410,U+11442,U+11411,U+11440,U+11443,U+11410,U+11442,U+11411,U+11441,U+11443;[E_dv.alt=0+275|Ga.icd=0+367|Gha.diag=0@100,0+386|AA_dv.alt=0+208|Candrabindu=0@17,-8+0|E_dv.alt=5+275|Ga.icd=5+367|Gha.diag=5@100,0+386|AU_dv_part.alt=5+213|Candrabindu.sm=5@-52,179+0]
 ../fonts/dcf774ca21062e7439f98658b18974ea8b956d0c.ttf;;U+11328,U+1134D,U+1CF4;[gid1=0+793|gid2=0+0|gid3=0+0]
+../fonts/23406a60ab081c4fb15e1596ea1cd4f27ae8443e.ttf;;U+11328,U+1133F,U+1134D,U+1CF4;[u11328=0+586|u1133F=0+316|uni25CC=0+652|u1134D=0+0|uni1CF4=0+0]
 ../fonts/4afb0e8b9a86bb9bd73a1247de4e33fbe3c1fd93.ttf;;U+1C00,U+1C27,U+1C28,U+1C34,U+1C35;[uni1C35=0+500|uni1C34=0+500|uni1C28=0+500|uni1C27=0+500|uni1C00=0+500]
 ../fonts/4afb0e8b9a86bb9bd73a1247de4e33fbe3c1fd93.ttf;;U+0D4E,U+0D15,U+0D4D,U+0D15,U+0D46;[uni0D15=0+500|uni0D4E=0+500|uni0D4D=0+500|uni0D46=3+500|uni0D15=3+500]
 ../fonts/4afb0e8b9a86bb9bd73a1247de4e33fbe3c1fd93.ttf;;U+1102D,U+11046,U+11013,U+11046,U+11013,U+11046;[u11013=0+500|u11046_u11013=0+500|u1102D_u11046=0+500|u11046=0+500]
 ../fonts/4afb0e8b9a86bb9bd73a1247de4e33fbe3c1fd93.ttf;;U+11083;[.notdef=0+500]
+../fonts/7c24183f26d60df414578a0a9f5e79ab9d32a22b.ttf;;U+11410,U+11441,U+11443;[E_dv.alt=0+275|Ga=0+576|AU_dv_part.alt=0+213|Candrabindu.sm=0@-52,179+0]
index 22bf266..0e1b106 100644 (file)
@@ -1,4 +1,4 @@
 ../fonts/191826b9643e3f124d865d617ae609db6a2ce203.ttf;--direction=t --font-funcs=ft;U+300C;[uni300C.vert=0@-512,-578+0,-1024]
 ../fonts/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf;--direction=t --font-funcs=ft;U+0041,U+0042;[gid1=0@-654,-2128+0,-2789|gid2=1@-665,-2125+0,-2789]
-../fonts/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf;--direction=t --font-funcs=ot;U+0041,U+0042;[gid1=0@-654,-1468+0,-2048|gid2=1@-665,-1462+0,-2048]
+../fonts/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf;--direction=t --font-funcs=ot;U+0041,U+0042;[gid1=0@-654,-2128+0,-2789|gid2=1@-665,-2125+0,-2789]
 ../fonts/4cbbc461be066fccc611dcc634af6e8cb2705537.ttf;--direction=t --font-funcs=ot;U+FF38;[gid2=0@-500,-867+0,-1000]
index 6b3acc3..bcdc0fb 100644 (file)
@@ -389,8 +389,6 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
-DIRECTWRITE_CXXFLAGS = @DIRECTWRITE_CXXFLAGS@
-DIRECTWRITE_LIBS = @DIRECTWRITE_LIBS@
 DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -488,6 +486,8 @@ STRIP = @STRIP@
 UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
 UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
 VERSION = @VERSION@
+WASM_CFLAGS = @WASM_CFLAGS@
+WASM_LIBS = @WASM_LIBS@
 _GI_EXP_DATADIR = @_GI_EXP_DATADIR@
 _GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@
 abs_builddir = @abs_builddir@
index 07e6882..48805c4 100644 (file)
Binary files a/test/shape/data/text-rendering-tests/fonts/TestGVAR-Composite-0.ttf and b/test/shape/data/text-rendering-tests/fonts/TestGVAR-Composite-0.ttf differ
index 58dd961..b24e82f 100644 (file)
Binary files a/test/shape/data/text-rendering-tests/fonts/TestGVAR-Composite-Missing.ttf and b/test/shape/data/text-rendering-tests/fonts/TestGVAR-Composite-Missing.ttf differ
index 271dc4b..a24e949 100644 (file)
Binary files a/test/shape/data/text-rendering-tests/fonts/TestGVAREight.ttf and b/test/shape/data/text-rendering-tests/fonts/TestGVAREight.ttf differ
index 2409eec..beb6cd2 100644 (file)
@@ -3,60 +3,52 @@ subdir('data/in-house') # in_house_tests
 subdir('data/aots') # aots_tests
 subdir('data/text-rendering-tests') # text_rendering_tests
 
-shaping_run_tests_py = find_program('run-tests.py')
+shape_run_tests_py = find_program('run-tests.py')
 
 env = environment()
 env.set('HAVE_FREETYPE', '@0@'.format(conf.get('HAVE_FREETYPE', 0)))
-
-in_house_tests = in_house_tests_base
-if conf.get('HAVE_CORETEXT', 0) == 1
-  in_house_tests += in_house_tests_coretext
-endif
-if conf.get('HAVE_UNISCRIBE', 0) == 1
-  in_house_tests += in_house_tests_uniscribe
-endif
-if conf.get('HAVE_DIRECTWRITE', 0) == 1
-  in_house_tests += in_house_tests_directwrite
-endif
+env.set('HAVE_CORETEXT', '@0@'.format(conf.get('HAVE_CORETEXT', 0)))
+env.set('HAVE_DIRECTWRITE', '@0@'.format(conf.get('HAVE_DIRECTWRITE', 0)))
+env.set('HAVE_UNISCRIBE', '@0@'.format(conf.get('HAVE_UNISCRIBE', 0)))
 
 foreach file_name : in_house_tests
   test_name = file_name.split('.')[0]
 
-  test(test_name, shaping_run_tests_py,
+  test(test_name, shape_run_tests_py,
     args: [
       hb_shape,
       meson.current_source_dir() / 'data' / 'in-house' / 'tests' / file_name,
     ],
     env: env,
     workdir: meson.current_build_dir() / '..' / '..',
-    suite: ['shaping', 'in-house'],
+    suite: ['shape', 'in-house'],
   )
 endforeach
 
 foreach file_name : aots_tests
   test_name = file_name.split('.')[0]
 
-  test(test_name, shaping_run_tests_py,
+  test(test_name, shape_run_tests_py,
     args: [
       hb_shape,
       meson.current_source_dir() / 'data' / 'aots' / 'tests' / file_name,
     ],
     env: env,
     workdir: meson.current_build_dir() / '..' / '..',
-    suite: ['shaping', 'aots'],
+    suite: ['shape', 'aots'],
   )
 endforeach
 
 foreach file_name : text_rendering_tests
   test_name = file_name.split('.')[0]
 
-  test(test_name, shaping_run_tests_py,
+  test(test_name, shape_run_tests_py,
     args: [
       hb_shape,
       meson.current_source_dir() / 'data' / 'text-rendering-tests' / 'tests' / file_name,
     ],
     env: env,
     workdir: meson.current_build_dir() / '..' / '..',
-    suite: ['shaping', 'text-rendering-tests'],
+    suite: ['shape', 'text-rendering-tests'],
   )
 endforeach
index 41e13c3..4f16d9c 100755 (executable)
@@ -19,6 +19,8 @@ if test "x$1" == 'x-o'; then
        out=$1
        shift
 fi
+hb_subset=$1
+shift
 hb_shape=$1
 shift
 fontfile=$1
@@ -27,8 +29,12 @@ if test "x${fontfile:0:1}" == 'x-'; then
        exit 1
 fi
 shift
+if ! echo "$hb_subset" | grep -q 'subset'; then
+       echo "Specify hb-subset (or \"fonttools subset\"): got '$hb_subset'." >&2
+       exit 1
+fi
 if ! echo "$hb_shape" | grep -q 'hb-shape'; then
-       echo "Specify hb-shape (not hb-view, etc): got "$hb_shape"." >&2
+       echo "Specify hb-shape (not hb-view, etc): got '$hb_shape'." >&2
        exit 1
 fi
 options=
@@ -61,7 +67,7 @@ fi
 glyph_ids=`echo "$text" | $hb_shape $options --no-glyph-names --no-clusters --no-positions "$fontfile" | sed 's/[][]//g; s/|/,/g'`
 
 cp "$fontfile" "$dir/font.ttf"
-echo fonttools subset \
+echo $hb_subset \
        --glyph-names \
        --no-hinting \
        --layout-features='*' \
@@ -69,7 +75,7 @@ echo fonttools subset \
        --text="$text" \
        --output-file="$dir/font.subset.ttf" \
        "$dir/font.ttf"
-fonttools subset \
+$hb_subset \
        --glyph-names \
        --no-hinting \
        --layout-features='*' \
index 83f1fec..03f03df 100755 (executable)
@@ -11,7 +11,10 @@ def shape_cmd(command):
 
 args = sys.argv[1:]
 
-have_freetype = bool(int(os.getenv ('HAVE_FREETYPE', '1')))
+have_freetype = int(os.getenv ('HAVE_FREETYPE', 1))
+have_coretext = int(os.getenv ('HAVE_CORETEXT', 0))
+have_directwrite = int(os.getenv ('HAVE_DIRECTWRITE', 0))
+have_uniscribe = int(os.getenv ('HAVE_UNISCRIBE', 0))
 
 if not args or args[0].find('hb-shape') == -1 or not os.path.exists (args[0]):
        sys.exit ("""First argument does not seem to point to usable hb-shape.""")
@@ -82,6 +85,7 @@ for filename in args:
                extra_options = ["--shaper=ot"]
                if glyphs_expected != '*':
                        extra_options.append("--verify")
+                       extra_options.append("--unsafe-to-concat")
 
                if comment:
                        print ('# %s "%s" --unicodes %s' % (hb_shape, fontfile, unicodes))
@@ -91,6 +95,18 @@ for filename in args:
                        skips += 1
                        continue
 
+               if "--shaper=coretext" in options and not have_coretext:
+                       skips += 1
+                       continue
+
+               if "--shaper=directwrite" in options and not have_directwrite:
+                       skips += 1
+                       continue
+
+               if "--shaper=uniscribe" in options and not have_uniscribe:
+                       skips += 1
+                       continue
+
                if "--font-funcs=ot" in options or not have_freetype:
                        glyphs1 = shape_cmd ([fontfile, "--font-funcs=ot"] + extra_options + ["--unicodes", unicodes] + options)
                else:
@@ -105,6 +121,7 @@ for filename in args:
                                passes += 1
 
                if glyphs1.strip() != glyphs_expected and glyphs_expected != '*':
+                       print ("hb-shape", fontfile, "--unicodes", unicodes, file=sys.stderr)
                        print ("Actual:   " + glyphs1, file=sys.stderr)
                        print ("Expected: " + glyphs_expected, file=sys.stderr)
                        fails += 1
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/language-persian/mehran.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/language-persian/mehran.txt
deleted file mode 100755 (executable)
index b5b670f..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-‫دَر فارسی گَچْ‌پَژْ هست. این «ی» فارسی است.‬
-‫حرف «ع» را به چٰهار شکلِ «ع‍» و «‍ع‍» و «‍ع» و «‌ع‌» می‌توان نشان داد.‬
-‫تشخیصِ اِعْ‌ًٌَُراب ناهمخوان از وظایف حروفْ‌چین است.‬
-‫دو اِعراب همخوان مانند « َ» و « ّ» به شکل « َّ» باهم ترکیب می‌شوند.‬
-‫لازم است حروف‌چین رفتار درستی با کشیدهٔ یونی‌کدی داشته باشد.‬
-‫مثلاً بتواند کلـمهٔ «پیِٓـــــــچ» یا حروف «ــٖٓـ» را به درستی نمایش دهد.‬
-‫حرف «لام» و «الف» باید به شکل لیگاتوری نمایش داده شوند.‬
-‫کلمهٔ «بَلَاٰ» از آزمون‌های سطح پائین حروف‌چین است.‬
\ No newline at end of file
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/2grams.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/2grams.txt
deleted file mode 100644 (file)
index 6b59920..0000000
+++ /dev/null
@@ -1,601 +0,0 @@
-با
-پا
-تا
-ٹا
-ثا
-جا
-چا
-حا
-خا
-سا
-شا
-صا
-ضا
-طا
-عا
-غا
-فا
-قا
-کا
-گا
-لا
-ما
-نا
-ہا
-ھا
-یا
-تب
-ٹب
-جب
-چب
-حب
-سب
-شب
-صب
-طب
-عب
-قب
-کب
-لب
-نب
-ہب
-ھب
-ئب
-یب
-بب
-غب
-رب
-تپ
-جپ
-چپ
-ٹپ
-شپ
-غپ
-کپ
-گپ
-لپ
-مپ
-نپ
-ہپ
-ھپ
-ئپ
-یپ
-پت
-تت
-ثت
-چت
-حت
-خت
-ست
-شت
-صت
-ضت
-طت
-ظت
-عت
-غت
-فت
-قت
-کت
-گت
-لت
-مت
-نت
-ہت
-ھت
-ئت
-یت
-ٹت
-جت
-بت
-پٹ
-ٹٹ
-جٹ
-چٹ
-سٹ
-غٹ
-فٹ
-کٹ
-گٹ
-لٹ
-مٹ
-نٹ
-ہٹ
-ھٹ
-ئٹ
-یٹ
-شٹ
-تٹ
-بٹ
-حث
-عث
-لث
-نث
-ئث
-یث
-بث
-پج
-تج
-جج
-حج
-سج
-کج
-لج
-نج
-ہج
-ھج
-ئج
-یج
-گج
-بج
-پچ
-جچ
-سچ
-کچ
-مچ
-نچ
-ئچ
-تچ
-چچ
-خچ
-غچ
-یچ
-گچ
-ٹچ
-بچ
-تح
-جح
-صح
-ضح
-لح
-مح
-نح
-یح
-شح
-فح
-ئح
-بح
-ٹخ
-چخ
-سخ
-لخ
-مخ
-نخ
-ئخ
-یخ
-پخ
-بخ
-پد
-تد
-جد
-چد
-حد
-خد
-سد
-شد
-صد
-ضد
-عد
-غد
-فد
-قد
-کد
-گد
-لد
-مد
-ند
-ہد
-ئد
-ید
-بد
-پڈ
-ٹڈ
-جڈ
-چڈ
-سڈ
-گڈ
-لڈ
-مڈ
-نڈ
-ہڈ
-ئڈ
-یڈ
-کڈ
-تڈ
-بڈ
-پذ
-تذ
-جذ
-حذ
-خذ
-شذ
-عذ
-غذ
-فذ
-قذ
-کذ
-لذ
-مذ
-نذ
-ہذ
-ئذ
-یذ
-گذ
-بذ
-پر
-تر
-ٹر
-ثر
-جر
-چر
-حر
-خر
-سر
-شر
-صر
-ضر
-طر
-ظر
-عر
-غر
-فر
-قر
-کر
-گر
-لر
-مر
-نر
-ہر
-ئر
-یر
-بر
-پڑ
-تڑ
-جڑ
-چڑ
-سڑ
-غڑ
-کڑ
-گڑ
-لڑ
-مڑ
-ہڑ
-ھڑ
-یڑ
-نڑ
-بڑ
-پز
-تز
-جز
-حز
-خز
-سز
-عز
-فز
-قز
-کز
-گز
-لز
-مز
-نز
-ہز
-ئز
-یز
-ٹز
-ٹز
-غز
-بز
-پژ
-کژ
-مژ
-نژ
-ہژ
-یژ
-پس
-تس
-ٹس
-جس
-چس
-خس
-حس
-فس
-قس
-کس
-گس
-لس
-مس
-نس
-ہس
-ئس
-یس
-ھس
-عس
-سس
-بس
-تش
-ٹش
-جش
-چش
-خش
-حش
-فش
-قش
-کش
-گش
-لش
-مش
-نش
-ہش
-ئش
-یش
-ھش
-عش
-شش
-بش
-قص
-لص
-نص
-ئص
-یص
-خص
-بص
-فض
-قض
-مض
-ئض
-یض
-غض
-کض
-بض
-خط
-سط
-قط
-ئط
-یط
-جع
-شع
-ضع
-طع
-فع
-قع
-لع
-مع
-نع
-ئع
-یع
-سع
-کع
-بع
-لغ
-یغ
-بغ
-تف
-حف
-سف
-شف
-صف
-طف
-عف
-غف
-فف
-قف
-لف
-نف
-ہف
-ئف
-یف
-خف
-کف
-گف
-بف
-چق
-حق
-سق
-شق
-طق
-فق
-لق
-مق
-نق
-ہق
-ئق
-یق
-بق
-پک
-تک
-ٹک
-جک
-چک
-سک
-شک
-فک
-کک
-لک
-مک
-ہک
-ھک
-ئک
-یک
-حک
-بک
-پگ
-تگ
-جگ
-چگ
-سگ
-لگ
-نگ
-یگ
-ہگ
-مگ
-گگ
-بگ
-پل
-تل
-ٹل
-لل
-مل
-نل
-ہل
-ھل
-ئل
-یل
-خل
-ثل
-بل
-تم
-ٹم
-ثم
-جم
-چم
-خم
-سم
-شم
-صم
-ضم
-عم
-غم
-فم
-قم
-کم
-گم
-لم
-نم
-ہم
-ھم
-ئم
-یم
-بم
-پن
-تن
-ٹن
-جن
-چن
-خن
-شن
-طن
-ظن
-عن
-فن
-قن
-کن
-گن
-لن
-من
-نن
-ہن
-ھن
-ئن
-ین
-غن
-بن
-یں
-پو
-تو
-ٹو
-ثو
-جو
-چو
-حو
-خو
-سو
-ضو
-عو
-غو
-فو
-قو
-کو
-گو
-لو
-مو
-نو
-ہو
-ھو
-ئو
-یو
-بو
-ئہ
-یئہ
-بی
-پی
-تی
-ٹی
-ثی
-جی
-چی
-حی
-خی
-سی
-شی
-صی
-ضی
-طی
-ظی
-عی
-غی
-فی
-قی
-کی
-گی
-لی
-می
-نی
-ہی
-ھی
-ئی
-بے
-پے
-تے
-ٹے
-ثے
-جے
-چے
-سے
-شے
-صے
-طے
-غے
-فے
-قے
-کے
-گے
-لے
-مے
-نے
-ہے
-ھے
-ئے
-خے
-حے
-ضے
-عے
-پہ
-تہ
-ثہ
-جہ
-چہ
-خہ
-سہ
-شہ
-صہ
-ضہ
-طہ
-عہ
-غہ
-فہ
-قہ
-کہ
-گہ
-لہ
-مہ
-یہ
-ہہ
-ٹہ
-بہ
-تھ
-ٹھ
-جھ
-چھ
-کھ
-گھ
-بھ
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/3grams.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/3grams.txt
deleted file mode 100644 (file)
index 4da97d2..0000000
+++ /dev/null
@@ -1,3415 +0,0 @@
-ببا
-بپا
-بتا
-بٹا
-بجا
-بچا
-بحا
-بخا
-بسا
-بشا
-بصا
-بضا
-بطا
-بظا
-بعا
-بغا
-بفا
-بقا
-بکا
-بگا
-بلا
-بما
-بنا
-بیا
-بہا
-بھا
-پتا
-پٹا
-پجا
-پچا
-پکا
-پسا
-پشا
-پکا
-پگا
-پلا
-پنا
-پیا
-پہا
-پھا
-تبا
-تپا
-تتا
-تٹا
-تجا
-تچا
-تحا
-تخا
-تسا
-تشا
-تصا
-تضا
-تطا
-تعا
-تغا
-تفا
-تقا
-تکا
-تگا
-تلا
-تما
-تنا
-تیا
-تہا
-تھا
-ٹبا
-ٹپا
-ٹتا
-ٹچا
-ٹکا
-ٹگا
-ٹلا
-ٹما
-ٹما
-ٹنا
-ٹیا
-ٹھا
-ثبا
-ثقا
-ثلا
-ثما
-ثنا
-ثیا
-جبا
-جپا
-جتا
-جٹا
-ججا
-جچا
-جحا
-جسا
-جغا
-جفا
-فکا
-جگا
-جلا
-جما
-جنا
-جیا
-جہا
-جھا
-چبا
-چپا
-چتا
-چٹا
-چچا
-چخا
-چخا
-چسا
-چغا
-چقا
-چکا
-چگا
-چلا
-چما
-چنا
-چیا
-چہا
-چھا
-حبا
-حجا
-حسا
-حشا
-حصا
-حضا
-حظا
-چغا
-حفا
-ھقا
-حکا
-حلا
-حما
-حنا
-حیا
-خبا
-ختا
-خٹا
-خجا
-خچا
-خحا
-خسا
-خشا
-خصا
-خضا
-خطا
-خفا
-خلا
-خما
-خنا
-خیا
-خہا
-سبا
-سپا
-ستا
-سٹا
-سجا
-سچا
-سحا
-سخا
-سسا
-سعا
-سفا
-سقا
-سکا
-سگا
-سلا
-سما
-سنا
-سیا
-سہا
-شبا
-شپا
-شتا
-شجا
-شچا
-شحا
-شخا
-شطا
-شعا
-شغا
-شفا
-شقا
-شکا
-شگا
-شما
-شنا
-شیا
-شہا
-صبا
-صحا
-صغا
-صفا
-صلا
-صما
-صنا
-صیا
-ضحا
-ضخا
-ضعا
-ضغا
-ضلا
-ضما
-ضیا
-طبا
-طپا
-طحا
-طعا
-طغا
-طفا
-طلا
-طما
-طنا
-طیا
-طہا
-ظلا
-ظہا
-عبا
-عتا
-عجا
-عسا
-عشا
-عصا
-عضا
-عطا
-عظا
-عفا
-عقا
-عکا
-علا
-عما
-عنا
-عیا
-غبا
-غپا
-غٹا
-غچا
-غسا
-غفا
-غلا
-غما
-غنا
-غیا
-فتا
-فٹا
-فجا
-فحا
-فسا
-فشا
-فصا
-فضا
-فطا
-فظا
-فعا
-فغا
-فقا
-فکا
-فگا
-فلا
-فما
-فنا
-فیا
-فہا
-قبا
-قتا
-قحا
-قسا
-قصا
-قضا
-قطا
-قعا
-قفا
-قلا
-قما
-قنا
-قیا
-قہا
-کبا
-کپا
-کتا
-کٹا
-کثا
-کجا
-کچا
-کحا
-کسا
-کشا
-کعا
-کفا
-ککا
-کگا
-کلا
-کما
-کنا
-کیا
-کہا
-کھا
-گبا
-گپا
-گتا
-گٹا
-گجا
-گچا
-گسا
-گلا
-گما
-گنا
-گیا
-گہا
-گھا
-لبا
-لپا
-لتا
-لٹا
-لثا
-لجا
-لچا
-لحا
-لخا
-لسا
-لشا
-لصا
-لطا
-لعا
-لغا
-لفا
-لقا
-لکا
-لگا
-لما
-لنا
-لیا
-لہا
-لھا
-مبا
-مپا
-متا
-مٹا
-مثا
-مجا
-مچا
-محا
-مخا
-مسا
-مشا
-مصا
-مضا
-مطا
-مظا
-معا
-مغا
-مفا
-مقا
-مکا
-مگا
-ملا
-مما
-منا
-میا
-مہا
-نبا
-نپا
-نتا
-نٹا
-نثا
-نجا
-نچا
-نحا
-نخا
-نسا
-نشا
-نصا
-نضا
-نظا
-نعا
-نفا
-نقا
-نکا
-نگا
-نلا
-مہا
-نبا
-نپا
-نتا
-نٹا
-نثا
-نجا
-نچا
-نحا
-نخا
-نسا
-نشا
-نصا
-نضا
-نما
-ننا
-نیا
-نہا
-نھا
-ئبا
-ئپا
-ئشا
-ئعا
-ئکا
-ئگا
-ئنا
-ئیا
-یبا
-یپا
-یتا
-یٹا
-یثا
-یجا
-یحا
-یخا
-یسا
-یشا
-یصا
-یضا
-یطا
-یعا
-یغا
-یفا
-یقا
-یکا
-یگا
-یلا
-یما
-ینا
-یئم
-یہا
-ہبا
-ہپا
-ہتا
-ہٹا
-ہجا
-ہچا
-ہسا
-ہشا
-ہفا
-ہقا
-ہکا
-ہگا
-ہلا
-ہما
-ہنا
-ہیا
-ھبا
-ھپا
-ھتا
-ھٹا
-ھجا
-ھسا
-ھکا
-ھگا
-ھلا
-ھما
-ھنا
-ھیا
-ھہا
-بلب
-بیب
-پھب
-تعب
-تکب
-تیب
-جست
-جلب
-جیب
-چھب
-حجب
-حسب
-حلب
-خطب
-سبب
-سلب
-سیب
-شعب
-شغب
-شیب
-صعب
-صلب
-طلب
-طیب
-عجب
-عصب
-عضب
-عقب
-عنب
-عیب
-ضصب
-غضب
-غلب
-غیب
-قطب
-قعب
-قلب
-قیب
-کتب
-کسب
-کعب
-کلب
-کیب
-کھب
-لطب
-لعب
-لقب
-لیب
-لہب
-محب
-مشب
-مطب
-نسب
-نصب
-نقب
-نیب
-یشب
-ینب
-ہیب
-بشپ
-پمپ
-پنپ
-پیپ
-تھپ
-ٹھپ
-جمپ
-جیپ
-جھپ
-چیپ
-چھپ
-سلپ
-سیپ
-فلپ
-کلپ
-کیپ
-کھپ
-گیپ
-گھپ
-لمپ
-لیپ
-میپ
-یمپ
-ینپ
-بپت
-بچت
-بخت
-بست
-بشت
-بعت
-بقت
-بنت
-بیت
-بہت
-بھت
-پتت
-پخت
-پست
-پشت
-پیت
-تبت
-تپت
-تحت
-تختتست
-تشت
-تمت
-تنت
-تیت
-ٹکت
-ثبت
-ثلت
-جست
-جعت
-جفت
-جگت
-جنت
-جیت
-جہت
-چپت
-چست
-چشت
-چکت
-چلت
-چنت
-چیت
-چھت
-حبت
-حجت
-حشت
-حفت
-حلت
-حمت
-حیت
-خست
-خشت
-کصت
-خفت
-خلت
-سبت
-سچت
-سخت
-سست
-سعت
-سفت
-سقت
-سکت
-سلت
-سمت
-سنت
-سیت
-شست
-شصت
-شفت
-شیت
-صحت
-صفت
-صلت
-صمت
-صیت
-ضیت
-طشت
-طفت
-طیت
-ظبت
-عفت
-علت
-عیت
-غبت
-غلت
-غیت
-فظت
-فعت
-فقت
-فیت
-قبت
-قعب
-قلت
-قیت
-کبت
-کپت
-کھت
-کشت
-کعت
-کلت
-کیت
-کھت
-گپت
-گست
-گشت
-گفت
-گمت
-گنت
-گیت
-لپت
-لجت
-لحت
-لخت
-لست
-لشت
-لغت
-لفت
-لگت
-للت
-لیت
-مست
-مشت
-معت
-مفت
-مکت
-ملت
-منت
-میت
-مہت
-نپت
-نست
-نعت
-نفت
-نکت
-نگت
-نیت
-ئیت
-یست
-یشت
-یعت
-یقت
-یمت
-ینت
-ہست
-ہشت
-ہفت
-ہمت
-ہیت
-ھست
-بجٹ
-بکٹ
-بلٹ
-بنٹ
-بیٹ
-بھٹ
-پسٹ
-پلٹ
-پیٹ
-پھٹ
-ٹسٹ
-ٹکٹ
-ٹنٹ
-ٹھٹ
-جسٹ
-جمٹ
-جنٹ
-جیٹ
-جھٹ
-چپٹ
-چکٹ
-چمٹ
-چنٹ
-چھٹ
-سٹٹ
-سکٹ
-سمٹ
-سیٹ
-شسٹ
-شفٹ
-شمٹ
-شیٹ
-فسٹ
-کپٹ
-کسٹ
-کشٹ
-کیٹ
-کھٹ
-گسٹ
-گشٹ
-گفٹ
-گلٹ
-گمٹ
-گیٹ
-گھٹ
-لپٹ
-لسٹ
-لشٹ
-لفٹ
-لنٹ
-لیٹ
-لہٹ
-مسٹ
-مشٹ
-مکٹ
-ملٹ
-منٹ
-میٹ
-نبٹ
-نپٹ
-نجٹ
-نسٹ
-نکٹ
-نگٹ
-نمٹ
-نیٹ
-یبٹ
-ئسٹ
-ئلٹ
-ئنٹ
-یبٹ
-یسٹ
-یکٹ
-ینٹ
-ہیٹ
-ھیٹ
-بحث
-بعث
-ثلث
-خبث
-شیث
-عبث
-نبث
-نیث
-بنج
-بیج
-بھج
-پنج
-پیج
-تہج
-تھج
-ٹیپ
-جھج
-سلج
-سیج
-سہج
-کنج
-کیج
-کھج
-گنج
-گیج
-لحج
-لنج
-لیج
-منج
-میج
-نپج
-نہج
-ینج
-ہپج
-بنچ
-بیچ
-بھچ
-پنچ
-پیچ
-پھچ
-تھچ
-ٹیج
-جکچ
-چمچ
-کلچ
-کیچ
-کھچ
-گھچ
-لنچ
-لیچ
-میچ
-نیچ
-ہیچ
-بیح
-جیح
-سطح
-سلح
-شیح
-صبح
-صلح
-صیح
-ضیح
-فتح
-فصح
-قبح
-لیح
-مسح
-ملح
-میخ
-نضح
-نفخ
-بطخ
-بلخ
-بیخ
-پٹخ
-تلخ
-تیخ
-ٹپخ
-چپخ
-چٹخ
-چیخ
-سیخ
-شیخ
-فسخ
-گٹخ
-مسخ
-مطخ
-ملخ
-میخ
-نسخ
-نفخ
-بتد
-بجد
-بحد
-بخد
-بسد
-بصد
-بضد
-بعد
-بغد
-بقد
-بگد
-بلد
-بمد
-بند
-بید
-بہد
-بھد
-پند
-پید
-پھد
-تبد
-تجد
-تحد
-تخد
-تسد
-تشد
-تصد
-تعد
-تقد
-تکد
-تمد
-تند
-تہد
-ثمد
-جسد
-جعد
-جلد
-جند
-جید
-جہد
-چغد
-چلد
-چند
-چید
-چھد
-حبد
-حسد
-حقد
-حمد
-حید
-ختہ
-خضد
-خلد
-خمد
-خند
-سبد
-ستد
-سجد
-سشد
-سعد
-سقد
-سمد
-سند
-سید
-شبد
-ششد
-شند
-شید
-شہد
-صفد
-صمد
-صند
-صید
-ضفد
-ضید
-عبد
-عتد
-عضد
-عقد
-عمد
-عند
-عید
-عہد
-غند
-غید
-فصد
-فعد
-فقد
-فند
-فید
-فہد
-قتد
-قصد
-قعد
-قند
-قید
-کند
-کید
-کھد
-گبد
-گلد
-گند
-گید
-لبد
-لحد
-لضد
-لعد
-لقد
-لکد
-لگد
-لمد
-لند
-لید
-مبد
-متد
-مجد
-محد
-محد
-مسد
-مشد
-مصد
-معد
-مقد
-مکد
-مگد
-ممد
-مند
-مید
-مہد
-نبد
-نتد
-نخد
-نسد
-نصد
-نعد
-نقد
-نگد
-نمد
-نند
-نہد
-ئمد
-ئند
-ئید
-یکد
-یگد
-یلد
-یند
-ہبد
-ہتد
-ہلد
-ہمد
-ہند
-ہید
-ھگد
-ھند
-بلڈ
-بنڈ
-بیڈ
-پگڈ
-پنڈ
-پیڈ
-پھڈ
-تکڈ
-تگڈ
-تنڈ
-ٹنڈ
-ٹھڈ
-جنڈ
-جھڈ
-چلڈ
-چنڈ
-سٹڈ
-سنڈ
-سیڈ
-شلڈ
-شیڈ
-غنڈ
-ئیڈ
-فنڈ
-فیڈ
-کبڈ
-کمڈ
-کنڈ
-کیڈ
-کھڈ
-گٹڈ
-کلڈ
-گنڈ
-گیڈ
-لنڈ
-لیڈ
-مکڈ
-مگڈ
-منڈ
-میڈ
-نیڈ
-ئٹڈ
-ئلڈ
-ئیڈ
-یجڈ
-یلڈ
-ینڈ
-ہلڈ
-ہنڈ
-ہیڈ
-ھنڈ
-بتذ
-پھڈ
-تبذ
-تحذ
-تعذ
-تغذ
-تکذ
-تلذ
-تہذ
-ٹھڈ
-جعد
-حبذ
-عتذ
-کیڈ
-لبذ
-لحز
-لقذ
-مبذ
-متذ
-مجذ
-محذ
-مخذ
-معذ
-مکذ
-ملذ
-منذ
-مہذ
-ہکذ
-ہگذ
-ببر
-بتر
-بٹر
-بجر
-بحر
-بخر
-بسر
-بشر
-بصر
-بطر
-بغر
-بفر
-بقر
-بکر
-بگر
-بلر
-بمر
-بنر
-بیر
-بہر
-بھر
-پتر
-پٹر
-پچر
-پسر
-پنر
-پیر
-پہر
-پھر
-تبر
-تپر
-تتر
-تٹر
-تجر
-تحر
-تخر
-تسر
-تشر
-تصر
-تضر
-تعر
-تغر
-تفر
-تقر
-تکر
-تگر
-تمر
-تنر
-تیر
-تہر
-تھر
-ٹبر
-ٹٹر
-ٹخر
-ٹسر
-ٹکر
-ٹمر
-ٹنر
-ٹیڈ
-ٹہر
-ٹھر
-ثمر
-ثیر
-جبر
-جتر
-جغر
-جفر
-جکر
-جگر
-جمر
-جنر
-جیر
-جہر
-جھر
-چپر
-چتر
-چٹر
-چسر
-چشر
-چفر
-چقر
-چکر
-چمر
-چنر
-چیر
-چہر
-چھر
-حتر
-حجر
-حسر
-حشر
-حصر
-حضر
-حفر
-حقر
-حمر
-حیر
-خبر
-ختر
-خچر
-خسر
-خشر
-خصر
-خضر
-خطر
-خفر
-خگر
-خمر
-خیر
-سپر
-ستر
-سٹر
-سجر
-سچر
-سحر
-سسر
-سطر
-سفر
-سقر
-سکر
-سگر
-سمر
-سیر
-سہر
-شبر
-شپر
-شتر
-شٹر
-شجر
-شطر
-شعر
-شغر
-شکر
-شگر
-شمر
-شیر
-شہر
-صبر
-صحر
-صطر
-صعر
-صغر
-صفر
-صہر
-ضطر
-طبر
-طغر
-طنز
-طیر
-طہر
-ظفر
-ظہر
-عبر
-عتر
-عسر
-عشر
-عصر
-عطر
-عفر
-عقر
-عکر
-عمر
-غٹر
-غفر
-غیر
-فتر
-فٹر
-فجر
-فخر
-فسر
-فشر
-فطر
-فغر
-ففر
-فقر
-فکر
-فلر
-فنر
-فیر
-فہر
-قبر
-قتر
-قشر
-قصر
-قطر
-قعر
-قلر
-قمر
-قیر
-قہر
-کبر
-کتر
-کٹر
-کثر
-کجر
-کچر
-کسر
-کثر
-کفر
-ککر
-کگر
-کلر
-کمر
-کیر
-کہر
-کھر
-گبر
-گٹر
-گجر
-گگر
-گلر
-گمر
-گنر
-گیر
-گہر
-گھر
-لبر
-لتر
-لٹر
-لجر
-لچر
-لھر
-لخر
-لشر
-لضر
-لطر
-لعر
-لغر
-لفر
-لقر
-لکر
-لگر
-لمر
-لنر
-لیر
-لہر
-مبر
-مپر
-متر
-مٹر
-مجر
-مچر
-محر
-مخر
-مسر
-مشر
-مصر
-مضر
-مطر
-معر
-مغر
-مفر
-مقر
-مکر
-مگر
-ملر
-ممر
-منر
-میر
-مہر
-نبر
-نتر
-نٹر
-نثر
-نجر
-نحر
-نخر
-نسر
-نشر
-نصر
-نظر
-نعر
-نفر
-نقر
-نکر
-نگر
-نمر
-نئر
-نیر
-نہر
-ئبر
-ئٹر
-ئکر
-ئمر
-ئنر
-ئیر
-ئہر
-یبر
-یپر
-یٹر
-یثر
-یجر
-یچر
-یخر
-یسر
-یشر
-یفر
-یکر
-یگر
-یلر
-یمر
-ینر
-یئر
-یہر
-ہبر
-ہتر
-ہٹر
-ہجر
-ہچر
-ہکر
-ہلر
-ہمر
-ہنر
-ہیر
-ھبر
-ھچر
-ھگر
-گیر
-بگڑ
-بنڑ
-بیڑ
-بھڑ
-پبڑ
-پٹڑ
-پجڑ
-پکڑ
-پگڑ
-پلڑ
-پیڑ
-پھڑ
-تپڑ
-تکڑ
-تگڑ
-تلڑ
-تیڑ
-تھڑ
-ٹکڑ
-ٹیر
-ٹھڑ
-جبڑ
-جکڑ
-جھڑ
-چبڑ
-چبڑ
-چپڑ
-چچڑ
-چسڑ
-چکڑ
-چمڑ
-چیڑ
-چھڑ
-سپڑ
-سکڑ
-سیڑ
-کبڑ
-کپڑ
-کچڑ
-ککڑ
-کلڑ
-کنڑ
-کیڑ
-کھڑ
-گپڑ
-گیڑ
-گھڑ
-لبڑ
-لپڑ
-لکڑ
-لگڑ
-لٹر
-لہڑ
-لھڑ
-مپڑ
-مسڑ
-مکڑ
-منڑ
-میڑ
-نبڑ
-نپڑ
-نتڑ
-نچڑ
-نسڑ
-نکڑ
-نگڑ
-نیڑ
-نہڑ
-ئیڑ
-یکڑ
-یہڑ
-ہبڑ
-ہپڑ
-ہیڑ
-ہجڑ
-ہلڑ
-ہمڑ
-ہنڑ
-ہیڑ
-ھبڑ
-ھکڑ
-ھگڑ
-ھیڑ
-بجز
-بلز
-بیز
-بہز
-پیز
-تجز
-تحز
-تعز
-تغز
-تنز
-تیز
-ٹیڑ
-چکز
-چیز
-حمز
-حیز
-خیز
-خنز
-سبز
-سلز
-سیز
-شلز
-شیز
-شہز
-طنز
-عتز
-عجز
-غمز
-فلز
-فیز
-قلز
-کبز
-کمز
-کنز
-کیز
-گلز
-گیز
-لتز
-لجز
-لحز
-لعز
-لغز
-لقز
-لنز
-لیز
-متز
-محز
-مخز
-مسز
-معز
-مغز
-ملز
-ممز
-منز
-میز
-نتز
-نغز
-نگز
-نلز
-نیز
-ئلز
-ئنز
-ئیز
-یگز
-یلز
-یمز
-ہتز
-ہلز
-ہمز
-ہیز
-لگژ
-بکس
-بلس
-بنس
-بیس
-بھس
-پٹس
-پنس
-پیس
-پھس
-تٹس
-تحس
-تکس
-تیس
-تہس
-ٹپس
-ٹکس
-ٹلس
-ٹنس
-ٹیز
-ٹھس
-جنس
-جیس
-چکس
-چیس
-حبس
-خمس
-خیس
-سٹس
-سمس
-سیس
-شپس
-شمس
-طلس
-طیس
-عکس
-فلس
-فنس
-فیس
-قفس
-قیس
-کتیس
-کلس
-کنس
-کھس
-گلس
-گیس
-گھس
-لپس
-لٹس
-لکس
-لمس
-لنس
-لیس
-مکس
-مگس
-ملس
-منس
-میس
-نٹس
-نجس
-نحس
-نسس
-نفس
-نکس
-ینس
-ئٹس
-ئنس
-ئیس
-یبس
-یٹس
-یسس
-یشس
-یکس
-یلس
-ینس
-ٹیس
-جیش
-حبش
-خفش
-سپش
-ستش
-شیش
-طپش
-طیش
-عطش
-عیش
-فحش
-فلش
-کشش
-کفش
-کنش
-کیش
-کفش
-کنش
-لکش
-منش
-میش
-نجش
-نعش
-نقش
-نگش
-نمش
-نیش
-ئیش
-یشش
-یعش
-ینش
-ہفش
-ہیش
-حصص
-حفص
-حیص
-شخص
-قصص
-نقص
-بعض
-بغض
-بیض
-حیض
-غیض
-فیض
-قبض
-محض
-میض
-نبض
-نقض
-بخط
-خبط
-خلط
-سبط
-سقط
-شخط
-ضبط
-غلط
-غیط
-فقط
-قحط
-قسط
-لخط
-لفط
-لقط
-حفظ
-غیظ
-لحظ
-لفظ
-بمع
-بیع
-تبع
-تسع
-تفع
-جمع
-جیع
-سبع
-سجع
-سمع
-سیع
-شجع
-شمع
-صطع
-صنع
-صیع
-ضلع
-ضیع
-طبع
-طمع
-فیع
-قطع
-قلع
-قمع
-قیع
-منع
-نطع
-نفع
-تیغ
-میغ
-نیغ
-بلف
-بیف
-تلف
-جیف
-چیف
-حلف
-حیف
-خلف
-خیف
-سقف
-سلف
-سیف
-شغف
-شلف
-صحف
-صنف
-صیف
-ضعف
-ضیف
-عطف
-علف
-قیف
-کتف
-کشف
-کلف
-کنف
-کیف
-کہف
-گلف
-لصف
-کطف
-کیف
-نجف
-نصف
-نیف
-بحق
-بلق
-بہق
-بھق
-پتق
-پھق
-تتق
-ثیق
-جلق
-حلق
-حمق
-حیق
-خلق
-سبق
-شفق
-شلق
-ضیق
-طبق
-عشق
-عمق
-فتق
-فسق
-سیق
-قلق
-قیق
-لحق
-لیق
-مشق
-نبق
-نسق
-نطق
-نیق
-بتک
-بٹک
-بچک
-بطک
-بلک
-بنک
-بیک
-بہک
-بھک
-پٹک
-پچک
-پلک
-پنک
-پیک
-پھک
-تپک
-تتک
-تشک
-تلک
-تنک
-تیک
-تھک
-ٹپک
-ٹسک
-ٹنک
-ٹیش
-ٹھک
-جبک
-جھک
-چبک
-چپک
-چٹک
-چسک
-چشک
-چلک
-چمک
-چنک
-چیک
-چہک
-چھک
-ختک
-خٹک
-خسک
-خشک
-خنک
-سبک
-ستک
-سٹک
-سسک
-سلک
-سمک
-سنک
-شلک
-ضحک
-غٹک
-غلک
-کبک
-کتک
-کٹک
-کسک
-کفک
-کلک
-کمک
-کنک
-کیک
-گٹک
-گجک
-گلک
-گمک
-گہم
-لپک
-لٹک
-لچل
-للک
-لنک
-لیک
-لہک
-مٹک
-مچک
-محک
-مسک
-مشک
-ملک
-میک
-مہک
-نسک
-نمک
-نیک
-ئیک
-یبک
-یپک
-یشک
-یفک
-یمک
-ینک
-ہبک
-ہتک
-ہچک
-ہلک
-ہمک
-ہنک
-کیک
-ھجک
-ھچک
-ھسک
-ھلک
-ھمک
-ھنک
-بنگ
-بیگ
-بھگ
-پلگ
-پنگ
-تنگ
-ٹنگ
-ٹیک
-جلگ
-جنگ
-چنگ
-خنگ
-سلگ
-سنگ
-سیگ
-شنگ
-کنگ
-کھگ
-گمگ
-گنگ
-لنگ
-لیگ
-منگ
-میگ
-ننگ
-نیگ
-ئنگ
-ینگ
-ہلگ
-ہنگ
-ہیگ
-ھنگ
-ببل
-بچل
-بحل
-بخل
-بصل
-بطل
-بعل
-بغل
-بقل
-بکل
-بگل
-بیل
-بہل
-بھل
-پبل
-پپل
-پتل
-پٹل
-پگل
-پیل
-پہل
-پھلتکل
-تیل
-تھل
-ٹکل
-ٹیگ
-ٹہل
-ثقل
-ثیل
-جبل
-جعل
-جکل
-جگل
-جمل
-جیل
-جہل
-جھل
-چبل
-چپل
-چغل
-چکل
-چمل
-چیل
-چہل
-چھل
-حبل
-حصل
-حلل
-حمل
-حیل
-خجل
-خلل
-خیل
-سبل
-ستل
-سٹل
-سجل
-سچل
-سفل
-سکل
-سگل
-سنل
-سیل
-سہل
-شطل
-شغل
-شکل
-شگل
-شیل
-صصل
-صنل
-صیل
-طبل
-طفل
-عسل
-عضل
-عقل
-علل
-عمل
-عیل
-غسل
-فحل
-فصل
-فضل
-فعل
-فیل
-قبل
-قتل
-قفل
-قیل
-کبل
-کپل
-کتل
-کچل
-کحل
-کسل
-کشل
-کفل
-کمل
-کیل
-کہل
-کھل
-گپل
-گٹل
-گسل
-گھل
-لعل
-لغل
-لیل
-مٹل
-مثل
-مچل
-محل
-مخل
-مضل
-مغل
-ملل
-میل
-نبل
-نپل
-نچل
-نحل
-نخل
-نسل
-نشل
-نصل
-نعل
-نفل
-نقل
-نکل
-نگل
-نیل
-ئبل
-ئٹل
-ئفل
-ئقل
-ئنل
-ئیل
-یشل
-یکل
-یگل
-ینل
-ہبل
-ہیل
-ھیل
-بسم
-بکم
-بلم
-بیم
-بہم
-پتم
-پٹم
-پچم
-پسم
-پشم
-پنم
-پیم
-پتم
-تخم
-تیم
-تھم
-ٹیل
-ثیم
-جسم
-جنم
-جیم
-جھم
-چشم
-چلم
-چھم
-حجم
-حشم
-حضم
-حکم
-حلم
-حیم
-ختم
-حشم
-خیم
-ستم
-سقم
-سکم
-سلم
-سیم
-سہم
-ششم
-شکم
-شلم
-شیم
-صنم
-طعم
-ظلم
-عجم
-عظم
-علم
-عیم
-غلم
-فلم
-فیم
-قسم
-قلم
-قیم
-کٹم
-کسم
-کلم
-کیم
-کھم
-گلم
-گیم
-گھم
-لبم
-لحم
-لکم
-لیم
-مسم
-مغم
-منم
-میم
-مہم
-نجم
-نظم
-نعم
-نکم
-نگم
-نیم
-نہم
-ئٹم
-یتم
-یٹم
-یشم
-یغم
-یکم
-ینم
-یئم
-ہضم
-ہمم
-ہیم
-ھکم
-کیم
-بٹن
-بچن
-بشن
-بطن
-بین
-بہن
-بھن
-پتن
-پٹن
-پشن
-پمن
-پین
-پہن
-پھن
-تپن
-تکن
-تلن
-تمن
-تین
-تہن
-تھن
-ٹپن
-ٹسن
-ٹفن
-ٹیم
-ٹھن
-ثمن
-ثین
-جبن
-جتن
-جشن
-جگن
-جلن
-جمن
-جین
-جھن
-چپن
-چکن
-چلن
-چمن
-چین
-چھن
-حسن
-حصن
-حین
-ختن
-خین
-سپن
-ستن
-سٹن
-سجن
-سخن
-سشن
-سقن
-سمن
-سنن
-سین
-سہن
-شکن
-شگن
-شمن
-شین
-صحن
-ضمن
-ضین
-طعن
-طین
-عین
-غبن
-غین
-فتن
-فٹن
-فگن
-فمن
-فین
-قطن
-قین
-کجن
-کچن
-کشن
-کفن
-کلن
-کین
-کہن
-کھن
-گگن
-گین
-گہن
-گھن
-لبن
-لٹن
-لجن
-لحن
-لسن
-لعن
-لفن
-لگن
-لمن
-لنن
-لین
-لہن
-لھن
-متن
-مٹن
-محن
-مسن
-مشن
-مکن
-مگن
-ملن
-منن
-مین
-نجن
-نشنر
-نگن
-نمن
-نین
-نہن
-ئین
-یپن
-یجن
-یشن
-یکن
-یگن
-یلن
-یمن
-ہمن
-ہین
-بیں
-پیں
-ٹیں
-ثین
-جیں
-چیں
-حیں
-خیں
-سیں
-شیں
-عیں
-کیں
-گیں
-لیں
-میں
-نیں
-ئیں
-ہیں
-ھیں
-ببو
-بپو
-بتو
-بٹو
-بجو
-پچو
-پسو
-پشو
-پکو
-پگو
-پلو
-پنو
-پئو
-پیو
-پھو
-تبو
-تپو
-تجو
-تچو
-تحو
-تخو
-تسو
-تشو
-تصو
-تضو
-تطو
-تعو
-تفو
-تقو
-تکو
-تگو
-تلو
-تمو
-تنو
-تیو
-تہو
-تھو
-ٹپو
-ٹٹو
-ٹچو
-ٹسو
-ٹشو
-ٹکو
-ٹلو
-ٹنو
-ٹیز
-ٹہو
-ٹھو
-ثبو
-ثپو
-ثتو
-ثمو
-جبو
-جپو
-جتو
-جٹو
-ججو
-جچو
-جسو
-جعو
-جلو
-جمو
-جنو
-جئو
-جیو
-جھو
-چبو
-چپو
-چتو
-چٹو
-چچو
-چخو
-چسو
-چقو
-چکو
-چگو
-چلو
-چمو
-چنو
-چیو
-چھو
-حبو
-حتو
-حثو
-حشو
-حصو
-حضو
-حظو
-حقو
-حکو
-حلو
-حنو
-حیو
-ختو
-خسو
-خشو
-خصو
-خضو
-خطو
-خلو
-خمو
-خنو
-خیو
-سبو
-سپو
-ستو
-سٹو
-سجو
-سچو
-سحو
-سشو
-سطو
-سعو
-سفو
-سقو
-سکو
-سگو
-سلو
-سمو
-سنو
-سیو
-سہو
-شبو
-شپو
-شتو
-ششو
-شعو
-شفو
-شقو
-شکو
-شگو
-شلو
-شمو
-شنو
-شیو
-شہو
-صبو
-صتو
-صحو
-صعو
-صفو
-صلو
-صنو
-ضتو
-ضحو
-ضعو
-طبو
-طفو
-طلو
-طنو
-طیو
-طہو
-ظتو
-ظلو
-ظنو
-ظہو
-عبو
-عتو
-عجو
-عشو
-عضو
-عطو
-عظو
-عفو
-عقو
-علو
-عمو
-عنو
-عیو
-غفو
-غلو
-غمو
-غنو
-غیو
-فتو
-فٹو
-فجو
-فحو
-فسو
-فصو
-فضو
-فظو
-فعو
-فقو
-فلو
-فنو
-فیو
-فہو
-قبو
-قپو
-قتو
-قسو
-قشو
-قصو
-قطو
-قعو
-قفو
-قلو
-قمو
-قنو
-قیو
-قہو
-کبو
-کتو
-کتو
-کٹو
-کچو
-کسو
-کشو
-کفو
-کلو
-کمو
-کنو
-کیو
-کہو
-کھو
-کو
-گپو
-گتو
-گٹو
-گجو
-گلو
-گمو
-گنو
-گئو
-گیو
-گہو
-گھو
-لبو
-لپو
-لتو
-لٹو
-لثو
-لجو
-لچو
-لحو
-لخو
-لسو
-لشو
-لصو
-لضو
-لطو
-لعو
-لغو
-لفو
-لقو
-لکو
-لگو
-للو
-لمو
-لنو
-لیو
-لہو
-لھو
-مپو
-متو
-مٹو
-مجو
-مچو
-جحو
-مخو
-مسو
-مشو
-مصو
-مطو
-مغو
-مقو
-مکو
-مگو
-ملو
-ممو
-منو
-مئو
-میو
-مہو
-مھو
-نبو
-نپو
-نتو
-نٹو
-نجو
-نچو
-نحو
-نخو
-نسو
-نشو
-نصو
-نطو
-نظو
-نعو
-نفو
-نقو
-نکو
-نگو
-نلو
-نمو
-ننو
-نیو
-نہو
-نھو
-ئبو
-ئپو
-ئتو
-ئٹو
-ئخو
-خشو
-ئفو
-ئقو
-ئکو
-ئلو
-ئنو
-ئیو
-یبو
-یپو
-یتو
-یٹو
-یثو
-یجو
-یخو
-یسو
-یشو
-یضو
-یعو
-یفو
-یقو
-یکو
-یگو
-یلو
-یمو
-ینو
-یئو
-یہو
-ہبو
-ہپو
-ہتو
-ہٹو
-ہجو
-ہشو
-ہضو
-ہفو
-ہکو
-ہگو
-ہلو
-ہمو
-ہنو
-ہیو
-ھبو
-ھپو
-ھتو
-ھجو
-ھکو
-ھگو
-ھلو
-ھنو
-ھیو
-مو
-ببی
-بتی
-بٹی
-بجی
-بچی
-بسی
-بطی
-بکی
-بلی
-بنی
-بئ
-بہی
-بھی
-بی
-پتی
-پٹی
-پجی
-پچی
-پخی
-پسی
-پشی
-پکی
-پلی
-پنی
-پئ
-تھی
-تبی
-تپی
-تتی
-تپی
-تجی
-تچی
-تشی
-تقی
-تکی
-تگی
-تلی
-تمی
-تنی
-تئ
-تہی
-تھی
-ٹپی
-ٹتی
-ٹٹی
-ٹچی
-ٹکی
-ٹگی
-ٹلی
-ٹمی
-ٹنی
-ٹھی
-ثتی
-جبی
-جپی
-جتی
-جٹی
-ججی
-جچی
-جعی
-جگی
-جلی
-جمی
-جنی
-جئ
-جہی
-جھی
-چبی
-چپی
-چتی
-چٹی
-چجی
-چچی
-چکی
-چگی
-چلی
-چنی
-چھی
-حبی
-حتی
-حسی
-حشی
-حظی
-حقی
-حلی
-حمی
-حئ
-ختی
-خشی
-خصی
-خطی
-خفی
-خلی
-خمی
-خنی
-خسپی
-ستی
-سٹی
-سجی
-سچی
-سخی
-سی
-سطی
-سعی
-سفی
-سکی
-سگی
-سلی
-سمی
-سنی
-سئ
-سہی
-سی
-شتی
-ششی
-شطی
-شقی
-شکی
-شمی
-شنی
-شہی
-صبی
-صتی
-صفی
-صگی
-صلی
-ضتی
-ضعی
-ظگی
-ضی
-طبی
-طمی
-طنی
-ظتی
-ظمی
-ظنی
-عتی
-عفی
-علی
-عمی
-عنی
-عئ
-غبی
-غپی
-غشی
-غلی
-غمی
-غنی
-فتی
-فجی
-فضی
-فعی
-فقی
-فگی
-فلی
-فمی
-فنی
-قتی
-قشی
-قصی
-قعی
-قلی
-قمی
-کبی
-کپی
-کتی
-کٹی
-کجی
-کچی
-کسی
-کشی
-کلی
-کمی
-کنی
-کہی
-کھی
-گبی
-گپی
-گتی
-گٹی
-گجی
-گچی
-گلی
-گمی
-گنی
-گئ
-گہی
-گھی
-لبی
-لپی
-لتی
-لٹی
-لثیمتی
-لجی
-لچی
-لسی
-لشی
-لعی
-لفی
-لکی
-لگی
-للی
-لمی
-لنی
-لہہ
-لی
-متی
-مٹی
-مجی
-مچی
-م]ی
-مسی
-مشی
-معی
-مکی
-مگی
-ملی
-ممی
-منی
-مہی
-نبی
-نپی
-نتی
-نٹی
-نجی
-نچی
-نسی
-نشی
-نفی
-نقی
-نکی
-نگی
-نلی
-نمی
-نلی
-نئ
-نہی
-نھی
-نی
-ئبی
-ئتی
-ئٹی
-ئچی
-ئسی
-ئشی
-ئقی
-ئکی
-ئلی
-ئمی
-ئنی
-یبی
-ہتی
-ہٹی
-ہفی
-ہکی
-ہگی
-ہلی
-ہمی
-ہنی
-ہئ
-ھپی
-ھتی
-ھجی
-ھکی
-ھگی
-ھلی
-ھنی
-ھئ
-بتے
-بٹے
-بجے
-بچے
-بسے
-بطے
-بعے
-بفے
-بقے
-بکے
-بلے
-بنے
-بۓ
-بہے
-بھے
-پتے
-پٹے
-پجے
-پچے
-پسے
-پشے
-پکے
-پلے
-پنے
-پۓ
-تبے
-تپے
-تتے
-تٹے
-تجے
-تچے
-تسے
-تشے
-تکے
-تگے
-تلے
-تمے
-تنے
-تۓ
-تھے
-ٹپے
-ٹتے
-ٹچے
-ٹکے
-ٹگے
-ٹلے
-ٹنے
-ٹۓ
-ٹھے
-جبے
-جپے
-جتے
-جٹے
-جثے
-جچے
-جسے
-جلے
-جمے
-جنے
-جۓ
-چھے
-حثے
-حصے
-حظے
-حقے
-حلے
-ختے
-حچے
-حطے
-خلے
-خہے
-ستے
-سٹے
-سجے
-سچے
-سطے
-سکے
-سکے
-سلے
-سمے
-سنے
-سۓ
-سہے
-شپے
-شتے
-شقے
-شمے
-شۓ
-صلے
-ضمے
-عشے
-علے
-غصے
-غلے
-فتے
-فٹے
-فسے
-فظے
-فلے
-قبے
-قصے
-قعے
-کپے
-کتے
-کٹے
-کجے
-کچے
-کسے
-کشے
-ککے
-کلے
-کمے
-کنے
-کۓ
-کیے
-کہے
-کھے
-گپے
-گتے
-گٹے
-گجے
-گلے
-گمے
-گنے
-گۓ
-گہے
-گھے
-لبے
-لیے
-لتے
-لٹے
-لثے
-لجے
-لچے
-لحے
-لخے
-لصے
-لعے
-لکے
-لگے
-لمے
-لنے
-لۓ
-لہے
-لھے
-متے
-مٹے
-مچے
-مسے
-مکے
-ملے
-نلے
-ننے
-نۓ
-ئٹے
-ئچے
-ئفے
-ئقے
-ئلے
-یتے
-یجے
-یچے
-یسے
-یشے
-یضے
-یعے
-یفے
-یقے
-یکے
-یگے
-یلے
-یمے
-ینے
-یۓ
-ہبے
-ہتے
-ہٹے
-ہجے
-ہکے
-ہگے
-ہلے
-ہمے
-ہنے
-ہۓ
-ھبے
-ھپے
-ھتے
-ھٹے
-ھجے
-ھکے
-ھگے
-ھلے
-ھمے
-ھۓ
-بتہ
-بچہ
-بحہ
-بطہ
-بعہ
-بغہ
-بقہ
-بلہ
-بیہ
-پتہ
-پٹہ
-پشہ
-پکہ
-پلہ
-پنہ
-پیہ
-تبہ
-تحہ
-تکہ
-تگہ
-تمہ
-تنہ
-تیہ
-تہہ
-ثقہ
-ثیم
-جبہ
-جتہ
-جثہ
-جگہ
-بلہ
-بمہ
-جنہ
-جیہ
-جہہ
-چپہ
-چغہ
-چلہ
-چنہ
-حبہ
-حثہ
-حشہ
-حصہ
-حظہ
-حقہ
-حلہ
-حمہ
-حیہ
-ختہ
-حچہ
-حطہ
-حلہ
-حمہ
-حنہ
-سبہ
-سپہ
-سبہ
-سجہ
-سخہ
-سسہ
-سطہ
-سفہ
-سقہ
-سکہ
-سلہ
-سمہ
-سنہ
-سۂ
-سیہ
-شبہ
-شتہ
-شقہ
-شلہ
-شمہ
-شنہ
-شۂ
-شیہ
-صفہ
-صلہصیہ
-ضمہ
-ظیہ
-طبہ
-طفہ
-طقہطمہ
-طیہ
-طہ
-ظلہ
-ظمہ
-عشہ
-عصہ
-عقہ
-عنہ
-عیہ
-غصہ
-غلہ
-غنہ
-فتہ
-فحہ
-فضہ
-فطہ
-فظہ
-فعہ
-فقہ
-فلہ
-فیہ
-فہہ
-قبہ
-قتہ
-قجہ
-قشہ
-قصہ
-قعہ
-قفہ
-قلہ
-قمہ
-قیہ
-کشہ
-کلہ
-کنہ
-کیہ
-کہہ
-گتہ
-گجہ
-گلہ
-گنہ
-گیہ
-گہہ
-لبہ
-لتہ
-لثہ
-لجہ
-لچہ
-لحہ
-لخہ
-لسہ
-لصہ
-لعہ
-لغہ
-لفہ
-لقہ
-لکہ
-للہ
-لمہ
-لنہ
-لیہ
-لہہ
-لہ
-متہ
-مچہ
-مطہ
-معہ
-مکہ
-ملہ
-منہ
-میہ
-مہہ
-نبہ
-نجہ
-نچہ
-نحہ
-نسہ
-نشہ
-نقہ
-نکہ
-نگہ
-نیہ
-نہہ
-ئبہ
-ئتہ
-ئٹہ
-ئچہ
-ئشہ
-ئفہ
-ئقہ
-ئکہ
-ئلہ
-ئمہ
-ئنہ
-ئیہ
-یبہ
-یجہ
-یچہ
-یحہ
-یشہ
-یضہ
-یعہ
-یفہ
-یقہ
-یکہ
-یگہ
-یلہ
-یمہ
-ینہ
-ہبہ
-ہمہ
-ہنہ
-ہیہ
-بجہھ
-بچھ
-بکھ
-پتھ
-پٹھ
-پچھ
-پکھ
-تتھ
-تجھ
-جتھ
-جٹھ
-چبھ
-چکھ
-سبھ
-سٹھ
-سجھ
-سکھ
-شبھ
-کچھ
-گتھ
-گٹھ
-گچھ
-لتھ
-لجھ
-لچھ
-لکھ
-متھ
-مٹھ
-مجھ
-مچھ
-مکھ
-منھ
-نبھ
-نتھ
-نٹھ
-نجھ
-نچھ
-نکھ
-نگھ
-نبھ
-یچھ
-یکھ
-ہتھ
-ہنھ
-طمۃ
-بی
-سی
-ضی
-بعا
-تا
-سطا
-صلا
-ظتا
-فتا
-قتا
-لبا
-متا
-معا
-ملا
-یتا
-یحا
-یضا
-نیا
-ینا
-ہلا
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/4grams.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/4grams.txt
deleted file mode 100644 (file)
index e5494b7..0000000
+++ /dev/null
@@ -1,6316 +0,0 @@
-ببیا
-ببھا
-بپتا
-بپھا
-بتتا
-بتخا
-بتسا
-بتغا
-بتلا
-بتما
-بتنا
-بتیا
-بتہا
-بتھا
-بٹتا
-بٹنا
-بٹیا
-بٹھا
-بجتا
-بجما
-بجنا
-بجیا
-بجھا
-بچتا
-بچکا
-بچلا
-بچنا
-بچیا
-بچھا
-بحسا
-بحفا
-بختا
-بخشا
-بخلا
-بخیا
-بستا
-بسٹا
-بسطا
-بسلا
-بسما
-بسنا
-بسیا
-بسہا
-بطحا
-بطخا
-بطلا
-بعضا
-بغیا
-بقضا
-بکتا
-بکسا
-بکشا
-بکلا
-بکما
-بکنا
-بکیا
-بکھا
-بگلا
-بگیا
-بگھا
-بلتا
-بلٹا
-بلحا
-بلطا
-بلغا
-بلفا
-بلقا
-بلکا
-بلگا
-بلما
-بلنا
-بلیا
-بلہا
-بمبا
-بمطا
-بمقا
-بمنا
-بنتا
-بنٹا
-بنجا
-بنکا
-بنگا
-بننا
-بنیا
-بیبا
-بیتا
-بیٹا
-بیجا
-بیچا
-بیسا
-بیشا
-بیضا
-بیطا
-بیعا
-بیکا
-بیگا
-بیلا
-بیما
-بینا
-بہتا
-بہکا
-بہلا
-بہنا
-بہیا
-بھپا
-بھتا
-بھٹا
-بھجا
-بھچا
-بھسا
-بھکا
-بھگا
-بھلا
-بھما
-بھنا
-بھیا
-پبیا
-پپیا
-پتتا
-پتلا
-پتنا
-پتیا
-پتھا
-پٹتا
-پٹخا
-پٹکا
-پٹلا
-پٹنا
-پٹیا
-پٹھا
-پجتا
-پجنا
-پچتا
-پچکا
-پچلا
-پچنا
-پچیا
-پچھا
-پخنا
-پخیا
-پسپا
-پستا
-پسما
-پسنا
-پشتا
-پشیا
-پغما
-پکتا
-پکما
-پکنا
-پکھا
-پگلا
-پلتا
-پلٹا
-پلکا
-پلنا
-پلیا
-پنیا
-پنجا
-پجچا
-پنچا
-پنسا
-پنگا
-پنیا
-پنہا
-پنھا
-پیپا
-پیتا
-پیٹا
-پیجا
-پیچا
-پیخا
-پیسا
-پیشا
-پیغا
-پیکا
-پیلا
-پیما
-پینا
-پہچا
-پہلا
-پہنا
-پہیا
-پھبا
-پھپا
-پھٹا
-پھچا
-پھسا
-پھکا
-پھلا
-تبخا
-تبیا
-تپتا
-تپکا
-تپنا
-تتکا
-تتلا
-تتھا
-تجتا
-تجلا
-تجنا
-تچنا
-تچتا
-تحتا
-تحیا
-تسلا
-تسما
-تشنا
-مملکتو
-تغما
-تغیا
-تفتا
-تقیا
-تکلا
-تکھا
-تگلا
-تلتا
-تلخا
-تللا
-تلنا
-تلیا
-تمبا
-تمثا
-تمغا
-تغیا
-تمنا
-تمہا
-تنبا
-تنتا
-تنکا
-تنگا
-تننا
-تنیا
-تنہا
-تیجا
-تیسا
-تیغا
-تیلا
-تیما
-تیہا
-تھپا
-تھتا
-تھجا
-تھکا
-تھلا
-تھما
-تھنا
-تھیا
-ٹپتا
-ٹپکا
-ٹپنا
-ٹٹیا
-ٹچیا
-ٹخنا
-ٹسکا
-ٹکتا
-ٹکسا
-ٹکلا
-ٹکنا
-ٹکیا
-ٹگلا
-ٹلتا
-ٹلنا
-ٹمنا
-ٹنٹا
-ٹنچا
-ٹنکا
-ٹنگا
-ٹننا
-ٹنیا
-ٹئیا
-ٹیبا
-ٹیپا
-ٹیکا
-ٹیلا
-ٹینا
-ٹہلا
-ٹہنا
-ٹھتا
-ٹھسا
-ٹھکا
-ٹھگا
-ٹھلا
-ٹھبنا
-ٹھیا
-ثعبا
-جبیا
-جبہا
-جبھا
-جپتا
-جپکا
-جپنا
-جتتا
-جتلا
-جتما
-جتنا
-جتیا
-جتہا
-جتھا
-جٹتا
-جٹنا
-جٹھا
-ججما
-جچتا
-جچنا
-جسکا
-جسما
-جفتا
-جفنا
-جکما
-چھپا
-چھٹا
-جگنا
-جگیا
-جگتا
-جلبا
-جلتا
-جلکا
-جلنا
-جلیا
-جمتا
-جلیا
-جمتا
-جمخا
-جمنا
-جنبا
-جنتا
-جنٹا
-جنکا
-جنجا
-جنگا
-جننا
-جنیا
-جیتا
-جیجا
-جیحا
-جیسا
-جیعا
-جیلا
-جینا
-جیہا
-جہتا
-جہلا
-جھبا
-جھپا
-جھتا
-جھجا
-جھکا
-جھلا
-جھما
-جھنا
-چبتا
-چبتا
-چبکا
-چبلا
-چبنا
-چبھا
-چبتا
-چپتا
-چپٹا
-چبکا
-چپلا
-چبپا
-چپنا
-چتتا
-چبھا
-چپتا
-چپکا
-چپلا
-چپنا
-چتتا
-چتلا
-چتنا
-چتھا
-چٹتا
-چٹکا
-چٹلا
-چٹنا
-چٹیا
-چٹھا
-چچکا
-چچیا
-چسپا
-چستا
-چسکا
-چسنا
-چغتا
-چقما
-چکتا
-چکٹا
-چکسا
-چکلا
-چکما
-چکنا
-چکھا
-چگتا
-چگلا
-چگنا
-چلپا
-چلتا
-چلکا
-چلنا
-چلیا
-چمپا
-چمٹا
-چمکا
-چمگا
-چملا
-چمن
-چنبا
-چنتا
-چنگا
-چننا
-چنیا
-چیپا
-چیتا
-چیخا
-چیچا
-چیلا
-چینا
-چہتا
-چہکا
-چہلا
-چھپا
-چھتا
-چھٹا
-چھجا
-چھچا
-چھکا
-چھلا
-چھما
-چھنا
-حتجا
-حتسا
-حتشا
-حتصا
-حتضا
-حتظا
-حتکا
-حتلا
-حتما
-حتیا
-حسنا
-حسنا
-حسیا
-حشیا
-حفظا
-حکما
-حمقا
-حنفا
-حیفا
-ختتا
-ختصا
-ختکا
-ختگا
-ختلا
-ختیا
-خچیا
-خشحا
-خشخا
-خشا
-خشما
-خصتا
-خصما
-خطبا
-خفتا
-خفقا
-خفنا
-خلجا
-خلخا
-خلفا
-خلکا
-خلیا
-خمیا
-خنسا
-خنگا
-خنا
-خنیا
-خیسا
-خیفا
-خیلا
-سبحا
-سبلا
-سبھا
-سپتا
-سپلا
-سپنا
-ستتا
-ستجا
-ستحا
-ستخا
-ستشا
-ستطا
-ستعا
-ستغا
-ستفا
-ستقا
-ستکا
-ستگا
-ستلا
-ستما
-ستنا
-ستیا
-ستہا
-ستھا
-سٹکا
-سٹنا
-سٹیا
-سٹھا
-سجتا
-سجلا
-سجنا
-سجھا
-سچتا
-سچلا
-سچنا
-سختا
-سستا
-سسکا
-سسنا
-سفنا
-سفیا
-سکتا
-سکشا
-سکلا
-سکنا
-سکیا
-سکھا
-سگھا
-سلتا
-سلطا
-سلفا
-سلکا
-سلگا
-سلما
-سلنا
-سلیا
-سمبا
-پنچا
-پنسا
-پنگا
-پننا
-پنیا
-پنہا
-پنھا
-پیپا
-پیتا
-پیچا
-پیخا
-پیسا
-پیشا
-پیغا
-پیکا
-پیلا
-پیما
-پینا
-پہچا
-پہلا
-پہنا
-پہیا
-پھپا
-پھچا
-پھسا
-پھکا
-پھلا
-تبخا
-تبیا
-تپتا
-تتکا
-تتلا
-تتھا
-تجتا
-تجلا
-تچتا
-تچنا
-تحتا
-تحیا
-تسلا
-تسما
-تشنا
-مملکتو
-تغما
-تغیا
-تفتا
-تقیا
-تکلا
-تکھا
-تگلا
-تلتا
-تلخا
-تللا
-تلنا
-تمبا
-تمثا
-تمغا
-تمہا
-تنتا
-تنکا
-تنگا
-تننا
-تنہا
-تیجا
-تیسا
-تیغا
-تیلا
-تیما
-تیہا
-تھپا
-تھتا
-تھجا
-تھکا
-تھلا
-تھما
-تھنا
-تھیا
-ٹپتا
-ٹپکا
-ٹٹیا
-ٹچیا
-ٹخنا
-ٹسکا
-ٹکتا
-ٹکسا
-ٹکلا
-سمپا
-سمٹا
-سمسا
-سمنا
-سمیا
-سنپا
-سنتا
-سنجا
-سنسا
-سنکا
-سنگا
-سننا
-سنیا
-سنہا
-سیپا
-سیتا
-سیٹا
-سیکا
-سیگا
-سیلا
-سیما
-سینا
-سئیا
-سیہا
-سہتا
-سہلا
-سہما
-سہنا
-شبکا
-شبہا
-شتعا
-شتکا
-شتما
-شتیا
-شتہا
-ششکا
-ششما
-شمشا
-شعبا
-شفتا
-شقیا
-شکبا
-شکشا
-شکلا
-شکنا
-شگتا
-شگنا
-شگیا
-شلتا
-شلیا
-شمشا
-شمنا
-شنیا
-شیبا
-شیخا
-شیطا
-شیلا
-شیما
-شہبا
-شہکا
-شہلا
-شہنا
-صطبا
-صطلا
-صفحا
-صفیا
-صفہا
-صلحا
-صمصا
-صمنا
-صنعا
-صہبا
-ضعفا
-ضگیا
-ضلکا
-ضمحا
-ضیحا
-طبقا
-طفلا
-طغیا
-طلبا
-طمنا
-طمیا
-طیبا
-طہما
-ظلما
-ظلہا
-عتبا
-عتصا
-عتقا
-عتکا
-عتلا
-عتما
-عتنا
-عثما
-عصیا
-عضلا
-عطیا
-عقلا
-علما
-علیا
-عنقا
-عنہا
-عیسا
-غپکا
-غثیا
-غصیا
-غلطا
-غلغا
-غلما
-غلیا
-غمنا
-غنیا
-غیبا
-غیلا
-فبہا
-فتتا
-فتخا
-فتگا
-فتنا
-فسطا
-فصحا
-فصلا
-فضلا
-فعلا
-فقہا
-فلپا
-فلما
-فنجا
-فنکا
-فیتا
-فیسا
-فیضا
-فیلا
-فیما
-فیہا
-فہما
-قبلا
-قتبا
-قتصا
-قتضا
-قتلا
-قتیا
-قحطا
-قسما
-قشلا
-قصبا
-قطعا
-قلپا
-قلفا
-قلقا
-قلما
-قلیا
-قمقا
-قیبا
-قیما
-کبجا
-کبلا
-کبھا
-کپتا
-کتسا
-کتشا
-کتفا
-کتکا
-کتلا
-کتنا
-کتیا
-کتھا
-کٹتا
-کٹکا
-کٹنا
-کٹیا
-کٹھا
-کجتا
-کجلا
-کچلا
-کچنا
-کچیا
-کچھا
-کستا
-کسلا
-کسما
-کسنا
-کسیا
-کشتا
-کشٹا
-کشیا
-کفتا
-کفنا
-کفیا
-ککیا
-کلپا
-کلتا
-کلچا
-کلسا
-کلکا
-کلما
-کلنا
-کلیا
-کلہا
-کلھا
-کمبا
-کمپا
-کمتا
-کمکا
-کملا
-کمنا
-کمیا
-کمہا
-کمنی
-کنسا
-کنعا
-کنکا
-کنگا
-کنیا
-کنہا
-کنھا
-کیسا
-کیکا
-کیلا
-کینا
-کیہا
-کہتا
-کہلا
-کہنا
-کھبا
-کھپا
-کھتا
-کھٹا
-کھجا
-کھچا
-کھسا
-کھکا
-کھلا
-کھما
-کھنا
-کھیا
-گبھا
-گپتا
-گمنا
-گپیا
-گپھا
-گتکا
-گتیا
-گتھا
-گٹکا
-گٹھا
-گجیا
-گجھا
-گچھا
-گستا
-گشتا
-گسٹا
-گستا
-گشتا
-گشٹا
-گلبا
-گفتا
-گگلا
-گلتا
-گلشا
-گلفا
-گلکا
-گلنا
-گلیا
-گلہا
-گمتا
-گمگا
-گملا
-گمنا
-گمیا
-گنتا
-گنٹا
-گنجا
-گنگا
-گننا
-گنیا
-گیپا
-گیشا
-گیلا
-گینا
-گیہا
-گہتا
-گہکا
-گہگا
-گہما
-گہنا
-گھپا
-گھتا
-گھٹا
-گھچا
-گھسا
-گیشا
-گھلا
-گھما
-گھنا
-گھیا
-لبخا
-لبفا
-لبقا
-لبنا
-لبیا
-لبھا
-لپٹا
-لپسا
-لپشا
-لپکا
-لپنا
-لپھا
-لتبا
-لتجا
-لتغا
-لتفا
-لتما
-لتیا
-لتہا
-لتھا
-لٹتا
-لٹکا
-لٹنا
-لٹیا
-لٹھا
-لجبا
-لجلا
-لجما
-لجنا
-لجہا
-لجھا
-لچتا
-لچکا
-لچنا
-لچھا
-لحجا
-لحسا
-لحقا
-لخلا
-لستا
-لسٹا
-لسقا
-لسلا
-لسنا
-لشتا
-لشفا
-لشکا
-لصبا
-لصتا
-لصفا
-لطلا
-لعبا
-لعتا
-لعشا
-لعلا
-لعنا
-لعیا
-لغفا
-لغیا
-لفتا
-لفقا
-لفگا
-لفلا
-لفن
-لفیا
-لقتا
-لقضا
-لقفا
-لقما
-لقنا
-لقیا
-لقہا
-لکتا
-لکسا
-لکسا
-لکلا
-لکما
-لکنا
-لکیا
-لکھا
-لگتا
-لگما
-لگنا
-للچا
-للع
-للغا
-للفا
-للقا
-للکا
-لمبا
-لمثا
-لمجا
-لمحا
-لمخا
-لمسا
-لمشا
-لمضا
-لمطا
-لمعا
-لمفا
-لمقا
-لمکا
-لملا
-لمنا
-لمیا
-لنبا
-لنجا
-لنسا
-لنکا
-لنگا
-لنیا
-لنہا
-لنھا
-لیبا
-لیپا
-لیٹا
-لیجا
-لیخا
-لیسا
-لیتا
-لیچا
-لیشا
-لیفا
-لیکا
-لیگا
-لیلا
-لیما
-لینا
-لہٹا
-لہکا
-لہلا
-لہنا
-للہا
-مبنا
-مبیا
-مپنا
-متتا
-متحا
-متجا
-متخا
-متسا
-متصا
-متعا
-متفا
-متشا
-متضا
-متغا
-متقا
-متگا
-متلا
-متما
-متنا
-متیا
-متہا
-متھا
-مٹتا
-مٹکا
-مٹنا
-مٹیا
-مٹھا
-مثقا
-مجلا
-مجید
-مجھا
-مچتا
-مچکا
-مچلا
-مچنا
-محبا
-محتا
-محلا
-مختا
-مستا
-مسکا
-مسلا
-مسما
-مسنا
-مشتا
-مشٹا
-مشعا
-مشغا
-مصبا
-مصفا
-مصلا
-معتا
-معلا
-معما
-معیا
-مغلا
-مفتا
-مقنا
-مقیا
-مقتا
-مکتا
-مکٹا
-مکنا
-مکھا
-مگنا
-ملتا
-ملبا
-ملیا
-ملجا
-ملکا
-ملما
-ملنا
-ملہا
-ممبا
-ممتا
-ممیا
-منتا
-منجا
-منسا
-منشا
-منقا
-منکا
-منیا
-منگا
-مننا
-منہا
-منھا
-میبا
-میتا
-میٹا
-میجا
-میخا
-میسا
-میثا
-میچا
-میشا
-میعا
-میقا
-میکا
-میگا
-میلا
-میما
-مینا
-مہبا
-مہتا
-مہکا
-مہما
-مہنا
-مہیا
-نبٹا
-نبسا
-نبیا
-نبھا
-نپتا
-نپٹا
-نپنا
-نتبا
-نتتا
-نتخا
-نتشا
-نتصا
-نتظا
-نتفا
-نتقا
-نتنا
-نتیا
-نتہا
-نتھا
-نٹتا
-نٹھا
-نثبا
-نثیا
-نجبا
-نجنا
-نجہا
-نجھا
-نچتا
-نچسا
-نچکا
-نچلا
-نچنا
-نچیا
-نچھا
-نحصا
-نحطا
-نخشا
-نخلا
-نستا
-نسقا
-نسنا
-نسیا
-نسکا
-نضبا
-نصفا
-نضما
-نظما
-نعطا
-نعطا
-نعقا
-نعکا
-نعما
-نعنا
-نغما
-نفتا
-نفسا
-نفطا
-نفعا
-نفکا
-نقسا
-نقشا
-نقصا
-نقضا
-نقلا
-نقیا
-نکتا
-نکسا
-نکشا
-نکلا
-نکما
-نکنا
-نکھا
-نگتا
-نگسا
-نگتا
-نگسا
-نگلا
-نگنا
-نگیا
-نگھا
-نلٹا
-نلکا
-نلیا
-نمٹا
-نمنا
-ننکا
-ننگا
-ننیا
-ننھا
-نیپا
-نیتا
-نیچا
-نیسا
-نیشا
-نیفا
-نیکا
-نیگا
-نیلا
-نینا
-نہتا
-نہٹا
-نہضا
-نہلا
-نہما
-ئٹیا
-ئچیا
-ئشگا
-ئشیا
-ئمقا
-ئیسا
-ئیکا
-ئیگا
-یتنا
-یتیا
-یٹنا
-یٹھا
-یحتا
-یختا
-یستا
-کٹھا
-یختا
-یسپا
-یشما
-یشیا
-یغما
-یکبا
-یکتا
-یکجا
-یکسا
-یکیا
-یکھا
-یلٹا
-یلعا
-یلغا
-یلیا
-یمیا
-ینٹا
-ینکا
-ہٹنا
-ینگا
-ینیا
-ہبلا
-ہپتا
-ہتما
-ہٹتا
-ہجہا
-ہچکا
-ہسپا
-ہسکا
-ہشتا
-ہشکا
-ہسیا
-ہفتا
-ہکتا
-ہکلا
-ہکنا
-ہگتا
-ہگنا
-ہلتا
-ہلجا
-ہلسا
-ہلکا
-ہلگا
-ہلنا
-ہلیا
-ہمتا
-ہمچا
-ہمسا
-ہمکا
-ہمنا
-ہمیا
-ہنجا
-ہنسا
-ہنشا
-ہیکا
-ہیکا
-ہنگا
-ہنما
-ہنیا
-ہیٹا
-ہیجا
-ہیگا
-ہیلا
-ہیما
-ہیہا
-ھپتا
-ھپنا
-ہتکا
-ھتگا
-ھتیا
-ھجیا
-ھچکا
-ھسکا
-ھکتا
-ھکنا
-ھلتا
-ھلکا
-ھلنا
-ھمکا
-ھملا
-ھنتا
-ھنسا
-ھنکا
-ھنگا
-ھننا
-ھنیا
-ھیکا
-ھیگا
-ھیلا
-ھیما
-بجیب
-بخیب
-بسبب
-بطیب
-بلمب
-تعجب
-تعصب
-تعقب
-تغلب
-تقلب
-ثعلب
-ثقیب
-جیکب
-چنکب
-حبیب
-حسیب
-حلیب
-خطیب
-سلیب
-شعیب
-شکیب
-صلیب
-طبیب
-ظہیب
-عجیب
-غبغب
-قضیب
-قطیب
-قلیب
-کٹمب
-لبلب
-لبیب
-لطلب
-لعجب
-لعیب
-لغیب
-لقلب
-لکتب
-مجیب
-محب
-مطلب
-مطلب
-مکتب
-مکعب
-منصب
-منیب
-مہلب
-مہیب
-نجیب
-نخشب
-نشیب
-نصیب
-نقیب
-نہیب
-چھیپ
-سٹمپ
-سکیپ
-کیمپ
-کھیپ
-گیلپ
-لچسپ
-لیمپ
-ہلک
-ہیمپ
-بلیت
-بجہت
-بسنت
-بصحت
-بعثت
-بعلت
-بعیت
-بکیت
-بلیت
-بنجو
-بیبت
-بیعت
-بہجت
-بہشت
-بھبت
-بھکت
-بھگت
-بھنت
-بھیت
-پٹیت
-پچیت
-پلیت
-پنگت
-تحیت
-تعنت
-تہمت
-جبلت
-چپیت
-چکنت
-چلنت
-چمپت
-چھیت
-حبیت
-حسنت
-حسیت
-حشمت
-حقیت
-حکمت
-حمیت
-خجلت
-خشیت
-خصلت
-خلقت
-خلیت
-سبقت
-سبیت
-سجیت
-سچیت
-سلیت
-سمبت
-سمیت
-سنگت
-سینت
-شفقت
-شکست
-شگفت
-صحبت
-صلیت
-صنعت
-طلعت
-طینت
-ظلمت
-عجلت
-عصمت
-عظمت
-غفلت
-غلظت
-غیبت
-فصلت
-قسمت
-قعیت
-قفیت
-قلت
-قلیت
-قیمت
-کسبت
-کلفت
-کلیت
-کمیت
-کنشت
-کنیت
-کیست
-کھپت
-کھیت
-گلگت
-لحیت
-لسنت
-لصلت
-لعبت
-لعنت
-لکنت
-لکھت
-لگنت
-لمست
-لمیت
-مثبت
-مچکتی
-محبت
-محنت
-مسکت
-مسیت
-مشقت
-مشیت
-معیت
-منبت
-منت
-منیت
-میت
-مہلت
-مہنت
-مہیت
-نجیت
-نچنت
-نچیت
-نخست
-نسبت
-نسیت
-نشست
-نصفت
-نعمت
-نکبت
-نکہت
-نکھت
-نگشت
-نگہت
-نمنٹ
-نیست
-نہفت
-ئینت
-یکھت
-ینیت
-ہبیت
-ہسیت
-ہلگت
-ہلیت
-ہمیت
-ہنیت
-ہیبت
-ہئیت
-بسکٹ
-بسیٹ
-بگٹٹ
-بیلٹ
-بینٹ
-بھگت
-بھیٹ
-پلیٹ
-پیسٹ
-پیکٹ
-پینٹ
-پھپٹ
-پھکٹ
-پھیٹ
-تلپٹ
-ٹمنٹ
-ٹیسٹ
-ٹینٹ
-ٹھیٹ
-جمنٹ
-جیکٹ
-جھپٹ
-چپیٹ
-چمیٹ
-چیکٹ
-چینٹ
-چھنٹ
-سٹنٹ
-سٹیٹ
-سفیٹ
-سلپٹ
-سلیٹ
-سلہٹ
-سمپٹ
-سمیٹ
-سینٹ
-شلسٹ
-فلیٹ
-فیلٹ
-کسکٹ
-کلسٹ
-کلیٹ
-کمیٹ
-کیسٹ
-منگٹ
-نٹسٹ
-نگھٹ
-نلسٹ
-نمنٹ
-ئجسٹ
-یٹنٹ
-سبید
-یجنٹ
-یکیٹ
-یگیٹ
-یلیٹ
-تحنث
-خبیث
-لبعث
-للیث
-مبحث
-مثلث
-مخنث
-مغیث
-بھیج
-پسیج
-تشنج
-جھنج
-چینج
-چھیج
-خلیج
-ستلج
-سٹیج
-سفنج
-سکنج
-قلنج
-کلنج
-منتج
-منضج
-مہیج
-نٹیج
-نگیج
-نہیج
-بینچ
-بھنچ
-بھیچ
-پہنچ
-بھنچ
-تبیچ
-سپیچ
-سکیچ
-سینچ
-قینچ
-کھپچ
-کھنچ
-کھیچ
-گھنچ
-ملیچ
-صبیح
-صحیح
-فصیح
-قبیح
-لفتح
-مسبح
-مسطح
-مسلح
-مسیح
-مصلح
-مفتح
-ملیح
-بطیخ
-لشیخ
-مسلخ
-مطبخ
-بتکد
-بجند
-بحمد
-بعید
-بعہد
-بقید
-بلند
-بلید
-بیلد
-بیند
-بھگد
-بھند
-بھید
-پسند
-پلند
-پلید
-پنشد
-پیکد
-پیند
-پھبد
-پھپد
-پھلد
-پھند
-تشہد
-تعبد
-تعہد
-تقید
-تمند
-تیند
-تہجد
-تہمد
-ٹھند
-جلند
-جمعد
-جمند
-جیند
-جھند
-چشید
-چقند
-چکند
-چمکد
-چمگد
-چنند
-چنید
-چیند
-چھند
-چھید
-حمید
-خشند
-خمید
-سبکد
-سپید
-سبید
-سپند
-ستبد
-ستعد
-ستقد
-سٹید
-سعید
-سفند
-سفید
-سکند
-سگند
-سمند
-سنگد
-سیند
-شعبد
-شقند
-شمعد
-شمند
-شمید
-شنند
-شنید
-شہید
-صعید
-ضلعد
-عبید
-عقید
-علمد
-عملد
-غمکد
-عملد
-فقید
-فیصد
-قصید
-قلمد
-قلند
-قلید
-کبید
-کتخد
-کشید
-مبتد
-کلند
-کلید
-کمید
-کنند
-کھند
-کھید
-گلبد
-گمشد
-گنبد
-گیند
-لبلد
-لبید
-لتصد
-لتعد
-لجعد
-لحمد
-لخلد
-لسجد
-لسید
-لصمد
-لعبد
-لعہد
-لقصد
-لقعد
-لقند
-لکند
-لکھد
-لمبد
-لمسد
-لمصد
-لمقد
-لمہد
-لہند
-متبد
-متحد
-متعد
-متقد
-متمد
-مجلد
-مجید
-محمد
-مخلد
-مسند
-مشہد
-معبد
-معتد
-مفسد
-مفید
-مقتد
-مقصد
-مقعد
-مقلد
-مقید
-ملحد
-ملید
-منجد
-منعد
-منہد
-میکد
-میند
-مہتد
-نبید
-نٹند
-نجید
-نشید
-نفید
-نکھد
-نگند
-نگہد
-نمکد
-نمند
-نیند
-نہند
-یقعد
-ہلحد
-ہیند
-بلیڈ
-بیکڈ
-بینڈ
-بھنڈ
-پگنڈ
-پلیڈ
-پینڈ
-پھسڈ
-پھلڈ
-تھنڈ
-ٹیچڈ
-ٹینڈ
-ٹھنڈ
-جھلڈ
-جھنڈ
-چینڈ
-چھنڈ
-سپنڈ
-سپیڈ
-سٹیڈ
-سکنڈ
-سلنڈ
-سینڈ
-فیلڈ
-کسنڈ
-کمنڈ
-کنگڈ
-کنیڈ
-کینڈ
-کھمڈ
-کھنڈ
-گینڈ
-گہگڈ
-گھنڈ
-لپنڈ
-لکنڈ
-لمنڈ
-لینڈ
-میکڈ
-محمڈ
-میگڈ
-مینڈ
-نٹنڈ
-نفیڈ
-ئٹیڈ
-ئمنڈ
-ئیٹڈ
-یپنڈ
-یٹنڈ
-یٹیڈ
-یجنڈ
-یشنڈ
-یگیڈ
-ینیڈ
-ہینڈ
-تلمذ
-کتحذ
-لہذ
-مبتذ
-نبیذ
-بپھر
-بتصر
-بتھر
-بٹلر
-بٹیر
-بجکر
-بجھر
-بچکر
-بچھر
-بحیر
-بحیر
-بستر
-بسفر
-بسیر
-بسہر
-بشیر
-بصیر
-بغیر
-بکثر
-بکیر
-بکھر
-بگیر
-بگھر
-بلغر
-بلگر
-بلیر
-بمپر
-بمتر
-بمہر
-بنجر
-بنسر
-بنصر
-بنظر
-بنکر
-بنگر
-بیٹر
-بیسر
-بیکر
-بینر
-بیئر
-بہتر
-بہیر
-بھسر
-بھقر
-بھکر
-بھگر
-بھیر
-پتھر
-پیٹر
-پچھڑ
-پکچر
-پکھر
-پمبر
-پنجر
-پنیر
-پنھر
-پیپر
-پیتر
-پیڑ
-پیسر
-پیشر
-پیکر
-پیلر
-پیہر
-پھسر
-پھیر
-تبحر
-تبصر
-تتہر
-تحیر
-تشتر
-تشکر
-تشنر
-تشہر
-پیٹر
-تعطر
-تغیر
-تفکر
-تفیر
-تکبر
-تکسر
-تکھر
-تلیر
-تمیر
-تنتر
-تنصر
-تنفر
-تیتر
-تیسر
-تہتر
-تھپر
-تھیر
-ٹیٹر
-ٹمبر
-ٹمپر
-ٹنبر
-ٹنگر
-ٹیٹر
-ٹیچر
-ٹیکر
-ٹیلر
-ٹھتر
-ٹھٹر
-ٹھکر
-ٹھمر
-ٹھیر
-ٹھہر
-جیتر
-جتیر
-جسٹر
-جعفر
-جگتر
-جگہر
-جلتر
-جلیر
-جمپر
-جمعر
-جمیر
-جنتر
-جننر
-جنجر
-جیکر
-جیلر
-جھبر
-جھجر
-جھمر
-جھیر
-چبکر
-چپکر
-چتبر
-چتیر
-چتھر
-چٹکر
-چچیر
-چلپر
-چلتر
-چنکر
-چلٹر
-چمبر
-چنبر
-چیکر
-چیئر
-چہیر
-چھپر
-چھتر
-چھیر
-چھنر
-چھہر
-حصیر
-حضیر
-حطیر
-حظیر
-حقیر
-حکمر
-حمیر
-خنصر
-خبیر
-خطیر
-خمیر
-خنجر
-خنصر
-خیبر
-سپیر
-سپہر
-ستبر
-ستتر
-ستخر
-ستغر
-ستفر
-ستقر
-ستکر
-ستمر
-ستھر
-سٹلر
-سٹیر
-سسٹر
-سعیر
-سفیر
-سکتر
-سکھر
-سلفر
-سلہر
-سمبر
-سمیر
-سنتر
-سنٹر
-سنجر
-سنچر
-سنسر
-سنکر
-سنگر
-سنہر
-سفیر
-سکتر
-سکھر
-سلفر
-سلہر
-سمبر
-سمیر
-سنتر
-سنجر
-سنکر
-سیکر
-سنچر
-سنسر
-سنگر
-سنہر
-سیسر
-سیگر
-سیلر
-سیمر
-سینر
-سہسر
-شبگر
-شبیر
-شنجر
-شعیر
-شکیر
-شنجر
-شنکر
-شنگر
-شیفر
-شیکر
-شیئر
-شہپر
-شہیر
-صغیر
-صفیر
-ضمیر
-طبغر
-طستر
-طشتر
-طمطر
-ظہیر
-عبقر
-عبیر
-عبہر
-عبتر
-عسکر
-عسیر
-عشیر
-عمیر
-عنبر
-عنصر
-عنقر
-غفیر
-فطیر
-فقیر
-فلتر
-فلٹر
-فلیر
-فیچر
-فیسر
-قصیر
-قلمر
-قمطر
-قیصر
-کبیر
-کتھر
-کٹلر
-کٹہر
-کٹھر
-کثیر
-کچہر
-کسپر
-کستر
-کسٹر
-کسکر
-کسگر
-کسیر
-کشنر
-کلچر
-کلنسر
-کلیر
-کمبر
-کمتر
-کمسر
-کمیر
-کنٹر
-کنجر
-کنسر
-کنفر
-کنکر
-کنگر
-کئیر
-کیپر
-کیتر
-کیسر
-کیفر
-کیکر
-کیلر
-کیمر
-کیئر
-کہتر
-کھپر
-کھتر
-کھسر
-کھیر
-گبھر
-گٹکر
-گٹھر
-گستر
-گلبر
-گلسر
-گلہر
-گنجر
-گیبر
-گیسر
-گیلر
-گہیر
-گبھر
-گھتر
-گھگر
-گھیر
-لبحر
-لبحر
-لبقر
-لبیر
-لبہر
-لپسر
-لتحر
-لتصر
-لتغر
-لتنر
-لیتر
-لتھر
-لٹیر
-لجبر
-لجیر
-لحجر
-لحشر
-لخمر
-لحمر
-لخیر
-لسٹر
-لشتر
-لشعر
-لشکر
-لصخر
-لعصر
-لعمر
-لفجر
-لفطر
-لفقر
-لقطر
-لقمر
-لکبر
-لکٹر
-لکچر
-لکسر
-لکیر
-لگیر
-لمبر
-لمعر
-لمکر
-لنسر
-لنصر
-لنظر
-لنگر
-لنہر
-لیبر
-لیٹر
-لیجر
-لیحر
-لیسر
-لکیر
-لیگر
-لیئر
-مبشر
-مبصر
-مپیر
-متبر
-متحر
-متشر
-متصر
-متضر
-متفر
-متمر
-متیر
-متہر
-مٹکر
-مثمر
-مجیر
-مچیر
-مچھر
-محتر
-محشر
-محضر
-محقر
-محیر
-مخبر
-مختر
-مخیر
-مستر
-مسٹر
-مسخر
-مسطر
-مسکر
-مسمر
-مسیر
-مسہر
-مشتر
-مشجر
-مشعر
-مشنر
-مشیر
-مضطر
-مضمر
-مظہر
-مظفر
-معبر
-معتر
-معطر
-معمر
-مغفر
-مغیر
-مفتر
-مفسر
-مضطر
-مفکر
-مفلر
-مقبر
-مقشر
-مقطر
-مکسر
-ملٹر
-ملکر
-ملیر
-ممبر
-ممیر
-منبر
-منٹر
-منجر
-منحر
-منخر
-منسر
-منکر
-منتر
-منخر
-منشر
-منصر
-منظر
-منفر
-منگر
-منیر
-منہر
-مئیر
-میٹر
-میجر
-میسر
-میکر
-میشر
-میگر
-میئر
-میہر
-مہتر
-نبتر
-نسٹر
-نبیر
-نبھر
-نبہر
-نتھر
-نٹیر
-نجیر
-نحضر
-نستر
-نسفر
-نسلر
-نسہر
-نشتر
-نصیر
-نضیر
-نظیر
-نفیر
-نکیر
-نکھر
-نگتر
-نگھر
-نمبر
-نمیر
-ننگر
-ننیر
-نیچر
-نیکر
-نیگر
-نیمر
-نئیر
-نیہر
-نہتر
-ئبیر
-ئسچر
-ئسکر
-ئمبر
-ئمنر
-ئمیر
-ئنگر
-ئیٹر
-ئیجر
-ئیگر
-ئیمر
-یتھر
-ییٹر
-یسٹر
-یسیر
-یشنر
-یکٹر
-یکسر
-یکطر
-یمپر
-یمنر
-یمئر
-ینٹر
-ینجر
-ینگر
-ینیر
-ہٹکر
-ہٹلر
-ہسٹر
-ہلبر
-ہمبر
-ہمسر
-ہنٹر
-ہیٹر
-ہیلر
-بتکڑ
-بچھڑ
-بنگڑ
-بنکڑ
-بیہڑ
-بھسٹر
-بھیڑ
-پچھر
-پنجڑ
-پنگڑ
-پنیڑ
-پیکڑ
-پیلڑ
-پینڑ
-پھسڑ
-پھکڑ
-پھگڑ
-پھیڑ
-تیتڑ
-تتہڑ
-تکھڑ
-تگیڑ
-تیلڑ
-تھپڑ
-تھمڑ
-تھیڑ
-جھکڑ
-جھگڑ
-جھلڑ
-چتھڑ
-چیپڑ
-چیچڑ
-چھبڑ
-چھپڑ
-چھکڑ
-چھلڑ
-چھیڑ
-سکیڑ
-سگھڑ
-سیکڑ
-شیخڑ
-غنگڑ
-کچکڑ
-کلچڑ
-کلھڑ
-کنجڑ
-کیچڑ
-کیکڑ
-کھچڑ
-کھیڑ
-گٹھڑ
-گنجڑ
-گیلڑ
-لبھڑ
-لتھڑ
-لکھڑ
-لمبڑ
-کنگڑ
-لیبڑ
-لیجڑ
-لیچڑ
-لیکڑ
-مسیر
-مکھڑ
-نبیڑ
-نبھڑ
-نچسڑ
-نکھڑ
-ہتکڑ
-ہیجڑ
-ہیکڑ
-بعجز
-بلٹز
-بیجز
-بیگز
-بینز
-پلیز
-تمیز
-ٹیمز
-جہیز
-چھیز
-ستلز
-ستمز
-ستیز
-شمیز
-سیلز
-طبعز
-کتحذ
-کنگز
-کنیز
-گلیز
-گیمز
-لمعز
-لیگز
-لیمز
-لینز
-لہمز
-مستز
-معتز
-معجز
-ملتز
-ممیز
-منیز
-منہز
-میگز
-نپلز
-نگیز
-ننگز
-نینز
-ئینز
-یٹمز
-یٹیز
-یشنز
-یلیز
-یمیز
-ہلیز
-ببیس
-بتیس
-بلیس
-بنفس
-بیطس
-بیکس
-بھلس
-بھیس
-پچیس
-پلٹس
-پلیس
-پیپس
-پتیس
-پیٹس
-پیلس
-پینس
-پھپس
-پھلس
-پھنس
-پھیس
-تجسس
-تنفس
-تئیس
-ٹیکس
-ٹیمس
-ٹینس
-ٹھنس
-ٹھیس
-جبیس
-جسٹس
-جلیس
-جیمس
-جھلس
-چکلس
-چنٹس
-چیفس
-خسیس
-خمیس
-سپیس
-سسکس
-سلیس
-سیکس
-فلپس
-فیکس
-قبیس
-ققنس
-کتیس
-کٹلس
-کسیس
-کتیس
-کھنس
-کھیس
-گیٹس
-گھٹس
-لٹمس
-لشمس
-لعکس
-لمبس
-لنفس
-لینس
-مجلس
-مخمس
-مفلس
-منٹس
-میپس
-میٹس
-میکس
-مینس
-نتیس
-نینس
-نفیس
-ئسنس
-ئیٹس
-ٹیمس
-یفنس
-یکٹس
-یلس
-یننس
-ہبیس
-ہنیں
-ھنیس
-بخشش
-بنگش
-بینش
-پیچش
-تعیش
-جنبش
-جنیش
-چکلش
-حشیش
-خشخش
-کشمش
-گنیش
-لتمش
-لعطش
-مفتش
-مقیش
-مینش
-مہیش
-نگلش
-ہمیش
-تخلص
-تشخص
-خصیص
-قمیص
-لقصص
-مختص
-مخلص
-مفیص
-ملخص
-حضیض
-سعفض
-مفیض
-نقیض
-بسیط
-تحفظ
-تسلط
-ستخط
-محیط
-مسقط
-مسلط
-مقسط
-تحفظ
-تلفظ
-حفیظ
-غلیظ
-للفظ
-مغلظ
-بلیع
-تتبع
-تشیع
-تصنع
-تضیع
-تمتع
-جمیع
-سمیع
-شفیع
-شنیع
-لجمع
-لطبع
-لطیع
-مبلع
-مبیع
-متبع
-مجمع
-مسجع
-مطبع
-مطلع
-مطمع
-مطیع
-مقطع
-ملمع
-منبع
-بلیغ
-مبلغ
-تعفف
-تکلف
-ثقیف
-حلیف
-حنیف
-خفیف
-ضعیف
-عفیف
-فکیف
-کثیف
-کسیف
-لخیف
-لسیف
-لصف
-لطیف
-لکہف
-متصف
-مخفف
-مصحف
-مصنف
-مضعف
-مکلف
-منصف
-نچیف
-نحیف
-نظیف
-یلیف
-تبلق
-تعشق
-تعلق
-تعمق
-تغلق
-تملق
-خلیق
-سحق
-شفیق
-طبلق
-عتیق
-عقیق
-عمیق
-عنیق
-لعلق
-لقلق
-لئیق
-مبیق
-متفق
-محقق
-مشتق
-مشفق
-مطلق
-معلق
-مغلق
-ملحق
-منطق
-نبیق
-ہنبق
-بٹھک
-بلیک
-بیجک
-بیشک
-بینک
-بھبک
-بھپک
-بھٹک
-بھچک
-بھسک
-بھلک
-بھنک
-بھیک
-پبلک
-پشتک
-پشمک
-پکنک
-پیٹک
-پیچک
-پینک
-پھپک
-پھبک
-پھٹک
-پھسک
-پھلک
-پھنک
-تشکک
-تمثک
-تنبک
-تہتک
-تھپک
-تھلک
-ٹیٹک
-ٹیلک
-ٹینک
-ٹھٹک
-بھکل
-ٹھسک
-ٹھمک
-ٹھنک
-ٹھیک
-جسٹک
-جھپک
-جھٹک
-جھجک
-جھلک
-جھمک
-چبلک
-چشمک
-چمبک
-چنبک
-چیٹک
-چیچک
-چیلک
-چھپک
-چھپک
-چھٹک
-چھلک
-چھمک
-چھنک
-چھیک
-خشتک
-سپلک
-سلنگ
-سلیک
-سنیک
-سینک
-صحنک
-طبلک
-علیک
-عینک
-غلطک
-کٹسک
-کلنک
-کیتک
-کھٹک
-کھسک
-کھنک
-گھٹک
-لبیک
-لمپک
-لملک
-مستک
-مسلک
-مشبک
-مضحک
-ممسک
-منسک
-میٹک
-میجک
-مینک
-مہلک
-نتھک
-نیلک
-نیمک
-یکنک
-ینفک
-بتنگ
-بٹنگ
-بجنگ
-بکنگ
-بلنگ
-بیلگ
-بینگ
-بھنگ
-بھیگ
-پتنگ
-پلنگ
-پلیگ
-پینگ
-تفنگ
-تلنگ
-تھلگ
-ٹلنگ
-ٹینگ
-جگمگ
-جننگ
-جھنگ
-چننگ
-چینگ
-سٹنگ
-سسنگ
-سلنگ
-سینگ
-شپنگ
-شلنگ
-علیگ
-فٹنگ
-فلیگ
-کٹنگ
-کسنگ
-کلنگ
-کننگ
-کھنگ
-گینگ
-لفنگ
-لہنگ
-متنگ
-ملنگ
-نٹنگ
-نچنگ
-نہنگ
-ئپنگ
-ئٹنگ
-ئلنگ
-ئننگ
-یٹنگ
-یسنگ
-یلنگ
-یننگ
-ہینگ
-ھینگت
-بخیل
-بسمل
-بشکل
-بعمل
-بفضل
-بکیل
-بکھل
-بگیل
-بلبل
-بمثل
-بنکل
-بنیل
-بیقل
-بیکل
-بھسل
-بھگل
-بھیل
-پتیل
-پتھل
-پٹیل
-پگھل
-پنسل
-پنگل
-پیبل
-پینل
-پیپل
-پیتل
-پیکل
-پھسل
-پھیل
-تجمل
-تحمل
-تخیل
-تشکل
-تعطل
-تعقل
-تفصل
-تفضل
-تکسل
-تمثل
-تنقل
-پٹیل
-ثقیل
-ٹگھل
-ٹیبل
-ٹیکل
-ٹھیل
-ثقیل
-جلیل
-جمیل
-جنبل
-جنٹل
-جنگل
-جیکل
-جھٹل
-جھجل
-جھیل
-چتھل
-چٹیل
-چسکل
-چلچل
-چنبل
-چنچل
-چنگل
-چیپل
-چیتل
-چینل
-چھیل
-حنبل
-خلیل
-سبیل
-ستیل
-سٹیل
-سطبل
-سکیل
-سگنل
-سلسل
-سمپل
-سمگل
-سنبل
-سنچل
-سنکل
-سنگل
-سیمل
-سہگل
-سہیل
-شکیل
-صطبل
-صلصل
-صیقل
-طفیل
-عقیل
-علیل
-غفیل
-غلیل
-فتیل
-فصیل
-فضیل
-فلفل
-فیشل
-فیصل
-قبیل
-قتیل
-قلقل
-قلیل
-قضل
-کتھل
-کٹھل
-کچیل
-کحیل
-کفیل
-کلبل
-کلکل
-کلیل
-کمبل
-کنجل
-کیبل
-کیچل
-کیسل
-کیہل
-کھٹل
-کھکل
-کھیل
-گٹھل
-گلگل
-گھچل
-لحیل
-لعقل
-لفصل
-لفضل
-لفعل
-لفیل
-لکحل
-لکفل
-للیل
-لمثل
-لنٹل
-لنجل
-لنمل
-لیبل
-لیگل
-متصل
-مجمل
-محصل
-محفل
-محلل
-محمل
-محیل
-مختل
-مخمل
-مسہل
-مشعل
-مشکل
-معتل
-معجل
-معطل
-مفصل
-مقبل
-مقتل
-مقفل
-مکمل
-ململ
-ممثل
-منگل
-میبل
-میٹل
-مینل
-مہمل
-نبیل
-نتھلا
-نٹھل
-نجیل
-نچھل
-نسپل
-نشیل
-نکیل
-نیمل
-ئٹیل
-ئیکل
-یٹیل
-یجنل
-یشنل
-یلغا
-یلیل
-ینٹل
-ینجل
-ینمل
-ہلبل
-ہلچل
-ہیکل
-ہیگل
-ھکیل
-ھلمل
-بچشم
-بحکم
-بستم
-بعلم
-بقلم
-بلغم
-تمیم
-بیچم
-بیگم
-بھسم
-پچھم
-پشتم
-پنجم
-پنچم
-پیتم
-پیہم
-تبسم
-تحکم
-تظلم
-تعلم
-تفہم
-تکلم
-تمیم
-تیمم
-تھکم
-جپسم
-حجیم
-جسیم
-جنتے
-جنگم
-جہلم
-جہنم
-جھلم
-چیخم
-چہلم
-چھلم
-حطیم
-حکیم
-حلکم
-حلیم
-حمیم
-سٹیم
-سسٹم
-سقیم
-سکیم
-سکھم
-سلیم
-سنگم
-سہیں
-شبنم
-شحیم
-شلجم
-شلغم
-شمیم
-شیشم
-صلعم
-صمیم
-ضخیم
-ضیغم
-طلسم
-ظلکم
-ظلہم
-عظیم
-عقیم
-علیم
-عمیم
-عنہم
-غنیم
-فہیم
-قسیم
-قلیم
-کسٹم
-کشتم
-کلیم
-کلہم
-کھلم
-کھیم
-گتھم
-گشتم
-گلیم
-گھسم
-لجہم
-لحکم
-لحیم
-لشتم
-لشٹم
-لعلم
-لفہم
-لقلم
-للحم
-للہم
-لنجم
-لئیم
-لیئم
-مبہم
-مجسم
-محکم
-مخیم
-مسلم
-مصمم
-مظلم
-معجم
-معظم
-معلم
-مغلم
-مقیم
-ملہم
-منجم
-منضم
-منظم
-منعم
-منیم
-میٹم
-میثم
-نسیم
-نعیم
-نگھم
-نیلم
-ئیٹم
-یتیم
-یلکم
-یمیم
-ینیم
-ہشتم
-ہفتم
-ہلکم
-ہنگم
-ھنگم
-بلین
-بجھن
-بچپن
-بچھن
-بحسن
-بضین
-بعین
-بقین
-بلبن
-بلین
-بئین
-بیٹن
-بیسن
-بیشن
-بیگن
-بیلن
-بہمن
-بھجن
-بھین
-پٹکن
-پٹین
-پچپن
-پچھم
-پشین
-پکین
-پلٹن
-پلین
-پنشن
-پیلن
-پھبن
-پھٹن
-پھکن
-پھننا
-پھین
-تپکن
-تسنن
-تعفن
-تعین
-تفنن
-تیقن
-تیلن
-تھکن
-ٹپکن
-ٹنگن
-ٹیشن
-ٹیکن
-ٹھکن
-ثمین
-ثنین
-جبین
-جیٹن
-جھکن
-جھلن
-جھین
-چبھن
-چپکن
-چپلن
-چپلن
-چٹخن
-چسکن
-چکٹن
-چلتن
-چلمن
-چمٹن
-چنین
-چیپن
-چھپن
-چھٹن
-چھکن
-چھنن
-چھین
-حبشن
-حسین
-حصین
-حفتن
-حقین
-حمن
-حنین
-سبین
-سپلن
-سپین
-ستین
-سٹین
-سکشن
-سکین
-سلگن
-سلین
-سمین
-سیٹن
-سیشن
-سیگن
-سیلن
-شفین
-صمین
-ضعین
-ظمین
-غضبن
-فطین
-فظین
-فقین
-فیشن
-فیمن
-کٹھن
-کلتن
-کلمن
-کلین
-کمسن
-کمین
-کنچن
-کنگن
-کنلن
-کیبن
-کیچن
-کیشن
-گلبن
-گلشن
-گیلن
-گیمن
-گھٹن
-گھسن
-لپٹن
-لٹکن
-لجین
-لجھن
-لچکن
-لچھن
-لحسن
-لحین
-لعین
-لفین
-لقین
-لکجن
-لکھن
-لمین
-لنکن
-لیٹن
-لیشن
-لیکن
-لیمن
-لینن
-لہسن
-مبین
-متحن
-متین
-مٹھن
-مثمن
-محسن
-مسکن
-مشین
-معجن
-معین
-مقنن
-مکمن
-مکین
-مکھن
-مگین
-ملٹن
-ملین
-ممکن
-منچن
-منمن
-منین
-میشن
-میگن
-میمن
-مہین
-نپین
-نٹین
-نجمن
-نچھن
-نشین
-نچھن
-نطین
-نگٹن
-نگین
-نیشن
-ئبین
-ئقین
-ئلین
-یشین
-یفین
-یقین
-یکشن
-یلین
-یمین
-ہستن
-ہلین
-ہنگن
-ہیگن
-ہیلن
-بتیں
-بٹیں
-بجیں
-پسیں
-بچیں
-پسیں
-بقیں
-بکیں
-بلیں
-بنیں
-بہیں
-پتیں
-پٹیں
-پجیں
-پچیں
-پشیں
-پکیں
-پلیں
-پئیں
-پھیں
-تپیں
-تتیں
-تچیں
-تشیں
-تکیں
-تگیں
-تلیں
-تنیں
-تئیں
-تھیں
-ٹپیں
-ٹتیں
-ٹکیں
-ٹلیں
-ٹھیں
-ثتیں
-جبیں
-جتیں
-جٹیں
-جپیں
-جچیں
-جگیں
-جلیں
-جمیں
-جنیں
-جئیں
-جھیں
-چپیں
-چبیں
-چتیں
-چٹیں
-چسیں
-چقیں
-چکیں
-چگیں
-چلیں
-چنیں
-چئیں
-چھیں
-حتیں
-حٹیں
-حسیں
-حنیں
-خسیں
-ستیں
-سچیں
-سشیں
-سکیں
-سلیں
-سمیں
-سنیں
-سہیم
-ششیں
-شقیں
-صحین
-صفیں
-صلیں
-ظتیں
-عتیں
-عظیں
-فتیں
-فطیں
-فمیں
-قتیں
-قمیں
-کتیں
-کٹیں
-کجیں
-کچیں
-کسیں
-کلیں
-کمیں
-کہیں
-کھیں
-گپیں
-گتیں
-گچیں
-گلیں
-گمیں
-گنیں
-گئیں
-لتیں
-لٹیں
-لچیں
-لفیں
-لکیں
-لگیں
-لنیں
-لیکن
-مبیں
-مٹیں
-مجیں
-متیں
-مچیں
-مسیں
-مکیں
-مگیں
-ملیں
-مہیں
-نپیں
-نتیں
-نٹیں
-نجیں
-نخیں
-نچیں
-نسیں
-نشیں
-نقیں
-نگیں
-نہیں
-نھیں
-ئٹیں
-ئشیں
-ئفیں
-ئلیں
-ئنیں
-یتیں
-یثیں
-یخیں
-یفیں
-یکیں
-یقیں
-یگیں
-یلیں
-یمیں
-ہپیں
-ہتیں
-ہٹیں
-ہشیں
-ہکیں
-ہگیں
-ہلیں
-ہمیں
-ہنیں
-ہئیں
-ھکیں
-ھلیں
-ھنیں
-بپتو
-بتیو
-بتھو
-بٹلو
-بٹنو
-بٹیو
-بٹھو
-بجنو
-بجھو
-بچتو
-بچکو
-بچلو
-بچیو
-بچھو
-بحثو
-بحصو
-بحضو
-بختو
-بخشو
-بخیو
-بشمو
-بشنو
-بطخو
-بعضو
-بعنو
-بغچو
-بغلو
-بقچو
-بقعو
-بکٹو
-بکسو
-بکلو
-بکیو
-بگلو
-بگھو
-بلبو
-بلٹو
-بلتو
-بلکو
-بلو
-بلیو
-بلہو
-بمبو
-بنٹو
-بنجو
-بنسو
-بنکو
-بیتو
-بیٹو
-بیجو
-بیحو
-بیچو
-بیسو
-بیضو
-بیکو
-بیگو
-بیلو
-بیمو
-بینو
-بیہو
-بہبو
-بہتو
-بہکو
-بہلو
-بہنو
-بھبو
-بھٹو
-بھپو
-بھجو
-بھچو
-بھسو
-بھکو
-بھگو
-بھلو
-بھنو
-پئپو
-پتلو
-پٹخو
-پٹکو
-پٹیو
-پٹھو
-پچتو
-پچکو
-پچھو
-پختو
-پستو
-پسلو
-پسیو
-پشتو
-پشیو
-پکھو
-پگلو
-پلٹو
-پلکو
-پمپو
-پنپو
-پنجو
-پنگو
-پیپو
-پیٹو
-پیچو
-پیسو
-پیشو
-پیکو
-پیلو
-پیمو
-پیئو
-پیہو
-پہلو
-پہنو
-پہیو
-پھبو
-پھپو
-پھٹو
-پھچو
-پھکو
-پھچو
-پھگو
-پھلو
-پھنو
-تپکو
-تتلو
-تحفو
-تختو
-تسلو
-تسمو
-تسنو
-تکیو
-تکھو
-تمبو
-تمغو
-تمکو
-تنبو
-تنخو
-تنکو
-تیٹو
-تیجو
-تیسو
-تیغو
-تیلو
-تیمو
-تینو
-تھجو
-تھکو
-تھلو
-تھمو
-تھنو
-تھیو
-ٹپکو
-ٹخنو
-ٹکٹو
-ٹکلو
-ٹکیو
-ٹنگو
-ٹیپو
-ٹیٹو
-ٹیسو
-ٹیکو
-ٹیشو
-ٹیگو
-ٹیلو
-ٹیمو
-ٹہلو
-ٹہنو
-ٹھسو
-ٹھکو
-ٹھگو
-ٹھلو
-ٹھنو
-ٹھئو
-ٹھیو
-ثیقو
-ثیمو
-جبھو
-جتنو
-جستو
-جسکو
-جسمو
-جشنو
-جگتو
-جگنو
-جگہو
-جلسو
-جمبو
-جملو
-جمہو
-جنتو
-جنجو
-جنسو
-جنگو
-جنمو
-جنیو
-جنہو
-جیبو
-جیپو
-جیتو
-جیحو
-جیسو
-جیشو
-جیلو
-جینو
-جیہو
-جہتو
-جھکو
-جھلو
-جھمو
-جھنو
-چبکو
-چبلو
-چبھو
-چپٹو
-چپکو
-چپلو
-چتلو
-چٹخو
-چٹکو
-چٹلو
-چٹیو
-چٹھو
-چچیو
-چسکو
-چسنو
-چشمو
-چسنو
-چکٹو
-چکلو
-چکمو
-چکنو
-چکیو
-چکھو
-چلغو
-چلمو
-چلھو
-چمبو
-چمٹو
-چمپو
-چمچو
-چمکو
-چمنو
-چنٹو
-چنیو
-چیپو
-چیتو
-چیخو
-چیکو
-چیلو
-چہکو
-چہنو
-چھپو
-چھتو
-چھٹو
-چھجو
-چھکو
-چھلو
-چھنو
-حبتو
-حجتو
-حجلو
-حشتو
-حشیو
-حکمو
-حلفو
-حلقو
-حلیو
-حمتو
-حمقو
-حملو
-حیتو
-حیلو
-ختنو
-خشبو
-خشنو
-خشیو
-خصمو
-خصیو
-خطبو
-خلتو
-خلفو
-خلقو
-خلیو
-خمیو
-خیمو
-سبعو
-سبغو
-سبکو
-سپنو
-ستخو
-ستصو
-ستکو
-ستلو
-سٹکو
-سٹلو
-سٹیو
-سٹھو
-سجنو
-سخنو
-سخیو
-سسکو
-سطحو
-سعتو
-سفلو
-سقمو
-سکتو
-سکیو
-سلحو
-سکیو
-سکھو
-سگنو
-سلجو
-سلفو
-سلکو
-سلگو
-سلیو
-سمپو
-سمتو
-سمٹو
-سمنو
-سنبو
-سنپو
-سنتو
-سنجو
-سنکو
-سنگو
-سنلو
-سیبو
-سیٹو
-سیخو
-سیسو
-سیکو
-سیلو
-سیمو
-سینو
-سہلو
-سہمو
-شبخو
-شبکو
-شبہو
-شتیو
-شخصو
-شعبو
-شغلو
-شفٹو
-شکلو
-شکنو
-شگنو
-شلفو
-شمشو
-شمعو
-شملو
-شمنو
-شنٹو
-شنیو
-شیخو
-شیشو
-شیعو
-شیلو
-شہتو
-شہسو
-صبحو
-صبہو
-صحتو
-صحنو
-صفتو
-صفحو
-صلو
-صلیو
-صلا
-صنفو
-صیتو
-صیغو
-صیلو
-صیہو
-ضگیو
-ضلعو
-طبقو
-طبلو
-طشتو
-طعنو
-طمیو
-طنبو
-طیسو
-ظمیو
-ظیفو
-عصفو
-عظمو
-عفتو
-عقلو
-عکسو
-علتو
-علمو
-عملو
-عنفو
-عیبو
-عیتو
-عیسو
-غبتو
-غبیو
-غلبو
-غنچو
-فتحو
-فتنو
-فسٹو
-فصلو
-فضلو
-فعتو
-فعلو
-فغفو
-فلمو
-فلیو
-فیتو
-فیسو
-فیقو
-فیلو
-فینو
-فہمو
-قبضو
-قبلو
-قتلو
-قتیو
-قسطو
-قسمو
-قشقو
-قصبو
-قضیو
-قطعو
-قلتو
-قلعو
-قلمو
-قلیو
-قیبو
-قیطو
-قیفو
-قیقو
-قیلو
-کبھو
-کتبو
-کتنو
-کتیو
-کتھو
-کٹکو
-کٹیو
-کٹھو
-کچکو
-کجکو
-کجلو
-کچلو
-کچھو
-کتھو
-کستو
-کسٹو
-کسفو
-کسلو
-کشتو
-کشٹو
-کشکو
-کشیو
-کعتو
-کفنو
-ککھو
-کلبو
-کلتو
-کلپو
-کلثو
-کلچو
-کلکو
-کلمو
-کلیو
-کلہو
-کمبو
-کمپو
-کمجو
-کمخو
-کملو
-کمیو
-کنبو
-کنٹو
-کنجو
-کنسو
-کنکو
-کیبو
-کنگو
-کیپو
-کیتو
-کیچو
-کیسو
-کیکو
-کیلو
-کیمو
-کینو
-کہلو
-کھپو
-کھتو
-کھٹو
-کھجو
-کھچو
-کھسو
-کھکو
-کھلو
-کھنو
-کھیو
-گپکو
-گتھو
-گٹکو
-گٹھو
-گچھو
-گسٹو
-گلگو
-گلیو
-گملو
-گنجو
-گنگو
-گنیو
-گیتو
-گیسو
-گیلو
-گیمو
-گیہو
-گہکو
-گہنو
-گھپو
-گھٹو
-گھجو
-گھچو
-گھسو
-گھگو
-گھلو
-گھنو
-گھیو
-لبمو
-لپٹو
-لپکو
-لتصو
-لتیو
-لٹکو
-لٹیو
-لثبو
-لجھو
-لچکو
-لچھو
-لحتو
-لحظو
-لحقو
-لحکو
-لخصو
-لسٹو
-لسطو
-لسلو
-لشتو
-لشعو
-لشکو
-لصبو
-لطو
-لعفو
-لعلو
-لعمو
-لغتو
-لغفو
-لغنو
-لغیو
-لفتو
-لفٹو
-لفطو
-لفظو
-لفنو
-لقلو
-لقمو
-لقیو
-لکیو
-لکھو
-لگنو
-لگیو
-لمبو
-لمپو
-لمحو
-لمصو
-لمکو
-لمیو
-لنکو
-لنگو
-لنیو
-لیپو
-لیٹو
-لیحو
-لیچو
-لیسو
-لیفو
-لیقو
-لیکو
-لیگو
-لیلو
-لیمو
-لینو
-لیہو
-لہٹو
-لہجو
-لہچو
-لہکو
-لہلو
-لہنو
-مبسو
-مبعو
-مبلو
-مبہو
-متبو
-متصو
-متلو
-متمو
-متنو
-متھو
-مٹکو
-مٹلو
-مٹیو
-مٹھو
-مثلو
-مثنو
-مجبو
-سنبھا
-مجمو
-مجنو
-مجہو
-مجھو
-مچکو
-مچلو
-مچھو
-محبو
-محتو
-محجو
-محشو
-محضو
-محظو
-محفو
-محکو
-محلو
-محمو
-مخبو
-مختو
-مخصو
-مخطو
-مخلو
-مخمو
-مسبو
-مسٹو
-مستو
-مسجو
-مسطو
-مسعو
-مسکو
-مسلو
-مسمو
-مسنو
-مسئو
-مشحو
-مشغو
-مشقو
-مشکو
-مشمو
-مشہو
-مصلو
-مصمو
-مصنو
-مصئو
-مضبو
-مضمو
-مطبو
-مطلو
-مطعو
-مظبو
-مظنو
-معبو
-معتو
-معجو
-معشو
-معصو
-معطو
-معقو
-معکو
-معلو
-معمو
-معنو
-معیو
-معہو
-مغسو
-مغشو
-مغضو
-مغفو
-مغلو
-مغمو
-مفتو
-مفعو
-مفقو
-مفلو
-مفہو
-مقبو
-مقتو
-مفسو
-مقصو
-مقلو
-مقہو
-مکتو
-مکحو
-مکسو
-مکشو
-مکنو
-مکھو
-ملبو
-ملتو
-ملحو
-ملعو
-ملغو
-ملفو
-ملکو
-ملنو
-ملیو
-مملو
-ممنو
-منتو
-منٹو
-منچو
-منحو
-منسو
-منشو
-منصو
-منطو
-منظو
-منقو
-منگو
-منکو
-منلو
-منیو
-منھو
-میتو
-میٹو
-میجو
-میخو
-میچو
-میسو
-میشو
-میکو
-میگو
-میلو
-میمو
-مینو
-مہجو
-مہکو
-مہمو
-نبٹو
-نبضو
-نبیو
-نبھو
-نپٹو
-نپجو
-نپلو
-نتھو
-نٹیو
-نٹھو
-نجسو
-نجشو
-نجنو
-نجھو
-نچلو
-نچھو
-نحضو
-نخلو
-نسپو
-نسبو
-نسٹو
-نستو
-نسخو
-نسکو
-نسلو
-نسیو
-نطفو
-نظمو
-نعتو
-نعشو
-نعلو
-نغمو
-نفسو
-نفعو
-نفلو
-نقشو
-نقصو
-نقلو
-نکتو
-نکٹو
-نکسو
-نکلو
-نکمو
-نکھو
-نگپو
-نگٹو
-نگلو
-نگیو
-نگھو
-نلکو
-نلیو
-نمٹو
-نمکو
-ننگو
-ننھو
-نیبو
-نیتو
-نیٹو
-نیجو
-نیسو
-نیشو
-نیفو
-نیکو
-نیگو
-نیلو
-نیمو
-نینو
-نہتو
-نہٹو
-نہجو
-ئٹیو
-ئچیو
-ئفلو
-ئلٹو
-ئنگو
-ئیسو
-ئیکو
-ئیلو
-ئینو
-ینپو
-یتھو
-یٹمو
-یٹئو
-یجنو
-یچھو
-یستو
-یشنو
-یشیو
-یعتو
-یعسو
-یعقو
-یکٹو
-یکسو
-یکنو
-یکیو
-یکھو
-یگچو
-یلبو
-یلٹو
-یلیو
-ینٹو
-ینکو
-ینگو
-ہچکو
-ہفتو
-ہکلو
-ہلکو
-ہلگو
-ہمتو
-ہمجو
-ہمچو
-ہمخو
-ہمکو
-ہنجو
-ہنسو
-ہیٹو
-ہیلو
-ہیمو
-ہینو
-ھتیو
-ھجیو
-ھچکو
-ھلکو
-ھمکو
-ھنکو
-ھنگو
-سقئہ
-صفحہ
-ئحئہ
-یچئہ
-ببلی
-ببئی
-بپتی
-بتتی
-بتنی
-بٹتی
-بٹلی
-بٹنی
-بجتی
-بجلی
-بجنی
-بجھی
-بچتی
-بچکی
-بچگی
-بچلی
-بچنی
-بچھی
-بحثی
-بختی
-بخشی
-بستی
-بسنی
-بطخی
-بطنی
-بعضی
-بغچی
-بغضی
-بغلی
-بقچی
-بکتی
-بکٹی
-بکسی
-بکنی
-بکئی
-بکھی
-بگتی
-بگھی
-بلتی
-بلٹی
-بلخی
-بلسی
-بلغی
-بلکی
-بللی
-بلنی
-بلہی
-بمپی
-بنتی
-بنٹی
-بنجی
-بنسی
-بنکی
-بنگی
-بننی
-بیتی
-بیٹی
-بیجی
-بیچی
-بیسی
-بیشی
-بیعی
-بیگی
-بیلی
-بینی
-بہتی
-بہکی
-بہلی
-بہنی
-بھتی
-بھٹی
-بھجی
-بھچی
-بھسی
-بھکی
-بھگی
-بھلی
-بھنی
-بھئی
-پئبی
-پپلی
-پپتی
-پتکی
-پتلی
-پتنی
-پتھی
-پٹتی
-پٹخی
-پٹکی
-پٹنی
-پٹھی
-پجتی
-پجنی
-پچتی
-پچکی
-پچنی
-پچھی
-پخنی
-پستی
-پسلی
-پسنی
-پشتی
-پکتی
-پکشی
-پکنی
-پگلی
-پلتی
-پلٹی
-پلنی
-پمپی
-پپنی
-پنجی
-پنکی
-پیتی
-پیٹی
-پیسی
-پیشی
-پیلی
-پینی
-پہلی
-پہنی
-پھبی
-پھپی
-پھٹی
-پھسی
-پھکی
-پھگی
-پھلی
-پھنی
-تبتی
-تبلی
-تبھی
-تپتی
-تپشی
-تتلی
-تتئی
-تجتی
-تجلی
-تجنی
-تجھی
-تچتی
-تچنی
-تحتی
-تحلی
-تختی
-تخمی
-تسلی
-تشتی
-تشفی
-تشکی
-تضی
-تکتی
-تکنی
-تگتی
-تگنی
-تلتی
-تلخی
-تلسی
-تلکی
-تللی
-تلنی
-تمنی
-تنتی
-تنکی
-تنگی
-تننی
-تیبی
-تیجی
-تیخی
-تیسی
-تیلی
-تہجی
-تھپی
-تھتی
-تھجی
-تھکی
-تھلی
-تھمی
-تھنی
-تھئی
-ٹپتی
-ٹپکی
-ٹپنی
-ٹخنی
-ٹکنی
-ٹکتی
-ٹکلی
-ٹکنی
-ٹگنی
-ٹلتی
-ٹلنی
-ٹمنی
-ٹنگی
-ٹیپی
-ٹیچی
-ٹیکی
-ٹیلی
-ٹیمی
-ٹینی
-ٹہلی
-ٹہنی
-ٹھتی
-ٹھسی
-ٹھگی
-ٹھلی
-ٹھنی
-ثقفی
-ثیقی
-ثیمی
-جبلی
-جبھی
-جپتی
-جپسی
-جپنی
-جتتی
-جتنی
-جٹھی
-جچتی
-جچگی
-جچنی
-جچئی
-جسکی
-جسمی
-جعتی
-جعلی
-جفتی
-جگتی
-جگنی
-جلتی
-جلقی
-جلنی
-جمتی
-جمعی
-جمنی
-جنبی
-جنمی
-جنتی
-جنجو
-جنسی
-جنکی
-جنگی
-جنمی
-جننی
-جیبی
-جیتی
-جیجی
-جیحی
-جیسی
-جیکی
-جیلی
-جیمی
-جینی
-جیہی
-جہتی
-جھتی
-جھکی
-جھگی
-جھلی
-جھنی
-چبتی
-چبکی
-چبلی
-چبنی
-چبھی
-چپتی
-چپٹی
-چپکی
-چپلی
-چپنی
-چتتی
-چتلی
-چتنی
-چٹتی
-چٹخی
-چٹکی
-چٹنی
-چٹھی
-چچلی
-چستی
-چسکی
-چسنی
-چشتی
-چشمی
-چغلی
-چکتی
-چکٹی
-چکلی
-چکنی
-چکئی
-چکھی
-چگتی
-چگنی
-چلتی
-چلنی
-چمپی
-چمٹی
-چمچی
-چمکی
-چملی
-چمنی
-چنتی
-چنگی
-چننی
-چیپی
-چیخی
-چیسی
-چیلی
-چینی
-چہکی
-چہلی
-چبھی
-چھپی
-چھٹی
-چھتی
-چھچی
-چھلی
-چھنی
-چھئی
-حبشی
-حتمی
-حتی
-حجتی
-حسبی
-حسنی
-حکمی
-حلبی
-حلفی
-حلقی
-حلمی
-حمتی
-حنفی
-حیضی
-حیمی
-خبطی
-ختگی
-ختمی
-ختنی
-ختئی
-خستی
-خشکی
-خصتی
-خصمی
-خطمی
-خفگی
-سفلی
-خلتی
-خلقی
-خلفی
-خمچی
-خنکی
-سبکی
-سبھی
-سپتی
-ستتی
-ستکی
-ستگی
-ستلی
-ستمی
-سٹکی
-سٹلی
-سٹھی
-سجتی
-سجنی
-سچلی
-سختی
-سسپی
-سستی
-سسکی
-سسلی
-سطحی
-سطی
-سفلی
-سقنی
-سکتی
-سکسی
-سکنی
-سکھی
-سگسی
-سگنی
-سلبی
-سلتی
-سلکی
-سلگی
-سلمی
-سلنی
-سمبی
-سمتی
-سمٹی
-سمسی
-سمعی
-سمنی
-سنبی
-سنتی
-سنٹی
-سنکی
-سنگی
-سنلی
-سننی
-سیبی
-سیپی
-سیتی
-سیسی
-سیفی
-سیعی
-سیقی
-سیکی
-سیلی
-سیمی
-سینی
-سیہی
-سہتی
-سہلی
-سہمی
-سہنی
-شبعی
-شبلی
-شٹمی
-شخصی
-شخطی
-شطحی
-شفقی
-شکتی
-شکلی
-شکمی
-شکنی
-شگتی
-شگنی
-شمسی
-شمعی
-شمنی
-شیخی
-شیشی
-شیعی
-شہکی
-شہنی
-ضحی
-صلبی
-صلگی
-صیتی
-صیعی
-ضبطی
-ضحی
-ضلعی
-ضمنی
-طبی
-طبعی
-طبلی
-طفلی
-طلبی
-طیبی
-طیسی
-طینی
-ظلمی
-ظہبی
-عجمی
-عشقی
-عشی
-عصبی
-عظمی
-عقبی
-عقلی
-عکسی
-علتی
-علمی
-علی
-عملی
-عمی
-عنہی
-عیبی
-عیتی
-عینی
-غبتی
-غچلی
-غضبی
-غلطی
-غلنی
-غلئی
-غیبی
-فتگی
-فتنی
-فصلی
-فضلی
-فعلی
-ففٹی
-فقہی
-فلکی
-فلمی
-فیضی
-فیقی
-فیلی
-فیمی
-فہمی
-قبطی
-قسمی
-قصی
-قطبی
-قطعی
-قفلی
-قلبی
-قلعی
-قلفی
-قلمی
-قمچی
-قیسی
-قیفی
-قیقی
-کبکی
-کبھی
-کپٹی
-کتنی
-کٹتی
-کٹکی
-کٹنی
-کٹھی
-کجلی
-کچلی
-کچھی
-کسبی
-کستی
-کسلی
-کسنی
-کشتی
-کشفی
-کعتی
-کفنی
-کلبی
-کلتی
-کلٹی
-کلچی
-کلغی
-کلفی
-کلکی
-کلنی
-کمبی
-کمپی
-کمتی
-کمٹی
-کملی
-کمنی
-کنجی
-کنکی
-کنگی
-کیتی
-کیچی
-کیسی
-کیفی
-کیکی
-کیلی
-کہتی
-کہنی
-کھبی
-کھپی
-کھتی
-کھٹی
-کھجی
-کھسی
-کھلی
-کھنی
-گپتی
-گپکی
-گتھی
-گٹکی
-گٹھی
-گجنی
-گجئی
-گجھی
-گچھی
-گشتی
-گفتی
-گلتی
-گلٹی
-گلجی
-گلنی
-گمتی
-گمٹی
-گملی
-گمنی
-گنتی
-گنجی
-گنگی
-گننی
-گیتی
-گیسی
-گیلی
-گینی
-گہکی
-گہمی
-گہنی
-گھپی
-گھٹی
-گھسی
-گھگی
-گھلی
-گھنی
-لبنی
-لپٹی
-لپسی
-لپکی
-لٹتی
-لٹکی
-لٹنی
-لجھی
-لچتی
-لچکی
-لچنی
-لچھی
-لحتی
-لحئی
-لخمی
-لسٹی
-لسکی
-لسئی
-لشتی
-لطفی
-لعلی
-لغنی
-لفظی
-لقمی
-لکتی
-لکٹی
-لکشی
-لکنی
-لکھی
-لگتی
-لگنی
-لمبی
-لمکی
-لنبی
-لنکی
-لنگی
-لیپی
-لیتی
-لیٹی
-لیچی
-لیسی
-لیفی
-لیقی
-لیکی
-لیگی
-لیمی
-لینی
-لیئی
-لیہی
-لہٹی
-لہکی
-لہی
-مبنی
-متقی
-متکی
-متلی
-متنی
-متھی
-مٹتی
-مٹکی
-مٹنی
-مٹھی
-مثنی
-مجھی
-مچتی
-مچکی
-مچلی
-مچنی
-مچھی
-محبی
-محیی
-مخفی
-مستی
-مسکی
-مسلی
-مسنی
-مشتی
-مشفی
-مشقی
-مشکی
-مصفی
-مضی
-معنی
-مغلی
-مغنی
-مفتی
-مقئی
-مکتی
-مکنی
-مکئی
-مکھی
-مگسی
-ملتی
-ملٹی
-ملکی
-ملی
-ملنی
-ممٹی
-منتی
-منجی
-منشی
-منفی
-منقی
-منکی
-منگی
-مننی
-منی
-میٹی
-میجی
-میچی
-میسی
-میشی
-میکی
-میلی
-میمی
-مینی
-مہکی
-مھیی
-نبتی
-نبٹی
-نبھی
-نپتی
-نپٹی
-نپنی
-نبچی
-نتتی
-نتنی
-نتھی
-نٹتی
-نٹنی
-نٹھی
-نجتی
-نجشی
-نجفی
-نجمی
-نجنی
-نجھی
-نچتی
-نچکی
-نچلی
-نچنی
-نچھی
-نحلی
-نسبی
-نستی
-نسٹی
-نسلی
-نسنی
-نظمی
-نغمی
-نفسی
-نفلی
-نقشی
-نقلی
-نکتی
-نکٹی
-نکسی
-نکلی
-نکمی
-نکنی
-نکھی
-نگتی
-نگلی
-نگنی
-نگہی
-نگھی
-نلکی
-نمٹی
-نمنی
-ننگی
-ننھی
-نیتی
-نیثی
-نیچی
-نیشی
-نیکی
-نیگی
-نیلی
-نیمی
-نینی
-نہٹی
-نہلی
-نہنی
-ئنسی
-ئیسی
-ئیشی
-ئیگی
-ئیلی
-ئینی
-یتنی
-یٹمی
-یحیی
-یختی
-یخنی
-یشمی
-یعتی
-یعنی
-یکتی
-یکھی
-یگچی
-یلٹی
-یلچی
-یلسی
-یلمی
-یلہی
-یمنی
-ینٹی
-ہٹتی
-ہٹنی
-ہچکی
-ہستی
-ہسکی
-ہسلی
-ہسنی
-ہضمی
-ہکتی
-ہکلی
-ہکنی
-ہگتی
-ہگلی
-ہلتی
-ہلکی
-ہلگی
-ہلنی
-ہمتی
-ہمکی
-ہمگی
-ہمنی
-ہنسی
-ہنکی
-ہنگی
-ہیتی
-ہیٹی
-ہیلی
-ہیمی
-ھپتی
-ھپنی
-ھستی
-ھسنی
-ھکتی
-ھکنی
-ھلتی
-ھلکی
-ھلنی
-ھمکی
-ھنتی
-ھنسی
-ھنکی
-ھنگی
-ھننی
-ھیلی
-ھیمی
-ھینی
-بپتے
-بتتے
-بتنے
-بتئے
-بٹتے
-بٹنے
-بٹئے
-بجتے
-بجنے
-بجئے
-بجھے
-بچتے
-بچکے
-بچلے
-بچنے
-بچئے
-بچھے
-بختے
-بخشے
-بخئے
-بخیے
-بستے
-بسکے
-بسنے
-بسئے
-بعضے
-بغچے
-بقچے
-بقعے
-بکتے
-بکٹے
-بکسے
-بکلے
-بکنے
-بکئے
-بگلے
-بگھے
-بلتے
-بلٹے
-بلسے
-بلکے
-بللے
-بلنے
-بلئے
-بنتے
-بنٹے
-بنجے
-بننے
-بنئے
-بیتے
-بیٹے
-بیجے
-بیچے
-بیضے
-بیلے
-بیمے
-بینے
-بہتے
-بہکے
-بہلے
-بہنے
-بہئے
-بھٹے
-بھجے
-بھچے
-بھکے
-بھگے
-بھلے
-بھنے
-پتتے
-پتلے
-پتنے
-پتئے
-پتھے
-پٹتے
-پٹخے
-پٹکے
-پٹنے
-پٹئے
-پٹھے
-پجتے
-پجنے
-پجئے
-پچتے
-پچکے
-پچنے
-پچئے
-پچھے
-پستے
-پسنے
-پسئے
-پشتے
-پکتے
-پکنے
-پکئے
-پگلے
-پلتے
-پلٹے
-پلنے
-پلئے
-پپنے
-پنتے
-پنجے
-پیپے
-پیتے
-پیٹے
-پیسے
-پیشے
-پیلے
-پینے
-پیئے
-پہلے
-پہنے
-پہئے
-پھبے
-پھٹے
-پھسے
-پھکے
-پھلے
-پھنے
-تپتے
-تپکے
-تپنے
-تپئے
-تتلے
-تتمے
-تجتے
-تجنے
-تجئے
-تجھے
-تچتے
-تچنے
-تچئے
-تحفے
-تختے
-تسلے
-تسمے
-تشنے
-تکتے
-تکلے
-تکنے
-تکیے
-تکئے
-تگتے
-تگنے
-تلتے
-تللے
-تلنے
-تلئے
-تمغے
-تنتے
-تنکے
-تننے
-تنئے
-تیجے
-تیشے
-تیلے
-تینے
-تھپے
-تھتے
-تھجے
-تھکے
-تھلے
-تھمے
-تھنے
-تھئے
-ٹپتے
-ٹپکے
-ٹپنے
-ٹپئے
-ٹخنے
-ٹکتے
-ٹکلے
-ٹکنے
-ٹکئے
-ٹلتے
-ٹلٹے
-ٹلنے
-ٹلئے
-ٹنٹے
-ٹنگے
-ٹیپے
-ٹیکے
-ٹیلے
-ٹینے
-ٹہلے
-ٹہنے
-ٹھتے
-ٹھٹے
-ٹھسے
-ٹھکے
-ٹھگے
-ٹھلے
-ٹھنے
-ٹھئے
-ثیقے
-جپتے
-جپنے
-جپئے
-جتتے
-جتنے
-جتئے
-جتھے
-جٹتے
-جٹھے
-جٹنے
-جٹئے
-جچتے
-جچنے
-جچئے
-جسکے
-جفتے
-جکتے
-جگتے
-جگنے
-جگئے
-جلتے
-جلسے
-جلنے
-جلئے
-جمتے
-جمعے
-جملے
-جمنے
-جمئے
-جنتے
-جنسے
-جنکے
-جننے
-جنئے
-جنھے
-جیتے
-جیسے
-جینے
-جیئے
-جھتے
-جھکے
-جھلے
-جھنے
-جھئے
-چبتے
-چبکے
-چبلے
-چبنے
-چبئے
-چبھے
-چپتے
-چپٹے
-چپکے
-چپنے
-چپئے
-چتتے
-چتنے
-چتئے
-چٹپے
-چٹتے
-چٹخے
-چٹکے
-چٹلے
-چٹنے
-چٹئے
-چٹھے
-چسکے
-چشمے
-چکتے
-چکٹے
-چکلے
-چکمے
-چکنے
-چکئے
-چکھے
-چگتے
-چگنے
-چگئے
-چلتے
-چلنے
-چلئے
-چمپے
-چمٹے
-چمچے
-چمکے
-چنتے
-چنکے
-چنگے
-چننے
-چنئے
-چیپے
-چیتے
-چیخے
-چیلے
-چہکے
-چھپے
-چھتے
-چھٹے
-چھجے
-چھچے
-چھکے
-چھلے
-چھنے
-چھئے
-حجلے
-حلقے
-حلئے
-حملے
-حیلے
-ختنے
-خشکے
-خطبے
-خلئے
-خیلے
-خیمے
-سپنے
-ستتے
-ستلے
-ستئے
-سٹکے
-سجتے
-سجنے
-سجئے
-سختے
-سخنے
-سستے
-سسکے
-سفلے
-سکتے
-سکنے
-سکئے
-سگتے
-سگنے
-سگئے
-سگلے
-سلتے
-سلحے
-سلکے
-سلگے
-سلنے
-سلئے
-سمبے
-سمٹے
-سمنے
-سنتے
-سنجے
-سنکے
-سنگے
-سنلے
-سننے
-سیتے
-سیسے
-شیشے
-سیلے
-سینے
-سیئے
-سہتے
-سہلے
-سہمے
-سہنے
-سہئے
-شخصے
-شعبے
-شعلے
-شکتے
-شکنے
-شگتے
-شگنے
-شملے
-شیشے
-شیلے
-شیئے
-صفحے
-صیغے
-ضحے
-ضلعے
-طبقے
-طبلے
-طعنے
-بقعے
-ظیفے
-علے
-عملے
-غصے
-غلبے
-غنچے
-فتنے
-فضلے
-فیتے
-فیلے
-فینے
-قبضے
-قبلے
-قتلے
-قشقے
-قصبے
-قطعے
-قعئے
-قلعے
-قیقے
-قیمے
-کبکے
-کتبے
-کتلے
-کتنے
-کتھے
-کٹتے
-کٹکے
-کٹنے
-کٹئے
-کٹھے
-کجلے
-کچلے
-کستے
-کسلے
-کسنے
-کسئے
-کعبے
-کلتے
-کلچے
-کلمے
-کلنے
-کلئے
-کملے
-کمنے
-کنبے
-کنجے
-کنکے
-کیسے
-کیفے
-کیکے
-کیئے
-کیلے
-کہتے
-کہکے
-کہنے
-کہئے
-کھبے
-کھپے
-کھتے
-کھٹے
-کھسے
-کھلے
-کھنے
-کھئے
-گپکے
-گپھے
-گتکے
-گتھے
-گٹکے
-گٹھے
-گجھے
-گلتے
-گلنے
-گلئے
-گمتے
-گملے
-گمنے
-گمئے
-گنتے
-گنجے
-گننے
-گنئے
-گیگے
-گیلے
-گہکے
-گہنے
-گھپے
-گھتے
-گھٹے
-گچھے
-گھسے
-گھلے
-گھنے
-گھئے
-لپٹے
-لپکے
-لٹتے
-لٹکے
-لٹنے
-لٹئے
-لجھے
-لچتے
-لچکے
-لچنے
-لچئے
-لچھے
-لشتے
-لقمے
-لکتے
-لکنے
-لکئے
-لکھے
-لگتے
-لگنے
-لگئے
-لمبے
-لمحے
-لمکے
-لمیے
-لنگے
-لیپے
-لیٹے
-لیجے
-لیچے
-لیسے
-لیکے
-لیگے
-لیمے
-لینے
-لیئے
-لہٹے
-لہجے
-لہکے
-متتے
-متلے
-متنے
-متھے
-مٹتے
-مٹکے
-مٹنے
-مٹئے
-مثلے
-مجلے
-مجھے
-مچتے
-مچکے
-مچلے
-مچنے
-مچئے
-مچھے
-محلے
-مستے
-مسے
-مسکے
-مسلے
-مسنے
-مسئے
-مشتے
-مشکے
-معمے
-مکتے
-مکنے
-مکئے
-ملبے
-ملتے
-ملنے
-ملئے
-منتے
-منکے
-منگے
-مننے
-میٹے
-میجے
-میچے
-میکے
-میلے
-میئے
-مہکے
-نبٹے
-نبھے
-نپتے
-نپٹے
-نپنے
-نپئے
-نتتے
-نٹتے
-نٹنے
-نٹئے
-نجتے
-نجنے
-نجھے
-نچتے
-نچکے
-نچلے
-نچنے
-نچھے
-نحلے
-نخشے
-نستے
-نسخے
-نسلے
-نسنے
-نسئے
-نشچے
-نطفے
-نغمے
-نفعے
-نقشے
-نقطے
-نکتے
-نکٹے
-نکسے
-نکلے
-نکمے
-نکنے
-نکئے
-نکھے
-نگتے
-نگٹے
-نگلے
-نگنے
-نگئے
-نگھے
-نلکے
-نمٹے
-ننگے
-ننھے
-نیٹے
-نیچے
-نیفے
-نیلے
-نہتے
-نہلے
-ئینے
-یتنے
-یٹھے
-یجئے
-یکتے
-یکھے
-یگچے
-یلٹے
-ہپتے
-ہپنے
-ہپئے
-ہٹتے
-ہٹنے
-ہٹئے
-ہچکے
-ہفتے
-ہکتے
-ہکلے
-ہکنے
-ہکئے
-ہگتے
-ہگنے
-ہگئے
-ہلتے
-ہلکے
-ہلگے
-ہلنے
-ہلئے
-ہمتے
-ہمکے
-ہمنے
-ہنسے
-ہٹیے
-ہیضے
-ھپتے
-ھپنے
-ھپئے
-ھچکے
-ھکتے
-ھکنے
-ھکئے
-ھلتے
-ھلکے
-ھلنے
-ھلئے
-ھمکے
-ھنتے
-ھنسے
-ھنکے
-ھنگے
-ھننے
-ھنئے
-ھنیے
-ھیلے
-ھیمے
-ھینے
-بخیہ
-بستہ
-بسکہ
-بغچہ
-بقچہ
-بقعہ
-بقیہ
-بلکہ
-بلیہ
-بمعہ
-بغچہ
-بیحہ
-بیشہ
-بیضہ
-بیعہ
-بیگہ
-بیلہ
-بیمہ
-بینہ
-پٹنہ
-پختہ
-پستہ
-پسنہ
-پشتہ
-پنبہ
-پنجہ
-پیسہ
-پیشہ
-پہیہ
-تتمہ
-تتیہ
-تحفہ
-تحیہ
-تختہ
-تخمہ
-تسمہ
-تشتہ
-تشنہ
-تغمہ
-تفتہ
-تقیہ
-تکمہ
-تکیہ
-تلخہ
-تلہہ
-تمغہ
-تنبہ
-تنگہ
-تیجہ
-تیشہ
-تیغہ
-تہیہ
-ٹکیہ
-ٹیکہ
-ٹیلہ
-ثیبہ
-جبکہ
-جبہہ
-جستہ
-جفتہ
-جلسہ
-جمعہ
-جملہ
-جنبہ
-جیعہ
-جیہہ
-چستہ
-چشمہ
-چکمہ
-چلتہ
-چمبہ
-چمچہ
-چیچہ
-چیمہ
-حبشہ
-حجتہ
-حجفہ
-حجلہ
-حسنہ
-حشفہ
-حقنہ
-حلقہ
-حلیہ
-حمتہ
-حملہ
-حمنہ
-حیطہ
-حیلہ
-حیمہ
-ختنہ
-خستہ
-خشکہ
-خصیہ
-خطبہ
-خطحہ
-خفتہ
-خفیہ
-خلیفہ
-خلیہ
-خمسہ
-خیمہ
-سبحہ
-ستمہ
-سفلہ
-سقہ
-سکتہ
-سکنہ
-سلحہ
-سلمہ
-سنبہ
-سیسہ
-سیفہ
-سیلہ
-سینہ
-شبکہ
-شبیہ
-شحنہ
-شستہ
-شعبہ
-شعفہ
-شغفہ
-شفتہ
-شفعہ
-شمسہ
-شملہ
-شنبہ
-شیبہ
-شیتہ
-شیشہ
-شیعہ
-شیلہ
-صبیہ
-صفحہ
-صفیہ
-صلچہ
-صیحہ
-صیعہ
-صیغہ
-ضحیہ
-ضعطہ
-ضیکہ
-ضیمہ
-ضیلہ
-طبقہ
-طبلہ
-طعمہ
-طعنہ
-طلبہ
-طمتہ
-طمیہ
-طنجہ
-طیبہ
-طیسو
-طیکہ
-ظیفہ
-عتبہ
-عشبہ
-عصبہ
-عضلہ
-عطیہ
-علفہ
-علیہ
-عملہ
-غبطہ
-غشتہ
-غلبہ
-غلطہ
-غنچہ
-فتحہ
-فتنہ
-فضلہ
-فعیہ
-فغفو
-فقیہ
-فیعہ
-فیقہ
-فینہ
-قبضہ
-قتلہ
-قحبہ
-قشقہ
-قصبہ
-قضیہ
-قطعہ
-قلبہ
-قلعہ
-قلیہ
-قمشہ
-قیقہ
-قیمہ
-کپچہ
-کتبہ
-کشتہ
-کعبہ
-کفچہ
-کلبہ
-کلچہ
-کلمہ
-کلیہ
-کنبہ
-کنیہ
-کیسہ
-کینہ
-کہنہ
-گنجفہ
-گستہ
-گشتہ
-گفتہ
-گینہ
-گہنہ
-لبتہ
-لجثہ
-لحجہ
-لحظہ
-لصفہ
-لطمہ
-لطہ
-لفتہ
-لقصہ
-لقطہ
-لقمہ
-للہ
-للھ
-لمحہ
-لمعہ
-لمیہ
-لیچہ
-لیلہ
-لیمہ
-لہجہ
-متعہ
-مثلہ
-مجلہ
-محلہ
-مسکہ
-معمہ
-مقلہ
-ملبہ
-ملکہ
-میلہ
-میمہ
-نبیہ
-نجمہ
-نستہ
-نسخہ
-نسیہ
-نطفہ
-نغمہ
-نفقہ
-نقشہ
-نقطہ
-نقیہ
-نکتہ
-نگیہ
-نملہ
-نیفہ
-نیلہ
-ئستہ
-ئنچہ
-ئیسہ
-ئیکہ
-ئیلہ
-ئینہ
-یبیہ
-یجتہ
-یختہ
-یفتہ
-یقظہ
-یگچہ
-ینکہ
-ہستہ
-ہفتہ
-ہلیہ
-ہیضہ
-ہیمہ
-ہینہ
-ھنیہ
-ھیلہ
-بیٹھ
-پنتھ
-پنکھ
-پیتھ
-ٹھٹھ
-جیتھ
-جیٹھ
-جھٹھ
-چیتھ
-چھٹھ
-سکچھ
-سلجھ
-سمجھ
-سنکھ
-سنگھ
-سیٹھ
-سیکھ
-کسٹھ
-کمبھ
-لنگھ
-لیتھ
-لیٹھ
-لیکھ
-ملچھ
-منجھ
-میٹھ
-میکھ
-میگھ
-مینھ
-نسٹھ
-یسٹھ
-ینٹھ
-ہیتھ
-بقیہ
-حتی
-صلو
-ضحی
-عشی
-علی
-منی
-یحیی
-بطنا
-جیہا
-حلفا
-خصتا
-سہلا
-ضمنا
-طبعا
-عبید
-غصبا
-عقلا
-عملا
-فعلا
-قطعا
-قعتا
-لصتا
-لفظا
-مثلا
-نسلا
-نسیا
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/5grams.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/5grams.txt
deleted file mode 100644 (file)
index f61dbce..0000000
+++ /dev/null
@@ -1,5029 +0,0 @@
-ببیسا
-بپتنا
-بتکتا
-بتیسا
-بتیلا
-بتھلا
-بجبجا
-بجلیا
-بجھتا
-بجھیا
-بچپنا
-بچکتا
-بچلتا
-بچھتا
-بچھیا
-بحثیا
-بختیا
-بخشتا
-بستگا
-بستیا
-بسیما
-بطگیا
-بغچیا
-بقچیا
-بکبکا
-بکستا
-بکسلا
-بکسیا
-بکیلا
-بگستا
-بگھیا
-بلبلا
-بلٹتا
-بلٹیا
-بلکتا
-بللا
-بلنگا
-بلیسا
-بلیغا
-بلیلا
-بنٹتا
-بنجتا
-بنگلا
-بیتتا
-بیتلا
-بیتیا
-بیٹھا
-بیجتا
-بیچتا
-بیسیا
-بیشما
-بیکسا
-بیکلا
-بیگما
-بیلتا
-بینتا
-بینکا
-بیننا
-بھبھا
-بہکتا
-بہلتا
-بہنیا
-بہئیا
-بہیما
-بھبکا
-بھبھا
-بھلتا
-بھپکا
-بھتنا
-بھٹکا
-بھٹیا
-بھجتا
-بھجیا
-بھچتا
-بھچکا
-بھچنا
-بھسکا
-بھکتا
-بھکیا
-بھگتا
-بھگیا
-بھلیا
-بھینا
-پپلیا
-پپیتا
-پپیہا
-پتلیا
-پتنگا
-پتنیا
-پتیلا
-پتھتا
-پتھنا
-پٹپٹا
-پٹختا
-پٹخیا
-پٹکتا
-پٹیلا
-پٹیما
-پٹھیا
-پچپچا
-پچکتا
-پچھتا
-پچلج
-پچیا
-پستیا
-پسلیا
-پسنگا
-پسیجا
-پسینا
-پشیما
-پکپکا
-پگلتا
-پگلیا
-پگھلا
-پلپلا
-پلٹتا
-پلٹیا
-پلیتا
-پنپتا
-پنجتا
-پنجسا
-پنجنا
-پنچسا
-پنکھا
-پنیلا
-پنیھا
-پنھیا
-پیپٹا
-پیپگا
-پیپلا
-پیٹتا
-پیٹیا
-پیٹھا
-پیچھا
-پیستا
-پیشتا
-پیشکا
-پیشیا
-پیلبا
-پیلپا
-پیلتا
-پیلیا
-پینتا
-پہنتا
-پہنچا
-پہننا
-پھبتا
-پھبکا
-پھبنا
-پھپسا
-پھپکا
-پھپیا
-پھپھا
-پھٹتا
-پھٹکا
-پھٹگا
-پھٹنا
-پھسکا
-پھسلا
-پھکتا
-پھلتا
-پھلکا
-پھلنا
-پھنتا
-پھنسا
-پھنکا
-پھننا
-پھنیا
-پھیکا
-پھیلا
-تپسیا
-تپکتا
-تتلیا
-تتئیا
-تثینا
-تجلیا
-تجملا
-تحفظا
-تحکما
-تختیا
-تسلیا
-تشنگا
-تعصبا
-تعلقا
-تعلا
-تعیشا
-تعینا
-تکتکا
-تکلفا
-تکلیا
-تلتلا
-تلخیا
-تلملا
-تلنگا
-تمتما
-تمسکا
-تمکنا
-تنبیا
-تنتنا
-تنکتا
-تنگیا
-تیجتا
-تیکھا
-تیلیا
-تینتا
-تھپتا
-تھپکا
-تھپنا
-تھتکا
-تھتھا
-تھجتا
-تھکتا
-تھلتا
-تھلکا
-تھلنا
-تھلیا
-تھمتا
-تھنچا
-تھیا
-تھیلا
-ٹپٹپا
-ٹپکتا
-ٹپیلا
-ٹخنیا
-ٹکٹکا
-ٹکسٹا
-ٹکسلا
-ٹکلیا
-ٹگھلا
-ٹلٹلا
-ٹمٹما
-ٹنٹنا
-ٹنگتا
-ٹیپتا
-ٹیکتا
-ٹیکسا
-ٹیکنا
-ٹیکتا
-ٹینٹا
-ٹہلتا
-ٹہلیا
-ٹہنیا
-ٹھپنا
-ٹھٹکا
-ٹھٹھا
-ٹھستا
-ٹھسکا
-ٹھسنا
-ٹھکتا
-ٹھگتا
-ٹھگیا
-ٹھلتا
-ٹھلیا
-ٹھمکا
-ٹھنتا
-ٹھنسا
-ٹھنکا
-ٹھننا
-ٹھیبا
-ٹھیکا
-ٹھیگا
-ٹھیلا
-جیتتا
-جستھا
-جسیلا
-جعلسا
-جعلیا
-جگتیا
-جگجگا
-جگمگا
-جلبلا
-جلیبا
-جمیکا
-جنٹیا
-جنجنا
-جنسیا
-جنگلا
-جیتتا
-جیٹھا
-جینیا
-جھپٹا
-جھپکا
-جھٹکا
-جھٹلا
-جھٹنا
-جھجکا
-جھجلا
-جھجنا
-جھکتا
-جھکیا
-جھگیا
-جھلتا
-جھلسا
-جھلکا
-جھلما
-جھلنا
-جھلیا
-جھمکا
-جھجنا
-جھنکا
-جھنگا
-جھیلا
-جھینا
-چبکتا
-چبینا
-چبھتا
-چپتیا
-چپٹتا
-چپچپا
-چپکتا
-چپکیا
-چپیٹا
-چتھلا
-چٹختا
-چٹکتا
-چٹکلا
-چٹکیا
-چٹنیا
-چٹیلا
-چٹھیا
-چسکتا
-چسکیا
-چسنیا
-چشتیا
-چغلیا
-چکٹتا
-چکلتا
-چکنیا
-چکھتا
-چلبلا
-چلچلا
-چلکنا
-چلیپا
-چمٹتا
-چمٹیا
-چمچما
-چمچیا
-چمکتا
-چمنیا
-چنبھا
-چنچنا
-چنکیا
-چنگلا
-چنگنا
-چنگیا
-چنگھا
-چیپتا
-چیتپا
-چیختا
-چیستا
-چیلکا
-چینٹا
-چینگا
-چہچہا
-چہکتا
-چہیتا
-چھپتا
-چھپکا
-چھپنا
-چھتیا
-چھٹتا
-چھٹکا
-چھٹنا
-چھٹیا
-چھچکا
-چھلتا
-چھلکا
-چھلیا
-چھنتا
-چھنگا
-چھننا
-چھیجا
-چھیکا
-چھیلا
-چھینا
-حتینا
-حسینا
-حکیما
-حنفیا
-حیتنا
-حیثیا
-خصتیا
-خطیبا
-خفتگا
-خلفشا
-خمچیا
-خمیسا
-خنخنا
-سبکسا
-سبکنا
-سبکیا
-سبلیا
-سبیتا
-ستبصا
-ستبعا
-ستثنا
-ستحسا
-ستحصا
-ستحقا
-ستحکا
-ستخفا
-ستخلا
-ستسقا
-ستشہا
-ستعجا
-ستعقا
-ستعلا
-ستعما
-ستغفا
-ستغنا
-ستفتا
-ستفسا
-ستفہا
-ستقبا
-ستقلا
-ستکبا
-ستکشا
-ستکما
-ستلیا
-ستنبا
-ستنجا
-ستیصا
-ستیعا
-ستیلا
-ستیہا
-ستھیا
-سٹکتا
-سٹنہا
-سٹھیا
-سجنیا
-سجیلا
-سختیا
-سسکتا
-سسکیا
-سکیلا
-سکھلا
-سکھیا
-سلٹنا
-سلجھا
-سلسلا
-سلگتا
-سلمہا
-سلنگا
-سلیکا
-سلیما
-سمٹتا
-سمجھا
-سمیٹا
-سنبھا
-سنجتا
-سنجھا
-سنچکا
-سنسنا
-سنکتا
-سنکیا
-سنگسا
-سنگلا
-سنگھا
-سنیگا
-سنیما
-سیپیا
-سیتلا
-سیٹھا
-سیستا
-سیکھا
-سیلتا
-سیمیا
-سینتا
-سینچا
-سینکا
-سینگا
-سینما
-سینیا
-سہلتا
-سہمتا
-شتیہا
-شخصیا
-شطحیا
-شکیبا
-شگنیا
-شلنگا
-شلیتا
-شمنیا
-شنگھا
-شیخیا
-شیشیا
-شہنشا
-ضعیفا
-ضمحلا
-طبیعا
-طلبگا
-طلسما
-طمینا
-طیلسا
-عسقلا
-عصبیا
-عملیا
-عنہما
-غسلخا
-غصیلا
-غضبنا
-غلبلا
-غلطیا
-غمگسا
-غنغنا
-فتحیا
-فتینا
-فسنجا
-فضیتا
-فعلیا
-فلکیا
-فلمسا
-فلیپا
-فیضیا
-فیلبا
-فیلپا
-فہمیا
-قلتیا
-قلفیا
-قلمکا
-قلیما
-کپکپا
-کٹکتا
-کٹنیا
-کٹیکا
-کٹیلا
-کٹھلا
-کٹھنا
-کچکچا
-کچلتا
-کچیلا
-کچھنا
-کسبیا
-کسلتا
-کسلیا
-کسنبا
-کسیلا
-کشتگا
-کشتیا
-ککھلا
-کلبلا
-کلپنا
-کلتکا
-کلٹیا
-کلچیا
-کلسنا
-کلغیا
-کلکتا
-کلکلا
-کلکنا
-کلیجا
-کلیسا
-کلھیا
-کمٹھا
-کملتا
-کمیسا
-کمیلا
-کمھلا
-کنٹھا
-کنجیا
-کنکتا
-کنکیا
-کنگلا
-کنگنا
-کنگھا
-کنلیا
-کنمنا
-کنہیا
-کیتیا
-کیتھا
-کیٹلا
-کیخلا
-کیسیا
-کیشیا
-کیفیا
-کیقبا
-کیکبا
-کیکتا
-کیلتا
-کیمیا
-کینیا
-کیہلا
-کہکشا
-کھپٹا
-کھپلا
-کھپنا
-کھتیا
-کھٹکا
-کھٹلا
-کھٹنا
-کھٹیا
-کھجلا
-کھستا
-کھسکا
-کھسلا
-کھسنا
-کھسیا
-کھکھا
-کھلتا
-کھلگا
-کھلنا
-کھلیا
-کھمبا
-کھما
-کھنچا
-کھنسا
-کھنگا
-کھتیا
-کھیسا
-کھیلا
-کھینا
-گپکتا
-گتھتا
-گتھیا
-گٹکتا
-گٹکیا
-گٹھتا
-گٹھیا
-گجگجا
-گچھیا
-گشتپا
-گلبہا
-گلٹیا
-گلستا
-گلگلا
-گنتیا
-گنٹھا
-گنجیا
-گنگنا
-گنہگا
-گیگلا
-گہکتا
-گھپتا
-گھپلا
-گھپنا
-گھٹتا
-گھٹکا
-گھٹنا
-گھٹیا
-گھچلا
-گھستا
-گھسیا
-گھگیا
-گھلتا
-گھلیا
-گھمسا
-گھنٹا
-گھنسا
-گھنیا
-گھیگا
-گھیلا
-لبلبا
-لبیلا
-لپٹتا
-لپکتا
-لپلپا
-لپیٹا
-لٹکتا
-لیٹنا
-لٹھیا
-لجلجا
-لجھتا
-لجھیا
-لچکتا
-لچلچا
-لچھتا
-لچھیا
-لحمقا
-لحمیا
-لخلخا
-لسبحا
-لسلسا
-لشعشا
-لشہبا
-لطلا
-لعلما
-لفظیا
-لفنگا
-لکشیا
-لکلیا
-لکھتا
-لکھیا
-لگنیا
-لگیلا
-للبقا
-لمپیا
-لمتعا
-لمتخا
-لمکتا
-لمیعا
-لنجھا
-لنگتا
-لنگیا
-لنگھا
-لیپتا
-لیٹتا
-لیچتا
-لیچیا
-لیستا
-لیسیا
-لیکھا
-لہکتا
-لہلہا
-لہنگا
-لہنیا
-لہیا
-مبتلا
-مبہیا
-متصفا
-متھتا
-مٹکتا
-مٹکیا
-مٹھیا
-مجسما
-مجلا
-مچکتا
-مچلتا
-محسنا
-محصنا
-محققا
-محکما
-محنتا
-مختیا
-مخلصا
-مخمسا
-مسبحا
-مستجا
-مستعا
-مشفقا
-مشکبا
-مشکلا
-مشکیا
-مصلحا
-معلقا
-معلما
-مغلظا
-مغیلا
-مفصلا
-مفلسا
-مقتضا
-مقطعا
-مکھنا
-مکھیا
-ملگجا
-ملنسا
-ملیسا
-ممکنا
-منجلا
-منجنا
-منجھا
-منچلا
-منشیا
-منصفا
-منگتا
-منگلا
-منگنا
-منگیا
-منمنا
-منیلا
-منہنا
-منہیا
-میٹتا
-میٹیا
-میٹھا
-میجتا
-میچتا
-میگھا
-میلیا
-میمنا
-میہما
-مہکتا
-مہملا
-مہنتا
-مہنگا
-مہیلا
-مہینا
-نبٹتا
-ننجتا
-نبھتا
-نپٹتا
-نپجتا
-نتیلا
-نتھلا
-نتھنا
-نتھیا
-نٹنیا
-نٹینا
-نٹھتا
-نجمنا
-نجھتا
-نچنیا
-نچھتا
-نشیلا
-نظمیا
-نفسیا
-نکسلا
-نکلتا
-نکمیا
-نکیلا
-نکھتا
-نکھیا
-نگستا
-نگلتا
-نگلیا
-نگیلا
-نگہبا
-نگھتا
-نمٹتا
-نمسکا
-نمکیا
-ننھیا
-نیٹنا
-نیشیا
-نیکیا
-نیکھا
-نیمیا
-ئیشیا
-ئیگیا
-یپلکا
-یتیلا
-یخنیا
-یستبا
-یکھتا
-یگچیا
-یگستا
-یمپلا
-ینٹھا
-ینکتا
-ینگتا
-ینگیا
-ہپہپا
-ہتھیا
-ہٹکنا
-ہٹیلا
-ہٹھیا
-ہچکتا
-ہچکچا
-ہچکیا
-ہسپتا
-ہستیا
-ہلبلا
-ہلپھا
-ہلگتا
-ہلینا
-ہلہلا
-ہمپشا
-ہمکتا
-ہمکیا
-ہنستا
-ہنسیا
-ہنگیا
-ہنہنا
-ہیلنا
-ہینسا
-ہینگا
-ھکنیا
-ھکیلا
-ھلکتا
-ھلکیا
-ھلملا
-ھمکتا
-ھمکیا
-ھنستا
-ھنسیا
-ھنکتا
-ھنکیا
-ھینگا
-بطیب
-تشبیب
-تصلیب
-تنصیب
-کینٹب
-لجیب
-لحسیب
-لحصیب
-لمجیب
-متعجب
-متعصب
-مجتنب
-محتسب
-مسبب
-مستجب
-مسیب
-منتخب
-منتسب
-جھینپ
-سٹیمپ
-سنکلپ
-گھینپ
-بشکست
-بعجلت
-ٹھینگے
-تبنیت
-تمکنت
-تہنیت
-جمعیت
-جنبیت
-جنسیت
-جھٹنت
-حقیقت
-حیثیت
-سلطنت
-سنگیت
-شخصیت
-شیطنت
-شیعیت
-طبیعت
-طیسیت
-عصبیت
-عظیمت
-عقلیت
-علمیت
-غنیمت
-فضیلت
-فضیحت
-فضیلت
-قطبیت
-قطعیت
-کمیت
-کیفیت
-کیمخت
-گھٹنت
-لپھیت
-لٹھیٹ
-لحکمت
-لخلقت
-لعصمت
-لکھپت
-لمقیت
-لممیت
-مسکنت
-مصلحت
-مصیبت
-معصیت
-معیشت
-معیئت
-ملتفت
-ملکیت
-مملکت
-منفعت
-منقبت
-میمنت
-نصیحت
-ئیلیت
-یکلخت
-یکمشت
-ہلسنت
-بیسنٹ
-بھینٹ
-پمفلٹ
-پنگھٹ
-پیٹنٹ
-پھینٹ
-تلچھٹ
-ٹسٹنٹ
-ٹیکسٹ
-جھپیٹ
-جھنجٹ
-چھینٹ
-سٹمنٹ
-سسپنٹ
-سسٹنٹ
-سلفیٹ
-سلیکٹ
-سیمنٹ
-شپمنٹ
-کیبنٹ
-کیمسٹ
-گھسیٹ
-گھینٹ
-لپٹنٹ
-لپمنٹ
-لٹھیٹ
-لجئیٹ
-لفٹنٹ
-میگنٹ
-نیٹنٹ
-ئنٹسٹ
-ہیلمٹ
-بھتیج
-چیلنج
-بھینچ
-پھینچ
-کھینچ
-تسبیح
-تصحیح
-تلمیح
-تنقیح
-مصطلح
-تنسیخ
-بخشند
-بسیند
-بینند
-پنجند
-پیجند
-پیچید
-تجلید
-تحمید
-تصعید
-تعقید
-تفسید
-تقلید
-تکسید
-تمجید
-تمحید
-تمہید
-تنفید
-تنقید
-تہبند
-جتمند
-جمشید
-چھلبد
-خشکید
-سمبند
-سمجھد
-سنجید
-علیحد
-فہمید
-کھلند
-لتمند
-لحمید
-لسعید
-لشہید
-لعقید
-لکھند
-لمجید
-لمسجد
-لمیعد
-لمقتد
-مجتہد
-مچھند
-مستبد
-مستعد
-مستند
-معتضد
-معتمد
-منجمد
-منجھد
-منعقد
-مہمند
-نشمند
-ہشمند
-بلینڈ
-بھٹنڈ
-پیگنڈ
-تلینڈ
-چچینڈ
-سٹینڈ
-سیکنڈ
-سگمنڈ
-شفیلڈ
-کلینڈ
-کنفیڈ
-کیتھڈ
-کیلنڈ
-کیلیڈ
-کینیڈ
-کھلنڈ
-گلینڈ
-گھمنڈ
-لمیٹڈ
-مشٹنڈ
-میتھڈ
-یمبلڈ
-ہسبنڈ
-تلمیذ
-فلہذ
-بجھبر
-بچھیر
-بکٹیر
-بکھیر
-بگستر
-بلیچر
-بیچلر
-بینجر
-بیشتر
-بینٹر
-بینکر
-بہتیر
-بھسٹر
-بھمبر
-بھیتر
-بھیکر
-پبلشر
-پتمبر
-پچھتر
-پسنجر
-پکھیر
-پلستر
-پلمبر
-پلیئر
-پنجیر
-پنشنر
-پنکچر
-پیسٹر
-پیشتر
-پیمبر
-پینتر
-پھپیر
-پھٹکر
-پھلسر
-تبختر
-تحقیر
-تخمیر
-تسخیر
-تسطیر
-تشہیر
-تصغیر
-تطہیر
-تظہیر
-تعبیر
-تعمیر
-تغیر
-تفسیر
-تقصیر
-تقطیر
-تکبیر
-تکثیر
-تکسیر
-تکفیر
-تمسخر
-تنکیر
-تینیر
-تھپیر
-تھمبر
-تھیٹر
-تھیچر
-ٹنکچر
-ٹیسٹر
-ٹیلگر
-ٹیمبر
-ٹینکر
-ٹھپکر
-ٹھیٹر
-ٹھٹھر
-ٹھیکر
-جمبیر
-جیکٹر
-جینیر
-جھجھر
-جھنجر
-جھنگر
-چمچیر
-چنگیر
-چنیسر
-چیٹھر
-چیکٹر
-چیمبر
-چھہتر
-سپنسر
-سپئیر
-سپیکر
-ستغفر
-ستگیر
-ستمبر
-ستمگر
-سٹمپر
-سٹینر
-سٹیکر
-سٹیمر
-سٹیئر
-سکیٹر
-سکیسر
-سکیلر
-سکینر
-سگنلر
-سلیپر
-سلیٹر
-سمسٹر
-سمگلر
-سنپٹر
-سنپیر
-سنتگر
-سنسکر
-سنگتر
-سنئیر
-سنیٹر
-سنیچر
-سکیٹر
-سینٹر
-سینسر
-سینئر
-شلیپر
-شمشیر
-شیلٹر
-علمبر
-غضنفر
-فیکٹر
-فیکچر
-قطمیر
-کبیسر
-کبیشر
-کٹیٹر
-کسٹمر
-کسمپر
-کسنجر
-کشمیر
-کفگیر
-کلکٹر
-کلنسر
-کلینر
-کمشنر
-کمنٹر
-کنٹھر
-کنستر
-کیتھر
-کیسٹر
-کیمبر
-کینبر
-کینسر
-کھنجر
-کھنکر
-کھنگر
-کھچر
-گلیسر
-گلیمر
-گنینر
-گھبیر
-گھگر
-گھمیر
-گھنگر
-گھنیر
-لبصیر
-لتھیر
-لخبیر
-لصغیر
-لکبیر
-لکھیر
-لمطہر
-لمگیر
-لمنظر
-لنٹیر
-لنصیر
-لیسٹر
-لیکٹر
-لیکچر
-لینبر
-لینٹر
-متبحر
-متحیر
-متشکر
-متغیر
-متفکر
-متکبر
-متنفر
-مجسٹر
-مختصر
-مخیر
-مستتر
-مسخر
-مستشر
-مستغر
-مستقر
-مستمر
-مشتہر
-مشینر
-معتبر
-مکسچر
-منتشر
-منتظر
-منجیر
-منچھر
-منحصر
-منسٹر
-منگسر
-منیجر
-میکنز
-منیجر
-نٹسیر
-نچسٹر
-نچھتر
-نخچیر
-نسسٹر
-نکسیر
-نکھتر
-نگسیر
-نگشتر
-نیشتر
-نیکلر
-ئیجیر
-یفلگر
-یکسپر
-یکلچر
-یمسٹر
-ینسٹر
-ینکفر
-ہمشیر
-ہمعصر
-ہیتھر
-ہیمبر
-ہینگر
-بتنگڑ
-بکھیڑ
-بلکھڑ
-بھیکڑ
-پلنگڑ
-پھسکڑ
-پھکڑ
-پھیپڑ
-تھپیڑ
-جھمکڑ
-جھنگڑ
-چمچیڑ
-چیتھڑ
-چیٹھڑ
-چیلھڑ
-چھچھڑ
-چھیچڑ
-سینکڑ
-سینگڑ
-علیگڑ
-کلنگڑ
-کلیگڑ
-کھچیڑ
-کھکیڑ
-کھنگڑ
-گنٹھڑ
-گھسیڑ
-لتھیڑ
-مسکیڑ
-ہتھکڑ
-پیپلز
-پیکلز
-تجہیز
-ٹیشنز
-ٹیکلز
-چنگیز
-سکیچز
-سگنلز
-سنگلز
-کسٹمز
-کشنیز
-متمیز
-مستلز
-مستیز
-مشکیز
-ممیز
-میکنز
-مہمیز
-نیپلز
-نیشنز
-ئیکلز
-یتھنز
-ینجلز
-بلقیس
-بیلنس
-بھینس
-پچیس
-پلیکس
-پینٹس
-تجسس
-تجنیس
-ٹمنٹس
-ٹیلکس
-چھبیس
-چھتیس
-خلیفہ
-سپکٹس
-سٹیٹس
-سمٹکش
-سنگلس
-سنیکس
-فٹنگس
-فلیٹس
-کلپٹس
-کیمپس
-گھنیس
-لخمیس
-لشمس
-لمپکس
-لیٹکس
-لیمپس
-متجسس
-متنفس
-ملتمس
-منعکس
-نلسٹس
-ئمیکس
-ئیسنس
-یجنٹس
-یلیکس
-ینجلس
-پیچکش
-پیشکش
-تفتیش
-چپقلش
-کشمکش
-گھنیش
-تخصیص
-تخلیص
-تشخیص
-تلخیص
-تمحیص
-تنقیص
-لتخلص
-متخلص
-تخلیط
-ٹپن
-لقلیط
-لمقسط
-منضبط
-تحفظ
-لحفیظ
-تشنیع
-تقطیع
-لسمیع
-لشفیع
-لمبلغ
-لمطیع
-لمقطع
-متمتع
-مجتمع
-ممتنع
-منقطع
-تبلیغ
-بللی
-تصحیف
-تصنیف
-تعطف
-تقشف
-تکثیف
-تکلیف
-تنصیف
-سنحیف
-للطیف
-متکلف
-مختلف
-مسقف
-مکلف
-منعطف
-منکشف
-تحقیق
-تخلیق
-تطبیق
-تعلیق
-لعتیق
-لمنطق
-متعلق
-مستحق
-منطبق
-ہنبق
-بیٹھک
-بھننک
-پیتھک
-پیسفک
-پھینک
-تشکیک
-تضحیک
-تکنیک
-تملیک
-ٹیکنک
-جھلنک
-جھینک
-چھینک
-کلینک
-کنجشک
-کھٹیک
-گنجلک
-مجسٹک
-منسلک
-منہمک
-ئنٹفک
-یپبلک
-بیٹنگ
-بیجنگ
-بھجنگ
-بھننگ
-پکٹنگ
-پمپنگ
-پئیگ
-پیکنگ
-پھننگ
-تھلنگ
-ٹیچنگ
-جمپنگ
-جیکنگ
-چیکنگ
-سپننگ
-سیکنگ
-فکسنگ
-فنشنگ
-کیپنگ
-کیٹنگ
-میپنگ
-میٹنگ
-میچنگ
-میکنگ
-میلنگ
-ئٹینگ
-ئٹینگ
-یشننگ
-یکٹنگ
-بسبیل
-بمشکل
-بیمثل
-پھٹکل
-پھلیل
-تجہیل
-تحصیل
-تحلیل
-تخلیل
-تخئیل
-تسلسل
-تسہیل
-تشکیل
-تعجیل
-تعطیل
-تعلیل
-تعمیل
-تفصل
-تفصیل
-تفضل
-تقلیل
-تکفیل
-تکمیل
-تمثیل
-تہلیل
-تھکیل
-ٹیمپل
-جھٹیل
-جھلمل
-جھمیل
-چھیچھڑ
-سپیشل
-سنججل
-سنبھل
-سنپتل
-سیمپل
-فیشنل
-فیشیل
-قیفیں
-کتھیل
-کیپٹل
-کیشنل
-کیمبل
-کینچل
-کینسل
-کینگل
-کھٹمل
-کھکھل
-لجلیل
-لجمیل
-لخلیل
-متحمل
-متکفل
-مچھیل
-محتمل
-مستقل
-مسجل
-مسلسل
-مشتعل
-مشتغل
-مشتمل
-مشخیل
-مضمحل
-معجل
-منتقل
-منفعل
-مینٹل
-مینگل
-نٹیبل
-نسٹبل
-نیشنل
-نینٹل
-ئیسکل
-ہینگل
-بلجیم
-بہنگم
-پچھم
-تجسیم
-تحکیم
-تسلیم
-تسنیم
-تصمیم
-تعظیم
-تعلم
-تعلیم
-تفہیم
-تقسیم
-تنجیم
-تنظیم
-تنعم
-تیمم
-ٹنگھم
-ٹھیکم
-جھیلم
-علیکم
-علیہم
-لبعلم
-لحکیم
-لحلیم
-لعظیم
-لعلیم
-لکلیم
-لمعظم
-لنعیم
-لیتیم
-تبسم
-متبسم
-متعلم
-متکلم
-محتشم
-مختتم
-معتصم
-منتظم
-منتقم
-منظم
-منقسم
-منگھم
-منمنا
-منہضم
-میکسم
-مہتمم
-نشینم
-بجکشن
-بلیٹن
-بینگن
-بھبکن
-بھپکن
-پھسلن
-بھنگن
-پبلکن
-پچھم
-پنجتن
-پیشین
-پھپکن
-پھٹکن
-پھسلن
-تھیلیا
-تبیین
-تحسین
-تخمین
-تسکین
-تضمین
-تکفین
-تلقین
-تلئیں
-تلیئن
-تمکین
-تیئین
-تھپکن
-ٹھٹکن
-ثقلین
-جنکشن
-جیکشن
-جھپٹن
-جھپکن
-جھٹکن
-چھلکن
-چھیجن
-چھیلن
-حسنین
-سبطین
-سٹفین
-سٹیشن
-سلجھن
-سلکشن
-سلکھن
-سنگین
-سیٹھن
-سیکشن
-سیمین
-سینچن
-سینکن
-شنگٹن
-شیخین
-علیین
-غمگین
-فنکشن
-قطبین
-کسیجن
-کلفٹن
-کلیمن
-کمیشن
-کنکشن
-کیپٹن
-کیپشن
-کیٹشن
-کیٹین
-کھٹکن
-کھنجن
-کھنچن
-گھسٹن
-لپیٹن
-لچھمن
-لحسین
-لحصین
-لستشن
-لمتین
-لمکین
-لنشین
-لنگٹن
-لیسین
-لیکسن
-لیکشن
-متعفن
-متعین
-متقین
-متمکن
-متنجن
-لمکین
-لنشین
-مسکین
-مطمئن
-ممتحن
-منقش
-میگلن
-مینشن
-نجبین
-نجکشن
-نشیمن
-نعلین
-نقشین
-نگبین
-نمکین
-نیپکن
-نیلشن
-ئمکین
-ئیشین
-یٹکشن
-یکسین
-یملین
-یسین
-ہمپٹن
-ہملٹن
-بپتیں
-بتتیں
-بتکیں
-بتیس
-بٹتیں
-بجبیں
-بجتیں
-بجھیں
-بچتیں
-بچکیں
-بچلیں
-بچھیں
-بحثیں
-بخشیں
-بستیں
-بطخیں
-بغلیں
-بکتیں
-بلتیں
-بلکیں
-بنتیں
-بنچیں
-بیتیں
-بیچیں
-بیلیں
-بینیں
-بہتیں
-بہکیں
-بہلیں
-بہنیں
-بھچیں
-بھکیں
-بھلیں
-بھنیں
-پتتیں
-پتھیں
-پٹتیں
-پٹخیں
-پٹکیں
-پچتیں
-پچکیں
-پچھیں
-پستیں
-پکتیں
-پگلیں
-پلتیں
-پلکیں
-پنپیں
-پیتیں
-پیشیں
-پیلیں
-پہنیں
-پھبیں
-پھکیں
-پھلیں
-تپتیں
-تپکیں
-تچتیں
-تگتیں
-تلتیں
-تلئیں
-تمہیں
-تنتیں
-تنکیں
-تیغیں
-تھپیں
-تھتیں
-تھجیں
-تھکیں
-تھلیں
-تھمیں
-ٹپتیں
-ٹپکیں
-ٹکتیں
-ٹکٹیں
-ٹلتیں
-ٹنگیں
-ٹیپیں
-ٹیکیں
-ٹیمیں
-ٹہلیں
-ٹھتیں
-ٹھسیں
-ٹھگیں
-ٹھلیں
-ٹھنیں
-جپتیں
-جتتیں
-جچتیں
-جگتیں
-جگہیں
-جلتیں
-جلیس
-جمپیں
-جنتیں
-جنسیں
-جنگیں
-جنہیں
-جنھیں
-جیپیں
-جیتیں
-جیلیں
-جیہیں
-جہتیں
-جھتیں
-جھکیں
-جھلیں
-چبتیں
-چبکیں
-چبلیں
-چبھیں
-چپتیں
-چپٹیں
-چپکیں
-چپلیں
-چتتیں
-چٹخیں
-چٹکیں
-چسکیں
-چکلیں
-چکھیں
-چگتیں
-چلتیں
-چمٹیں
-چمکیں
-چنتیں
-چیپیں
-چیخیں
-چیلیں
-چہکیں
-چھپیں
-چھتیں
-چھلیں
-چھنیں
-حبتیں
-حجتیں
-حشتیں
-حمتیں
-حیتیں
-خلتیں
-ستتیں
-سٹکیں
-سجتیں
-سسکیں
-سعتیں
-سکتیں
-سلتیں
-سلگیں
-سمتیں
-سنتیں
-سنگیں
-سیتیں
-سیجیں
-سیخیں
-سیکیں
-سیلیں
-سیمیں
-چیلنج
-سہتیں
-سہلیں
-سہمیں
-شفٹیں
-شکلیں
-شکنیں
-شلفیں
-شمعیں
-صحتیں
-صفتیں
-صیتیں
-شفٹیں
-علتیں
-غمگیں
-عنیں
-عیتیں
-غبتیں
-غمگیں
-فصلیں
-فعتیں
-فلمیں
-فیسیں
-قسطیں
-قسمیں
-قلتیں
-قلمیں
-کٹتیں
-کٹکیں
-کچلیں
-کستیں
-کسلیں
-کعتیں
-کلتیں
-کملیں
-کیبیں
-کیکیں
-کیلیں
-کہتیں
-کھپیں
-کھتیں
-کھٹیں
-کھلیں
-گپکیں
-گتھیں
-گٹکیں
-گٹھیں
-گلتیں
-گنتیں
-گیسیں
-گہکیں
-گھٹیں
-گھچیں
-گھسیں
-گھلیں
-لپٹیں
-لپکیں
-لٹتیں
-لٹکیں
-لجھیں
-لچتیں
-لچکیں
-لچھیں
-لحتیں
-لسٹیں
-لشتیں
-لغتیں
-لکتیں
-لکھیں
-لگتیں
-لگنیں
-لمکیں
-لنشیں
-لنگیں
-لیپیں
-لیتیں
-لیٹیں
-لیچیں
-لیفیں
-لیقیں
-لیکیں
-لیلیں
-لہکیں
-لہنیں
-مٹتیں
-مٹکیں
-مثلیں
-مچتیں
-مچکیں
-مچلیں
-مسکیں
-مسلیں
-مشقیں
-مشکیں
-مکتیں
-ملتیں
-منتیں
-منکیں
-منگیں
-میتیں
-میٹیں
-میجیں
-میچیں
-میخیں
-میمیں
-مہکیں
-نبٹیں
-نبضیں
-نبھیں
-نپتیں
-نپٹیں
-نتتیں
-نتیس
-نتھیں
-نٹتیں
-نٹھیں
-نجبیں
-نجتیں
-نجشیں
-نجھیں
-نچتیں
-نچھیں
-نستیں
-نسلیں
-نظمیں
-نعتیں
-نسٹھو
-لچسپیا
-مطمع
-ثیق
-مغلظ
-پیچک
-فظے
-محنت
-نعشیں
-نعلیں
-نفلیں
-نقلیں
-نکتیں
-نکلیں
-نکھیں
-نگبیں
-نگتیں
-نگلیں
-نگئیں
-نگھیں
-نمٹیں
-نیتیں
-ئینس
-یشنیں
-یعتیں
-یکھیں
-یلتیں
-ینکیں
-ینگیں
-ہٹتیں
-ہچکیں
-ہکتیں
-ہگتیں
-ہلتیں
-ہلگیں
-ہمتیں
-ہمکیں
-ہمگیں
-ہنسیں
-ھکتیں
-ھلتیں
-ھلکیں
-ھمکیں
-ھنتیں
-ھنسیں
-ھنکیں
-بتیسو
-بٹینو
-بجلیو
-بچھیو
-بحثیو
-بختیو
-بخششو
-بخیلو
-بستیو
-بسکٹو
-بسملو
-بطگیو
-بقچیو
-بکسنو
-بکسیو
-بکیلو
-بگیلو
-بگینو
-بگھیو
-بلبلو
-بلٹیو
-بلخیو
-بلنگو
-بلیمو
-بمبیو
-بنگلو
-بیبیو
-بیتیو
-بیٹیو
-بیٹھو
-بیعتو
-بیکسو
-بیگمو
-بیگنو
-بیلٹو
-بیلچو
-بیلنو
-بینجو
-بینکو
-بھبکو
-بھبو
-بھپکو
-بھتنو
-بھٹکو
-بھٹیو
-بھسکو
-بھشکو
-بھگتو
-بھلسو
-بھمبو
-بھنکو
-بھنگو
-بھیجو
-بھیسو
-بھیگو
-بھیلو
-پپیتو
-پپیہو
-پتلیو
-پتنگو
-پتنیو
-پتیلو
-پٹیلو
-پچپنو
-پچیسو
-پچھلو
-پستیو
-پسلیو
-پسیجو
-پسینو
-پگلیو
-پگھلو
-پلپلو
-پلٹنو
-پلٹیو
-پلنگو
-پنسلو
-پنکھو
-پیٹیو
-پیٹھو
-پھٹکو
-پیچھو
-پیکٹو
-پینٹو
-پیکٹو
-پینٹو
-پینگو
-پہنچو
-پھبکو
-پھنسو
-پھپکو
-پھپھو
-پھٹکو
-پھسکو
-پھسلو
-پھلکو
-پھلیو
-پھنسو
-پھنکو
-پھیکو
-پھیلو
-تبتیو
-تتلیو
-تجلیو
-تختیو
-تسلیو
-تشفیو
-تصفیو
-تعلقو
-تلتلو
-تلخیو
-تنتنو
-تیلتو
-تیلیو
-تینہو
-تہمتو
-تھپکو
-تھنچو
-تھنیو
-تھلو
-ٹکلیو
-ٹگھلو
-ٹلٹلو
-ٹمنٹو
-ٹیبلو
-ٹیسٹو
-ٹیکسو
-ٹیلبو
-ٹیلیو
-ٹینٹو
-ٹینکو
-ٹہنیو
-ٹھٹکو
-ٹھٹھو
-ٹھسکو
-ٹھگنو
-ٹھلیو
-ٹھمکو
-ٹھنسو
-ٹھنکو
-ٹھنیو
-ٹھیکو
-ٹھیلو
-جبینو
-جپسیو
-جثیمو
-جستجو
-جنبشو
-جنبیو
-جنتیو
-جنگلو
-جنئیو
-جیٹھو
-جنیو
-جھپٹو
-جھپکو
-جھٹکن
-جھجکو
-جھکیو
-جھگیو
-جھلسو
-جھلکو
-جھمکو
-جھنجو
-جھنکو
-جھیلو
-چپٹیو
-چٹھیو
-چٹکلو
-چٹکیو
-چٹنیو
-چٹیلو
-چسکیو
-چسنیو
-چشتیو
-چغلیو
-چلبلو
-چلمنو
-چمٹیو
-چمچیو
-چمنیو
-چنکٹو
-چنگیو
-چنگھو
-چنٹو
-چینٹو
-چینگو
-چینیو
-چہچہو
-چہیتو
-چھپنو
-چھٹکو
-چھٹیو
-چھچھل
-چھلکو
-چھنٹو
-چھنکو
-چھیکو
-چھیلو
-چھینو
-حبشنو
-حبشیو
-حبیبو
-حسنیو
-حسینو
-حشتیو
-حشمتو
-حکمتو
-حکیمو
-حلیفو
-حنفیو
-حیتیو
-خبطیو
-خبیثو
-خصتیو
-خصلتو
-خطیبو
-خلفیو
-خلقیو
-خلیجو
-خلیقو
-خمچیو
-خمیسو
-خنکیو
-سبکیو
-سبیلو
-ستخطو
-ستعفو
-ستلیو
-ستنبو
-ستنجو
-سٹیجو
-سٹیچو
-سٹیفو
-سٹینو
-سجنیو
-سختیو
-سسکیو
-سطبلو
-سفینو
-سقنقو
-سقیفو
-سسکچیو
-سیکچو
-سکیلو
-سکیمو
-سگنلو
-سلجھو
-سلسلو
-سلفیو
-سلیٹو
-سلیقو
-سمجھو
-سمیٹو
-سنجیو
-سنجھو
-سنکیو
-سنگتو
-سنگیو
-سنیو
-سیپیو
-سیٹھو
-سیشنو
-سیکھو
-سینتو
-سینٹو
-سینچو
-سینکو
-سینگو
-سینیو
-شبیہو
-شفقتو
-شکستو
-شکنجو
-شکیو
-شلغمو
-شمنیو
-شیخیو
-شیشیو
-شیمپو
-صحبتو
-صحیفو
-صطبلو
-صنعتو
-ضبطیو
-ضعیفو
-ضمیمو
-طبلقو
-طبیبو
-طلعتو
-طنطنو
-طینتو
-ظلمتو
-عجمیو
-عصبیو
-عصمتو
-عظمتو
-علتو
-عملیو
-عنکبو
-عیبیو
-عیلیو
-فیسٹو
-فیصلو
-فیلسو
-فہمیو
-قبطیو
-قبیلو
-قسمتو
-قفیتو
-قلفیو
-قلیتو
-قلیمو
-قمچیو
-قمقمو
-قمیصو
-قیمتو
-قہقہو
-کپکپو
-کتیسو
-کٹکٹو
-کٹنیو
-کسبیو
-کستیو
-کسٹھو
-کلغیو
-کلفتو
-کلیجو
-کلیلو
-کلیمو
-کلھیو
-کمبلو
-کمپیو
-کمسنو
-کمیتو
-کمیلو
-کمنو
-کنٹھو
-کنجیو
-کنکٹو
-کنکئو
-کنگفو
-کنگلو
-کنگنو
-کنگھو
-کیبنو
-کیتیو
-کیسٹو
-کیسیو
-کیمپو
-کینچو
-کھٹکو
-کھٹلو
-کھٹیو
-کھسکو
-کھسلو
-کھکھو
-کھمبو
-کھنچو
-کھنکو
-کھیپو
-کھیتو
-کھیلو
-کھیئو
-گتھنو
-گتھیو
-گٹکیو
-گشتیو
-گفتگو
-گلٹیو
-گلگلو
-گنتیو
-گنٹھو
-گنجیو
-گنگنو
-گھپلو
-گھٹکو
-گھٹنو
-گھسٹو
-گھگھو
-گھنٹو
-گھنگو
-گھیکو
-لبلبو
-لبیلو
-لپیٹو
-لٹکنو
-لجھنو
-لچھنو
-لشتیو
-لطیفو
-لعنتو
-لعینو
-لفینگو
-لکشیو
-لگنیو
-لمحمو
-لمختو
-لمخلو
-لمعبو
-لمعمو
-لمکتو
-لمنظو
-لنگیو
-لنگھو
-لیبلو
-لیتھو
-لیچیو
-لیسیو
-لیگیو
-لیمپو
-لہنگو
-مبلغو
-متقیو
-مٹکیو
-مٹھیو
-مثلثو
-مجسمو
-مجلسو
-مجمعو
-مچلکو
-محبتو
-محسنو
-محفلو
-محققو
-محکمو
-محملو
-محنتو
-مخلصو
-مخمصو
-مخملو
-مخنثو
-مسکنو
-مسلکو
-مسلمو
-مسئلو
-مشعلو
-مشغلو
-مشفقو
-مشقتو
-مشکبو
-مشکلو
-مشکیو
-مشکو
-مشینو
-مصطفو
-مصلحو
-مصنفو
-مطلعو
-معلمو
-مغلپو
-مغنیو
-مفلسو
-مکتبو
-مکینو
-مکھنو
-مکھیو
-ملکیو
-منجمو
-منجنو
-منچلو
-منشیو
-منصبو
-منصبو
-منصفو
-منطقو
-منگنو
-منگھو
-میٹھو
-میکلو
-میمنو
-مہینو
-نتیجو
-نتھنو
-نٹنیو
-نٹیٹو
-نٹھلو
-نجمنو
-نجیبو
-نجیلو
-نچلیو
-نسبتو
-نسٹھو
-نسسکو
-نشستو
-نشیبو
-نشینو
-نصیبو
-نظمیو
-نعمتو
-نقیبو
-نکمو
-نکمیو
-نکیلو
-نکھتو
-نکھٹو
-نکھیو
-نگلیو
-نگینو
-نگیلو
-نلسٹو
-نلکیو
-نمکخو
-نیپچو
-نیسکو
-نیکیو
-نیلگو
-نیمچو
-ئجسٹو
-ئیسکو
-ئیکلو
-ئیگیو
-ئینچو
-یتیمو
-یجنٹو
-یخنیو
-یسٹھو
-یکھیو
-یگچیو
-یلچیو
-یلیمو
-ھکینو
-ھمکیو
-بصیغئہ
-سینئہ
-شعبئہ
-صیغئہ
-عطیئہ
-غنچئہ
-فیقئہ
-قبلئہ
-قلعئہ
-نقطعئہ
-نیمئہ
-ہفتئہ
-ببیسی
-بپتنی
-بتکتی
-بتکنی
-بتیسی
-بجھتی
-بجھنی
-بچکتی
-بچکنی
-بچلتی
-بچلنی
-بچھتی
-بچھنی
-بخشتی
-بخششی
-بخشنی
-بخیلی
-بستگی
-بستنی
-بسکٹی
-بسنتی
-بکبکی
-بکینی
-بگینی
-بگیلی
-بلبلی
-بلٹتی
-بلٹنی
-بلغی
-بلکتی
-بلکنی
-بللی
-بلیسی
-بمبئی
-بنٹتی
-بنٹنی
-بنجتی
-بنجنی
-بنسنی
-بنفشی
-بنیٹی
-بنینی
-بتیتی
-بتینی
-بیٹھی
-بیجتی
-بیجنی
-بیچتی
-بیچنی
-بیسنی
-بیکسی
-بیگمی
-بیگنی
-بیلتی
-بیلتی
-بیلنی
-بینتی
-بینکی
-بیننی
-بیہقی
-بھجتی
-بھجنی
-بہشتی
-بہکتی
-بہکنی
-بہلتی
-بہلنی
-بہنگی
-بھبکی
-بھپکی
-بھتنی
-بھٹکی
-بھٹنی
-بھٹئ
-بھجتی
-بھجنی
-بھچتی
-بھچنی
-بھسکی
-بھشتی
-بھکتی
-بھکنی
-بھگتی
-بھلتی
-بھلسی
-بھلنی
-بھنتی
-بھنچی
-بھنکی
-بھنگی
-بھننی
-بھیجی
-بھیکی
-بھیگی
-بھیلی
-بھینی
-پتیلی
-پتھتی
-پتھنی
-پٹختی
-پٹچنی
-پٹکنی
-پٹکتی
-پٹیتی
-پچکتی
-پچکنی
-پچپسی
-پچھتی
-پچھلی
-پچھمی
-پچھنی
-پچتگی
-پستئ
-پسیجی
-پگلتی
-پگلنی
-پگھلی
-پلپلی
-پلتھی
-پلٹتی
-پلٹنی
-پنبئ
-پنپنی
-پنتھی
-پنچھی
-پنکھی
-پنگتی
-پنیلی
-پیپسی
-پیپلی
-پیتلی
-پیتھی
-پیٹتی
-پیٹنی
-پیٹھی
-پیستی
-پیسنی
-پیشگی
-پیکسی
-پیلتی
-پیلنی
-پینٹی
-پھسکی
-پہنتی
-پہنچی
-پہنی
-پہیلی
-پھبتی
-پھبکی
-پھبنی
-پھپی
-پھپکی
-پھپھی
-پھٹتی
-پھٹکی
-پھٹنی
-پھسکی
-پھسلی
-پھکتی
-پھکنی
-پھلتی
-پھلٹی
-پھلسی
-پھلکی
-پھلنی
-پھنتی
-پھنسی
-پھنکی
-پھنگی
-پھننی
-پھیکی
-پھیلی
-پھینی
-تبتی
-تیبچی
-تپکتی
-تپکنی
-تحفگی
-تشنجی
-تشنگی
-تعصبی
-تعصبی
-تعلقی
-تعلی
-تغلقی
-تکبکی
-تکتکی
-تکلفی
-تکینی
-تلتلی
-تللی
-تلملی
-تلیٹی
-تمیمی
-تنتنی
-تنفسی
-تنکتی
-تنکنی
-تیبچی
-تیپچی
-تیجتی
-تیجنی
-تیکھی
-تھپتی
-تھپکی
-تھپنی
-تھتھی
-تھجتی
-تھجنی
-تھکتی
-تھکلی
-تھکنی
-تھگلی
-تھلتی
-تھلنی
-تھمتی
-تھمنی
-تھنچی
-تھیلی
-ٹپکتی
-ٹکٹکی
-ٹکھلی
-ٹلٹلی
-ٹنگتی
-ٹنگنی
-ٹیپتی
-ٹیپنی
-ٹیکتی
-ٹیکسی
-ٹیکنی
-ٹینکی
-ٹہلتی
-ٹہلنی
-ٹھٹکی
-ٹھٹھی
-ٹھستی
-ٹھسکی
-ٹھسنی
-ٹھکتی
-ٹھکنی
-ٹھگتی
-ٹھگنی
-ٹھلتی
-ٹھلنی
-ٹھمکی
-ٹھنتی
-ٹھنکی
-ٹھنگی
-ٹھننی
-ٹھیکی
-ٹھیگی
-ٹھینی
-ثعلبی
-جستگی
-جلیبی
-جلیسی
-جلیلی
-جملگی
-جمنئ
-جمیلی
-جنگلی
-جیتتی
-جیتنی
-جیٹھی
-جہنمی
-جھپٹی
-جھپکی
-جھجکی
-جھکتی
-جھکنی
-جھلتی
-جھلسی
-جھلکی
-جھلنی
-جھمکی
-جھنجی
-جھیلی
-چبکتی
-چبکنی
-چبینی
-چبھتی
-چبھنی
-چپٹتی
-چپٹنی
-چپکتی
-چپکنی
-چپنٹی
-چپیٹی
-چتھلی
-چٹختی
-چٹخنی
-چٹکتی
-چٹکنی
-ہچکنی
-چسکتی
-چسکنی
-چکٹتی
-چکٹنی
-چکلتی
-چکلنی
-چکھتی
-چکھنی
-چلبلی
-چلچلی
-چلملچی
-چمپئ
-چمٹتی
-چمٹنی
-چمکتی
-چمکنی
-چنبلی
-چنچنی
-چپیتی
-چپینی
-چیختی
-چیخنی
-چپنٹی
-چینگی
-چہکتی
-چہکنی
-چہیتی
-چھپتی
-چھپٹی
-چھپنی
-چھٹتی
-چھٹکی
-چھچھو
-چھلتی
-چھلتی
-چھلکی
-چھلنی
-چھنتی
-چھنٹی
-چھنکی
-چھننی
-چھیپی
-چھیلی
-چھینی
-حبیبی
-حسنی
-حسینی
-حقیقی
-حکمتی
-حکیمی
-حلیلی
-حلیمی
-حنبلی
-خستگی
-خصلتی
-خفتگی
-خلتسی
-خلخلی
-خلیجی
-خمینی
-خنثی
-سپینی
-ستخطی
-ستھنی
-سٹکتی
-سٹکنی
-سجیلی
-سچیتی
-سسکتی
-سسکنی
-سلپـی
-سلجھی
-سلسلی
-سلفچی
-سلگتی
-سلگنی
-سلمی
-سلیٹی
-سلگنی
-سمبلی
-سمبھی
-سمپلی
-سمٹتی
-سمٹنی
-سمجھی
-سمیٹی
-سنسنی
-سنکتی
-سنکلی
-سنکنی
-سککتی
-سیفٹی
-سیکھی
-سیلتی
-سیلنی
-سیمگی
-سینتی
-سینٹی
-سینچی
-سینکی
-سینگی
-سہلتی
-سہلنی
-سہمتی
-سہمنی
-سہیلی
-شبنمی
-شستگی
-شفتگی
-شفتلی
-شکیبی
-شلجمی
-شلغمی
-شمنگی
-صحبتی
-صخحچی
-صلیبی
-صنعتی
-ضعیفی
-طبلچی
-طبیعی
-طفیلی
-طلسمی
-عظمی
-عظیمی
-عقبی
-عقیلی
-علیگی
-غصیلی
-غفلتی
-غلئ
-غنچگی
-غنغنی
-غیبتی
-فلسفی
-فلیٹی
-فیمچی
-فیملی
-فینسی
-قسمتی
-قلعئ
-قلیبی
-قلیتی
-قلیمی
-قیمتی
-قینـی
-کپکپی
-کتھئ
-کٹکٹی
-کٹکنی
-کچکچی
-کچلتی
-کچلنی
-کچھنی
-کسلتی
-کسلنی
-کشتنی
-کشمشی
-کلبلی
-کلتھی
-کلیتی
-کلیٹی
-کلیجی
-کلیمی
-کمپلی
-کمسنی
-کملتی
-کملنی
-کمیتی
-کمیٹی
-کمینی
-کنپٹی
-کنجنی
-کنچنی
-کنکتی
-کنکٹی
-کنکنی
-کنکلی
-کنگھی
-کیتلی
-کیتھی
-کیچلی
-کیکتی
-ککیلنی
-کھبی
-کھپتی
-کھپچی
-کھپنی
-کھتی
-کھتلی
-کھٹتی
-کھٹی
-کھٹکی
-کھٹل
-کھجی
-کھجلی
-کھسکی
-کھسلی
-کھلتی
-کھلنی
-کھمبی
-کھنچی
-کھنسی
-کھنکی
-کھنی
-کھیتی
-کھیلی
-کھینی
-کھیئی
-گپکتی
-گپکنی
-گتھتی
-گتھنی
-گٹکتی
-گٹکنی
-گٹھتی
-گٹھلی
-گٹھنی
-گجگجی
-گشتگی
-گفتنی
-گلتھی
-گلکلی
-گنٹھی
-گنگنی
-گینتی
-گہکتی
-گہکنی
-گھپتی
-گھپنی
-گھٹتی
-گھٹکی
-گھٹنی
-گھچلی
-گھستی
-گھسٹی
-گھسنی
-گھلتی
-گھلنی
-گھنٹی
-گھنگی
-گھنی
-لبلبی
-لبنی
-لنیلی
-لپٹتی
-لپٹنی
-لپکتی
-لپکنی
-لپیٹی
-لٹکتی
-لٹکنی
-لجمعی
-لجھتی
-لجھنی
-لچسپی
-نچکتی
-لچکنی
-لچھتی
-لچھمی
-لچھنی
-لیسنی
-لضحی
-لعنتی
-لفنگی
-لکشمی
-لکعبی
-لکھتی
-لکھنی
-لمحصی
-لمحیی
-لمعطی
-لمغنی
-لمکتی
-لکتی
-لمکنی
-لنسکی
-لنگتی
-کینڑ
-لنگھی
-لیپتی
-لیپنی
-لیٹتی
-لیٹنی
-لیجھی
-لیچتی
-لیچنی
-لیستی
-لیسنی
-لیلی
-لہکتی
-لہکنی
-مبنی
-مثیلی
-مجسٹی
-مجلسی
-مجلی
-مجملی
-مچکتی
-مچکنی
-مچلنی
-مچھلی
-محبتی
-محسنی
-محشی
-محلی
-محنتی
-مخلصی
-مخلی
-مخملی
-مسکتی
-مسکنی
-مسنتی
-مسلنی
-مسمسی
-مسمی
-مسیحی
-مشفقی
-مشقتی
-مثنی
-مشینی
-مصحفی
-مفطکی
-مصطگی
-مصلی
-مطلبی
-معطلی
-معلمی
-معلی
-معینی
-مغلئٖ
-مفلسی
-مقتضی
-مقضی
-مقفی
-مکتبی
-ملتجی
-ملگجی
-ملنکی
-ملہٹی
-منتہی
-منجلی
-منجھی
-منچلی
-منحنی
-منصبی
-منصفی
-منطقی
-منقی
-منکتی
-منکتی
-منگتی
-منگنی
-منمنی
-منہنی
-میتھی
-میٹتی
-میٹنی
-میٹھی
-میجتی
-میجنی
-میچتی
-میچنی
-میکسی
-میگنی
-میلسی
-میمنی
-مہکتی
-مہکنی
-مہنگی
-نبٹتی
-نبٹنی
-نبختی
-نبھتی
-نپٹتی
-نپٹنی
-پنجتی
-پنجنی
-نتھنی
-نٹیلی
-نٹھتی
-نٹھنی
-نجیلی
-نجھتی
-نجھنی
-نچھتی
-نچھنی
-نسبتی
-نسیسی
-نسینی
-نشیبی
-نشیلی
-نشینی
-نعیمی
-نکلتی
-نکلنی
-نکمی
-نکیلی
-نکھتی
-نکھنی
-نگلتی
-نگلنی
-نگیلی
-نگینی
-نگھتی
-نگھنی
-نمٹتی
-نمٹنی
-نطینی
-نیستی
-نیکسی
-نینسی
-ئستگی
-ئینٹی
-ٹینکی
-ئینگی
-یتیلی
-یتیمی
-یجنسی
-یحیی
-یخھنی
-یحیی
-یفتگی
-یقینی
-یکنسی
-یکھتی
-یکھنی
-یلمعی
-یمیمی
-یمینی
-ینٹھی
-ینکتی
-ینکنی
-ینگتی
-ینگنی
-ہتھنی
-نٹیلی
-ہچکتی
-ہچکنی
-ہستگی
-ہستنی
-ہلبلی
-ہلگتی
-ہلگنی
-ہمکنی
-ہنستی
-ہنسلی
-ہنسنی
-ہشیمی
-ھکیلی
-ھلکتی
-ھلکنی
-ھمکتی
-ھمکنی
-ھنستی
-ھسنی
-ھنکتی
-ھنکنی
-بپتنے
-بپتئے
-بتکتے
-بتکنے
-بتکئے
-بجھتے
-بجھنے
-بجھئے
-بچپنے
-بچکتے
-بچکنے
-بچکئے
-بچلتے
-بچلنے
-بچلئے
-بچھتے
-بچھنے
-بچھئے
-بخشتے
-بخشئے
-بکسلے
-بکسنے
-بگیلے
-بگینے
-بلبلے
-بلٹتے
-بلٹئے
-بلکتے
-بلکئے
-بللے
-بنٹتے
-بنٹئے
-بنجتے
-بنجئے
-بنگلے
-بیتتے
-بیتئے
-بیٹھے
-بیجتے
-بیچتے
-بیچئے
-بیلتے
-بیلچے
-بیلنے
-بیلئے
-بینتے
-بینئے
-بہکتے
-بہکئے
-بہلتے
-بہلئے
-بھپکے
-بھتنے
-بھٹکے
-بھجتے
-بھجئے
-بھچتے
-بھچئے
-بھسکے
-بھکتے
-بھکئے
-بھگتے
-بھلتے
-بھلسے
-بھلنے
-بھلئے
-بھنتے
-بھنچے
-بھنگے
-بھننے
-بھنئے
-بھیجے
-بھیگے
-بھیلے
-بھینے
-پپیتے
-پپیہے
-پتنگے
-پتیلے
-پتھتے
-پتھئے
-پٹختے
-پٹخئے
-پٹکتے
-پچکتے
-پچکئے
-پچھتے
-پچھلے
-پچھنے
-پچھئے
-پسیجے
-پسینے
-پگلتے
-پگلئے
-پگھلے
-پلپلے
-پلٹتے
-پلٹئے
-پنپتے
-پنپئے
-پنکھے
-پنیلے
-پیٹتے
-پیٹئے
-پیٹھے
-پیجئے
-پیچھے
-پیستے
-پیسئے
-پیلنے
-پیلئے
-پہنتے
-پہنچے
-پہننے
-پہنئے
-پھبتے
-پھبکے
-پھبنے
-پھبئے
-پھپکے
-پھٹتے
-پھٹکے
-پھٹنے
-پھٹئے
-پھسکے
-پھسلے
-پھکتے
-پھکئے
-پھلتے
-پھلسے
-پھلکے
-پھلنے
-پھلئے
-پھنسے
-پھنکے
-پھننے
-پھیکے
-پھیلے
-تپکتے
-تپکئے
-تصیفے
-تعلقے
-تکملے
-تلتلے
-تلملے
-تنتنے
-تنتئے
-تنکتے
-تنکئے
-تیجتے
-تیجئے
-تیکھے
-تھپتے
-تھپکے
-تھپنے
-تھپئے
-تھجتے
-تھجئے
-تھکتے
-تھکئے
-تھلتے
-تھلئے
-تھمتے
-تھمئے
-تھنچے
-تھیلے
-ٹپکتے
-ٹپکئے
-ٹگھلے
-ٹلٹلے
-ٹنگتے
-ٹنگئے
-ٹیپتے
-ٹیپئے
-ٹیکتے
-ٹیکئے
-ٹہلتے
-ٹہلئے
-ٹھٹکے
-ٹھٹھے
-ٹھستے
-ٹھسکے
-ٹھسئے
-ٹھگتے
-ٹھگئے
-ٹھلتے
-ٹھلئے
-ٹھمکے
-ٹھنتے
-ٹھننے
-ٹھنئے
-ٹھیکے
-ٹھیلے
-جنگلے
-جیتتے
-جیتئے
-جیٹھے
-جھپٹتے
-جھپکے
-جھٹکی
-جھجکے
-جھکتے
-جھکئے
-جھلتے
-جھلسے
-جھلکے
-جھلنے
-جھلئے
-جھمکے
-جھیلے
-چبکتے
-چبکئے
-چبینے
-چبھتے
-چبھئے
-چپٹتے
-چپٹئے
-چپچے
-چپکتے
-چپکئے
-چپیٹے
-چٹختے
-چٹخئے
-چٹکتے
-چٹکلے
-چٹکنے
-چٹکئے
-چسکتے
-چکٹتے
-چکٹئے
-چکلتے
-چکلئے
-چکھتے
-چکھئے
-چلبلے
-چمٹتے
-چمٹئے
-چمکتے
-چمکئے
-چنبھے
-چنچنے
-چیپتے
-چیپئے
-چیختے
-چیخئے
-چینٹے
-چینگے
-چہچہے
-چہکتے
-چہکئے
-چہیتے
-چھپتے
-چھپکے
-چھپنے
-چھپئے
-چھٹتے
-چھٹکے
-چھٹنے
-چھٹئے
-چھلتے
-چھلکے
-چھلنے
-چھلئے
-چھنتے
-چھنکے
-چھننے
-چھننے
-چھنئے
-چھیپے
-چھیلے
-چھینے
-ستعفے
-ستنجے
-سٹکتے
-سٹکئے
-سجیلے
-سسکتے
-سسکئے
-سفینے
-سلجھے
-سلسلے
-سلگتے
-سلگئے
-سلمے
-سلیقے
-سمٹتے
-سمٹئے
-سمجھے
-سمیٹے
-سنکتے
-سنکئے
-سیٹھے
-سیجئے
-سیچتے
-سیچئے
-سیکھے
-سیلتے
-سیلئے
-سینتے
-سینچے
-سینگے
-سہلتے
-سہلئے
-سہمتے
-سہمئے
-شکنجے
-صحیفے
-ضمیمے
-عطیئے
-عقبے
-عقیقے
-غصیلے
-غلبلے
-غلیلے
-فتیلے
-فلسفے
-فلیتے
-فیصلے
-قبیلے
-قضیئے
-قلئیے
-قمقمے
-قہقہے
-کپکپے
-کٹکتے
-کٹکٹے
-کٹکئے
-کٹیلے
-کچکچے
-کچلتے
-کچلئے
-کسلتے
-کسلئے
-کسیلے
-کلبلے
-کلیجے
-کملتے
-کملئے
-کمیلے
-کمینے
-کنٹھے
-کنکتے
-کنکٹے
-کنکنے
-کنکئے
-کنگلے
-کنگنے
-کنگھے
-کیجئے
-کیکتے
-کیکئے
-کیلتے
-کیلئے
-کھپتے
-کھپئے
-کھٹتے
-کھٹکے
-کھٹلے
-کھٹنے
-کھٹئے
-کھجلے
-کھسکے
-کھسلے
-کھلتے
-کھلئے
-کھمبے
-کھنچے
-کھنکے
-کھتے
-کھیلے
-کھنے
-کھیئے
-گپکتے
-گپکئے
-گتھتے
-گتھئے
-گٹھے
-گٹکتے
-گٹکئے
-گٹھتے
-گٹھئے
-گجگجے
-گلگلے
-گنٹھے
-گنگنے
-گہکتے
-گہکئے
-گھپتے
-گھپلے
-گھپنے
-گھپئے
-گھٹتے
-گھٹکے
-گھٹنے
-گھٹئے
-گھچلے
-گھستے
-گھٹے
-گھسئے
-گھلتے
-گھلئے
-گھنٹے
-گھنئے
-لبلبے
-لبیلے
-لپٹتے
-لپٹئے
-لپکتے
-لپکئے
-لپیٹتے
-لٹکتے
-لٹکئے
-لجھتے
-لجھئے
-لچکتے
-لچکئے
-لچھتے
-لچھئے
-لشتیے
-لطیفے
-لفنگے
-لکھتے
-لکھئے
-لمکتے
-لمکئے
-لنگتے
-لنگئے
-لنگھے
-لیپتے
-لیپئے
-لیٹتے
-لیٹئے
-لیجئے
-لیچتے
-لیچئے
-لیستے
-لیسئے
-لیکھے
-لیلے
-لینگے
-لہکتے
-لہکئے
-متھتے
-متھئے
-مٹکتے
-مٹکئے
-مثنے
-مجسمے
-مجلے
-مچکتے
-مچکئے
-مچلتے
-مچلئے
-محکمے
-مخلے
-مخمصے
-مسکتے
-مسکئے
-مسلتے
-مسلئے
-مسئلے
-مشغلے
-مشکلے
-مصلے
-مطلعے
-معلے
-ملگجے
-منجھے
-منچلے
-منکتے
-منکئے
-منگتے
-منگئے
-میٹتے
-میٹئے
-میٹھے
-میجتے
-میجئے
-میچتے
-میچئے
-مہکتے
-مہکئے
-مہنگے
-مہینے
-نبٹتے
-نبٹئے
-نبھتے
-نبھئے
-نپٹتے
-نپٹئے
-نپجتے
-نپجئے
-نتیجے
-نتھنے
-نتھئے
-نٹھئے
-نجھتے
-نجھئے
-نچنئے
-نچھتے
-نچھئے
-نشیلے
-نصیبے
-نکلتے
-نکلئے
-نکمے
-نکیلے
-نکھتے
-نکھئے
-نگلتے
-نگلئے
-نگیلے
-نگینے
-نگھتے
-نگھئے
-نمٹتے
-نمٹئے
-نمستے
-نیٹھے
-نیمچے
-ئینچے
-ئینگے
-یتیلے
-یکھتے
-یکھئے
-ینٹھے
-ینکتے
-ینکئے
-ینگتے
-ینگئے
-ہٹیلے
-ہچکتے
-ہچکئے
-ہلگتے
-ہلگئے
-ہمکتے
-ہمکئے
-ہنستے
-ہنسئے
-ھکیلتے
-ھکیلئے
-ھکیلے
-ھلکتے
-ھلکئے
-ھمکتے
-ھمکئے
-ھنستے
-ھنسئے
-ھنکتے
-ھنکئے
-بصیغہ
-بقیتہ
-بگینہ
-بلیلبہ
-بنفشہ
-بنگلہ
-بیلچہ
-تپنچہ
-تثنیہ
-تخلیہ
-تسمیہ
-تشبیہ
-تصفیہ
-تعلقہ
-تعمیہ
-تکمیلہ
-تمنچہ
-تنبیہ
-تہلکہ
-ٹھٹھہ
-ٹھیکہ
-ٹھیلہ
-ثعلبہ
-ثمینہ
-جلیلہ
-جمعتہ
-جمیلہ
-چشتیہ
-حبیبہ
-حسینہ
-حشتیہ
-حلفیہ
-حلیلہ
-حلیمہ
-حنیفہ
-خبیثہ
-خجستہ
-خفیفہ
-خلیلہ
-سفینہ
-سقیفہ
-شکستہ
-سکینہ
-سلسلہ
-سنبلہ
-سہیلہ
-شبیلہ
-شبینہ
-شعشعہ
-شفیعہ
-شفیقہ
-شقیقہ
-شکبیہ
-شکستہ
-شکنجہ
-شکیبہ
-شکیلہ
-شگفتہ
-شمیمہ
-شنیعہ
-شیفتہ
-شہنشہ
-صبعتہ
-صبغتہ
-صبیحہ
-صحیفہ
-ضحیفہ
-ضمیمہ
-طبیبہ
-طپنچہ
-طلیعہ
-طمنچہ
-طنطنہ
-عجیبہ
-عشقیہ
-عصبیہ
-عطیۂ
-عظیمہعفیفہ
-عقیقہ
-عقیلہ
-عقیمہ
-علقمہ
-علمیہ
-عیلیہ
-غلغلہ
-غلیطہ
-غلیظہ
-غلیلہ
-غنچۂ
-فتیلہ
-فصیحہ
-فلبتہ
-فلسفہ
-فلیتہ
-فیصلہ
-قبیحہ
-قبیلہ
-قتیکہ
-قسمیہ
-قمقمہ
-قہقہہ
-کبیسہ
-کٹکنہ
-کلبلہ
-کلکتہ
-کلمتہ
-کلنکہ
-کلیجہ
-کلیلہ
-کمینہ
-کنینہ
-کہھجلہ
-گنجفہ
-گھنٹہ
-لجمعہ
-لجملہ
-لجنتہ
-لخلخہ
-لشتیہ
-لشعبہ
-لطیفہ
-لعنتہ
-لقلقہ
-لکعبہ
-للغتہ
-للہ
-لمنتہ
-لیلتہ
-مبینہ
-متصلہ
-متفقہ
-متنبہ
-مثبتہ
-مجسمہ
-مجلہ
-مچلکہ
-محسنہ
-محصنہ
-محکمہ
-محلہ
-مخمصہ
-مسلمہ
-مسئلہ
-مسینہ
-مشتبہ
-مشعلہ
-مشغلہ
-مصنفہ
-مضحکہ
-مطلقہ
-مظلمہ
-مظنہ
-معلقہ
-معلمہ
-معینہ
-مغلیہ
-مغنیہ
-مقنہ
-مکتبہ
-منحقہ
-ملیحہ
-ممکنہ
-منصۂ
-منطقہ
-میختہ
-میمنہ
-مہملہ
-مہینہ
-نپیلہ
-نتیجہ
-نسیمہ
-نشستہ
-نصیبہ
-نطینہ
-نظمیہ
-نعتیہ
-نعیمہ
-نگینہ
-نیمچہ
-ئنچہ
-ہلیلہ
-ہمیشہ
-ہمہمہ
-پینٹہ
-ٹھیٹھ
-جھنجھ
-کھنکھ
-لینتھ
-ملیچھ
-ہیلتھ
-لبینتہ
-لعظمتہ
-مشخیل
-حسنی
-خنثی
-عقبی
-عیسی
-لبنی
-لصلو
-مثنی
-مجلی
-مجملا
-محشی
-جلگ
-معلی
-مقفی
-یحیی
-تعلقا
-قیمتا
-مجملا
-مطلقا
-بنجتی
-بنجنی
-بنسنی
-بنفشی
-بنیٹی
-بنینی
-بتیتی
-بتینی
-بیٹھی
-بیجتی
-بیجنی
-بیچتی
-بیچنی
-بیسنی
-بیکسی
-بیگمی
-بیگنی
-بیلتی
-بیلتی
-بیلنی
-بینتی
-بینکی
-بیننی
-بیہقی
-بھجتی
-بھجنی
-بہشتی
-بہکتی
-بہکنی
-بہلتی
-بہلنی
-بہنگی
-بھبکی
-بھپکی
-بھتنی
-بھٹکی
-بھٹنی
-بھٹئ
-بھجتی
-بھجنی
-بھچتی
-بھچنی
-بھسکی
-بھشتی
-بھکتی
-بھکنی
-بھگتی
-بھلتی
-بھلسی
-بھلنی
-بھنتی
-بھنچی
-بھنکی
-بھنگی
-بھننی
-بھیجی
-بھیکی
-بھیگی
-بھیلی
-بھینی
-پتیلی
-پتھتی
-پتھنی
-پٹختی
-پٹچنی
-پٹکنی
-پٹکتی
-پٹیتی
-پچکتی
-پچکنی
-پچپسی
-پچھتی
-پچھلی
-پچھمی
-پچھنی
-پچتگی
-پستئ
-پسیجی
-پگلتی
-پگلنی
-پگھلی
-پلپلی
-پلتھی
-پلٹتی
-پلٹنی
-پنبئ
-پنپنی
-پنتھی
-پنچھی
-پنکھی
-پنگتی
-پنیلی
-پیپسی
-پیپلی
-پیتلی
-پیتھی
-پیٹتی
-پیٹنی
-پیٹھی
-پیستی
-پیسنی
-پیشگی
-پیکسی
-پیلتی
-پیلنی
-پینٹی
-پھسکی
-پہنتی
-پہنچی
-پہنی
-پہیلی
-پھبتی
-پھبکی
-پھبنی
-پھپی
-پھپکی
-پھپھی
-پھٹتی
-پھٹکی
-پھٹنی
-پھسکی
-پھسلی
-پھکتی
-پھکنی
-پھلتی
-پھلٹی
-پھلسی
-پھلکی
-پھلنی
-پھنتی
-پھنسی
-پھنکی
-پھنگی
-پھننی
-پھیکی
-پھیلی
-پھینی
-تبتی
-تیبچی
-تپکتی
-تپکنی
-تحفگی
-تشنجی
-تشنگی
-تعصبی
-تعصبی
-تعلقی
-تعلی
-تغلقی
-تکبکی
-تکتکی
-تکلفی
-تکینی
-تلتلی
-تللی
-تلملی
-تلیٹی
-تمیمی
-تنتنی
-تنفسی
-تنکتی
-تنکنی
-تیبچی
-تیپچی
-تیجتی
-تیجنی
-تیکھی
-تھپتی
-تھپکی
-تھپنی
-تھتھی
-تھجتی
-تھجنی
-تھکتی
-تھکلی
-تھکنی
-تھگلی
-تھلتی
-تھلنی
-تھمتی
-تھمنی
-تھنچی
-تھیلی
-ٹپکتی
-ٹکٹکی
-ٹکھلی
-ٹلٹلی
-ٹنگتی
-ٹنگنی
-ٹیپتی
-ٹیپنی
-ٹیکتی
-ٹیکسی
-ٹیکنی
-ٹینکی
-ٹہلتی
-ٹہلنی
-ٹھٹکی
-ٹھٹھی
-ٹھستی
-ٹھسکی
-ٹھسنی
-ٹھکتی
-ٹھکنی
-ٹھگتی
-ٹھگنی
-ٹھلتی
-ٹھلنی
-ٹھمکی
-ٹھنتی
-ٹھنکی
-ٹھنگی
-ٹھننی
-ٹھیکی
-ٹھیگی
-ٹھینی
-ثعلبی
-جستگی
-جلیبی
-جلیسی
-جلیلی
-جملگی
-جمنئ
-جمیلی
-جنگلی
-جیتتی
-جیتنی
-جیٹھی
-جہنمی
-جھپٹی
-جھپکی
-جھجکی
-جھکتی
-جھکنی
-جھلتی
-جھلسی
-جھلکی
-جھلنی
-جھمکی
-جھنجی
-جھیلی
-چبکتی
-چبکنی
-چبینی
-چبھتی
-چبھنی
-چپٹتی
-چپٹنی
-چپکتی
-چپکنی
-چپنٹی
-چپیٹی
-چتھلی
-چٹختی
-چٹخنی
-چٹکتی
-چٹکنی
-ہچکنی
-چسکتی
-چسکنی
-چکٹتی
-چکٹنی
-چکلتی
-چکلنی
-چکھتی
-چکھنی
-چلبلی
-چلچلی
-چلملچی
-چمپئ
-چمٹتی
-چمٹنی
-چمکتی
-چمکنی
-چنبلی
-چنچنی
-چپیتی
-چپینی
-چیختی
-چیخنی
-چپنٹی
-چینگی
-چہکتی
-چہکنی
-چہیتی
-چھپتی
-چھپٹی
-چھپنی
-چھٹتی
-چھٹکی
-چھچھو
-چھلتی
-چھلتی
-چھلکی
-چھلنی
-چھنتی
-چھنٹی
-چھنکی
-چھننی
-چھیپی
-چھیلی
-چھینی
-حبیبی
-حسنی
-حسینی
-حقیقی
-حکمتی
-حکیمی
-حلیلی
-حلیمی
-حنبلی
-خستگی
-خصلتی
-خفتگی
-خلتسی
-خلخلی
-خلیجی
-خمینی
-خنثی
-سپینی
-ستخطی
-ستھنی
-سٹکتی
-سٹکنی
-سجیلی
-سچیتی
-سسکتی
-سسکنی
-سلپـی
-سلجھی
-سلسلی
-سلفچی
-سلگتی
-سلگنی
-سلمی
-سلیٹی
-سلگنی
-سمبلی
-سمبھی
-سمپلی
-سمٹتی
-سمٹنی
-سمجھی
-سمیٹی
-سنسنی
-سنکتی
-سنکلی
-سنکنی
-سککتی
-سیفٹی
-سیکھی
-سیلتی
-سیلنی
-سیمگی
-سینتی
-سینٹی
-سینچی
-سینکی
-سینگی
-سہلتی
-سہلنی
-سہمتی
-سہمنی
-سہیلی
-شبنمی
-شستگی
-شفتگی
-شفتلی
-شکیبی
-شلجمی
-شلغمی
-شمنگی
-صحبتی
-صخحچی
-صلیبی
-صنعتی
-ضعیفی
-طبلچی
-طبیعی
-طفیلی
-طلسمی
-عظمی
-عظیمی
-عقبی
-عقیلی
-علیگی
-غصیلی
-غفلتی
-غلئ
-غنچگی
-غنغنی
-غیبتی
-فلسفی
-فلیٹی
-فیمچی
-فیملی
-فینسی
-قسمتی
-قلعئ
-قلیبی
-قلیتی
-قلیمی
-قیمتی
-قینـی
-کپکپی
-کتھئ
-کٹکٹی
-کٹکنی
-کچکچی
-کچلتی
-کچلنی
-کچھنی
-کسلتی
-کسلنی
-کشتنی
-کشمشی
-کلبلی
-کلتھی
-کلیتی
-کلیٹی
-کلیجی
-کلیمی
-کمپلی
-کمسنی
-کملتی
-کملنی
-کمیتی
-کمیٹی
-کمینی
-کنپٹی
-کنجنی
-کنچنی
-کنکتی
-کنکٹی
-کنکنی
-کنکلی
-کنگھی
-کیتلی
-کیتھی
-کیچلی
-کیکتی
-ککیلنی
-کھبی
-کھپتی
-کھپچی
-کھپنی
-کھتی
-کھتلی
-کھٹتی
-کھٹی
-کھٹکی
-کھٹل
-کھجی
-کھجلی
-کھسکی
-کھسلی
-کھلتی
-کھلنی
-کھمبی
-کھنچی
-کھنسی
-کھنکی
-کھنی
-کھیتی
-کھیلی
-کھینی
-کھیئی
-گپکتی
-گپکنی
-گتھتی
-گتھنی
-گٹکتی
-گٹکنی
-گٹھتی
-گٹھلی
-گٹھنی
-گجگجی
-گشتگی
-گفتنی
-گلتھی
-گلکلی
-گنٹھی
-گنگنی
-گینتی
-گہکتی
-گہکنی
-گھپتی
-گھپنی
-گھٹتی
-گھٹکی
-گھٹنی
-گھچلی
-گھستی
-گھسٹی
-گھسنی
-گھلتی
-گھلنی
-گھنٹی
-گھنگی
-گھنی
-لبلبی
-لبنی
-لنیلی
-لپٹتی
-لپٹنی
-لپکتی
-لپکنی
-لپیٹی
-لٹکتی
-لٹکنی
-لجمعی
-لجھتی
-لجھنی
-لچسپی
-نچکتی
-لچکنی
-لچھتی
-لچھمی
-لچھنی
-لیسنی
-لضحی
-لعنتی
-لفنگی
-لکشمی
-لکعبی
-لکھتی
-لکھنی
-لمحصی
-لمحیی
-لمعطی
-لمغنی
-لمکتی
-لکتی
-لمکنی
-لنسکی
-لنگتی
-کینڑ
-لنگھی
-لیپتی
-لیپنی
-لیٹتی
-لیٹنی
-لیجھی
-لیچتی
-لیچنی
-لیستی
-لیسنی
-لیلی
-لہکتی
-لہکنی
-مبنی
-مثیلی
-مجسٹی
-مجلسی
-مجلی
-مجملی
-مچکتی
-مچکنی
-مچلنی
-مچھلی
-محبتی
-محسنی
-محشی
-محلی
-محنتی
-مخلصی
-مخلی
-مخملی
-مسکتی
-مسکنی
-مسنتی
-مسلنی
-مسمسی
-مسمی
-مسیحی
-مشفقی
-مشقتی
-مثنی
-مشینی
-مصحفی
-مفطکی
-مصطگی
-مصلی
-مطلبی
-معطلی
-معلمی
-معلی
-معینی
-مغلئٖ
-مفلسی
-مقتضی
-مقضی
-مقفی
-مکتبی
-ملتجی
-ملگجی
-ملنکی
-ملہٹی
-منتہی
-منجلی
-منجھی
-منچلی
-منحنی
-منصبی
-منصفی
-منطقی
-منقی
-منکتی
-منکتی
-منگتی
-منگنی
-منمنی
-منہنی
-میتھی
-میٹتی
-میٹنی
-میٹھی
-میجتی
-میجنی
-میچتی
-میچنی
-میکسی
-میگنی
-میلسی
-میمنی
-مہکتی
-مہکنی
-مہنگی
-نبٹتی
-نبٹنی
-نبختی
-نبھتی
-نپٹتی
-نپٹنی
-پنجتی
-پنجنی
-نتھنی
-نٹیلی
-نٹھتی
-نٹھنی
-نجیلی
-نجھتی
-نجھنی
-نچھتی
-نچھنی
-نسبتی
-نسیسی
-نسینی
-نشیبی
-نشیلی
-نشینی
-نعیمی
-نکلتی
-نکلنی
-نکمی
-نکیلی
-نکھتی
-نکھنی
-نگلتی
-نگلنی
-نگیلی
-نگینی
-نگھتی
-نگھنی
-نمٹتی
-نمٹنی
-نطینی
-نیستی
-نیکسی
-نینسی
-ئستگی
-ئینٹی
-ٹینکی
-ئینگی
-یتیلی
-یتیمی
-یجنسی
-یحیی
-یخھنی
-یحیی
-یفتگی
-یقینی
-یکنسی
-یکھتی
-یکھنی
-یلمعی
-یمیمی
-یمینی
-ینٹھی
-ینکتی
-ینکنی
-ینگتی
-ینگنی
-ہتھنی
-نٹیلی
-ہچکتی
-ہچکنی
-ہستگی
-ہستنی
-ہلبلی
-ہلگتی
-ہلگنی
-ہمکنی
-ہنستی
-ہنسلی
-ہنسنی
-ہشیمی
-ھکیلی
-ھلکتی
-ھلکنی
-ھمکتی
-ھمکنی
-ھنستی
-ھسنی
-ھنکتی
-ھنکنی
-بصیغہ
-بقیتہ
-بگینہ
-بلیلبہ
-بنفشہ
-بنگلہ
-بیلچہ
-تپنچہ
-تثنیہ
-تخلیہ
-تسمیہ
-تشبیہ
-تصفیہ
-تعلقہ
-تعمیہ
-تکمیلہ
-تمنچہ
-تنبیہ
-تہلکہ
-ٹھٹھہ
-ٹھیکہ
-ٹھیلہ
-ثعلبہ
-ثمینہ
-جلیلہ
-جمعتہ
-جمیلہ
-چشتیہ
-حبیبہ
-حسینہ
-حشتیہ
-حلفیہ
-حلیلہ
-حلیمہ
-حنیفہ
-خبیثہ
-خجستہ
-خفیفہ
-خلیلہ
-سفینہ
-سقیفہ
-شکستہ
-سکینہ
-سلسلہ
-سنبلہ
-سہیلہ
-شبیلہ
-شبینہ
-شعشعہ
-شفیعہ
-شفیقہ
-شقیقہ
-شکبیہ
-شکستہ
-شکنجہ
-شکیبہ
-شکیلہ
-شگفتہ
-شمیمہ
-شنیعہ
-شیفتہ
-شہنشہ
-صبعتہ
-صبغتہ
-صبیحہ
-صحیفہ
-ضحیفہ
-ضمیمہ
-طبیبہ
-طپنچہ
-طلیعہ
-طمنچہ
-طنطنہ
-عجیبہ
-عشقیہ
-عصبیہ
-عطیۂ
-عظیمہعفیفہ
-عقیقہ
-عقیلہ
-عقیمہ
-علقمہ
-علمیہ
-عیلیہ
-غلغلہ
-غلیطہ
-غلیظہ
-غلیلہ
-غنچۂ
-فتیلہ
-فصیحہ
-فلبتہ
-فلسفہ
-فلیتہ
-فیصلہ
-قبیحہ
-قبیلہ
-قتیکہ
-قسمیہ
-قمقمہ
-قہقہہ
-کبیسہ
-کٹکنہ
-کلبلہ
-کلکتہ
-کلمتہ
-کلنکہ
-کلیجہ
-کلیلہ
-کمینہ
-کنینہ
-کہھجلہ
-گنجفہ
-گھنٹہ
-لجمعہ
-لجملہ
-لجنتہ
-لخلخہ
-لشتیہ
-لشعبہ
-لطیفہ
-لعنتہ
-لقلقہ
-لکعبہ
-للغتہ
-للہ
-لمنتہ
-لیلتہ
-مبینہ
-متصلہ
-متفقہ
-متنبہ
-مثبتہ
-مجسمہ
-مجلہ
-مچلکہ
-محسنہ
-محصنہ
-محکمہ
-محلہ
-مخمصہ
-مسلمہ
-مسئلہ
-مسینہ
-مشتبہ
-مشعلہ
-مشغلہ
-مصنفہ
-مضحکہ
-مطلقہ
-مظلمہ
-مظنہ
-معلقہ
-معلمہ
-معینہ
-مغلیہ
-مغنیہ
-مقنہ
-مکتبہ
-منحقہ
-ملیحہ
-ممکنہ
-منصۂ
-منطقہ
-میختہ
-میمنہ
-مہملہ
-مہینہ
-نپیلہ
-نتیجہ
-نسیمہ
-نشستہ
-نصیبہ
-نطینہ
-نظمیہ
-نعتیہ
-نعیمہ
-نگینہ
-نیمچہ
-ئنچہ
-ہلیلہ
-ہمیشہ
-ہمہمہ
-پینٹہ
-ٹھیٹھ
-جھنجھ
-کھنکھ
-لینتھ
-ملیچھ
-ہیلتھ
-لبینتہ
-لعظمتہ
-مشخیل
-حسنی
-خنثی
-عقبی
-عیسی
-لبنی
-لصلو
-مثنی
-مجلی
-مجملا
-محشی
-جلگ
-معلی
-مقفی
-یحیی
-تعلقا
-قیمتا
-مجملا
-مطلقا
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/6grams.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/6grams.txt
deleted file mode 100644 (file)
index d1e21f1..0000000
+++ /dev/null
@@ -1,1542 +0,0 @@
-بھینگا
-ٹھینگا
-پتیلیا
-بلبلیا
-پلپلیا
-تلتلیا
-ٹلٹلیا
-پھینکا
-پگھلتا
-پگھلنا
-ٹگھلتا
-ٹگھلنا
-بنگلیا
-بیٹھتا
-بیٹھنا
-ینٹھتا
-ینٹھنا
-بھیجتا
-بھیجنا
-پہنچتا
-پہنچنا
-بھیلتا
-بھیلنا
-بھیلیا
-پھیلتا
-پھیلنا
-ٹھیلتا
-ٹھیلنا
-ٹیکسٹا
-ٹیکسیا
-پسیجتا
-پسیجنا
-بھبکتا
-بھبکنا
-بھبکیا
-بھپکتا
-بھپکنا
-بھپکیا
-بھٹکتا
-بھنکتا
-بھنکنا
-بھیگتا
-بھیگنا
-پھٹکتا
-پھنکتا
-پھنکنا
-پھنکیا
-تپھکتا
-تپھکیا
-ٹھنکتا
-ٹھنکنا
-ٹھنکیا
-بھٹکنا
-پٹھکنا
-تھپکنا
-بھتیجا
-بھینچا
-پھینچا
-تھیلیا
-ٹھمکتا
-ٹھمکنا
-ٹھمکیا
-ھکیلتا
-پہیلیا
-بھگتنا
-پھسلنا
-پھسلتا
-پھنستا
-پھنسنا
-ٹھنستا
-ٹھنسنا
-چھبیلا
-چٹخنیا
-ھکیلنا
-پھکنیا
-سلجھتا
-سلجھنا
-کھیلتا
-کھیلنا
-کھینچتا
-جھینکا
-جھینگا
-چھینکا
-کھنچنا
-کھٹکتا
-کھٹکنا
-کھٹکیا
-کھنکتا
-کھنکنا
-بھگتتا
-چینٹیا
-جھیلتا
-جھیلنا
-چھیلتا
-چھیلنا
-چینگتا
-چینگنا
-سمجھتا
-سمجھنا
-جھلنگا
-چھلنگا
-جھپٹتا
-جھپٹنا
-جھینپا
-چھنٹتا
-چھنٹنا
-چھیننا
-جھلکتا
-جھلکنا
-جھلکیا
-چھلکتا
-چھلکنا
-چھلکیا
-جھپکتا
-جھپینا
-جھپکیا
-جھٹکتا
-جھٹکنا
-جھکیا
-چھٹکتا
-چھٹکنا
-چھٹکیا
-لپیٹتا
-لپیٹنا
-بھسکنا
-بھسکتا
-ٹھسکتا
-ٹھسکنا
-جھجکنا
-جھجکتا
-چھینتا
-سمیٹنا
-سمیٹتا
-گھنٹیا
-چپیٹتا
-چپیٹنا
-چھینیا
-طبیعیا
-کھسکتا
-کھسکنا
-کھیتیا
-گھٹنیا
-میٹھتا
-میٹھنا
-جھپیٹا
-لبلبیا
-لبیلیا
-ہتھنیا
-چمکیلا
-چھلنیا
-سنکھیا
-سیکھتا
-سیکھنا
-چٹکیلیا
-جلیبیا
-جھلستا
-جھلسنا
-چھینٹا
-سینچتا
-سینچنا
-گھسٹتا
-گھسیٹا
-جھنجلا
-جھلملا
-جھمیلا
-سینکتا
-سینکنا
-فلسفیا
-لہسنیا
-لنگھتا
-لنگھنا
-بہنگیا
-بھینسا
-پتنگیا
-پھلکیا
-تخلیقا
-نتھنیا
-نخلستا
-جھنجھنا
-چھیجتا
-چھنکتا
-چھنکنا
-چبھینا
-سٹکنیا
-کیتلیا
-کنپٹیا
-گھٹلیا
-لچکیلا
-تخمینا
-سینتتا
-سینتنا
-بپتسما
-منگنیا
-مہکیلا
-سنبھلا
-مطلقا
-تحقیقا
-جھنجھیا
-جھمکتا
-جھمکنا
-جھمکیا
-چھتیسا
-سنجھلا
-فضیحتا
-فضیحتا
-متعلقا
-مچھلیا
-ملیشیا
-بھتنیا
-پھبتیا
-کھینچا
-گھیتلا
-گھیتلا
-کنکھیا
-کٹکھنا
-کنگھیا
-چھچھلا
-منجھلا
-سینگنا
-سینگیا
-طلیستا
-کنگنیا
-کھٹہنا
-کھسلتا
-گنٹھیا
-کچھنیا
-کھسلنا
-کیچلیا
-گنجھیا
-گینگٹا
-چھچھنا
-سنسنیا
-گھنگھنا
-کھکھلا
-گنٹھتا
-گنٹھنا
-بھجنگا
-بھنگیا
-ٹھنگنا
-گملیلا
-پھبکتا
-پھبکنا
-پھنگیا
-گینگلا
-پھپکنا
-تحصیلا
-ٹھٹکتا
-ٹھٹکنا
-کھلبلا
-کھنستا
-کھنسنا
-کھیکٹا
-گھٹکتا
-گھٹکنا
-گھینٹا
-گھینپا
-پٹیلتا
-پٹیلنا
-پھینٹا
-پیپلیا
-تسلیا
-تسلیما
-تعصبا
-تعطیلا
-تعلیما
-تعمیلا
-تعیشا
-تکلیفا
-تمثیلا
-تھنچتا
-تھنچنا
-ٹیکسلا
-یمیلیا
-پھسکتا
-پھسکنا
-سبھیتا
-کمپنیا
-معلما
-پھپھیا
-تنصیبا
-نگلستا
-مصطلحا
-گیمبیا
-بکسیلا
-تعظیما
-ٹکسیلا
-کنکٹیا
-تفصیلا
-گھنشیا
-تکلفا
-گھینٹا
-چھیجنا
-لکیمیا
-جھٹپٹا
-بھینٹا
-سنگیتا
-میکنما
-سٹیبلا
-نگینیا
-فلمستا
-فلمسٹا
-بھلسنا
-بھلستا
-سیمینا
-پنکھیا
-پنچھیا
-پھنسیا
-پھسکیا
-قینچیا
-لچیسپیا
-صنعتکا
-تصنیفا
-بلتستا
-تلمیحا
-ملتجیا
-تشبیحا
-بہشتیا
-مصلحتا
-منتظما
-کمیٹیا
-کنٹھیا
-کھچیا
-میکسیا
-بگھلیا
-تصحیفا
-چلمـچیا
-چہیتیا
-سلفچیا
-چمنستا
-لنہیا
-تضحیکا
-بستگیا
-فیملیو
-میگھنا
-پچکلیا
-تنعما
-تنقیحا
-پشیتبا
-ضعیفو
-سمبلیا
-نمیبیا
-منتخبا
-حسینیا
-یجنسیا
-پچیسیا
-یچھنیا
-بتیسیا
-نشینیا
-سہیلیا
-مستجیب
-متعصب
-صنعتیت
-مستغیث
-لحقیقت
-بحیثیت
-لمحصنت
-لسلطنت
-ہلسنت
-بلیسیت
-مسیحیت
-حسینیت
-جھنجھٹ
-لیمینٹ
-یتھلیٹ
-یلپمنٹ
-سٹیٹمنٹ
-لیفٹسٹ
-بینیفٹ
-لیفٹنٹ
-ٹیفیکٹ
-جسٹمنٹ
-مستغیث
-تسبیح
-عقلمند
-نقشبند
-مستفید
-کسلمند
-فلمبند
-قلمبند
-صحتمند
-ٹھیکید
-کشتمند
-تحصیلد
-کمیشنڈ
-نگلینڈ
-پلیٹڈ
-سٹلینڈ
-کھٹمنڈ
-کنسیلڈ
-ہتھکنڈ
-جھینگر
-ٹیلیگر
-نسپکڑ
-پیغمبر
-پیتمبر
-پسینجر
-مینیجر
-لمختصر
-گمبیھر
-ٹھٹھیر
-گھمبیر
-کھینچر
-کیمسٹر
-گلیشیر
-مستعمر
-منگیتر
-سپیکٹر
-مستفسر
-نجینءر
-لمتکبر
-یلفیءر
-سٹیشنر
-گھنگھر
-کھنکھر
-نیپیءر
-نفینٹر
-منٹگر
-ستکھیر
-مستظہر
-لکسمبر
-لگسمبر
-پچھتّر
-لمشتہر
-جھنجھر
-مستنصر
-کمپلسر
-سپینسر
-ٹھیھیر
-مستحصر
-بینظیر
-کینٹیز
-کمیشنر
-لمینڑ
-کمپیءر
-بغلگیر
-بیکٹیر
-لنجھیڑ
-پھلجھڑ
-کھکھپڑ
-بھلکّڑ
-پیکیجز
-کمپنیز
-متمیّز
-منگنیز
-کمیٹیز
-یجنسیز
-فنکشنز
-یلیشنز
-کمیشنر
-جیلنجز
-میٹنگز
-پنیتیس
-کمپلکس
-تینتیس
-ٹیلیکس
-سینتیس
-کلینکس
-لتشخیص
-لمتخلص
-لتخصیص
-مستفیض
-لتصنیف
-منجنیق
-لتحقیق
-ٹیکنیک
-میکینک
-ینگلیک
-تعلّقہ
-میجسٹک
-تھلیٹک
-پینٹنگ
-منیجنگ
-سمگلنگ
-میفکنگ
-کیمپنگ
-ٹیسٹنگ
-بینکنگ
-بلیجنگ
-ٹیکنکل
-نسٹیبل
-یکٹیکل
-لتفصیل
-چھنٹیل
-سٹینسل
-لتحصیل
-سلسبیل
-لتعمیل
-مستعمل
-مستقبل
-مستطیل
-کیمیکل
-بتفصیل
-سمعیل
-مستعجل
-تھلتھل
-کیلسیم
-کیلشیم
-متعلّم
-لتعظیم
-مستقیم
-بکنگھم
-لمنتکم
-مستحکم
-لتعلیم
-مستعصم
-چلبلین
-چمپیءن
-لحسنین
-فلسطین
-سلیکشن
-سلیکشن
-کینٹین
-لیٹیشن
-فسنطین
-کعبتین
-کھنکھن
-لمہیمن
-گبھیلن
-کنسیشن
-مجیشین
-کیپسٹن
-کیسپین
-محققین
-مستحسن
-کنگسٹن
-تھمپٹن
-چھچھلن
-مسلمین
-لثقلین
-متخصصین
-مصنفین
-معلمین
-فٹسمین
-محسنین
-مبلغین
-منصفین
-مصلحین
-بینجمن
-یسیپشن
-بیجتیں
-پٹختیں
-بیچتیں
-تکتیں
-پلٹتیں
-پچکتیں
-جھیلیں
-چھیلیں
-غفلتیں
-بھسکیں
-ٹھسکیں
-بھنتیں
-پھٹتیں
-ٹگھلیں
-پگھلیں
-ٹھنتیں
-نمٹتیں
-پتنگیں
-پینگیں
-پینگیں
-نٹھتیں
-بھیلیں
-پھیلیں
-ٹھیلیں
-پگلتیں
-نکلتیں
-نگلتیں
-نکھتیں
-نگھتیں
-نگھتیں
-بہلتیں
-ٹہلتیں
-بھکتیں
-بھگتیں
-پھکتیں
-ٹھکتیں
-ٹھگتیں
-بھپکیں
-بھٹکیں
-بھٹکیں
-بھیگیں
-پھٹکیں
-پھنکیں
-تھپکیں
-چٹختیں
-بچکتیں
-نکیلیں
-نگیلیں
-بیلتیں
-چبھتیں
-چپکتیں
-چٹکتیں
-کھٹکیں
-کھنکیں
-کھلتیں
-گھلتیں
-سمٹتیں
-سمیٹیں
-نجھتیں
-پچھتیں
-پٹکتیں
-ٹپکتیں
-ٹنگتیں
-ٹیکتیں
-ینکتیں
-ینگتیں
-نچھتیں
-بچھتیں
-کھیتیں
-گھٹتیں
-ھینگیں
-بجھتیں
-بھبکیں
-ٹھنکیں
-بچھئیں
-چپٹتیں
-مٹکتیں
-منگتیں
-محبتیں
-محنتیں
-جھپکیں
-جھٹکیں
-جھیکیں
-جھیکیں
-جیتتیں
-لپٹتیں
-لیپتیں
-لیٹتیں
-کھپتیں
-لپٹیں
-بتکتیں
-چکٹتیں
-لپکتیں
-لٹکتیں
-لنگتیں
-لنگتیں
-ہنستیں
-ھکیلیں
-چلبلیں
-چھپتیں
-چھٹتیں
-چسکتیں
-لہکتیں
-جھپٹیں
-چھنٹیں
-جھلسیں
-لیستیں
-ہچکتیں
-پھسلیں
-پھسلیں
-لجھتیں
-لچھتیں
-پھلتیں
-کیلتیں
-ملتیں
-بچلتیں
-پسیجیں
-بلکتیں
-پہنتیں
-پہنچیں
-بہکتیں
-ٹھستیں
-پھنسیں
-چبکتیں
-چبکتیں
-جھجکیں
-قیمتیں
-کٹکتیں
-گٹکتیں
-گھستیں
-گھسٹیں
-لکھتیں
-مجلسیں
-مچلتیں
-مچکتیں
-مسلیں
-مشکلیں
-میٹتیں
-مہکتیں
-ہمکتیں
-ٹھمکیں
-چمکتیں
-چھلکیں
-سبیلیں
-سنکتیں
-سہلتیں
-کلیلیں
-مشیتیں
-بنفشیں
-چہکتیں
-چھنکیں
-میچتین
-نسبتیں
-گھپتیں
-کھٹتیں
-سینکیں
-سینگیں
-چینگیں
-لچکتیں
-لیکھیں
-فسنطیں
-سیلتیں
-کچلتیں
-کسلتیں
-کلفتیں
-کھسکیں
-کھنچیں
-کھیلیں
-گٹھتیں
-گنٹھیں
-مخملیں
-مکھئں
-جھلکیں
-میجتیں
-بخشتیں
-بھچتیں
-بھیجیں
-سلگتیں
-سہمتیں
-سہمگیں
-سینچیں
-سیکھیں
-فضلتیں
-مسلتیں
-میٹھیں
-پیستیں
-مسکتیں
-لیچتیں
-کملتیں
-گلگلیں
-کھسلیں
-سلجھیں
-سمجھیں
-گتھتیں
-کلبلیں
-نشستیں
-گھٹکیں
-ھمکتیں
-بھلتیں
-پتھتیں
-تپکتیں
-تنکتیں
-تھلتیں
-تھمتیں
-تہمتیں
-ٹھٹکیں
-ٹھٹکیں
-سسکتیں
-سسکتیں
-سینتیں
-گپکتیں
-گپکتیں
-کیکتیں
-لعنتیں
-مشینیں
-ٹھنسیں
-بلنگیں
-پلنگیں
-پھسکیں
-بھنگیں
-پھبکیں
-ٹھلتیں
-گہکتیں
-مثلثیں
-منکتیں
-منکتیں
-تھپتیں
-نخستیں
-صحبتیں
-بگیلیں
-بھجتیں
-تھجتیں
-چپیٹیں
-تیجتیں
-ہلگتیں
-بنجتیں
-بنٹتیں
-بتیتیں
-بیٹھیں
-بینتیں
-پنپتیں
-پیٹتیں
-ٹیپتیں
-نبٹتیں
-نپٹتیں
-چیپتیں
-ینٹھیں
-جھکتیں
-بخششیں
-قسمتیں
-عصمتیں
-صنعتیں
-صنعتیں
-خشمگیں
-خصلتیں
-خصلتیں
-شکستیں
-قمیصیں
-ئجسٹیں
-غیبتیں
-قلیتیں
-خلیجیں
-شفقتیں
-محفلیں
-صلیتیں
-صلیبیں
-حبشنیں
-لجھنیں
-ستینیں
-غلیلیں
-بیلٹیں
-جبینیں
-کیسٹیں
-قفیتیں
-کمیتیں
-منطقیں
-عظمتیں
-جنبشیں
-چپٹتیں
-نجمجنیں
-پلٹنیں
-سکیمیں
-قلیمیں
-مشعلیں
-ہمیتیں
-مشقتیں
-بلبلیں
-سنگتیں
-حشمتیں
-حکمتیں
-سلیٹیں
-بیگمیں
-بھنگنو
-بھنگیو
-بھیلیو
-تھیلیو
-بھینگو
-پھینکو
-ٹھینگو
-پھکینو
-پہیلیو
-بھبکیو
-بھپکیو
-پھنکیو
-ٹھنکیو
-تھپکیو
-بھتیجو
-بھینچو
-پھینچو
-جھینکو
-چھینکو
-جھپیٹو
-جھینپو
-چھینیو
-چھینٹو
-گھٹنیو
-طبلچیو
-ہتھنیو
-طفیلیو
-حقیقتو
-چھلنیو
-لچسپیو
-پھلکیو
-ٹھمکیو
-کیتلیو
-گٹھلیو
-مچھلیو
-ٹیکسیو
-ہتھنیو
-جنگلیو
-فیمچیو
-کیپسیو
-کنپٹیو
-لبلیو
-کھینچو
-کھٹملو
-سٹکنیو
-گھینپو
-تحصیلو
-سنبھلو
-فضیلتو
-فضیحتو
-مسکینو
-گھنگھو
-گھسیٹو
-کنکھیو
-کنگھیو
-کمپنیو
-کمینیو
-کنٹھیو
-کیچلیو
-گنٹھیو
-کنگیو
-منطقیو
-لعنبکو
-بلینکو
-تعطیلو
-تکنیکو
-تنظیمو
-شخصیتو
-متھیلو
-مجسمو
-معلمو
-مملکتو
-ٹیلیفو
-مصلحتو
-سسکچیو
-کیلیفو
-بطلیمو
-بھینسو
-بھمبھو
-بیٹھکو
-مستحقو
-مغنیو
-پتیلیو
-پیپلیو
-ٹمبکٹو
-منگنیو
-بگھیلو
-ٹکھیلو
-کیلیکو
-چمیسفو
-پھنگیو
-چینٹیو
-بمبینو
-بھینٹو
-پھبتیو
-جھلکیو
-جھلکیو
-چھلکیو
-لکھنؤ
-سلطنتو
-کیسینو
-جھنجھو
-سنگینو
-جھمیلو
-پنکھیو
-پنچھیو
-قینچیو
-طبیعتو
-تکلیفو
-پھنسیو
-تصنیفو
-فیسٹیو
-عصبتیو
-مصیبتو
-بہشتیو
-لمسلمو
-بھتنیو
-جھینگو
-کھیتیو
-کیبنٹو
-لچھیو
-فیمیلیا
-کلینکو
-کمیشنو
-کیمسٹو
-میٹنگو
-مطلبیو
-کمیسٹو
-کنکشنو
-نصیحتو
-ٹیکنکو
-تمثیلو
-پیشکشو
-کیفیتو
-کھچیو
-کمیٹیو
-میکسیو
-تفصیلو
-تشبیہو
-تیئسو
-تخمینو
-تخمینو
-نیستیو
-نشیشیو
-چھبیسو
-چھتیسو
-حسینیو
-سنگھیو
-سمبلیو
-سٹیشنو
-ضعیفیا
-سہیلیو
-معیشتو
-نسیسیو
-چیلنجو
-جھمکیو
-لبعلمو
-بستگیو
-جنکشنو
-تبلیغو
-بتیسیو
-سیکشنو
-نگینیو
-لبیلیو
-یجنسیو
-پچیسو
-نطینیو
-تفتیشو
-فنکشکنو
-پیشگیو
-پینسلو
-جمعیتو
-چھبیلو
-جہنمیو
-یچھنیو
-بھشتیو
-فلسفیو
-منتظمو
-پمفلٹو
-تسبیحو
-پیچکشو
-چٹخنیو
-بصیغۂ
-بصیغۂ
-سقیفۂ
-سفینۂ
-منطقۂ
-پگھلتی
-پگھلنی
-ٹگھلتی
-ٹگھلنی
-پسیجتی
-پسیجنی
-بھتیجی
-بھینچی
-پھینچی
-بھگتتی
-بھگتنی
-پہنچتی
-پہنچنی
-پھنستی
-پھنسنی
-ٹھنستی
-ٹھنسنی
-بھینگی
-پھینکی
-ٹھینگی
-بھیلتی
-بھیلنی
-پھیلتی
-پھیلنی
-ٹھیلتی
-ٹھیلنی
-بھپکنی
-بھٹکتی
-بھٹکنی
-پھٹکتی
-پھٹکنی
-ٹھٹکنی
-بھیگتی
-بھیگنی
-بھپکتی
-ٹھمکتی
-ٹھمکنی
-چھپکی
-ستثنی
-بھنکتی
-بھنکنی
-پھنکتی
-پھنکنی
-تھپکتی
-تھپکنی
-ٹھنکتی
-ٹھنکنی
-بیٹھتی
-بیٹھنی
-ینٹھتی
-کھنچتی
-کھنچنی
-تمکینی
-جھلستی
-جھلستی
-جھلسنی
-پھسلتی
-پھسلنی
-جھلکتی
-جھلکنی
-چھلکتی
-چھلکنی
-کھٹکتی
-کھنکتی
-کھنکنی
-نمکینی
-سلجھتی
-سلجھنی
-جھجکتی
-جھجکنی
-چینگتی
-چینگنی
-سمیٹتی
-سمیٹنی
-کھیلتی
-کھیلنی
-لپیٹتی
-لپیٹنی
-بھسکتی
-بھسکنی
-ٹھسکتی
-ٹھسکنی
-چھبیسی
-چھتیسی
-ھکیلتی
-ھکیلنی
-چھنگلی
-چھپیٹی
-چھینتی
-جھپٹتی
-جھپٹنی
-چھنٹتی
-چھنٹنی
-چھیننی
-میٹھتی
-میٹھنی
-جھپکتی
-جھپکنی
-جھٹکتی
-جھٹکنی
-چھٹکتی
-چھٹکنی
-ہتھیلی
-چپیٹتی
-چپیٹنی
-بھبکتی
-بھبکنی
-ٹھٹکتی
-چنبیلی
-جھیلتی
-جھیلنی
-چھیلتی
-چھیلنی
-جھینپی
-جھینکی
-چھٹنکی
-چھینکی
-ہمیشگی
-کھسکتی
-کھسکنی
-گھسٹتی
-گھسٹنی
-گھسیٹی
-چبھینی
-سینکتی
-سینکنی
-سٹیپنی
-سینتتی
-سینتنی
-سینچتی
-سینچنی
-پھینٹی
-لحسنین
-بھیجتی
-بھیجنی
-مقفی
-چھبیلی
-چھیبلی
-مجتبی
-سیکھتی
-سیکھنی
-مسکینی
-تحقیقی
-تخفیفی
-تخلیقی
-نخستگی
-نخستگی
-چھنکتی
-چھنکنی
-سنجھلی
-مینگنی
-نہفتگی
-خجستگی
-لچکیلی
-لمنتہی
-لنگھتی
-لنگھنی
-منجھلی
-معطلی
-کھٹکنی
-کھلبلی
-متمنی
-متنبی
-متبنی
-جھلملی
-جٹکیلی
-چھیجتی
-چھیجنی
-کھپچی
-کہینگی
-کھٹیکی
-کینچلی
-گٹھیلی
-گھنگچی
-معلمی
-مصطفی
-کھسلتی
-کھسلنی
-کھسکنی
-کھٹکٹی
-فضیحتی
-مشعلچی
-مستعفی
-مستقلی
-چمکیلی
-بینجنی
-سنبھلی
-شیفتگی
-گھینٹی
-پھبکتی
-پھبکنی
-پھپکتی
-پھپکنی
-سمجھتی
-سمجھنی
-مستسقی
-بھینٹی
-پبلسٹی
-تخمینی
-تعمیلی
-تفصیلی
-تفضیلی
-سنگینی
-گنٹھنی
-گنٹھتی
-لعظمی
-مسمی
-میجیسٹی
-بلجیمی
-بھلستی
-بھلسنی
-پھلستی
-پھلسنی
-پیگشتی
-شکستگی
-شگفتگی
-گھٹکتی
-گھٹکنی
-لحسنی
-پشیتنی
-پھنگنی
-ٹھنگنی
-یکجہتی
-ستعفی
-تکمیلی
-نگلیسی
-سیلسٹی
-تحلیلی
-ٹکھیلی
-سنکھنی
-مستغنی
-گھینپی
-متحلی
-تعلی
-پیتھنی
-لیکھتی
-پھلیلی
-تمثیلی
-منتقلی
-گلیکسی
-سینکنے
-نسپلٹی
-کھینچی
-لمجستی
-تفہیمی
-تنظیمی
-تبلیغی
-تشکیلی
-فکلٹی
-غمگینی
-پینجنی
-حیثیتی
-کیفیتی
-معیشتی
-تلمیحی
-تشخیصی
-تعظیمی
-بھیکنی
-تھنکنی
-تھنکتی
-بینگنی
-پینلٹی
-سلطنتی
-عقلیتی
-کمینگی
-تہنیتی
-نصیحتی
-لبعلمی
-تفتیشی
-مکینکی
-نگیٹھی
-سلیقگی
-بھیجتے
-بھیجنے
-بھیجئے
-بھتیجے
-بھینچے
-پگھلتے
-پگھلنے
-پگھلنے
-پگھلئے
-ٹگھلتے
-ٹگھلنے
-ٹگھلئے
-پہنچتے
-پہنچنے
-ٹھٹکتے
-ٹھٹکنے
-ھکیلتے
-ھکیلنے
-ھکیلنے
-ھکیلئے
-پسیجتے
-پسیجنے
-پہنچئے
-بھگتئے
-بھپکتے
-بھپکنے
-بھنکتے
-بھنکنے
-بھیگتے
-بھیگنے
-پھنکنے
-تھپکتے
-تھپکنے
-ٹھنکتے
-ٹھنکنے
-بھینگے
-پھینکے
-پسیجئے
-بھبکتے
-بھبکنے
-بھبکئے
-بھپکئے
-بھٹکتے
-بھٹکنے
-بھٹکئے
-بھنکئے
-پھٹکتے
-پھٹکنے
-پھٹکئے
-پھنکئے
-تھپکئے
-ٹھٹکئے
-ٹھینگے
-ٹھینگے
-بھگتنے
-بھگتتے
-بھگتتے
-بھیگئے
-ٹھنکئے
-پھیلتے
-پھیلنے
-بھیلتے
-بھیلنے
-ٹھیلتے
-ٹھیلنے
-ٹھیلئے
-ٹھمکنے
-ٹھمکئے
-ٹھمکتے
-پھسلتے
-پھسلنے
-پھسلئے
-بیٹھنے
-بیٹھتے
-بیٹھئے
-ینٹھئے
-بھیلئے
-پھنستے
-پھنسنے
-پھنسئے
-ٹھنسئے
-چینگتے
-چینگنے
-چینگئے
-جھلستے
-جھلسنے
-جھلسئے
-چھیلئے
-جھلکتے
-جھلکنے
-جھلکئے
-چھلکتے
-چھلکنے
-چھلکئے
-سلجھتے
-سلجھنے
-کھٹکتے
-کھٹکنے
-کھٹکئے
-کھنکتے
-کھنکنے
-کھنکئے
-پھیلئے
-بھسکتے
-بھسکنے
-بھسکئے
-ٹھسکتے
-ٹھسکنے
-ٹھسکئے
-جھپٹتے
-جھپٹنے
-جھپٹئے
-جھینپے
-جھپیٹے
-چھنٹتے
-چھنٹنے
-چھینتے
-چھیننے
-چھینئے
-چھینٹے
-چھنٹئے
-جھپکتے
-جھپکنے
-جھپکئے
-جھٹکتے
-جھٹکنے
-جھٹکئے
-چھٹکتے
-چھٹکنے
-چھٹکئے
-چھنکتے
-چھنکنے
-چھنکئے
-سلجھئے
-سمیٹتے
-سمیٹنے
-کھنچتے
-کھنچنے
-کھنچئے
-جھجکتے
-جھجکنے
-جھجکئے
-سمیٹئے
-سمجھتے
-کھسکتے
-کھسکنے
-کھسکئے
-لپیٹتے
-لپیٹنے
-لپیٹئے
-میٹھتے
-میٹھنے
-میٹھئے
-جھیلئے
-جھینکے
-جھینگے
-چھینکے
-جھیلتے
-جھیلنے
-چھیلتے
-چھیلنے
-چپیٹتے
-چپیٹنے
-سمجھنے
-گھسٹتے
-گھسٹنے
-گھسٹئے
-گھسیٹے
-چپیٹئے
-سیکھتے
-سیکھنے
-سیکھئے
-ینٹھتے
-ینٹھنے
-چٹکیلے
-سمجھئے
-سینکتے
-سینکنے
-سینکئے
-سینتئے
-سینچتے
-سینچنے
-بھلستے
-بھلسنے
-بھلسئے
-پھلستے
-پھلسنے
-پھلسئے
-سٹینلے
-مصطفے
-بھجنگے
-پھسکتے
-پھسکنے
-پھسکئے
-تھنچتے
-تھنچنے
-تھنچئے
-تھنچئے
-جھمیلے
-کھیلتے
-کھیلنے
-چمکیلے
-کھیلئے
-تخمینے
-بھنچتے
-چھٹپٹے
-گنجینے
-لچکیلے
-چھبیلے
-تخمینہ
-متعلقہ
-مفصلہ
-متعینہ
-گنجینہ
-معلمہ
-مقننہ
-معظمہ
-لعظمتہ
-لبینتہ
-بسلسلہ
-تعلقہ
-منسلکہ
-متخیلہ
-پشمینہ
-تشمینہ
-تہمینہ
-لسبیلہ
-مختلفہ
-طلیلیہ
-طلیلیہ
-حسینیہ
-لمحکمہ
-تعلیقہ
-شبیلیہ
-مسیلمہ
-منتخبہ
-منتظمہ
-حنفیہ
-پینسٹھ
-مجتبے
-طبیعتا
-طخمینا
-مصلحتا
-مجتمعا
-تعمیلا
-مستقلا
-تعظیما
-تفصیلا
-تکلفا
-تمثیلا
-تحقیقا
-نتیجتا
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/7grams.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/7grams.txt
deleted file mode 100644 (file)
index 5adff9f..0000000
+++ /dev/null
@@ -1,354 +0,0 @@
-پھینکتا
-پھینکنا
-بھینچتا
-بھینچنا
-بھینچنا
-پھینچتا
-پھینچنا
-پھینٹتا
-پھینٹتا
-پھنیٹنا
-بھنبھنا
-پھٹپھٹا
-نمکینیا
-جھپیٹتا
-جھپیٹنا
-جھینپتا
-جھینپنا
-چھنگلیا
-چنبیلیا
-چھٹنکیا
-چھینکنا
-چھپکلیا
-کھینچتا
-کھینچنا
-جھینکتا
-جھینکنا
-چھینکتا
-گھسیٹتا
-گھسیٹنا
-سنبھلتا
-سنبھلنا
-جھپیٹیا
-کینچلیا
-چھمچھما
-کھلبلیا
-چھلچھلا
-جھمجھما
-کھٹکھٹا
-گھنگھنا
-مستثنیا
-جھمیلیا
-مینگنیا
-بھینٹتا
-بھینٹنا
-پھنپھنا
-چھچھلتا
-چھچھلیا
-چھچھلنا
-کھکھنا
-گھینپتا
-گھینپنا
-کھسکھسا
-ٹکھیلیا
-تعظیما
-بھلبھلا
-پھلپھلا
-تھلتھلا
-جھنجھنا
-چھنچھنا
-تعلیمیا
-کھپکھپا
-بھتیجیا
-ہتھیلیا
-فیکلٹیا
-تھکتھکا
-کمینگیا
-سنگینیا
-چھتیسیا
-نگیٹھیا
-لمحصنت
-لمحصنت
-تشبیہیت
-نیشنلسٹ
-سپلیمنٹ
-سپیشلسٹ
-سٹیٹمنٹ
-یسپشنسٹ
-مینجمنٹ
-کنسلٹنٹ
-یکسچینج
-سلیکٹیڑ
-بھنبھیر
-کمنٹیٹر
-مسکیٹئر
-یکٹیشنر
-جیسلمیر
-سپلیمنٹر
-سیلیبیز
-کیمیکلز
-نٹلیجنس
-میکینکس
-ٹیفکیٹس
-نستعلیق
-سینتھٹک
-مینیجنگ
-میکینکل
-ٹیکنیکل
-پلیٹینم
-تھیلیئم
-تھینیئم
-لمستقیم
-جنٹلمین
-کمپیٹیشن
-متعلقین
-متکلمین
-مستحقیین
-منتظمین
-لمسلمین
-لمطففین
-بیٹسمین
-ٹیفیکیشن
-سبکتگین
-لیٹیشین
-متخصصین
-لنبیین
-منجمین
-ٹیکسیشن
-پنیسلین
-بھسکتیں
-ٹھسکتیں
-ٹھمکتیں
-ٹھٹکتیں
-بھیلتیں
-پھیتلتیں
-ٹھیلتیں
-چینگتیں
-چپٹیتیں
-چھلتیں
-چھنٹتیں
-بیھٹتں
-ینٹھتیں
-بھینچیں
-پھینچیں
-پگھلتیں
-ٹگھلتیں
-بھبکتیں
-بھپکتیں
-بھٹکتیں
-بھنگتیں
-بھنگنیں
-بھیگتیں
-پھٹکتیں
-تھپکتیں
-ٹھنکتین
-جھلکتین
-چھلکتین
-جھینکین
-جھینکین
-جھلستین
-جھپکتین
-جھٹکتین
-چھٹکتین
-جھیلتین
-جھینپین
-جھپٹتین
-چھینتین
-گھسٹتین
-گھسیٹین
-حقیقتین
-لپٹیتین
-پھسلتین
-تحصیلین
-بھیجتین
-پھنستین
-پھنستین
-فضیلتین
-فضیلتین
-کھینچین
-مشیتین
-ھکیلتین
-لنگھتین
-بھگتتین
-پسیجتین
-پھینکین
-سلجھتین
-کھٹکتین
-کھسکتین
-کھیلتین
-چھچھیلین
-پہنچتیں
-چھیجتیں
-سمجھتیں
-سمیٹتیں
-سیکھتیں
-سیکھتیں
-کھینچتیں
-کھینچتیں
-فضیحتیں
-میٹھتیں
-گٹھیلیں
-گنٹھتیں
-تعلیلیں
-تمثیلیں
-سنبھلیں
-سینتتین
-کھسلتیں
-بھینٹیں
-پھبکتیں
-پھپکتیں
-پھسکتیں
-تھنچتیں
-مصلحتیں
-مملکتین
-تنظیمیں
-بھنکتیں
-بھنکتیں
-شخصیتیں
-شخصیتیں
-کھنکتیں
-گھٹکتیں
-جھپیٹیں
-سلطنتیں
-بیٹھکیں
-سنگینیں
-بھینسیں
-تکلیفیں
-طبیعتیں
-ئسکلیں
-مصیبتیں
-کیفیتیں
-کلینکیں
-تفصیلیں
-میٹنگیں
-حیثیتیں
-معیشتیں
-تشبیہیں
-تشبیہیں
-جمعیتیں
-پیشکشیں
-تعطیلیں
-تنبیہیں
-تحقیقیں
-پینسلیں
-تسبیحیں
-نمکینکو
-چھٹنکیو
-چھنگلیو
-چھپکلیو
-چھینکیو
-بھنبھو
-پھٹپٹھو
-مینگنیو
-کھلبلیو
-بھتیجیو
-کیمبلپو
-کیمبلپو
-لجسلیٹیو
-میکسیکو
-نسٹیٹیو
-کینچلیو
-نسٹیبلو
-ہتھیلیو
-منجنیقیو
-گیلیلیو
-ٹیفکیٹو
-کینٹیٹو
-کمینگیو
-لیفٹسٹو
-چنبیلیو
-پینتیسو
-تینتیسو
-سینتیسو
-چھبیلیو
-کمینی
-چھتیسیو
-پینسٹھو
-پیشینگو
-نگیٹھیو
-فٹسمینو
-گنجینہ
-بھینچتی
-بھینچنی
-پھینچتی
-پھینچنی
-پھینٹتی
-پھینٹنی
-جھینپتی
-جھینپنی
-جھینکتی
-جھینکنی
-چھینکتی
-چھینکنی
-پھینکتی
-پھینکنی
-جھپیٹتی
-سنبھلتی
-متبنی
-پھٹپھٹی
-سنبھلنی
-کھٹیکنی
-کھینچتی
-کھینچنی
-گھسیٹتی
-گھسیٹنی
-گتھنیلی
-گھینپتی
-گھینپنی
-بھینٹتی
-بھینٹنی
-مستثنی
-مستغنی
-ہیلسنکی
-فلسطینی
-ٹیکنیکی
-لمنتہی
-پھسپھسی
-بھینچتے
-بھینچنے
-بھینچئے
-پھینچتے
-پھینچنے
-پھینچئے
-پسیجتے
-پھینٹتے
-پھینٹنے
-پھینٹئے
-پھینکئے
-جھینپتے
-جھینپنے
-جھینپئے
-جھینکتے
-جھینکنے
-جھینکئے
-چھینکتے
-چھینکنے
-چھینکئے
-کھینچتے
-کھینچنے
-کھینچئے
-گھسیٹتے
-گھسیٹنے
-گھسیٹئے
-جھپیٹتے
-جھپیٹنے
-جھپیٹئے
-سنبھلتے
-سنبھلنے
-سنبھلئے
-پھٹپھٹے
-چھچھلئے
-گھینپئے
-گھینپتے
-گھینپنے
-چھچھلتے
-چھچھلنے
-بھینٹتے
-بھینٹنے
-بھینٹئے
-پھینکتے
-پھینکنے
-لبینتہ
-لممتحنہ
-متخیلہ
-تفضیلیہ
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/8grams.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/8grams.txt
deleted file mode 100644 (file)
index d067491..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-چھنچھنیا
-جھنجھٹیا
-جھنجھنیا
-گھنگھنیا
-سپلیمینٹر
-شیکسپئر
-لمطففین
-جھینکتیں
-چھینکتین
-بھینچتین
-پھینچتین
-جھینپتین
-کھینچتین
-گھسیٹتین
-پھینکتین
-گھینپتین
-چھچھلتین
-سنبھلتین
-پھینٹتین
-بھینٹتین
-جھپیٹتین
-فلسطینو
-بیٹسمینو
-نسپیلیٹی
-نیشنیلٹی
-قسطنطیہ
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/LICENSE b/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/LICENSE
deleted file mode 100644 (file)
index 85f2b63..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-CC BY-NC-SA 3.0
-http://www.crulp.org/software/license/CreativeCommons.html
-https://creativecommons.org/licenses/by-nc-sa/3.0/
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/README b/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/README
deleted file mode 100644 (file)
index 33202c4..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-ORIGINAL README:
-
-Valid Ligatures of Urdu.
-
-In 1980 Mr. Ahmad Mirza Jamil has invented a ligature based Nastaleeq writing
-system. He has written about 18,000 valid ligatures of Urdu and developed a
-Noori Nastaliq font. Center for Research in Urdu Language Processing (CRULP) is
-releasing a soft copy of these ligatures in Unicode format. CRULP has
-extensively used these ligatures for testing the fonts developed at the center
-and realised that it will be a valuable resource for other font developers.
-These ligatures are grouped in 2 to 8 characters and are sorted in the end
-character order.
-
-These ligatures have been copied from a "Noori Nastaliq computerised Urdu
-calligraphy (list of ligatures)" calligraphically designed and compiled by
-Ahmad Mirza Jamil, Elite Publishers Limited, Karachi.
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/SOURCES b/test/shape/texts/in-house/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/SOURCES
deleted file mode 100644 (file)
index 5e67ed4..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Adapted from:
-
-http://www.crulp.org/software/ling_resources/UrduLigatures.htm
-http://www.crulp.org/Downloads/ling_resources/ligatures/Valid_Urdu_Ligatures_v1.1.zip
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/lam-alef.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/lam-alef.txt
deleted file mode 100644 (file)
index 26f6f7b..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-لًا
-ـلًا
-لاً
-ـلاً
-لّا
-ـلّا
-لاّ
-ـلاّ
-لًّا
-ـلًّا
-لاًّ
-ـلاًّ
-لَّا
-ـلَّا
-لاَّ
-ـلاَّ
-لَا
-ـلَا
-لاَ
-ـلاَ
-لُا
-ـلُا
-لاُ
-ـلاُ
-لِا
-ـلِا
-لاِ
-ـلاِ
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-arabic.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-arabic.txt
deleted file mode 100644 (file)
index 24eb0c9..0000000
+++ /dev/null
@@ -1,695 +0,0 @@
-ـيًـ
-ـاً
-يُـ
-ـرً
-ـقًـ
-ـدً
-رً
-رٍ
-ـبًـ
-ـرّ
-مًـ
-ـضًـ
-مُـ
-ـدّ
-ـوّ
-ـمًـ
-ـتًـ
-ـيّـ
-يًـ
-تُـ
-ءً
-دً
-نًـ
-ـمُـ
-ـمّـ
-ةً
-حًـ
-ـوً
-ـحًـ
-ـرِّ
-ـةً
-نٍ
-ـمّ
-فًـ
-ـكّـ
-ـعًـ
-ـصًـ
-اً
-سِـ
-ـيُـ
-قِـ
-ـفًـ
-ـذّ
-ـجّـ
-بًـ
-غًـ
-ـلّـ
-ـصّـ
-ـلّ
-ـدَّ
-ـسِّـ
-ـزً
-وّ
-ـثًـ
-بُـ
-ـغّـ
-خِـ
-ـدِّ
-فٍ
-ـسّـ
-ـنًـ
-عًـ
-ـفّـ
-ـيَّـ
-ـلٍ
-ـطًـ
-ـبّـ
-ـطّـ
-ـجِّـ
-عُـ
-ـيّ
-ـنّـ
-كًـ
-ـلِـ
-ـئًـ
-جًـ
-ـذَّ
-قًـ
-ـنُـ
-ـخّـ
-ـتُـ
-رَ
-كّـ
-طًـ
-نُـ
-رّ
-لٍ
-ـضّـ
-بّـ
-عِـ
-زً
-مِـ
-ـكَّـ
-ـدَ
-ـدٍ
-أُ
-ـمَّـ
-ـأً
-ـرَ
-ـزّ
-حِـ
-مَـ
-ـيِّـ
-ـوَّ
-ـمَـ
-صًـ
-ضًـ
-ـرِ
-
-وُ
-يّ
-ـمِّـ
-ـيًّـ
-ـرَّ
-ـوِّ
-ـكًـ
-رِ
-ـلَّـ
-ـجِـ
-يَـ
-ـجَّـ
-ـاّ
-ـذً
-ـقّـ
-ـغِّـ
-ـخًـ
-ـسَّـ
-ـلٍّ
-ـهًـ
-قّـ
-حَـ
-ـجًـ
-ـفَّـ
-شُـ
-جّـ
-ـهّـ
-سَـ
-ـعّـ
-ـدِ
-دٍ
-رِّ
-ـذٍ
-ـبُّـ
-ـتَـ
-دُ
-ـتُ
-لّ
-سِّـ
-لّـ
-دّ
-دِ
-يٍّ
-جَـ
-نّ
-هَّـ
-ـكِّـ
-ـقِّـ
-ـعُـ
-بَـ
-تَـ
-ـنِّـ
-ـلُّـ
-ـسُـ
-مّـ
-قَّـ
-لَـ
-يّـ
-فُـ
-قٍ
-ـتٍ
-سّـ
-وَ
-ـسِـ
-ـتَ
-شِـ
-فَـ
-صُـ
-ـضَّـ
-تَ
-ـقَّـ
-ـطَّـ
-ـفِـ
-سًـ
-فّـ
-وَّ
-كُـ
-ـصَّـ
-عَـ
-لِـ
-ـقِ
-ـقٍ
-ـتّـ
-ـمْـ
-نّـ
-ـقَ
-وٍ
-ـطٍ
-ـةٍ
-هّـ
-هُـ
-ـوٍ
-ـبِـ
-رُ
-حّـ
-تّـ
-وِّ
-زُ
-ـلًـ
-ـفُّـ
-تٍ
-سُـ
-ضٍ
-بِـ
-خَـ
-ىً
-ضّـ
-ـبِّـ
-خّـ
-لًـ
-كَّـ
-ـظًـ
-ظًـ
-ةٍ
-ـغًـ
-ـكِـ
-طُـ
-ـنٍ
-ـقُـ
-ـبُـ
-دَ
-ثًـ
-فِـ
-يٍ
-نْـ
-ضِـ
-جُـ
-هٍ
-ـشِـ
-ـنَّـ
-يًّـ
-فِّـ
-ـفّ
-ـظّـ
-ـسَـ
-ـظِّـ
-ـبَّـ
-رْ
-تَّـ
-بٍ
-ـبَـ
-ـزُّ
-ـدُ
-ـكُـ
-طّـ
-صِـ
-تِـ
-ـغَّـ
-ـعَـ
-ـهِّـ
-ـرُ
-ـثّـ
-سَّـ
-ذً
-ـمَ
-ـلِّـ
-ـزِّ
-يٌّ
-قِّـ
-ـشِّـ
-ـسًـ
-شٍ
-سٍ
-تًـ
-ـلَـ
-ـحُـ
-ـصّ
-ـحِـ
-ـجُـ
-يَّـ
-لَّـ
-قَـ
-ـبْـ
-اِ
-وُّ
-ـشّـ
-خًـ
-ـسَ
-حُـ
-يْ
-نِـ
-كُّـ
-ـطُّـ
-سْـ
-زِ
-يَّ
-هِـ
-نَـ
-مَّـ
-مٍ
-كِـ
-ـيُّـ
-ـمِـ
-ـدٍّ
-ـحّـ
-ـتَّـ
-رِّ
-ـطّ
-ـرُّ
-عٍ
-زّ
-خَّـ
-قُـ
-ـشَـ
-ـحَـ
-ـجِّـ
-مَ
-ـيَّ
-ـقّ
-ـغِ
-ـطِ
-ـشُـ
-صّـ
-شّـ
-جِّـ
-جِـ
-وِ
-ـهِ
-ـهِـ
-ــّـ
-ـرٍ
-ـاًّ
-طَّـ
-ثُـ
-تُ
-بَّـ
-هَـ
-لْـ
-صَـ
-دْ
-يِـ
-كِّـ
-ـعِـ
-ـذَ
-ـةَ
-دَّ
-يِّ
-هًـ
-كْـ
-ـوَ
-ـقَّ
-ـؤّ
-زَ
-حٍ
-يْـ
-كَـ
-فِ
-ـهٍ
-ـنّ
-ـكِ
-ـضَـ
-ـصِـ
-صِّـ
-شِّـ
-رَّ
-يِّـ
-ـاَ
-عُ
-شَـ
-ئًـ
-مٌـ
-لُـ
-ـوِ
-ـقِـ
-ـقَـ
-ـخَـ
-ـةِ
-دِّ
-جْـ
-ةِ
-نْ
-لِّـ
-ـيَـ
-ـنَـ
-ـلٌ
-ـفِ
-ـزَّ
-ـزِ
-ـاِ
-عّـ
-حَّـ
-ثَـ
-أَ
-ـمٍ
-ـكُّـ
-عْـ
-صَّـ
-يٌـ
-مْـ
-مّ
-فُّـ
-ـنْـ
-ـمَّ
-ـكَـ
-ـصِّـ
-ـصَـ
-ـاَّ
-حْـ
-ثّـ
-اُ
-نِ
-كَ
-ـمِ
-ـلٌّ
-ـلِ
-ـلَ
-ـفَـ
-ـفٍ
-ـظَّـ
-ـزَ
-ـةُ
-ـأُ
-عَّـ
-شَّـ
-ـنِـ
-ـلُ
-ـطِّـ
-ـطَـ
-ـضِّـ
-ـصُـ
-ـسُّـ
-ـحُ
-ـثّ
-ـأَ
-ضَـ
-تْ
-اَ
-مًّـ
-ـيِـ
-ـهُـ
-ـمًّـ
-ـكْـ
-ـعْـ
-ـرِّ
-ـتِـ
-ـتً
-ـاُ
-غَـ
-عِ
-طً
-شًـ
-زٍ
-تِ
-بْـ
-بِ
-لِ
-قْـ
-قٌـ
-فّ
-ـىً
-ـلُّ
-ـلُـ
-ـفُـ
-ــُـ
-ـعَّـ
-ـشَّـ
-ـشًـ
-ـذِ
-ـدٌ
-طِـ
-طَـ
-ضَّـ
-صْـ
-رُّ
-ذُ
-جَّـ
-بِّـ
-ئِـ
-ءُ
-هُّـ
-مِّـ
-مُ
-كِ
-قُ
-فْـ
-ـيٍّ
-ـىَّ
-ـوِّ
-ـكَ
-ـعَ
-ـطَ
-ـسْـ
-ـرٌ
-ـذِّ
-ـدُّ
-ـخَّـ
-ـحْ
-ـجَـ
-ـثَّـ
-ـثُـ
-ـتّ
-ـبِ
-ـاْ
-ـإِ
-عَ
-طِّـ
-صُّـ
-زْ
-خِّـ
-خَ
-ثِـ
-تْـ
-تّ
-بٌـ
-ءَ
-ءٍ
-وْ
-نُ
-مِ
-كُ
-فْ
-ـوُّ
-ـلٍـ
-ـقٍّ
-ـفِّـ
-ـفًّـ
-ـعُ
-ـعٍ
-ـطْـ
-ـطِـ
-ـطُـ
-ـصٍ
-ـرْ
-ـرٍّ
-ـذُّ
-ـدْ
-ـدِّ
-ـخِـ
-ـجَّـ
-ـثْ
-ـتَّ
-ـةٌ
-سِ
-خْـ
-ثَ
-تُّـ
-تَّ
-إِ
-أّ
-أً
-ءِ
-ءٌ
-يُّـ
-يُّ
-نٌـ
-لْ
-لُ
-لَ
-قِ
-ـيًّ
-ـيَ
-ـهَّـ
-ـهِّـ
-ـنُّـ
-ـمٍّ
-ـلْـ
-ـلْ
-ـلٍّ
-ـكِّـ
-ـعّ
-ـطَّ
-ـضُـ
-ـضٍ
-ـضٌـ
-ـصْـ
-
-ـصُّـ
-ـصًّـ
-ـسًّـ
-ـدَّ
-ـثِّـ
-ـثِـ
-ـتِّـ
-ـبّ
-ـبَ
-ـأٌ
-غُـ
-ظَـ
-طْـ
-ضْـ
-ضِ
-صّ
-صِ
-شْـ
-سٌـ
-ذْ
-ذَ
-خِ
-خُـ
-خٌـ
-حِّـ
-حٌـ
-بِّ
-بُّ
-بَ
-يٍّ
-ىّ
-نِّـ
-نَّـ
-نٍـ
-نٌ
-مْ
-مٌ
-لُّـ
-قُّـ
-قّ
-فَّـ
-فُ
-فٍـ
-ـيْـ
-ـيَّـ
-ـيً
-ـىّ
-ـوُ
-ـهّ
-ـهَـ
-ـنُ
-ـنَ
-ـمَّـ
-ـلَّ
-ـقٌ
-ـفِّ
-ـفٍّ
-ـفًّ
-ــِّـ
-ــِ
-ــَـ
-ـغِـ
-ـغُـ
-ـغَـ
-ـعٌـ
-ـظّ
-ـظِـ
-ـظَ
-ـطٍّ
-ـطِّـ
-ـطُ
-ـضً
-ـصِ
-ـصَ
-ـصٌ
-ـشّ
-ـسّ
-ـسَّـ
-ـزْ
-ـزُ
-ـرًّ
-ـدًّ
-ـخُـ
-ـخُ
-ـحَّـ
-ـجْـ
-ـثِ
-ـثُ
-ـتْـ
-ـتْ
-ـتِ
-ـبْ
-ـبِّ
-ـبُّـ
-ـبُ
-ـبَّـ
-ـأٰ
-ـأِ
-ـأٍ
-غْـ
-غِّـ
-عْ
-ظِـ
-ضُ
-شّ
-سٍـ
-زِّ
-دُّ
-حْ
-حِ
-جُ
-ثُ
-تٌـ
-تٌ
-ةُ
-ةَ
-ةٌ
-أْ
-أِ
-أٌ
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-persian.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-persian.txt
deleted file mode 100644 (file)
index 00d9840..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-ـاً
-اً
-ـهٔ
-هٔ
-وِ
-پُـ
-ـلِ
-سِـ
-اِ
-اُ
-ـهُ
-ـرّ
-گِـ
-کِـ
-کُـ
-ژِ
-ـیِ
-ـنِـ
-ـمُ
-ـصّـ
-ـسّـ
-رِ
-دّ
-دِ
-یِ
-هّ
-لِـ
-لِ
-ـیٰ
-ـیّ
-ـیَـ
-ـنِ
-ـمّـ
-ـعّـ
-ـشِ
-ـسِ
-ـزّ
-ـرِ
-ـذّ
-ـخّـ
-ـحِ
-ـثْ
-ـبّـ
-ـبّ
-ـأُ
-تّـ
-تِ
-بُـ
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-urdu.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-urdu.txt
deleted file mode 100644 (file)
index fddb6e5..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-ـیّـ
-ـمّـ
-ـلّـ
-ـرّ
-ـاً
-ـلِـ
-ـرِ
-بُـ
-ـوّ
-ؤ
-اً
-اِ
-ـنّـ
-ثّـ
-ـجّـ
-پُـ
-ـصّـ
-ـہٰـ
-ـعّـ
-ـخّـ
-یَـ
-کُـ
-جّـ
-ـنٰـ
-ـظّـ
-دّ
-ـھّـ
-اُ
-کِـ
-لِـ
-بِـ
-نِـ
-لُـ
-ـلٰـ
-ـدّ
-مّـ
-گُـ
-ـوِ
-ـسّـ
-سُـ
-رِ
-ـھُـ
-مِـ
-يُـ
-ـطّـ
-شِـ
-سَـ
-ـگَـ
-زُ
-ـگُـ
-ئِـ
-قّـ
-قِـ
-ـفّـ
-خّـ
-نّـ
-ـبّـ
-ہِ
-تّـ
-بَـ
-فِـ
-بّـ
-ـیٰ
-ـٹّـ
-وَ
-چّـ
-پِـ
-لّـ
-دُ
-ـلِ
-ـبٰـ
-ـچّـ
-سِـ
-کّـ
-ٹِـ
-وِ
-ـی٘ـ
-ـۂ
-ـوٰ
-وّ
-ـۓ
-ـکّـ
-نِ
-مُـ
-ـتّـ
-دِ
-یِـ
-ہِـ
-گَـ
-پَـ
-ٹّ
-یٔ
-یّـ
-ہُـ
-چُـ
-مِ
-ـوُ
-ـاَ
-اَ
-گِـ
-فِ
-ـےٍ
-ـڈّ
-ـؤ
-ـقّـ
-ـجِ
-اٰ
-ـڈِ
-ـپّـ
-ـٹِـ
-ـمِـ
-ـلٔـ
-ـخِ
-رُ
-تِ
-بِ
-ۓ
-کَـ
-ٹُـ
-ـی٘
-ـںَ
-ـو٘
-ـنُـ
-ـعّ
-ـشّـ
-ـرُ
-ـحّـ
-ـجِـ
-ـبَـ
-طّـ
-شِ
-شُـ
-رّ
-جِـ
-ئٰـ
-ہٰـ
-ۂ
-ڈِ
-ڈُ
-چِـ
-نِّـ
-نُـ
-نَـ
-مٰـ
-مّ
-مَـ
-لِّـ
-لِ
-فّـ
-ـیّ
-ـیِـ
-ـہ٘ـ
-ـہّ
-ـہِـ
-ـں٘
-ـگِـ
-ـکٰـ
-ـکِـ
-ـٹَـ
-ـيّـ
-ـوَ
-ـنِـ
-ـفِـ
-ـصِ
-ـسِـ
-ـزّ
-ـرً
-ـدَ
-ـحِـ
-ـحِ
-ـتّٰـ
-ـتِ
-ـبُـ
-ـأ
-عُـ
-ظِ
-صّـ
-صُـ
-زِ
-رَ
-دِّ
-خُـ
-حِ
-حَـ
-جّ
-جُـ
-جَـ
-تَـ
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/ligature-components.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/ligature-components.txt
deleted file mode 100644 (file)
index 0d4d47f..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-لّله
-لَّله
-لَّله
-للّه
-للَّه
-للَّه
-للهّ
-للهَّ
-للهَّ
-لّلَه
-لَلّه
-لّلهَ
-لَلهّ
-للّهَ
-للَهّ
-لّلّهَ
-لّلَّه
-لَّلّه
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/ligature-diacritics.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/ligature-diacritics.txt
deleted file mode 100644 (file)
index 80ba2f7..0000000
+++ /dev/null
@@ -1 +0,0 @@
-لَا لا لِله للَه لله
diff --git a/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/mark-skipping.txt b/test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/mark-skipping.txt
deleted file mode 100644 (file)
index 038c921..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-تختة
-تخنة
-تخئة
-تخثة
-تخٹة
-تختّة
-تخنّة
-تخئّة
-تخثّة
-تخٹّة
diff --git a/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/misc.txt b/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/misc.txt
deleted file mode 100644 (file)
index 57317de..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-ᠬᠦᠮᠦᠨ ᠮᠤᠩᠭᠣᠯ ᠪᠢᠴᠢᠭ᠌
-ᠪᠢᠴᠢᠭ᠌ ᠬᠦᠮᠦᠨ ᠮᠤᠩᠭᠣᠯ
-ᠮᠤᠩᠭᠣᠯ ᠪᠢᠴᠢᠭ᠌ ᠬᠦᠮᠦᠨ
-ᠡ᠆ᠡ
-ᠡ᠇ᠡ
-ᠡ᠊ᠡ
diff --git a/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/non-joining.txt b/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/non-joining.txt
deleted file mode 100644 (file)
index 93e9dd6..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-ᠡᢀᠡ
-ᠡᢁᠡ
-ᠡᢂᠡ
-ᠡᢃᠡ
-ᠡᢄᠡ
-ᠡᢅᠡ
-ᠡᢆᠡ
-ᠡᢇᠡ
diff --git a/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/poem.txt b/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/poem.txt
deleted file mode 100644 (file)
index 14ce2d4..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-ᠥᠰᠬᠦ ᠡᠴᠡ ᠰᠤᠷᠤᠭᠰᠠᠨ ᠦᠨᠳᠦᠰᠦᠨ ᠬᠡᠯᠡ
-ᠮᠠᠷᠲᠠᠵᠤ ᠪᠣᠯᠣᠰᠢ ᠦᠭᠡᠢ ᠰᠣᠶᠣᠯ
-ᠦᠬᠦᠲᠡᠯ᠎ᠡ ᠣᠷᠣᠰᠢᠬᠤ ᠲᠦᠷᠦᠯᠬᠢ ᠨᠤᠲᠤᠭ
-ᠰᠠᠯᠵᠤ ᠪᠣᠯᠣᠰᠢ ᠦᠭᠡᠢ ᠣᠷᠣᠨ
diff --git a/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/variation-selectors.txt b/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/variation-selectors.txt
deleted file mode 100644 (file)
index 0ffb498..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-ᠺᠣᠮᠫᠢᠦ᠋ᠲ᠋ᠧᠷ
-ᠭ ᠭ᠋ ᠭ᠌ ᠭ᠍‍     isol(,FVS1,FVS2,FVS3)
-ᠭ‍ ᠭ᠋‍ ᠭ᠌‍ ᠭ᠍‍     init(,FVS1,FVS2,FVS3)
-‍ᠭ‍ ‍ᠭ᠋‍ ‍ᠭ᠌‍ ‍ᠭ᠍‍      medi(,FVS1,FVS2,FVS3)
-‍ᠭ ‍ᠭ᠋ ‍ᠭ᠌      fina(,FVS1,FVS2)
-ᠠ‌ᠭᠠᠷ        ZWNJ
-ᠰᠤᠷ‍ ‍ᠭᠠ‍ ‍ᠭᠤᠯᠢ  ZWJ
-ᠪᠠᠢᠭ᠎ᠠ ᠶᠢᠨ   MVS,NNBSP
diff --git a/test/shape/texts/in-house/shaper-arabic/script-nko/misc/misc.txt b/test/shape/texts/in-house/shaper-arabic/script-nko/misc/misc.txt
deleted file mode 100644 (file)
index a86af91..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-ߊߊ
-ߊ߳ߊ
-ߊ߳ߺߊ
-ߊߺߊ
diff --git a/test/shape/texts/in-house/shaper-arabic/script-phags-pa/misc/misc.txt b/test/shape/texts/in-house/shaper-arabic/script-phags-pa/misc/misc.txt
deleted file mode 100644 (file)
index d535b67..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-ꡳꡡ
-ꡡꡳꡡ
-ꡞꡞꡞ ꡞ
-ꡟꡟꡟ ꡟ
-ꡠꡠꡠ ꡠ
-ꡡꡡꡡ ꡡ
-‍ꡡ‍
-‍ꡡ
-ꡡ‍
-ꡞ‌ꡟ‌ꡠ‌ꡡ
-ꡉꡞ
-ꡉꡞ︀
-ꡪꡞ
-ꡪꡞ︀
diff --git a/test/shape/texts/in-house/shaper-arabic/script-syriac/misc/abbreviation-mark.txt b/test/shape/texts/in-house/shaper-arabic/script-syriac/misc/abbreviation-mark.txt
deleted file mode 100644 (file)
index 52bdbea..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-ܐܒ
-ܐ܏
-ܐ܏ܒ
-ܐ܏ܒܓ
-ܐ܏ܒܓܕ
-ܐ܏ܒܓܕܐ
-ܐ܏ܒܓܕܐܐܐܐܐܐܐܐܐ
-ܐ܏ܒܓܕܐ܏ܐܐܐ܏ܐ܏ܐܐܐܐ
-ܐ܏ܒܓܕܓܓܓܓܓܓ
-ܐ܏ܒܓ
-܏ܫܘabcܒ.
diff --git a/test/shape/texts/in-house/shaper-arabic/script-syriac/misc/alaph.txt b/test/shape/texts/in-house/shaper-arabic/script-syriac/misc/alaph.txt
deleted file mode 100644 (file)
index 27b035f..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
- ܐ
- ܐܘ
- ܐܪ
- ܐܖ
- ܐܕ
- ܐܯ
- ܐܒ
-ܘܐ
-ܘܐܘ
-ܘܐܪ
-ܘܐܖ
-ܘܐܕ
-ܘܐܯ
-ܘܐܒ
-ܪܐ
-ܪܐܘ
-ܪܐܪ
-ܪܐܖ
-ܪܐܕ
-ܪܐܯ
-ܪܐܒ
-ܖܐ
-ܖܐܘ
-ܖܐܪ
-ܖܐܖ
-ܖܐܕ
-ܖܐܯ
-ܖܐܒ
-ܕܐ
-ܕܐܘ
-ܕܐܪ
-ܕܐܖ
-ܕܐܕ
-ܕܐܯ
-ܕܐܒ
-ܯܐ
-ܯܐܘ
-ܯܐܪ
-ܯܐܖ
-ܯܐܕ
-ܯܐܯ
-ܯܐܒ
-ܒܐ
-ܒܐܘ
-ܒܐܪ
-ܒܐܖ
-ܒܐܕ
-ܒܐܯ
-ܒܐܒ
- ܐܐ
- ܐܐܘ
- ܐܐܪ
- ܐܐܖ
- ܐܐܕ
- ܐܐܯ
- ܐܐܒ
-ܘܐܐ
-ܘܐܐܘ
-ܘܐܐܪ
-ܘܐܐܖ
-ܘܐܐܕ
-ܘܐܐܯ
-ܘܐܐܒ
-ܪܐܐ
-ܪܐܐܘ
-ܪܐܐܪ
-ܪܐܐܖ
-ܪܐܐܕ
-ܪܐܐܯ
-ܪܐܐܒ
-ܖܐܐ
-ܖܐܐܘ
-ܖܐܐܪ
-ܖܐܐܖ
-ܖܐܐܕ
-ܖܐܐܯ
-ܖܐܐܒ
-ܕܐܐ
-ܕܐܐܘ
-ܕܐܐܪ
-ܕܐܐܖ
-ܕܐܐܕ
-ܕܐܐܯ
-ܕܐܐܒ
-ܯܐܐ
-ܯܐܐܘ
-ܯܐܐܪ
-ܯܐܐܖ
-ܯܐܐܕ
-ܯܐܐܯ
-ܯܐܐܒ
-ܒܐܐ
-ܒܐܐܘ
-ܒܐܐܪ
-ܒܐܐܖ
-ܒܐܐܕ
-ܒܐܐܯ
-ܒܐܐܒ
diff --git a/test/shape/texts/in-house/shaper-default/script-ethiopic/misc/misc.txt b/test/shape/texts/in-house/shaper-default/script-ethiopic/misc/misc.txt
deleted file mode 100644 (file)
index 60dd8cc..0000000
+++ /dev/null
@@ -1 +0,0 @@
-ላ፟ህ
diff --git a/test/shape/texts/in-house/shaper-default/script-han/misc/cjk-compat.txt b/test/shape/texts/in-house/shaper-default/script-han/misc/cjk-compat.txt
deleted file mode 100644 (file)
index b3ab645..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-艹
-艹
-艹
diff --git a/test/shape/texts/in-house/shaper-default/script-hiragana/misc/kazuraki-liga-lines.txt b/test/shape/texts/in-house/shaper-default/script-hiragana/misc/kazuraki-liga-lines.txt
deleted file mode 100644 (file)
index 5bc2d00..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-ありあるあれいているべきいろうれし
-うれしくかしこかとがとうくもこと
-こともことをこのこれこれもされ
-しかししてするせんたしたのちる
-とけとしとしてとのともかくとを
-なくなどなどのなるひさひとふるほど
-ますむとめてもしろものをやるゆる
-られるとるものれる〳〵〴〵
diff --git a/test/shape/texts/in-house/shaper-default/script-hiragana/misc/kazuraki-liga.txt b/test/shape/texts/in-house/shaper-default/script-hiragana/misc/kazuraki-liga.txt
deleted file mode 100644 (file)
index e043e17..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-あり
-ある
-あれ
-いて
-いるべき
-いろ
-うれし
-うれしく
-かしこ
-かと
-がとう
-くも
-こと
-ことも
-ことを
-この
-これ
-これも
-され
-しかし
-して
-する
-せん
-たし
-たの
-ちる
-とけ
-とし
-として
-との
-ともかく
-とを
-なく
-など
-などの
-なる
-ひさ
-ひと
-ふる
-ほど
-ます
-むと
-めて
-もしろ
-ものを
-やる
-ゆる
-られ
-ると
-るもの
-れる
-〳〵
-〴〵
diff --git a/test/shape/texts/in-house/shaper-default/script-linear-b/misc/misc.txt b/test/shape/texts/in-house/shaper-default/script-linear-b/misc/misc.txt
deleted file mode 100644 (file)
index b085605..0000000
+++ /dev/null
@@ -1 +0,0 @@
-𐀁𐀂𐀃
diff --git a/test/shape/texts/in-house/shaper-default/script-tifinagh/misc/misc.txt b/test/shape/texts/in-house/shaper-default/script-tifinagh/misc/misc.txt
deleted file mode 100644 (file)
index 9fc069a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-ⵎⵜ
-ⵎ⵿ⵜ
-ⵏⴾ
-ⵏ⵿ⴾ
-ⵏⵜ
-ⵏ⵿ⵜ
-ⵔⵜ
-ⵔ⵿ⵜ
-ⵙⵜ
-ⵙ⵿ⵜ
diff --git a/test/shape/texts/in-house/shaper-hangul/script-hangul/misc/misc.txt b/test/shape/texts/in-house/shaper-hangul/script-hangul/misc/misc.txt
deleted file mode 100644 (file)
index 797b1c6..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-휴가 가-- (오--)
-휴가 가-- (오--)
-ᄒᆞᆫ
-ᅟᅡᄫᅠ
diff --git a/test/shape/texts/in-house/shaper-hebrew/script-hebrew/misc/diacritics.txt b/test/shape/texts/in-house/shaper-hebrew/script-hebrew/misc/diacritics.txt
deleted file mode 100644 (file)
index f3cf91f..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-קול דודי הנה־זה בא מדלג על־ההרים מקפץ על־הגבעות
-הֲבֵל הֲבָלִים אָמַר קֹהֶלֶת
-לְהַגִּיד בַּבֹּקֶר חַסְדֶּךָ וֶאֱמוּנָתְךָ בַּלֵּילוֹת
-יְרוּשָׁלִַם
-יְרוּשָׁלִָם
-יְרוּשָׁלְַמָה
-יְרוּשָׁלְָמָה
-נְבֻֽכַדְנֶאצַּ֣ר
-מִתָּ֑͏ַ֜חַת
-אֲ‍ֽ֭דַבְּרָה
-וֽ͏ַיְהִי־֯כֵֽן
-לׅׄוּלֵׅ֗ׄאׅׄ
-אָנָּֽה אָנָּֽה
-תַעֲשֶׂ֦ה
-שֹֽׁטְרֵי֙
-אֲ‍ֽ֭
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/LICENSE
deleted file mode 100644 (file)
index 2cf8228..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/README
deleted file mode 100644 (file)
index 8bad337..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/SOURCES
deleted file mode 100644 (file)
index 0ed1a89..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
deleted file mode 100644 (file)
index 2bc4fff..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-ৠ
-ৡ
-ৢ
-ৣ
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644 (file)
index 0f8fa91..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-ক
-খ
-গ
-ঘ
-ঙ
-চ
-ছ
-জ
-ঝ
-ঞ
-ট
-ঠ
-ড
-ঢ
-ণ
-ত
-থ
-দ
-ধ
-ন
-প
-ফ
-ব
-ভ
-ম
-য
-ৰ
-ৱ
-ল
-ড়
-ঢ়
-য়
-শ
-ষ
-স
-হ
-ৎ
-ং
-ঃ
-ঁ
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644 (file)
index ddf03c0..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-া
-ি
-ী
-ু
-ূ
-ৃ
-ে
-ৈ
-ো
-ৌ
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644 (file)
index 870ce26..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-০
-১
-২
-৩
-৪
-৫
-৬
-৭
-৮
-৯
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644 (file)
index 821c261..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-অ
-আ
-ই
-ঈ
-উ
-ঊ
-ঋ
-এ
-ঐ
-ও
-ঔ
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
deleted file mode 100644 (file)
index 66a7ca4..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644 (file)
index 0afc191..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-্
-়
-ং
-ঃ
-ঁ
-৺
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
deleted file mode 100644 (file)
index ebbc87d..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-কঁ
-খঁ
-গঁ
-ঘঁ
-চঁ
-ছঁ
-জঁ
-ঝঁ
-টঁ
-ঠঁ
-ডঁ
-ঢঁ
-তঁ
-থঁ
-দঁ
-ধঁ
-পঁ
-ফঁ
-বঁ
-ভঁ
-মঁ
-যঁ
-ৰঁ
-লঁ
-শঁ
-ষঁ
-সঁ
-হঁ
-ৰ্ক
-ৰ্খ
-ৰ্গ
-ৰ্ঘ
-ৰ্চ
-ৰ্ছ
-ৰ্জ
-ৰ্ঝ
-ৰ্ঞ
-ৰ্ট
-ৰ্ঠ
-ৰ্ড
-ৰ্ঢ
-ৰ্ণ
-ৰ্ত
-ৰ্থ
-ৰ্দ
-ৰ্ধ
-ৰ্ন
-ৰ্প
-ৰ্ফ
-ৰ্ব
-ৰ্ভ
-ৰ্ম
-ৰ্য
-ৰ্ৰ
-ৰ্ল
-ৰ্শ
-ৰ্ষ
-ৰ্স
-ৰ্হ
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
deleted file mode 100644 (file)
index accebeb..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-কু
-কূ
-কৃ
-খু
-খূ
-খৃ
-গু
-গূ
-গৃ
-ঘু
-ঘূ
-ঘৃ
-ঙু
-ঙূ
-ঙৃ
-চু
-চূ
-চৃ
-ছু
-ছূ
-ছৃ
-জু
-জূ
-জৃ
-ঝু
-ঝূ
-ঝৃ
-ঞু
-ঞূ
-টু
-টূ
-টৃ
-ঠু
-ঠূ
-ঠৃ
-ডু
-ডূ
-ডৃ
-ঢু
-ঢূ
-ঢৃ
-ণু
-ণূ
-ণৃ
-তু
-তূ
-তৃ
-থু
-থূ
-থৃ
-দু
-দূ
-দৃ
-ধু
-ধূ
-ধৃ
-নু
-নূ
-নৃ
-পু
-পূ
-পৃ
-ফু
-ফূ
-ফৃ
-বু
-বূ
-বৃ
-ভু
-ভূ
-ভৃ
-মু
-মূ
-মৃ
-যু
-যূ
-যৃ
-ৰু
-ৰূ
-ৰৃ
-লু
-লূ
-লৃ
-শু
-শূ
-শৃ
-ষু
-ষূ
-ষৃ
-সু
-সূ
-সৃ
-হু
-হূ
-হৃ
-ক্
-খ্
-গ্
-ঘ্
-ঙ্
-চ্
-ছ্
-জ্
-ঝ্
-ঞ্
-ট্
-ঠ্
-ড্
-ঢ্
-ণ্
-ত্
-থ্
-দ্
-ধ্
-ন্
-প্
-ফ্
-ব্
-ভ্
-ম্
-য্
-ৰ্
-ল্
-শ্
-ষ্
-স্
-হ্
-জ়
-ড়
-ঢ়
-য়
diff --git a/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644 (file)
index 87e5ea8..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-ক্ৰ
-খ্ৰ
-গ্ৰ
-ঘ্ৰ
-জ্ৰ
-ত্ৰ
-দ্ৰ
-ধ্ৰ
-প্ৰ
-ম্ৰ
-শ্ৰ
-স্ৰ
-হ্ৰ
-ক্ল
-গ্ল
-প্ল
-ম্ল
-ল্ল
-শ্ল
-স্ল
-হ্ল
-ক্ক
-ক্ব
-জ্ব
-ট্ব
-ত্ব
-দ্ব
-ধ্ব
-ন্ব
-ব্ব
-ম্ব
-ল্ব
-শ্ব
-ষ্ব
-স্ব
-হ্ব
-ণ্ণ
-ষ্ণ
-ষ্ণু
-হ্ণ
-হ্ণি
-জ্জ
-ট্ট
-ত্ত
-দ্দ
-ন্ন
-প্প
-ব্ব
-ম্ম
-ত্ন
-ম্ন
-স্ন
-হ্ন
-ক্ন
-গ্ন
-ত্ম
-গ্ম
-ঙ্ম
-ট্ম
-ণ্ম
-ত্ম
-দ্ম
-ধ্ম
-ন্ম
-ম্ম
-ল্ম
-শ্ম
-ষ্ম
-হ্ম
-ক্ষ
-ক্ত
-গ্ধ
-ঙ্ক
-ঙ্খ
-ঙ্গ
-ঙ্ঘ
-চ্চ
-চ্ছ
-চ্ঞ
-জ্ঝ
-জ্ঞ
-ঞ্চ
-ঞ্ছ
-ঞ্জ
-ণ্ট
-ক্ট
-ণ্ড
-ন্ড
-দ্গ
-দ্ঘ
-দ্ধ
-দ্ভ
-ন্ত
-ন্থ
-ন্দ
-ন্ধ
-প্ত
-ব্জ
-ব্দ
-ম্প
-ম্ফ
-ম্ব
-ম্ভ
-ল্ক
-ল্গ
-ল্প
-ল্ফ
-ল্ম
-শ্চ
-ষ্ক
-ষ্ট
-ষ্ঠ
-ষ্প
-ষ্ফ
-স্ক
-স্খ
-স্ত
-স্থ
-স্প
-স্ফ
-ক্ষ্ণ
-ক্ষ্ম
-জ্জ্ব
-ত্ত্ব
-ত্ম্য
-ন্ত্ৰ
-ন্ত্ব
-ন্দ্ৰ
-ন্ধ্য
-ন্ন্য
-ম্প্ৰ
-ম্ভ্ৰ
-ৰ্ধ্ব
-ৰ্শ্ব
-ষ্ট্ৰ
-ষ্প্ৰ
-স্ত্ৰ
-চ্ছ্ব
-প্স
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/bengali-vowel-letters.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/bengali-vowel-letters.txt
deleted file mode 100644 (file)
index f09dbc8..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-আ অা
-ৠ ঋৃ
-ৡ ঌৢ
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/misc/misc.txt
deleted file mode 100644 (file)
index aa43590..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-অ্য
-ক
-ক়
-কি
-ক্
-ক্ক
-ক্র
-ক্র্ক
-ক্‌ক
-ক্‍ক
-দ্য
-ন্ক
-ন্ধ
-ন্ব
-ন্য
-ন্র
-ন্‌ক
-ন্‌ধ
-ন্‌ব
-ন্‌র
-ন্‍ক
-ন্‍ধ
-ন্‍ব
-ন্‍র
-য্
-র্ক
-র্কি
-র্কৌ
-র্ন্‍
-র্ব্ব
-শ্য
-ষ্য
-স্য
-ি
-কো
-কৌ
-ক্র্ক
-ন্‌ক
-ন্‌ব
-ন্‍ক
-ন্‍ব
-ন্‍র
-র্কাং
-র্কাঃ
-র্কৌ
-র্ভ
-ৰ্ভ
-ৱ্ভ
-অৗ
-ন্ত্র
-ত্যু
-চ্য্র
-ক্‍ষ
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/misc/reph.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/misc/reph.txt
deleted file mode 100644 (file)
index 9739eaa..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-র্ক
-র্কা
-র্কি
-র্কী
-র্কু
-র্কূ
-র্কে
-র্কৈ
-র্কো
-র্কৌ
-র্য
-র্‍য
-র‍্য
-র্র‍্য
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/LICENSE
deleted file mode 100644 (file)
index 2cf8228..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/README
deleted file mode 100644 (file)
index 8bad337..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/SOURCES
deleted file mode 100644 (file)
index 0ed1a89..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
deleted file mode 100644 (file)
index fd5e6e6..0000000
+++ /dev/null
@@ -1 +0,0 @@
-codepoint, imagepath, rawcode, desc
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644 (file)
index 7554b36..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-ক
-খ
-গ
-ঘ
-ঙ
-চ
-ছ
-জ
-ঝ
-ঞ
-ট
-ঠ
-ড
-ঢ
-ণ
-ত
-থ
-দ
-ধ
-ন
-প
-ফ
-ব
-ভ
-ম
-য
-র
-ল
-ড়
-ঢ়
-য়
-শ
-ষ
-স
-হ
-ৎ
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644 (file)
index ddf03c0..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-া
-ি
-ী
-ু
-ূ
-ৃ
-ে
-ৈ
-ো
-ৌ
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644 (file)
index 870ce26..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-০
-১
-২
-৩
-৪
-৫
-৬
-৭
-৮
-৯
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644 (file)
index 169ba5d..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-অ
-আ
-ই
-ঈ
-উ
-ঊ
-ঋ
-ঌ
-এ
-ঐ
-ও
-ঔ
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
deleted file mode 100644 (file)
index 66a7ca4..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644 (file)
index 0afc191..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-্
-়
-ং
-ঃ
-ঁ
-৺
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
deleted file mode 100644 (file)
index 7c652be..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-কঁ
-খঁ
-গঁ
-ঘঁ
-চঁ
-ছঁ
-জঁ
-ঝঁ
-টঁ
-ঠঁ
-ডঁ
-ঢঁ
-তঁ
-থঁ
-দঁ
-ধঁ
-পঁ
-ফঁ
-বঁ
-ভঁ
-মঁ
-যঁ
-রঁ
-লঁ
-শঁ
-ষঁ
-সঁ
-হঁ
-র্ক
-র্খ
-র্গ
-র্ঘ
-র্চ
-র্ছ
-র্জ
-র্ঝ
-র্ট
-র্ঠ
-র্ড
-র্ঢ
-র্ণ
-র্ত
-র্থ
-র্দ
-র্ধ
-র্ন
-র্প
-র্ফ
-র্ব
-র্ভ
-র্ম
-র্য
-র্র
-র্ল
-র্শ
-র্ষ
-র্স
-র্হ
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
deleted file mode 100644 (file)
index 2fd42e0..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-কু
-কূ
-কৃ
-খু
-খূ
-খৃ
-গু
-গূ
-গৃ
-ঘু
-ঘূ
-ঘৃ
-চু
-চূ
-চৃ
-ছু
-ছূ
-ছৃ
-জু
-জূ
-জৃ
-ঝু
-ঝূ
-ঝৃ
-টু
-টূ
-টৃ
-ঠু
-ঠূ
-ঠৃ
-ডু
-ডূ
-ডৃ
-ঢু
-ঢূ
-ণু
-ণূ
-তু
-তূ
-তৃ
-থু
-থূ
-দু
-দূ
-দৃ
-ধু
-ধূ
-ধৃ
-নু
-নূ
-নৃ
-পু
-পূ
-পৃ
-ফু
-ফূ
-ফৃ
-বু
-বূ
-বৃ
-ভু
-ভূ
-ভৃ
-মু
-মূ
-মৃ
-যু
-যূ
-যৃ
-রু
-রূ
-রৃ
-লু
-লূ
-শু
-শূ
-শৃ
-ষু
-ষূ
-ষৃ
-সু
-সূ
-সৃ
-হু
-হূ
-হৃ
-ক্
-খ্
-গ্
-ঘ্
-ঙ্
-চ্
-ছ্
-জ্
-ঝ্
-ঞ্
-ট্
-ঠ্
-ড্
-ঢ্
-ণ্
-ত্
-থ্
-দ্
-ধ্
-ন্
-প্
-ফ্
-ব্
-ভ্
-ম্
-য্
-র্
-ল্
-শ্
-ষ্
-স্
-হ্
-জ়
diff --git a/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644 (file)
index b45b778..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-ক্র
-খ্র
-গ্র
-ঘ্র
-জ্র
-ত্র
-দ্র
-ধ্র
-প্র
-ম্র
-শ্র
-স্র
-হ্র
-ছ্র
-ট্র
-ঠ্র
-ড্র
-থ্র
-ফ্র
-ব্র
-ভ্র
-ক্য
-খ্য
-গ্য
-ঘ্য
-চ্য
-জ্য
-ট্য
-ঠ্য
-ড্য
-ড়্য
-ঢ্য
-ত্য
-থ্য
-দ্য
-ধ্য
-ন্য
-প্য
-ফ্য
-ব্য
-ভ্য
-ম্য
-য্য
-র‍্য
-ল্য
-শ্য
-ষ্য
-স্য
-হ্য
-ক্ল
-গ্ল
-প্ল
-ম্ল
-ল্ল
-শ্ল
-স্ল
-হ্ল
-ক্ক
-ক্ব
-জ্ব
-ট্ব
-ত্ব
-দ্ব
-ধ্ব
-ন্ব
-ব্ব
-ম্ব
-ল্ব
-শ্ব
-ষ্ব
-স্ব
-হ্ব
-ণ্ণ
-ষ্ণ
-ষ্ণু
-হ্ণ
-হ্ণি
-জ্জ
-ট্ট
-ত্ত
-দ্দ
-ন্ন
-প্প
-ত্ন
-ম্ন
-স্ন
-হ্ন
-ক্ন
-গ্ন
-গ্ম
-ঙ্ম
-ট্ম
-ণ্ম
-ত্ম
-দ্ম
-ধ্ম
-ন্ম
-ম্ম
-ল্ম
-শ্ম
-ষ্ম
-হ্ম
-ক্ষ
-ক্ত
-গ্ধ
-ঙ্ক
-ঙ্খ
-ঙ্গ
-ঙ্ঘ
-চ্চ
-চ্ছ
-চ্ঞ
-জ্ঝ
-জ্ঞ
-ঞ্চ
-ঞ্ছ
-ঞ্জ
-ণ্ট
-ক্ট
-ণ্ড
-ন্ড
-দ্গ
-দ্ঘ
-দ্ধ
-দ্ভ
-ন্ত
-ন্থ
-ন্দ
-ন্ধ
-প্ত
-ব্জ
-ব্দ
-ম্প
-ম্ফ
-ম্ভ
-ল্ক
-ল্গ
-ল্প
-ল্ফ
-শ্চ
-ষ্ক
-ষ্ট
-ষ্ঠ
-ষ্প
-ষ্ফ
-স্ক
-স্খ
-স্ত
-স্থ
-স্প
-স্ফ
-ম্থ
-ল্ত
-ল্ধ
-ক্ম
-ক্স
-গ্গ
-ঘ্ন
-চ্ন
-ছ্ব
-ঞ্ঝ
-ড্ড
-ড্ম
-ড়্গ
-ণ্ঠ
-ণ্ঢ
-ণ্ব
-ত্থ
-থ্ব
-ধ্ন
-ন্ট
-ন্ঠ
-ন্স
-প্ট
-প্ন
-ফ্ল
-ব্ধ
-ব্ল
-ভ্ল
-ম্ত
-ম্দ
-ল্ট
-ল্ড
-শ্ছ
-শ্ন
-শ্ত
-স্ট
-স্ম
-চ্ছ্র
-চ্ছ্ব
-দ্দ্ব
-দ্ধ্ব
-ন্ধ্র
-ব্দ্র
-ক্ষ্ণ
-ক্ষ্ম
-জ্জ্ব
-ত্ত্ব
-ত্ম্য
-ন্ত্র
-ন্ত্ব
-ন্দ্র
-ন্ধ্য
-ন্ন্য
-ম্প্র
-ম্ভ্র
-র্ধ্ব
-র্শ্ব
-ষ্ট্র
-ষ্প্র
-স্ত্র
-স্ট্র
-স্ক্র
-ক্ট্র
-প্স
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/devanagari-atomic-consonants.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/devanagari-atomic-consonants.txt
deleted file mode 100644 (file)
index 4265436..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-ख ख्ा ख्‍ा
-ग ग्ा ग्‍ा
-घ घ्ा घ्‍ा
-च च्ा च्‍ा
-ज ज्ा ज्‍ा
-झ झ्ा झ्‍ा
-ञ ञ्ा ञ्‍ा
-ण ण्ा ण्‍ा
-त त्ा त्‍ा
-थ थ्ा थ्‍ा
-ध ध्ा ध्‍ा
-न न्ा न्‍ा
-ऩ ऩ्ा ऩ्‍ा ऩ्ा ऩ्‍ा
-प प्ा प्‍ा
-ब ब्ा ब्‍ा
-भ भ्ा भ्‍ा
-म म्ा म्‍ा
-य य्ा य्‍ा
-ल ल्ा ल्‍ा
-व व्ा व्‍ा
-श श्ा श्‍ा
-ष ष्ा ष्‍ा
-स स्ा स्‍ा
-ख़ ख़्ा ख़्‍ा ख़्ा ख़्‍ा
-ग़ ग़्ा ग़्‍ा ग़्ा ग़्‍ा
-ज़ ज़्ा ज़्‍ा ज़्ा ज़्‍ा
-य़ य़्ा य़्‍ा य़्ा य़्‍ा
-ॹ ॹ्ा ॹ्‍ा
-ॺ ॺ्ा ॺ्‍ा
-ज़ ॻ्ा ॻ्‍ा
-ॼ ॼ्ा ॼ्‍ा
-ॾ ॾ्ा ॾ्‍ा
-ॿ ॿ्ा ॿ्‍ा
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/devanagari-vowel-letters.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/devanagari-vowel-letters.txt
deleted file mode 100644 (file)
index 5a41252..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-ऄ अॆ
-आ अा
-ई र्इ
-ऊ उु
-ऍ एॅ
-ऎ एॆ
-ऐ एे
-ऑ अॉ आॅ
-ऒ अॊ आॆ
-ओ अो आे
-औ अौ आै
-ॲ अॅ
-ॳ अऺ
-ॴ अऻ आऺ
-ॵ अॏ
-ॶ अॖ
-ॷ अॗ
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/dottedcircle.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/dottedcircle.txt
deleted file mode 100644 (file)
index fd0ebdb..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-र्◌
-र्◌्च
-र्◌्च्छे
-र्◌ि
-र्◌्
-र्◌़
-◌्च्छे
-र् 
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/eyelash.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/eyelash.txt
deleted file mode 100644 (file)
index 8e11955..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-त्र्क
-त्र्‍क
-त्र्‌क
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/joiners.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/joiners.txt
deleted file mode 100644 (file)
index 75f85cc..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-र्ह
-र्‌ह
-र्‍ह
-ऱ्ह
-ऱ्‌ह
-ऱ्‍ह
-क्क
-क्‍
-क्‌क
-क्‍क
-क्कि
-क्‌कि
-क्‍कि
-क्ष
-क्‌ष
-क्‍ष
-द्सि
-द्‌सि
-द्‍सि
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/misc.txt
deleted file mode 100644 (file)
index 4a8326c..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-क
-क़
-कि
-क्
-क्क
-क्र
-क्र्क
-क्र्‍
-क्ष
-क्ष्
-क्‌ष
-क्‍
-क्‍ष
-छ्र्क
-ज्ञ्
-ट्रु
-र्क
-र्कि
-र्क्रि
-र्‍
-ि
-फ़्र
-फ्र
-द्दि
-क्ष
-क्‌ष
-क्‍ष
-र्अ्
-र्अ्‌
-र्अ्‍
-र्आ्र्
-क‌ि
-ऽं
-रुँः
-1ि
-१॑
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/spec-deviations.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/spec-deviations.txt
deleted file mode 100644 (file)
index 4814019..0000000
+++ /dev/null
@@ -1 +0,0 @@
-सा़े
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/tricky-reordering.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/tricky-reordering.txt
deleted file mode 100644 (file)
index 1723ced..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-Usage:
-  ./hb-unicode-encode UNICODE_STRING...
-or:
-  ./hb-unicode-encode --stdin
-फि्
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/LICENSE
deleted file mode 100644 (file)
index 2cf8228..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/README
deleted file mode 100644 (file)
index 8bad337..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/SOURCES
deleted file mode 100644 (file)
index 0ed1a89..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt
deleted file mode 100644 (file)
index 89cefb6..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-क़
-ख़
-ग़
-ज़
-ड़
-ढ़
-फ़
-य
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
deleted file mode 100644 (file)
index 9f7cda9..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-ॠ
-ॡ
-ॢ
-ॣ
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644 (file)
index 3aa66ce..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-क
-ख
-ग
-घ
-ङ
-च
-छ
-ज
-झ
-ञ
-ट
-ठ
-ड
-ढ
-ण
-त
-थ
-द
-ध
-न
-ऩ
-प
-फ
-ब
-भ
-म
-य
-र
-ऱ
-ल
-ळ
-ऴ
-व
-श
-ष
-स
-ह
-क़
-ख़
-ग़
-ज़
-ड़
-ढ़
-फ़
-य़
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644 (file)
index 04cf0a7..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-ा
-ि
-ी
-ु
-ू
-ृ
-ॄ
-ॅ
-ॆ
-े
-ै
-ॉ
-ो
-ौ
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DevnagariSpecificAddition.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DevnagariSpecificAddition.txt
deleted file mode 100644 (file)
index 7b0b32c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-॰
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644 (file)
index 1427002..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-०
-१
-२
-३
-४
-५
-६
-७
-८
-९
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-GenericPunctuation.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-GenericPunctuation.txt
deleted file mode 100644 (file)
index 66a7ca4..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644 (file)
index b336c35..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-अ
-आ
-इ
-ई
-उ
-ऊ
-ऋ
-ऌ
-ऍ
-ऎ
-ए
-ऐ
-ऑ
-ऒ
-ओ
-औ
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644 (file)
index 2ff3e87..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-ँ
-ं
-ः
-़
-ऽ
-्
-ॐ
-॒
-॓
-॔
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
deleted file mode 100644 (file)
index 6d57308..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-कॅ
-खॅ
-गॅ
-घॅ
-ङॅ
-चॅ
-छॅ
-जॅ
-झॅ
-ञॅ
-टॅ
-ठॅ
-डॅ
-ढॅ
-णॅ
-तॅ
-थॅ
-दॅ
-धॅ
-नॅ
-ऩॅ
-पॅ
-फॅ
-बॅ
-भॅ
-मॅ
-यॅ
-रॅ
-ऱॅ
-लॅ
-ळॅ
-ऴॅ
-वॅ
-शॅ
-षॅ
-सॅ
-हॅ
-कॆ
-खॆ
-गॆ
-घॆ
-ङॆ
-चॆ
-छॆ
-जॆ
-झॆ
-ञॆ
-टॆ
-ठॆ
-डॆ
-ढॆ
-णॆ
-तॆ
-थॆ
-दॆ
-धॆ
-नॆ
-ऩॆ
-पॆ
-फॆ
-बॆ
-भॆ
-मॆ
-यॆ
-रॆ
-ऱॆ
-लॆ
-ळॆ
-ऴॆ
-वॆ
-शॆ
-षॆ
-सॆ
-हॆ
-के
-खे
-गे
-घे
-ङे
-चे
-छे
-जे
-झे
-ञे
-टे
-ठे
-डे
-ढे
-णे
-ते
-थे
-दे
-धे
-ने
-ऩे
-पे
-फे
-बे
-भे
-मे
-ये
-रे
-ऱे
-ले
-ळे
-ऴे
-वे
-शे
-षे
-से
-हे
-कै
-खै
-गै
-घै
-ङै
-चै
-छै
-जै
-झै
-ञै
-टै
-ठै
-डै
-ढै
-णै
-तै
-थै
-दै
-धै
-नै
-ऩै
-पै
-फै
-बै
-भै
-मै
-यै
-रै
-ऱै
-लै
-ळै
-ऴै
-वै
-शै
-षै
-सै
-है
-कँ
-खँ
-गँ
-घँ
-ङँ
-चँ
-छँ
-जँ
-झँ
-ञँ
-टँ
-ठँ
-डँ
-ढँ
-णँ
-तँ
-थँ
-दँ
-धँ
-नँ
-ऩँ
-पँ
-फँ
-बँ
-भँ
-मँ
-यँ
-रँ
-ऱँ
-लँ
-ळँ
-ऴँ
-वँ
-शँ
-षँ
-सँ
-हँ
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
deleted file mode 100644 (file)
index bff1a7b..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-कु
-खु
-गु
-घु
-ङु
-चु
-छु
-जु
-झु
-ञु
-टु
-ठु
-डु
-ढु
-णु
-तु
-थु
-दु
-धु
-नु
-ऩु
-पु
-फु
-बु
-भु
-मु
-यु
-रु
-ऱु
-लु
-ळु
-ऴु
-वु
-शु
-षु
-सु
-हु
-कू
-खू
-गू
-घू
-ङू
-चू
-छू
-जू
-झू
-ञू
-टू
-ठू
-डू
-ढू
-णू
-तू
-थू
-दू
-धू
-नू
-ऩू
-पू
-फू
-बू
-भू
-मू
-यू
-रू
-ऱू
-लू
-ळू
-ऴू
-वू
-शू
-षू
-सू
-हू
-कृ
-खृ
-गृ
-घृ
-ङृ
-चृ
-छृ
-जृ
-झृ
-ञृ
-टृ
-ठृ
-डृ
-ढृ
-णृ
-तृ
-थृ
-दृ
-धृ
-नृ
-ऩृ
-पृ
-फृ
-बृ
-भृ
-मृ
-यृ
-रृ
-ऱृ
-लृ
-ळृ
-ऴृ
-वृ
-शृ
-षृ
-सृ
-हृ
-कॄ
-खॄ
-गॄ
-घॄ
-ङॄ
-चॄ
-छॄ
-जॄ
-झॄ
-ञॄ
-टॄ
-ठॄ
-डॄ
-ढॄ
-णॄ
-तॄ
-थॄ
-दॄ
-धॄ
-नॄ
-ऩॄ
-पॄ
-फॄ
-बॄ
-भॄ
-मॄ
-यॄ
-रॄ
-ऱॄ
-लॄ
-ळॄ
-ऴॄ
-वॄ
-शॄ
-षॄ
-सॄ
-हॄ
-क्
-ख्
-ग्
-घ्
-ङ्
-च्
-छ्
-ज्
-झ्
-ञ्
-ट्
-ठ्
-ड्
-ढ्
-ण्
-त्
-थ्
-द्
-ध्
-न्
-ऩ्
-प्
-फ्
-ब्
-भ्
-म्
-य्
-र्
-ऱ्
-ल्
-ळ्
-ऴ्
-व्
-श्
-ष्
-स्
-ह्
diff --git a/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644 (file)
index 3b5e620..0000000
+++ /dev/null
@@ -1,1367 +0,0 @@
-क्क
-क्ख
-क्ग
-क्घ
-क्ङ
-क्च
-क्छ
-क्ज
-क्झ
-क्ञ
-क्ट
-क्ठ
-क्ड
-क्ढ
-क्ण
-क्त
-क्थ
-क्द
-क्ध
-क्न
-क्ऩ
-क्प
-क्फ
-क्ब
-क्भ
-क्म
-क्य
-क्र
-क्ऱ
-क्ल
-क्ळ
-क्ऴ
-क्व
-क्श
-क्ष
-क्स
-क्ह
-ख्क
-ख्ख
-ख्ग
-ख्घ
-ख्ङ
-ख्च
-ख्छ
-ख्ज
-ख्झ
-ख्ञ
-ख्ट
-ख्ठ
-ख्ड
-ख्ढ
-ख्ण
-ख्त
-ख्थ
-ख्द
-ख्ध
-ख्न
-ख्ऩ
-ख्प
-ख्फ
-ख्ब
-ख्भ
-ख्म
-ख्य
-ख्र
-ख्ऱ
-ख्ल
-ख्ळ
-ख्ऴ
-ख्व
-ख्श
-ख्ष
-ख्स
-ख्ह
-ग्क
-ग्ख
-ग्ग
-ग्घ
-ग्ङ
-ग्च
-ग्छ
-ग्ज
-ग्झ
-ग्ञ
-ग्ट
-ग्ठ
-ग्ड
-ग्ढ
-ग्ण
-ग्त
-ग्थ
-ग्द
-ग्ध
-ग्न
-ग्ऩ
-ग्प
-ग्फ
-ग्ब
-ग्भ
-ग्म
-ग्य
-ग्र
-ग्ऱ
-ग्ल
-ग्ळ
-ग्ऴ
-ग्व
-ग्श
-ग्ष
-ग्स
-ग्ह
-घ्क
-घ्ख
-घ्ग
-घ्घ
-घ्ङ
-घ्च
-घ्छ
-घ्ज
-घ्झ
-घ्ञ
-घ्ट
-घ्ठ
-घ्ड
-घ्ढ
-घ्ण
-घ्त
-घ्थ
-घ्द
-घ्ध
-घ्न
-घ्ऩ
-घ्प
-घ्फ
-घ्ब
-घ्भ
-घ्म
-घ्य
-घ्र
-घ्ऱ
-घ्ल
-घ्ळ
-घ्ऴ
-घ्व
-घ्श
-घ्ष
-घ्स
-घ्ह
-ङ्क
-ङ्ख
-ङ्ग
-ङ्घ
-ङ्ङ
-ङ्च
-ङ्छ
-ङ्ज
-ङ्झ
-ङ्ञ
-ङ्ट
-ङ्ठ
-ङ्ड
-ङ्ढ
-ङ्ण
-ङ्त
-ङ्थ
-ङ्द
-ङ्ध
-ङ्न
-ङ्ऩ
-ङ्प
-ङ्फ
-ङ्ब
-ङ्भ
-ङ्म
-ङ्य
-ङ्र
-ङ्ऱ
-ङ्ल
-ङ्ळ
-ङ्ऴ
-ङ्व
-ङ्श
-ङ्ष
-ङ्स
-ङ्ह
-च्क
-च्ख
-च्ग
-च्घ
-च्ङ
-च्च
-च्छ
-च्ज
-च्झ
-च्ञ
-च्ट
-च्ठ
-च्ड
-च्ढ
-च्ण
-च्त
-च्थ
-च्द
-च्ध
-च्न
-च्ऩ
-च्प
-च्फ
-च्ब
-च्भ
-च्म
-च्य
-च्र
-च्ऱ
-च्ल
-च्ळ
-च्ऴ
-च्व
-च्श
-च्ष
-च्स
-च्ह
-छ्क
-छ्ख
-छ्ग
-छ्घ
-छ्ङ
-छ्च
-छ्छ
-छ्ज
-छ्झ
-छ्ञ
-छ्ट
-छ्ठ
-छ्ड
-छ्ढ
-छ्ण
-छ्त
-छ्थ
-छ्द
-छ्ध
-छ्न
-छ्ऩ
-छ्प
-छ्फ
-छ्ब
-छ्भ
-छ्म
-छ्य
-छ्र
-छ्ऱ
-छ्ल
-छ्ळ
-छ्ऴ
-छ्व
-छ्श
-छ्ष
-छ्स
-छ्ह
-ज्क
-ज्ख
-ज्ग
-ज्घ
-ज्ङ
-ज्च
-ज्छ
-ज्ज
-ज्झ
-ज्ञ
-ज्ट
-ज्ठ
-ज्ड
-ज्ढ
-ज्ण
-ज्त
-ज्थ
-ज्द
-ज्ध
-ज्न
-ज्ऩ
-ज्प
-ज्फ
-ज्ब
-ज्भ
-ज्म
-ज्य
-ज्र
-ज्ऱ
-ज्ल
-ज्ळ
-ज्ऴ
-ज्व
-ज्श
-ज्ष
-ज्स
-ज्ह
-झ्क
-झ्ख
-झ्ग
-झ्घ
-झ्ङ
-झ्च
-झ्छ
-झ्ज
-झ्झ
-झ्ञ
-झ्ट
-झ्ठ
-झ्ड
-झ्ढ
-झ्ण
-झ्त
-झ्थ
-झ्द
-झ्ध
-झ्न
-झ्ऩ
-झ्प
-झ्फ
-झ्ब
-झ्भ
-झ्म
-झ्य
-झ्र
-झ्ऱ
-झ्ल
-झ्ळ
-झ्ऴ
-झ्व
-झ्श
-झ्ष
-झ्स
-झ्ह
-ञ्क
-ञ्ख
-ञ्ग
-ञ्घ
-ञ्ङ
-ञ्च
-ञ्छ
-ञ्ज
-ञ्झ
-ञ्ञ
-ञ्ट
-ञ्ठ
-ञ्ड
-ञ्ढ
-ञ्ण
-ञ्त
-ञ्थ
-ञ्द
-ञ्ध
-ञ्न
-ञ्ऩ
-ञ्प
-ञ्फ
-ञ्ब
-ञ्भ
-ञ्म
-ञ्य
-ञ्र
-ञ्ऱ
-ञ्ल
-ञ्ळ
-ञ्ऴ
-ञ्व
-ञ्श
-ञ्ष
-ञ्स
-ञ्ह
-ट्क
-ट्ख
-ट्ग
-ट्घ
-ट्ङ
-ट्च
-ट्छ
-ट्ज
-ट्झ
-ट्ञ
-ट्ट
-ट्ठ
-ट्ड
-ट्ढ
-ट्ण
-ट्त
-ट्थ
-ट्द
-ट्ध
-ट्न
-ट्ऩ
-ट्प
-ट्फ
-ट्ब
-ट्भ
-ट्म
-ट्य
-ट्र
-ट्ऱ
-ट्ल
-ट्ळ
-ट्ऴ
-ट्व
-ट्श
-ट्ष
-ट्स
-ट्ह
-ठ्क
-ठ्ख
-ठ्ग
-ठ्घ
-ठ्ङ
-ठ्च
-ठ्छ
-ठ्ज
-ठ्झ
-ठ्ञ
-ठ्ट
-ठ्ठ
-ठ्ड
-ठ्ढ
-ठ्ण
-ठ्त
-ठ्थ
-ठ्द
-ठ्ध
-ठ्न
-ठ्ऩ
-ठ्प
-ठ्फ
-ठ्ब
-ठ्भ
-ठ्म
-ठ्य
-ठ्र
-ठ्ऱ
-ठ्ल
-ठ्ळ
-ठ्ऴ
-ठ्व
-ठ्श
-ठ्ष
-ठ्स
-ठ्ह
-ड्क
-ड्ख
-ड्ग
-ड्घ
-ड्ङ
-ड्च
-ड्छ
-ड्ज
-ड्झ
-ड्ञ
-ड्ट
-ड्ठ
-ड्ड
-ड्ढ
-ड्ण
-ड्त
-ड्थ
-ड्द
-ड्ध
-ड्न
-ड्ऩ
-ड्प
-ड्फ
-ड्ब
-ड्भ
-ड्म
-ड्य
-ड्र
-ड्ऱ
-ड्ल
-ड्ळ
-ड्ऴ
-ड्व
-ड्श
-ड्ष
-ड्स
-ड्ह
-ढ्क
-ढ्ख
-ढ्ग
-ढ्घ
-ढ्ङ
-ढ्च
-ढ्छ
-ढ्ज
-ढ्झ
-ढ्ञ
-ढ्ट
-ढ्ठ
-ढ्ड
-ढ्ढ
-ढ्ण
-ढ्त
-ढ्थ
-ढ्द
-ढ्ध
-ढ्न
-ढ्ऩ
-ढ्प
-ढ्फ
-ढ्ब
-ढ्भ
-ढ्म
-ढ्य
-ढ्र
-ढ्ऱ
-ढ्ल
-ढ्ळ
-ढ्ऴ
-ढ्व
-ढ्श
-ढ्ष
-ढ्स
-ढ्ह
-ण्क
-ण्ख
-ण्ग
-ण्घ
-ण्ङ
-ण्च
-ण्छ
-ण्ज
-ण्झ
-ण्ञ
-ण्ट
-ण्ठ
-ण्ड
-ण्ढ
-ण्ण
-ण्त
-ण्थ
-ण्द
-ण्ध
-ण्न
-ण्ऩ
-ण्प
-ण्फ
-ण्ब
-ण्भ
-ण्म
-ण्य
-ण्र
-ण्ऱ
-ण्ल
-ण्ळ
-ण्ऴ
-ण्व
-ण्श
-ण्ष
-ण्स
-ण्ह
-त्क
-त्ख
-त्ग
-त्घ
-त्ङ
-त्च
-त्छ
-त्ज
-त्झ
-त्ञ
-त्ट
-त्ठ
-त्ड
-त्ढ
-त्ण
-त्त
-त्थ
-त्द
-त्ध
-त्न
-त्ऩ
-त्प
-त्फ
-त्ब
-त्भ
-त्म
-त्य
-त्र
-त्ऱ
-त्ल
-त्ळ
-त्ऴ
-त्व
-त्श
-त्ष
-त्स
-त्ह
-थ्क
-थ्ख
-थ्ग
-थ्घ
-थ्ङ
-थ्च
-थ्छ
-थ्ज
-थ्झ
-थ्ञ
-थ्ट
-थ्ठ
-थ्ड
-थ्ढ
-थ्ण
-थ्त
-थ्थ
-थ्द
-थ्ध
-थ्न
-थ्ऩ
-थ्प
-थ्फ
-थ्ब
-थ्भ
-थ्म
-थ्य
-थ्र
-थ्ऱ
-थ्ल
-थ्ळ
-थ्ऴ
-थ्व
-थ्श
-थ्ष
-थ्स
-थ्ह
-द्क
-द्ख
-द्ग
-द्घ
-द्ङ
-द्च
-द्छ
-द्ज
-द्झ
-द्ञ
-द्ट
-द्ठ
-द्ड
-द्ढ
-द्ण
-द्त
-द्थ
-द्द
-द्ध
-द्न
-द्ऩ
-द्प
-द्फ
-द्ब
-द्भ
-द्म
-द्य
-द्र
-द्ऱ
-द्ल
-द्ळ
-द्ऴ
-द्व
-द्श
-द्ष
-द्स
-द्ह
-ध्क
-ध्ख
-ध्ग
-ध्घ
-ध्ङ
-ध्च
-ध्छ
-ध्ज
-ध्झ
-ध्ञ
-ध्ट
-ध्ठ
-ध्ड
-ध्ढ
-ध्ण
-ध्त
-ध्थ
-ध्द
-ध्ध
-ध्न
-ध्ऩ
-ध्प
-ध्फ
-ध्ब
-ध्भ
-ध्म
-ध्य
-ध्र
-ध्ऱ
-ध्ल
-ध्ळ
-ध्ऴ
-ध्व
-ध्श
-ध्ष
-ध्स
-ध्ह
-न्क
-न्ख
-न्ग
-न्घ
-न्ङ
-न्च
-न्छ
-न्ज
-न्झ
-न्ञ
-न्ट
-न्ठ
-न्ड
-न्ढ
-न्ण
-न्त
-न्थ
-न्द
-न्ध
-न्न
-न्ऩ
-न्प
-न्फ
-न्ब
-न्भ
-न्म
-न्य
-न्र
-न्ऱ
-न्ल
-न्ळ
-न्ऴ
-न्व
-न्श
-न्ष
-न्स
-न्ह
-ऩ्क
-ऩ्ख
-ऩ्ग
-ऩ्घ
-ऩ्ङ
-ऩ्च
-ऩ्छ
-ऩ्ज
-ऩ्झ
-ऩ्ञ
-ऩ्ट
-ऩ्ठ
-ऩ्ड
-ऩ्ढ
-ऩ्ण
-ऩ्त
-ऩ्थ
-ऩ्द
-ऩ्ध
-ऩ्न
-ऩ्ऩ
-ऩ्प
-ऩ्फ
-ऩ्ब
-ऩ्भ
-ऩ्म
-ऩ्य
-ऩ्र
-ऩ्ऱ
-ऩ्ल
-ऩ्ळ
-ऩ्ऴ
-ऩ्व
-ऩ्श
-ऩ्ष
-ऩ्स
-ऩ्ह
-प्क
-प्ख
-प्ग
-प्घ
-प्ङ
-प्च
-प्छ
-प्ज
-प्झ
-प्ञ
-प्ट
-प्ठ
-प्ड
-प्ढ
-प्ण
-प्त
-प्थ
-प्द
-प्ध
-प्न
-प्ऩ
-प्प
-प्फ
-प्ब
-प्भ
-प्म
-प्य
-प्र
-प्ऱ
-प्ल
-प्ळ
-प्ऴ
-प्व
-प्श
-प्ष
-प्स
-प्ह
-फ्क
-फ्ख
-फ्ग
-फ्घ
-फ्ङ
-फ्च
-फ्छ
-फ्ज
-फ्झ
-फ्ञ
-फ्ट
-फ्ठ
-फ्ड
-फ्ढ
-फ्ण
-फ्त
-फ्थ
-फ्द
-फ्ध
-फ्न
-फ्ऩ
-फ्प
-फ्फ
-फ्ब
-फ्भ
-फ्म
-फ्य
-फ्र
-फ्ऱ
-फ्ल
-फ्ळ
-फ्ऴ
-फ्व
-फ्श
-फ्ष
-फ्स
-फ्ह
-ब्क
-ब्ख
-ब्ग
-ब्घ
-ब्ङ
-ब्च
-ब्छ
-ब्ज
-ब्झ
-ब्ञ
-ब्ट
-ब्ठ
-ब्ड
-ब्ढ
-ब्ण
-ब्त
-ब्थ
-ब्द
-ब्ध
-ब्न
-ब्ऩ
-ब्प
-ब्फ
-ब्ब
-ब्भ
-ब्म
-ब्य
-ब्र
-ब्ऱ
-ब्ल
-ब्ळ
-ब्ऴ
-ब्व
-ब्श
-ब्ष
-ब्स
-ब्ह
-भ्क
-भ्ख
-भ्ग
-भ्घ
-भ्ङ
-भ्च
-भ्छ
-भ्ज
-भ्झ
-भ्ञ
-भ्ट
-भ्ठ
-भ्ड
-भ्ढ
-भ्ण
-भ्त
-भ्थ
-भ्द
-भ्ध
-भ्न
-भ्ऩ
-भ्प
-भ्फ
-भ्ब
-भ्भ
-भ्म
-भ्य
-भ्र
-भ्ऱ
-भ्ल
-भ्ळ
-भ्ऴ
-भ्व
-भ्श
-भ्ष
-भ्स
-भ्ह
-म्क
-म्ख
-म्ग
-म्घ
-म्ङ
-म्च
-म्छ
-म्ज
-म्झ
-म्ञ
-म्ट
-म्ठ
-म्ड
-म्ढ
-म्ण
-म्त
-म्थ
-म्द
-म्ध
-म्न
-म्ऩ
-म्प
-म्फ
-म्ब
-म्भ
-म्म
-म्य
-म्र
-म्ऱ
-म्ल
-म्ळ
-म्ऴ
-म्व
-म्श
-म्ष
-म्स
-म्ह
-य्क
-य्ख
-य्ग
-य्घ
-य्ङ
-य्च
-य्छ
-य्ज
-य्झ
-य्ञ
-य्ट
-य्ठ
-य्ड
-य्ढ
-य्ण
-य्त
-य्थ
-य्द
-य्ध
-य्न
-य्ऩ
-य्प
-य्फ
-य्ब
-य्भ
-य्म
-य्य
-य्र
-य्ऱ
-य्ल
-य्ळ
-य्ऴ
-य्व
-य्श
-य्ष
-य्स
-य्ह
-र्क
-र्ख
-र्ग
-र्घ
-र्ङ
-र्च
-र्छ
-र्ज
-र्झ
-र्ञ
-र्ट
-र्ठ
-र्ड
-र्ढ
-र्ण
-र्त
-र्थ
-र्द
-र्ध
-र्न
-र्ऩ
-र्प
-र्फ
-र्ब
-र्भ
-र्म
-र्य
-र्र
-र्ऱ
-र्ल
-र्ळ
-र्ऴ
-र्व
-र्श
-र्ष
-र्स
-र्ह
-ऱ्क
-ऱ्ख
-ऱ्ग
-ऱ्घ
-ऱ्ङ
-ऱ्च
-ऱ्छ
-ऱ्ज
-ऱ्झ
-ऱ्ञ
-ऱ्ट
-ऱ्ठ
-ऱ्ड
-ऱ्ढ
-ऱ्ण
-ऱ्त
-ऱ्थ
-ऱ्द
-ऱ्ध
-ऱ्न
-ऱ्ऩ
-ऱ्प
-ऱ्फ
-ऱ्ब
-ऱ्भ
-ऱ्म
-ऱ्य
-ऱ्र
-ऱ्ऱ
-ऱ्ल
-ऱ्ळ
-ऱ्ऴ
-ऱ्व
-ऱ्श
-ऱ्ष
-ऱ्स
-ऱ्ह
-ल्क
-ल्ख
-ल्ग
-ल्घ
-ल्ङ
-ल्च
-ल्छ
-ल्ज
-ल्झ
-ल्ञ
-ल्ट
-ल्ठ
-ल्ड
-ल्ढ
-ल्ण
-ल्त
-ल्थ
-ल्द
-ल्ध
-ल्न
-ल्ऩ
-ल्प
-ल्फ
-ल्ब
-ल्भ
-ल्म
-ल्य
-ल्र
-ल्ऱ
-ल्ल
-ल्ळ
-ल्ऴ
-ल्व
-ल्श
-ल्ष
-ल्स
-ल्ह
-ळ्क
-ळ्ख
-ळ्ग
-ळ्घ
-ळ्ङ
-ळ्च
-ळ्छ
-ळ्ज
-ळ्झ
-ळ्ञ
-ळ्ट
-ळ्ठ
-ळ्ड
-ळ्ढ
-ळ्ण
-ळ्त
-ळ्थ
-ळ्द
-ळ्ध
-ळ्न
-ळ्ऩ
-ळ्प
-ळ्फ
-ळ्ब
-ळ्भ
-ळ्म
-ळ्य
-ळ्र
-ळ्ऱ
-ळ्ल
-ळ्ळ
-ळ्ऴ
-ळ्व
-ळ्श
-ळ्ष
-ळ्स
-ळ्ह
-ऴ्क
-ऴ्ख
-ऴ्ग
-ऴ्घ
-ऴ्ङ
-ऴ्च
-ऴ्छ
-ऴ्ज
-ऴ्झ
-ऴ्ञ
-ऴ्ट
-ऴ्ठ
-ऴ्ड
-ऴ्ढ
-ऴ्ण
-ऴ्त
-ऴ्थ
-ऴ्द
-ऴ्ध
-ऴ्न
-ऴ्ऩ
-ऴ्प
-ऴ्फ
-ऴ्ब
-ऴ्भ
-ऴ्म
-ऴ्य
-ऴ्र
-ऴ्ऱ
-ऴ्ल
-ऴ्ळ
-ऴ्ऴ
-ऴ्व
-ऴ्श
-ऴ्ष
-ऴ्स
-ऴ्ह
-व्क
-व्ख
-व्ग
-व्घ
-व्ङ
-व्च
-व्छ
-व्ज
-व्झ
-व्ञ
-व्ट
-व्ठ
-व्ड
-व्ढ
-व्ण
-व्त
-व्थ
-व्द
-व्ध
-व्न
-व्ऩ
-व्प
-व्फ
-व्ब
-व्भ
-व्म
-व्य
-व्र
-व्ऱ
-व्ल
-व्ळ
-व्ऴ
-व्व
-व्श
-व्ष
-व्स
-व्ह
-श्क
-श्ख
-श्ग
-श्घ
-श्ङ
-श्च
-श्छ
-श्ज
-श्झ
-श्ञ
-श्ट
-श्ठ
-श्ड
-श्ढ
-श्ण
-श्त
-श्थ
-श्द
-श्ध
-श्न
-श्ऩ
-श्प
-श्फ
-श्ब
-श्भ
-श्म
-श्य
-श्र
-श्ऱ
-श्ल
-श्ळ
-श्ऴ
-श्व
-श्श
-श्ष
-श्स
-श्ह
-ष्क
-ष्ख
-ष्ग
-ष्घ
-ष्ङ
-ष्च
-ष्छ
-ष्ज
-ष्झ
-ष्ञ
-ष्ट
-ष्ठ
-ष्ड
-ष्ढ
-ष्ण
-ष्त
-ष्थ
-ष्द
-ष्ध
-ष्न
-ष्ऩ
-ष्प
-ष्फ
-ष्ब
-ष्भ
-ष्म
-ष्य
-ष्र
-ष्ऱ
-ष्ल
-ष्ळ
-ष्ऴ
-ष्व
-ष्श
-ष्ष
-ष्स
-ष्ह
-स्क
-स्ख
-स्ग
-स्घ
-स्ङ
-स्च
-स्छ
-स्ज
-स्झ
-स्ञ
-स्ट
-स्ठ
-स्ड
-स्ढ
-स्ण
-स्त
-स्थ
-स्द
-स्ध
-स्न
-स्ऩ
-स्प
-स्फ
-स्ब
-स्भ
-स्म
-स्य
-स्र
-स्ऱ
-स्ल
-स्ळ
-स्ऴ
-स्व
-स्श
-स्ष
-स्स
-स्ह
-ह्क
-ह्ख
-ह्ग
-ह्घ
-ह्ङ
-ह्च
-ह्छ
-ह्ज
-ह्झ
-ह्ञ
-ह्ट
-ह्ठ
-ह्ड
-ह्ढ
-ह्ण
-ह्त
-ह्थ
-ह्द
-ह्ध
-ह्न
-ह्ऩ
-ह्प
-ह्फ
-ह्ब
-ह्भ
-ह्म
-ह्य
-ह्र
-ह्ऱ
-ह्ल
-ह्ळ
-ह्ऴ
-ह्व
-ह्श
-ह्ष
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/gujarati-vowel-letters.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/gujarati-vowel-letters.txt
deleted file mode 100644 (file)
index add4332..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-આ અા
-ઍ અૅ
-એ અે
-ઐ અૈ
-ઑ અૉ
-ઓ અો અાૅ
-ઔ અૌ અાૈ
-ૉ ૅા
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/LICENSE
deleted file mode 100644 (file)
index 2cf8228..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/README
deleted file mode 100644 (file)
index 8bad337..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/SOURCES
deleted file mode 100644 (file)
index 0ed1a89..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
deleted file mode 100644 (file)
index fd5e6e6..0000000
+++ /dev/null
@@ -1 +0,0 @@
-codepoint, imagepath, rawcode, desc
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644 (file)
index e91003a..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-ક
-ખ
-ગ
-ઘ
-ઙ
-ચ
-છ
-જ
-ઝ
-ઞ
-ટ
-ઠ
-ડ
-ઢ
-ણ
-ત
-થ
-દ
-ધ
-ન
-પ
-ફ
-બ
-ભ
-મ
-ય
-ર
-લ
-ળ
-વ
-શ
-ષ
-સ
-હ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644 (file)
index 3650298..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-ા
-િ
-ી
-ુ
-ૂ
-ૃ
-ૅ
-ે
-ૈ
-ૉ
-ો
-ૌ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644 (file)
index eabae39..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-૦
-૧
-૨
-૩
-૪
-૫
-૬
-૭
-૮
-૯
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644 (file)
index 116eb60..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-અ
-આ
-ઇ
-ઈ
-ઉ
-ઊ
-ઋ
-ઍ
-એ
-ઐ
-ઑ
-ઓ
-ઔ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
deleted file mode 100644 (file)
index 66a7ca4..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644 (file)
index 218e507..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-ઁ
-ં
-ઃ
-઼
-ઽ
-્
-ૐ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
deleted file mode 100644 (file)
index f7ff3af..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-કૅ
-ખૅ
-ગૅ
-ઘૅ
-ઙૅ
-ચૅ
-છૅ
-જૅ
-ઝૅ
-ઞૅ
-ટૅ
-ઠૅ
-ડૅ
-ઢૅ
-ણૅ
-તૅ
-થૅ
-દૅ
-ધૅ
-નૅ
-પૅ
-ફૅ
-બૅ
-ભૅ
-મૅ
-યૅ
-રૅ
-લૅ
-ળૅ
-વૅ
-શૅ
-ષૅ
-સૅ
-હૅ
-કે
-ખે
-ગે
-ઘે
-ઙે
-ચે
-છે
-જે
-ઝે
-ઞે
-ટે
-ઠે
-ડે
-ઢે
-ણે
-તે
-થે
-દે
-ધે
-ને
-પે
-ફે
-બે
-ભે
-મે
-યે
-રે
-લે
-ળે
-વે
-શે
-ષે
-સે
-હે
-કૈ
-ખૈ
-ગૈ
-ઘૈ
-ઙૈ
-ચૈ
-છૈ
-જૈ
-ઝૈ
-ઞૈ
-ટૈ
-ઠૈ
-ડૈ
-ઢૈ
-ણૈ
-તૈ
-થૈ
-દૈ
-ધૈ
-નૈ
-પૈ
-ફૈ
-બૈ
-ભૈ
-મૈ
-યૈ
-રૈ
-લૈ
-ળૈ
-વૈ
-શૈ
-ષૈ
-સૈ
-હૈ
-કઁ
-ખઁ
-ગઁ
-ઘઁ
-ઙઁ
-ચઁ
-છઁ
-જઁ
-ઝઁ
-ઞઁ
-ટઁ
-ઠઁ
-ડઁ
-ઢઁ
-ણઁ
-તઁ
-થઁ
-દઁ
-ધઁ
-નઁ
-પઁ
-ફઁ
-બઁ
-ભઁ
-મઁ
-યઁ
-રઁ
-લઁ
-ળઁ
-વઁ
-શઁ
-ષઁ
-સઁ
-હઁ
-કં
-ખં
-ગં
-ઘં
-ઙં
-ચં
-છં
-જં
-ઝં
-ઞં
-ટં
-ઠં
-ડં
-ઢં
-ણં
-તં
-થં
-દં
-ધં
-નં
-પં
-ફં
-બં
-ભં
-મં
-યં
-રં
-લં
-ળં
-વં
-શં
-ષં
-સં
-હં
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
deleted file mode 100644 (file)
index fa658cf..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-કુ
-ખુ
-ગુ
-ઘુ
-ઙુ
-ચુ
-છુ
-જુ
-ઝુ
-ઞુ
-ટુ
-ઠુ
-ડુ
-ઢુ
-ણુ
-તુ
-થુ
-દુ
-ધુ
-નુ
-પુ
-ફુ
-બુ
-ભુ
-મુ
-યુ
-રુ
-લુ
-ળુ
-વુ
-શુ
-ષુ
-સુ
-હુ
-કૂ
-ખૂ
-ગૂ
-ઘૂ
-ઙૂ
-ચૂ
-છૂ
-જૂ
-ઝૂ
-ઞૂ
-ટૂ
-ઠૂ
-ડૂ
-ઢૂ
-ણૂ
-તૂ
-થૂ
-દૂ
-ધૂ
-નૂ
-પૂ
-ફૂ
-બૂ
-ભૂ
-મૂ
-યૂ
-રૂ
-લૂ
-ળૂ
-વૂ
-શૂ
-ષૂ
-સૂ
-હૂ
-કૃ
-ખૃ
-ગૃ
-ઘૃ
-ઙૃ
-ચૃ
-છૃ
-જૃ
-ઝૃ
-ઞૃ
-ટૃ
-ઠૃ
-ડૃ
-ઢૃ
-ણૃ
-તૃ
-થૃ
-દૃ
-ધૃ
-નૃ
-પૃ
-ફૃ
-બૃ
-ભૃ
-મૃ
-યૃ
-રૃ
-લૃ
-ળૃ
-વૃ
-શૃ
-ષૃ
-સૃ
-હૃ
-કૄ
-ખૄ
-ગૄ
-ઘૄ
-ઙૄ
-ચૄ
-છૄ
-જૄ
-ઝૄ
-ઞૄ
-ટૄ
-ઠૄ
-ડૄ
-ઢૄ
-ણૄ
-તૄ
-થૄ
-દૄ
-ધૄ
-નૄ
-પૄ
-ફૄ
-બૄ
-ભૄ
-મૄ
-યૄ
-રૄ
-લૄ
-ળૄ
-વૄ
-શૄ
-ષૄ
-સૄ
-હૄ
-ક્
-ખ્
-ગ્
-ઘ્
-ઙ્
-ચ્
-છ્
-જ્
-ઝ્
-ઞ્
-ટ્
-ઠ્
-ડ્
-ઢ્
-ણ્
-ત્
-થ્
-દ્
-ધ્
-ન્
-પ્
-ફ્
-બ્
-ભ્
-મ્
-ય્
-ર્
-લ્
-ળ્
-વ્
-શ્
-ષ્
-સ્
-હ્
diff --git a/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644 (file)
index 6211c9b..0000000
+++ /dev/null
@@ -1,1156 +0,0 @@
-ક્ક
-ક્ખ
-ક્ગ
-ક્ઘ
-ક્ઙ
-ક્ચ
-ક્છ
-ક્જ
-ક્ઝ
-ક્ઞ
-ક્ટ
-ક્ઠ
-ક્ડ
-ક્ઢ
-ક્ણ
-ક્ત
-ક્થ
-ક્દ
-ક્ધ
-ક્ન
-ક્પ
-ક્ફ
-ક્બ
-ક્ભ
-ક્મ
-ક્ય
-ક્ર
-ક્લ
-ક્ળ
-ક્વ
-ક્શ
-ક્ષ
-ક્સ
-ક્હ
-ખ્ક
-ખ્ખ
-ખ્ગ
-ખ્ઘ
-ખ્ઙ
-ખ્ચ
-ખ્છ
-ખ્જ
-ખ્ઝ
-ખ્ઞ
-ખ્ટ
-ખ્ઠ
-ખ્ડ
-ખ્ઢ
-ખ્ણ
-ખ્ત
-ખ્થ
-ખ્દ
-ખ્ધ
-ખ્ન
-ખ્પ
-ખ્ફ
-ખ્બ
-ખ્ભ
-ખ્મ
-ખ્ય
-ખ્ર
-ખ્લ
-ખ્ળ
-ખ્વ
-ખ્શ
-ખ્ષ
-ખ્સ
-ખ્હ
-ગ્ક
-ગ્ખ
-ગ્ગ
-ગ્ઘ
-ગ્ઙ
-ગ્ચ
-ગ્છ
-ગ્જ
-ગ્ઝ
-ગ્ઞ
-ગ્ટ
-ગ્ઠ
-ગ્ડ
-ગ્ઢ
-ગ્ણ
-ગ્ત
-ગ્થ
-ગ્દ
-ગ્ધ
-ગ્ન
-ગ્પ
-ગ્ફ
-ગ્બ
-ગ્ભ
-ગ્મ
-ગ્ય
-ગ્ર
-ગ્લ
-ગ્ળ
-ગ્વ
-ગ્શ
-ગ્ષ
-ગ્સ
-ગ્હ
-ઘ્ક
-ઘ્ખ
-ઘ્ગ
-ઘ્ઘ
-ઘ્ઙ
-ઘ્ચ
-ઘ્છ
-ઘ્જ
-ઘ્ઝ
-ઘ્ઞ
-ઘ્ટ
-ઘ્ઠ
-ઘ્ડ
-ઘ્ઢ
-ઘ્ણ
-ઘ્ત
-ઘ્થ
-ઘ્દ
-ઘ્ધ
-ઘ્ન
-ઘ્પ
-ઘ્ફ
-ઘ્બ
-ઘ્ભ
-ઘ્મ
-ઘ્ય
-ઘ્ર
-ઘ્લ
-ઘ્ળ
-ઘ્વ
-ઘ્શ
-ઘ્ષ
-ઘ્સ
-ઘ્હ
-ઙ્ક
-ઙ્ખ
-ઙ્ગ
-ઙ્ઘ
-ઙ્ઙ
-ઙ્ચ
-ઙ્છ
-ઙ્જ
-ઙ્ઝ
-ઙ્ઞ
-ઙ્ટ
-ઙ્ઠ
-ઙ્ડ
-ઙ્ઢ
-ઙ્ણ
-ઙ્ત
-ઙ્થ
-ઙ્દ
-ઙ્ધ
-ઙ્ન
-ઙ્પ
-ઙ્ફ
-ઙ્બ
-ઙ્ભ
-ઙ્મ
-ઙ્ય
-ઙ્ર
-ઙ્લ
-ઙ્ળ
-ઙ્વ
-ઙ્શ
-ઙ્ષ
-ઙ્સ
-ઙ્હ
-ચ્ક
-ચ્ખ
-ચ્ગ
-ચ્ઘ
-ચ્ઙ
-ચ્ચ
-ચ્છ
-ચ્જ
-ચ્ઝ
-ચ્ઞ
-ચ્ટ
-ચ્ઠ
-ચ્ડ
-ચ્ઢ
-ચ્ણ
-ચ્ત
-ચ્થ
-ચ્દ
-ચ્ધ
-ચ્ન
-ચ્પ
-ચ્ફ
-ચ્બ
-ચ્ભ
-ચ્મ
-ચ્ય
-ચ્ર
-ચ્લ
-ચ્ળ
-ચ્વ
-ચ્શ
-ચ્ષ
-ચ્સ
-ચ્હ
-છ્ક
-છ્ખ
-છ્ગ
-છ્ઘ
-છ્ઙ
-છ્ચ
-છ્છ
-છ્જ
-છ્ઝ
-છ્ઞ
-છ્ટ
-છ્ઠ
-છ્ડ
-છ્ઢ
-છ્ણ
-છ્ત
-છ્થ
-છ્દ
-છ્ધ
-છ્ન
-છ્પ
-છ્ફ
-છ્બ
-છ્ભ
-છ્મ
-છ્ય
-છ્ર
-છ્લ
-છ્ળ
-છ્વ
-છ્શ
-છ્ષ
-છ્સ
-છ્હ
-જ્ક
-જ્ખ
-જ્ગ
-જ્ઘ
-જ્ઙ
-જ્ચ
-જ્છ
-જ્જ
-જ્ઝ
-જ્ઞ
-જ્ટ
-જ્ઠ
-જ્ડ
-જ્ઢ
-જ્ણ
-જ્ત
-જ્થ
-જ્દ
-જ્ધ
-જ્ન
-જ્પ
-જ્ફ
-જ્બ
-જ્ભ
-જ્મ
-જ્ય
-જ્ર
-જ્લ
-જ્ળ
-જ્વ
-જ્શ
-જ્ષ
-જ્સ
-જ્હ
-ઝ્ક
-ઝ્ખ
-ઝ્ગ
-ઝ્ઘ
-ઝ્ઙ
-ઝ્ચ
-ઝ્છ
-ઝ્જ
-ઝ્ઝ
-ઝ્ઞ
-ઝ્ટ
-ઝ્ઠ
-ઝ્ડ
-ઝ્ઢ
-ઝ્ણ
-ઝ્ત
-ઝ્થ
-ઝ્દ
-ઝ્ધ
-ઝ્ન
-ઝ્પ
-ઝ્ફ
-ઝ્બ
-ઝ્ભ
-ઝ્મ
-ઝ્ય
-ઝ્ર
-ઝ્લ
-ઝ્ળ
-ઝ્વ
-ઝ્શ
-ઝ્ષ
-ઝ્સ
-ઝ્હ
-ઞ્ક
-ઞ્ખ
-ઞ્ગ
-ઞ્ઘ
-ઞ્ઙ
-ઞ્ચ
-ઞ્છ
-ઞ્જ
-ઞ્ઝ
-ઞ્ઞ
-ઞ્ટ
-ઞ્ઠ
-ઞ્ડ
-ઞ્ઢ
-ઞ્ણ
-ઞ્ત
-ઞ્થ
-ઞ્દ
-ઞ્ધ
-ઞ્ન
-ઞ્પ
-ઞ્ફ
-ઞ્બ
-ઞ્ભ
-ઞ્મ
-ઞ્ય
-ઞ્ર
-ઞ્લ
-ઞ્ળ
-ઞ્વ
-ઞ્શ
-ઞ્ષ
-ઞ્સ
-ઞ્હ
-ટ્ક
-ટ્ખ
-ટ્ગ
-ટ્ઘ
-ટ્ઙ
-ટ્ચ
-ટ્છ
-ટ્જ
-ટ્ઝ
-ટ્ઞ
-ટ્ટ
-ટ્ઠ
-ટ્ડ
-ટ્ઢ
-ટ્ણ
-ટ્ત
-ટ્થ
-ટ્દ
-ટ્ધ
-ટ્ન
-ટ્પ
-ટ્ફ
-ટ્બ
-ટ્ભ
-ટ્મ
-ટ્ય
-ટ્ર
-ટ્લ
-ટ્ળ
-ટ્વ
-ટ્શ
-ટ્ષ
-ટ્સ
-ટ્હ
-ઠ્ક
-ઠ્ખ
-ઠ્ગ
-ઠ્ઘ
-ઠ્ઙ
-ઠ્ચ
-ઠ્છ
-ઠ્જ
-ઠ્ઝ
-ઠ્ઞ
-ઠ્ટ
-ઠ્ઠ
-ઠ્ડ
-ઠ્ઢ
-ઠ્ણ
-ઠ્ત
-ઠ્થ
-ઠ્દ
-ઠ્ધ
-ઠ્ન
-ઠ્પ
-ઠ્ફ
-ઠ્બ
-ઠ્ભ
-ઠ્મ
-ઠ્ય
-ઠ્ર
-ઠ્લ
-ઠ્ળ
-ઠ્વ
-ઠ્શ
-ઠ્ષ
-ઠ્સ
-ઠ્હ
-ડ્ક
-ડ્ખ
-ડ્ગ
-ડ્ઘ
-ડ્ઙ
-ડ્ચ
-ડ્છ
-ડ્જ
-ડ્ઝ
-ડ્ઞ
-ડ્ટ
-ડ્ઠ
-ડ્ડ
-ડ્ઢ
-ડ્ણ
-ડ્ત
-ડ્થ
-ડ્દ
-ડ્ધ
-ડ્ન
-ડ્પ
-ડ્ફ
-ડ્બ
-ડ્ભ
-ડ્મ
-ડ્ય
-ડ્ર
-ડ્લ
-ડ્ળ
-ડ્વ
-ડ્શ
-ડ્ષ
-ડ્સ
-ડ્હ
-ઢ્ક
-ઢ્ખ
-ઢ્ગ
-ઢ્ઘ
-ઢ્ઙ
-ઢ્ચ
-ઢ્છ
-ઢ્જ
-ઢ્ઝ
-ઢ્ઞ
-ઢ્ટ
-ઢ્ઠ
-ઢ્ડ
-ઢ્ઢ
-ઢ્ણ
-ઢ્ત
-ઢ્થ
-ઢ્દ
-ઢ્ધ
-ઢ્ન
-ઢ્પ
-ઢ્ફ
-ઢ્બ
-ઢ્ભ
-ઢ્મ
-ઢ્ય
-ઢ્ર
-ઢ્લ
-ઢ્ળ
-ઢ્વ
-ઢ્શ
-ઢ્ષ
-ઢ્સ
-ઢ્હ
-ણ્ક
-ણ્ખ
-ણ્ગ
-ણ્ઘ
-ણ્ઙ
-ણ્ચ
-ણ્છ
-ણ્જ
-ણ્ઝ
-ણ્ઞ
-ણ્ટ
-ણ્ઠ
-ણ્ડ
-ણ્ઢ
-ણ્ણ
-ણ્ત
-ણ્થ
-ણ્દ
-ણ્ધ
-ણ્ન
-ણ્પ
-ણ્ફ
-ણ્બ
-ણ્ભ
-ણ્મ
-ણ્ય
-ણ્ર
-ણ્લ
-ણ્ળ
-ણ્વ
-ણ્શ
-ણ્ષ
-ણ્સ
-ણ્હ
-ત્ક
-ત્ખ
-ત્ગ
-ત્ઘ
-ત્ઙ
-ત્ચ
-ત્છ
-ત્જ
-ત્ઝ
-ત્ઞ
-ત્ટ
-ત્ઠ
-ત્ડ
-ત્ઢ
-ત્ણ
-ત્ત
-ત્થ
-ત્દ
-ત્ધ
-ત્ન
-ત્પ
-ત્ફ
-ત્બ
-ત્ભ
-ત્મ
-ત્ય
-ત્ર
-ત્લ
-ત્ળ
-ત્વ
-ત્શ
-ત્ષ
-ત્સ
-ત્હ
-થ્ક
-થ્ખ
-થ્ગ
-થ્ઘ
-થ્ઙ
-થ્ચ
-થ્છ
-થ્જ
-થ્ઝ
-થ્ઞ
-થ્ટ
-થ્ઠ
-થ્ડ
-થ્ઢ
-થ્ણ
-થ્ત
-થ્થ
-થ્દ
-થ્ધ
-થ્ન
-થ્પ
-થ્ફ
-થ્બ
-થ્ભ
-થ્મ
-થ્ય
-થ્ર
-થ્લ
-થ્ળ
-થ્વ
-થ્શ
-થ્ષ
-થ્સ
-થ્હ
-દ્ક
-દ્ખ
-દ્ગ
-દ્ઘ
-દ્ઙ
-દ્ચ
-દ્છ
-દ્જ
-દ્ઝ
-દ્ઞ
-દ્ટ
-દ્ઠ
-દ્ડ
-દ્ઢ
-દ્ણ
-દ્ત
-દ્થ
-દ્દ
-દ્ધ
-દ્ન
-દ્પ
-દ્ફ
-દ્બ
-દ્ભ
-દ્મ
-દ્ય
-દ્ર
-દ્લ
-દ્ળ
-દ્વ
-દ્શ
-દ્ષ
-દ્સ
-દ્હ
-ધ્ક
-ધ્ખ
-ધ્ગ
-ધ્ઘ
-ધ્ઙ
-ધ્ચ
-ધ્છ
-ધ્જ
-ધ્ઝ
-ધ્ઞ
-ધ્ટ
-ધ્ઠ
-ધ્ડ
-ધ્ઢ
-ધ્ણ
-ધ્ત
-ધ્થ
-ધ્દ
-ધ્ધ
-ધ્ન
-ધ્પ
-ધ્ફ
-ધ્બ
-ધ્ભ
-ધ્મ
-ધ્ય
-ધ્ર
-ધ્લ
-ધ્ળ
-ધ્વ
-ધ્શ
-ધ્ષ
-ધ્સ
-ધ્હ
-ન્ક
-ન્ખ
-ન્ગ
-ન્ઘ
-ન્ઙ
-ન્ચ
-ન્છ
-ન્જ
-ન્ઝ
-ન્ઞ
-ન્ટ
-ન્ઠ
-ન્ડ
-ન્ઢ
-ન્ણ
-ન્ત
-ન્થ
-ન્દ
-ન્ધ
-ન્ન
-ન્પ
-ન્ફ
-ન્બ
-ન્ભ
-ન્મ
-ન્ય
-ન્ર
-ન્લ
-ન્ળ
-ન્વ
-ન્શ
-ન્ષ
-ન્સ
-ન્હ
-પ્ક
-પ્ખ
-પ્ગ
-પ્ઘ
-પ્ઙ
-પ્ચ
-પ્છ
-પ્જ
-પ્ઝ
-પ્ઞ
-પ્ટ
-પ્ઠ
-પ્ડ
-પ્ઢ
-પ્ણ
-પ્ત
-પ્થ
-પ્દ
-પ્ધ
-પ્ન
-પ્પ
-પ્ફ
-પ્બ
-પ્ભ
-પ્મ
-પ્ય
-પ્ર
-પ્લ
-પ્ળ
-પ્વ
-પ્શ
-પ્ષ
-પ્સ
-પ્હ
-ફ્ક
-ફ્ખ
-ફ્ગ
-ફ્ઘ
-ફ્ઙ
-ફ્ચ
-ફ્છ
-ફ્જ
-ફ્ઝ
-ફ્ઞ
-ફ્ટ
-ફ્ઠ
-ફ્ડ
-ફ્ઢ
-ફ્ણ
-ફ્ત
-ફ્થ
-ફ્દ
-ફ્ધ
-ફ્ન
-ફ્પ
-ફ્ફ
-ફ્બ
-ફ્ભ
-ફ્મ
-ફ્ય
-ફ્ર
-ફ્લ
-ફ્ળ
-ફ્વ
-ફ્શ
-ફ્ષ
-ફ્સ
-ફ્હ
-બ્ક
-બ્ખ
-બ્ગ
-બ્ઘ
-બ્ઙ
-બ્ચ
-બ્છ
-બ્જ
-બ્ઝ
-બ્ઞ
-બ્ટ
-બ્ઠ
-બ્ડ
-બ્ઢ
-બ્ણ
-બ્ત
-બ્થ
-બ્દ
-બ્ધ
-બ્ન
-બ્પ
-બ્ફ
-બ્બ
-બ્ભ
-બ્મ
-બ્ય
-બ્ર
-બ્લ
-બ્ળ
-બ્વ
-બ્શ
-બ્ષ
-બ્સ
-બ્હ
-ભ્ક
-ભ્ખ
-ભ્ગ
-ભ્ઘ
-ભ્ઙ
-ભ્ચ
-ભ્છ
-ભ્જ
-ભ્ઝ
-ભ્ઞ
-ભ્ટ
-ભ્ઠ
-ભ્ડ
-ભ્ઢ
-ભ્ણ
-ભ્ત
-ભ્થ
-ભ્દ
-ભ્ધ
-ભ્ન
-ભ્પ
-ભ્ફ
-ભ્બ
-ભ્ભ
-ભ્મ
-ભ્ય
-ભ્ર
-ભ્લ
-ભ્ળ
-ભ્વ
-ભ્શ
-ભ્ષ
-ભ્સ
-ભ્હ
-મ્ક
-મ્ખ
-મ્ગ
-મ્ઘ
-મ્ઙ
-મ્ચ
-મ્છ
-મ્જ
-મ્ઝ
-મ્ઞ
-મ્ટ
-મ્ઠ
-મ્ડ
-મ્ઢ
-મ્ણ
-મ્ત
-મ્થ
-મ્દ
-મ્ધ
-મ્ન
-મ્પ
-મ્ફ
-મ્બ
-મ્ભ
-મ્મ
-મ્ય
-મ્ર
-મ્લ
-મ્ળ
-મ્વ
-મ્શ
-મ્ષ
-મ્સ
-મ્હ
-ય્ક
-ય્ખ
-ય્ગ
-ય્ઘ
-ય્ઙ
-ય્ચ
-ય્છ
-ય્જ
-ય્ઝ
-ય્ઞ
-ય્ટ
-ય્ઠ
-ય્ડ
-ય્ઢ
-ય્ણ
-ય્ત
-ય્થ
-ય્દ
-ય્ધ
-ય્ન
-ય્પ
-ય્ફ
-ય્બ
-ય્ભ
-ય્મ
-ય્ય
-ય્ર
-ય્લ
-ય્ળ
-ય્વ
-ય્શ
-ય્ષ
-ય્સ
-ય્હ
-ર્ક
-ર્ખ
-ર્ગ
-ર્ઘ
-ર્ઙ
-ર્ચ
-ર્છ
-ર્જ
-ર્ઝ
-ર્ઞ
-ર્ટ
-ર્ઠ
-ર્ડ
-ર્ઢ
-ર્ણ
-ર્ત
-ર્થ
-ર્દ
-ર્ધ
-ર્ન
-ર્પ
-ર્ફ
-ર્બ
-ર્ભ
-ર્મ
-ર્ય
-ર્ર
-ર્લ
-ર્ળ
-ર્વ
-ર્શ
-ર્ષ
-ર્સ
-ર્હ
-લ્ક
-લ્ખ
-લ્ગ
-લ્ઘ
-લ્ઙ
-લ્ચ
-લ્છ
-લ્જ
-લ્ઝ
-લ્ઞ
-લ્ટ
-લ્ઠ
-લ્ડ
-લ્ઢ
-લ્ણ
-લ્ત
-લ્થ
-લ્દ
-લ્ધ
-લ્ન
-લ્પ
-લ્ફ
-લ્બ
-લ્ભ
-લ્મ
-લ્ય
-લ્ર
-લ્લ
-લ્ળ
-લ્વ
-લ્શ
-લ્ષ
-લ્સ
-લ્હ
-ળ્ક
-ળ્ખ
-ળ્ગ
-ળ્ઘ
-ળ્ઙ
-ળ્ચ
-ળ્છ
-ળ્જ
-ળ્ઝ
-ળ્ઞ
-ળ્ટ
-ળ્ઠ
-ળ્ડ
-ળ્ઢ
-ળ્ણ
-ળ્ત
-ળ્થ
-ળ્દ
-ળ્ધ
-ળ્ન
-ળ્પ
-ળ્ફ
-ળ્બ
-ળ્ભ
-ળ્મ
-ળ્ય
-ળ્ર
-ળ્લ
-ળ્ળ
-ળ્વ
-ળ્શ
-ળ્ષ
-ળ્સ
-ળ્હ
-વ્ક
-વ્ખ
-વ્ગ
-વ્ઘ
-વ્ઙ
-વ્ચ
-વ્છ
-વ્જ
-વ્ઝ
-વ્ઞ
-વ્ટ
-વ્ઠ
-વ્ડ
-વ્ઢ
-વ્ણ
-વ્ત
-વ્થ
-વ્દ
-વ્ધ
-વ્ન
-વ્પ
-વ્ફ
-વ્બ
-વ્ભ
-વ્મ
-વ્ય
-વ્ર
-વ્લ
-વ્ળ
-વ્વ
-વ્શ
-વ્ષ
-વ્સ
-વ્હ
-શ્ક
-શ્ખ
-શ્ગ
-શ્ઘ
-શ્ઙ
-શ્ચ
-શ્છ
-શ્જ
-શ્ઝ
-શ્ઞ
-શ્ટ
-શ્ઠ
-શ્ડ
-શ્ઢ
-શ્ણ
-શ્ત
-શ્થ
-શ્દ
-શ્ધ
-શ્ન
-શ્પ
-શ્ફ
-શ્બ
-શ્ભ
-શ્મ
-શ્ય
-શ્ર
-શ્લ
-શ્ળ
-શ્વ
-શ્શ
-શ્ષ
-શ્સ
-શ્હ
-ષ્ક
-ષ્ખ
-ષ્ગ
-ષ્ઘ
-ષ્ઙ
-ષ્ચ
-ષ્છ
-ષ્જ
-ષ્ઝ
-ષ્ઞ
-ષ્ટ
-ષ્ઠ
-ષ્ડ
-ષ્ઢ
-ષ્ણ
-ષ્ત
-ષ્થ
-ષ્દ
-ષ્ધ
-ષ્ન
-ષ્પ
-ષ્ફ
-ષ્બ
-ષ્ભ
-ષ્મ
-ષ્ય
-ષ્ર
-ષ્લ
-ષ્ળ
-ષ્વ
-ષ્શ
-ષ્ષ
-ષ્સ
-ષ્હ
-સ્ક
-સ્ખ
-સ્ગ
-સ્ઘ
-સ્ઙ
-સ્ચ
-સ્છ
-સ્જ
-સ્ઝ
-સ્ઞ
-સ્ટ
-સ્ઠ
-સ્ડ
-સ્ઢ
-સ્ણ
-સ્ત
-સ્થ
-સ્દ
-સ્ધ
-સ્ન
-સ્પ
-સ્ફ
-સ્બ
-સ્ભ
-સ્મ
-સ્ય
-સ્ર
-સ્લ
-સ્ળ
-સ્વ
-સ્શ
-સ્ષ
-સ્સ
-સ્હ
-હ્ક
-હ્ખ
-હ્ગ
-હ્ઘ
-હ્ઙ
-હ્ચ
-હ્છ
-હ્જ
-હ્ઝ
-હ્ઞ
-હ્ટ
-હ્ઠ
-હ્ડ
-હ્ઢ
-હ્ણ
-હ્ત
-હ્થ
-હ્દ
-હ્ધ
-હ્ન
-હ્પ
-હ્ફ
-હ્બ
-હ્ભ
-હ્મ
-હ્ય
-હ્ર
-હ્લ
-હ્ળ
-હ્વ
-હ્શ
-હ્ષ
-હ્સ
-હ્હ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/gurmukhi-vowel-letters.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/gurmukhi-vowel-letters.txt
deleted file mode 100644 (file)
index b2adaab..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-ਆ ਅਾ
-ਇ ੲਿ
-ਈ ੲੀ
-ਉ ੳੁ
-ਊ ੳੂ
-ਏ ੲੇ
-ਐ ਅੈ
-ਓ ੳੋ
-ਔ ਅੌ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/misc/misc.txt
deleted file mode 100644 (file)
index 27a39f6..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-ਕ੍ਹ
-ਤ੍ਯੋ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/LICENSE
deleted file mode 100644 (file)
index 2cf8228..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/README
deleted file mode 100644 (file)
index 8bad337..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/SOURCES
deleted file mode 100644 (file)
index 0ed1a89..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644 (file)
index ee8b3be..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-ਕ
-ਖ
-ਗ
-ਘ
-ਙ
-ਚ
-ਛ
-ਜ
-ਝ
-ਞ
-ਟ
-ਠ
-ਡ
-ਢ
-ਣ
-ਤ
-ਥ
-ਦ
-ਧ
-ਨ
-ਪ
-ਫ
-ਬ
-ਭ
-ਮ
-ਯ
-ਰ
-ਲ
-ਲ਼
-ਵ
-ਸ਼
-ਸ
-ਹ
-ਖ਼
-ਗ਼
-ਜ਼
-ੜ
-ਫ਼
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644 (file)
index a934caa..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-ਾ
-ਿ
-ੀ
-ੁ
-ੂ
-ੇ
-ੈ
-ੋ
-ੌ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644 (file)
index d08b7a8..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-੦
-੧
-੨
-੩
-੪
-੫
-੬
-੭
-੮
-੯
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-GurmukhiSpecific.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-GurmukhiSpecific.txt
deleted file mode 100644 (file)
index 8565c88..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-ੰ
-ੱ
-ੲ
-ੳ
-ੴ
-ੵ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644 (file)
index 05827ca..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-ਅ
-ਆ
-ਇ
-ਈ
-ਉ
-ਊ
-ਏ
-ਐ
-ਓ
-ਔ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
deleted file mode 100644 (file)
index 66a7ca4..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644 (file)
index adb725e..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-ਁ
-ਂ
-ਃ
-਼
-੍
-ੑ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
deleted file mode 100644 (file)
index 7fdf6e4..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-ਉਂ
-ਊਂ
-ਏਂ
-ਐਂ
-ਓਂ
-ਔਂ
-ਠਂ
-ਠੇ
-ਠੈ
-ਠੋ
-ਠੌ
-ਠੰ
-ਨਂ
-ਨੇ
-ਨੈ
-ਨੋ
-ਨੌ
-ਨੰ
-ਠੱ
-ਨੱ
-ਲੱ
-ਲ਼ੱ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
deleted file mode 100644 (file)
index 63d54a5..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-ੳ
-ੲ
diff --git a/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644 (file)
index eb2e8ee..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-ਕ੍ਯ
-ਖ੍ਯ
-ਗ੍ਯ
-ਘ੍ਯ
-ਙ੍ਯ
-ਚ੍ਯ
-ਛ੍ਯ
-ਜ੍ਯ
-ਝ੍ਯ
-ਞ੍ਯ
-ਟ੍ਯ
-ਠ੍ਯ
-ਡ੍ਯ
-ਢ੍ਯ
-ਣ੍ਯ
-ਤ੍ਯ
-ਥ੍ਯ
-ਦ੍ਯ
-ਧ੍ਯ
-ਨ੍ਯ
-ਪ੍ਯ
-ਫ੍ਯ
-ਬ੍ਯ
-ਭ੍ਯ
-ਮ੍ਯ
-ਯ੍ਯ
-ਰ੍ਯ
-ਲ੍ਯ
-ਲ਼੍ਯ
-ਵ੍ਯ
-ਸ਼੍ਯ
-ਸ੍ਯ
-ਹ੍ਯ
-ਖ਼੍ਯ
-ਗ਼੍ਯ
-ਜ਼੍ਯ
-ੜ੍ਯ
-ਫ਼੍ਯ
-ਕ੍ਰ
-ਖ੍ਰ
-ਗ੍ਰ
-ਘ੍ਰ
-ਙ੍ਰ
-ਚ੍ਰ
-ਛ੍ਰ
-ਜ੍ਰ
-ਝ੍ਰ
-ਞ੍ਰ
-ਟ੍ਰ
-ਠ੍ਰ
-ਡ੍ਰ
-ਢ੍ਰ
-ਣ੍ਰ
-ਤ੍ਰ
-ਥ੍ਰ
-ਦ੍ਰ
-ਧ੍ਰ
-ਨ੍ਰ
-ਪ੍ਰ
-ਫ੍ਰ
-ਬ੍ਰ
-ਭ੍ਰ
-ਮ੍ਰ
-ਯ੍ਰ
-ਰ੍ਰ
-ਲ੍ਰ
-ਲ਼੍ਰ
-ਵ੍ਰ
-ਸ਼੍ਰ
-ਸ੍ਰ
-ਹ੍ਰ
-ਖ਼੍ਰ
-ਗ਼੍ਰ
-ਜ਼੍ਰ
-ੜ੍ਰ
-ਫ਼੍ਰ
-ਕ੍ਵ
-ਖ੍ਵ
-ਗ੍ਵ
-ਘ੍ਵ
-ਙ੍ਵ
-ਚ੍ਵ
-ਛ੍ਵ
-ਜ੍ਵ
-ਝ੍ਵ
-ਞ੍ਵ
-ਟ੍ਵ
-ਠ੍ਵ
-ਡ੍ਵ
-ਢ੍ਵ
-ਣ੍ਵ
-ਤ੍ਵ
-ਥ੍ਵ
-ਦ੍ਵ
-ਧ੍ਵ
-ਨ੍ਵ
-ਪ੍ਵ
-ਫ੍ਵ
-ਬ੍ਵ
-ਭ੍ਵ
-ਮ੍ਵ
-ਯ੍ਵ
-ਰ੍ਵ
-ਲ੍ਵ
-ਲ਼੍ਵ
-ਵ੍ਵ
-ਸ਼੍ਵ
-ਸ੍ਵ
-ਹ੍ਵ
-ਖ਼੍ਵ
-ਗ਼੍ਵ
-ਜ਼੍ਵ
-ੜ੍ਵ
-ਫ਼੍ਵ
-ਕ੍ਹ
-ਖ੍ਹ
-ਗ੍ਹ
-ਘ੍ਹ
-ਙ੍ਹ
-ਚ੍ਹ
-ਛ੍ਹ
-ਜ੍ਹ
-ਝ੍ਹ
-ਞ੍ਹ
-ਟ੍ਹ
-ਠ੍ਹ
-ਡ੍ਹ
-ਢ੍ਹ
-ਣ੍ਹ
-ਤ੍ਹ
-ਥ੍ਹ
-ਦ੍ਹ
-ਧ੍ਹ
-ਨ੍ਹ
-ਪ੍ਹ
-ਫ੍ਹ
-ਬ੍ਹ
-ਭ੍ਹ
-ਮ੍ਹ
-ਯ੍ਹ
-ਰ੍ਹ
-ਲ੍ਹ
-ਲ਼੍ਹ
-ਵ੍ਹ
-ਸ਼੍ਹ
-ਸ੍ਹ
-ਹ੍ਹ
-ਖ਼੍ਹ
-ਗ਼੍ਹ
-ਜ਼੍ਹ
-ੜ੍ਹ
-ਫ਼੍ਹ
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/kannada-vowel-letters.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/kannada-vowel-letters.txt
deleted file mode 100644 (file)
index cc05db9..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-ಊ ಉಾ
-ಔ ಒೌ
-ೠ ಋಾ
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/misc/misc.txt
deleted file mode 100644 (file)
index a8a6325..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-ಕ್ರ
-ನ್ಡ
-ನ್ನ
-ಯೂ
-ರ್ಕ
-ರ್ಮ
-ರ್‍ಕ
-ವೋ
-ಷೆ
-ಷ್
-ೠ
-೦೧೨
-ಕೀ
-ಕೊ
-ಕೇ
-ಕೈ
-ಕೋ
-ಕ್ಷ
-ಕ್ಷಿ
-ಚ್ಚ್
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/misc/right-matras.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/misc/right-matras.txt
deleted file mode 100644 (file)
index 3130f35..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-ಸ್ಕು
-ಸ್ಕೂ
-ಸ್ಕೃ
-ಸ್ಕೄ
-ಸ್ಕಾ
-ಸ್ಕೕ
-ಸ್ಕೕ
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/LICENSE
deleted file mode 100644 (file)
index 2cf8228..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/README
deleted file mode 100644 (file)
index 8bad337..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/SOURCES
deleted file mode 100644 (file)
index 0ed1a89..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt
deleted file mode 100644 (file)
index fff748a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-ೞ
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
deleted file mode 100644 (file)
index f641547..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-ೠ
-ೡ
-ೢ
-ೣ
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644 (file)
index 650cbf7..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-ಕ
-ಖ
-ಗ
-ಘ
-ಙ
-ಚ
-ಛ
-ಜ
-ಝ
-ಞ
-ಟ
-ಠ
-ಡ
-ಢ
-ಣ
-ತ
-ಥ
-ದ
-ಧ
-ನ
-ಪ
-ಫ
-ಬ
-ಭ
-ಮ
-ಯ
-ರ
-ಱ
-ಲ
-ಳ
-ವ
-ಶ
-ಷ
-ಸ
-ಹ
-ಂ
-ಃ
-಼
-ಽ
-್
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644 (file)
index 476f39f..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-ಾ
-ಿ
-ೀ
-ು
-ೂ
-ೃ
-ೄ
-ೆ
-ೇ
-ೈ
-ೊ
-ೋ
-ೌ
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644 (file)
index 57ac088..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-೦
-೧
-೨
-೩
-೪
-೫
-೬
-೭
-೮
-೯
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644 (file)
index 38f1719..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-ಅ
-ಆ
-ಇ
-ಈ
-ಉ
-ಊ
-ಋ
-ಌ
-ಎ
-ಏ
-ಐ
-ಒ
-ಓ
-ಔ
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
deleted file mode 100644 (file)
index 66a7ca4..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644 (file)
index 6bbf23e..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-ಂ
-ಃ
-಼
-ಽ
-್
-ೕ
-ೖ
-ೱ
-ೲ
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
deleted file mode 100644 (file)
index 4cc0f56..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-ಕಾ
-ಖಾ
-ಗಾ
-ಠಾ
-ಡಾ
-ಛಾ
-ಕಿ
-ಖಿ
-ಗಿ
-ಘಿ
-ಙಿ
-ಚಿ
-ಛಿ
-ಜಿ
-ಝಿ
-ಞಿ
-ಟಿ
-ಠಿ
-ಡಿ
-ಢಿ
-ಣಿ
-ತಿ
-ಥಿ
-ದಿ
-ಧಿ
-ನಿ
-ಪಿ
-ಫಿ
-ಬಿ
-ಭಿ
-ಮಿ
-ಯಿ
-ರಿ
-ಱಿ
-ಲಿ
-ಳಿ
-ವಿ
-ಶಿ
-ಷಿ
-ಸಿ
-ಹಿ
-ಕು
-ಗು
-ಜು
-ಟು
-ತು
-ಖು
-ಕೂ
-ಖೂ
-ಗೂ
-ಟೂ
-ಚೂ
-ಛೂ
-ಕೄ
-ಗೄ
-ಜೄ
-ಟೄ
-ತೄ
-ಖೄ
-ಕೇ
-ಗೇ
-ಜೇ
-ಟೇ
-ತೇ
-ಖೇ
-ಕೈ
-ಗೈ
-ಜೈ
-ಟೈ
-ತೈ
-ಖೈ
-ಕೊ
-ಗೊ
-ಜೊ
-ಟೊ
-ತೊ
-ಖೊ
-ಕೋ
-ಗೋ
-ಜೋ
-ಟೋ
-ತೋ
-ಖೋ
-ಕೆ
-ಖೆ
-ಗೆ
-ಘೆ
-ಙೆ
-ಚೆ
-ಛೆ
-ಜೆ
-ಝೆ
-ಞೆ
-ಟೆ
-ಠೆ
-ಡೆ
-ಢೆ
-ಣೆ
-ತೆ
-ಥೆ
-ದೆ
-ಧೆ
-ನೆ
-ಪೆ
-ಫೆ
-ಬೆ
-ಭೆ
-ಮೆ
-ಯೆ
-ರೆ
-ಱೆ
-ಲೆ
-ಳೆ
-ವೆ
-ಶೆ
-ಷೆ
-ಸೆ
-ಹೆ
-ಕೌ
-ಖೌ
-ಗೌ
-ಘೌ
-ಙೌ
-ಚೌ
-ಛೌ
-ಜೌ
-ಝೌ
-ಞೌ
-ಟೌ
-ಠೌ
-ಡೌ
-ಢೌ
-ಣೌ
-ತೌ
-ಥೌ
-ದೌ
-ಧೌ
-ನೌ
-ಪೌ
-ಫೌ
-ಬೌ
-ಭೌ
-ಮೌ
-ಯೌ
-ರೌ
-ಱೌ
-ಲೌ
-ಳೌ
-ವೌ
-ಶೌ
-ಷೌ
-ಸೌ
-ಹೌ
-ಕ್
-ಖ್
-ಗ್
-ಘ್
-ಙ್
-ಚ್
-ಛ್
-ಜ್
-ಝ್
-ಞ್
-ಟ್
-ಠ್
-ಡ್
-ಢ್
-ಣ್
-ತ್
-ಥ್
-ದ್
-ಧ್
-ನ್
-ಪ್
-ಫ್
-ಬ್
-ಭ್
-ಮ್
-ಯ್
-ರ್
-ಱ್
-ಲ್
-ಳ್
-ವ್
-ಶ್
-ಷ್
-ಸ್
-ಹ್
diff --git a/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644 (file)
index 583072d..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-ಕ್ಕ
-ಕ್ಖ
-ಕ್ಗ
-ಕ್ಘ
-ಕ್ಙ
-ಕ್ಚ
-ಕ್ಛ
-ಕ್ಜ
-ಕ್ಝ
-ಕ್ಞ
-ಕ್ಟ
-ಕ್ಠ
-ಕ್ಡ
-ಕ್ಢ
-ಕ್ಣ
-ಕ್ತ
-ಕ್ಥ
-ಕ್ದ
-ಕ್ಧ
-ಕ್ನ
-ಕ್ಪ
-ಕ್ಫ
-ಕ್ಬ
-ಕ್ಭ
-ಕ್ಮ
-ಕ್ಯ
-ಕ್ರ
-ಕ್ಲ
-ಕ್ಳ
-ಕ್ವ
-ಕ್ಶ
-ಕ್ಷ
-ಕ್ಸ
-ಕ್ಹ
-ತ್ಕ
-ತ್ಖ
-ತ್ಗ
-ತ್ಘ
-ತ್ಙ
-ತ್ಚ
-ತ್ಛ
-ತ್ಜ
-ತ್ಝ
-ತ್ಞ
-ತ್ಟ
-ತ್ಠ
-ತ್ಡ
-ತ್ಢ
-ತ್ಣ
-ತ್ತ
-ತ್ಥ
-ತ್ದ
-ತ್ಧ
-ತ್ನ
-ತ್ಪ
-ತ್ಫ
-ತ್ಬ
-ತ್ಭ
-ತ್ಮ
-ತ್ಯ
-ತ್ರ
-ತ್ಲ
-ತ್ಳ
-ತ್ವ
-ತ್ಶ
-ತ್ಷ
-ತ್ಸ
-ತ್ಹ
-ನ್ಕ
-ನ್ಖ
-ನ್ಗ
-ನ್ಘ
-ನ್ಙ
-ನ್ಚ
-ನ್ಛ
-ನ್ಜ
-ನ್ಝ
-ನ್ಞ
-ನ್ಟ
-ನ್ಠ
-ನ್ಡ
-ನ್ಢ
-ನ್ಣ
-ನ್ತ
-ನ್ಥ
-ನ್ದ
-ನ್ಧ
-ನ್ನ
-ನ್ಪ
-ನ್ಫ
-ನ್ಬ
-ನ್ಭ
-ನ್ಮ
-ನ್ಯ
-ನ್ರ
-ನ್ಲ
-ನ್ಳ
-ನ್ವ
-ನ್ಶ
-ನ್ಷ
-ನ್ಸ
-ನ್ಹ
-ಮ್ಕ
-ಮ್ಖ
-ಮ್ಗ
-ಮ್ಘ
-ಮ್ಙ
-ಮ್ಚ
-ಮ್ಛ
-ಮ್ಜ
-ಮ್ಝ
-ಮ್ಞ
-ಮ್ಟ
-ಮ್ಠ
-ಮ್ಡ
-ಮ್ಢ
-ಮ್ಣ
-ಮ್ತ
-ಮ್ಥ
-ಮ್ದ
-ಮ್ಧ
-ಮ್ನ
-ಮ್ಪ
-ಮ್ಫ
-ಮ್ಬ
-ಮ್ಭ
-ಮ್ಮ
-ಮ್ಯ
-ಮ್ರ
-ಮ್ಲ
-ಮ್ಳ
-ಮ್ವ
-ಮ್ಶ
-ಮ್ಷ
-ಮ್ಸ
-ಮ್ಹ
-ಯ್ಕ
-ಯ್ಖ
-ಯ್ಗ
-ಯ್ಘ
-ಯ್ಙ
-ಯ್ಚ
-ಯ್ಛ
-ಯ್ಜ
-ಯ್ಝ
-ಯ್ಞ
-ಯ್ಟ
-ಯ್ಠ
-ಯ್ಡ
-ಯ್ಢ
-ಯ್ಣ
-ಯ್ತ
-ಯ್ಥ
-ಯ್ದ
-ಯ್ಧ
-ಯ್ನ
-ಯ್ಪ
-ಯ್ಫ
-ಯ್ಬ
-ಯ್ಭ
-ಯ್ಮ
-ಯ್ಯ
-ಯ್ರ
-ಯ್ಲ
-ಯ್ಳ
-ಯ್ವ
-ಯ್ಶ
-ಯ್ಷ
-ಯ್ಸ
-ಯ್ಹ
-ರ್ಕ
-ರ್ಖ
-ರ್ಗ
-ರ್ಘ
-ರ್ಙ
-ರ್ಚ
-ರ್ಛ
-ರ್ಜ
-ರ್ಝ
-ರ್ಞ
-ರ್ಟ
-ರ್ಠ
-ರ್ಡ
-ರ್ಢ
-ರ್ಣ
-ರ್ತ
-ರ್ಥ
-ರ್ದ
-ರ್ಧ
-ರ್ನ
-ರ್ಪ
-ರ್ಫ
-ರ್ಬ
-ರ್ಭ
-ರ್ಮ
-ರ್ಯ
-ರ್ರ
-ರ್ಲ
-ರ್ಳ
-ರ್ವ
-ರ್ಶ
-ರ್ಷ
-ರ್ಸ
-ರ್ಹ
-ರ್ಕ
-ರ್ಖ
-ರ್ಗ
-ರ್ಘ
-ರ್ಙ
-ರ್ಚ
-ರ್ಛ
-ರ್ಜ
-ರ್ಝ
-ರ್ಞ
-ರ್ಟ
-ರ್ಠ
-ರ್ಡ
-ರ್ಢ
-ರ್ಣ
-ರ್ತ
-ರ್ಥ
-ರ್ದ
-ರ್ಧ
-ರ್ನ
-ರ್ಪ
-ರ್ಫ
-ರ್ಬ
-ರ್ಭ
-ರ್ಮ
-ರ್ಯ
-ರ್ರ
-ರ್ಲ
-ರ್ಳ
-ರ್ವ
-ರ್ಶ
-ರ್ಷ
-ರ್ಸ
-ರ್ಹ
-ಲ್ಕ
-ಲ್ಖ
-ಲ್ಗ
-ಲ್ಘ
-ಲ್ಙ
-ಲ್ಚ
-ಲ್ಛ
-ಲ್ಜ
-ಲ್ಝ
-ಲ್ಞ
-ಲ್ಟ
-ಲ್ಠ
-ಲ್ಡ
-ಲ್ಢ
-ಲ್ಣ
-ಲ್ತ
-ಲ್ಥ
-ಲ್ದ
-ಲ್ಧ
-ಲ್ನ
-ಲ್ಪ
-ಲ್ಫ
-ಲ್ಬ
-ಲ್ಭ
-ಲ್ಮ
-ಲ್ಯ
-ಲ್ರ
-ಲ್ಲ
-ಲ್ಳ
-ಲ್ವ
-ಲ್ಶ
-ಲ್ಷ
-ಲ್ಸ
-ಲ್ಹ
-ವ್ಕ
-ವ್ಖ
-ವ್ಗ
-ವ್ಘ
-ವ್ಙ
-ವ್ಚ
-ವ್ಛ
-ವ್ಜ
-ವ್ಝ
-ವ್ಞ
-ವ್ಟ
-ವ್ಠ
-ವ್ಡ
-ವ್ಢ
-ವ್ಣ
-ವ್ತ
-ವ್ಥ
-ವ್ದ
-ವ್ಧ
-ವ್ನ
-ವ್ಪ
-ವ್ಫ
-ವ್ಬ
-ವ್ಭ
-ವ್ಮ
-ವ್ಯ
-ವ್ರ
-ವ್ಲ
-ವ್ಳ
-ವ್ವ
-ವ್ಶ
-ವ್ಷ
-ವ್ಸ
-ವ್ಹ
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/malayalam-vowel-letters.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/malayalam-vowel-letters.txt
deleted file mode 100644 (file)
index 061c642..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-ഈ ഇൗ
-ഊ ഉൗ
-ഐ എെ
-ഓ ഒാ
-ഔ ഒൗ
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/misc/cibu.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/misc/cibu.txt
deleted file mode 100644 (file)
index 3d53867..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-2ാം
-2-ാം
-ല്ം
-എ്ന
-9-൹
-₹100
-൦
-൧
-൨
-൩
-൪
-൫
-൬
-൭
-൮
-൯
-൰
-൱
-൲
-൳
-൴
-൵
-അങ്ങ്
-അത്
-അർത്ഥം
-അന്ധൻ
-അന്യം
-അന്വയം
-അൽപ്പം
-അമ്മ
-അമ്ലം
-അല്പം
-അല
-അവൻ
-അവന്
-അവനു്
-അസോഽസൗ
-അഹല്യ
-അഺ്
-ആമ്പിൿ
-ആല
-ആാ
-ആാാാ
-ഇൻക
-ഇല്ല
-ഇല
-ഇള
-ഇഴ
-ഈറ
-ഈൗ
-ഉമ
-ഉള്ള
-ഊമ
-ഊൗ
-ഋതു
-ൠന്ന്
-ഌകാരം
-ൡതം
-എന്ന
-എന്റെ
-എലി
-എൻറോൾ
-ഏലം
-ഐക്യം
-ഒരു
-ഓരം
-ഓാാാ
-ഔഷധം
-ഔൗ
-കണ്ഢം
-കണ്ണ്
-കണ്വൻ
-കഥ
-കമ്പം
-കമ്രം
-കല്മഷം
-കല
-കാാ
-കീീ
-കുണ്ഠിതം
-കൂൂ
-കൄന്ന്
-കൢപ്തം
-കൣതം
-കൌതുകം
-ക്രൌഞ്ചം
-ഗങ്ഗ
-ഗരം
-ങഞ
-അച്ഛൻ
-ങ്യാവൂ
-ചരം
-ഛായ
-ജലം
-ജാള്യം
-ഝാൻസി
-ഞാൻ
-ടിപ്പു
-ഡപ്പി
-തത്ത
-തെരഞ്ഞെടുപ്പിന്‍െറ
-ദയ
-ദുഃഖം
-ദൃഢം
-ധനം
-നഖം
-നന്ദി
-നന്ന്
-നന്മ
-നാണ്യം
-തന്ത
-ന്രസ്ഥി
-പച്ച
-പട്ട
-പണ്ടു്
-പല
-പറ
-പാഠം
-പാണ്ഡു
-പാണ്ഡ്യൻ
-പാന്ഥൻ
-പാറ്റ
-പിന്നെ
-പുച്ഛം
-പുഞ്ച
-പൊൻനാണ്യം
-ഫലം
-ബലം
-ഭയം
-ഭാൎയ്യ
-ഭാര്യ
-മങ്ക
-മണം
-മണ്ട
-മ്അദനി
-മയം
-മേഘം
-മോഹന്‍ലാല്‍
-യതി
-രണ്ട്
-രമ്യം
-ലത
-അറബ്‌ബസ്സാർ
-ലോക്‌സഭ
-വഅള്
-വരം
-വാഞ്ഛ
-വില്വാദ്രി
-വെണ്മ
-ഷാരം
-ശ്രുതി
-ശരം
-ശാർങ്ഗപക്ഷി
-സമ്യക്
-സംയോഗം
-സംരംഭം
-സമ്രാട്ട്
-സസ്യം
-സാരം
-സ്രാവം
-സ്ലാവിക്
-സ്വരം
-സ്വാതന്ത്ര്യം
-സ്ട്രാപ്പ്
-സ്റ്റിംഗ്
-സ്റ്റ്രീം
-ഹാരം
-റിപ്പോര്‍ട്ട്
-  ന്‍റെ
-ന്റെ
-ൻ്റെ
-ച്ച്യൂ
-യ്ക്ക്യൂ
-ട്ട്യൂ
-യ‍്യ
-വ‍്വ
-ഹൈലൈറ്റ്സ്
- ച്ല്‍സി
-മലയാളത്തില്‍
-ഡിപ്പാർട്ട്മെന്റിന്റെ
-യ്യ്ര
- യ്യ്ര
- ്യ്ര
- ്യ്യ്ര
-വ്വ്ര
- വ്വ്ര
- ്വ്ര
- ്വ്വ്ര
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/misc/dot-reph.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/misc/dot-reph.txt
deleted file mode 100644 (file)
index fc74da9..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-ൎക
-ൎക്ക്ര
-ൎന്ന
-ൎഗ്ഗ്രോ
-ൎഗ്രോ
-ൎഗോ
-ൎഗ
-ഗ്ഗ്രോ
-ഗ്ഗ്ര
-ഗ്ഗോ
-ഗ്ഗ
-ഗ്രോ
-ൎകു
-ൎക്കു
-ൎച്ച്
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/misc/misc.txt
deleted file mode 100644 (file)
index 2e732ae..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-അൎത്ഥം
-അഥൎവ്വം
-ക്‍
-കായ്‌കറി
-കാര്‍ക്കോടകന്‍
-കുറ്റ്യാടി
-കെ
-കേ
-കൈ
-കൊ
-കോ
-കൌ
-ക്കെ
-ക്കൊ
-ക്ത്ര
-ക്യ
-ക്വ
-ഖ്യ
-ഖ്ര
-ഗ്ദ്ധ്രോ
-ട്ട
-ട്ടു്
-ണ്‍
-ണ്ട
-ത്ത
-ത്തെ
-ത്തൊ
-ദ്ദ
-ന്‍
-ന്ത
-ന്ത്യ
-ന്ത്ര്യ
-പ്ര
-പ്ലോ
-മുഖ്യമന്ത്രി
-മ്പ
-യാത്രാകൂലി
-യും
-യ്ക്കു
-യ്യ
-ര്
-ര്‍
-ര്ക
-ര്യ
-ര്‍വ്വ
-ല്‍
-ല്യ
-ല്ല
-ല്ലാം
-വ്വ
-ഷ്ട്രീ
-സോഫ്റ്റ്‌വെയര്‍
-സ്പ്രി
-സ്പ്രേ
-സ്പ്ലേ
-സ്വാതന്ത്ര്യം
-ഹാര്‍ഡ്‌വെയര്‍
-ള്‍
-ള്യം
-ള്ള
-ല്‍പ്പേ
-ശിം‌
-കോം‌
-യ‍്യ
-സ്റ്റ്
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/LICENSE
deleted file mode 100644 (file)
index 2cf8228..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/README
deleted file mode 100644 (file)
index 8bad337..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/SOURCES
deleted file mode 100644 (file)
index 0ed1a89..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
deleted file mode 100644 (file)
index 0d1a19b..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-ൠ
-ൡ
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644 (file)
index 4924e56..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-ക
-ഖ
-ഗ
-ഘ
-ങ
-ച
-ഛ
-ജ
-ഝ
-ഞ
-ട
-ഠ
-ഡ
-ഢ
-ണ
-ത
-ഥ
-ദ
-ധ
-ന
-പ
-ഫ
-ബ
-ഭ
-മ
-യ
-ര
-റ
-ല
-ള
-ഴ
-വ
-ശ
-ഷ
-സ
-ഹ
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644 (file)
index dc49691..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-ാ
-ി
-ീ
-ു
-ൂ
-ൃ
-െ
-േ
-ൈ
-ൊ
-ോ
-ൌ
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644 (file)
index c2a9f06..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-൦
-൧
-൨
-൩
-൪
-൫
-൬
-൭
-൮
-൯
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644 (file)
index d879c3b..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-അ
-ആ
-ഇ
-ഈ
-ഉ
-ഊ
-ഋ
-ഌ
-എ
-ഏ
-ഐ
-ഒ
-ഓ
-ഔ
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
deleted file mode 100644 (file)
index 66a7ca4..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644 (file)
index 2c976a4..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-ം
-ഃ
-്
-ൗ
diff --git a/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644 (file)
index 1053215..0000000
+++ /dev/null
@@ -1,254 +0,0 @@
-ക്ക
-ച്ച
-ട്ട
-ത്ത
-പ്പ
-ഗ്ഗ
-ജ്ജ
-ഡ്ഡ
-ദ്ദ
-ബ്ബ
-ങ്ങ
-ഞ്ഞ
-ണ്ണ
-ന്ന
-മ്മ
-യ്യ
-ല്ല
-വ്വ
-ശ്ശ
-സ്സ
-ള്ള
-റ്റ
-ക്ത
-ക്ഷ
-ഗ്ന
-ഗ്മ
-ങ്ക
-ച്ഛ
-ജ്ഞ
-ഞ്ച
-ണ്ട
-ണ്മ
-ത്ഥ
-ത്മ
-ത്ഭ
-ത്സ
-ദ്ധ
-ന്ത
-ന്ഥ
-ന്ദ
-ന്ധ
-ന്മ
-ന്റ
-മ്പ
-ബ്ദ
-ബ്ധ
-ശ്ച
-ഷ്ട
-സ്ഥ
-ഹ്ന
-ഹ്മ
-ക്യ
-ഖ്യ
-ഗ്യ
-ഘ്യ
-ങ്യ
-ച്യ
-ഛ്യ
-ജ്യ
-ഝ്യ
-ഞ്യ
-ട്യ
-ഠ്യ
-ഡ്യ
-ഢ്യ
-ണ്യ
-ത്യ
-ഥ്യ
-ദ്യ
-ധ്യ
-ന്യ
-പ്യ
-ഫ്യ
-ബ്യ
-ഭ്യ
-മ്യ
-ര്യ
-റ്യ
-ല്യ
-ള്യ
-ഴ്യ
-വ്യ
-ശ്യ
-ഷ്യ
-സ്യ
-ഹ്യ
-ക്ര
-ഖ്ര
-ഗ്ര
-ഘ്ര
-ച്ര
-ഛ്ര
-ജ്ര
-ട്ര
-ഠ്ര
-ഡ്ര
-ഢ്ര
-ത്ര
-ഥ്ര
-ദ്ര
-ധ്ര
-ന്ര
-പ്ര
-ഫ്ര
-ബ്ര
-ഭ്ര
-മ്ര
-ല്ര
-വ്ര
-ശ്ര
-ഷ്ര
-സ്ര
-ഹ്ര
-ക്ല
-ഖ്ല
-ഗ്ല
-ഘ്ല
-ങ്ല
-ച്ല
-ഛ്ല
-ജ്ല
-ഝ്ല
-ഞ്ല
-ട്ല
-ഠ്ല
-ഡ്ല
-ഢ്ല
-ണ്ല
-ത്ല
-ഥ്ല
-ദ്ല
-ധ്ല
-ന്ല
-പ്ല
-ഫ്ല
-ബ്ല
-ഭ്ല
-മ്ല
-യ്ല
-ര്ല
-റ്ല
-വ്ല
-ശ്ല
-ഷ്ല
-സ്ല
-ഹ്ല
-ക്ള
-ഖ്ള
-ഗ്ള
-ഘ്ള
-ങ്ള
-ച്ള
-ഛ്ള
-ജ്ള
-ഝ്ള
-ഞ്ള
-ട്ള
-ഠ്ള
-ഡ്ള
-ഢ്ള
-ണ്ള
-ത്ള
-ഥ്ള
-ദ്ള
-ധ്ള
-ന്ള
-പ്ള
-ഫ്ള
-ബ്ള
-ഭ്ള
-മ്ള
-യ്ള
-ര്ള
-റ്ള
-വ്ള
-ശ്ള
-ഷ്ള
-സ്ള
-ഹ്ള
-ക്വ
-ഖ്വ
-ഗ്വ
-ഘ്വ
-ങ്വ
-ച്വ
-ഛ്വ
-ജ്വ
-ഝ്വ
-ഞ്വ
-ട്വ
-ഠ്വ
-ഡ്വ
-ഢ്വ
-ണ്വ
-ത്വ
-ഥ്വ
-ദ്വ
-ധ്വ
-ന്വ
-പ്വ
-ഫ്വ
-ബ്വ
-ഭ്വ
-മ്വ
-ര്വ
-റ്വ
-ല്വ
-ള്വ
-ഴ്വ
-ശ്വ
-ഷ്വ
-സ്വ
-ഹ്വ
-ക്
-ഖ്
-ഗ്
-ഘ്
-ങ്
-ച്
-ഛ്
-ജ്
-ഝ്
-ഞ്
-ട്
-ഠ്
-ഡ്
-ഢ്
-ണ്
-ത്
-ഥ്
-ദ്
-ധ്
-ന്
-പ്
-ഫ്
-ബ്
-ഭ്
-മ്
-യ്
-ര്
-റ്
-ല്
-ള്
-ഴ്
-വ്
-ശ്
-ഷ്
-സ്
-ഹ്
-ഡ്രൈവ്
-അപ്ഡേറ്റ്
-അപ്ഗ്രേഡ്
-വ്യക്തം
-ഇന്‍സ്റ്റോള്‍
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/misc/bindu.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/misc/bindu.txt
deleted file mode 100644 (file)
index 13de6ee..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-ମୁଁ
-ମୁଂ
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/misc/misc.txt
deleted file mode 100644 (file)
index 44a53df..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-ஃ
-ஃக
-கூ
-கெ
-கொ
-கொ
-க்ஷ
-க்ஷொ
-க்ஷொ
-ஙூ
-சூ
-டி
-டீ
-டூ
-தூ
-மூ
-ரி
-ரீ
-ரூ
-ர்
-லி
-லீ
-କ୍ତ୍ର
-ତ୍ତ୍ବ
-ନ୍ତ୍ବ
-ନ୍ତ୍ର
-ନ୍ତ୍ର୍ଯ
-ସ୍ତ୍ର
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/oriya-vowel-letters.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/oriya-vowel-letters.txt
deleted file mode 100644 (file)
index e8d24cb..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-ଆ ଅା
-ଐ ଏୗ
-ଔ ଓୗ
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/LICENSE
deleted file mode 100644 (file)
index 2cf8228..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/README
deleted file mode 100644 (file)
index 8bad337..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/SOURCES
deleted file mode 100644 (file)
index 0ed1a89..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt
deleted file mode 100644 (file)
index c311f42..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-ଡ଼
-ଢ଼
-ୟ
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
deleted file mode 100644 (file)
index c15795c..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-ୠ
-ୡ
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644 (file)
index 5692fa1..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-କ
-ଖ
-ଗ
-ଘ
-ଙ
-ଚ
-ଛ
-ଜ
-ଝ
-ଞ
-ଟ
-ଠ
-ଡ
-ଢ
-ଣ
-ତ
-ଥ
-ଦ
-ଧ
-ନ
-ପ
-ଫ
-ବ
-ଭ
-ମ
-ଯ
-ର
-ଲ
-ଳ
-ଵ
-ଶ
-ଷ
-ସ
-ହ
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644 (file)
index d95d909..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-ା
-ି
-ୀ
-ୁ
-ୂ
-ୃ
-େ
-ୈ
-ୋ
-ୌ
-ୖ
-ୗ
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644 (file)
index ce7af5e..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-୦
-୧
-୨
-୩
-୪
-୫
-୬
-୭
-୮
-୯
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644 (file)
index 9d21b9d..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-ଅ
-ଆ
-ଇ
-ଈ
-ଉ
-ଊ
-ଋ
-ଌ
-ଏ
-ଐ
-ଓ
-ଔ
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-OriyaSpecific.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-OriyaSpecific.txt
deleted file mode 100644 (file)
index 6571b52..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-୰
-ୱ
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
deleted file mode 100644 (file)
index 66a7ca4..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644 (file)
index ce411d2..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-ଁ
-ଂ
-ଃ
-଼
-ଽ
-୍
-ୖ
-ୗ
diff --git a/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644 (file)
index fe11060..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-କ୍ଷ
-ଙ୍କ
-ଙ୍ଖ
-ଙ୍ଗ
-ଙ୍ଘ
-ଙ୍ଳ
-ଙ୍କ୍ତ
-ଚ୍ଚ
-ଚ୍ଛ
-ଜ୍ଜ
-ଜ୍ଝ
-ଜ୍ଞ
-ଞ୍ଚ
-ଞ୍ଛ
-ଞ୍ଜ
-ଟ୍ଟ
-ଣ୍ଟ
-ଣ୍ଠ
-ଣ୍ଡ
-ଣ୍ଢ
-ଣ୍ଣ
-ତ୍କ
-ତ୍ତ
-ତ୍ଥ
-ତ୍ନ
-ତ୍ସ
-ତ୍ପ
-ଦ୍ଦ
-ଦ୍ଧ
-ଦ୍ଭ
-ଦ୍ଯ
-ବ୍ଡ
-ବ୍ଦ
-ବ୍ଧ
-ନ୍ତ
-ନ୍ତ୍ର
-ନ୍ଥ
-ନ୍ଦ
-ନ୍ଧ
-ନ୍ନ
-ଯ୍ତ
-ମ୍ପ
-ମ୍ଫ
-ମ୍ବ
-ମ୍ମ
-ମ୍ଭ
-ଶ୍ଚ
-ଶ୍ପ
-ଶ୍ଫ
-ଶ୍କ
-ଶ୍ଟ
-ଷ୍ଟ
-ଷ୍ଟ୍ବ
-ଷ୍ଠ
-ଷ୍ଣ
-ସ୍କ
-ସ୍ଖ
-ସ୍ଘ
-ସ୍ପ
-ସ୍ଫ
-ସ୍ତ
-ସ୍ତ୍ର
-ସ୍ଥ
-ସ୍ବ
-ସ୍ମୃ
-ହ୍ନ
-ହ୍ଳ
-ହ୍ଵ
-ପ୍ଟ
-କ୍କ
-କ୍ଖ
-କ୍ଗ
-କ୍ଘ
-କ୍ଚ
-କ୍ଛ
-କ୍ଜ
-କ୍ଝ
-କ୍ଟ
-କ୍ଠ
-କ୍ଡ
-କ୍ଢ
-କ୍ଣ
-କ୍ତ
-କ୍ଥ
-କ୍ଦ
-କ୍ଧ
-କ୍ନ
-କ୍ପ
-କ୍ଫ
-କ୍ବ
-କ୍ଭ
-କ୍ମ
-କ୍ଯ
-କ୍ର
-କ୍ଳ
-କ୍ଲ
-କ୍ହ
-ର୍କ
-ର୍ଖ
-ର୍ଗ
-ର୍ଘ
-ର୍ଚ
-ର୍ଚ୍ଚ
-ର୍ଚ୍ଛ
-ର୍ଛ
-ର୍ଜ
-ର୍ଝ
-ର୍ଟ
-ର୍ଠ
-ର୍ଡ
-ର୍ଢ
-ର୍ଣ
-ର୍ତ
-ର୍ତ୍ତ
-ର୍ଥ
-ର୍ଦ
-ର୍ଦ୍ଦ
-ର୍ଦ୍ଧ
-ର୍ଧ
-ର୍ନ
-ର୍ପ
-ର୍ଫ
-ର୍ବ
-ର୍ଭ
-ର୍ମ
-ର୍ଯ
-ର୍ଯ୍ଯ
-ର୍ଶ
-ର୍ଷ
-ର୍ସ
-ର୍ହ
-ର୍ଡ଼
-ର୍ଢ଼
-ଖ୍ର
-ଗ୍ର
-ଘ୍ର
-ଚ୍ଚ୍ର
-ଚ୍ଛ୍ର
-ଚ୍ର
-ଛ୍ର
-ଜ୍ର
-ଝ୍ର
-ଟ୍ର
-ଠ୍ର
-ଡ୍ର
-ଢ୍ର
-ଣ୍ର
-ତ୍ର
-ତ୍ତ୍ର
-ତ୍ଥ୍ର
-ଥ୍ର
-ଦ୍ର
-ଦ୍ଦ୍ର
-ଦ୍ଧ୍ର
-ଧ୍ର
-ନ୍ର
-ପ୍ର
-ଫ୍ର
-ବ୍ର
-ଭ୍ର
-ମ୍ର
-ଯ୍ର
-ଶ୍ର
-ଷ୍ର
-ସ୍ର
-ହ୍ର
-ଡ଼୍ର
-ଢ଼୍ର
-ଦ୍ଗ
-ତ୍ମ
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/extensive.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/extensive.txt
deleted file mode 100644 (file)
index 231a1f7..0000000
+++ /dev/null
@@ -1,4390 +0,0 @@
-අ
-ආ
-ඇ
-ඈ
-ඉ
-ඊ
-උ
-ඌ
-ඍ
-ඎ
-ඏ
-ඐ
-එ
-ඒ
-ඓ
-ඔ
-ඕ
-ඖ
-ක
-කා
-කැ
-කෑ
-කි
-කී
-කු
-කූ
-කෘ
-කෲ
-කෟ
-කෳ
-කෙ
-කේ
-කෛ
-කො
-කෝ
-කෞ
-ක්
-කං
-කඃ
-ක්‍ර
-ක්‍රා
-ක්‍රැ
-ක්‍රෑ
-ක්‍රි
-ක්‍රී
-ක්‍රු
-ක්‍රූ
-ක්‍රෘ
-ක්‍රෲ
-ක්‍රෟ
-ක්‍රෳ
-ක්‍රෙ
-ක්‍රේ
-ක්‍රෛ
-ක්‍රො
-ක්‍රෝ
-ක්‍රෞ
-ක්‍ර්
-ක්‍රං
-ක්‍රඃ
-ක්‍ය
-ක්‍යා
-ක්‍යැ
-ක්‍යෑ
-ක්‍යි
-ක්‍යී
-ක්‍යු
-ක්‍යූ
-ක්‍යෘ
-ක්‍යෲ
-ක්‍යෟ
-ක්‍යෳ
-ක්‍යෙ
-ක්‍යේ
-ක්‍යෛ
-ක්‍යො
-ක්‍යෝ
-ක්‍යෞ
-ක්‍ය්
-ක්‍යං
-ක්‍යඃ
-ර්‍ක
-ර්‍කා
-ර්‍කැ
-ර්‍කෑ
-ර්‍කි
-ර්‍කී
-ර්‍කු
-ර්‍කූ
-ර්‍කෘ
-ර්‍කෲ
-ර්‍කෟ
-ර්‍කෳ
-ර්‍කෙ
-ර්‍කේ
-ර්‍කෛ
-ර්‍කො
-ර්‍කෝ
-ර්‍කෞ
-ර්‍ක්
-ර්‍කං
-ර්‍කඃ
-ඛ
-ඛා
-ඛැ
-ඛෑ
-ඛි
-ඛී
-ඛු
-ඛූ
-ඛෘ
-ඛෲ
-ඛෟ
-ඛෳ
-ඛෙ
-ඛේ
-ඛෛ
-ඛො
-ඛෝ
-ඛෞ
-ඛ්
-ඛං
-ඛඃ
-ඛ්‍ර
-ඛ්‍රා
-ඛ්‍රැ
-ඛ්‍රෑ
-ඛ්‍රි
-ඛ්‍රී
-ඛ්‍රු
-ඛ්‍රූ
-ඛ්‍රෘ
-ඛ්‍රෲ
-ඛ්‍රෟ
-ඛ්‍රෳ
-ඛ්‍රෙ
-ඛ්‍රේ
-ඛ්‍රෛ
-ඛ්‍රො
-ඛ්‍රෝ
-ඛ්‍රෞ
-ඛ්‍ර්
-ඛ්‍රං
-ඛ්‍රඃ
-ඛ්‍ය
-ඛ්‍යා
-ඛ්‍යැ
-ඛ්‍යෑ
-ඛ්‍යි
-ඛ්‍යී
-ඛ්‍යු
-ඛ්‍යූ
-ඛ්‍යෘ
-ඛ්‍යෲ
-ඛ්‍යෟ
-ඛ්‍යෳ
-ඛ්‍යෙ
-ඛ්‍යේ
-ඛ්‍යෛ
-ඛ්‍යො
-ඛ්‍යෝ
-ඛ්‍යෞ
-ඛ්‍ය්
-ඛ්‍යං
-ඛ්‍යඃ
-ර්‍ඛ
-ර්‍ඛා
-ර්‍ඛැ
-ර්‍ඛෑ
-ර්‍ඛි
-ර්‍ඛී
-ර්‍ඛු
-ර්‍ඛූ
-ර්‍ඛෘ
-ර්‍ඛෲ
-ර්‍ඛෟ
-ර්‍ඛෳ
-ර්‍ඛෙ
-ර්‍ඛේ
-ර්‍ඛෛ
-ර්‍ඛො
-ර්‍ඛෝ
-ර්‍ඛෞ
-ර්‍ඛ්
-ර්‍ඛං
-ර්‍ඛඃ
-ග
-ගා
-ගැ
-ගෑ
-ගි
-ගී
-ගු
-ගූ
-ගෘ
-ගෲ
-ගෟ
-ගෳ
-ගෙ
-ගේ
-ගෛ
-ගො
-ගෝ
-ගෞ
-ග්
-ගං
-ගඃ
-ග්‍ර
-ග්‍රා
-ග්‍රැ
-ග්‍රෑ
-ග්‍රි
-ග්‍රී
-ග්‍රු
-ග්‍රූ
-ග්‍රෘ
-ග්‍රෲ
-ග්‍රෟ
-ග්‍රෳ
-ග්‍රෙ
-ග්‍රේ
-ග්‍රෛ
-ග්‍රො
-ග්‍රෝ
-ග්‍රෞ
-ග්‍ර්
-ග්‍රං
-ග්‍රඃ
-ග්‍ය
-ග්‍යා
-ග්‍යැ
-ග්‍යෑ
-ග්‍යි
-ග්‍යී
-ග්‍යු
-ග්‍යූ
-ග්‍යෘ
-ග්‍යෲ
-ග්‍යෟ
-ග්‍යෳ
-ග්‍යෙ
-ග්‍යේ
-ග්‍යෛ
-ග්‍යො
-ග්‍යෝ
-ග්‍යෞ
-ග්‍ය්
-ග්‍යං
-ග්‍යඃ
-ර්‍ග
-ර්‍ගා
-ර්‍ගැ
-ර්‍ගෑ
-ර්‍ගි
-ර්‍ගී
-ර්‍ගු
-ර්‍ගූ
-ර්‍ගෘ
-ර්‍ගෲ
-ර්‍ගෟ
-ර්‍ගෳ
-ර්‍ගෙ
-ර්‍ගේ
-ර්‍ගෛ
-ර්‍ගො
-ර්‍ගෝ
-ර්‍ගෞ
-ර්‍ග්
-ර්‍ගං
-ර්‍ගඃ
-ඝ
-ඝා
-ඝැ
-ඝෑ
-ඝි
-ඝී
-ඝු
-ඝූ
-ඝෘ
-ඝෲ
-ඝෟ
-ඝෳ
-ඝෙ
-ඝේ
-ඝෛ
-ඝො
-ඝෝ
-ඝෞ
-ඝ්
-ඝං
-ඝඃ
-ඝ්‍ර
-ඝ්‍රා
-ඝ්‍රැ
-ඝ්‍රෑ
-ඝ්‍රි
-ඝ්‍රී
-ඝ්‍රු
-ඝ්‍රූ
-ඝ්‍රෘ
-ඝ්‍රෲ
-ඝ්‍රෟ
-ඝ්‍රෳ
-ඝ්‍රෙ
-ඝ්‍රේ
-ඝ්‍රෛ
-ඝ්‍රො
-ඝ්‍රෝ
-ඝ්‍රෞ
-ඝ්‍ර්
-ඝ්‍රං
-ඝ්‍රඃ
-ඝ්‍ය
-ඝ්‍යා
-ඝ්‍යැ
-ඝ්‍යෑ
-ඝ්‍යි
-ඝ්‍යී
-ඝ්‍යු
-ඝ්‍යූ
-ඝ්‍යෘ
-ඝ්‍යෲ
-ඝ්‍යෟ
-ඝ්‍යෳ
-ඝ්‍යෙ
-ඝ්‍යේ
-ඝ්‍යෛ
-ඝ්‍යො
-ඝ්‍යෝ
-ඝ්‍යෞ
-ඝ්‍ය්
-ඝ්‍යං
-ඝ්‍යඃ
-ර්‍ඝ
-ර්‍ඝා
-ර්‍ඝැ
-ර්‍ඝෑ
-ර්‍ඝි
-ර්‍ඝී
-ර්‍ඝු
-ර්‍ඝූ
-ර්‍ඝෘ
-ර්‍ඝෲ
-ර්‍ඝෟ
-ර්‍ඝෳ
-ර්‍ඝෙ
-ර්‍ඝේ
-ර්‍ඝෛ
-ර්‍ඝො
-ර්‍ඝෝ
-ර්‍ඝෞ
-ර්‍ඝ්
-ර්‍ඝං
-ර්‍ඝඃ
-ඞ
-ඞා
-ඞැ
-ඞෑ
-ඞි
-ඞී
-ඞු
-ඞූ
-ඞෘ
-ඞෲ
-ඞෟ
-ඞෳ
-ඞෙ
-ඞේ
-ඞෛ
-ඞො
-ඞෝ
-ඞෞ
-ඞ්
-ඞං
-ඞඃ
-ඞ්‍ර
-ඞ්‍රා
-ඞ්‍රැ
-ඞ්‍රෑ
-ඞ්‍රි
-ඞ්‍රී
-ඞ්‍රු
-ඞ්‍රූ
-ඞ්‍රෘ
-ඞ්‍රෲ
-ඞ්‍රෟ
-ඞ්‍රෳ
-ඞ්‍රෙ
-ඞ්‍රේ
-ඞ්‍රෛ
-ඞ්‍රො
-ඞ්‍රෝ
-ඞ්‍රෞ
-ඞ්‍ර්
-ඞ්‍රං
-ඞ්‍රඃ
-ඞ්‍ය
-ඞ්‍යා
-ඞ්‍යැ
-ඞ්‍යෑ
-ඞ්‍යි
-ඞ්‍යී
-ඞ්‍යු
-ඞ්‍යූ
-ඞ්‍යෘ
-ඞ්‍යෲ
-ඞ්‍යෟ
-ඞ්‍යෳ
-ඞ්‍යෙ
-ඞ්‍යේ
-ඞ්‍යෛ
-ඞ්‍යො
-ඞ්‍යෝ
-ඞ්‍යෞ
-ඞ්‍ය්
-ඞ්‍යං
-ඞ්‍යඃ
-ර්‍ඞ
-ර්‍ඞා
-ර්‍ඞැ
-ර්‍ඞෑ
-ර්‍ඞි
-ර්‍ඞී
-ර්‍ඞු
-ර්‍ඞූ
-ර්‍ඞෘ
-ර්‍ඞෲ
-ර්‍ඞෟ
-ර්‍ඞෳ
-ර්‍ඞෙ
-ර්‍ඞේ
-ර්‍ඞෛ
-ර්‍ඞො
-ර්‍ඞෝ
-ර්‍ඞෞ
-ර්‍ඞ්
-ර්‍ඞං
-ර්‍ඞඃ
-ඟ
-ඟා
-ඟැ
-ඟෑ
-ඟි
-ඟී
-ඟු
-ඟූ
-ඟෘ
-ඟෲ
-ඟෟ
-ඟෳ
-ඟෙ
-ඟේ
-ඟෛ
-ඟො
-ඟෝ
-ඟෞ
-ඟ්
-ඟං
-ඟඃ
-ඟ්‍ර
-ඟ්‍රා
-ඟ්‍රැ
-ඟ්‍රෑ
-ඟ්‍රි
-ඟ්‍රී
-ඟ්‍රු
-ඟ්‍රූ
-ඟ්‍රෘ
-ඟ්‍රෲ
-ඟ්‍රෟ
-ඟ්‍රෳ
-ඟ්‍රෙ
-ඟ්‍රේ
-ඟ්‍රෛ
-ඟ්‍රො
-ඟ්‍රෝ
-ඟ්‍රෞ
-ඟ්‍ර්
-ඟ්‍රං
-ඟ්‍රඃ
-ඟ්‍ය
-ඟ්‍යා
-ඟ්‍යැ
-ඟ්‍යෑ
-ඟ්‍යි
-ඟ්‍යී
-ඟ්‍යු
-ඟ්‍යූ
-ඟ්‍යෘ
-ඟ්‍යෲ
-ඟ්‍යෟ
-ඟ්‍යෳ
-ඟ්‍යෙ
-ඟ්‍යේ
-ඟ්‍යෛ
-ඟ්‍යො
-ඟ්‍යෝ
-ඟ්‍යෞ
-ඟ්‍ය්
-ඟ්‍යං
-ඟ්‍යඃ
-ර්‍ඟ
-ර්‍ඟා
-ර්‍ඟැ
-ර්‍ඟෑ
-ර්‍ඟි
-ර්‍ඟී
-ර්‍ඟු
-ර්‍ඟූ
-ර්‍ඟෘ
-ර්‍ඟෲ
-ර්‍ඟෟ
-ර්‍ඟෳ
-ර්‍ඟෙ
-ර්‍ඟේ
-ර්‍ඟෛ
-ර්‍ඟො
-ර්‍ඟෝ
-ර්‍ඟෞ
-ර්‍ඟ්
-ර්‍ඟං
-ර්‍ඟඃ
-ච
-චා
-චැ
-චෑ
-චි
-චී
-චු
-චූ
-චෘ
-චෲ
-චෟ
-චෳ
-චෙ
-චේ
-චෛ
-චො
-චෝ
-චෞ
-ච්
-චං
-චඃ
-ච්‍ර
-ච්‍රා
-ච්‍රැ
-ච්‍රෑ
-ච්‍රි
-ච්‍රී
-ච්‍රු
-ච්‍රූ
-ච්‍රෘ
-ච්‍රෲ
-ච්‍රෟ
-ච්‍රෳ
-ච්‍රෙ
-ච්‍රේ
-ච්‍රෛ
-ච්‍රො
-ච්‍රෝ
-ච්‍රෞ
-ච්‍ර්
-ච්‍රං
-ච්‍රඃ
-ච්‍ය
-ච්‍යා
-ච්‍යැ
-ච්‍යෑ
-ච්‍යි
-ච්‍යී
-ච්‍යු
-ච්‍යූ
-ච්‍යෘ
-ච්‍යෲ
-ච්‍යෟ
-ච්‍යෳ
-ච්‍යෙ
-ච්‍යේ
-ච්‍යෛ
-ච්‍යො
-ච්‍යෝ
-ච්‍යෞ
-ච්‍ය්
-ච්‍යං
-ච්‍යඃ
-ර්‍ච
-ර්‍චා
-ර්‍චැ
-ර්‍චෑ
-ර්‍චි
-ර්‍චී
-ර්‍චු
-ර්‍චූ
-ර්‍චෘ
-ර්‍චෲ
-ර්‍චෟ
-ර්‍චෳ
-ර්‍චෙ
-ර්‍චේ
-ර්‍චෛ
-ර්‍චො
-ර්‍චෝ
-ර්‍චෞ
-ර්‍ච්
-ර්‍චං
-ර්‍චඃ
-ඡ
-ඡා
-ඡැ
-ඡෑ
-ඡි
-ඡී
-ඡු
-ඡූ
-ඡෘ
-ඡෲ
-ඡෟ
-ඡෳ
-ඡෙ
-ඡේ
-ඡෛ
-ඡො
-ඡෝ
-ඡෞ
-ඡ්
-ඡං
-ඡඃ
-ඡ්‍ර
-ඡ්‍රා
-ඡ්‍රැ
-ඡ්‍රෑ
-ඡ්‍රි
-ඡ්‍රී
-ඡ්‍රු
-ඡ්‍රූ
-ඡ්‍රෘ
-ඡ්‍රෲ
-ඡ්‍රෟ
-ඡ්‍රෳ
-ඡ්‍රෙ
-ඡ්‍රේ
-ඡ්‍රෛ
-ඡ්‍රො
-ඡ්‍රෝ
-ඡ්‍රෞ
-ඡ්‍ර්
-ඡ්‍රං
-ඡ්‍රඃ
-ඡ්‍ය
-ඡ්‍යා
-ඡ්‍යැ
-ඡ්‍යෑ
-ඡ්‍යි
-ඡ්‍යී
-ඡ්‍යු
-ඡ්‍යූ
-ඡ්‍යෘ
-ඡ්‍යෲ
-ඡ්‍යෟ
-ඡ්‍යෳ
-ඡ්‍යෙ
-ඡ්‍යේ
-ඡ්‍යෛ
-ඡ්‍යො
-ඡ්‍යෝ
-ඡ්‍යෞ
-ඡ්‍ය්
-ඡ්‍යං
-ඡ්‍යඃ
-ර්‍ඡ
-ර්‍ඡා
-ර්‍ඡැ
-ර්‍ඡෑ
-ර්‍ඡි
-ර්‍ඡී
-ර්‍ඡු
-ර්‍ඡූ
-ර්‍ඡෘ
-ර්‍ඡෲ
-ර්‍ඡෟ
-ර්‍ඡෳ
-ර්‍ඡෙ
-ර්‍ඡේ
-ර්‍ඡෛ
-ර්‍ඡො
-ර්‍ඡෝ
-ර්‍ඡෞ
-ර්‍ඡ්
-ර්‍ඡං
-ර්‍ඡඃ
-ජ
-ජා
-ජැ
-ජෑ
-ජි
-ජී
-ජු
-ජූ
-ජෘ
-ජෲ
-ජෟ
-ජෳ
-ජෙ
-ජේ
-ජෛ
-ජො
-ජෝ
-ජෞ
-ජ්
-ජං
-ජඃ
-ජ්‍ර
-ජ්‍රා
-ජ්‍රැ
-ජ්‍රෑ
-ජ්‍රි
-ජ්‍රී
-ජ්‍රු
-ජ්‍රූ
-ජ්‍රෘ
-ජ්‍රෲ
-ජ්‍රෟ
-ජ්‍රෳ
-ජ්‍රෙ
-ජ්‍රේ
-ජ්‍රෛ
-ජ්‍රො
-ජ්‍රෝ
-ජ්‍රෞ
-ජ්‍ර්
-ජ්‍රං
-ජ්‍රඃ
-ජ්‍ය
-ජ්‍යා
-ජ්‍යැ
-ජ්‍යෑ
-ජ්‍යි
-ජ්‍යී
-ජ්‍යු
-ජ්‍යූ
-ජ්‍යෘ
-ජ්‍යෲ
-ජ්‍යෟ
-ජ්‍යෳ
-ජ්‍යෙ
-ජ්‍යේ
-ජ්‍යෛ
-ජ්‍යො
-ජ්‍යෝ
-ජ්‍යෞ
-ජ්‍ය්
-ජ්‍යං
-ජ්‍යඃ
-ර්‍ජ
-ර්‍ජා
-ර්‍ජැ
-ර්‍ජෑ
-ර්‍ජි
-ර්‍ජී
-ර්‍ජු
-ර්‍ජූ
-ර්‍ජෘ
-ර්‍ජෲ
-ර්‍ජෟ
-ර්‍ජෳ
-ර්‍ජෙ
-ර්‍ජේ
-ර්‍ජෛ
-ර්‍ජො
-ර්‍ජෝ
-ර්‍ජෞ
-ර්‍ජ්
-ර්‍ජං
-ර්‍ජඃ
-ඣ
-ඣා
-ඣැ
-ඣෑ
-ඣි
-ඣී
-ඣු
-ඣූ
-ඣෘ
-ඣෲ
-ඣෟ
-ඣෳ
-ඣෙ
-ඣේ
-ඣෛ
-ඣො
-ඣෝ
-ඣෞ
-ඣ්
-ඣං
-ඣඃ
-ඣ්‍ර
-ඣ්‍රා
-ඣ්‍රැ
-ඣ්‍රෑ
-ඣ්‍රි
-ඣ්‍රී
-ඣ්‍රු
-ඣ්‍රූ
-ඣ්‍රෘ
-ඣ්‍රෲ
-ඣ්‍රෟ
-ඣ්‍රෳ
-ඣ්‍රෙ
-ඣ්‍රේ
-ඣ්‍රෛ
-ඣ්‍රො
-ඣ්‍රෝ
-ඣ්‍රෞ
-ඣ්‍ර්
-ඣ්‍රං
-ඣ්‍රඃ
-ඣ්‍ය
-ඣ්‍යා
-ඣ්‍යැ
-ඣ්‍යෑ
-ඣ්‍යි
-ඣ්‍යී
-ඣ්‍යු
-ඣ්‍යූ
-ඣ්‍යෘ
-ඣ්‍යෲ
-ඣ්‍යෟ
-ඣ්‍යෳ
-ඣ්‍යෙ
-ඣ්‍යේ
-ඣ්‍යෛ
-ඣ්‍යො
-ඣ්‍යෝ
-ඣ්‍යෞ
-ඣ්‍ය්
-ඣ්‍යං
-ඣ්‍යඃ
-ර්‍ඣ
-ර්‍ඣා
-ර්‍ඣැ
-ර්‍ඣෑ
-ර්‍ඣි
-ර්‍ඣී
-ර්‍ඣු
-ර්‍ඣූ
-ර්‍ඣෘ
-ර්‍ඣෲ
-ර්‍ඣෟ
-ර්‍ඣෳ
-ර්‍ඣෙ
-ර්‍ඣේ
-ර්‍ඣෛ
-ර්‍ඣො
-ර්‍ඣෝ
-ර්‍ඣෞ
-ර්‍ඣ්
-ර්‍ඣං
-ර්‍ඣඃ
-ඥ
-ඥා
-ඥැ
-ඥෑ
-ඥි
-ඥී
-ඥු
-ඥූ
-ඥෘ
-ඥෲ
-ඥෟ
-ඥෳ
-ඥෙ
-ඥේ
-ඥෛ
-ඥො
-ඥෝ
-ඥෞ
-ඥ්
-ඥං
-ඥඃ
-ඥ්‍ර
-ඥ්‍රා
-ඥ්‍රැ
-ඥ්‍රෑ
-ඥ්‍රි
-ඥ්‍රී
-ඥ්‍රු
-ඥ්‍රූ
-ඥ්‍රෘ
-ඥ්‍රෲ
-ඥ්‍රෟ
-ඥ්‍රෳ
-ඥ්‍රෙ
-ඥ්‍රේ
-ඥ්‍රෛ
-ඥ්‍රො
-ඥ්‍රෝ
-ඥ්‍රෞ
-ඥ්‍ර්
-ඥ්‍රං
-ඥ්‍රඃ
-ඥ්‍ය
-ඥ්‍යා
-ඥ්‍යැ
-ඥ්‍යෑ
-ඥ්‍යි
-ඥ්‍යී
-ඥ්‍යු
-ඥ්‍යූ
-ඥ්‍යෘ
-ඥ්‍යෲ
-ඥ්‍යෟ
-ඥ්‍යෳ
-ඥ්‍යෙ
-ඥ්‍යේ
-ඥ්‍යෛ
-ඥ්‍යො
-ඥ්‍යෝ
-ඥ්‍යෞ
-ඥ්‍ය්
-ඥ්‍යං
-ඥ්‍යඃ
-ර්‍ඥ
-ර්‍ඥා
-ර්‍ඥැ
-ර්‍ඥෑ
-ර්‍ඥි
-ර්‍ඥී
-ර්‍ඥු
-ර්‍ඥූ
-ර්‍ඥෘ
-ර්‍ඥෲ
-ර්‍ඥෟ
-ර්‍ඥෳ
-ර්‍ඥෙ
-ර්‍ඥේ
-ර්‍ඥෛ
-ර්‍ඥො
-ර්‍ඥෝ
-ර්‍ඥෞ
-ර්‍ඥ්
-ර්‍ඥං
-ර්‍ඥඃ
-ඤ
-ඤා
-ඤැ
-ඤෑ
-ඤි
-ඤී
-ඤු
-ඤූ
-ඤෘ
-ඤෲ
-ඤෟ
-ඤෳ
-ඤෙ
-ඤේ
-ඤෛ
-ඤො
-ඤෝ
-ඤෞ
-ඤ්
-ඤං
-ඤඃ
-ඤ්‍ර
-ඤ්‍රා
-ඤ්‍රැ
-ඤ්‍රෑ
-ඤ්‍රි
-ඤ්‍රී
-ඤ්‍රු
-ඤ්‍රූ
-ඤ්‍රෘ
-ඤ්‍රෲ
-ඤ්‍රෟ
-ඤ්‍රෳ
-ඤ්‍රෙ
-ඤ්‍රේ
-ඤ්‍රෛ
-ඤ්‍රො
-ඤ්‍රෝ
-ඤ්‍රෞ
-ඤ්‍ර්
-ඤ්‍රං
-ඤ්‍රඃ
-ඤ්‍ය
-ඤ්‍යා
-ඤ්‍යැ
-ඤ්‍යෑ
-ඤ්‍යි
-ඤ්‍යී
-ඤ්‍යු
-ඤ්‍යූ
-ඤ්‍යෘ
-ඤ්‍යෲ
-ඤ්‍යෟ
-ඤ්‍යෳ
-ඤ්‍යෙ
-ඤ්‍යේ
-ඤ්‍යෛ
-ඤ්‍යො
-ඤ්‍යෝ
-ඤ්‍යෞ
-ඤ්‍ය්
-ඤ්‍යං
-ඤ්‍යඃ
-ර්‍ඤ
-ර්‍ඤා
-ර්‍ඤැ
-ර්‍ඤෑ
-ර්‍ඤි
-ර්‍ඤී
-ර්‍ඤු
-ර්‍ඤූ
-ර්‍ඤෘ
-ර්‍ඤෲ
-ර්‍ඤෟ
-ර්‍ඤෳ
-ර්‍ඤෙ
-ර්‍ඤේ
-ර්‍ඤෛ
-ර්‍ඤො
-ර්‍ඤෝ
-ර්‍ඤෞ
-ර්‍ඤ්
-ර්‍ඤං
-ර්‍ඤඃ
-ඦ
-ඦා
-ඦැ
-ඦෑ
-ඦි
-ඦී
-ඦු
-ඦූ
-ඦෘ
-ඦෲ
-ඦෟ
-ඦෳ
-ඦෙ
-ඦේ
-ඦෛ
-ඦො
-ඦෝ
-ඦෞ
-ඦ්
-ඦං
-ඦඃ
-ඦ්‍ර
-ඦ්‍රා
-ඦ්‍රැ
-ඦ්‍රෑ
-ඦ්‍රි
-ඦ්‍රී
-ඦ්‍රු
-ඦ්‍රූ
-ඦ්‍රෘ
-ඦ්‍රෲ
-ඦ්‍රෟ
-ඦ්‍රෳ
-ඦ්‍රෙ
-ඦ්‍රේ
-ඦ්‍රෛ
-ඦ්‍රො
-ඦ්‍රෝ
-ඦ්‍රෞ
-ඦ්‍ර්
-ඦ්‍රං
-ඦ්‍රඃ
-ඦ්‍ය
-ඦ්‍යා
-ඦ්‍යැ
-ඦ්‍යෑ
-ඦ්‍යි
-ඦ්‍යී
-ඦ්‍යු
-ඦ්‍යූ
-ඦ්‍යෘ
-ඦ්‍යෲ
-ඦ්‍යෟ
-ඦ්‍යෳ
-ඦ්‍යෙ
-ඦ්‍යේ
-ඦ්‍යෛ
-ඦ්‍යො
-ඦ්‍යෝ
-ඦ්‍යෞ
-ඦ්‍ය්
-ඦ්‍යං
-ඦ්‍යඃ
-ර්‍ඦ
-ර්‍ඦා
-ර්‍ඦැ
-ර්‍ඦෑ
-ර්‍ඦි
-ර්‍ඦී
-ර්‍ඦු
-ර්‍ඦූ
-ර්‍ඦෘ
-ර්‍ඦෲ
-ර්‍ඦෟ
-ර්‍ඦෳ
-ර්‍ඦෙ
-ර්‍ඦේ
-ර්‍ඦෛ
-ර්‍ඦො
-ර්‍ඦෝ
-ර්‍ඦෞ
-ර්‍ඦ්
-ර්‍ඦං
-ර්‍ඦඃ
-ට
-ටා
-ටැ
-ටෑ
-ටි
-ටී
-ටු
-ටූ
-ටෘ
-ටෲ
-ටෟ
-ටෳ
-ටෙ
-ටේ
-ටෛ
-ටො
-ටෝ
-ටෞ
-ට්
-ටං
-ටඃ
-ට්‍ර
-ට්‍රා
-ට්‍රැ
-ට්‍රෑ
-ට්‍රි
-ට්‍රී
-ට්‍රු
-ට්‍රූ
-ට්‍රෘ
-ට්‍රෲ
-ට්‍රෟ
-ට්‍රෳ
-ට්‍රෙ
-ට්‍රේ
-ට්‍රෛ
-ට්‍රො
-ට්‍රෝ
-ට්‍රෞ
-ට්‍ර්
-ට්‍රං
-ට්‍රඃ
-ට්‍ය
-ට්‍යා
-ට්‍යැ
-ට්‍යෑ
-ට්‍යි
-ට්‍යී
-ට්‍යු
-ට්‍යූ
-ට්‍යෘ
-ට්‍යෲ
-ට්‍යෟ
-ට්‍යෳ
-ට්‍යෙ
-ට්‍යේ
-ට්‍යෛ
-ට්‍යො
-ට්‍යෝ
-ට්‍යෞ
-ට්‍ය්
-ට්‍යං
-ට්‍යඃ
-ර්‍ට
-ර්‍ටා
-ර්‍ටැ
-ර්‍ටෑ
-ර්‍ටි
-ර්‍ටී
-ර්‍ටු
-ර්‍ටූ
-ර්‍ටෘ
-ර්‍ටෲ
-ර්‍ටෟ
-ර්‍ටෳ
-ර්‍ටෙ
-ර්‍ටේ
-ර්‍ටෛ
-ර්‍ටො
-ර්‍ටෝ
-ර්‍ටෞ
-ර්‍ට්
-ර්‍ටං
-ර්‍ටඃ
-ඨ
-ඨා
-ඨැ
-ඨෑ
-ඨි
-ඨී
-ඨු
-ඨූ
-ඨෘ
-ඨෲ
-ඨෟ
-ඨෳ
-ඨෙ
-ඨේ
-ඨෛ
-ඨො
-ඨෝ
-ඨෞ
-ඨ්
-ඨං
-ඨඃ
-ඨ්‍ර
-ඨ්‍රා
-ඨ්‍රැ
-ඨ්‍රෑ
-ඨ්‍රි
-ඨ්‍රී
-ඨ්‍රු
-ඨ්‍රූ
-ඨ්‍රෘ
-ඨ්‍රෲ
-ඨ්‍රෟ
-ඨ්‍රෳ
-ඨ්‍රෙ
-ඨ්‍රේ
-ඨ්‍රෛ
-ඨ්‍රො
-ඨ්‍රෝ
-ඨ්‍රෞ
-ඨ්‍ර්
-ඨ්‍රං
-ඨ්‍රඃ
-ඨ්‍ය
-ඨ්‍යා
-ඨ්‍යැ
-ඨ්‍යෑ
-ඨ්‍යි
-ඨ්‍යී
-ඨ්‍යු
-ඨ්‍යූ
-ඨ්‍යෘ
-ඨ්‍යෲ
-ඨ්‍යෟ
-ඨ්‍යෳ
-ඨ්‍යෙ
-ඨ්‍යේ
-ඨ්‍යෛ
-ඨ්‍යො
-ඨ්‍යෝ
-ඨ්‍යෞ
-ඨ්‍ය්
-ඨ්‍යං
-ඨ්‍යඃ
-ර්‍ඨ
-ර්‍ඨා
-ර්‍ඨැ
-ර්‍ඨෑ
-ර්‍ඨි
-ර්‍ඨී
-ර්‍ඨු
-ර්‍ඨූ
-ර්‍ඨෘ
-ර්‍ඨෲ
-ර්‍ඨෟ
-ර්‍ඨෳ
-ර්‍ඨෙ
-ර්‍ඨේ
-ර්‍ඨෛ
-ර්‍ඨො
-ර්‍ඨෝ
-ර්‍ඨෞ
-ර්‍ඨ්
-ර්‍ඨං
-ර්‍ඨඃ
-ඩ
-ඩා
-ඩැ
-ඩෑ
-ඩි
-ඩී
-ඩු
-ඩූ
-ඩෘ
-ඩෲ
-ඩෟ
-ඩෳ
-ඩෙ
-ඩේ
-ඩෛ
-ඩො
-ඩෝ
-ඩෞ
-ඩ්
-ඩං
-ඩඃ
-ඩ්‍ර
-ඩ්‍රා
-ඩ්‍රැ
-ඩ්‍රෑ
-ඩ්‍රි
-ඩ්‍රී
-ඩ්‍රු
-ඩ්‍රූ
-ඩ්‍රෘ
-ඩ්‍රෲ
-ඩ්‍රෟ
-ඩ්‍රෳ
-ඩ්‍රෙ
-ඩ්‍රේ
-ඩ්‍රෛ
-ඩ්‍රො
-ඩ්‍රෝ
-ඩ්‍රෞ
-ඩ්‍ර්
-ඩ්‍රං
-ඩ්‍රඃ
-ඩ්‍ය
-ඩ්‍යා
-ඩ්‍යැ
-ඩ්‍යෑ
-ඩ්‍යි
-ඩ්‍යී
-ඩ්‍යු
-ඩ්‍යූ
-ඩ්‍යෘ
-ඩ්‍යෲ
-ඩ්‍යෟ
-ඩ්‍යෳ
-ඩ්‍යෙ
-ඩ්‍යේ
-ඩ්‍යෛ
-ඩ්‍යො
-ඩ්‍යෝ
-ඩ්‍යෞ
-ඩ්‍ය්
-ඩ්‍යං
-ඩ්‍යඃ
-ර්‍ඩ
-ර්‍ඩා
-ර්‍ඩැ
-ර්‍ඩෑ
-ර්‍ඩි
-ර්‍ඩී
-ර්‍ඩු
-ර්‍ඩූ
-ර්‍ඩෘ
-ර්‍ඩෲ
-ර්‍ඩෟ
-ර්‍ඩෳ
-ර්‍ඩෙ
-ර්‍ඩේ
-ර්‍ඩෛ
-ර්‍ඩො
-ර්‍ඩෝ
-ර්‍ඩෞ
-ර්‍ඩ්
-ර්‍ඩං
-ර්‍ඩඃ
-ඪ
-ඪා
-ඪැ
-ඪෑ
-ඪි
-ඪී
-ඪු
-ඪූ
-ඪෘ
-ඪෲ
-ඪෟ
-ඪෳ
-ඪෙ
-ඪේ
-ඪෛ
-ඪො
-ඪෝ
-ඪෞ
-ඪ්
-ඪං
-ඪඃ
-ඪ්‍ර
-ඪ්‍රා
-ඪ්‍රැ
-ඪ්‍රෑ
-ඪ්‍රි
-ඪ්‍රී
-ඪ්‍රු
-ඪ්‍රූ
-ඪ්‍රෘ
-ඪ්‍රෲ
-ඪ්‍රෟ
-ඪ්‍රෳ
-ඪ්‍රෙ
-ඪ්‍රේ
-ඪ්‍රෛ
-ඪ්‍රො
-ඪ්‍රෝ
-ඪ්‍රෞ
-ඪ්‍ර්
-ඪ්‍රං
-ඪ්‍රඃ
-ඪ්‍ය
-ඪ්‍යා
-ඪ්‍යැ
-ඪ්‍යෑ
-ඪ්‍යි
-ඪ්‍යී
-ඪ්‍යු
-ඪ්‍යූ
-ඪ්‍යෘ
-ඪ්‍යෲ
-ඪ්‍යෟ
-ඪ්‍යෳ
-ඪ්‍යෙ
-ඪ්‍යේ
-ඪ්‍යෛ
-ඪ්‍යො
-ඪ්‍යෝ
-ඪ්‍යෞ
-ඪ්‍ය්
-ඪ්‍යං
-ඪ්‍යඃ
-ර්‍ඪ
-ර්‍ඪා
-ර්‍ඪැ
-ර්‍ඪෑ
-ර්‍ඪි
-ර්‍ඪී
-ර්‍ඪු
-ර්‍ඪූ
-ර්‍ඪෘ
-ර්‍ඪෲ
-ර්‍ඪෟ
-ර්‍ඪෳ
-ර්‍ඪෙ
-ර්‍ඪේ
-ර්‍ඪෛ
-ර්‍ඪො
-ර්‍ඪෝ
-ර්‍ඪෞ
-ර්‍ඪ්
-ර්‍ඪං
-ර්‍ඪඃ
-ණ
-ණා
-ණැ
-ණෑ
-ණි
-ණී
-ණු
-ණූ
-ණෘ
-ණෲ
-ණෟ
-ණෳ
-ණෙ
-ණේ
-ණෛ
-ණො
-ණෝ
-ණෞ
-ණ්
-ණං
-ණඃ
-ණ්‍ර
-ණ්‍රා
-ණ්‍රැ
-ණ්‍රෑ
-ණ්‍රි
-ණ්‍රී
-ණ්‍රු
-ණ්‍රූ
-ණ්‍රෘ
-ණ්‍රෲ
-ණ්‍රෟ
-ණ්‍රෳ
-ණ්‍රෙ
-ණ්‍රේ
-ණ්‍රෛ
-ණ්‍රො
-ණ්‍රෝ
-ණ්‍රෞ
-ණ්‍ර්
-ණ්‍රං
-ණ්‍රඃ
-ණ්‍ය
-ණ්‍යා
-ණ්‍යැ
-ණ්‍යෑ
-ණ්‍යි
-ණ්‍යී
-ණ්‍යු
-ණ්‍යූ
-ණ්‍යෘ
-ණ්‍යෲ
-ණ්‍යෟ
-ණ්‍යෳ
-ණ්‍යෙ
-ණ්‍යේ
-ණ්‍යෛ
-ණ්‍යො
-ණ්‍යෝ
-ණ්‍යෞ
-ණ්‍ය්
-ණ්‍යං
-ණ්‍යඃ
-ර්‍ණ
-ර්‍ණා
-ර්‍ණැ
-ර්‍ණෑ
-ර්‍ණි
-ර්‍ණී
-ර්‍ණු
-ර්‍ණූ
-ර්‍ණෘ
-ර්‍ණෲ
-ර්‍ණෟ
-ර්‍ණෳ
-ර්‍ණෙ
-ර්‍ණේ
-ර්‍ණෛ
-ර්‍ණො
-ර්‍ණෝ
-ර්‍ණෞ
-ර්‍ණ්
-ර්‍ණං
-ර්‍ණඃ
-ඬ
-ඬා
-ඬැ
-ඬෑ
-ඬි
-ඬී
-ඬු
-ඬූ
-ඬෘ
-ඬෲ
-ඬෟ
-ඬෳ
-ඬෙ
-ඬේ
-ඬෛ
-ඬො
-ඬෝ
-ඬෞ
-ඬ්
-ඬං
-ඬඃ
-ඬ්‍ර
-ඬ්‍රා
-ඬ්‍රැ
-ඬ්‍රෑ
-ඬ්‍රි
-ඬ්‍රී
-ඬ්‍රු
-ඬ්‍රූ
-ඬ්‍රෘ
-ඬ්‍රෲ
-ඬ්‍රෟ
-ඬ්‍රෳ
-ඬ්‍රෙ
-ඬ්‍රේ
-ඬ්‍රෛ
-ඬ්‍රො
-ඬ්‍රෝ
-ඬ්‍රෞ
-ඬ්‍ර්
-ඬ්‍රං
-ඬ්‍රඃ
-ඬ්‍ය
-ඬ්‍යා
-ඬ්‍යැ
-ඬ්‍යෑ
-ඬ්‍යි
-ඬ්‍යී
-ඬ්‍යු
-ඬ්‍යූ
-ඬ්‍යෘ
-ඬ්‍යෲ
-ඬ්‍යෟ
-ඬ්‍යෳ
-ඬ්‍යෙ
-ඬ්‍යේ
-ඬ්‍යෛ
-ඬ්‍යො
-ඬ්‍යෝ
-ඬ්‍යෞ
-ඬ්‍ය්
-ඬ්‍යං
-ඬ්‍යඃ
-ර්‍ඬ
-ර්‍ඬා
-ර්‍ඬැ
-ර්‍ඬෑ
-ර්‍ඬි
-ර්‍ඬී
-ර්‍ඬු
-ර්‍ඬූ
-ර්‍ඬෘ
-ර්‍ඬෲ
-ර්‍ඬෟ
-ර්‍ඬෳ
-ර්‍ඬෙ
-ර්‍ඬේ
-ර්‍ඬෛ
-ර්‍ඬො
-ර්‍ඬෝ
-ර්‍ඬෞ
-ර්‍ඬ්
-ර්‍ඬං
-ර්‍ඬඃ
-ත
-තා
-තැ
-තෑ
-ති
-තී
-තු
-තූ
-තෘ
-තෲ
-තෟ
-තෳ
-තෙ
-තේ
-තෛ
-තො
-තෝ
-තෞ
-ත්
-තං
-තඃ
-ත්‍ර
-ත්‍රා
-ත්‍රැ
-ත්‍රෑ
-ත්‍රි
-ත්‍රී
-ත්‍රු
-ත්‍රූ
-ත්‍රෘ
-ත්‍රෲ
-ත්‍රෟ
-ත්‍රෳ
-ත්‍රෙ
-ත්‍රේ
-ත්‍රෛ
-ත්‍රො
-ත්‍රෝ
-ත්‍රෞ
-ත්‍ර්
-ත්‍රං
-ත්‍රඃ
-ත්‍ය
-ත්‍යා
-ත්‍යැ
-ත්‍යෑ
-ත්‍යි
-ත්‍යී
-ත්‍යු
-ත්‍යූ
-ත්‍යෘ
-ත්‍යෲ
-ත්‍යෟ
-ත්‍යෳ
-ත්‍යෙ
-ත්‍යේ
-ත්‍යෛ
-ත්‍යො
-ත්‍යෝ
-ත්‍යෞ
-ත්‍ය්
-ත්‍යං
-ත්‍යඃ
-ර්‍ත
-ර්‍තා
-ර්‍තැ
-ර්‍තෑ
-ර්‍ති
-ර්‍තී
-ර්‍තු
-ර්‍තූ
-ර්‍තෘ
-ර්‍තෲ
-ර්‍තෟ
-ර්‍තෳ
-ර්‍තෙ
-ර්‍තේ
-ර්‍තෛ
-ර්‍තො
-ර්‍තෝ
-ර්‍තෞ
-ර්‍ත්
-ර්‍තං
-ර්‍තඃ
-ථ
-ථා
-ථැ
-ථෑ
-ථි
-ථී
-ථු
-ථූ
-ථෘ
-ථෲ
-ථෟ
-ථෳ
-ථෙ
-ථේ
-ථෛ
-ථො
-ථෝ
-ථෞ
-ථ්
-ථං
-ථඃ
-ථ්‍ර
-ථ්‍රා
-ථ්‍රැ
-ථ්‍රෑ
-ථ්‍රි
-ථ්‍රී
-ථ්‍රු
-ථ්‍රූ
-ථ්‍රෘ
-ථ්‍රෲ
-ථ්‍රෟ
-ථ්‍රෳ
-ථ්‍රෙ
-ථ්‍රේ
-ථ්‍රෛ
-ථ්‍රො
-ථ්‍රෝ
-ථ්‍රෞ
-ථ්‍ර්
-ථ්‍රං
-ථ්‍රඃ
-ථ්‍ය
-ථ්‍යා
-ථ්‍යැ
-ථ්‍යෑ
-ථ්‍යි
-ථ්‍යී
-ථ්‍යු
-ථ්‍යූ
-ථ්‍යෘ
-ථ්‍යෲ
-ථ්‍යෟ
-ථ්‍යෳ
-ථ්‍යෙ
-ථ්‍යේ
-ථ්‍යෛ
-ථ්‍යො
-ථ්‍යෝ
-ථ්‍යෞ
-ථ්‍ය්
-ථ්‍යං
-ථ්‍යඃ
-ර්‍ථ
-ර්‍ථා
-ර්‍ථැ
-ර්‍ථෑ
-ර්‍ථි
-ර්‍ථී
-ර්‍ථු
-ර්‍ථූ
-ර්‍ථෘ
-ර්‍ථෲ
-ර්‍ථෟ
-ර්‍ථෳ
-ර්‍ථෙ
-ර්‍ථේ
-ර්‍ථෛ
-ර්‍ථො
-ර්‍ථෝ
-ර්‍ථෞ
-ර්‍ථ්
-ර්‍ථං
-ර්‍ථඃ
-ද
-දා
-දැ
-දෑ
-දි
-දී
-දු
-දූ
-දෘ
-දෲ
-දෟ
-දෳ
-දෙ
-දේ
-දෛ
-දො
-දෝ
-දෞ
-ද්
-දං
-දඃ
-ද්‍ර
-ද්‍රා
-ද්‍රැ
-ද්‍රෑ
-ද්‍රි
-ද්‍රී
-ද්‍රු
-ද්‍රූ
-ද්‍රෘ
-ද්‍රෲ
-ද්‍රෟ
-ද්‍රෳ
-ද්‍රෙ
-ද්‍රේ
-ද්‍රෛ
-ද්‍රො
-ද්‍රෝ
-ද්‍රෞ
-ද්‍ර්
-ද්‍රං
-ද්‍රඃ
-ද්‍ය
-ද්‍යා
-ද්‍යැ
-ද්‍යෑ
-ද්‍යි
-ද්‍යී
-ද්‍යු
-ද්‍යූ
-ද්‍යෘ
-ද්‍යෲ
-ද්‍යෟ
-ද්‍යෳ
-ද්‍යෙ
-ද්‍යේ
-ද්‍යෛ
-ද්‍යො
-ද්‍යෝ
-ද්‍යෞ
-ද්‍ය්
-ද්‍යං
-ද්‍යඃ
-ර්‍ද
-ර්‍දා
-ර්‍දැ
-ර්‍දෑ
-ර්‍දි
-ර්‍දී
-ර්‍දු
-ර්‍දූ
-ර්‍දෘ
-ර්‍දෲ
-ර්‍දෟ
-ර්‍දෳ
-ර්‍දෙ
-ර්‍දේ
-ර්‍දෛ
-ර්‍දො
-ර්‍දෝ
-ර්‍දෞ
-ර්‍ද්
-ර්‍දං
-ර්‍දඃ
-ධ
-ධා
-ධැ
-ධෑ
-ධි
-ධී
-ධු
-ධූ
-ධෘ
-ධෲ
-ධෟ
-ධෳ
-ධෙ
-ධේ
-ධෛ
-ධො
-ධෝ
-ධෞ
-ධ්
-ධං
-ධඃ
-ධ්‍ර
-ධ්‍රා
-ධ්‍රැ
-ධ්‍රෑ
-ධ්‍රි
-ධ්‍රී
-ධ්‍රු
-ධ්‍රූ
-ධ්‍රෘ
-ධ්‍රෲ
-ධ්‍රෟ
-ධ්‍රෳ
-ධ්‍රෙ
-ධ්‍රේ
-ධ්‍රෛ
-ධ්‍රො
-ධ්‍රෝ
-ධ්‍රෞ
-ධ්‍ර්
-ධ්‍රං
-ධ්‍රඃ
-ධ්‍ය
-ධ්‍යා
-ධ්‍යැ
-ධ්‍යෑ
-ධ්‍යි
-ධ්‍යී
-ධ්‍යු
-ධ්‍යූ
-ධ්‍යෘ
-ධ්‍යෲ
-ධ්‍යෟ
-ධ්‍යෳ
-ධ්‍යෙ
-ධ්‍යේ
-ධ්‍යෛ
-ධ්‍යො
-ධ්‍යෝ
-ධ්‍යෞ
-ධ්‍ය්
-ධ්‍යං
-ධ්‍යඃ
-ර්‍ධ
-ර්‍ධා
-ර්‍ධැ
-ර්‍ධෑ
-ර්‍ධි
-ර්‍ධී
-ර්‍ධු
-ර්‍ධූ
-ර්‍ධෘ
-ර්‍ධෲ
-ර්‍ධෟ
-ර්‍ධෳ
-ර්‍ධෙ
-ර්‍ධේ
-ර්‍ධෛ
-ර්‍ධො
-ර්‍ධෝ
-ර්‍ධෞ
-ර්‍ධ්
-ර්‍ධං
-ර්‍ධඃ
-න
-නා
-නැ
-නෑ
-නි
-නී
-නු
-නූ
-නෘ
-නෲ
-නෟ
-නෳ
-නෙ
-නේ
-නෛ
-නො
-නෝ
-නෞ
-න්
-නං
-නඃ
-න්‍ර
-න්‍රා
-න්‍රැ
-න්‍රෑ
-න්‍රි
-න්‍රී
-න්‍රු
-න්‍රූ
-න්‍රෘ
-න්‍රෲ
-න්‍රෟ
-න්‍රෳ
-න්‍රෙ
-න්‍රේ
-න්‍රෛ
-න්‍රො
-න්‍රෝ
-න්‍රෞ
-න්‍ර්
-න්‍රං
-න්‍රඃ
-න්‍ය
-න්‍යා
-න්‍යැ
-න්‍යෑ
-න්‍යි
-න්‍යී
-න්‍යු
-න්‍යූ
-න්‍යෘ
-න්‍යෲ
-න්‍යෟ
-න්‍යෳ
-න්‍යෙ
-න්‍යේ
-න්‍යෛ
-න්‍යො
-න්‍යෝ
-න්‍යෞ
-න්‍ය්
-න්‍යං
-න්‍යඃ
-ර්‍න
-ර්‍නා
-ර්‍නැ
-ර්‍නෑ
-ර්‍නි
-ර්‍නී
-ර්‍නු
-ර්‍නූ
-ර්‍නෘ
-ර්‍නෲ
-ර්‍නෟ
-ර්‍නෳ
-ර්‍නෙ
-ර්‍නේ
-ර්‍නෛ
-ර්‍නො
-ර්‍නෝ
-ර්‍නෞ
-ර්‍න්
-ර්‍නං
-ර්‍නඃ
-ඳ
-ඳා
-ඳැ
-ඳෑ
-ඳි
-ඳී
-ඳු
-ඳූ
-ඳෘ
-ඳෲ
-ඳෟ
-ඳෳ
-ඳෙ
-ඳේ
-ඳෛ
-ඳො
-ඳෝ
-ඳෞ
-ඳ්
-ඳං
-ඳඃ
-ඳ්‍ර
-ඳ්‍රා
-ඳ්‍රැ
-ඳ්‍රෑ
-ඳ්‍රි
-ඳ්‍රී
-ඳ්‍රු
-ඳ්‍රූ
-ඳ්‍රෘ
-ඳ්‍රෲ
-ඳ්‍රෟ
-ඳ්‍රෳ
-ඳ්‍රෙ
-ඳ්‍රේ
-ඳ්‍රෛ
-ඳ්‍රො
-ඳ්‍රෝ
-ඳ්‍රෞ
-ඳ්‍ර්
-ඳ්‍රං
-ඳ්‍රඃ
-ඳ්‍ය
-ඳ්‍යා
-ඳ්‍යැ
-ඳ්‍යෑ
-ඳ්‍යි
-ඳ්‍යී
-ඳ්‍යු
-ඳ්‍යූ
-ඳ්‍යෘ
-ඳ්‍යෲ
-ඳ්‍යෟ
-ඳ්‍යෳ
-ඳ්‍යෙ
-ඳ්‍යේ
-ඳ්‍යෛ
-ඳ්‍යො
-ඳ්‍යෝ
-ඳ්‍යෞ
-ඳ්‍ය්
-ඳ්‍යං
-ඳ්‍යඃ
-ර්‍ඳ
-ර්‍ඳා
-ර්‍ඳැ
-ර්‍ඳෑ
-ර්‍ඳි
-ර්‍ඳී
-ර්‍ඳු
-ර්‍ඳූ
-ර්‍ඳෘ
-ර්‍ඳෲ
-ර්‍ඳෟ
-ර්‍ඳෳ
-ර්‍ඳෙ
-ර්‍ඳේ
-ර්‍ඳෛ
-ර්‍ඳො
-ර්‍ඳෝ
-ර්‍ඳෞ
-ර්‍ඳ්
-ර්‍ඳං
-ර්‍ඳඃ
-ප
-පා
-පැ
-පෑ
-පි
-පී
-පු
-පූ
-පෘ
-පෲ
-පෟ
-පෳ
-පෙ
-පේ
-පෛ
-පො
-පෝ
-පෞ
-ප්
-පං
-පඃ
-ප්‍ර
-ප්‍රා
-ප්‍රැ
-ප්‍රෑ
-ප්‍රි
-ප්‍රී
-ප්‍රු
-ප්‍රූ
-ප්‍රෘ
-ප්‍රෲ
-ප්‍රෟ
-ප්‍රෳ
-ප්‍රෙ
-ප්‍රේ
-ප්‍රෛ
-ප්‍රො
-ප්‍රෝ
-ප්‍රෞ
-ප්‍ර්
-ප්‍රං
-ප්‍රඃ
-ප්‍ය
-ප්‍යා
-ප්‍යැ
-ප්‍යෑ
-ප්‍යි
-ප්‍යී
-ප්‍යු
-ප්‍යූ
-ප්‍යෘ
-ප්‍යෲ
-ප්‍යෟ
-ප්‍යෳ
-ප්‍යෙ
-ප්‍යේ
-ප්‍යෛ
-ප්‍යො
-ප්‍යෝ
-ප්‍යෞ
-ප්‍ය්
-ප්‍යං
-ප්‍යඃ
-ර්‍ප
-ර්‍පා
-ර්‍පැ
-ර්‍පෑ
-ර්‍පි
-ර්‍පී
-ර්‍පු
-ර්‍පූ
-ර්‍පෘ
-ර්‍පෲ
-ර්‍පෟ
-ර්‍පෳ
-ර්‍පෙ
-ර්‍පේ
-ර්‍පෛ
-ර්‍පො
-ර්‍පෝ
-ර්‍පෞ
-ර්‍ප්
-ර්‍පං
-ර්‍පඃ
-ඵ
-ඵා
-ඵැ
-ඵෑ
-ඵි
-ඵී
-ඵු
-ඵූ
-ඵෘ
-ඵෲ
-ඵෟ
-ඵෳ
-ඵෙ
-ඵේ
-ඵෛ
-ඵො
-ඵෝ
-ඵෞ
-ඵ්
-ඵං
-ඵඃ
-ඵ්‍ර
-ඵ්‍රා
-ඵ්‍රැ
-ඵ්‍රෑ
-ඵ්‍රි
-ඵ්‍රී
-ඵ්‍රු
-ඵ්‍රූ
-ඵ්‍රෘ
-ඵ්‍රෲ
-ඵ්‍රෟ
-ඵ්‍රෳ
-ඵ්‍රෙ
-ඵ්‍රේ
-ඵ්‍රෛ
-ඵ්‍රො
-ඵ්‍රෝ
-ඵ්‍රෞ
-ඵ්‍ර්
-ඵ්‍රං
-ඵ්‍රඃ
-ඵ්‍ය
-ඵ්‍යා
-ඵ්‍යැ
-ඵ්‍යෑ
-ඵ්‍යි
-ඵ්‍යී
-ඵ්‍යු
-ඵ්‍යූ
-ඵ්‍යෘ
-ඵ්‍යෲ
-ඵ්‍යෟ
-ඵ්‍යෳ
-ඵ්‍යෙ
-ඵ්‍යේ
-ඵ්‍යෛ
-ඵ්‍යො
-ඵ්‍යෝ
-ඵ්‍යෞ
-ඵ්‍ය්
-ඵ්‍යං
-ඵ්‍යඃ
-ර්‍ඵ
-ර්‍ඵා
-ර්‍ඵැ
-ර්‍ඵෑ
-ර්‍ඵි
-ර්‍ඵී
-ර්‍ඵු
-ර්‍ඵූ
-ර්‍ඵෘ
-ර්‍ඵෲ
-ර්‍ඵෟ
-ර්‍ඵෳ
-ර්‍ඵෙ
-ර්‍ඵේ
-ර්‍ඵෛ
-ර්‍ඵො
-ර්‍ඵෝ
-ර්‍ඵෞ
-ර්‍ඵ්
-ර්‍ඵං
-ර්‍ඵඃ
-බ
-බා
-බැ
-බෑ
-බි
-බී
-බු
-බූ
-බෘ
-බෲ
-බෟ
-බෳ
-බෙ
-බේ
-බෛ
-බො
-බෝ
-බෞ
-බ්
-බං
-බඃ
-බ්‍ර
-බ්‍රා
-බ්‍රැ
-බ්‍රෑ
-බ්‍රි
-බ්‍රී
-බ්‍රු
-බ්‍රූ
-බ්‍රෘ
-බ්‍රෲ
-බ්‍රෟ
-බ්‍රෳ
-බ්‍රෙ
-බ්‍රේ
-බ්‍රෛ
-බ්‍රො
-බ්‍රෝ
-බ්‍රෞ
-බ්‍ර්
-බ්‍රං
-බ්‍රඃ
-බ්‍ය
-බ්‍යා
-බ්‍යැ
-බ්‍යෑ
-බ්‍යි
-බ්‍යී
-බ්‍යු
-බ්‍යූ
-බ්‍යෘ
-බ්‍යෲ
-බ්‍යෟ
-බ්‍යෳ
-බ්‍යෙ
-බ්‍යේ
-බ්‍යෛ
-බ්‍යො
-බ්‍යෝ
-බ්‍යෞ
-බ්‍ය්
-බ්‍යං
-බ්‍යඃ
-ර්‍බ
-ර්‍බා
-ර්‍බැ
-ර්‍බෑ
-ර්‍බි
-ර්‍බී
-ර්‍බු
-ර්‍බූ
-ර්‍බෘ
-ර්‍බෲ
-ර්‍බෟ
-ර්‍බෳ
-ර්‍බෙ
-ර්‍බේ
-ර්‍බෛ
-ර්‍බො
-ර්‍බෝ
-ර්‍බෞ
-ර්‍බ්
-ර්‍බං
-ර්‍බඃ
-භ
-භා
-භැ
-භෑ
-භි
-භී
-භු
-භූ
-භෘ
-භෲ
-භෟ
-භෳ
-භෙ
-භේ
-භෛ
-භො
-භෝ
-භෞ
-භ්
-භං
-භඃ
-භ්‍ර
-භ්‍රා
-භ්‍රැ
-භ්‍රෑ
-භ්‍රි
-භ්‍රී
-භ්‍රු
-භ්‍රූ
-භ්‍රෘ
-භ්‍රෲ
-භ්‍රෟ
-භ්‍රෳ
-භ්‍රෙ
-භ්‍රේ
-භ්‍රෛ
-භ්‍රො
-භ්‍රෝ
-භ්‍රෞ
-භ්‍ර්
-භ්‍රං
-භ්‍රඃ
-භ්‍ය
-භ්‍යා
-භ්‍යැ
-භ්‍යෑ
-භ්‍යි
-භ්‍යී
-භ්‍යු
-භ්‍යූ
-භ්‍යෘ
-භ්‍යෲ
-භ්‍යෟ
-භ්‍යෳ
-භ්‍යෙ
-භ්‍යේ
-භ්‍යෛ
-භ්‍යො
-භ්‍යෝ
-භ්‍යෞ
-භ්‍ය්
-භ්‍යං
-භ්‍යඃ
-ර්‍භ
-ර්‍භා
-ර්‍භැ
-ර්‍භෑ
-ර්‍භි
-ර්‍භී
-ර්‍භු
-ර්‍භූ
-ර්‍භෘ
-ර්‍භෲ
-ර්‍භෟ
-ර්‍භෳ
-ර්‍භෙ
-ර්‍භේ
-ර්‍භෛ
-ර්‍භො
-ර්‍භෝ
-ර්‍භෞ
-ර්‍භ්
-ර්‍භං
-ර්‍භඃ
-ම
-මා
-මැ
-මෑ
-මි
-මී
-මු
-මූ
-මෘ
-මෲ
-මෟ
-මෳ
-මෙ
-මේ
-මෛ
-මො
-මෝ
-මෞ
-ම්
-මං
-මඃ
-ම්‍ර
-ම්‍රා
-ම්‍රැ
-ම්‍රෑ
-ම්‍රි
-ම්‍රී
-ම්‍රු
-ම්‍රූ
-ම්‍රෘ
-ම්‍රෲ
-ම්‍රෟ
-ම්‍රෳ
-ම්‍රෙ
-ම්‍රේ
-ම්‍රෛ
-ම්‍රො
-ම්‍රෝ
-ම්‍රෞ
-ම්‍ර්
-ම්‍රං
-ම්‍රඃ
-ම්‍ය
-ම්‍යා
-ම්‍යැ
-ම්‍යෑ
-ම්‍යි
-ම්‍යී
-ම්‍යු
-ම්‍යූ
-ම්‍යෘ
-ම්‍යෲ
-ම්‍යෟ
-ම්‍යෳ
-ම්‍යෙ
-ම්‍යේ
-ම්‍යෛ
-ම්‍යො
-ම්‍යෝ
-ම්‍යෞ
-ම්‍ය්
-ම්‍යං
-ම්‍යඃ
-ර්‍ම
-ර්‍මා
-ර්‍මැ
-ර්‍මෑ
-ර්‍මි
-ර්‍මී
-ර්‍මු
-ර්‍මූ
-ර්‍මෘ
-ර්‍මෲ
-ර්‍මෟ
-ර්‍මෳ
-ර්‍මෙ
-ර්‍මේ
-ර්‍මෛ
-ර්‍මො
-ර්‍මෝ
-ර්‍මෞ
-ර්‍ම්
-ර්‍මං
-ර්‍මඃ
-ඹ
-ඹා
-ඹැ
-ඹෑ
-ඹි
-ඹී
-ඹු
-ඹූ
-ඹෘ
-ඹෲ
-ඹෟ
-ඹෳ
-ඹෙ
-ඹේ
-ඹෛ
-ඹො
-ඹෝ
-ඹෞ
-ඹ්
-ඹං
-ඹඃ
-ඹ්‍ර
-ඹ්‍රා
-ඹ්‍රැ
-ඹ්‍රෑ
-ඹ්‍රි
-ඹ්‍රී
-ඹ්‍රු
-ඹ්‍රූ
-ඹ්‍රෘ
-ඹ්‍රෲ
-ඹ්‍රෟ
-ඹ්‍රෳ
-ඹ්‍රෙ
-ඹ්‍රේ
-ඹ්‍රෛ
-ඹ්‍රො
-ඹ්‍රෝ
-ඹ්‍රෞ
-ඹ්‍ර්
-ඹ්‍රං
-ඹ්‍රඃ
-ඹ්‍ය
-ඹ්‍යා
-ඹ්‍යැ
-ඹ්‍යෑ
-ඹ්‍යි
-ඹ්‍යී
-ඹ්‍යු
-ඹ්‍යූ
-ඹ්‍යෘ
-ඹ්‍යෲ
-ඹ්‍යෟ
-ඹ්‍යෳ
-ඹ්‍යෙ
-ඹ්‍යේ
-ඹ්‍යෛ
-ඹ්‍යො
-ඹ්‍යෝ
-ඹ්‍යෞ
-ඹ්‍ය්
-ඹ්‍යං
-ඹ්‍යඃ
-ර්‍ඹ
-ර්‍ඹා
-ර්‍ඹැ
-ර්‍ඹෑ
-ර්‍ඹි
-ර්‍ඹී
-ර්‍ඹු
-ර්‍ඹූ
-ර්‍ඹෘ
-ර්‍ඹෲ
-ර්‍ඹෟ
-ර්‍ඹෳ
-ර්‍ඹෙ
-ර්‍ඹේ
-ර්‍ඹෛ
-ර්‍ඹො
-ර්‍ඹෝ
-ර්‍ඹෞ
-ර්‍ඹ්
-ර්‍ඹං
-ර්‍ඹඃ
-ය
-යා
-යැ
-යෑ
-යි
-යී
-යු
-යූ
-යෘ
-යෲ
-යෟ
-යෳ
-යෙ
-යේ
-යෛ
-යො
-යෝ
-යෞ
-ය්
-යං
-යඃ
-ය්‍ර
-ය්‍රා
-ය්‍රැ
-ය්‍රෑ
-ය්‍රි
-ය්‍රී
-ය්‍රු
-ය්‍රූ
-ය්‍රෘ
-ය්‍රෲ
-ය්‍රෟ
-ය්‍රෳ
-ය්‍රෙ
-ය්‍රේ
-ය්‍රෛ
-ය්‍රො
-ය්‍රෝ
-ය්‍රෞ
-ය්‍ර්
-ය්‍රං
-ය්‍රඃ
-ය්‍ය
-ය්‍යා
-ය්‍යැ
-ය්‍යෑ
-ය්‍යි
-ය්‍යී
-ය්‍යු
-ය්‍යූ
-ය්‍යෘ
-ය්‍යෲ
-ය්‍යෟ
-ය්‍යෳ
-ය්‍යෙ
-ය්‍යේ
-ය්‍යෛ
-ය්‍යො
-ය්‍යෝ
-ය්‍යෞ
-ය්‍ය්
-ය්‍යං
-ය්‍යඃ
-ර්‍ය
-ර්‍යා
-ර්‍යැ
-ර්‍යෑ
-ර්‍යි
-ර්‍යී
-ර්‍යු
-ර්‍යූ
-ර්‍යෘ
-ර්‍යෲ
-ර්‍යෟ
-ර්‍යෳ
-ර්‍යෙ
-ර්‍යේ
-ර්‍යෛ
-ර්‍යො
-ර්‍යෝ
-ර්‍යෞ
-ර්‍ය්
-ර්‍යං
-ර්‍යඃ
-ර
-රා
-රැ
-රෑ
-රි
-රී
-රු
-රූ
-රෘ
-රෲ
-රෟ
-රෳ
-රෙ
-රේ
-රෛ
-රො
-රෝ
-රෞ
-ර්
-රං
-රඃ
-ර්‍ර
-ර්‍රා
-ර්‍රැ
-ර්‍රෑ
-ර්‍රි
-ර්‍රී
-ර්‍රු
-ර්‍රූ
-ර්‍රෘ
-ර්‍රෲ
-ර්‍රෟ
-ර්‍රෳ
-ර්‍රෙ
-ර්‍රේ
-ර්‍රෛ
-ර්‍රො
-ර්‍රෝ
-ර්‍රෞ
-ර්‍ර්
-ර්‍රං
-ර්‍රඃ
-ර්‍ය
-ර්‍යා
-ර්‍යැ
-ර්‍යෑ
-ර්‍යි
-ර්‍යී
-ර්‍යු
-ර්‍යූ
-ර්‍යෘ
-ර්‍යෲ
-ර්‍යෟ
-ර්‍යෳ
-ර්‍යෙ
-ර්‍යේ
-ර්‍යෛ
-ර්‍යො
-ර්‍යෝ
-ර්‍යෞ
-ර්‍ය්
-ර්‍යං
-ර්‍යඃ
-ර්‍ර
-ර්‍රා
-ර්‍රැ
-ර්‍රෑ
-ර්‍රි
-ර්‍රී
-ර්‍රු
-ර්‍රූ
-ර්‍රෘ
-ර්‍රෲ
-ර්‍රෟ
-ර්‍රෳ
-ර්‍රෙ
-ර්‍රේ
-ර්‍රෛ
-ර්‍රො
-ර්‍රෝ
-ර්‍රෞ
-ර්‍ර්
-ර්‍රං
-ර්‍රඃ
-ල
-ලා
-ලැ
-ලෑ
-ලි
-ලී
-ලු
-ලූ
-ලෘ
-ලෲ
-ලෟ
-ලෳ
-ලෙ
-ලේ
-ලෛ
-ලො
-ලෝ
-ලෞ
-ල්
-ලං
-ලඃ
-ල්‍ර
-ල්‍රා
-ල්‍රැ
-ල්‍රෑ
-ල්‍රි
-ල්‍රී
-ල්‍රු
-ල්‍රූ
-ල්‍රෘ
-ල්‍රෲ
-ල්‍රෟ
-ල්‍රෳ
-ල්‍රෙ
-ල්‍රේ
-ල්‍රෛ
-ල්‍රො
-ල්‍රෝ
-ල්‍රෞ
-ල්‍ර්
-ල්‍රං
-ල්‍රඃ
-ල්‍ය
-ල්‍යා
-ල්‍යැ
-ල්‍යෑ
-ල්‍යි
-ල්‍යී
-ල්‍යු
-ල්‍යූ
-ල්‍යෘ
-ල්‍යෲ
-ල්‍යෟ
-ල්‍යෳ
-ල්‍යෙ
-ල්‍යේ
-ල්‍යෛ
-ල්‍යො
-ල්‍යෝ
-ල්‍යෞ
-ල්‍ය්
-ල්‍යං
-ල්‍යඃ
-ර්‍ල
-ර්‍ලා
-ර්‍ලැ
-ර්‍ලෑ
-ර්‍ලි
-ර්‍ලී
-ර්‍ලු
-ර්‍ලූ
-ර්‍ලෘ
-ර්‍ලෲ
-ර්‍ලෟ
-ර්‍ලෳ
-ර්‍ලෙ
-ර්‍ලේ
-ර්‍ලෛ
-ර්‍ලො
-ර්‍ලෝ
-ර්‍ලෞ
-ර්‍ල්
-ර්‍ලං
-ර්‍ලඃ
-ව
-වා
-වැ
-වෑ
-වි
-වී
-වු
-වූ
-වෘ
-වෲ
-වෟ
-වෳ
-වෙ
-වේ
-වෛ
-වො
-වෝ
-වෞ
-ව්
-වං
-වඃ
-ව්‍ර
-ව්‍රා
-ව්‍රැ
-ව්‍රෑ
-ව්‍රි
-ව්‍රී
-ව්‍රු
-ව්‍රූ
-ව්‍රෘ
-ව්‍රෲ
-ව්‍රෟ
-ව්‍රෳ
-ව්‍රෙ
-ව්‍රේ
-ව්‍රෛ
-ව්‍රො
-ව්‍රෝ
-ව්‍රෞ
-ව්‍ර්
-ව්‍රං
-ව්‍රඃ
-ව්‍ය
-ව්‍යා
-ව්‍යැ
-ව්‍යෑ
-ව්‍යි
-ව්‍යී
-ව්‍යු
-ව්‍යූ
-ව්‍යෘ
-ව්‍යෲ
-ව්‍යෟ
-ව්‍යෳ
-ව්‍යෙ
-ව්‍යේ
-ව්‍යෛ
-ව්‍යො
-ව්‍යෝ
-ව්‍යෞ
-ව්‍ය්
-ව්‍යං
-ව්‍යඃ
-ර්‍ව
-ර්‍වා
-ර්‍වැ
-ර්‍වෑ
-ර්‍වි
-ර්‍වී
-ර්‍වු
-ර්‍වූ
-ර්‍වෘ
-ර්‍වෲ
-ර්‍වෟ
-ර්‍වෳ
-ර්‍වෙ
-ර්‍වේ
-ර්‍වෛ
-ර්‍වො
-ර්‍වෝ
-ර්‍වෞ
-ර්‍ව්
-ර්‍වං
-ර්‍වඃ
-ශ
-ශා
-ශැ
-ශෑ
-ශි
-ශී
-ශු
-ශූ
-ශෘ
-ශෲ
-ශෟ
-ශෳ
-ශෙ
-ශේ
-ශෛ
-ශො
-ශෝ
-ශෞ
-ශ්
-ශං
-ශඃ
-ශ්‍ර
-ශ්‍රා
-ශ්‍රැ
-ශ්‍රෑ
-ශ්‍රි
-ශ්‍රී
-ශ්‍රු
-ශ්‍රූ
-ශ්‍රෘ
-ශ්‍රෲ
-ශ්‍රෟ
-ශ්‍රෳ
-ශ්‍රෙ
-ශ්‍රේ
-ශ්‍රෛ
-ශ්‍රො
-ශ්‍රෝ
-ශ්‍රෞ
-ශ්‍ර්
-ශ්‍රං
-ශ්‍රඃ
-ශ්‍ය
-ශ්‍යා
-ශ්‍යැ
-ශ්‍යෑ
-ශ්‍යි
-ශ්‍යී
-ශ්‍යු
-ශ්‍යූ
-ශ්‍යෘ
-ශ්‍යෲ
-ශ්‍යෟ
-ශ්‍යෳ
-ශ්‍යෙ
-ශ්‍යේ
-ශ්‍යෛ
-ශ්‍යො
-ශ්‍යෝ
-ශ්‍යෞ
-ශ්‍ය්
-ශ්‍යං
-ශ්‍යඃ
-ර්‍ශ
-ර්‍ශා
-ර්‍ශැ
-ර්‍ශෑ
-ර්‍ශි
-ර්‍ශී
-ර්‍ශු
-ර්‍ශූ
-ර්‍ශෘ
-ර්‍ශෲ
-ර්‍ශෟ
-ර්‍ශෳ
-ර්‍ශෙ
-ර්‍ශේ
-ර්‍ශෛ
-ර්‍ශො
-ර්‍ශෝ
-ර්‍ශෞ
-ර්‍ශ්
-ර්‍ශං
-ර්‍ශඃ
-ෂ
-ෂා
-ෂැ
-ෂෑ
-ෂි
-ෂී
-ෂු
-ෂූ
-ෂෘ
-ෂෲ
-ෂෟ
-ෂෳ
-ෂෙ
-ෂේ
-ෂෛ
-ෂො
-ෂෝ
-ෂෞ
-ෂ්
-ෂං
-ෂඃ
-ෂ්‍ර
-ෂ්‍රා
-ෂ්‍රැ
-ෂ්‍රෑ
-ෂ්‍රි
-ෂ්‍රී
-ෂ්‍රු
-ෂ්‍රූ
-ෂ්‍රෘ
-ෂ්‍රෲ
-ෂ්‍රෟ
-ෂ්‍රෳ
-ෂ්‍රෙ
-ෂ්‍රේ
-ෂ්‍රෛ
-ෂ්‍රො
-ෂ්‍රෝ
-ෂ්‍රෞ
-ෂ්‍ර්
-ෂ්‍රං
-ෂ්‍රඃ
-ෂ්‍ය
-ෂ්‍යා
-ෂ්‍යැ
-ෂ්‍යෑ
-ෂ්‍යි
-ෂ්‍යී
-ෂ්‍යු
-ෂ්‍යූ
-ෂ්‍යෘ
-ෂ්‍යෲ
-ෂ්‍යෟ
-ෂ්‍යෳ
-ෂ්‍යෙ
-ෂ්‍යේ
-ෂ්‍යෛ
-ෂ්‍යො
-ෂ්‍යෝ
-ෂ්‍යෞ
-ෂ්‍ය්
-ෂ්‍යං
-ෂ්‍යඃ
-ර්‍ෂ
-ර්‍ෂා
-ර්‍ෂැ
-ර්‍ෂෑ
-ර්‍ෂි
-ර්‍ෂී
-ර්‍ෂු
-ර්‍ෂූ
-ර්‍ෂෘ
-ර්‍ෂෲ
-ර්‍ෂෟ
-ර්‍ෂෳ
-ර්‍ෂෙ
-ර්‍ෂේ
-ර්‍ෂෛ
-ර්‍ෂො
-ර්‍ෂෝ
-ර්‍ෂෞ
-ර්‍ෂ්
-ර්‍ෂං
-ර්‍ෂඃ
-ස
-සා
-සැ
-සෑ
-සි
-සී
-සු
-සූ
-සෘ
-සෲ
-සෟ
-සෳ
-සෙ
-සේ
-සෛ
-සො
-සෝ
-සෞ
-ස්
-සං
-සඃ
-ස්‍ර
-ස්‍රා
-ස්‍රැ
-ස්‍රෑ
-ස්‍රි
-ස්‍රී
-ස්‍රු
-ස්‍රූ
-ස්‍රෘ
-ස්‍රෲ
-ස්‍රෟ
-ස්‍රෳ
-ස්‍රෙ
-ස්‍රේ
-ස්‍රෛ
-ස්‍රො
-ස්‍රෝ
-ස්‍රෞ
-ස්‍ර්
-ස්‍රං
-ස්‍රඃ
-ස්‍ය
-ස්‍යා
-ස්‍යැ
-ස්‍යෑ
-ස්‍යි
-ස්‍යී
-ස්‍යු
-ස්‍යූ
-ස්‍යෘ
-ස්‍යෲ
-ස්‍යෟ
-ස්‍යෳ
-ස්‍යෙ
-ස්‍යේ
-ස්‍යෛ
-ස්‍යො
-ස්‍යෝ
-ස්‍යෞ
-ස්‍ය්
-ස්‍යං
-ස්‍යඃ
-ර්‍ස
-ර්‍සා
-ර්‍සැ
-ර්‍සෑ
-ර්‍සි
-ර්‍සී
-ර්‍සු
-ර්‍සූ
-ර්‍සෘ
-ර්‍සෲ
-ර්‍සෟ
-ර්‍සෳ
-ර්‍සෙ
-ර්‍සේ
-ර්‍සෛ
-ර්‍සො
-ර්‍සෝ
-ර්‍සෞ
-ර්‍ස්
-ර්‍සං
-ර්‍සඃ
-හ
-හා
-හැ
-හෑ
-හි
-හී
-හු
-හූ
-හෘ
-හෲ
-හෟ
-හෳ
-හෙ
-හේ
-හෛ
-හො
-හෝ
-හෞ
-හ්
-හං
-හඃ
-හ්‍ර
-හ්‍රා
-හ්‍රැ
-හ්‍රෑ
-හ්‍රි
-හ්‍රී
-හ්‍රු
-හ්‍රූ
-හ්‍රෘ
-හ්‍රෲ
-හ්‍රෟ
-හ්‍රෳ
-හ්‍රෙ
-හ්‍රේ
-හ්‍රෛ
-හ්‍රො
-හ්‍රෝ
-හ්‍රෞ
-හ්‍ර්
-හ්‍රං
-හ්‍රඃ
-හ්‍ය
-හ්‍යා
-හ්‍යැ
-හ්‍යෑ
-හ්‍යි
-හ්‍යී
-හ්‍යු
-හ්‍යූ
-හ්‍යෘ
-හ්‍යෲ
-හ්‍යෟ
-හ්‍යෳ
-හ්‍යෙ
-හ්‍යේ
-හ්‍යෛ
-හ්‍යො
-හ්‍යෝ
-හ්‍යෞ
-හ්‍ය්
-හ්‍යං
-හ්‍යඃ
-ර්‍හ
-ර්‍හා
-ර්‍හැ
-ර්‍හෑ
-ර්‍හි
-ර්‍හී
-ර්‍හු
-ර්‍හූ
-ර්‍හෘ
-ර්‍හෲ
-ර්‍හෟ
-ර්‍හෳ
-ර්‍හෙ
-ර්‍හේ
-ර්‍හෛ
-ර්‍හො
-ර්‍හෝ
-ර්‍හෞ
-ර්‍හ්
-ර්‍හං
-ර්‍හඃ
-ළ
-ළා
-ළැ
-ළෑ
-ළි
-ළී
-ළු
-ළූ
-ළෘ
-ළෲ
-ළෟ
-ළෳ
-ළෙ
-ළේ
-ළෛ
-ළො
-ළෝ
-ළෞ
-ළ්
-ළං
-ළඃ
-ළ්‍ර
-ළ්‍රා
-ළ්‍රැ
-ළ්‍රෑ
-ළ්‍රි
-ළ්‍රී
-ළ්‍රු
-ළ්‍රූ
-ළ්‍රෘ
-ළ්‍රෲ
-ළ්‍රෟ
-ළ්‍රෳ
-ළ්‍රෙ
-ළ්‍රේ
-ළ්‍රෛ
-ළ්‍රො
-ළ්‍රෝ
-ළ්‍රෞ
-ළ්‍ර්
-ළ්‍රං
-ළ්‍රඃ
-ළ්‍ය
-ළ්‍යා
-ළ්‍යැ
-ළ්‍යෑ
-ළ්‍යි
-ළ්‍යී
-ළ්‍යු
-ළ්‍යූ
-ළ්‍යෘ
-ළ්‍යෲ
-ළ්‍යෟ
-ළ්‍යෳ
-ළ්‍යෙ
-ළ්‍යේ
-ළ්‍යෛ
-ළ්‍යො
-ළ්‍යෝ
-ළ්‍යෞ
-ළ්‍ය්
-ළ්‍යං
-ළ්‍යඃ
-ර්‍ළ
-ර්‍ළා
-ර්‍ළැ
-ර්‍ළෑ
-ර්‍ළි
-ර්‍ළී
-ර්‍ළු
-ර්‍ළූ
-ර්‍ළෘ
-ර්‍ළෲ
-ර්‍ළෟ
-ර්‍ළෳ
-ර්‍ළෙ
-ර්‍ළේ
-ර්‍ළෛ
-ර්‍ළො
-ර්‍ළෝ
-ර්‍ළෞ
-ර්‍ළ්
-ර්‍ළං
-ර්‍ළඃ
-ෆ
-ෆා
-ෆැ
-ෆෑ
-ෆි
-ෆී
-ෆු
-ෆූ
-ෆෘ
-ෆෲ
-ෆෟ
-ෆෳ
-ෆෙ
-ෆේ
-ෆෛ
-ෆො
-ෆෝ
-ෆෞ
-ෆ්
-ෆං
-ෆඃ
-ෆ්‍ර
-ෆ්‍රා
-ෆ්‍රැ
-ෆ්‍රෑ
-ෆ්‍රි
-ෆ්‍රී
-ෆ්‍රු
-ෆ්‍රූ
-ෆ්‍රෘ
-ෆ්‍රෲ
-ෆ්‍රෟ
-ෆ්‍රෳ
-ෆ්‍රෙ
-ෆ්‍රේ
-ෆ්‍රෛ
-ෆ්‍රො
-ෆ්‍රෝ
-ෆ්‍රෞ
-ෆ්‍ර්
-ෆ්‍රං
-ෆ්‍රඃ
-ෆ්‍ය
-ෆ්‍යා
-ෆ්‍යැ
-ෆ්‍යෑ
-ෆ්‍යි
-ෆ්‍යී
-ෆ්‍යු
-ෆ්‍යූ
-ෆ්‍යෘ
-ෆ්‍යෲ
-ෆ්‍යෟ
-ෆ්‍යෳ
-ෆ්‍යෙ
-ෆ්‍යේ
-ෆ්‍යෛ
-ෆ්‍යො
-ෆ්‍යෝ
-ෆ්‍යෞ
-ෆ්‍ය්
-ෆ්‍යං
-ෆ්‍යඃ
-ර්‍ෆ
-ර්‍ෆා
-ර්‍ෆැ
-ර්‍ෆෑ
-ර්‍ෆි
-ර්‍ෆී
-ර්‍ෆු
-ර්‍ෆූ
-ර්‍ෆෘ
-ර්‍ෆෲ
-ර්‍ෆෟ
-ර්‍ෆෳ
-ර්‍ෆෙ
-ර්‍ෆේ
-ර්‍ෆෛ
-ර්‍ෆො
-ර්‍ෆෝ
-ර්‍ෆෞ
-ර්‍ෆ්
-ර්‍ෆං
-ර්‍ෆඃ
-ක්‍ෂ
-ක්‍ෂා
-ක්‍ෂැ
-ක්‍ෂෑ
-ක්‍ෂි
-ක්‍ෂී
-ක්‍ෂු
-ක්‍ෂූ
-ක්‍ෂෘ
-ක්‍ෂෲ
-ක්‍ෂෟ
-ක්‍ෂෳ
-ක්‍ෂෙ
-ක්‍ෂේ
-ක්‍ෂෛ
-ක්‍ෂො
-ක්‍ෂෝ
-ක්‍ෂෞ
-ක්‍ෂ්
-ක්‍ෂං
-ක්‍ෂඃ
-ක්‍ෂ්‍ර
-ක්‍ෂ්‍රා
-ක්‍ෂ්‍රැ
-ක්‍ෂ්‍රෑ
-ක්‍ෂ්‍රි
-ක්‍ෂ්‍රී
-ක්‍ෂ්‍රු
-ක්‍ෂ්‍රූ
-ක්‍ෂ්‍රෘ
-ක්‍ෂ්‍රෲ
-ක්‍ෂ්‍රෟ
-ක්‍ෂ්‍රෳ
-ක්‍ෂ්‍රෙ
-ක්‍ෂ්‍රේ
-ක්‍ෂ්‍රෛ
-ක්‍ෂ්‍රො
-ක්‍ෂ්‍රෝ
-ක්‍ෂ්‍රෞ
-ක්‍ෂ්‍ර්
-ක්‍ෂ්‍රං
-ක්‍ෂ්‍රඃ
-ක්‍ෂ්‍ය
-ක්‍ෂ්‍යා
-ක්‍ෂ්‍යැ
-ක්‍ෂ්‍යෑ
-ක්‍ෂ්‍යි
-ක්‍ෂ්‍යී
-ක්‍ෂ්‍යු
-ක්‍ෂ්‍යූ
-ක්‍ෂ්‍යෘ
-ක්‍ෂ්‍යෲ
-ක්‍ෂ්‍යෟ
-ක්‍ෂ්‍යෳ
-ක්‍ෂ්‍යෙ
-ක්‍ෂ්‍යේ
-ක්‍ෂ්‍යෛ
-ක්‍ෂ්‍යො
-ක්‍ෂ්‍යෝ
-ක්‍ෂ්‍යෞ
-ක්‍ෂ්‍ය්
-ක්‍ෂ්‍යං
-ක්‍ෂ්‍යඃ
-ර්‍ක්‍ෂ
-ර්‍ක්‍ෂා
-ර්‍ක්‍ෂැ
-ර්‍ක්‍ෂෑ
-ර්‍ක්‍ෂි
-ර්‍ක්‍ෂී
-ර්‍ක්‍ෂු
-ර්‍ක්‍ෂූ
-ර්‍ක්‍ෂෘ
-ර්‍ක්‍ෂෲ
-ර්‍ක්‍ෂෟ
-ර්‍ක්‍ෂෳ
-ර්‍ක්‍ෂෙ
-ර්‍ක්‍ෂේ
-ර්‍ක්‍ෂෛ
-ර්‍ක්‍ෂො
-ර්‍ක්‍ෂෝ
-ර්‍ක්‍ෂෞ
-ර්‍ක්‍ෂ්
-ර්‍ක්‍ෂං
-ර්‍ක්‍ෂඃ
-ක්‍ව
-ක්‍වා
-ක්‍වැ
-ක්‍වෑ
-ක්‍වි
-ක්‍වී
-ක්‍වු
-ක්‍වූ
-ක්‍වෘ
-ක්‍වෲ
-ක්‍වෟ
-ක්‍වෳ
-ක්‍වෙ
-ක්‍වේ
-ක්‍වෛ
-ක්‍වො
-ක්‍වෝ
-ක්‍වෞ
-ක්‍ව්
-ක්‍වං
-ක්‍වඃ
-ක්‍ව්‍ර
-ක්‍ව්‍රා
-ක්‍ව්‍රැ
-ක්‍ව්‍රෑ
-ක්‍ව්‍රි
-ක්‍ව්‍රී
-ක්‍ව්‍රු
-ක්‍ව්‍රූ
-ක්‍ව්‍රෘ
-ක්‍ව්‍රෲ
-ක්‍ව්‍රෟ
-ක්‍ව්‍රෳ
-ක්‍ව්‍රෙ
-ක්‍ව්‍රේ
-ක්‍ව්‍රෛ
-ක්‍ව්‍රො
-ක්‍ව්‍රෝ
-ක්‍ව්‍රෞ
-ක්‍ව්‍ර්
-ක්‍ව්‍රං
-ක්‍ව්‍රඃ
-ක්‍ව්‍ය
-ක්‍ව්‍යා
-ක්‍ව්‍යැ
-ක්‍ව්‍යෑ
-ක්‍ව්‍යි
-ක්‍ව්‍යී
-ක්‍ව්‍යු
-ක්‍ව්‍යූ
-ක්‍ව්‍යෘ
-ක්‍ව්‍යෲ
-ක්‍ව්‍යෟ
-ක්‍ව්‍යෳ
-ක්‍ව්‍යෙ
-ක්‍ව්‍යේ
-ක්‍ව්‍යෛ
-ක්‍ව්‍යො
-ක්‍ව්‍යෝ
-ක්‍ව්‍යෞ
-ක්‍ව්‍ය්
-ක්‍ව්‍යං
-ක්‍ව්‍යඃ
-ර්‍ක්‍ව
-ර්‍ක්‍වා
-ර්‍ක්‍වැ
-ර්‍ක්‍වෑ
-ර්‍ක්‍වි
-ර්‍ක්‍වී
-ර්‍ක්‍වු
-ර්‍ක්‍වූ
-ර්‍ක්‍වෘ
-ර්‍ක්‍වෲ
-ර්‍ක්‍වෟ
-ර්‍ක්‍වෳ
-ර්‍ක්‍වෙ
-ර්‍ක්‍වේ
-ර්‍ක්‍වෛ
-ර්‍ක්‍වො
-ර්‍ක්‍වෝ
-ර්‍ක්‍වෞ
-ර්‍ක්‍ව්
-ර්‍ක්‍වං
-ර්‍ක්‍වඃ
-ත්‍ථ
-ත්‍ථා
-ත්‍ථැ
-ත්‍ථෑ
-ත්‍ථි
-ත්‍ථී
-ත්‍ථු
-ත්‍ථූ
-ත්‍ථෘ
-ත්‍ථෲ
-ත්‍ථෟ
-ත්‍ථෳ
-ත්‍ථෙ
-ත්‍ථේ
-ත්‍ථෛ
-ත්‍ථො
-ත්‍ථෝ
-ත්‍ථෞ
-ත්‍ථ්
-ත්‍ථං
-ත්‍ථඃ
-ත්‍ථ්‍ර
-ත්‍ථ්‍රා
-ත්‍ථ්‍රැ
-ත්‍ථ්‍රෑ
-ත්‍ථ්‍රි
-ත්‍ථ්‍රී
-ත්‍ථ්‍රු
-ත්‍ථ්‍රූ
-ත්‍ථ්‍රෘ
-ත්‍ථ්‍රෲ
-ත්‍ථ්‍රෟ
-ත්‍ථ්‍රෳ
-ත්‍ථ්‍රෙ
-ත්‍ථ්‍රේ
-ත්‍ථ්‍රෛ
-ත්‍ථ්‍රො
-ත්‍ථ්‍රෝ
-ත්‍ථ්‍රෞ
-ත්‍ථ්‍ර්
-ත්‍ථ්‍රං
-ත්‍ථ්‍රඃ
-ත්‍ථ්‍ය
-ත්‍ථ්‍යා
-ත්‍ථ්‍යැ
-ත්‍ථ්‍යෑ
-ත්‍ථ්‍යි
-ත්‍ථ්‍යී
-ත්‍ථ්‍යු
-ත්‍ථ්‍යූ
-ත්‍ථ්‍යෘ
-ත්‍ථ්‍යෲ
-ත්‍ථ්‍යෟ
-ත්‍ථ්‍යෳ
-ත්‍ථ්‍යෙ
-ත්‍ථ්‍යේ
-ත්‍ථ්‍යෛ
-ත්‍ථ්‍යො
-ත්‍ථ්‍යෝ
-ත්‍ථ්‍යෞ
-ත්‍ථ්‍ය්
-ත්‍ථ්‍යං
-ත්‍ථ්‍යඃ
-ර්‍ත්‍ථ
-ර්‍ත්‍ථා
-ර්‍ත්‍ථැ
-ර්‍ත්‍ථෑ
-ර්‍ත්‍ථි
-ර්‍ත්‍ථී
-ර්‍ත්‍ථු
-ර්‍ත්‍ථූ
-ර්‍ත්‍ථෘ
-ර්‍ත්‍ථෲ
-ර්‍ත්‍ථෟ
-ර්‍ත්‍ථෳ
-ර්‍ත්‍ථෙ
-ර්‍ත්‍ථේ
-ර්‍ත්‍ථෛ
-ර්‍ත්‍ථො
-ර්‍ත්‍ථෝ
-ර්‍ත්‍ථෞ
-ර්‍ත්‍ථ්
-ර්‍ත්‍ථං
-ර්‍ත්‍ථඃ
-ත්‍ව
-ත්‍වා
-ත්‍වැ
-ත්‍වෑ
-ත්‍වි
-ත්‍වී
-ත්‍වු
-ත්‍වූ
-ත්‍වෘ
-ත්‍වෲ
-ත්‍වෟ
-ත්‍වෳ
-ත්‍වෙ
-ත්‍වේ
-ත්‍වෛ
-ත්‍වො
-ත්‍වෝ
-ත්‍වෞ
-ත්‍ව්
-ත්‍වං
-ත්‍වඃ
-ත්‍ව්‍ර
-ත්‍ව්‍රා
-ත්‍ව්‍රැ
-ත්‍ව්‍රෑ
-ත්‍ව්‍රි
-ත්‍ව්‍රී
-ත්‍ව්‍රු
-ත්‍ව්‍රූ
-ත්‍ව්‍රෘ
-ත්‍ව්‍රෲ
-ත්‍ව්‍රෟ
-ත්‍ව්‍රෳ
-ත්‍ව්‍රෙ
-ත්‍ව්‍රේ
-ත්‍ව්‍රෛ
-ත්‍ව්‍රො
-ත්‍ව්‍රෝ
-ත්‍ව්‍රෞ
-ත්‍ව්‍ර්
-ත්‍ව්‍රං
-ත්‍ව්‍රඃ
-ත්‍ව්‍ය
-ත්‍ව්‍යා
-ත්‍ව්‍යැ
-ත්‍ව්‍යෑ
-ත්‍ව්‍යි
-ත්‍ව්‍යී
-ත්‍ව්‍යු
-ත්‍ව්‍යූ
-ත්‍ව්‍යෘ
-ත්‍ව්‍යෲ
-ත්‍ව්‍යෟ
-ත්‍ව්‍යෳ
-ත්‍ව්‍යෙ
-ත්‍ව්‍යේ
-ත්‍ව්‍යෛ
-ත්‍ව්‍යො
-ත්‍ව්‍යෝ
-ත්‍ව්‍යෞ
-ත්‍ව්‍ය්
-ත්‍ව්‍යං
-ත්‍ව්‍යඃ
-ර්‍ත්‍ව
-ර්‍ත්‍වා
-ර්‍ත්‍වැ
-ර්‍ත්‍වෑ
-ර්‍ත්‍වි
-ර්‍ත්‍වී
-ර්‍ත්‍වු
-ර්‍ත්‍වූ
-ර්‍ත්‍වෘ
-ර්‍ත්‍වෲ
-ර්‍ත්‍වෟ
-ර්‍ත්‍වෳ
-ර්‍ත්‍වෙ
-ර්‍ත්‍වේ
-ර්‍ත්‍වෛ
-ර්‍ත්‍වො
-ර්‍ත්‍වෝ
-ර්‍ත්‍වෞ
-ර්‍ත්‍ව්
-ර්‍ත්‍වං
-ර්‍ත්‍වඃ
-න්‍ථ
-න්‍ථා
-න්‍ථැ
-න්‍ථෑ
-න්‍ථි
-න්‍ථී
-න්‍ථු
-න්‍ථූ
-න්‍ථෘ
-න්‍ථෲ
-න්‍ථෟ
-න්‍ථෳ
-න්‍ථෙ
-න්‍ථේ
-න්‍ථෛ
-න්‍ථො
-න්‍ථෝ
-න්‍ථෞ
-න්‍ථ්
-න්‍ථං
-න්‍ථඃ
-න්‍ථ්‍ර
-න්‍ථ්‍රා
-න්‍ථ්‍රැ
-න්‍ථ්‍රෑ
-න්‍ථ්‍රි
-න්‍ථ්‍රී
-න්‍ථ්‍රු
-න්‍ථ්‍රූ
-න්‍ථ්‍රෘ
-න්‍ථ්‍රෲ
-න්‍ථ්‍රෟ
-න්‍ථ්‍රෳ
-න්‍ථ්‍රෙ
-න්‍ථ්‍රේ
-න්‍ථ්‍රෛ
-න්‍ථ්‍රො
-න්‍ථ්‍රෝ
-න්‍ථ්‍රෞ
-න්‍ථ්‍ර්
-න්‍ථ්‍රං
-න්‍ථ්‍රඃ
-න්‍ථ්‍ය
-න්‍ථ්‍යා
-න්‍ථ්‍යැ
-න්‍ථ්‍යෑ
-න්‍ථ්‍යි
-න්‍ථ්‍යී
-න්‍ථ්‍යු
-න්‍ථ්‍යූ
-න්‍ථ්‍යෘ
-න්‍ථ්‍යෲ
-න්‍ථ්‍යෟ
-න්‍ථ්‍යෳ
-න්‍ථ්‍යෙ
-න්‍ථ්‍යේ
-න්‍ථ්‍යෛ
-න්‍ථ්‍යො
-න්‍ථ්‍යෝ
-න්‍ථ්‍යෞ
-න්‍ථ්‍ය්
-න්‍ථ්‍යං
-න්‍ථ්‍යඃ
-ර්‍න්‍ථ
-ර්‍න්‍ථා
-ර්‍න්‍ථැ
-ර්‍න්‍ථෑ
-ර්‍න්‍ථි
-ර්‍න්‍ථී
-ර්‍න්‍ථු
-ර්‍න්‍ථූ
-ර්‍න්‍ථෘ
-ර්‍න්‍ථෲ
-ර්‍න්‍ථෟ
-ර්‍න්‍ථෳ
-ර්‍න්‍ථෙ
-ර්‍න්‍ථේ
-ර්‍න්‍ථෛ
-ර්‍න්‍ථො
-ර්‍න්‍ථෝ
-ර්‍න්‍ථෞ
-ර්‍න්‍ථ්
-ර්‍න්‍ථං
-ර්‍න්‍ථඃ
-න්‍ද
-න්‍දා
-න්‍දැ
-න්‍දෑ
-න්‍දි
-න්‍දී
-න්‍දු
-න්‍දූ
-න්‍දෘ
-න්‍දෲ
-න්‍දෟ
-න්‍දෳ
-න්‍දෙ
-න්‍දේ
-න්‍දෛ
-න්‍දො
-න්‍දෝ
-න්‍දෞ
-න්‍ද්
-න්‍දං
-න්‍දඃ
-න්‍ද්‍ර
-න්‍ද්‍රා
-න්‍ද්‍රැ
-න්‍ද්‍රෑ
-න්‍ද්‍රි
-න්‍ද්‍රී
-න්‍ද්‍රු
-න්‍ද්‍රූ
-න්‍ද්‍රෘ
-න්‍ද්‍රෲ
-න්‍ද්‍රෟ
-න්‍ද්‍රෳ
-න්‍ද්‍රෙ
-න්‍ද්‍රේ
-න්‍ද්‍රෛ
-න්‍ද්‍රො
-න්‍ද්‍රෝ
-න්‍ද්‍රෞ
-න්‍ද්‍ර්
-න්‍ද්‍රං
-න්‍ද්‍රඃ
-න්‍ද්‍ය
-න්‍ද්‍යා
-න්‍ද්‍යැ
-න්‍ද්‍යෑ
-න්‍ද්‍යි
-න්‍ද්‍යී
-න්‍ද්‍යු
-න්‍ද්‍යූ
-න්‍ද්‍යෘ
-න්‍ද්‍යෲ
-න්‍ද්‍යෟ
-න්‍ද්‍යෳ
-න්‍ද්‍යෙ
-න්‍ද්‍යේ
-න්‍ද්‍යෛ
-න්‍ද්‍යො
-න්‍ද්‍යෝ
-න්‍ද්‍යෞ
-න්‍ද්‍ය්
-න්‍ද්‍යං
-න්‍ද්‍යඃ
-ර්‍න්‍ද
-ර්‍න්‍දා
-ර්‍න්‍දැ
-ර්‍න්‍දෑ
-ර්‍න්‍දි
-ර්‍න්‍දී
-ර්‍න්‍දු
-ර්‍න්‍දූ
-ර්‍න්‍දෘ
-ර්‍න්‍දෲ
-ර්‍න්‍දෟ
-ර්‍න්‍දෳ
-ර්‍න්‍දෙ
-ර්‍න්‍දේ
-ර්‍න්‍දෛ
-ර්‍න්‍දො
-ර්‍න්‍දෝ
-ර්‍න්‍දෞ
-ර්‍න්‍ද්
-ර්‍න්‍දං
-ර්‍න්‍දඃ
-න්‍ධ
-න්‍ධා
-න්‍ධැ
-න්‍ධෑ
-න්‍ධි
-න්‍ධී
-න්‍ධු
-න්‍ධූ
-න්‍ධෘ
-න්‍ධෲ
-න්‍ධෟ
-න්‍ධෳ
-න්‍ධෙ
-න්‍ධේ
-න්‍ධෛ
-න්‍ධො
-න්‍ධෝ
-න්‍ධෞ
-න්‍ධ්
-න්‍ධං
-න්‍ධඃ
-න්‍ධ්‍ර
-න්‍ධ්‍රා
-න්‍ධ්‍රැ
-න්‍ධ්‍රෑ
-න්‍ධ්‍රි
-න්‍ධ්‍රී
-න්‍ධ්‍රු
-න්‍ධ්‍රූ
-න්‍ධ්‍රෘ
-න්‍ධ්‍රෲ
-න්‍ධ්‍රෟ
-න්‍ධ්‍රෳ
-න්‍ධ්‍රෙ
-න්‍ධ්‍රේ
-න්‍ධ්‍රෛ
-න්‍ධ්‍රො
-න්‍ධ්‍රෝ
-න්‍ධ්‍රෞ
-න්‍ධ්‍ර්
-න්‍ධ්‍රං
-න්‍ධ්‍රඃ
-න්‍ධ්‍ය
-න්‍ධ්‍යා
-න්‍ධ්‍යැ
-න්‍ධ්‍යෑ
-න්‍ධ්‍යි
-න්‍ධ්‍යී
-න්‍ධ්‍යු
-න්‍ධ්‍යූ
-න්‍ධ්‍යෘ
-න්‍ධ්‍යෲ
-න්‍ධ්‍යෟ
-න්‍ධ්‍යෳ
-න්‍ධ්‍යෙ
-න්‍ධ්‍යේ
-න්‍ධ්‍යෛ
-න්‍ධ්‍යො
-න්‍ධ්‍යෝ
-න්‍ධ්‍යෞ
-න්‍ධ්‍ය්
-න්‍ධ්‍යං
-න්‍ධ්‍යඃ
-ර්‍න්‍ධ
-ර්‍න්‍ධා
-ර්‍න්‍ධැ
-ර්‍න්‍ධෑ
-ර්‍න්‍ධි
-ර්‍න්‍ධී
-ර්‍න්‍ධු
-ර්‍න්‍ධූ
-ර්‍න්‍ධෘ
-ර්‍න්‍ධෲ
-ර්‍න්‍ධෟ
-ර්‍න්‍ධෳ
-ර්‍න්‍ධෙ
-ර්‍න්‍ධේ
-ර්‍න්‍ධෛ
-ර්‍න්‍ධො
-ර්‍න්‍ධෝ
-ර්‍න්‍ධෞ
-ර්‍න්‍ධ්
-ර්‍න්‍ධං
-ර්‍න්‍ධඃ
-න්‍ව
-න්‍වා
-න්‍වැ
-න්‍වෑ
-න්‍වි
-න්‍වී
-න්‍වු
-න්‍වූ
-න්‍වෘ
-න්‍වෲ
-න්‍වෟ
-න්‍වෳ
-න්‍වෙ
-න්‍වේ
-න්‍වෛ
-න්‍වො
-න්‍වෝ
-න්‍වෞ
-න්‍ව්
-න්‍වං
-න්‍වඃ
-න්‍ව්‍ර
-න්‍ව්‍රා
-න්‍ව්‍රැ
-න්‍ව්‍රෑ
-න්‍ව්‍රි
-න්‍ව්‍රී
-න්‍ව්‍රු
-න්‍ව්‍රූ
-න්‍ව්‍රෘ
-න්‍ව්‍රෲ
-න්‍ව්‍රෟ
-න්‍ව්‍රෳ
-න්‍ව්‍රෙ
-න්‍ව්‍රේ
-න්‍ව්‍රෛ
-න්‍ව්‍රො
-න්‍ව්‍රෝ
-න්‍ව්‍රෞ
-න්‍ව්‍ර්
-න්‍ව්‍රං
-න්‍ව්‍රඃ
-න්‍ව්‍ය
-න්‍ව්‍යා
-න්‍ව්‍යැ
-න්‍ව්‍යෑ
-න්‍ව්‍යි
-න්‍ව්‍යී
-න්‍ව්‍යු
-න්‍ව්‍යූ
-න්‍ව්‍යෘ
-න්‍ව්‍යෲ
-න්‍ව්‍යෟ
-න්‍ව්‍යෳ
-න්‍ව්‍යෙ
-න්‍ව්‍යේ
-න්‍ව්‍යෛ
-න්‍ව්‍යො
-න්‍ව්‍යෝ
-න්‍ව්‍යෞ
-න්‍ව්‍ය්
-න්‍ව්‍යං
-න්‍ව්‍යඃ
-ර්‍න්‍ව
-ර්‍න්‍වා
-ර්‍න්‍වැ
-ර්‍න්‍වෑ
-ර්‍න්‍වි
-ර්‍න්‍වී
-ර්‍න්‍වු
-ර්‍න්‍වූ
-ර්‍න්‍වෘ
-ර්‍න්‍වෲ
-ර්‍න්‍වෟ
-ර්‍න්‍වෳ
-ර්‍න්‍වෙ
-ර්‍න්‍වේ
-ර්‍න්‍වෛ
-ර්‍න්‍වො
-ර්‍න්‍වෝ
-ර්‍න්‍වෞ
-ර්‍න්‍ව්
-ර්‍න්‍වං
-ර්‍න්‍වඃ
-ද්‍ව
-ද්‍වා
-ද්‍වැ
-ද්‍වෑ
-ද්‍වි
-ද්‍වී
-ද්‍වු
-ද්‍වූ
-ද්‍වෘ
-ද්‍වෲ
-ද්‍වෟ
-ද්‍වෳ
-ද්‍වෙ
-ද්‍වේ
-ද්‍වෛ
-ද්‍වො
-ද්‍වෝ
-ද්‍වෞ
-ද්‍ව්
-ද්‍වං
-ද්‍වඃ
-ද්‍ව්‍ර
-ද්‍ව්‍රා
-ද්‍ව්‍රැ
-ද්‍ව්‍රෑ
-ද්‍ව්‍රි
-ද්‍ව්‍රී
-ද්‍ව්‍රු
-ද්‍ව්‍රූ
-ද්‍ව්‍රෘ
-ද්‍ව්‍රෲ
-ද්‍ව්‍රෟ
-ද්‍ව්‍රෳ
-ද්‍ව්‍රෙ
-ද්‍ව්‍රේ
-ද්‍ව්‍රෛ
-ද්‍ව්‍රො
-ද්‍ව්‍රෝ
-ද්‍ව්‍රෞ
-ද්‍ව්‍ර්
-ද්‍ව්‍රං
-ද්‍ව්‍රඃ
-ද්‍ව්‍ය
-ද්‍ව්‍යා
-ද්‍ව්‍යැ
-ද්‍ව්‍යෑ
-ද්‍ව්‍යි
-ද්‍ව්‍යී
-ද්‍ව්‍යු
-ද්‍ව්‍යූ
-ද්‍ව්‍යෘ
-ද්‍ව්‍යෲ
-ද්‍ව්‍යෟ
-ද්‍ව්‍යෳ
-ද්‍ව්‍යෙ
-ද්‍ව්‍යේ
-ද්‍ව්‍යෛ
-ද්‍ව්‍යො
-ද්‍ව්‍යෝ
-ද්‍ව්‍යෞ
-ද්‍ව්‍ය්
-ද්‍ව්‍යං
-ද්‍ව්‍යඃ
-ර්‍ද්‍ව
-ර්‍ද්‍වා
-ර්‍ද්‍වැ
-ර්‍ද්‍වෑ
-ර්‍ද්‍වි
-ර්‍ද්‍වී
-ර්‍ද්‍වු
-ර්‍ද්‍වූ
-ර්‍ද්‍වෘ
-ර්‍ද්‍වෲ
-ර්‍ද්‍වෟ
-ර්‍ද්‍වෳ
-ර්‍ද්‍වෙ
-ර්‍ද්‍වේ
-ර්‍ද්‍වෛ
-ර්‍ද්‍වො
-ර්‍ද්‍වෝ
-ර්‍ද්‍වෞ
-ර්‍ද්‍ව්
-ර්‍ද්‍වං
-ර්‍ද්‍වඃ
-ද්‍ධ
-ද්‍ධා
-ද්‍ධැ
-ද්‍ධෑ
-ද්‍ධි
-ද්‍ධී
-ද්‍ධු
-ද්‍ධූ
-ද්‍ධෘ
-ද්‍ධෲ
-ද්‍ධෟ
-ද්‍ධෳ
-ද්‍ධෙ
-ද්‍ධේ
-ද්‍ධෛ
-ද්‍ධො
-ද්‍ධෝ
-ද්‍ධෞ
-ද්‍ධ්
-ද්‍ධං
-ද්‍ධඃ
-ද්‍ධ්‍ර
-ද්‍ධ්‍රා
-ද්‍ධ්‍රැ
-ද්‍ධ්‍රෑ
-ද්‍ධ්‍රි
-ද්‍ධ්‍රී
-ද්‍ධ්‍රු
-ද්‍ධ්‍රූ
-ද්‍ධ්‍රෘ
-ද්‍ධ්‍රෲ
-ද්‍ධ්‍රෟ
-ද්‍ධ්‍රෳ
-ද්‍ධ්‍රෙ
-ද්‍ධ්‍රේ
-ද්‍ධ්‍රෛ
-ද්‍ධ්‍රො
-ද්‍ධ්‍රෝ
-ද්‍ධ්‍රෞ
-ද්‍ධ්‍ර්
-ද්‍ධ්‍රං
-ද්‍ධ්‍රඃ
-ද්‍ධ්‍ය
-ද්‍ධ්‍යා
-ද්‍ධ්‍යැ
-ද්‍ධ්‍යෑ
-ද්‍ධ්‍යි
-ද්‍ධ්‍යී
-ද්‍ධ්‍යු
-ද්‍ධ්‍යූ
-ද්‍ධ්‍යෘ
-ද්‍ධ්‍යෲ
-ද්‍ධ්‍යෟ
-ද්‍ධ්‍යෳ
-ද්‍ධ්‍යෙ
-ද්‍ධ්‍යේ
-ද්‍ධ්‍යෛ
-ද්‍ධ්‍යො
-ද්‍ධ්‍යෝ
-ද්‍ධ්‍යෞ
-ද්‍ධ්‍ය්
-ද්‍ධ්‍යං
-ද්‍ධ්‍යඃ
-ර්‍ද්‍ධ
-ර්‍ද්‍ධා
-ර්‍ද්‍ධැ
-ර්‍ද්‍ධෑ
-ර්‍ද්‍ධි
-ර්‍ද්‍ධී
-ර්‍ද්‍ධු
-ර්‍ද්‍ධූ
-ර්‍ද්‍ධෘ
-ර්‍ද්‍ධෲ
-ර්‍ද්‍ධෟ
-ර්‍ද්‍ධෳ
-ර්‍ද්‍ධෙ
-ර්‍ද්‍ධේ
-ර්‍ද්‍ධෛ
-ර්‍ද්‍ධො
-ර්‍ද්‍ධෝ
-ර්‍ද්‍ධෞ
-ර්‍ද්‍ධ්
-ර්‍ද්‍ධං
-ර්‍ද්‍ධඃ
-ට්‍ඨ
-ට්‍ඨා
-ට්‍ඨැ
-ට්‍ඨෑ
-ට්‍ඨි
-ට්‍ඨී
-ට්‍ඨු
-ට්‍ඨූ
-ට්‍ඨෘ
-ට්‍ඨෲ
-ට්‍ඨෟ
-ට්‍ඨෳ
-ට්‍ඨෙ
-ට්‍ඨේ
-ට්‍ඨෛ
-ට්‍ඨො
-ට්‍ඨෝ
-ට්‍ඨෞ
-ට්‍ඨ්
-ට්‍ඨං
-ට්‍ඨඃ
-ට්‍ඨ්‍ර
-ට්‍ඨ්‍රා
-ට්‍ඨ්‍රැ
-ට්‍ඨ්‍රෑ
-ට්‍ඨ්‍රි
-ට්‍ඨ්‍රී
-ට්‍ඨ්‍රු
-ට්‍ඨ්‍රූ
-ට්‍ඨ්‍රෘ
-ට්‍ඨ්‍රෲ
-ට්‍ඨ්‍රෟ
-ට්‍ඨ්‍රෳ
-ට්‍ඨ්‍රෙ
-ට්‍ඨ්‍රේ
-ට්‍ඨ්‍රෛ
-ට්‍ඨ්‍රො
-ට්‍ඨ්‍රෝ
-ට්‍ඨ්‍රෞ
-ට්‍ඨ්‍ර්
-ට්‍ඨ්‍රං
-ට්‍ඨ්‍රඃ
-ට්‍ඨ්‍ය
-ට්‍ඨ්‍යා
-ට්‍ඨ්‍යැ
-ට්‍ඨ්‍යෑ
-ට්‍ඨ්‍යි
-ට්‍ඨ්‍යී
-ට්‍ඨ්‍යු
-ට්‍ඨ්‍යූ
-ට්‍ඨ්‍යෘ
-ට්‍ඨ්‍යෲ
-ට්‍ඨ්‍යෟ
-ට්‍ඨ්‍යෳ
-ට්‍ඨ්‍යෙ
-ට්‍ඨ්‍යේ
-ට්‍ඨ්‍යෛ
-ට්‍ඨ්‍යො
-ට්‍ඨ්‍යෝ
-ට්‍ඨ්‍යෞ
-ට්‍ඨ්‍ය්
-ට්‍ඨ්‍යං
-ට්‍ඨ්‍යඃ
-ර්‍ට්‍ඨ
-ර්‍ට්‍ඨා
-ර්‍ට්‍ඨැ
-ර්‍ට්‍ඨෑ
-ර්‍ට්‍ඨි
-ර්‍ට්‍ඨී
-ර්‍ට්‍ඨු
-ර්‍ට්‍ඨූ
-ර්‍ට්‍ඨෘ
-ර්‍ට්‍ඨෲ
-ර්‍ට්‍ඨෟ
-ර්‍ට්‍ඨෳ
-ර්‍ට්‍ඨෙ
-ර්‍ට්‍ඨේ
-ර්‍ට්‍ඨෛ
-ර්‍ට්‍ඨො
-ර්‍ට්‍ඨෝ
-ර්‍ට්‍ඨෞ
-ර්‍ට්‍ඨ්
-ර්‍ට්‍ඨං
-ර්‍ට්‍ඨඃ
-්‍ර
-්‍ය
-ර්‍
-෴
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/misc.txt
deleted file mode 100644 (file)
index c43cb95..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-ක
-කං
-කඃ
-කා
-කැ
-කෑ
-කි
-කී
-කු
-කූ
-කෘ
-කෲ
-කෟ
-කෳ
-කෙ
-කො
-කෞ
-කේ
-කේ
-කෛ
-කො
-කෝ
-කෝ
-කෞ
-ක්
-ක්‍ය
-ක්‍ර
-ක‍්‍රම
-ර්‍ම
-ශී‍්‍ර
-ස්ට්‍රේ
-ග්‍යෙ
-ර්‍ය්‍ය
-එ‍ඬේ
-න්ගේ
-න්‍ගේ
-න‍්ගේ
-ර්‍
-ක්‍රා
-කේ
-ගර්‍
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/reph.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/reph.txt
deleted file mode 100644 (file)
index f5f2f53..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-ර්ධ
-ර්‍ධ
-ර්‌ධ
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/split-matras.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/split-matras.txt
deleted file mode 100644 (file)
index 2a73a40..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-කේ
-කො
-කෝ
-කෞ
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/LICENSE
deleted file mode 100644 (file)
index 2cf8228..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/README
deleted file mode 100644 (file)
index 8bad337..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/SOURCES
deleted file mode 100644 (file)
index 0ed1a89..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644 (file)
index 0e8810a..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-ක
-ඛ
-ග
-ඝ
-ඞ
-ඟ
-ච
-ඡ
-ජ
-ඣ
-ඤ
-ඥ
-ඦ
-ට
-ඨ
-ඩ
-ඪ
-ණ
-ඬ
-ත
-ථ
-ද
-ධ
-න
-ඳ
-ප
-ඵ
-බ
-භ
-ම
-ඹ
-ය
-ර
-ල
-ව
-ශ
-ෂ
-ස
-හ
-ළ
-ෆ
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644 (file)
index 27911e4..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-ා
-ැ
-ෑ
-ි
-ී
-ු
-ූ
-ෘ
-ෙ
-ේ
-ෛ
-ො
-ෝ
-ෞ
-ෟ
-ෲ
-ෳ
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644 (file)
index 939be04..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-අ
-ආ
-ඇ
-ඈ
-ඉ
-ඊ
-උ
-ඌ
-ඍ
-ඎ
-ඏ
-ඐ
-එ
-ඒ
-ඓ
-ඔ
-ඕ
-ඖ
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Punctuation.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Punctuation.txt
deleted file mode 100644 (file)
index d6c6809..0000000
+++ /dev/null
@@ -1 +0,0 @@
-෴
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644 (file)
index a65a9ba..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-ං
-ඃ
-්
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gpos/IndicFontFeatureGPOS.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gpos/IndicFontFeatureGPOS.txt
deleted file mode 100644 (file)
index 7cd1eac..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-කේ
-කෛ
-කී
-කෑ
-කූ
-කෲ
-ගේ
-ගෛ
-ගී
-ගෑ
-ගූ
-ගෲ
-තේ
-තෛ
-තී
-තෑ
-තූ
-තෲ
-ටේ
-ටෛ
-ටී
-ටෑ
-ටූ
-ටෲ
-ඩේ
-ඩෛ
-ඩී
-ඩෑ
-ඩූ
-ඩෲ
-චේ
-චෛ
-චී
-චෑ
-චූ
-චෲ
-ඡේ
-ඡෛ
-ඡී
-ඡෑ
-ඡූ
-ඡෲ
-ණේ
-ණෛ
-ණී
-ණෑ
-ණූ
-ණෲ
-පේ
-පෛ
-පී
-පෑ
-පූ
-පෲ
-දේ
-දෛ
-දී
-දෑ
-දූ
-දෲ
-ඳේ
-ඳෛ
-ඳී
-ඳෑ
-ඳූ
-ඳෲ
-ධේ
-ධෛ
-ධී
-ධෑ
-ධූ
-ධෲ
-බේ
-බෛ
-බී
-බෑ
-බූ
-බෲ
-මේ
-මෛ
-මී
-මෑ
-මූ
-මෲ
-වේ
-වෛ
-වී
-වෑ
-වූ
-වෲ
-හේ
-හෛ
-හී
-හෑ
-හූ
-හෲ
-රේ
-රෛ
-රී
-රෑ
-රූ
-රෲ
-ෆේ
-ෆෛ
-ෆී
-ෆෑ
-ෆූ
-ෆෲ
-ළේ
-ළෛ
-ළී
-ළෑ
-ළූ
-ළෲ
-ලේ
-ලෛ
-ලී
-ලෑ
-ලූ
-ලෲ
-යේ
-යෛ
-යී
-යෑ
-යූ
-යෲ
-සේ
-සෛ
-සී
-සෑ
-සූ
-සෲ
-ශේ
-ශෛ
-ශී
-ශෑ
-ශූ
-ශෲ
-ෂේ
-ෂෛ
-ෂී
-ෂෑ
-ෂූ
-ෂෲ
-ඹේ
-ඹෛ
-ඹී
-ඹෑ
-ඹූ
-ඹෲ
-ඵේ
-ඵෛ
-ඵී
-ඵෑ
-ඵූ
-ඵෲ
-ථේ
-ථෛ
-ථී
-ථෑ
-ථූ
-ථෲ
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Conjunct.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Conjunct.txt
deleted file mode 100644 (file)
index a100c69..0000000
+++ /dev/null
@@ -1 +0,0 @@
-්‍
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Rakaaraansaya.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Rakaaraansaya.txt
deleted file mode 100644 (file)
index bf89a71..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-ක්‍ර
-ඛ්‍ර
-ග්‍ර
-ඝ්‍ර
-ඞ්‍ර
-ඟ්‍ර
-ච්‍ර
-ඡ්‍ර
-ජ්‍ර
-ඣ්‍ර
-ඤ්‍ර
-ඥ්‍ර
-ඦ්‍ර
-ට්‍ර
-ඨ්‍ර
-ඩ්‍ර
-ඪ්‍ර
-ණ්‍ර
-ඬ්‍ර
-ත්‍ර
-ථ්‍ර
-ද්‍ර
-ධ්‍ර
-න්‍ර
-ඳ්‍ර
-ප්‍ර
-ඵ්‍ර
-බ්‍ර
-භ්‍ර
-ම්‍ර
-ඹ්‍ර
-ය්‍ර
-ර්‍ර
-ල්‍ර
-ව්‍ර
-ශ්‍ර
-ෂ්‍ර
-ස්‍ර
-හ්‍ර
-ළ්‍ර
-ෆ්‍ර
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Repaya.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Repaya.txt
deleted file mode 100644 (file)
index 6f0293d..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-කර්‍ක
-ඛර්‍ක
-ගර්‍ක
-ඝර්‍ක
-ඞර්‍ක
-ඟර්‍ක
-චර්‍ක
-ඡර්‍ක
-ජර්‍ක
-ඣර්‍ක
-ඤර්‍ක
-ඥර්‍ක
-ඦර්‍ක
-ටර්‍ක
-ඨර්‍ක
-ඩර්‍ක
-ඪර්‍ක
-ණර්‍ක
-ඬර්‍ක
-තර්‍ක
-ථර්‍ක
-දර්‍ක
-ධර්‍ක
-නර්‍ක
-ඳර්‍ක
-පර්‍ක
-ඵර්‍ක
-බර්‍ක
-භර්‍ක
-මර්‍ක
-ඹර්‍ක
-යර්‍ක
-රර්‍ක
-ලර්‍ක
-වර්‍ක
-ශර්‍ක
-ෂර්‍ක
-සර්‍ක
-හර්‍ක
-ළර්‍ක
-ෆර්‍ක
-කර්‍ය්‍ය
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Special-Cases.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Special-Cases.txt
deleted file mode 100644 (file)
index 109c873..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-ක්‍ෂ
-න්‍ද
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-TouchingLetters.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-TouchingLetters.txt
deleted file mode 100644 (file)
index 105b295..0000000
+++ /dev/null
@@ -1 +0,0 @@
-‍්
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Yansaya.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Yansaya.txt
deleted file mode 100644 (file)
index 299ca9d..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-ක්‍ය
-ඛ්‍ය
-ග්‍ය
-ඝ්‍ය
-ඞ්‍ය
-ඟ්‍ය
-ච්‍ය
-ඡ්‍ය
-ජ්‍ය
-ඣ්‍ය
-ඤ්‍ය
-ඥ්‍ය
-ඦ්‍ය
-ට්‍ය
-ඨ්‍ය
-ඩ්‍ය
-ඪ්‍ය
-ණ්‍ය
-ඬ්‍ය
-ත්‍ය
-ථ්‍ය
-ද්‍ය
-ධ්‍ය
-න්‍ය
-ඳ්‍ය
-ප්‍ය
-ඵ්‍ය
-බ්‍ය
-භ්‍ය
-ම්‍ය
-ඹ්‍ය
-ය්‍ය
-ර්‍ය
-ල්‍ය
-ව්‍ය
-ශ්‍ය
-ෂ්‍ය
-ස්‍ය
-හ්‍ය
-ළ්‍ය
-ෆ්‍ය
diff --git a/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644 (file)
index fd5e6e6..0000000
+++ /dev/null
@@ -1 +0,0 @@
-codepoint, imagepath, rawcode, desc
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/misc/misc.txt
deleted file mode 100644 (file)
index c72be69..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-தமிழ்நாடு
-ஓர்
-இந்திய
-மாநிலமாகும்.
-தமிழ்நாடு,
-தமிழகம்
-என்றும்
-பரவலாக
-அழைக்கப்படுகிறது.
-ஆங்கிலத்தில்
-மெட்ராஸ்
-ஸ்டேட்
-என்றும்
-தமிழில்
-சென்னை
-ராஜ்ஜியம்
-என்றும்
-அழைக்கப்பெற்றது.
-இதனை
-தமிழ்நாடு
-என்று
-மாற்றக்கோரி
-போராட்டங்கள்
-நடைபெற்றன.
-சங்கரலிங்கனார்
-என்பவர்
-நாட்கள்
-உண்ணாவிரதம்
-இருந்து
-உயிர்துறந்தார்.
-பின்னர்
-மதராசு
-ஸ்டேட்
-என்று
-இருந்த
-பெயர்
-ஆம்
-ஆண்டு
-தமிழ்நாடு
-என்று
-மாற்றப்பட்டது.
-ஸ்ரீ
-க்ஷ
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/LICENSE
deleted file mode 100644 (file)
index 2cf8228..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/README
deleted file mode 100644 (file)
index 8bad337..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/SOURCES
deleted file mode 100644 (file)
index 0ed1a89..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644 (file)
index 7a26510..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-க
-ங
-ச
-ஜ
-ஞ
-ட
-ண
-த
-ந
-ன
-ப
-ம
-ய
-ர
-ற
-ல
-ள
-ழ
-வ
-ஶ
-ஷ
-ஸ
-ஹ
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-CurrencySymbols.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-CurrencySymbols.txt
deleted file mode 100644 (file)
index f70ba6a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-௹
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644 (file)
index f22470c..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-ா
-ி
-ீ
-ு
-ூ
-ெ
-ே
-ை
-ொ
-ோ
-ௌ
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644 (file)
index 47b1d62..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-௦
-௧
-௨
-௩
-௪
-௫
-௬
-௭
-௮
-௯
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644 (file)
index 3940ad3..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-அ
-ஆ
-இ
-ஈ
-உ
-ஊ
-எ
-ஏ
-ஐ
-ஒ
-ஓ
-ஔ
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Numerics.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Numerics.txt
deleted file mode 100644 (file)
index 33f6850..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-௰
-௱
-௲
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
deleted file mode 100644 (file)
index 66a7ca4..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Symbols.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Symbols.txt
deleted file mode 100644 (file)
index a7d89e8..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-௳
-௴
-௵
-௶
-௷
-௸
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-TamilSymbol.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-TamilSymbol.txt
deleted file mode 100644 (file)
index 2d4bdc1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-௺
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644 (file)
index 49c469c..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-ஂ
-ஃ
-்
-ௗ
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
deleted file mode 100644 (file)
index 40b2b21..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-கி
-ஙி
-சி
-ஜி
-ஞி
-டி
-ணி
-தி
-நி
-னி
-பி
-மி
-யி
-ரி
-றி
-லி
-ளி
-ழி
-வி
-ஷி
-ஸி
-ஹி
-கீ
-ஙீ
-சீ
-ஜீ
-ஞீ
-டீ
-ணீ
-தீ
-நீ
-னீ
-பீ
-மீ
-யீ
-ரீ
-றீ
-லீ
-ளீ
-ழீ
-வீ
-ஷீ
-ஸீ
-க்
-ங்
-ச்
-ஜ்
-ஞ்
-ட்
-ண்
-த்
-ந்
-ன்
-ப்
-ம்
-ய்
-ர்
-ற்
-ல்
-ழ்
-வ்
-ஷ்
-ஸ்
-ஹ்
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
deleted file mode 100644 (file)
index 847495a..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-கு
-ஙு
-சு
-ஜு
-ஞு
-டு
-ணு
-து
-நு
-னு
-பு
-மு
-யு
-ரு
-று
-லு
-ளு
-ழு
-வு
-ஷு
-ஸு
-ஹு
-கூ
-ஙூ
-சூ
-ஜூ
-ஞூ
-டூ
-ணூ
-தூ
-நூ
-னூ
-பூ
-மூ
-யூ
-ரூ
-றூ
-லூ
-ளூ
-ழூ
-வூ
-ஷூ
-ஸூ
-ஹூ
diff --git a/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644 (file)
index 2ca1df3..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-க்ஷ
-க்ஷி
-க்ஷீ
-ஷ்ரீ
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/misc/misc.txt
deleted file mode 100644 (file)
index ff522d2..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-కై
-క్
-క్కై
-క్ర
-క్రి
-క్రై
-క్ర్
-క్ర్క
-క్ష
-క్ష్
-క్ష్ణ
-ఽం
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/telugu-vowel-letters.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/telugu-vowel-letters.txt
deleted file mode 100644 (file)
index c3cfc84..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-ఓ ఒౕ
-ఔ ఒౌ
-ీ ిౕ
-ే ెౕ
-ో ొౕ
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/LICENSE
deleted file mode 100644 (file)
index 2cf8228..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2010 Red Hat Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/README
deleted file mode 100644 (file)
index 8bad337..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-Introduction:
-A system to compare a reference image of a text character, word or phrase with another image of the character, word or phrase that was rendered by a text rendering engine. Differences between the reference image and the rendered image may be recorded for subsequent analysis. Performance of a text rendering engine producing text according to typographical rules applicable to a natural language can be evaluated by one with no knowledge or ability to read the natural language
-
-
-COPYRIGHT: Red Hat Inc. 2010
-
-license: this project is under MIT license
-
-
-AUTHORS:
-Lawrence Lim
-Satyabrata Maitra
-Amanpreet Singh Brar
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/SOURCES
deleted file mode 100644 (file)
index 0ed1a89..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-https://fedorahosted.org/utrrs/
-Fetched in late 2011
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
deleted file mode 100644 (file)
index a92b179..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-ౠ
-ౡ
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
deleted file mode 100644 (file)
index 9b8ff69..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-క
-ఖ
-గ
-ఘ
-ఙ
-చ
-ఛ
-జ
-ఝ
-ఞ
-ట
-ఠ
-డ
-ఢ
-ణ
-త
-థ
-ద
-ధ
-న
-ప
-ఫ
-బ
-భ
-మ
-య
-ర
-ఱ
-ల
-ళ
-వ
-శ
-ష
-స
-హ
-ఁ
-ం
-ః
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
deleted file mode 100644 (file)
index b48ed5d..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-ా
-ి
-ీ
-ు
-ూ
-ృ
-ౄ
-ె
-ే
-ై
-ొ
-ో
-ౌ
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
deleted file mode 100644 (file)
index 8751b40..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-౦
-౧
-౨
-౩
-౪
-౫
-౬
-౭
-౮
-౯
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
deleted file mode 100644 (file)
index 53c6daf..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-అ
-ఆ
-ఇ
-ఈ
-ఉ
-ఊ
-ఋ
-ఌ
-ఎ
-ఏ
-ఐ
-ఒ
-ఓ
-ఔ
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
deleted file mode 100644 (file)
index 66a7ca4..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-।
-॥
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
deleted file mode 100644 (file)
index ebefb52..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-ఁ
-ం
-ః
-్
-ౕ
-ౖ
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
deleted file mode 100644 (file)
index 939e44a..0000000
+++ /dev/null
@@ -1,385 +0,0 @@
-కా
-ఖా
-గా
-ఘా
-ఙా
-చా
-ఛా
-జా
-ఝా
-ఞా
-టా
-ఠా
-డా
-ఢా
-ణా
-తా
-థా
-దా
-ధా
-నా
-పా
-ఫా
-బా
-భా
-మా
-యా
-రా
-ఱా
-లా
-ళా
-వా
-శా
-షా
-సా
-హా
-కి
-ఖి
-గి
-ఘి
-ఙి
-చి
-ఛి
-జి
-ఝి
-ఞి
-టి
-ఠి
-డి
-ఢి
-ణి
-తి
-థి
-ది
-ధి
-ని
-పి
-ఫి
-బి
-భి
-మి
-యి
-రి
-ఱి
-లి
-ళి
-వి
-శి
-షి
-సి
-హి
-కీ
-ఖీ
-గీ
-ఘీ
-ఙీ
-చీ
-ఛీ
-జీ
-ఝీ
-ఞీ
-టీ
-ఠీ
-డీ
-ఢీ
-ణీ
-తీ
-థీ
-దీ
-ధీ
-నీ
-పీ
-ఫీ
-బీ
-భీ
-మీ
-యీ
-రీ
-ఱీ
-లీ
-ళీ
-వీ
-శీ
-షీ
-సీ
-హీ
-కె
-ఖె
-గె
-ఘె
-ఙె
-చె
-ఛె
-జె
-ఝె
-ఞె
-టె
-ఠె
-డె
-ఢె
-ణె
-తె
-థె
-దె
-ధె
-నె
-పె
-ఫె
-బె
-భె
-మె
-యె
-రె
-ఱె
-లె
-ళె
-వె
-శె
-షె
-సె
-హె
-కే
-ఖే
-గే
-ఘే
-ఙే
-చే
-ఛే
-జే
-ఝే
-ఞే
-టే
-ఠే
-డే
-ఢే
-ణే
-తే
-థే
-దే
-ధే
-నే
-పే
-ఫే
-బే
-భే
-మే
-యే
-రే
-ఱే
-లే
-ళే
-వే
-శే
-షే
-సే
-హే
-కై
-ఖై
-గై
-ఘై
-ఙై
-చై
-ఛై
-జై
-ఝై
-ఞై
-టై
-ఠై
-డై
-ఢై
-ణై
-తై
-థై
-దై
-ధై
-నై
-పై
-ఫై
-బై
-భై
-మై
-యై
-రై
-ఱై
-లై
-ళై
-వై
-శై
-షై
-సై
-హై
-కొ
-ఖొ
-గొ
-ఘొ
-ఙొ
-చొ
-ఛొ
-జొ
-ఝొ
-ఞొ
-టొ
-ఠొ
-డొ
-ఢొ
-ణొ
-తొ
-థొ
-దొ
-ధొ
-నొ
-పొ
-ఫొ
-బొ
-భొ
-మొ
-యొ
-రొ
-ఱొ
-లొ
-ళొ
-వొ
-శొ
-షొ
-సొ
-హొ
-కో
-ఖో
-గో
-ఘో
-ఙో
-చో
-ఛో
-జో
-ఝో
-ఞో
-టో
-ఠో
-డో
-ఢో
-ణో
-తో
-థో
-దో
-ధో
-నో
-పో
-ఫో
-బో
-భో
-మో
-యో
-రో
-ఱో
-లో
-ళో
-వో
-శో
-షో
-సో
-హో
-కౌ
-ఖౌ
-గౌ
-ఘౌ
-ఙౌ
-చౌ
-ఛౌ
-జౌ
-ఝౌ
-ఞౌ
-టౌ
-ఠౌ
-డౌ
-ఢౌ
-ణౌ
-తౌ
-థౌ
-దౌ
-ధౌ
-నౌ
-పౌ
-ఫౌ
-బౌ
-భౌ
-మౌ
-యౌ
-రౌ
-ఱౌ
-లౌ
-ళౌ
-వౌ
-శౌ
-షౌ
-సౌ
-హౌ
-కఁ
-ఖఁ
-గఁ
-ఘఁ
-ఙఁ
-చఁ
-ఛఁ
-జఁ
-ఝఁ
-ఞఁ
-టఁ
-ఠఁ
-డఁ
-ఢఁ
-ణఁ
-తఁ
-థఁ
-దఁ
-ధఁ
-నఁ
-పఁ
-ఫఁ
-బఁ
-భఁ
-మఁ
-యఁ
-రఁ
-ఱఁ
-లఁ
-ళఁ
-వఁ
-శఁ
-షఁ
-సఁ
-హఁ
-క్
-ఖ్
-గ్
-ఘ్
-ఙ్
-చ్
-ఛ్
-జ్
-ఝ్
-ఞ్
-ట్
-ఠ్
-డ్
-ఢ్
-ణ్
-త్
-థ్
-ద్
-ధ్
-న్
-ప్
-ఫ్
-బ్
-భ్
-మ్
-య్
-ర్
-ఱ్
-ల్
-ళ్
-వ్
-శ్
-ష్
-స్
-హ్
diff --git a/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/gsub/IndicFontFeatureGSUB.txt
deleted file mode 100644 (file)
index 50b630b..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-క్క
-క్ఖ
-క్గ
-క్ఘ
-క్ఙ
-క్చ
-క్ఛ
-క్జ
-క్ఝ
-క్ఞ
-క్ట
-క్ఠ
-క్డ
-క్ఢ
-క్ణ
-క్త
-క్థ
-క్ద
-క్ధ
-క్న
-క్ప
-క్ఫ
-క్బ
-క్భ
-క్మ
-క్య
-క్ర
-క్ఱ
-క్ల
-క్ళ
-క్వ
-క్శ
-క్ష
-క్స
-క్హ
-త్క
-త్ఖ
-త్గ
-త్ఘ
-త్ఙ
-త్చ
-త్ఛ
-త్జ
-త్ఝ
-త్ఞ
-త్ట
-త్ఠ
-త్డ
-త్ఢ
-త్ణ
-త్త
-త్థ
-త్ద
-త్ధ
-త్న
-త్ప
-త్ఫ
-త్బ
-త్భ
-త్మ
-త్య
-త్ర
-త్ఱ
-త్ల
-త్ళ
-త్వ
-త్శ
-త్ష
-త్స
-త్హ
-న్క
-న్ఖ
-న్గ
-న్ఘ
-న్ఙ
-న్చ
-న్ఛ
-న్జ
-న్ఝ
-న్ఞ
-న్ట
-న్ఠ
-న్డ
-న్ఢ
-న్ణ
-న్త
-న్థ
-న్ద
-న్ధ
-న్న
-న్ప
-న్ఫ
-న్బ
-న్భ
-న్మ
-న్య
-న్ర
-న్ఱ
-న్ల
-న్ళ
-న్వ
-న్శ
-న్ష
-న్స
-న్హ
-మ్క
-మ్ఖ
-మ్గ
-మ్ఘ
-మ్ఙ
-మ్చ
-మ్ఛ
-మ్జ
-మ్ఝ
-మ్ఞ
-మ్ట
-మ్ఠ
-మ్డ
-మ్ఢ
-మ్ణ
-మ్త
-మ్థ
-మ్ద
-మ్ధ
-మ్న
-మ్ప
-మ్ఫ
-మ్బ
-మ్భ
-మ్మ
-మ్య
-మ్ర
-మ్ఱ
-మ్ల
-మ్ళ
-మ్వ
-మ్శ
-మ్ష
-మ్స
-మ్హ
-య్క
-య్ఖ
-య్గ
-య్ఘ
-య్ఙ
-య్చ
-య్ఛ
-య్జ
-య్ఝ
-య్ఞ
-య్ట
-య్ఠ
-య్డ
-య్ఢ
-య్ణ
-య్త
-య్థ
-య్ద
-య్ధ
-య్న
-య్ప
-య్ఫ
-య్బ
-య్భ
-య్మ
-య్య
-య్ర
-య్ఱ
-య్ల
-య్ళ
-య్వ
-య్శ
-య్ష
-య్స
-య్హ
-ర్క
-ర్ఖ
-ర్గ
-ర్ఘ
-ర్ఙ
-ర్చ
-ర్ఛ
-ర్జ
-ర్ఝ
-ర్ఞ
-ర్ట
-ర్ఠ
-ర్డ
-ర్ఢ
-ర్ణ
-ర్త
-ర్థ
-ర్ద
-ర్ధ
-ర్న
-ర్ప
-ర్ఫ
-ర్బ
-ర్భ
-ర్మ
-ర్య
-ర్ర
-ర్ఱ
-ర్ల
-ర్ళ
-ర్వ
-ర్శ
-ర్ష
-ర్స
-ర్హ
-ల్క
-ల్ఖ
-ల్గ
-ల్ఘ
-ల్ఙ
-ల్చ
-ల్ఛ
-ల్జ
-ల్ఝ
-ల్ఞ
-ల్ట
-ల్ఠ
-ల్డ
-ల్ఢ
-ల్ణ
-ల్త
-ల్థ
-ల్ద
-ల్ధ
-ల్న
-ల్ప
-ల్ఫ
-ల్బ
-ల్భ
-ల్మ
-ల్య
-ల్ర
-ల్ఱ
-ల్ల
-ల్ళ
-ల్వ
-ల్శ
-ల్ష
-ల్స
-ల్హ
-వ్క
-వ్ఖ
-వ్గ
-వ్ఘ
-వ్ఙ
-వ్చ
-వ్ఛ
-వ్జ
-వ్ఝ
-వ్ఞ
-వ్ట
-వ్ఠ
-వ్డ
-వ్ఢ
-వ్ణ
-వ్త
-వ్థ
-వ్ద
-వ్ధ
-వ్న
-వ్ప
-వ్ఫ
-వ్బ
-వ్భ
-వ్మ
-వ్య
-వ్ర
-వ్ఱ
-వ్ల
-వ్ళ
-వ్వ
-వ్శ
-వ్ష
-వ్స
-వ్హ
-స్త్ర
-స్త్రి
-స్త్రీ
-ష్ట్ర
-షటరీ
-క్ష్మ
-క్ష్మి
diff --git a/test/shape/texts/in-house/shaper-khmer/misc.txt b/test/shape/texts/in-house/shaper-khmer/misc.txt
deleted file mode 100644 (file)
index 3bbffe7..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-ខ្មែ
-ជា
-ថ្ងៃ
-មា
-ម្ពុ
-រ
-រី
-រ៍
-សៅ
-រ្ឥ
-ងឹ្ឈ
-ង្ឈឹ
-ង្គ្រ
-ង្រ្គ
-ម៉្លេះ
-ម‌៉្លេះ
-ប៊័
-នែ៎
-កេ្រ
-កៀ្រ
-កោ្រ
-កៅ្រ
-ព៑ា
-កន្ត្រាក់
-កន្រ្សិក់
-កន្រ្សីក់
-ក្សាន្ត
-ក្សិន្ត
-ក្សីន្ត
-ក្សឹន្ត
-ក្សឺន្ត
-ក្សុន្ត
-ក្សូន្ត
-ក្សួន្ត
-ក្សឿន្ត
-ឃ្ល្សាំ
-ឃ្ល្សិះ
-ឃ្ល្សុំ
-ឃ្ល្សុះ
-ឃ្ល្សេះ
-ឃ្ល្សោះ
-ឃ្ល្សំ
-ឃ្ល្សះ
-ញូ
-ញ្ញ
-ញ្ញុ
-ញ្ញូ
-ញ្ញួ
-ត្រ្សៀ
-ត្រ្សេ
-ត្រ្សែ
-ត្រ្សៃ
-ត្រ្សោ
-ត្រ្សៅ
-ធ្លុំក់
-ធ្លោក់
-ធ្លៅក់
-ធ្លំក់
-ម្ត្ល៉ា
-ម្ត្ល៉ុ
-ម្ត្ល៉ឿ
-ម្ត្ល៉ៀ
-យ្យើហ្វ្លៃ
-រ្រ
-សាស្ត្រឃ្ឈងា
-សាស្ត្រឃ្ឈងិ
-សាស្ត្រឃ្ឈងី
-ស្ត្រីវ័ខ្ញ្សា
-ស្រ្តា
-ស្រ្តិ
-ស្រ្តី
-ស្រ្តឹ
-ស្រ្តឺ
-ស្រ្តុ
-ស្រ្តូ
-ស្រ្តួ
-ស្រ្តើ
-ស្រ្តឿ
-ស្រ្ត៊ឿ
-ស្រ្ត៊ៀ
-ស្រ្ត៊េ
-ស្រ្ត៊ែ
-ស្រ្ត៊ៃ
-ស្រ្ត៊ំ
-ហ្គ្ស៊ើ
-ហ្គ្ស៊ឿ
-ហ្គ្ស៊ៀ
-ហ្រ្វង្ក
-ហ្រ្វាំង
diff --git a/test/shape/texts/in-house/shaper-khmer/other-marks-invalid.txt b/test/shape/texts/in-house/shaper-khmer/other-marks-invalid.txt
deleted file mode 100644 (file)
index 213cfc2..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-ព់្ឈា
-ព្ឈា៉
-ព្ឈា៌
-ព្ឈ៌ា
diff --git a/test/shape/texts/in-house/shaper-khmer/other-marks.txt b/test/shape/texts/in-house/shaper-khmer/other-marks.txt
deleted file mode 100644 (file)
index 1fd350c..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-ព្ឈា
-ព្ឈា់
-ព្ឈ់ា
-ព្ឈ៉ា
-ព៉្ឈា
-ព៌្ឈា
-ក៝ៈនូយ្សក៝ៈនហ៝ម់
diff --git a/test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/misc.txt b/test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/misc.txt
deleted file mode 100644 (file)
index 9dc6332..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-သီဟိုဠ်မှ ဉာဏ်ကြီးရှင်သည် အာယုဝဍ္ဎနဆေးညွှန်းစာကို ဇလွန်ဈေးဘေးဗာဒံပင်ထက် အဓိဋ္ဌာန်လျက် ဂဃနဏဖတ်ခဲ့သည်။
-။း
-င်္၎
-နၣ်
-နၢၣ်
-ဂ်ျ
-ဂျ်
diff --git a/test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/otspec.txt b/test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/otspec.txt
deleted file mode 100644 (file)
index e3d460d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-င်္က္ကျြွှေို့်ာှီ့ၤဲံ့းႍ
diff --git a/test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/utn11.txt b/test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/utn11.txt
deleted file mode 100644 (file)
index d5cea7c..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-စာ
-ခါ
-သိက္ခာ
-သဒ္ဓါ
-ညို
-ထုံး
-နေ
-ပေါ
-ဖျား
-ကြေး
-မွေး
-မှု
-ပတ္တာ
-ထင်
-ကြဉ်
-ကော်
-စင်္ကြံ
-သင်္ဘော
-ပသျှူး
-မြွှာ
-သျှောင်
-ကောင်လေးတွေကျောင်းကိုသွားကြတယ်။
-အိပ်ခန်းတံခါးကို
-အိပ်ခန်းတံ⁠ခါးကို
-အင်္ဝေ
-အငွေ
-ယောက်ျား
-ကျွန်ုပ်
-ဝါကျ
-ဂိမှာန်
-ဥယ‌ျာန
-က္လ
-ကျ္လပ်
-နိယ္အ်
diff --git a/test/shape/texts/in-house/shaper-thai/script-lao/misc/sara-am.txt b/test/shape/texts/in-house/shaper-thai/script-lao/misc/sara-am.txt
deleted file mode 100644 (file)
index 234d8c0..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-ດຳ
-ດ໋ຳ
-ດໍ໋າ
-ດ໋ໍາ
-ມັຳ
-ມິຳ
-ມີຳ
-ມຶຳ
-ມືຳ
-ມຸຳ
-ມູຳ
-ມ຺ຳ
-ມ໇ຳ
-ມ່ຳ
-ມ້ຳ
-ມ໊ຳ
-ມ໋ຳ
-ມ໌ຳ
-ມໍຳ
-ມ໎ຳ
diff --git a/test/shape/texts/in-house/shaper-thai/script-thai/misc/misc.txt b/test/shape/texts/in-house/shaper-thai/script-thai/misc/misc.txt
deleted file mode 100644 (file)
index b4f164b..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-ป่ำ
-ป่ำซ้ำพ่อปู่พี่ปี่ฎุฐุญุ
-ก่ํา
-กํ่า
-กุเ
-กะ
-ก่ื
-กื
-กำ
-ก่ำ
-ก่
diff --git a/test/shape/texts/in-house/shaper-thai/script-thai/misc/phinthu.txt b/test/shape/texts/in-house/shaper-thai/script-thai/misc/phinthu.txt
deleted file mode 100644 (file)
index e304777..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-ป
-ปฺ
-ปุ
-ปู
-ปุู
-ปูุ
-ปฺุ
-ปฺุ
-ปฺู
-ปฺู
-ปฺุู
-ปฺุู
-ปฺุู
-ปฺูุ
-ปฺูุ
-ปฺูุ
diff --git a/test/shape/texts/in-house/shaper-thai/script-thai/misc/pua-shaping.txt b/test/shape/texts/in-house/shaper-thai/script-thai/misc/pua-shaping.txt
deleted file mode 100644 (file)
index c17834b..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-นี
-น่
-นี่
-น่ี
-ป็
-ญ
-ญุ
-ฝิ
-ฝิ่
-ฝ่
-ฎู
diff --git a/test/shape/texts/in-house/shaper-thai/script-thai/misc/sara-am.txt b/test/shape/texts/in-house/shaper-thai/script-thai/misc/sara-am.txt
deleted file mode 100644 (file)
index 9f044ce..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-ดำ
-ด๋ำ
-ดํ๋า
-ด๋ํา
-มัำ
-มิำ
-มีำ
-มึำ
-มืำ
-มุำ
-มูำ
-มฺำ
-ม็ำ
-ม่ำ
-ม้ำ
-ม๊ำ
-ม๋ำ
-ม์ำ
-มํำ
-ม๎ำ
diff --git a/test/shape/texts/in-house/shaper-tibetan/script-tibetan/misc/contractions.txt b/test/shape/texts/in-house/shaper-tibetan/script-tibetan/misc/contractions.txt
deleted file mode 100644 (file)
index 46da1af..0000000
+++ /dev/null
@@ -1,612 +0,0 @@
-ཀི་ཀང་
-ཀྐིང་
-ཀི་ཀི་སྭོ་སྭོ་
-ཀིི་སྭོོ་
-ཀུན་དཀྲིས་
-ཀིུས་
-ཀུན་མཁྱེན་
-ཀེུན་
-ཀུན་དགའ་
-ཀུནའ་
-ཀུན་འཇོམས་
-ཀུནོམས་
-ཀུན་བརྡུངས་
-ཀུནྡུང་
-ཀུན་ནས་
-ཀུནྶ་
-ཀུན་རྫོབ་
-ཀོུབ༹་
-ཀུན་གཟིགས་
-ཀིུགས་
-ཀུན་བཟང་
-ཀུན༹ང་
-ཀུན་ཤེས་
-ཀེུས་
-ཀླུ་ཐེབས་
-ཀླེུབས་
-ཀླུ་ཟློག་
-ཀློུག་
-དཀར་པོ་
-དཀརོ་
-དཀར་ཡོལ་
-དཀོལ་
-དཀོན་མཆོག་
-དཀོོག་
-དཀོར་ནོར་
-དཀོོར་
-དཀྱིལ་འཁོར་
-དཀྱོིར་
-བཀའ་དྲིན་
-བཀྲིན་
-བཀྲ་ཤིས་
-བཀྲིས་
-བཀྲ་ཤིས་ཉི་མ་
-བཀྲིསྙི་
-སྐལ་བཟང་
-སྐལ༹ང་
-སྐུ་གསུང་ཐུགས་
-སྐུགས་
-སྐྱེ་རྒུ་
-སྐྱེུ་
-སྐྱེ་མཆེད་
-སྐྱེདེ་
-བསྐྱེད་བསྐྱེད་
-བསྐྱེེད་
-བསྐྱེད་བསྐྱེད་བསྐྱེད་
-བསྐྱེེེད་
-ཁམས་གསུམ་
-ཁམསུཾ་
-ཁུར་ཚོས་
-ཁོུས༹་
-ཁྱད་པར་
-ཁྱདར་
-ཁྱབ་བདག་
-ཁྱབདག་
-ཁྱུ་མཆོག་
-ཁྱོུག་
-ཁྲུན་མེད་
-ཁྲེུད་
-ཁྲུན་རིང་
-ཁྲིུང་
-ཁྲུམས་སྟོད་
-ཁྲོུད་
-ཁྲུམས་སྨད་
-ཁྲུཾད་
-མཁའ་འགྲོ་
-མཁའགྲོ་
-མཁྱེན་མཁྱེན་མཁྱེན་
-མཁྱེེེན་
-འཁོར་འདས་
-འཁོརས་
-འཁོར་བཅས་
-འཁོརས་
-འཁོར་ལོ་
-འཁོོར་
-གུར་ཐོག་
-གོུག་
-གྱུར་ཅིག་
-གྱིུག་
-གྲུ་འཛིན་
-གྲིུན་
-གྲུ་བཞི་
-གྲིུ་
-གྲུ་ཡོན་
-གྲོུན་
-གྲུབ་ཉི་
-གྲུབྙི་
-གྲུབ་ཐོབ་
-གྲོུབ་
-གྲོ་བཞིན་
-གྲོིན་
-གྲོང་ཁྱེར་
-གྲོེར་
-གླང་པོ་
-གླངོ་
-གླེགས་བམ་
-གླེམ་
-དགུང་ཐིག་
-དགིུག་
-དགེ་འདུན་
-དགེུན་
-དགེ་ལུགས་
-དགེུགས་
-དགེ་སློང་
-དགློེང་
-དགྲ་བགེགས་
-དགྲེགས་
-དགྲ་བཅོམ་
-དགྲོམ་
-མགོན་པོ་
-མགོོན་
-འགྲུབ་བྱ་
-འགྲུབྱ་
-འགྲུབ་སྦྱོར་
-འགྲུབྱོར་
-རྒ་ཤི་
-རྒི་
-རྒུན་འབྲུམ་
-རྒྲུམ་
-རྒྱ་མཚོ་
-རྪོ་
-རྒྱལ་པོ་
-རྒྱོལ་
-རྒྱལ་བློན་
-རྒྱལོན་
-རྒྱལ་མཚན་
-རྒྱལ༹ན་
-ངན་ཀྱང་
-ངནྱང་
-ངུར་སྨྲིག་
-ངིུག་
-དངོས་གྲུབ་
-དགྲོུབ་
-གཅུ་གལ་
-གཅུལ་
-བཅུ་གཅིག་
-བཅིུག་
-བཅུ་གཉིས་
-བཅིུས་
-བཅུ་དྲུག་
-བཅྲུག་
-བཅུ་བདུན་
-བཅུན་
-བཅུ་བཞི་
-བཅིུ་
-བཅུ་གསུམ་
-བཅུཾ་
-བཅོ་བརྒྱད་
-བཅྱོད་
-བཅོམ་ལྡན་
-བཅོནཾ་
-བཅོམ་ལྡན་འདས་
-བཅོནྡས་
-ལྕགས་
-ལྕཊ་
-ལྕགས་སྒྲོག་
-ལྕགསྒྲོག་
-ཆ་ཤེས་
-ཆེས་
-ཆགས་ཐོགས་
-ཆཊ་ཐོཊ་
-ཆད་
-ཆྡ་
-ཆུ་དཀྱིལ་
-ཆིུལ་
-ཆུ་སྟོད་
-ཆོུད་
-ཆུ་སྣོད་
-ཆོུད་
-ཆུ་སྨད་
-ཆུཾད་
-ཆུ་ཚོད་
-ཆོུ༹ད་
-ཆུ་སྲིན་
-ཆྲིུན་
-ཆུབ་ཉི་
-ཆུབྙི་
-ཆོ་འཕྲུལ་
-ཆྲོུལ་
-ཆོས་སྤྱོད་
-ཆོསྤྱོད་
-མཆོད་རྟེན་
-མཆོེན་
-འཆི་བདག་
-འཆྡིག་
-འཆི་སྦྱོར་
-འཆྱོིར་
-ཇོ་བོ་
-ཇོོ་
-ཇོ་མོ་
-ཇོོ་
-ཇོ་ཇོ་
-ཇོོ་
-འཇིག་ཉི་
-འཇིགྙི་
-འཇིག་རྟེན་
-འཇིགེན་
-རྗེ་བཙུན་
-རྗེུན༹་
-ཉན་ཐོས་
-ཉནོས་
-ཉི་ཤུ་
-ཉིུ་
-ཉིན་གུང་
-ཉིུང་
-ཉིན་ནག་
-ཉིནག་
-ཉིན་ཚད་
-ཉིན༹ད་
-ཉིན་མཚན་
-ཉི༹ན་
-ཉེར་གཅིག་
-ཉྲེ་གཅིག་
-ཉོན་མོངས་
-ཉོནོངས་
-མཉན་ཡོད་
-མཉོད་
-མཉམ་ཉིད་
-མཉིཾད་
-མཉམ་བཞག་
-མཉཾག་
-སྙིང་རྗེ་
-སྙིངེ་
-བསྙེན་བཀུར་
-བསྙུར་
-ཏིང་འཛིན་
-ཏིངི༹ན་
-གཏི་མུག་
-གཏིུག་
-གཏུན་ཤིང་
-་གཏུནིང་
-གཏུམ་མོ་
-གཏུམོ་
-བཏང་སྙོམས་
-བཏངོཾས་
-རྟག་ཏུ་
-རྟགྟུ་
-སྟག་སྨྱོས་
-སྟྱོས་
-སྟོབས་རྒྱས་
-སྟོབྱས་
-བསྟན་འཛིན་
-བསྟི༹ན་
-ཐམ་པ་
-ཐཾ་པ་
-ཐམས་ཅད་
-ཐཾད་
-ཐུགས་རྗེ་
-ཐུཊེ་
-ཐུགས་བརྩེ་
-ཐེུ༹ཊ་
-ཐུན་མོང་
-ཐུནོང་
-ཐུན་བཞི་
-ཐིུན་
-ཐེག་ཆེན་
-ཐེགེན་
-མཐའ་འཁོབ་
-མཐོབ་
-མཐའ་དག་
-མཐྡག་
-མཐར་ཕྱིན་
-མཐྱིན་
-མཐུན་མོང་
-མཐོུང་
-མཐེ་བོང་
-མཐོེང་
-མཐོ་རིས་
-མཐོིས་
-དུར་ཁྲོད་
-དུརྲོད་
-དུས་དབྱིགས་
-དུསྱིགས་
-དུས་སུ་
-དུསུ་
-དེ་བཞིན་གཤེགས་པ་
-དེནིཊེ་པ་
-དྲག་པོ་
-དྲགོ་
-དྲག་ཤོས་
-དྲགོས་
-དྲང་སྲོང་
-དྲོང་
-དྲུང་དུ་
-དྲུངྡུ་
-དྲུང་ཡིག་
-དྲིུག་
-གདུང་རྟེན་
-གདེུན་
-གདུང་འཛིན་
-གདིུ༹ན་
-གདུབ་བུ་
-གདུབུ་
-བདུག་སྤོས་
-བདོུས་
-བདུད་རྒྱལ་
-བདུདྱལ་
-བདུད་ཉི་
-བདུདྙི་
-བདུད་རྩི་
-བདུདི༹་
-བདེ་ཆེན་
-བདེནེ་
-བདེ་གཤེགས་
-བདཻགས་
-འདུ་བྱེད་
-འདེུད་
-རྡོ་རྗེ་
-རྡོེ་
-སྡིག་སྲིན་
-སྡིན་
-སྡིགས་མཛུབ་
-སྡིུབ་
-སྡུག་བསྔལ་
-སྡུགལ་
-ནབས་སོ་
-ནབསོ་
-ནམ་མཁའ་
-ནམཁའ་
-ནམ་གྲུ་
-ནམྲུ་
-ནུབ་ཕྱོགས་
-ནོུགས་
-ནོར་བུ་
-ནོུར་
-གནམ་སྦྱོར་
-གནྱོཾར་
-གནས་སྐབས་
-གནསྐབས་
-རྣམ་གྲངས་
-རྣངཾས་
-རྣམ་ཤེས་
-རྣཾསེ་
-རྣམས་
-རྣཾས་
-རྣལ་འབྱོར་
-རྣལྱོར་
-སྣ་ཚོགས་
-སྣོ༹གས་
-པི་ལིང་
-པླིང་
-དཔག་མེད་
-དཔགེད་
-དཔལ་ལྡན་
-དཔལྡན་
-དཔལ་བེའུ་
-དཔལེ་
-དཔལ་འབྱོར་
-དཔལྱོར་
-དཔུང་ཚོགས་
-དཔོུགས་
-དཔེ་བྱད་
-དཔྱེད་
-སྤྱན་རས་གཟིགས་
-སྤྱས་གཟིགས་
-སྤྲོས་བྲལ་
-སྤྲོལ་
-ཕན་གནོད་
-ཕནོད་
-ཕུན་ཚོགས་
-ཕུགས་
-ཕོ་ཉ་
-ཕྙོ་
-ཕོ་རོལ་
-ཕརོལ་
-ཕྱག་འཚལ་ལོ་
-ཕྱ༹ལོ་
-ཕྲག་དོག་
-ཕྲོག་
-ཕྲིན་ལས་
-ཕྲིས་
-འཕེལ་ཉི་
-འཕེལྙི་
-འཕྲིན་ལས་
-ཕྲིས་
-བར་ཆད་
-བརད་
-བུ་མོ་
-བོུ་
-བུད་མེད་
-བེུད་
-བུད་ཤིང་
-བིུང་
-བོང་བུ་
-བོུང་
-བྱ་ཚོགས་
-བྱོ༹གས་
-བྱ་རོག་
-བྱོག་
-བྱང་ཆུབ་
-བྱུཾབ་
-བྱང་ཕྱོགས་
-བྱོགས་
-བྱི་བཞིན་
-བྱིནི་
-བྱོལ་སོང་
-བྱོང་
-བྲམ་ཟེ་
-བྲེམ་
-བླུན་པོ་
-བློུན་
-བློ་གྲོས་
-བློས་
-བློན་པོ་
-བློོན་
-དབང་པོ་
-དབངོ་
-དབང་ཕྱུག་
-དབྱུག་
-དབུ་ཐོད་
-དབོུད་
-དབུགས་ཐོབ་
-དབོུབས་
-དབྱེར་མེད་
-དབྱེརེད་
-འབྲས་བུ་
-འབྲུས་
-སྦྱོར་ཉི་
-སྦྱོརྙི་
-སྦྲང་རྩི་
-སྦྲིང༹་
-མ་རིག་
-མྲིག་
-མི་འཕྲོད་ཉི་
-མི་འཕྲོདྙི་
-མིག་དམར་
-མིར་
-མིང་གཟུགས་
-མིངུགས་
-མུ་གེ་
-མེུ་
-མུ་སྙེགས་
-མེུགས་
-མུ་ཏིག་
-མིུག་
-མུ་སྟེགས་
-མེུགས་
-མུ་མེན་
-མེུན་
-མེ་ཏོག་
-མྟོེག་
-མེ་ལོང་
-མོེང་
-མོན་གྲུ་
-མོནྲུ་
-མོན་དྲེ་
-མོནྲེ་
-མྱ་ངན་
-མྱན་
-དམག་དཔུང་
-དམུང་
-དམག་དཔོན་
-དམོན་
-སྨིན་དྲུག་
-སྨིནྲུག་
-ཙན་དན་
-ཙྡན་
-གཙུག་ཏོར་
-གཙོུར་
-རྩ་བཏོན་
-རྩོན་
-བརྩོན་འགྲུས་
-བརྩུས་
-ཚུལ་ཁྲིམས་
-ཚུལྲིམས་
-ཚུལ་ལྡན་
-ཚུལྡན་
-ཚེ་ལྡན་
-ཚྡེན་
-མཚན་ཉིད་
-མཚིད་
-མཚན་ཚད་
-མཚན༹ད་
-མཚམས་ཞུས་
-མཚྮུཾས་
-རྫུ་འཕྲུལ་
-རྫྲུལ་
-རྫུས་སྐྱེས་
-རྫེུས་
-རྫེ་བཙུན་
-རྫེུན་
-ཞུ་གསོལ་
-ཞོུལ་
-གཞལ་སྒང་
-གཞལྒང་
-གཞུ་ཐོག་
-གཞོུག་
-གཞུ་འདོམས་
-གཞོུམས་
-གཞོན་ནུ་
-གཞོནུ་
-གཟུ་བོ་
-གཟོུ་
-གཟུ་ཤིང་
-གཟིུང་
-གཟུག་གིན་འདུག་
-གཟུགིན་འདུག་
-གཟུག་ཟེར་
-གཟེུར་
-གཟུག་གཟེར་
-གཟེུར་
-གཟུགས་སྐུ་
-གཟུགསྐུ་
-གཟུགས་སྡུག་
-གཟུགསྡུག་
-གཟུགས་མེད་
-གཟེུད་
-འོད་དཀར་
-འོདཀར་
-འོད་ཟེར་
-འོེར་
-ཡན་ལག་
-ཡནག་
-ཡི་གེ་
-ཡིེ་
-ཡིན་ནམ་
-ཡིནམ་
-ཡེ་ཤེས་
-ཡེེས་
-ཡོན་ཏན་
-ཡྟོན་
-རབ་བྱུང་
-རབྱུང་
-རལ་གྲི་
-རལྲི་
-རིན་ཆེན་
-རིནེ་
-རིན་པོ་ཆེ་
-རིནོེ་
-རོང་ཡུལ་
-རོུལ་
-ལང་འཚོ་
-ལངོ༹་
-ལས་བཟང་
-ལསང་
-ལེགས་སྦྱར་
-ལེགསྦྱར་
-ལོངས་སྐུ་
-ལོངསྐུ་
-ལོངས་སྤྱོད་
-ལོངསྤྱོད་
-ཤ་འཁོན་
-ཤྑོན་
-ཤིན་ཏུ་
-ཤིནྟུ་
-ཤེས་བྱ་
-ཤྱེས་
-ཤེས་རབ་
-ཤེབ་
-ས་བོན་
-སོན་
-སངས་རྒྱས་
-སངྱས་
-སེང་གེ་
-སེངྒེ་
-སེམས་
-སྶེ་
-སེམས་ཅན་
-སེཾན་
-སེམས་དཔའ་
-སེཾདའ་
-སོ་སོ་བ་
-སོོབ་
-སོ་སོར་
-སོོར་
-སོགས་
-སོཊ་
-སོམས་ཤིག་
-སོསཾ་ཤིག་
-སྲེག་སྦྱོར་
-སྲེགྱོར་
-སྲེག་ཚེས་
-སྲོེས་
-སློབ་འདོད་
-སློོད་
-སློབ་དཔོན་
-སློོན་
-གསུང་རབ་
-གསུབ་
-བསོད་སྙོམས་
-བསྙོཾདས་
-བསོད་ནམས་
-བསོདཾས་
-ལྷ་ཚོགས་
-ལྷོ༹གས་
-ལྷ་མཚམས་
-ལྷ༹ཾས་
-ལྷག་
-ལྷྒ་
-ལྷན་རྒྱས་
-ལྷྱས་
-ལྷན་ཅིག་
-ལྷིག་
-ལྷན་གཅིག་
-ལྷིག་
-ལྷན་ཚོགས་
-ལྷནོ༹ཊ་
-ལྷུན་གྲུབ་
-ལྷུནྲུབ་
-ལྷོ་ཕྱོགས་
-ལྷྱོགས་
-ཨོ་རྒྱན་
-ཨྱོན་
diff --git a/test/shape/texts/in-house/shaper-tibetan/script-tibetan/misc/misc.txt b/test/shape/texts/in-house/shaper-tibetan/script-tibetan/misc/misc.txt
deleted file mode 100644 (file)
index a5d4082..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-སྟྲཱ
-ཀ࿆ྃ
diff --git a/test/shape/texts/in-house/shaper-use/script-batak/misc.txt b/test/shape/texts/in-house/shaper-use/script-batak/misc.txt
deleted file mode 100644 (file)
index c8ae04b..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-ᯂᯩ
-ᯄ᯦ᯩ
-ᯇᯪᯰ
-ᯓᯩᯰ
-ᯄᯮ
-ᯃᯮ
-ᯎᯮ
-ᯞᯮ
-ᯖᯪᯇ᯲
diff --git a/test/shape/texts/in-house/shaper-use/script-buginese/misc.txt b/test/shape/texts/in-house/shaper-use/script-buginese/misc.txt
deleted file mode 100644 (file)
index 5c1a03a..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-ᨒᨚᨈᨑ
-ᨔᨑ
-ᨅᨔ ᨈᨚ ᨅᨙᨀ
-ᨕᨒᨚ ᨆᨒᨗᨕᨘ ᨅᨛᨈᨘᨕᨊ
-ᨕᨗᨉᨚ ᨔᨘᨑᨛ
-ᨕᨗᨊ ᨔᨘᨑᨛ
-ᨕᨊ ᨔᨘᨑᨛ
-
-ᨊᨀᨚ      ᨕᨛᨃ       ᨈᨕᨘᨄᨔᨒ᨞   ᨕᨍ  ᨆᨘᨄᨈᨒᨒᨚᨓᨗ     ᨄᨌᨒᨆᨘ ᨑᨗᨈᨚᨄᨔᨒᨕᨙ᨞
-ᨄᨔᨗᨈᨘᨍᨘᨓᨗᨆᨘᨈᨚᨓᨗᨔ       ᨕᨔᨒᨊ    ᨄᨌᨒᨆᨘ᨞      ᨕᨄ  ᨕᨗᨀᨚᨊᨈᨘ   ᨊᨁᨗᨒᨗ ᨉᨙᨓᨈᨕᨙ᨞
-ᨊᨀᨚ      ᨅᨕᨗᨌᨘᨆᨘᨄᨗ     ᨕᨔᨒᨊ    ᨈᨕᨘᨓᨙ᨞      ᨆᨘᨄᨙᨑᨍᨕᨗᨔ     ᨄᨉᨈᨚᨓᨗ᨞
-ᨊᨀᨚ      ᨄᨔᨒᨕᨗ ᨈᨕᨘᨓᨙ᨞      ᨕᨍ  ᨈᨗᨆᨘᨌᨒᨕᨗ        ᨑᨗᨔᨗᨈᨗᨊᨍᨊᨕᨙᨈᨚᨔ      ᨕᨔᨒᨊ᨞
-
-ᨕᨛᨛᨃ   ᨕᨛᨃ       ᨄ ᨙᨑ᨞   ᨕᨛᨃ        ᨙᨔᨕᨘᨓ        ᨓᨛᨈᨘ᨞
-ᨕᨛᨃ       ᨙᨔᨕᨘᨓ        ᨕᨑᨘ       ᨆᨀᨘᨋᨕᨗ      ᨑᨗ  ᨒᨘᨓᨘ᨞ ᨆᨔᨒ       ᨕᨘᨒᨗ᨞
-
-ᨄᨘᨑᨊᨗᨀᨚ  ᨆᨙᨋ?
-ᨉᨙᨄ
-
-ᨆᨙᨒᨚ ᨀ ᨌᨛᨙᨆ
-ᨔᨙᨉᨗ
-ᨉᨘᨓ
-ᨈᨛᨒᨘ
-ᨕᨛᨄ
-ᨒᨗᨆ
-ᨕᨛᨊᨛ
-ᨄᨗᨈᨘ
-ᨕᨑᨘᨓ
-ᨕᨙᨔᨑ
-ᨔᨄᨘᨒᨚ
-ᨉᨘᨓᨄᨘᨒᨚ
-ᨈᨛᨒᨘᨄᨘᨒᨚ
-ᨄᨈᨄᨘᨒᨚ
-ᨒᨗᨆᨄᨘᨒᨚ
-ᨕᨛᨊᨛᨄᨘᨒᨚᨊ
-ᨄᨗᨈᨘᨄᨘᨒᨚ
-ᨕᨑᨘᨓᨄᨘᨒᨚᨊ
-ᨕᨙᨔᨑᨄᨘᨒᨚᨊ
-ᨔᨗᨑᨈᨘ
-ᨔᨗᨔᨛᨅᨘ
-ᨔᨗᨒᨔ
-ᨔᨗᨀᨚᨈᨗ
-
-ᨅᨔ ᨕᨘᨁᨗ
-
-ᨅᨔ ᨆᨀᨔᨑ
-ᨅᨒ
-ᨅᨚᨒᨚ
-ᨅᨅ
-ᨌᨗᨄᨘᨑᨘ
-ᨉᨚᨕᨙ
-ᨕᨗᨐᨚ
-ᨒᨚᨄᨚ
-ᨔᨒᨚ
-ᨈ ᨅᨙᨙ
-ᨈᨙᨊ
-ᨀᨑᨕᨙ
-ᨕᨄ ᨀᨑᨙᨅ?
-ᨒᨀᨙᨀᨚ ᨆᨕᨙ?
-ᨅᨒ
-ᨅᨚᨈᨚ
-ᨑᨈᨔ
-ᨅᨈᨒ
-ᨅᨗᨒ
-ᨁᨙᨒᨙ ᨁᨙᨒᨙ
-ᨀᨚᨀᨚ
-ᨍᨑ
-ᨅᨙᨅᨙ
-ᨆᨚᨈᨙᨑᨙ
-ᨂᨑᨙ
diff --git a/test/shape/texts/in-house/shaper-use/script-cham/misc.txt b/test/shape/texts/in-house/shaper-use/script-cham/misc.txt
deleted file mode 100644 (file)
index 32b793a..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-ꩀꨴ
-ꨗꨪꨇꨮꩃꨯꨗꨱꨧꨩꩂꨯꨨꨱꩃꨨꨮ
-ꨆꨴꨯ
diff --git a/test/shape/texts/in-house/shaper-use/script-javanese/misc.txt b/test/shape/texts/in-house/shaper-use/script-javanese/misc.txt
deleted file mode 100644 (file)
index 16c3d9c..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-ꦥꦺ
-ꦟ꧀ꦢꦿ
-ꦥꦺꦴꦂꦠꦸꦒꦭ꧀
-꧋
-​꧅
-꧑꧐꧇
-꧒꧐꧐꧔
-꧑꧘꧘꧕꧇
-ꦥꦤꦶꦠꦿ꧇
-ꦏꦠꦿꦁꦔꦤ꧀
-꧅꧉ꦟ꧀ꦢꦿ꧉꧅
-ꦥꦺꦔꦼꦠ꧀ꦠꦤ꧀
-ꦄꦒꦸꦱ꧀ꦠꦸꦱ꧀꧇
-ꦮꦸꦭꦤ꧀ꦗꦤꦸꦮꦫꦶ
-ꦠꦸꦮꦤ꧀​ꦯꦶꦏꦺꦕꦶ
-ꦲꦶꦁ​ꦱꦸꦂꦪ​ꦏꦥꦶꦁ꧇
-ꦯꦺꦟꦦꦡꦶ​ꦲꦶꦁ​ꦔꦭꦓ꧈
-ꦲꦸꦠꦮꦶ​ꦯꦸꦂꦪ​ꦏꦥꦶꦁ꧇
-ꦥꦩꦼꦁꦏꦸꦤꦶꦫꦺꦁ​ꦨꦸꦮꦤ꧈
-ꦩꦁꦏꦾ​ꦲꦶꦁ​ꦔꦪꦸꦓꦾꦏꦂꦡ꧈
-ꦠꦤ꧀ꦧꦁꦏꦶꦠ꧀ꦲꦔꦸꦕꦥ꧀ꦥꦼꦤ꧈
-ꦠꦸꦮꦤ꧀​ꦈꦤ꧀​ꦕꦸꦤ꧀​ꦲꦺꦴꦏ꧀
-ꦲꦢꦶꦤꦶꦁꦔꦿꦠ꧀ꦏꦿꦡꦺꦴꦤ꧀ꦲꦗꦶ꧈
-ꦥꦔꦿꦺꦃꦲꦶꦁꦩꦱ꧀ꦗꦶꦢ꧀ꦱꦭꦶꦏꦶꦤ꧀
-ꦠꦼꦤ꧀ꦠꦽꦩ꧀ꦥꦿꦢꦱꦶꦃ​ꦒꦼꦁꦲꦭꦶꦠ꧀
-ꦲꦶꦁꦏꦁ​ꦲꦁꦒꦫꦥ꧀​ꦫꦢꦺꦤ꧀​ꦯꦸꦰꦺꦗ
-ꦫꦢꦺꦤ꧀ꦲꦗꦶꦩ꦳ꦸꦃꦏ꦳ꦩ꦳ꦢ꧀‌ꦔꦢ꧀ꦤꦤ꧀
-ꦮꦸꦭꦤ꧀ꦗꦸꦩꦢꦶꦭꦮꦭ꧀ꦠꦲꦸꦤ꧀ꦗꦶꦩ꧀ꦩꦮꦭ꧀
-ꦑꦭꦶꦦꦡꦸꦭ꧀ꦭꦃ​ꦲꦶꦁꦏꦁ​ꦗꦸꦩꦼꦤꦼꦁ​ꦏꦥꦶꦁ
-ꦠꦤ꧀ꦝꦶꦁꦔꦤ꧀ꦤꦶꦥꦸꦤ꧀ꦱꦮꦸꦁ​ꦧꦭ꧀ꦧꦭ꧀ꦭꦤ꧀꧈
-ꦩꦶꦤꦺꦴꦁꦏ​ꦥꦺꦔꦼꦠ꧀ꦠꦤ꧀ꦗꦸꦩꦼꦤꦼꦁ​ꦢꦊꦩ꧀ꦟꦡ꧈
-ꦏꦑꦒꦓꦔꦕꦖꦗꦙꦚꦛꦜꦝꦞꦟꦠꦡꦢꦣꦤꦥꦦꦧꦨꦩꦪꦫꦭꦮꦯꦰꦱꦲ
-ꦢꦺꦤ꧀ꦤꦶꦁ​ꦫꦢꦺꦤ꧀ꦔꦤ꧀ꦠꦺꦤ꧀ꦡꦸꦩꦼꦁꦒꦸꦁ​ꦦꦿꦮꦶꦫꦢꦶꦂꦗ꧉
-ꦲꦶꦁꦩꦡꦫꦩ꧀ꦢꦸꦏ꧀ꦫꦸꦩꦸꦲꦸꦤ꧀​ꦠꦼꦊꦁꦔꦶꦁ​ꦏꦫꦡꦺꦴꦤ꧀ꦗꦮꦶ꧈
-ꦮꦼꦝꦶ​ꦒꦩ꧀ꦥꦶꦁ​ꦏꦗꦼꦁ​ꦭꦤ꧀ꦱꦤ꧀ꦤꦺꦱ꧀ꦱꦤ꧀ꦤꦺꦱ꧀ꦱꦶꦥꦸꦤ꧀​
-ꦩꦺꦴꦁꦏ​ꦱꦫꦮꦺꦢꦶꦤꦶꦁꦫꦠ꧀​ꦢꦺꦫꦤꦿꦸꦱ꧀ꦏꦼꦤ꧀ꦲꦸꦗ꧀ꦮꦭꦤ꧀ꦤꦶꦁ꧈
-ꦩꦶꦤꦺꦴꦁꦏ​ꦮꦏꦶꦭ꧀ꦪꦪꦱꦤ꧀ꦏꦭ꧀ꦭꦺꦴꦲꦸꦱ꧀ꦠꦼ​ꦒꦸꦭ꧀ꦧꦺꦤꦏꦶꦲꦤ꧀꧇
-ꦥꦶꦤꦽꦤꦃꦏꦼꦤ꧀ꦩꦁꦒꦺꦤ꧀ꦤꦶꦥꦸꦤ꧀​ꦲꦶꦁ​ꦥꦥꦤ꧀ꦲꦶꦁꦏꦁ​ꦥꦏꦺꦴꦭꦶꦃ꧈
-ꦠꦸꦩꦸꦗ꧀ꦮꦺꦁ​ꦊꦉꦱ꧀ꦤꦼꦂꦫꦶꦥꦸꦤ꧀​ꦱꦸꦱꦠꦾ​ꦠꦼꦩꦼꦤ꧀ꦤꦸꦲꦺꦴꦤ꧀ꦤꦶ꧈
-ꦲꦶꦁꦏꦁ​ꦲꦔꦽꦁꦒꦤ꧀ꦤꦶ​ꦑꦫꦡꦺꦴꦤ꧀ꦢꦊꦩ꧀ꦲꦶꦁ​ꦔꦪꦸꦓꦾꦏꦂꦡ​ꦲꦢꦶꦟꦶꦁꦔꦿꦠ꧀꧈
-ꦗꦸꦩꦼꦤꦼꦁ​ꦢꦊꦩ꧀ꦟꦡ​ꦲꦩꦉꦁꦔꦶ​ꦢꦶꦤ꧀ꦠꦼꦤ꧀ꦱꦼꦤꦺꦤ꧀ꦥꦺꦴꦤ꧀​ꦠꦁꦒꦭ꧀ꦏꦥꦶꦁ꧇
-꧋ꦱꦧꦼꦤ꧀ꦲꦸꦮꦺꦴꦁꦏꦭꦲꦶꦫꦏꦺꦏꦤ꧀ꦛꦶꦩꦂꦢꦶꦏꦭꦤ꧀ꦢꦂꦧꦺꦩꦂꦠꦧꦠ꧀ꦭꦤ꧀ꦲꦏ꧀ꦲꦏ꧀ꦏꦁꦥꦝ꧉
-ꦱꦁꦏꦶꦁ​ꦥꦫ​ꦧꦺꦴꦁꦱ​ꦡꦾꦺꦴꦁꦲ꧀ꦮ​ꦒꦺꦴꦭꦺꦴꦁꦔꦤ꧀ꦲꦶꦁ​ꦔꦪꦸꦓꦾꦏꦂꦡ​ꦲꦢꦶꦤꦶꦁꦔꦿꦠ꧀
-ꦔꦂꦰ​ꦢꦊꦩ꧀​ꦯꦩ꧀ꦦꦺꦪꦤ꧀ꦢꦊꦩ꧀​ꦲꦶꦁꦑꦁ​ꦯꦶꦟꦸꦮꦸꦤ꧀ꦏꦗꦼꦁ​ꦯꦸꦭ꧀ꦡꦤ꧀​ꦲꦩꦼꦁꦑꦸꦨꦸꦮꦟ꧈
-ꦲꦢꦼꦒ꧀ꦒꦶꦁ​ꦩꦱ꧀ꦗꦶꦢ꧀ꦱꦭꦶꦏꦶꦤ꧀​ꦪꦱꦤ꧀ꦤꦶꦥꦸꦤ꧀ꦫꦢꦺꦤ꧀ꦔꦤ꧀ꦠꦺꦤ꧀ꦡꦸꦩꦼꦁꦒꦸꦁ​ꦦꦿꦮꦶꦫꦢꦶꦂꦗ꧈
-ꦒꦸꦧꦼꦂꦤꦸꦂ​ꦝꦃꦲꦺꦫꦃ​ꦆꦱ꧀ꦠꦶꦩꦺꦮꦃ​ꦪꦺꦴꦒꦾꦏꦂꦠ​ꦠꦸꦮꦶꦤ꧀ꦲꦶꦁꦏꦁ​ꦩꦶꦤꦸꦭ꧀ꦪ​ꦠꦸꦮꦤ꧀ꦪꦺꦴꦱꦺ​ꦧ꧀ꦭꦤ꧀ꦕꦺꦴ꧈
-ꦲꦶꦁꦒꦶꦃ​ꦥꦸꦤꦶꦏ​ꦧꦧ꧀ꦮꦺꦴꦤ꧀ꦠꦼꦤ꧀ꦤꦶꦥꦸꦤ꧀ꦱꦮꦸꦁ​ꦧꦭ꧀ꦧꦭ꧀ꦭꦤ꧀ꦠꦤꦃ​ꦔꦿꦶꦏꦶ​ꦲꦶꦁꦏꦁ​ꦱꦩꦶ​ꦔ꧀ꦭꦸꦫꦸꦒ꧀ꦝꦠꦼꦁ​ꦌꦫꦺꦴꦦꦃ꧈
-ꦱꦺꦴꦏꦺꦴꦁꦔꦤ꧀ꦱꦏꦶꦁ​ꦥꦫ​ꦩꦸꦱ꧀ꦭꦶꦩꦶꦤ꧀​ꦢꦺꦤ꧀ꦤꦺ​ꦲꦶꦁꦏꦁ​ꦔꦿꦚ꧀ꦕꦁ​ꦱꦲ​ꦔꦮꦠ꧀ꦲꦮꦠ꧀ꦠꦶ​ꦥꦁꦒꦫꦥ꧀ꦥꦶꦥꦸꦤ꧀ꦩꦱ꧀ꦗꦶꦢ꧀​ꦫꦢꦺꦤ꧀ꦔꦧꦺꦲꦶ​ꦕꦺꦴꦤ꧀ꦢꦿꦢꦶꦥꦿꦗ꧈
-ꦭꦗꦼꦁ​ꦏꦮꦏꦥ꧀ꦥꦏꦼꦤ꧀ꦏꦁꦒꦺ​ꦥꦂꦭꦸꦤꦶꦁ​ꦆꦱ꧀ꦭꦩ꧀ꦭꦤ꧀ꦩꦸꦱ꧀ꦭꦶꦩꦶꦤ꧀ꦲꦶꦁ​ꦱꦭꦩꦶꦭꦩꦶꦤꦶꦥꦸꦤ꧀​ꦥꦩ꧀ꦧꦶꦏꦏ꧀ꦏꦶꦥꦸꦤ꧀ꦲꦶꦁ​ꦢꦶꦤ꧀ꦠꦼꦤ꧀ꦏꦼꦩꦶꦱ꧀ꦏꦭꦶꦮꦺꦴꦤ꧀ꦠꦁꦒꦭ꧀ꦏꦥꦶꦁ꧇
-ꦲꦶꦁ​ꦔꦿꦶꦏꦶ​ꦔꦼꦕꦿꦠ꧀ꦒꦩ꧀ꦧꦂꦫꦶꦥꦸꦤ꧀ꦱꦮꦸꦁ​ꦱꦮꦸꦁ​ꦮꦲꦸ​ꦤꦭꦶꦏ​ꦤꦸꦗꦸ​ꦠꦤ꧀ꦝꦶꦁꦔꦤ꧀ꦏꦭꦶꦪꦤ꧀ꦱꦮꦸꦁ​ꦧꦭ꧀ꦧꦭ꧀ꦭꦤ꧀ꦱꦏꦶꦁ​ꦲꦺꦴꦁꦓꦫꦶꦪꦼ​ꦮꦺꦴꦤ꧀ꦠꦼꦤ꧀ꦲꦶꦁ​ꦲꦭꦸꦤ꧀ꦲꦭꦸꦤ꧀꧇
-ꦱꦢꦺꦫꦺꦁꦔꦶꦥꦸꦤ꧀ꦩꦱ꧀ꦗꦶꦢ꧀ꦱꦭꦶꦏꦶꦤ꧀ꦏꦒꦫꦥ꧀​ꦱꦩ꧀ꦥꦸꦤ꧀ꦮꦺꦴꦤ꧀ꦠꦼꦤ꧀ꦩꦲꦸꦗꦸꦢ꧀ꦥꦤ꧀ꦝꦼꦩꦺꦤ꧀ꦤꦶꦁ​ꦩꦱ꧀ꦗꦶꦢ꧀​ꦯꦸꦫꦩ꧀ꦧꦶ​ꦱꦲ​ꦥꦭꦩ꧀ꦥꦃꦲꦤ꧀​ꦱꦂꦠ​ꦧꦺꦴꦤ꧀ꦝꦱꦮꦠꦮꦶꦱ꧀​ꦏꦢꦺꦴꦱ꧀ꦠ꧇
-ꦩꦸꦭ꧀ꦪꦏ꧀ꦏꦏꦺ​ꦈꦩ꧀ꦧꦸꦭ꧀ꦧꦶꦤꦁꦔꦸꦤ꧀ꦠꦩ꧀ꦩꦤ꧀ꦱꦂꦫꦶ​ꦏꦊꦏ꧀ꦱꦤ꧀ꦤꦏ꧀ꦏꦏꦼꦤ꧀ꦏꦤ꧀ꦛꦶ​ꦥꦚꦼꦁꦏꦸꦪꦸꦁꦔꦶꦥꦸꦤ꧀ꦪꦪꦱ꧀ꦱꦤ꧀ꦏꦭ꧀ꦭꦲꦸꦱ꧀ꦠꦼ​ꦒꦸꦭ꧀ꦧꦼꦤ꧀ꦏꦶꦲꦤ꧀ꦱꦲ​ꦏꦂꦉꦱ꧀ꦩꦺꦏ꧀ꦏꦏꦼꦤ꧀ꦢꦶꦤꦶꦁ​ꦲꦶꦁꦏꦁ​ꦩꦶꦤꦸꦭ꧀ꦪ​ꦯꦿꦶ​ꦯꦸꦭ꧀ꦠꦤ꧀ꦲꦩꦁꦏꦸꦨꦸꦮꦤ꧇
-ꦠꦸꦮꦤ꧀Dr꧇ꦯꦶꦩ꧀​ꦏꦶꦄꦌ
-ꦠꦸꦮꦤ꧀Ir꧇ꦭꦶꦩ꧀​ꦆꦁꦲ꧀ꦮꦶ
diff --git a/test/shape/texts/in-house/shaper-use/script-kaithi/misc.txt b/test/shape/texts/in-house/shaper-use/script-kaithi/misc.txt
deleted file mode 100644 (file)
index 5503298..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-𑂍   𑂎 𑂍𑂹𑂎 𑂍𑂹𑂎𑂱 𑂍𑂹𑂍𑂹𑂎𑂱 𑂍𑂹𑂎𑂹𑂎𑂱 𑂍𑂱 𑂍𑂹𑂍𑂹𑂎𑂱 𑂍𑂹𑂎𑂹𑂎𑂱𑂁 𑂍𑂹𑂎𑂹𑂎𑂱𑂀 𑂎𑂱𑂁
-𑂩𑂍 𑂩𑂹𑂍 𑂩𑂹𑂞 𑂩𑂹𑂍𑂹𑂍 𑂩𑂹𑂍
-𑂩𑂹𑂍𑂵 𑂩𑂹𑂍𑂵
-𑂩𑂍 𑂩𑂹𑂍 𑂩𑂹𑂞 𑂩𑂹𑂍𑂹𑂍 𑂩𑂹𑂍
-𑂩𑂹𑂍𑂵 𑂩𑂹𑂍𑂵
-𑂩𑂍 𑂩𑂹𑂍𑂱  𑂩𑂹𑂍𑂹𑂍𑂱  𑂩𑂹𑂍𑂹𑂍𑂵  𑂩𑂹𑂔𑂹𑂍𑂹𑂍𑂱 𑂩𑂹𑂞
diff --git a/test/shape/texts/in-house/shaper-use/script-kharoshti/misc.txt b/test/shape/texts/in-house/shaper-use/script-kharoshti/misc.txt
deleted file mode 100644 (file)
index 5a563c1..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-𐨤𐨪𐨌𐨪𐨿𐨗𐨸𐨅𐨌𐨏
-𐨀𐨁
-𐨐𐨁
-𐨠𐨁
-𐨀𐨂
-𐨱𐨂
-𐨨𐨂
-𐨀𐨃
-𐨨𐨃
-𐨀𐨅
-𐨐𐨅
-𐨠𐨅
-𐨡𐨅
-𐨀𐨆
-𐨤𐨆
-𐨨𐨌
-𐨯𐨍
-𐨀𐨎
-𐨐𐨏
-𐨗𐨸
-𐨒𐨹
-𐨨𐨺
-𐨢𐨁𐨐𐨿
-𐨐𐨿𐨮
-𐨨𐨿𐨪
-𐨬𐨿𐨱
-𐨯𐨿𐨟
-𐨯𐨿𐨩
-𐨪𐨿𐨟
-𐨟𐨿𐨪
-𐨫𐨿𐨤
-𐨤𐨿𐨫
-𐨐𐨿𐨫
-𐨟𐨿𐨬
-𐨐𐨿𐨟
-𐨑𐨿𐨐𐨿𐨮
diff --git a/test/shape/texts/in-house/shaper-use/script-tai-tham/misc.txt b/test/shape/texts/in-house/shaper-use/script-tai-tham/misc.txt
deleted file mode 100644 (file)
index 62e9317..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-ᨠ᩠ᨠᩮᩕ
-ᩋᩫᨶ᩠ᨲᩕᩣ᩠ᨿ
diff --git a/test/shape/texts/in-house/shaper-use/script-tai-tham/torture.txt b/test/shape/texts/in-house/shaper-use/script-tai-tham/torture.txt
deleted file mode 100644 (file)
index faee302..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-ᨣᩕ᩵ᩣᩴᨣᩕ᩠ᩅᩁ
-ᨣᩕ᩵ᩮ᩠ᨦᨣᩕᩢ᩠ᨯ
-ᩅᩥᨣᩅᩰᩬᩡ
-ᩋᩫᨶ᩠ᨲᩕᩣ᩠ᨿ
-ᨶᩫᨶ᩠ᨲᩕᩧ
-ᩈ᩠ᨾ᩵ᩣᩴᩈ᩠ᨾᩮᩬᩥ
-ᩀᩢ᩠᩵ᨦᨶ᩶ᩣᩴ
-ᩉᩫ᩠ᨯᩉ᩠ᨿᩬᩴ᩶
-ᩅᩥᨱ᩠ᨬᩣ᩠ᨱ
-ᨠᩕᩫ᩠ᨮᩉᩫ᩠ᩅᨷᩫ᩠ᩅ
-ᨷᩴ᩠᩵ᨯᩲ᩶
-ᨷᩴ᩠᩶ᨯᩲ᩵
-ᨺᩮᩥᩢ᩠ᨠ
-ᨡᩧ᩠᩶ᨦ᩻
-ᨸᩢ᩠᩶ᨶ
-ᨵᩥᩢ᩠᩶ᨶ
-ᨷᩣ᩠ᨦ
-ᨷᩤ᩠ᨦ
-ᨻᩮᩬᩧ᩵ᩋᩉᩲ᩶
-ᨾᩨᨤᩕᩢ᩠᩵ᨦ
-ᨴᩣᩴᩋᩁᩲ
-ᩈᩢᨬ᩠ᨬᩣ
-◌ᩲ
index b80cef5..2ed4539 100644 (file)
@@ -221,8 +221,6 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
-DIRECTWRITE_CXXFLAGS = @DIRECTWRITE_CXXFLAGS@
-DIRECTWRITE_LIBS = @DIRECTWRITE_LIBS@
 DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -320,6 +318,8 @@ STRIP = @STRIP@
 UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
 UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
 VERSION = @VERSION@
+WASM_CFLAGS = @WASM_CFLAGS@
+WASM_LIBS = @WASM_LIBS@
 _GI_EXP_DATADIR = @_GI_EXP_DATADIR@
 _GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@
 abs_builddir = @abs_builddir@
index 337e1cf..9a7d08c 100644 (file)
@@ -7,7 +7,10 @@ SUBDIRS = repack_tests
 
 EXTRA_DIST += \
        $(TESTS) \
+       $(DISABLED_TESTS) \
+       expected/32bit_var_store \
        expected/basics \
+       expected/preprocess \
        expected/full-font \
        expected/glyf_bug_3131 \
        expected/cff-full-font \
@@ -38,23 +41,38 @@ EXTRA_DIST += \
        expected/layout.gdef-attachlist \
        expected/layout.notonastaliqurdu \
        expected/layout.tinos \
-       expected/layout.default_features \
        expected/layout.duplicate_features \
        expected/layout.unsorted_featurelist \
        expected/layout.drop_feature \
+       expected/no_layout_closure \
        expected/cmap \
        expected/cmap14 \
        expected/sbix \
        expected/colr \
        expected/colr_glyphs \
        expected/colrv1 \
+       expected/colrv1_copy_varstore \
        expected/colr_with_components \
        expected/cbdt \
        expected/variable \
        expected/glyph_names \
+       expected/glyph_map \
        expected/math \
        expected/math_coverage_offset \
        expected/post \
+       expected/full_instance \
+       expected/instance_feature_variations \
+       expected/instantiate_glyf \
+       expected/instantiate_cff2 \
+       expected/pin_all_at_default \
+       expected/instance_no_double_free \
+       expected/mvar_full_instance \
+       expected/instance_comp_glyph_empty_child \
+       expected/post_apply_mvar_delta \
+       expected/apply_cvar_delta \
+       expected/collect_name_ids \
+       expected/instantiate_colrv1 \
+       expected/instantiate_cff2_update_metrics \
        fonts \
        profiles \
        $(NULL)
index 898cf12..d864327 100644 (file)
@@ -89,10 +89,12 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-TESTS = tests/basics.tests tests/cbdt.tests tests/cff-full-font.tests \
-       tests/cff-japanese.tests tests/cff.notoserifmyanmar.tests \
-       tests/cmap.tests tests/cmap14.tests tests/colr.tests \
-       tests/colr_glyphs.tests tests/colrv1.tests \
+TESTS = tests/32bit_var_store.tests tests/basics.tests \
+       tests/preprocess.tests tests/cbdt.tests \
+       tests/cff-full-font.tests tests/cff-japanese.tests \
+       tests/cff.notoserifmyanmar.tests tests/cmap.tests \
+       tests/cmap14.tests tests/colr.tests tests/colr_glyphs.tests \
+       tests/colrv1.tests tests/colrv1_copy_varstore.tests \
        tests/colr_with_components.tests tests/full-font.tests \
        tests/glyf_bug_3131.tests tests/japanese.tests \
        tests/layout.context.tests tests/layout.context_format2.tests \
@@ -107,13 +109,22 @@ TESTS = tests/basics.tests tests/cbdt.tests tests/cff-full-font.tests \
        tests/layout.gsub5_format2.tests tests/layout.gsub6.tests \
        tests/layout.gsub8.tests tests/layout.khmer.tests \
        tests/layout.notonastaliqurdu.tests tests/layout.tests \
-       tests/layout.tinos.tests tests/layout.default_features.tests \
-       tests/layout.duplicate_features.tests \
+       tests/layout.tinos.tests tests/layout.duplicate_features.tests \
        tests/layout.unsorted_featurelist.tests \
-       tests/layout.drop_feature.tests tests/sbix.tests \
-       tests/variable.tests tests/glyph_names.tests tests/math.tests \
+       tests/layout.drop_feature.tests tests/no_layout_closure.tests \
+       tests/sbix.tests tests/variable.tests tests/glyph_names.tests \
+       tests/glyph_map.tests tests/math.tests \
        tests/math_coverage_offset.tests tests/post.tests \
-       $(am__EXEEXT_1)
+       tests/full_instance.tests \
+       tests/instance_feature_variations.tests \
+       tests/instantiate_glyf.tests tests/instantiate_cff2.tests \
+       tests/pin_all_at_default.tests \
+       tests/instance_no_double_free.tests \
+       tests/mvar_full_instance.tests \
+       tests/instance_comp_glyph_empty_child.tests \
+       tests/post_apply_mvar_delta.tests tests/apply_cvar_delta.tests \
+       tests/collect_name_ids.tests tests/instantiate_colrv1.tests \
+       tests/instantiate_cff2_update_metrics.tests $(am__EXEEXT_1)
 XFAIL_TESTS = $(am__EXEEXT_1)
 subdir = test/subset/data
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -449,8 +460,6 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
-DIRECTWRITE_CXXFLAGS = @DIRECTWRITE_CXXFLAGS@
-DIRECTWRITE_LIBS = @DIRECTWRITE_LIBS@
 DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -548,6 +557,8 @@ STRIP = @STRIP@
 UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
 UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
 VERSION = @VERSION@
+WASM_CFLAGS = @WASM_CFLAGS@
+WASM_LIBS = @WASM_LIBS@
 _GI_EXP_DATADIR = @_GI_EXP_DATADIR@
 _GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@
 abs_builddir = @abs_builddir@
@@ -607,7 +618,8 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 NULL = 
-EXTRA_DIST = $(TESTS) expected/basics expected/full-font \
+EXTRA_DIST = $(TESTS) $(DISABLED_TESTS) expected/32bit_var_store \
+       expected/basics expected/preprocess expected/full-font \
        expected/glyf_bug_3131 expected/cff-full-font \
        expected/japanese expected/cff-japanese \
        expected/cff.notoserifmyanmar expected/layout \
@@ -623,19 +635,29 @@ EXTRA_DIST = $(TESTS) expected/basics expected/full-font \
        expected/layout.context_format2 expected/layout.gdef-varstore \
        expected/layout.gdef-attachlist \
        expected/layout.notonastaliqurdu expected/layout.tinos \
-       expected/layout.default_features \
        expected/layout.duplicate_features \
        expected/layout.unsorted_featurelist \
-       expected/layout.drop_feature expected/cmap expected/cmap14 \
-       expected/sbix expected/colr expected/colr_glyphs \
-       expected/colrv1 expected/colr_with_components expected/cbdt \
-       expected/variable expected/glyph_names expected/math \
-       expected/math_coverage_offset expected/post fonts profiles \
+       expected/layout.drop_feature expected/no_layout_closure \
+       expected/cmap expected/cmap14 expected/sbix expected/colr \
+       expected/colr_glyphs expected/colrv1 \
+       expected/colrv1_copy_varstore expected/colr_with_components \
+       expected/cbdt expected/variable expected/glyph_names \
+       expected/glyph_map expected/math expected/math_coverage_offset \
+       expected/post expected/full_instance \
+       expected/instance_feature_variations expected/instantiate_glyf \
+       expected/instantiate_cff2 expected/pin_all_at_default \
+       expected/instance_no_double_free expected/mvar_full_instance \
+       expected/instance_comp_glyph_empty_child \
+       expected/post_apply_mvar_delta expected/apply_cvar_delta \
+       expected/collect_name_ids expected/instantiate_colrv1 \
+       expected/instantiate_cff2_update_metrics fonts profiles \
        $(NULL)
 CLEANFILES = 
 SUBDIRS = repack_tests
 TEST_EXTENSIONS = .tests
 TESTS_LOG_COMPILER = $(srcdir)/../run-tests.py $(top_builddir)/util/hb-subset$(EXEEXT)
+
+# Disabled because instancing is only available w/ experimental API on.
 DISABLED_TESTS = \
        $(NULL)
 
index 94a910c..398f2b8 100644 (file)
@@ -1,5 +1,7 @@
 TESTS = \
+       tests/32bit_var_store.tests \
        tests/basics.tests \
+       tests/preprocess.tests \
        tests/cbdt.tests \
        tests/cff-full-font.tests \
        tests/cff-japanese.tests \
@@ -9,6 +11,7 @@ TESTS = \
        tests/colr.tests \
        tests/colr_glyphs.tests \
        tests/colrv1.tests \
+       tests/colrv1_copy_varstore.tests \
        tests/colr_with_components.tests \
        tests/full-font.tests \
        tests/glyf_bug_3131.tests \
@@ -37,16 +40,30 @@ TESTS = \
        tests/layout.notonastaliqurdu.tests \
        tests/layout.tests \
        tests/layout.tinos.tests \
-       tests/layout.default_features.tests \
        tests/layout.duplicate_features.tests \
        tests/layout.unsorted_featurelist.tests \
        tests/layout.drop_feature.tests \
+       tests/no_layout_closure.tests \
         tests/sbix.tests \
        tests/variable.tests \
        tests/glyph_names.tests \
+       tests/glyph_map.tests \
        tests/math.tests \
        tests/math_coverage_offset.tests \
        tests/post.tests \
+       tests/full_instance.tests \
+       tests/instance_feature_variations.tests \
+       tests/instantiate_glyf.tests \
+       tests/instantiate_cff2.tests \
+       tests/pin_all_at_default.tests \
+       tests/instance_no_double_free.tests \
+       tests/mvar_full_instance.tests \
+       tests/instance_comp_glyph_empty_child.tests \
+       tests/post_apply_mvar_delta.tests \
+       tests/apply_cvar_delta.tests \
+       tests/collect_name_ids.tests \
+       tests/instantiate_colrv1.tests \
+       tests/instantiate_cff2_update_metrics.tests \
        $(NULL)
 
 # TODO: re-enable once colrv1 subsetting is stabilized.
@@ -57,5 +74,6 @@ TESTS = \
 XFAIL_TESTS = \
        $(NULL)
 
+# Disabled because instancing is only available w/ experimental API on.
 DISABLED_TESTS = \
        $(NULL)
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62,63,64.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62,63,64.otf
new file mode 100644 (file)
index 0000000..6b28104
Binary files /dev/null and b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62,63,64.otf differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62.otf
new file mode 100644 (file)
index 0000000..42a573e
Binary files /dev/null and b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,62.otf differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,63.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,63.otf
new file mode 100644 (file)
index 0000000..50f1965
Binary files /dev/null and b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,63.otf differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,64.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,64.otf
new file mode 100644 (file)
index 0000000..77dbebe
Binary files /dev/null and b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61,64.otf differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61.otf
new file mode 100644 (file)
index 0000000..e2d1818
Binary files /dev/null and b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.61.otf differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.62.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.62.otf
new file mode 100644 (file)
index 0000000..bc42c26
Binary files /dev/null and b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.62.otf differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.63.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.63.otf
new file mode 100644 (file)
index 0000000..7a3481d
Binary files /dev/null and b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.63.otf differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.64.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.64.otf
new file mode 100644 (file)
index 0000000..4fb8b80
Binary files /dev/null and b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline-retain-gids.64.otf differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62,63,64.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62,63,64.otf
new file mode 100644 (file)
index 0000000..6b28104
Binary files /dev/null and b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62,63,64.otf differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62.otf
new file mode 100644 (file)
index 0000000..42a573e
Binary files /dev/null and b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,62.otf differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,63.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,63.otf
new file mode 100644 (file)
index 0000000..4b6ad6f
Binary files /dev/null and b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,63.otf differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,64.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,64.otf
new file mode 100644 (file)
index 0000000..c861f65
Binary files /dev/null and b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61,64.otf differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61.otf
new file mode 100644 (file)
index 0000000..e2d1818
Binary files /dev/null and b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.61.otf differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.62.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.62.otf
new file mode 100644 (file)
index 0000000..bfecc0c
Binary files /dev/null and b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.62.otf differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.63.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.63.otf
new file mode 100644 (file)
index 0000000..d742e54
Binary files /dev/null and b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.63.otf differ
diff --git a/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.64.otf b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.64.otf
new file mode 100644 (file)
index 0000000..69e32ea
Binary files /dev/null and b/test/subset/data/expected/32bit_var_store/32bit_var_store.notdef-outline.64.otf differ
diff --git a/test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.retain-all-codepoint.wght=300.ttf b/test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.retain-all-codepoint.wght=300.ttf
new file mode 100644 (file)
index 0000000..ca91b51
Binary files /dev/null and b/test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.retain-all-codepoint.wght=300.ttf differ
diff --git a/test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.retain-all-codepoint.wght=700.ttf b/test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.retain-all-codepoint.wght=700.ttf
new file mode 100644 (file)
index 0000000..2545786
Binary files /dev/null and b/test/subset/data/expected/apply_cvar_delta/Comfortaa-Regular-new.default.retain-all-codepoint.wght=700.ttf differ
diff --git a/test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.retain-all-codepoint.wght=300.ttf b/test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.retain-all-codepoint.wght=300.ttf
new file mode 100644 (file)
index 0000000..d2680eb
Binary files /dev/null and b/test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.retain-all-codepoint.wght=300.ttf differ
diff --git a/test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.retain-all-codepoint.wght=700.ttf b/test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.retain-all-codepoint.wght=700.ttf
new file mode 100644 (file)
index 0000000..d590978
Binary files /dev/null and b/test/subset/data/expected/apply_cvar_delta/Muli-ABC.default.retain-all-codepoint.wght=700.ttf differ
diff --git a/test/subset/data/expected/collect_name_ids/SourceSerif4Variable-Roman_subset.keep-all-layout-features.retain-all-codepoint.otf b/test/subset/data/expected/collect_name_ids/SourceSerif4Variable-Roman_subset.keep-all-layout-features.retain-all-codepoint.otf
new file mode 100644 (file)
index 0000000..c375eaa
Binary files /dev/null and b/test/subset/data/expected/collect_name_ids/SourceSerif4Variable-Roman_subset.keep-all-layout-features.retain-all-codepoint.otf differ
index 67020e2..8c93da9 100644 (file)
Binary files a/test/subset/data/expected/colr_with_components/colr-table.default.6B.ttf and b/test/subset/data/expected/colr_with_components/colr-table.default.6B.ttf differ
index a2be484..6857f7b 100644 (file)
Binary files a/test/subset/data/expected/colr_with_components/colr-table.drop-hints-retain-gids.6B.ttf and b/test/subset/data/expected/colr_with_components/colr-table.drop-hints-retain-gids.6B.ttf differ
index 67020e2..8c93da9 100644 (file)
Binary files a/test/subset/data/expected/colr_with_components/colr-table.drop-hints.6B.ttf and b/test/subset/data/expected/colr_with_components/colr-table.drop-hints.6B.ttf differ
index a2be484..6857f7b 100644 (file)
Binary files a/test/subset/data/expected/colr_with_components/colr-table.retain-gids.6B.ttf and b/test/subset/data/expected/colr_with_components/colr-table.retain-gids.6B.ttf differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.default.41,42.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.default.41,42.ttf
new file mode 100644 (file)
index 0000000..e28036b
Binary files /dev/null and b/test/subset/data/expected/colrv1_copy_varstore/Foldit.default.41,42.ttf differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.default.41.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.default.41.ttf
new file mode 100644 (file)
index 0000000..a75cd17
Binary files /dev/null and b/test/subset/data/expected/colrv1_copy_varstore/Foldit.default.41.ttf differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.default.retain-all-codepoint.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.default.retain-all-codepoint.ttf
new file mode 100644 (file)
index 0000000..4981bd0
Binary files /dev/null and b/test/subset/data/expected/colrv1_copy_varstore/Foldit.default.retain-all-codepoint.ttf differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.41,42.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.41,42.ttf
new file mode 100644 (file)
index 0000000..d6d25f6
Binary files /dev/null and b/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.41,42.ttf differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.41.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.41.ttf
new file mode 100644 (file)
index 0000000..47d2eab
Binary files /dev/null and b/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.41.ttf differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.retain-all-codepoint.ttf
new file mode 100644 (file)
index 0000000..5df3ab1
Binary files /dev/null and b/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints-retain-gids.retain-all-codepoint.ttf differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.41,42.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.41,42.ttf
new file mode 100644 (file)
index 0000000..48c337e
Binary files /dev/null and b/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.41,42.ttf differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.41.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.41.ttf
new file mode 100644 (file)
index 0000000..5777f2a
Binary files /dev/null and b/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.41.ttf differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.retain-all-codepoint.ttf
new file mode 100644 (file)
index 0000000..5df3ab1
Binary files /dev/null and b/test/subset/data/expected/colrv1_copy_varstore/Foldit.drop-hints.retain-all-codepoint.ttf differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.41,42.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.41,42.ttf
new file mode 100644 (file)
index 0000000..78cc03d
Binary files /dev/null and b/test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.41,42.ttf differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.41.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.41.ttf
new file mode 100644 (file)
index 0000000..1abc3ec
Binary files /dev/null and b/test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.41.ttf differ
diff --git a/test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.retain-all-codepoint.ttf
new file mode 100644 (file)
index 0000000..4981bd0
Binary files /dev/null and b/test/subset/data/expected/colrv1_copy_varstore/Foldit.retain-gids.retain-all-codepoint.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644 (file)
index 0000000..b66269f
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644 (file)
index 0000000..4d50684
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.1FC,21,41,20,62,63.ttf
new file mode 100644 (file)
index 0000000..38de0fe
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.1FC,21,41,20,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.1FC,21,41,20,62,63.ttf
new file mode 100644 (file)
index 0000000..2de0e2c
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.1FC,21,41,20,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644 (file)
index 0000000..cd3d30a
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63.ttf
new file mode 100644 (file)
index 0000000..3c04b26
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.61,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf
new file mode 100644 (file)
index 0000000..d7d7a73
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644 (file)
index 0000000..9dbd498
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63.ttf
new file mode 100644 (file)
index 0000000..836df1c
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.61,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.D7,D8,D9,DA,DE.ttf
new file mode 100644 (file)
index 0000000..263c644
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts-features.D7,D8,D9,DA,DE.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.1FC,21,41,20,62,63.ttf
new file mode 100644 (file)
index 0000000..6fed674
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.1FC,21,41,20,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644 (file)
index 0000000..e6dd264
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63.ttf
new file mode 100644 (file)
index 0000000..5ecaaed
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.61,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.D7,D8,D9,DA,DE.ttf
new file mode 100644 (file)
index 0000000..69d7875
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.filter-scripts.D7,D8,D9,DA,DE.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.1FC,21,41,20,62,63.ttf
new file mode 100644 (file)
index 0000000..5f46234
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.1FC,21,41,20,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644 (file)
index 0000000..424209a
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63.ttf
new file mode 100644 (file)
index 0000000..5397c5b
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.61,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.D7,D8,D9,DA,DE.ttf
new file mode 100644 (file)
index 0000000..8660d67
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.no-scripts.D7,D8,D9,DA,DE.ttf differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644 (file)
index 0000000..57ff1f9
Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63,64,65,66,67,68,69,6A,6B.ttf differ
index 930d871..b0069ab 100644 (file)
Binary files a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.1FC,21,41,20,62,63.ttf and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.1FC,21,41,20,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644 (file)
index 0000000..57ff1f9
Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63,64,65,66,67,68,69,6A,6B.ttf differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.1FC,21,41,20,62,63.ttf
new file mode 100644 (file)
index 0000000..d450397
Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.1FC,21,41,20,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.1FC,21,41,20,62,63.ttf
new file mode 100644 (file)
index 0000000..d7dbd75
Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.1FC,21,41,20,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644 (file)
index 0000000..f86d3dd
Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63.ttf
new file mode 100644 (file)
index 0000000..03a14d0
Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.61,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf
new file mode 100644 (file)
index 0000000..cac2b1e
Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644 (file)
index 0000000..715c714
Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63.ttf
new file mode 100644 (file)
index 0000000..7d9ca25
Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.61,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.D7,D8,D9,DA,DE.ttf
new file mode 100644 (file)
index 0000000..b402ea9
Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts-features.D7,D8,D9,DA,DE.ttf differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.1FC,21,41,20,62,63.ttf
new file mode 100644 (file)
index 0000000..40fb67a
Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.1FC,21,41,20,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644 (file)
index 0000000..28c3605
Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63.ttf
new file mode 100644 (file)
index 0000000..590ccb9
Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.61,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.D7,D8,D9,DA,DE.ttf
new file mode 100644 (file)
index 0000000..bbab9ca
Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.filter-scripts.D7,D8,D9,DA,DE.ttf differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.1FC,21,41,20,62,63.ttf
new file mode 100644 (file)
index 0000000..08bdd83
Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.1FC,21,41,20,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf
new file mode 100644 (file)
index 0000000..baa3468
Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63.ttf
new file mode 100644 (file)
index 0000000..06dfe74
Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.61,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.D7,D8,D9,DA,DE.ttf
new file mode 100644 (file)
index 0000000..c278d1f
Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.no-scripts.D7,D8,D9,DA,DE.ttf differ
diff --git a/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=150,wdth=80.ttf b/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=150,wdth=80.ttf
new file mode 100644 (file)
index 0000000..6c7a145
Binary files /dev/null and b/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=150,wdth=80.ttf differ
diff --git a/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=300,wdth=90.ttf b/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=300,wdth=90.ttf
new file mode 100644 (file)
index 0000000..2a02cdb
Binary files /dev/null and b/test/subset/data/expected/full_instance/Roboto-Variable.default.retain-all-codepoint.wght=300,wdth=90.ttf differ
diff --git a/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=150,wdth=80.ttf b/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=150,wdth=80.ttf
new file mode 100644 (file)
index 0000000..6c7a145
Binary files /dev/null and b/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=150,wdth=80.ttf differ
diff --git a/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=300,wdth=90.ttf b/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=300,wdth=90.ttf
new file mode 100644 (file)
index 0000000..2a02cdb
Binary files /dev/null and b/test/subset/data/expected/full_instance/Roboto-Variable.no-prune-unicode-ranges.retain-all-codepoint.wght=300,wdth=90.ttf differ
diff --git a/test/subset/data/expected/glyph_map/Roboto-Regular.glyph_map_roboto.41,43,61,66,69.ttf b/test/subset/data/expected/glyph_map/Roboto-Regular.glyph_map_roboto.41,43,61,66,69.ttf
new file mode 100644 (file)
index 0000000..a4c8266
Binary files /dev/null and b/test/subset/data/expected/glyph_map/Roboto-Regular.glyph_map_roboto.41,43,61,66,69.ttf differ
diff --git a/test/subset/data/expected/instance_comp_glyph_empty_child/RobotoMono.default.retain-all-codepoint.wght=700.ttf b/test/subset/data/expected/instance_comp_glyph_empty_child/RobotoMono.default.retain-all-codepoint.wght=700.ttf
new file mode 100644 (file)
index 0000000..16084db
Binary files /dev/null and b/test/subset/data/expected/instance_comp_glyph_empty_child/RobotoMono.default.retain-all-codepoint.wght=700.ttf differ
diff --git a/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.30DD.wght=100.ttf b/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.30DD.wght=100.ttf
new file mode 100644 (file)
index 0000000..7026094
Binary files /dev/null and b/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.30DD.wght=100.ttf differ
diff --git a/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.30DD.wght=400.ttf b/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.30DD.wght=400.ttf
new file mode 100644 (file)
index 0000000..a01f7bc
Binary files /dev/null and b/test/subset/data/expected/instance_feature_variations/MPLUS1-Variable.default.30DD.wght=400.ttf differ
diff --git a/test/subset/data/expected/instance_no_double_free/Handjet.default.retain-all-codepoint.wght=100,ELGR=1,ELSH=2.ttf b/test/subset/data/expected/instance_no_double_free/Handjet.default.retain-all-codepoint.wght=100,ELGR=1,ELSH=2.ttf
new file mode 100644 (file)
index 0000000..87aa06b
Binary files /dev/null and b/test/subset/data/expected/instance_no_double_free/Handjet.default.retain-all-codepoint.wght=100,ELGR=1,ELSH=2.ttf differ
diff --git a/test/subset/data/expected/instance_no_double_free/Handjet.notdef-outline.retain-all-codepoint.wght=100,ELGR=1,ELSH=2.ttf b/test/subset/data/expected/instance_no_double_free/Handjet.notdef-outline.retain-all-codepoint.wght=100,ELGR=1,ELSH=2.ttf
new file mode 100644 (file)
index 0000000..ca588d1
Binary files /dev/null and b/test/subset/data/expected/instance_no_double_free/Handjet.notdef-outline.retain-all-codepoint.wght=100,ELGR=1,ELSH=2.ttf differ
diff --git a/test/subset/data/expected/instantiate_cff2/AdobeVFPrototype.default.retain-all-codepoint.wght=650,CNTR=50.otf b/test/subset/data/expected/instantiate_cff2/AdobeVFPrototype.default.retain-all-codepoint.wght=650,CNTR=50.otf
new file mode 100644 (file)
index 0000000..a870015
Binary files /dev/null and b/test/subset/data/expected/instantiate_cff2/AdobeVFPrototype.default.retain-all-codepoint.wght=650,CNTR=50.otf differ
diff --git a/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.default.retain-all-codepoint.wght=800.otf b/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.default.retain-all-codepoint.wght=800.otf
new file mode 100644 (file)
index 0000000..def60cf
Binary files /dev/null and b/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.default.retain-all-codepoint.wght=800.otf differ
diff --git a/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.retain-gids.retain-all-codepoint.wght=800.otf b/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.retain-gids.retain-all-codepoint.wght=800.otf
new file mode 100644 (file)
index 0000000..def60cf
Binary files /dev/null and b/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.retain-gids.retain-all-codepoint.wght=800.otf differ
diff --git a/test/subset/data/expected/instantiate_colrv1/Foldit.default.retain-all-codepoint.wght=900.ttf b/test/subset/data/expected/instantiate_colrv1/Foldit.default.retain-all-codepoint.wght=900.ttf
new file mode 100644 (file)
index 0000000..fba3a72
Binary files /dev/null and b/test/subset/data/expected/instantiate_colrv1/Foldit.default.retain-all-codepoint.wght=900.ttf differ
diff --git a/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=200,wdth=90.ttf b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=200,wdth=90.ttf
new file mode 100644 (file)
index 0000000..190aee1
Binary files /dev/null and b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=200,wdth=90.ttf differ
diff --git a/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=650,wdth=85.ttf b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=650,wdth=85.ttf
new file mode 100644 (file)
index 0000000..38264db
Binary files /dev/null and b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.ABC.default.retain-all-codepoint.wght=650,wdth=85.ttf differ
diff --git a/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=200,wdth=90.ttf b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=200,wdth=90.ttf
new file mode 100644 (file)
index 0000000..0fa5526
Binary files /dev/null and b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=200,wdth=90.ttf differ
diff --git a/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=650,wdth=85.ttf b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=650,wdth=85.ttf
new file mode 100644 (file)
index 0000000..4b07bbc
Binary files /dev/null and b/test/subset/data/expected/instantiate_glyf/Roboto-Variable.composite.default.retain-all-codepoint.wght=650,wdth=85.ttf differ
index 70dd0fd..5ae5d5b 100644 (file)
Binary files a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf and b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf differ
index f9349f6..cfe6648 100644 (file)
Binary files a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42.otf and b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42.otf differ
index 07e6ad5..0e98d1a 100644 (file)
Binary files a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf and b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf differ
index 070f9ec..6530ab6 100644 (file)
Binary files a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42,43.otf and b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42,43.otf differ
index 60fd45c..cac1abb 100644 (file)
Binary files a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42.otf and b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42.otf differ
index 07e6ad5..0e98d1a 100644 (file)
Binary files a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf and b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf differ
diff --git a/test/subset/data/expected/layout.default_features/FranklinGothic-Regular.default.61,63,68,69.ttf b/test/subset/data/expected/layout.default_features/FranklinGothic-Regular.default.61,63,68,69.ttf
deleted file mode 100644 (file)
index 4e7ce29..0000000
Binary files a/test/subset/data/expected/layout.default_features/FranklinGothic-Regular.default.61,63,68,69.ttf and /dev/null differ
diff --git a/test/subset/data/expected/layout.default_features/FranklinGothic-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.default_features/FranklinGothic-Regular.default.retain-all-codepoint.ttf
deleted file mode 100644 (file)
index 566cac6..0000000
Binary files a/test/subset/data/expected/layout.default_features/FranklinGothic-Regular.default.retain-all-codepoint.ttf and /dev/null differ
diff --git a/test/subset/data/expected/layout.default_features/FranklinGothic-Regular.layout-test.61,63,68,69.ttf b/test/subset/data/expected/layout.default_features/FranklinGothic-Regular.layout-test.61,63,68,69.ttf
deleted file mode 100644 (file)
index b0ee6ab..0000000
Binary files a/test/subset/data/expected/layout.default_features/FranklinGothic-Regular.layout-test.61,63,68,69.ttf and /dev/null differ
diff --git a/test/subset/data/expected/layout.default_features/FranklinGothic-Regular.layout-test.retain-all-codepoint.ttf b/test/subset/data/expected/layout.default_features/FranklinGothic-Regular.layout-test.retain-all-codepoint.ttf
deleted file mode 100644 (file)
index c341ab8..0000000
Binary files a/test/subset/data/expected/layout.default_features/FranklinGothic-Regular.layout-test.retain-all-codepoint.ttf and /dev/null differ
diff --git a/test/subset/data/expected/layout.default_features/FranklinGothic-Regular.retain-gids.61,63,68,69.ttf b/test/subset/data/expected/layout.default_features/FranklinGothic-Regular.retain-gids.61,63,68,69.ttf
deleted file mode 100644 (file)
index 9e1167f..0000000
Binary files a/test/subset/data/expected/layout.default_features/FranklinGothic-Regular.retain-gids.61,63,68,69.ttf and /dev/null differ
diff --git a/test/subset/data/expected/layout.default_features/FranklinGothic-Regular.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/layout.default_features/FranklinGothic-Regular.retain-gids.retain-all-codepoint.ttf
deleted file mode 100644 (file)
index 0f89424..0000000
Binary files a/test/subset/data/expected/layout.default_features/FranklinGothic-Regular.retain-gids.retain-all-codepoint.ttf and /dev/null differ
index ab0c1d1..c64ef97 100644 (file)
Binary files a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.retain-all-codepoint.ttf and b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.retain-all-codepoint.ttf differ
index 2306381..b4a2677 100644 (file)
Binary files a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.retain-all-codepoint.ttf and b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.retain-all-codepoint.ttf differ
index ab0c1d1..c64ef97 100644 (file)
Binary files a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.retain-all-codepoint.ttf and b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.retain-all-codepoint.ttf differ
index e939b0b..428bf0f 100644 (file)
Binary files a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43,57.otf and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43,57.otf differ
index 798b856..81ff828 100644 (file)
Binary files a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43.otf and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43.otf differ
index a0d7fee..46db5bb 100644 (file)
Binary files a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42.otf and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42.otf differ
index 68654ea..f3ae184 100644 (file)
Binary files a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,56,57.otf and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,56,57.otf differ
index 6e0aa21..c484821 100644 (file)
Binary files a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41.otf and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41.otf differ
index 600edf9..0dfcfc4 100644 (file)
Binary files a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.42,57.otf and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.42,57.otf differ
index 0606b02..f7b7a36 100644 (file)
Binary files a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43,57.otf and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43,57.otf differ
index 76fb186..294bfad 100644 (file)
Binary files a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43.otf and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43.otf differ
index 13437bc..8c2c8da 100644 (file)
Binary files a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42.otf and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42.otf differ
index 64e299a..8f454b7 100644 (file)
Binary files a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,56,57.otf and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,56,57.otf differ
index ada8cb6..bea2117 100644 (file)
Binary files a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41.otf and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41.otf differ
index e38300e..8419d4e 100644 (file)
Binary files a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.42,57.otf and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.42,57.otf differ
index 1d3f3cd..f6b78bc 100644 (file)
Binary files a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf and b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf differ
index 5a0d0c4..6f2e7ef 100644 (file)
Binary files a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42.otf and b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42.otf differ
index b3d6ae9..ff0595a 100644 (file)
Binary files a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf and b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf differ
index 0a693c6..8086051 100644 (file)
Binary files a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42,43.otf and b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42,43.otf differ
index 128c1d4..0a26e0f 100644 (file)
Binary files a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42.otf and b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42.otf differ
index b3d6ae9..ff0595a 100644 (file)
Binary files a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.retain-all-codepoint.otf and b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.retain-all-codepoint.otf differ
index cbfad3d..e402e57 100644 (file)
Binary files a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,62D,628.ttf and b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,62D,628.ttf differ
index f4938d8..5683d04 100644 (file)
Binary files a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,6D2.ttf and b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,6D2.ttf differ
index 6ac7bcd..e19feda 100644 (file)
Binary files a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.63A,64A,631.ttf and b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.63A,64A,631.ttf differ
index ba99d30..ea153c9 100644 (file)
Binary files a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.retain-all-codepoint.ttf and b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.retain-all-codepoint.ttf differ
index 81ee9e8..fb9746e 100644 (file)
Binary files a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,62D,628.ttf and b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,62D,628.ttf differ
index 3f5367a..81319fd 100644 (file)
Binary files a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,6D2.ttf and b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,6D2.ttf differ
index 2610a64..b9aa70b 100644 (file)
Binary files a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.63A,64A,631.ttf and b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.63A,64A,631.ttf differ
index e41720c..4458d5f 100644 (file)
Binary files a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.retain-all-codepoint.ttf and b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.retain-all-codepoint.ttf differ
diff --git a/test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.retain-all-codepoint.wght=150,wdth=80,CTGR=0.ttf b/test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.retain-all-codepoint.wght=150,wdth=80,CTGR=0.ttf
new file mode 100644 (file)
index 0000000..5a46c64
Binary files /dev/null and b/test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.retain-all-codepoint.wght=150,wdth=80,CTGR=0.ttf differ
diff --git a/test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.retain-all-codepoint.wght=300,wdth=90,CTGR=0.ttf b/test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.retain-all-codepoint.wght=300,wdth=90,CTGR=0.ttf
new file mode 100644 (file)
index 0000000..dad3489
Binary files /dev/null and b/test/subset/data/expected/mvar_full_instance/NotoSans-VF.abc.no-layout.retain-all-codepoint.wght=300,wdth=90,CTGR=0.ttf differ
diff --git a/test/subset/data/expected/no_layout_closure/Roboto-Regular.no-layout-closure-gids.no-unicodes.ttf b/test/subset/data/expected/no_layout_closure/Roboto-Regular.no-layout-closure-gids.no-unicodes.ttf
new file mode 100644 (file)
index 0000000..73458aa
Binary files /dev/null and b/test/subset/data/expected/no_layout_closure/Roboto-Regular.no-layout-closure-gids.no-unicodes.ttf differ
diff --git a/test/subset/data/expected/no_layout_closure/Roboto-Regular.no-layout-closure-gids2.no-unicodes.ttf b/test/subset/data/expected/no_layout_closure/Roboto-Regular.no-layout-closure-gids2.no-unicodes.ttf
new file mode 100644 (file)
index 0000000..592a5f3
Binary files /dev/null and b/test/subset/data/expected/no_layout_closure/Roboto-Regular.no-layout-closure-gids2.no-unicodes.ttf differ
diff --git a/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=400,wdth=100.0.ttf b/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=400,wdth=100.0.ttf
new file mode 100644 (file)
index 0000000..adceacd
Binary files /dev/null and b/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=400,wdth=100.0.ttf differ
diff --git a/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=drop,wdth=100.ttf b/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=drop,wdth=100.ttf
new file mode 100644 (file)
index 0000000..adceacd
Binary files /dev/null and b/test/subset/data/expected/pin_all_at_default/Roboto-Variable.ABC.default.retain-all-codepoint.wght=drop,wdth=100.ttf differ
diff --git a/test/subset/data/expected/post_apply_mvar_delta/Recursive-ABC.no-layout.retain-all-codepoint.wght=400,CASL=0,CRSV=0,MONO=0,slnt=0.ttf b/test/subset/data/expected/post_apply_mvar_delta/Recursive-ABC.no-layout.retain-all-codepoint.wght=400,CASL=0,CRSV=0,MONO=0,slnt=0.ttf
new file mode 100644 (file)
index 0000000..08a3081
Binary files /dev/null and b/test/subset/data/expected/post_apply_mvar_delta/Recursive-ABC.no-layout.retain-all-codepoint.wght=400,CASL=0,CRSV=0,MONO=0,slnt=0.ttf differ
diff --git a/test/subset/data/expected/preprocess/Roboto-Regular.gids.61,62,63,30D9.ttf b/test/subset/data/expected/preprocess/Roboto-Regular.gids.61,62,63,30D9.ttf
new file mode 100644 (file)
index 0000000..5f8bff0
Binary files /dev/null and b/test/subset/data/expected/preprocess/Roboto-Regular.gids.61,62,63,30D9.ttf differ
index bc03e40..fb6aebd 100644 (file)
Binary files a/test/subset/data/expected/variable/Fraunces.default.61.ttf and b/test/subset/data/expected/variable/Fraunces.default.61.ttf differ
diff --git a/test/subset/data/expected/variable/Fraunces.retain-gids.26,66,69,124,125.ttf b/test/subset/data/expected/variable/Fraunces.retain-gids.26,66,69,124,125.ttf
new file mode 100644 (file)
index 0000000..310bc67
Binary files /dev/null and b/test/subset/data/expected/variable/Fraunces.retain-gids.26,66,69,124,125.ttf differ
diff --git a/test/subset/data/expected/variable/Fraunces.retain-gids.61.ttf b/test/subset/data/expected/variable/Fraunces.retain-gids.61.ttf
new file mode 100644 (file)
index 0000000..c77d9f1
Binary files /dev/null and b/test/subset/data/expected/variable/Fraunces.retain-gids.61.ttf differ
diff --git a/test/subset/data/fonts/32bit_var_store.otf b/test/subset/data/fonts/32bit_var_store.otf
new file mode 100644 (file)
index 0000000..1d376c9
Binary files /dev/null and b/test/subset/data/fonts/32bit_var_store.otf differ
diff --git a/test/subset/data/fonts/Cantarell-VF-ABC.otf b/test/subset/data/fonts/Cantarell-VF-ABC.otf
new file mode 100644 (file)
index 0000000..e9991ef
Binary files /dev/null and b/test/subset/data/fonts/Cantarell-VF-ABC.otf differ
diff --git a/test/subset/data/fonts/Foldit.ttf b/test/subset/data/fonts/Foldit.ttf
new file mode 100644 (file)
index 0000000..3f3b2e7
Binary files /dev/null and b/test/subset/data/fonts/Foldit.ttf differ
diff --git a/test/subset/data/fonts/FranklinGothic-Regular.ttf b/test/subset/data/fonts/FranklinGothic-Regular.ttf
deleted file mode 100644 (file)
index 9779739..0000000
Binary files a/test/subset/data/fonts/FranklinGothic-Regular.ttf and /dev/null differ
diff --git a/test/subset/data/fonts/Handjet.ttf b/test/subset/data/fonts/Handjet.ttf
new file mode 100644 (file)
index 0000000..66f4d50
Binary files /dev/null and b/test/subset/data/fonts/Handjet.ttf differ
diff --git a/test/subset/data/fonts/MPLUS1-Variable.ttf b/test/subset/data/fonts/MPLUS1-Variable.ttf
new file mode 100644 (file)
index 0000000..078795d
Binary files /dev/null and b/test/subset/data/fonts/MPLUS1-Variable.ttf differ
diff --git a/test/subset/data/fonts/Muli-ABC.ttf b/test/subset/data/fonts/Muli-ABC.ttf
new file mode 100644 (file)
index 0000000..60e6520
Binary files /dev/null and b/test/subset/data/fonts/Muli-ABC.ttf differ
diff --git a/test/subset/data/fonts/NotoSans-VF.abc.ttf b/test/subset/data/fonts/NotoSans-VF.abc.ttf
new file mode 100644 (file)
index 0000000..8a5de1f
Binary files /dev/null and b/test/subset/data/fonts/NotoSans-VF.abc.ttf differ
diff --git a/test/subset/data/fonts/Recursive-ABC.ttf b/test/subset/data/fonts/Recursive-ABC.ttf
new file mode 100644 (file)
index 0000000..33dea5a
Binary files /dev/null and b/test/subset/data/fonts/Recursive-ABC.ttf differ
diff --git a/test/subset/data/fonts/Roboto-Variable.ABC.ttf b/test/subset/data/fonts/Roboto-Variable.ABC.ttf
new file mode 100644 (file)
index 0000000..6cf001f
Binary files /dev/null and b/test/subset/data/fonts/Roboto-Variable.ABC.ttf differ
diff --git a/test/subset/data/fonts/Roboto-Variable.composite.ttf b/test/subset/data/fonts/Roboto-Variable.composite.ttf
new file mode 100644 (file)
index 0000000..d0e12c0
Binary files /dev/null and b/test/subset/data/fonts/Roboto-Variable.composite.ttf differ
diff --git a/test/subset/data/fonts/Roboto-Variable.ttf b/test/subset/data/fonts/Roboto-Variable.ttf
new file mode 100644 (file)
index 0000000..175c7b7
Binary files /dev/null and b/test/subset/data/fonts/Roboto-Variable.ttf differ
diff --git a/test/subset/data/fonts/RobotoFlex-Variable.ttf b/test/subset/data/fonts/RobotoFlex-Variable.ttf
new file mode 100644 (file)
index 0000000..bd32e0d
Binary files /dev/null and b/test/subset/data/fonts/RobotoFlex-Variable.ttf differ
diff --git a/test/subset/data/fonts/RobotoMono.ttf b/test/subset/data/fonts/RobotoMono.ttf
new file mode 100644 (file)
index 0000000..1920be0
Binary files /dev/null and b/test/subset/data/fonts/RobotoMono.ttf differ
diff --git a/test/subset/data/fonts/SourceSerif4Variable-Roman_subset.otf b/test/subset/data/fonts/SourceSerif4Variable-Roman_subset.otf
new file mode 100644 (file)
index 0000000..e3a9f7b
Binary files /dev/null and b/test/subset/data/fonts/SourceSerif4Variable-Roman_subset.otf differ
index c4b2a55..d930faa 100644 (file)
Binary files a/test/subset/data/fonts/colr-table.ttf and b/test/subset/data/fonts/colr-table.ttf differ
diff --git a/test/subset/data/profiles/filter-scripts-features.2.txt b/test/subset/data/profiles/filter-scripts-features.2.txt
new file mode 100644 (file)
index 0000000..6890a27
--- /dev/null
@@ -0,0 +1,2 @@
+--layout-scripts=grek,latn
+--layout-features=liga
diff --git a/test/subset/data/profiles/filter-scripts-features.txt b/test/subset/data/profiles/filter-scripts-features.txt
new file mode 100644 (file)
index 0000000..971824c
--- /dev/null
@@ -0,0 +1,2 @@
+--layout-scripts=grek,cyrl
+--layout-features=numr,onum
diff --git a/test/subset/data/profiles/filter-scripts.txt b/test/subset/data/profiles/filter-scripts.txt
new file mode 100644 (file)
index 0000000..428f7fa
--- /dev/null
@@ -0,0 +1 @@
+--layout-scripts=grek,cyrl
diff --git a/test/subset/data/profiles/glyph_map_roboto.txt b/test/subset/data/profiles/glyph_map_roboto.txt
new file mode 100644 (file)
index 0000000..2ee33b3
--- /dev/null
@@ -0,0 +1,2 @@
+--gid-map=37:1,39:2,69:3,74:4,77:5
+--layout-features+=c2sc
diff --git a/test/subset/data/profiles/no-layout-closure-gids.txt b/test/subset/data/profiles/no-layout-closure-gids.txt
new file mode 100644 (file)
index 0000000..ca56cf1
--- /dev/null
@@ -0,0 +1,2 @@
+--no-layout-closure
+--gids=74,77,446
diff --git a/test/subset/data/profiles/no-layout-closure-gids2.txt b/test/subset/data/profiles/no-layout-closure-gids2.txt
new file mode 100644 (file)
index 0000000..d7a54a8
--- /dev/null
@@ -0,0 +1,3 @@
+--no-layout-closure
+--gids=74,87,88,443,448
+--layout-features+=dlig
diff --git a/test/subset/data/profiles/no-layout.txt b/test/subset/data/profiles/no-layout.txt
new file mode 100644 (file)
index 0000000..d03b77a
--- /dev/null
@@ -0,0 +1 @@
+--drop-tables+=GSUB,GPOS,GDEF
diff --git a/test/subset/data/profiles/no-scripts.txt b/test/subset/data/profiles/no-scripts.txt
new file mode 100644 (file)
index 0000000..9bbc847
--- /dev/null
@@ -0,0 +1 @@
+--layout-scripts-=*
diff --git a/test/subset/data/profiles/no-tables-with-item-variations.txt b/test/subset/data/profiles/no-tables-with-item-variations.txt
new file mode 100644 (file)
index 0000000..d61fb71
--- /dev/null
@@ -0,0 +1 @@
+--drop-tables+=COLR
index b2973e1..b3ce831 100644 (file)
@@ -427,8 +427,6 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
-DIRECTWRITE_CXXFLAGS = @DIRECTWRITE_CXXFLAGS@
-DIRECTWRITE_LIBS = @DIRECTWRITE_LIBS@
 DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -526,6 +524,8 @@ STRIP = @STRIP@
 UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
 UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
 VERSION = @VERSION@
+WASM_CFLAGS = @WASM_CFLAGS@
+WASM_LIBS = @WASM_LIBS@
 _GI_EXP_DATADIR = @_GI_EXP_DATADIR@
 _GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@
 abs_builddir = @abs_builddir@
diff --git a/test/subset/data/tests/32bit_var_store.tests b/test/subset/data/tests/32bit_var_store.tests
new file mode 100644 (file)
index 0000000..015549e
--- /dev/null
@@ -0,0 +1,16 @@
+FONTS:
+32bit_var_store.otf
+
+PROFILES:
+notdef-outline.txt
+notdef-outline-retain-gids.txt
+
+SUBSETS:
+a
+b
+c
+d
+ab
+ac
+ad
+abcd
diff --git a/test/subset/data/tests/apply_cvar_delta.tests b/test/subset/data/tests/apply_cvar_delta.tests
new file mode 100644 (file)
index 0000000..d19d71a
--- /dev/null
@@ -0,0 +1,13 @@
+FONTS:
+Comfortaa-Regular-new.ttf
+Muli-ABC.ttf
+
+PROFILES:
+default.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wght=700
+wght=300
diff --git a/test/subset/data/tests/collect_name_ids.tests b/test/subset/data/tests/collect_name_ids.tests
new file mode 100644 (file)
index 0000000..06b5cf7
--- /dev/null
@@ -0,0 +1,11 @@
+FONTS:
+SourceSerif4Variable-Roman_subset.otf
+
+PROFILES:
+keep-all-layout-features.txt
+
+SUBSETS:
+*
+
+OPTIONS:
+no_fonttools
@@ -1,11 +1,13 @@
 FONTS:
-FranklinGothic-Regular.ttf
+Foldit.ttf
 
 PROFILES:
-layout-test.txt
 default.txt
+drop-hints.txt
+drop-hints-retain-gids.txt
 retain-gids.txt
 
 SUBSETS:
-achi
+A
+AB
 *
index d9519b6..31cb92c 100644 (file)
@@ -5,8 +5,13 @@ SourceSerifVariable-Roman.ttf
 PROFILES:
 default.txt
 drop-hints.txt
+no-scripts.txt
+filter-scripts.txt
+filter-scripts-features.txt
+filter-scripts-features.2.txt
 
 SUBSETS:
 abc
 Ǽ!A bc
+abcdefghijk
 ×ØÙÚÞ
diff --git a/test/subset/data/tests/full_instance.tests b/test/subset/data/tests/full_instance.tests
new file mode 100644 (file)
index 0000000..f760572
--- /dev/null
@@ -0,0 +1,16 @@
+FONTS:
+Roboto-Variable.ttf
+
+PROFILES:
+default.txt
+no-prune-unicode-ranges.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wght=150,wdth=80
+wght=300,wdth=90
+
+OPTIONS:
+no_fonttools
diff --git a/test/subset/data/tests/glyph_map.tests b/test/subset/data/tests/glyph_map.tests
new file mode 100644 (file)
index 0000000..f2a3d17
--- /dev/null
@@ -0,0 +1,8 @@
+FONTS:
+Roboto-Regular.ttf
+
+PROFILES:
+glyph_map_roboto.txt
+
+SUBSETS:
+ACafi
diff --git a/test/subset/data/tests/instance_comp_glyph_empty_child.tests b/test/subset/data/tests/instance_comp_glyph_empty_child.tests
new file mode 100644 (file)
index 0000000..ed963c9
--- /dev/null
@@ -0,0 +1,11 @@
+FONTS:
+RobotoMono.ttf
+
+PROFILES:
+default.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wght=700
diff --git a/test/subset/data/tests/instance_feature_variations.tests b/test/subset/data/tests/instance_feature_variations.tests
new file mode 100644 (file)
index 0000000..2a68108
--- /dev/null
@@ -0,0 +1,12 @@
+FONTS:
+MPLUS1-Variable.ttf
+
+PROFILES:
+default.txt
+
+SUBSETS:
+ポ
+
+INSTANCES:
+wght=100
+wght=400
diff --git a/test/subset/data/tests/instance_no_double_free.tests b/test/subset/data/tests/instance_no_double_free.tests
new file mode 100644 (file)
index 0000000..0e9f930
--- /dev/null
@@ -0,0 +1,12 @@
+FONTS:
+Handjet.ttf
+
+PROFILES:
+default.txt
+notdef-outline.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wght=100,ELGR=1,ELSH=2
diff --git a/test/subset/data/tests/instantiate_cff2.tests b/test/subset/data/tests/instantiate_cff2.tests
new file mode 100644 (file)
index 0000000..13c5b59
--- /dev/null
@@ -0,0 +1,14 @@
+FONTS:
+AdobeVFPrototype.otf
+
+PROFILES:
+default.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wght=650,CNTR=50
+
+OPTIONS:
+no_fonttools
diff --git a/test/subset/data/tests/instantiate_cff2_update_metrics.tests b/test/subset/data/tests/instantiate_cff2_update_metrics.tests
new file mode 100644 (file)
index 0000000..459168e
--- /dev/null
@@ -0,0 +1,15 @@
+FONTS:
+Cantarell-VF-ABC.otf
+
+PROFILES:
+default.txt
+retain-gids.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wght=800
+
+OPTIONS:
+no_fonttools
diff --git a/test/subset/data/tests/instantiate_colrv1.tests b/test/subset/data/tests/instantiate_colrv1.tests
new file mode 100644 (file)
index 0000000..fae81b3
--- /dev/null
@@ -0,0 +1,14 @@
+FONTS:
+Foldit.ttf
+
+PROFILES:
+default.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wght=900
+
+OPTIONS:
+no_fonttools
diff --git a/test/subset/data/tests/instantiate_glyf.tests b/test/subset/data/tests/instantiate_glyf.tests
new file mode 100644 (file)
index 0000000..e297667
--- /dev/null
@@ -0,0 +1,13 @@
+FONTS:
+Roboto-Variable.ABC.ttf
+Roboto-Variable.composite.ttf
+
+PROFILES:
+default.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wght=650,wdth=85
+wght=200,wdth=90
diff --git a/test/subset/data/tests/mvar_full_instance.tests b/test/subset/data/tests/mvar_full_instance.tests
new file mode 100644 (file)
index 0000000..6cdd562
--- /dev/null
@@ -0,0 +1,12 @@
+FONTS:
+NotoSans-VF.abc.ttf
+
+PROFILES:
+no-layout.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wght=150,wdth=80,CTGR=0
+wght=300,wdth=90,CTGR=0
diff --git a/test/subset/data/tests/no_layout_closure.tests b/test/subset/data/tests/no_layout_closure.tests
new file mode 100644 (file)
index 0000000..2d638e1
--- /dev/null
@@ -0,0 +1,9 @@
+FONTS:
+Roboto-Regular.ttf
+
+PROFILES:
+no-layout-closure-gids.txt
+no-layout-closure-gids2.txt
+
+SUBSETS:
+no-unicodes
diff --git a/test/subset/data/tests/pin_all_at_default.tests b/test/subset/data/tests/pin_all_at_default.tests
new file mode 100644 (file)
index 0000000..068c8ad
--- /dev/null
@@ -0,0 +1,12 @@
+FONTS:
+Roboto-Variable.ABC.ttf
+
+PROFILES:
+default.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wght=drop,wdth=100
+wght=400,wdth=100.0
diff --git a/test/subset/data/tests/post_apply_mvar_delta.tests b/test/subset/data/tests/post_apply_mvar_delta.tests
new file mode 100644 (file)
index 0000000..82b819a
--- /dev/null
@@ -0,0 +1,11 @@
+FONTS:
+Recursive-ABC.ttf
+
+PROFILES:
+no-layout.txt
+
+SUBSETS:
+*
+
+INSTANCES:
+wght=400,CASL=0,CRSV=0,MONO=0,slnt=0
diff --git a/test/subset/data/tests/preprocess.tests b/test/subset/data/tests/preprocess.tests
new file mode 100644 (file)
index 0000000..ba2a0e2
--- /dev/null
@@ -0,0 +1,8 @@
+FONTS:
+Roboto-Regular.ttf
+
+PROFILES:
+gids.txt
+
+SUBSETS:
+abcベ
index bda5875..2d803af 100644 (file)
@@ -3,6 +3,7 @@ Fraunces.ttf
 
 PROFILES:
 default.txt
+retain-gids.txt
 
 SUBSETS:
 a
index 780144a..827528a 100644 (file)
@@ -1,5 +1,6 @@
 tests = [
   'basics',
+  'preprocess',
   'full-font',
   'cff-full-font',
   'japanese',
@@ -33,7 +34,7 @@ tests = [
   'layout.duplicate_features',
   'layout.unsorted_featurelist',
   'layout.drop_feature',
-  'layout.default_features',
+  'no_layout_closure',
   'cmap',
   'cmap14',
   'sbix',
@@ -41,16 +42,40 @@ tests = [
   'colr_glyphs',
   'math',
   'math_coverage_offset',
-# TODO: re-enable once colrv1 subsetting is stabilized.
-# 'colrv1.notoemoji',
+  # TODO: re-enable once colrv1 subsetting is stabilized.
+  # 'colrv1.notoemoji',
   'colrv1',
+  'colrv1_copy_varstore',
   'colr_with_components',
   'cbdt',
   'variable',
   'glyph_names',
+  'glyph_map',
   'post',
+  '32bit_var_store',
+  'pin_all_at_default',
+  'instantiate_glyf',
+  'instantiate_cff2',
+  'full_instance',
+  'instance_feature_variations',
+  'instance_no_double_free',
+  'mvar_full_instance',
+  'instance_comp_glyph_empty_child',
+  'post_apply_mvar_delta',
+  'apply_cvar_delta',
+  'collect_name_ids',
+  'instantiate_colrv1',
+  'instantiate_cff2_update_metrics',
 ]
 
+if get_option('experimental_api')
+  tests += [
+    'glyf_partial_instancing',
+    'mvar_partial_instance',
+    'update_def_wght',
+    ]
+endif
+
 repack_tests = [
   'basic',
   'prioritization',
@@ -60,7 +85,6 @@ repack_tests = [
   'space_splitting',
 ]
 
-
 run_test = find_program('run-tests.py')
 
 foreach t : tests
index 75f8738..db3c042 100755 (executable)
@@ -47,14 +47,19 @@ def fail_test (test, cli_args, message):
        print ('  expected_file     %s' % os.path.abspath (expected_file))
        return 1
 
-def run_test (test, should_check_ots):
+def run_test (test, should_check_ots, preprocess):
        out_file = os.path.join (tempfile.mkdtemp (), test.get_font_name () + '-subset' + test.get_font_extension ())
        cli_args = ["--font-file=" + test.font_path,
                    "--output-file=" + out_file,
                    "--unicodes=%s" % test.unicodes (),
                    "--drop-tables+=DSIG",
                    "--drop-tables-=sbix"]
+       if preprocess:
+               cli_args.extend(["--preprocess-face",])
+
        cli_args.extend (test.get_profile_flags ())
+       if test.get_instance_flags ():
+               cli_args.extend (["--instance=%s" % ','.join(test.get_instance_flags ())])
        ret = subset_cmd (cli_args)
 
        if ret != "success":
@@ -139,7 +144,10 @@ for path in args:
                print ("Running tests in " + path)
                test_suite = SubsetTestSuite (path, f.read ())
                for test in test_suite.tests ():
-                       fails += run_test (test, has_ots)
+                       # Tests are run with and without preprocessing, results should be the
+                       # same between them.
+                       fails += run_test (test, has_ots, False)
+                       fails += run_test (test, has_ots, True)
 
 if fails != 0:
        sys.exit ("%d test(s) failed." % fails)
index a58d017..b755e4e 100644 (file)
@@ -5,38 +5,62 @@ import os
 # A single test in a subset test suite. Identifies a font
 # a subsetting profile, and a subset to be cut.
 class Test:
-       def __init__(self, font_path, profile_path, subset):
+       def __init__(self, font_path, profile_path, subset, instance, options):
                self.font_path = font_path
                self.profile_path = profile_path
                self.subset = subset
+               self.instance = instance
+               self.options = options
 
        def unicodes(self):
                import re
                if self.subset == '*':
                        return self.subset[0]
+               elif self.subset == "no-unicodes":
+                       return ""
                elif re.match("^U\+", self.subset):
                        s = re.sub (r"U\+", "", self.subset)
                        return s
                else:
                        return ",".join("%X" % ord(c) for (i, c) in enumerate(self.subset))
 
+       def instance_name(self):
+               if not self.instance:
+                       return self.instance
+               else:
+                       s = "." + self.instance.replace(':', '-')
+                       return s
+
        def get_profile_flags(self):
                with open (self.profile_path, mode="r", encoding="utf-8") as f:
                    return f.read().splitlines()
 
+       def get_instance_flags(self):
+               if not self.instance:
+                       return []
+               else:
+                       return self.instance.split(',')
+
        def get_font_name(self):
                font_base_name = os.path.basename(self.font_path)
                font_base_name_parts = os.path.splitext(font_base_name)
                profile_name = os.path.splitext(os.path.basename(self.profile_path))[0]
 
                if self.unicodes() == "*":
-                       return "%s.%s.retain-all-codepoint%s" % (font_base_name_parts[0],
+                       return "%s.%s.retain-all-codepoint%s%s" % (font_base_name_parts[0],
+                                      profile_name,
+                                      self.instance_name(),
+                                      font_base_name_parts[1])
+               elif self.unicodes() == "":
+                       return "%s.%s.no-unicodes%s%s" % (font_base_name_parts[0],
                                       profile_name,
+                                      self.instance_name(),
                                       font_base_name_parts[1])
                else:
-                       return "%s.%s.%s%s" % (font_base_name_parts[0],
+                       return "%s.%s.%s%s%s" % (font_base_name_parts[0],
                                       profile_name,
                                       self.unicodes(),
+                                      self.instance_name(),
                                       font_base_name_parts[1])
 
        def get_font_extension(self):
@@ -53,6 +77,8 @@ class SubsetTestSuite:
                self.fonts = []
                self.profiles = []
                self.subsets = []
+               self.instances = []
+               self.options = []
                self._parse(definition)
 
        def get_output_directory(self):
@@ -73,7 +99,11 @@ class SubsetTestSuite:
                        for profile in self.profiles:
                                profile = os.path.join(self._base_path(), "profiles", profile)
                                for subset in self.subsets:
-                                       yield Test(font, profile, subset)
+                                       if self.instances:
+                                               for instance in self.instances:
+                                                       yield Test(font, profile, subset, instance, options=self.options)
+                                       else:
+                                               yield Test(font, profile, subset, "", options=self.options)
 
        def _base_path(self):
                return os.path.dirname(os.path.dirname(self.test_path))
@@ -82,7 +112,9 @@ class SubsetTestSuite:
                destinations = {
                                "FONTS:": self.fonts,
                                "PROFILES:": self.profiles,
-                               "SUBSETS:": self.subsets
+                               "SUBSETS:": self.subsets,
+                               "INSTANCES:": self.instances,
+                               "OPTIONS:": self.options,
                }
 
                current_destination = None
diff --git a/test/threads/Makefile.am b/test/threads/Makefile.am
new file mode 100644 (file)
index 0000000..f0347d4
--- /dev/null
@@ -0,0 +1,17 @@
+# Process this file with automake to produce Makefile.in
+
+NULL =
+EXTRA_DIST =
+SUBDIRS =
+
+EXTRA_DIST += \
+       meson.build \
+       hb-shape-threads.cc \
+       hb-subset-threads.cc \
+       $(NULL)
+
+# Convenience targets:
+lib:
+       @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
+
+-include $(top_srcdir)/git.mk
diff --git a/test/threads/Makefile.in b/test/threads/Makefile.in
new file mode 100644 (file)
index 0000000..eb8a6c7
--- /dev/null
@@ -0,0 +1,708 @@
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Process this file with automake to produce Makefile.in
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \  ]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs  ]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = test/threads
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_link_flag.m4 \
+       $(top_srcdir)/m4/ax_code_coverage.m4 \
+       $(top_srcdir)/m4/ax_cxx_compile_stdcxx.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)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+       ctags-recursive dvi-recursive html-recursive info-recursive \
+       install-data-recursive install-dvi-recursive \
+       install-exec-recursive install-html-recursive \
+       install-info-recursive install-pdf-recursive \
+       install-ps-recursive install-recursive installcheck-recursive \
+       installdirs-recursive pdf-recursive ps-recursive \
+       tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive        \
+  distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+  $(RECURSIVE_TARGETS) \
+  $(RECURSIVE_CLEAN_TARGETS) \
+  $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+       distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_FT_CFLAGS = @CAIRO_FT_CFLAGS@
+CAIRO_FT_LIBS = @CAIRO_FT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CHAFA_CFLAGS = @CHAFA_CFLAGS@
+CHAFA_LIBS = @CHAFA_LIBS@
+CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@
+CODE_COVERAGE_CPPFLAGS = @CODE_COVERAGE_CPPFLAGS@
+CODE_COVERAGE_CXXFLAGS = @CODE_COVERAGE_CXXFLAGS@
+CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
+CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@
+CODE_COVERAGE_LIBS = @CODE_COVERAGE_LIBS@
+CORETEXT_CFLAGS = @CORETEXT_CFLAGS@
+CORETEXT_LIBS = @CORETEXT_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
+FREETYPE_DEPS = @FREETYPE_DEPS@
+FREETYPE_LIBS = @FREETYPE_LIBS@
+GCOV = @GCOV@
+GDI_CFLAGS = @GDI_CFLAGS@
+GDI_LIBS = @GDI_LIBS@
+GENHTML = @GENHTML@
+GIT = @GIT@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_DEPS = @GLIB_DEPS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GRAPHITE2_CFLAGS = @GRAPHITE2_CFLAGS@
+GRAPHITE2_DEPS = @GRAPHITE2_DEPS@
+GRAPHITE2_LIBS = @GRAPHITE2_LIBS@
+GREP = @GREP@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+HAVE_CXX11 = @HAVE_CXX11@
+HB_LIBTOOL_VERSION_INFO = @HB_LIBTOOL_VERSION_INFO@
+HB_VERSION = @HB_VERSION@
+HB_VERSION_MAJOR = @HB_VERSION_MAJOR@
+HB_VERSION_MICRO = @HB_VERSION_MICRO@
+HB_VERSION_MINOR = @HB_VERSION_MINOR@
+HTML_DIR = @HTML_DIR@
+ICU_CFLAGS = @ICU_CFLAGS@
+ICU_LIBS = @ICU_LIBS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
+INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
+INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@
+INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@
+INTROSPECTION_LIBS = @INTROSPECTION_LIBS@
+INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@
+INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
+INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+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@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
+UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
+VERSION = @VERSION@
+WASM_CFLAGS = @WASM_CFLAGS@
+WASM_LIBS = @WASM_LIBS@
+_GI_EXP_DATADIR = @_GI_EXP_DATADIR@
+_GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+have_gobject = @have_gobject@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+NULL = 
+EXTRA_DIST = meson.build hb-shape-threads.cc hb-subset-threads.cc \
+       $(NULL)
+SUBDIRS = 
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits test/threads/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnits test/threads/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+#     (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+       @fail=; \
+       if $(am__make_keepgoing); then \
+         failcom='fail=yes'; \
+       else \
+         failcom='exit 1'; \
+       fi; \
+       dot_seen=no; \
+       target=`echo $@ | sed s/-recursive//`; \
+       case "$@" in \
+         distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+         *) list='$(SUBDIRS)' ;; \
+       esac; \
+       for subdir in $$list; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           dot_seen=yes; \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done; \
+       if test "$$dot_seen" = "no"; then \
+         $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+       fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+       $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+       set x; \
+       here=`pwd`; \
+       if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+         include_option=--etags-include; \
+         empty_fix=.; \
+       else \
+         include_option=--include; \
+         empty_fix=; \
+       fi; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           test ! -f $$subdir/TAGS || \
+             set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+         fi; \
+       done; \
+       $(am__define_uniq_tagged_files); \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+       $(am__define_uniq_tagged_files); \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+       list='$(am__tagged_files)'; \
+       case "$(srcdir)" in \
+         [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+         *) sdir=$(subdir)/$(srcdir) ;; \
+       esac; \
+       for i in $$list; do \
+         if test -f "$$i"; then \
+           echo "$(subdir)/$$i"; \
+         else \
+           echo "$$sdir/$$i"; \
+         fi; \
+       done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+       @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           $(am__make_dryrun) \
+             || test -d "$(distdir)/$$subdir" \
+             || $(MKDIR_P) "$(distdir)/$$subdir" \
+             || exit 1; \
+           dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+           $(am__relativize); \
+           new_distdir=$$reldir; \
+           dir1=$$subdir; dir2="$(top_distdir)"; \
+           $(am__relativize); \
+           new_top_distdir=$$reldir; \
+           echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+           echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+           ($(am__cd) $$subdir && \
+             $(MAKE) $(AM_MAKEFLAGS) \
+               top_distdir="$$new_top_distdir" \
+               distdir="$$new_distdir" \
+               am__remove_distdir=: \
+               am__skip_length_check=: \
+               am__skip_mode_fix=: \
+               distdir) \
+             || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+       check-am clean clean-generic clean-libtool cscopelist-am ctags \
+       ctags-am distclean distclean-generic distclean-libtool \
+       distclean-tags distdir dvi dvi-am html html-am info info-am \
+       install install-am install-data install-data-am install-dvi \
+       install-dvi-am install-exec install-exec-am install-html \
+       install-html-am install-info install-info-am install-man \
+       install-pdf install-pdf-am install-ps install-ps-am \
+       install-strip installcheck installcheck-am installdirs \
+       installdirs-am maintainer-clean maintainer-clean-generic \
+       mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+       ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Convenience targets:
+lib:
+       @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
+
+-include $(top_srcdir)/git.mk
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/threads/hb-shape-threads.cc b/test/threads/hb-shape-threads.cc
new file mode 100644 (file)
index 0000000..96dff34
--- /dev/null
@@ -0,0 +1,210 @@
+#include <cassert>
+#include <cstring>
+#include <thread>
+#include <condition_variable>
+#include <vector>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hb.h"
+#include "hb-ot.h"
+#ifdef HAVE_FREETYPE
+#include "hb-ft.h"
+#endif
+
+#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
+
+struct test_input_t
+{
+  const char *font_path;
+  const char *text_path;
+  bool is_variable;
+} default_tests[] =
+{
+
+  {"perf/fonts/NotoNastaliqUrdu-Regular.ttf",
+   "perf/texts/fa-thelittleprince.txt",
+   false},
+
+  {"perf/fonts/Amiri-Regular.ttf",
+   "perf/texts/fa-thelittleprince.txt",
+   false},
+
+  {"perf/fonts/Roboto-Regular.ttf",
+   "perf/texts/en-thelittleprince.txt",
+   false},
+
+  {"perf/fonts/Roboto-Regular.ttf",
+   "perf/texts/en-words.txt",
+   false},
+
+  {SUBSET_FONT_BASE_PATH "SourceSerifVariable-Roman.ttf",
+   "perf/texts/en-thelittleprince.txt",
+   true},
+};
+
+
+static test_input_t *tests = default_tests;
+static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
+
+enum backend_t { HARFBUZZ, FREETYPE };
+
+// https://en.cppreference.com/w/cpp/thread/condition_variable/wait
+static std::condition_variable cv;
+static std::mutex cv_m;
+static bool ready = false;
+
+static unsigned num_repetitions = 1;
+static unsigned num_threads = 3;
+
+static void shape (const test_input_t &input,
+                  hb_font_t *font)
+{
+  // Wait till all threads are ready.
+  {
+    std::unique_lock<std::mutex> lk (cv_m);
+    cv.wait(lk, [] {return ready;});
+  }
+
+  const char *lang_str = strrchr (input.text_path, '/');
+  lang_str = lang_str ? lang_str + 1 : input.text_path;
+  hb_language_t language = hb_language_from_string (lang_str, -1);
+
+  hb_blob_t *text_blob = hb_blob_create_from_file_or_fail (input.text_path);
+  assert (text_blob);
+  unsigned orig_text_length;
+  const char *orig_text = hb_blob_get_data (text_blob, &orig_text_length);
+
+  hb_buffer_t *buf = hb_buffer_create ();
+  hb_buffer_set_flags (buf, HB_BUFFER_FLAG_VERIFY);
+  for (unsigned i = 0; i < num_repetitions; i++)
+  {
+    unsigned text_length = orig_text_length;
+    const char *text = orig_text;
+
+    const char *end;
+    while ((end = (const char *) memchr (text, '\n', text_length)))
+    {
+      hb_buffer_clear_contents (buf);
+      hb_buffer_add_utf8 (buf, text, text_length, 0, end - text);
+      hb_buffer_guess_segment_properties (buf);
+      hb_buffer_set_language (buf, language);
+      hb_shape (font, buf, nullptr, 0);
+
+      unsigned skip = end - text + 1;
+      text_length -= skip;
+      text += skip;
+    }
+  }
+  hb_buffer_destroy (buf);
+
+  hb_blob_destroy (text_blob);
+}
+
+static void test_backend (backend_t backend,
+                         const char *backend_name,
+                         bool variable,
+                         const test_input_t &test_input)
+{
+  char name[1024] = "shape";
+  const char *p;
+  strcat (name, "/");
+  p = strrchr (test_input.font_path, '/');
+  strcat (name, p ? p + 1 : test_input.font_path);
+  strcat (name, "/");
+  p = strrchr (test_input.text_path, '/');
+  strcat (name, p ? p + 1 : test_input.text_path);
+  strcat (name, variable ? "/var" : "");
+  strcat (name, "/");
+  strcat (name, backend_name);
+
+  printf ("Testing %s\n", name);
+
+  hb_font_t *font;
+  {
+    hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
+    assert (blob);
+    hb_face_t *face = hb_face_create (blob, 0);
+    hb_blob_destroy (blob);
+    font = hb_font_create (face);
+    hb_face_destroy (face);
+  }
+
+  if (variable)
+  {
+    hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500};
+    hb_font_set_variations (font, &wght, 1);
+  }
+
+  switch (backend)
+  {
+    case HARFBUZZ:
+      hb_ot_font_set_funcs (font);
+      break;
+
+    case FREETYPE:
+#ifdef HAVE_FREETYPE
+      hb_ft_font_set_funcs (font);
+#endif
+      break;
+  }
+
+  std::vector<std::thread> threads;
+  for (unsigned i = 0; i < num_threads; i++)
+    threads.push_back (std::thread (shape, test_input, font));
+
+  {
+    std::unique_lock<std::mutex> lk (cv_m);
+    ready = true;
+  }
+  cv.notify_all();
+
+  for (unsigned i = 0; i < num_threads; i++)
+    threads[i].join ();
+
+  hb_font_destroy (font);
+}
+
+int main(int argc, char** argv)
+{
+  if (argc > 1)
+    num_threads = atoi (argv[1]);
+  if (argc > 2)
+    num_repetitions = atoi (argv[2]);
+
+  /* Dummy call to alleviate _guess_segment_properties thread safety-ness
+   * https://github.com/harfbuzz/harfbuzz/issues/1191 */
+  hb_language_get_default ();
+
+  if (argc > 4)
+  {
+    num_tests = (argc - 3) / 2;
+    tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
+    for (unsigned i = 0; i < num_tests; i++)
+    {
+      tests[i].is_variable = true;
+      tests[i].font_path = argv[3 + i * 2];
+      tests[i].text_path = argv[4 + i * 2];
+    }
+  }
+
+  printf ("Num threads %u; num repetitions %u\n", num_threads, num_repetitions);
+  for (unsigned i = 0; i < num_tests; i++)
+  {
+    auto& test_input = tests[i];
+    for (int variable = 0; variable < int (test_input.is_variable) + 1; variable++)
+    {
+      bool is_var = (bool) variable;
+
+      test_backend (HARFBUZZ, "hb", is_var, test_input);
+#ifdef HAVE_FREETYPE
+      test_backend (FREETYPE, "ft", is_var, test_input);
+#endif
+    }
+  }
+
+  if (tests != default_tests)
+    free (tests);
+}
diff --git a/test/threads/hb-subset-threads.cc b/test/threads/hb-subset-threads.cc
new file mode 100644 (file)
index 0000000..f0e4b7e
--- /dev/null
@@ -0,0 +1,182 @@
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <thread>
+#include <condition_variable>
+#include <vector>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hb-subset.h"
+
+enum operation_t
+{
+  subset_codepoints,
+  subset_glyphs
+};
+
+#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
+
+struct test_input_t
+{
+  const char *font_path;
+  const unsigned max_subset_size;
+} default_tests[] =
+{
+  {SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf", 4000},
+  {SUBSET_FONT_BASE_PATH "Amiri-Regular.ttf", 4000},
+  {SUBSET_FONT_BASE_PATH "NotoNastaliqUrdu-Regular.ttf", 1000},
+  {SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf", 1000},
+  {SUBSET_FONT_BASE_PATH "Mplus1p-Regular.ttf", 10000},
+  {SUBSET_FONT_BASE_PATH "SourceHanSans-Regular_subset.otf", 10000},
+  {SUBSET_FONT_BASE_PATH "SourceSansPro-Regular.otf", 2000},
+};
+
+
+static test_input_t *tests = default_tests;
+static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
+
+
+// https://en.cppreference.com/w/cpp/thread/condition_variable/wait
+static std::condition_variable cv;
+static std::mutex cv_m;
+static bool ready = false;
+
+static unsigned num_repetitions = 1;
+static unsigned num_threads = 3;
+
+static void AddCodepoints(const hb_set_t* codepoints_in_font,
+                          unsigned subset_size,
+                          hb_subset_input_t* input)
+{
+  auto *unicodes = hb_subset_input_unicode_set (input);
+  hb_codepoint_t cp = HB_SET_VALUE_INVALID;
+  for (unsigned i = 0; i < subset_size; i++) {
+    if (!hb_set_next (codepoints_in_font, &cp)) return;
+    hb_set_add (unicodes, cp);
+  }
+}
+
+static void AddGlyphs(unsigned num_glyphs_in_font,
+               unsigned subset_size,
+               hb_subset_input_t* input)
+{
+  auto *glyphs = hb_subset_input_glyph_set (input);
+  for (unsigned i = 0; i < subset_size && i < num_glyphs_in_font; i++) {
+    hb_set_add (glyphs, i);
+  }
+}
+
+static void subset (operation_t operation,
+                    const test_input_t &test_input,
+                    hb_face_t *face)
+{
+  // Wait till all threads are ready.
+  {
+    std::unique_lock<std::mutex> lk (cv_m);
+    cv.wait(lk, [] {return ready;});
+  }
+
+  unsigned subset_size = test_input.max_subset_size;
+
+  hb_subset_input_t* input = hb_subset_input_create_or_fail ();
+  assert (input);
+
+  switch (operation)
+  {
+    case subset_codepoints:
+    {
+      hb_set_t* all_codepoints = hb_set_create ();
+      hb_face_collect_unicodes (face, all_codepoints);
+      AddCodepoints(all_codepoints, subset_size, input);
+      hb_set_destroy (all_codepoints);
+    }
+    break;
+
+    case subset_glyphs:
+    {
+      unsigned num_glyphs = hb_face_get_glyph_count (face);
+      AddGlyphs(num_glyphs, subset_size, input);
+    }
+    break;
+  }
+
+  for (unsigned i = 0; i < num_repetitions; i++)
+  {
+    hb_face_t* subset = hb_subset_or_fail (face, input);
+    assert (subset);
+    hb_face_destroy (subset);
+  }
+
+  hb_subset_input_destroy (input);
+}
+
+static void test_operation (operation_t operation,
+                            const char *operation_name,
+                            const test_input_t &test_input)
+{
+  char name[1024] = "subset";
+  const char *p;
+  strcat (name, "/");
+  p = strrchr (test_input.font_path, '/');
+  strcat (name, p ? p + 1 : test_input.font_path);
+  strcat (name, "/");
+  strcat (name, operation_name);
+
+  printf ("Testing %s\n", name);
+
+  hb_face_t *face;
+  {
+    hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
+    assert (blob);
+    face = hb_face_create (blob, 0);
+    hb_blob_destroy (blob);
+  }
+
+  std::vector<std::thread> threads;
+  for (unsigned i = 0; i < num_threads; i++)
+    threads.push_back (std::thread (subset, operation, test_input, face));
+
+  {
+    std::unique_lock<std::mutex> lk (cv_m);
+    ready = true;
+  }
+  cv.notify_all();
+
+  for (unsigned i = 0; i < num_threads; i++)
+    threads[i].join ();
+
+  hb_face_destroy (face);
+}
+
+int main(int argc, char** argv)
+{
+  if (argc > 1)
+    num_threads = atoi (argv[1]);
+  if (argc > 2)
+    num_repetitions = atoi (argv[2]);
+
+  if (argc > 4)
+  {
+    num_tests = argc - 3;
+    tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
+    for (unsigned i = 0; i < num_tests; i++)
+    {
+      tests[i].font_path = argv[3 + i];
+    }
+  }
+
+  printf ("Num threads %u; num repetitions %u\n", num_threads, num_repetitions);
+  for (unsigned i = 0; i < num_tests; i++)
+  {
+    auto& test_input = tests[i];
+    test_operation (subset_codepoints, "codepoints", test_input);
+    test_operation (subset_glyphs, "glyphs", test_input);
+  }
+
+  if (tests != default_tests)
+    free (tests);
+}
diff --git a/test/threads/meson.build b/test/threads/meson.build
new file mode 100644 (file)
index 0000000..1848a1c
--- /dev/null
@@ -0,0 +1,28 @@
+test('shape_threads', executable('hb-shape-threads', 'hb-shape-threads.cc',
+  dependencies: [
+    freetype_dep, thread_dep
+  ],
+  cpp_args: [],
+  include_directories: [incconfig, incsrc],
+  link_with: [libharfbuzz],
+  install: false,
+  ),
+  workdir: meson.current_source_dir() / '..' / '..',
+  timeout: 300,
+  suite: ['threads', 'slow'],
+)
+
+
+test('subset_threads', executable('hb-subset-threads', 'hb-subset-threads.cc',
+  dependencies: [
+    thread_dep
+  ],
+  cpp_args: [],
+  include_directories: [incconfig, incsrc],
+  link_with: [libharfbuzz, libharfbuzz_subset],
+  install: false,
+  ),
+  workdir: meson.current_source_dir() / '..' / '..',
+  timeout: 300,
+  suite: ['threads', 'slow'],
+)
index cabb9ef..ca6f438 100644 (file)
@@ -36,27 +36,40 @@ LDADD = \
 
 if HAVE_GLIB
 
-if HAVE_FREETYPE
-if HAVE_CAIRO_FT
+if HAVE_CAIRO
 hb_view_SOURCES = $(HB_VIEW_sources)
 hb_view_LDADD = \
+       $(top_builddir)/src/libharfbuzz-cairo.la \
        $(LDADD) \
        $(CAIRO_LIBS) \
        $(CAIRO_FT_LIBS) \
        $(CHAFA_LIBS) \
        $(NULL)
 bin_PROGRAMS += hb-view
-endif # HAVE_CAIRO_FT
-endif # HAVE_FREETYPE
+endif # HAVE_CAIRO
 
 hb_shape_SOURCES = $(HB_SHAPE_sources)
 bin_PROGRAMS += hb-shape
 
+hb_info_SOURCES = $(HB_INFO_sources)
+hb_info_LDADD = \
+       $(LDADD) \
+       $(NULL)
+if HAVE_GOBJECT
+hb_info_LDADD += \
+       $(top_builddir)/src/libharfbuzz-gobject.la \
+       $(GOBJECT_LIBS) \
+       $(NULL)
+endif # HAVE_GOBJECT
+if HAVE_CHAFA
+hb_info_LDADD += $(CHAFA_LIBS)
+endif # HAVE_CHAFA
+bin_PROGRAMS += hb-info
+
 hb_subset_SOURCES = $(HB_SUBSET_CLI_sources)
 hb_subset_LDADD = \
        $(top_builddir)/src/libharfbuzz-subset.la \
        $(LDADD)
-
 bin_PROGRAMS += hb-subset
 
 hb_ot_shape_closure_SOURCES = $(HB_OT_SHAPE_CLOSURE_sources)
index 8983736..abac1ee 100644 (file)
@@ -91,8 +91,15 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 bin_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2)
-@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am__append_1 = hb-view
-@HAVE_GLIB_TRUE@am__append_2 = hb-shape hb-subset hb-ot-shape-closure
+@HAVE_CAIRO_TRUE@@HAVE_GLIB_TRUE@am__append_1 = hb-view
+@HAVE_GLIB_TRUE@am__append_2 = hb-shape hb-info hb-subset \
+@HAVE_GLIB_TRUE@       hb-ot-shape-closure
+@HAVE_GLIB_TRUE@@HAVE_GOBJECT_TRUE@am__append_3 = \
+@HAVE_GLIB_TRUE@@HAVE_GOBJECT_TRUE@    $(top_builddir)/src/libharfbuzz-gobject.la \
+@HAVE_GLIB_TRUE@@HAVE_GOBJECT_TRUE@    $(GOBJECT_LIBS) \
+@HAVE_GLIB_TRUE@@HAVE_GOBJECT_TRUE@    $(NULL)
+
+@HAVE_CHAFA_TRUE@@HAVE_GLIB_TRUE@am__append_4 = $(CHAFA_LIBS)
 subdir = util
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_link_flag.m4 \
@@ -109,33 +116,50 @@ mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
-@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am__EXEEXT_1 = hb-view$(EXEEXT)
-@HAVE_GLIB_TRUE@am__EXEEXT_2 = hb-shape$(EXEEXT) hb-subset$(EXEEXT) \
+@HAVE_CAIRO_TRUE@@HAVE_GLIB_TRUE@am__EXEEXT_1 = hb-view$(EXEEXT)
+@HAVE_GLIB_TRUE@am__EXEEXT_2 = hb-shape$(EXEEXT) hb-info$(EXEEXT) \
+@HAVE_GLIB_TRUE@       hb-subset$(EXEEXT) \
 @HAVE_GLIB_TRUE@       hb-ot-shape-closure$(EXEEXT)
 am__installdirs = "$(DESTDIR)$(bindir)"
 PROGRAMS = $(bin_PROGRAMS)
-am__hb_ot_shape_closure_SOURCES_DIST = face-options.hh font-options.hh \
-       hb-ot-shape-closure.cc main-font-text.hh options.hh \
-       text-options.hh
+am__hb_info_SOURCES_DIST = batch.hh face-options.hh font-options.hh \
+       hb-info.cc options.hh
 am__objects_1 =
-am__objects_2 = hb-ot-shape-closure.$(OBJEXT) $(am__objects_1)
-@HAVE_GLIB_TRUE@am_hb_ot_shape_closure_OBJECTS = $(am__objects_2)
-hb_ot_shape_closure_OBJECTS = $(am_hb_ot_shape_closure_OBJECTS)
-hb_ot_shape_closure_LDADD = $(LDADD)
+am__objects_2 = hb-info.$(OBJEXT) $(am__objects_1)
+@HAVE_GLIB_TRUE@am_hb_info_OBJECTS = $(am__objects_2)
+hb_info_OBJECTS = $(am_hb_info_OBJECTS)
 am__DEPENDENCIES_1 =
-hb_ot_shape_closure_DEPENDENCIES = $(top_builddir)/src/libharfbuzz.la \
+am__DEPENDENCIES_2 = $(top_builddir)/src/libharfbuzz.la \
        $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
        $(am__DEPENDENCIES_1)
+@HAVE_GLIB_TRUE@@HAVE_GOBJECT_TRUE@am__DEPENDENCIES_3 = $(top_builddir)/src/libharfbuzz-gobject.la \
+@HAVE_GLIB_TRUE@@HAVE_GOBJECT_TRUE@    $(am__DEPENDENCIES_1) \
+@HAVE_GLIB_TRUE@@HAVE_GOBJECT_TRUE@    $(am__DEPENDENCIES_1)
+@HAVE_CHAFA_TRUE@@HAVE_GLIB_TRUE@am__DEPENDENCIES_4 =  \
+@HAVE_CHAFA_TRUE@@HAVE_GLIB_TRUE@      $(am__DEPENDENCIES_1)
+@HAVE_GLIB_TRUE@hb_info_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+@HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_3) \
+@HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_4)
 AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
 am__v_lt_0 = --silent
 am__v_lt_1 = 
+am__hb_ot_shape_closure_SOURCES_DIST = face-options.hh font-options.hh \
+       hb-ot-shape-closure.cc main-font-text.hh options.hh \
+       text-options.hh
+am__objects_3 = hb-ot-shape-closure.$(OBJEXT) $(am__objects_1)
+@HAVE_GLIB_TRUE@am_hb_ot_shape_closure_OBJECTS = $(am__objects_3)
+hb_ot_shape_closure_OBJECTS = $(am_hb_ot_shape_closure_OBJECTS)
+hb_ot_shape_closure_LDADD = $(LDADD)
+hb_ot_shape_closure_DEPENDENCIES = $(top_builddir)/src/libharfbuzz.la \
+       $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+       $(am__DEPENDENCIES_1)
 am__hb_shape_SOURCES_DIST = batch.hh face-options.hh font-options.hh \
        hb-shape.cc main-font-text.hh options.hh output-options.hh \
        shape-consumer.hh shape-format.hh shape-options.hh \
-       text-options.hh
-am__objects_3 = hb-shape.$(OBJEXT) $(am__objects_1)
-@HAVE_GLIB_TRUE@am_hb_shape_OBJECTS = $(am__objects_3)
+       shape-output.hh text-options.hh
+am__objects_4 = hb-shape.$(OBJEXT) $(am__objects_1)
+@HAVE_GLIB_TRUE@am_hb_shape_OBJECTS = $(am__objects_4)
 hb_shape_OBJECTS = $(am_hb_shape_OBJECTS)
 hb_shape_LDADD = $(LDADD)
 hb_shape_DEPENDENCIES = $(top_builddir)/src/libharfbuzz.la \
@@ -143,28 +167,27 @@ hb_shape_DEPENDENCIES = $(top_builddir)/src/libharfbuzz.la \
        $(am__DEPENDENCIES_1)
 am__hb_subset_SOURCES_DIST = batch.hh face-options.hh hb-subset.cc \
        main-font-text.hh options.hh output-options.hh text-options.hh
-am__objects_4 = hb-subset.$(OBJEXT) $(am__objects_1)
-@HAVE_GLIB_TRUE@am_hb_subset_OBJECTS = $(am__objects_4)
+am__objects_5 = hb-subset.$(OBJEXT) $(am__objects_1)
+@HAVE_GLIB_TRUE@am_hb_subset_OBJECTS = $(am__objects_5)
 hb_subset_OBJECTS = $(am_hb_subset_OBJECTS)
-am__DEPENDENCIES_2 = $(top_builddir)/src/libharfbuzz.la \
-       $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
-       $(am__DEPENDENCIES_1)
 @HAVE_GLIB_TRUE@hb_subset_DEPENDENCIES =  \
 @HAVE_GLIB_TRUE@       $(top_builddir)/src/libharfbuzz-subset.la \
 @HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_2)
 am__hb_view_SOURCES_DIST = ansi-print.hh face-options.hh \
        font-options.hh hb-view.cc helper-cairo-ansi.hh \
-       helper-cairo.hh main-font-text.hh options.hh output-options.hh \
-       shape-consumer.hh shape-options.hh text-options.hh \
-       view-cairo.hh view-options.hh
-am__objects_5 = hb-view.$(OBJEXT) $(am__objects_1)
-@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am_hb_view_OBJECTS = $(am__objects_5)
+       helper-cairo-ft.hh helper-cairo.hh main-font-text.hh \
+       options.hh output-options.hh shape-consumer.hh \
+       shape-options.hh text-options.hh view-cairo.hh view-options.hh
+am__objects_6 = hb-view.$(OBJEXT) $(am__objects_1)
+@HAVE_CAIRO_TRUE@@HAVE_GLIB_TRUE@am_hb_view_OBJECTS =  \
+@HAVE_CAIRO_TRUE@@HAVE_GLIB_TRUE@      $(am__objects_6)
 hb_view_OBJECTS = $(am_hb_view_OBJECTS)
-@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@hb_view_DEPENDENCIES = $(am__DEPENDENCIES_2) \
-@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_1) \
-@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_1) \
-@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_1) \
-@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@       $(am__DEPENDENCIES_1)
+@HAVE_CAIRO_TRUE@@HAVE_GLIB_TRUE@hb_view_DEPENDENCIES = $(top_builddir)/src/libharfbuzz-cairo.la \
+@HAVE_CAIRO_TRUE@@HAVE_GLIB_TRUE@      $(am__DEPENDENCIES_2) \
+@HAVE_CAIRO_TRUE@@HAVE_GLIB_TRUE@      $(am__DEPENDENCIES_1) \
+@HAVE_CAIRO_TRUE@@HAVE_GLIB_TRUE@      $(am__DEPENDENCIES_1) \
+@HAVE_CAIRO_TRUE@@HAVE_GLIB_TRUE@      $(am__DEPENDENCIES_1) \
+@HAVE_CAIRO_TRUE@@HAVE_GLIB_TRUE@      $(am__DEPENDENCIES_1)
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -180,9 +203,9 @@ am__v_at_1 =
 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
 depcomp = $(SHELL) $(top_srcdir)/depcomp
 am__maybe_remake_depfiles = depfiles
-am__depfiles_remade = ./$(DEPDIR)/hb-ot-shape-closure.Po \
-       ./$(DEPDIR)/hb-shape.Po ./$(DEPDIR)/hb-subset.Po \
-       ./$(DEPDIR)/hb-view.Po
+am__depfiles_remade = ./$(DEPDIR)/hb-info.Po \
+       ./$(DEPDIR)/hb-ot-shape-closure.Po ./$(DEPDIR)/hb-shape.Po \
+       ./$(DEPDIR)/hb-subset.Po ./$(DEPDIR)/hb-view.Po
 am__mv = mv -f
 CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
        $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
@@ -220,9 +243,10 @@ 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 = $(hb_ot_shape_closure_SOURCES) $(hb_shape_SOURCES) \
-       $(hb_subset_SOURCES) $(hb_view_SOURCES)
-DIST_SOURCES = $(am__hb_ot_shape_closure_SOURCES_DIST) \
+SOURCES = $(hb_info_SOURCES) $(hb_ot_shape_closure_SOURCES) \
+       $(hb_shape_SOURCES) $(hb_subset_SOURCES) $(hb_view_SOURCES)
+DIST_SOURCES = $(am__hb_info_SOURCES_DIST) \
+       $(am__hb_ot_shape_closure_SOURCES_DIST) \
        $(am__hb_shape_SOURCES_DIST) $(am__hb_subset_SOURCES_DIST) \
        $(am__hb_view_SOURCES_DIST)
 am__can_run_installinfo = \
@@ -286,8 +310,6 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
-DIRECTWRITE_CXXFLAGS = @DIRECTWRITE_CXXFLAGS@
-DIRECTWRITE_LIBS = @DIRECTWRITE_LIBS@
 DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -385,6 +407,8 @@ STRIP = @STRIP@
 UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
 UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
 VERSION = @VERSION@
+WASM_CFLAGS = @WASM_CFLAGS@
+WASM_LIBS = @WASM_LIBS@
 _GI_EXP_DATADIR = @_GI_EXP_DATADIR@
 _GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@
 abs_builddir = @abs_builddir@
@@ -454,6 +478,7 @@ HB_VIEW_sources = \
        font-options.hh \
        hb-view.cc \
        helper-cairo-ansi.hh \
+       helper-cairo-ft.hh \
        helper-cairo.hh \
        main-font-text.hh \
        options.hh \
@@ -476,9 +501,18 @@ HB_SHAPE_sources = \
        shape-consumer.hh \
        shape-format.hh \
        shape-options.hh \
+       shape-output.hh \
        text-options.hh \
        $(NULL)
 
+HB_INFO_sources = \
+       batch.hh \
+       face-options.hh \
+       font-options.hh \
+       hb-info.cc \
+       options.hh \
+       $(NULL)
+
 HB_SUBSET_CLI_sources = \
        batch.hh \
        face-options.hh \
@@ -515,15 +549,19 @@ LDADD = \
        $(FREETYPE_LIBS) \
        $(NULL)
 
-@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@hb_view_SOURCES = $(HB_VIEW_sources)
-@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@hb_view_LDADD = \
-@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@       $(LDADD) \
-@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@       $(CAIRO_LIBS) \
-@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@       $(CAIRO_FT_LIBS) \
-@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@       $(CHAFA_LIBS) \
-@HAVE_CAIRO_FT_TRUE@@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@       $(NULL)
+@HAVE_CAIRO_TRUE@@HAVE_GLIB_TRUE@hb_view_SOURCES = $(HB_VIEW_sources)
+@HAVE_CAIRO_TRUE@@HAVE_GLIB_TRUE@hb_view_LDADD = \
+@HAVE_CAIRO_TRUE@@HAVE_GLIB_TRUE@      $(top_builddir)/src/libharfbuzz-cairo.la \
+@HAVE_CAIRO_TRUE@@HAVE_GLIB_TRUE@      $(LDADD) \
+@HAVE_CAIRO_TRUE@@HAVE_GLIB_TRUE@      $(CAIRO_LIBS) \
+@HAVE_CAIRO_TRUE@@HAVE_GLIB_TRUE@      $(CAIRO_FT_LIBS) \
+@HAVE_CAIRO_TRUE@@HAVE_GLIB_TRUE@      $(CHAFA_LIBS) \
+@HAVE_CAIRO_TRUE@@HAVE_GLIB_TRUE@      $(NULL)
 
 @HAVE_GLIB_TRUE@hb_shape_SOURCES = $(HB_SHAPE_sources)
+@HAVE_GLIB_TRUE@hb_info_SOURCES = $(HB_INFO_sources)
+@HAVE_GLIB_TRUE@hb_info_LDADD = $(LDADD) $(NULL) $(am__append_3) \
+@HAVE_GLIB_TRUE@       $(am__append_4)
 @HAVE_GLIB_TRUE@hb_subset_SOURCES = $(HB_SUBSET_CLI_sources)
 @HAVE_GLIB_TRUE@hb_subset_LDADD = \
 @HAVE_GLIB_TRUE@       $(top_builddir)/src/libharfbuzz-subset.la \
@@ -630,6 +668,10 @@ installcheck-binPROGRAMS: $(bin_PROGRAMS)
          done; \
        done; rm -f c$${pid}_.???; exit $$bad
 
+hb-info$(EXEEXT): $(hb_info_OBJECTS) $(hb_info_DEPENDENCIES) $(EXTRA_hb_info_DEPENDENCIES) 
+       @rm -f hb-info$(EXEEXT)
+       $(AM_V_CXXLD)$(CXXLINK) $(hb_info_OBJECTS) $(hb_info_LDADD) $(LIBS)
+
 hb-ot-shape-closure$(EXEEXT): $(hb_ot_shape_closure_OBJECTS) $(hb_ot_shape_closure_DEPENDENCIES) $(EXTRA_hb_ot_shape_closure_DEPENDENCIES) 
        @rm -f hb-ot-shape-closure$(EXEEXT)
        $(AM_V_CXXLD)$(CXXLINK) $(hb_ot_shape_closure_OBJECTS) $(hb_ot_shape_closure_LDADD) $(LIBS)
@@ -652,6 +694,7 @@ mostlyclean-compile:
 distclean-compile:
        -rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-info.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-ot-shape-closure.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-shape.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-subset.Po@am__quote@ # am--include-marker
@@ -820,7 +863,8 @@ clean: clean-am
 clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
 
 distclean: distclean-am
-               -rm -f ./$(DEPDIR)/hb-ot-shape-closure.Po
+               -rm -f ./$(DEPDIR)/hb-info.Po
+       -rm -f ./$(DEPDIR)/hb-ot-shape-closure.Po
        -rm -f ./$(DEPDIR)/hb-shape.Po
        -rm -f ./$(DEPDIR)/hb-subset.Po
        -rm -f ./$(DEPDIR)/hb-view.Po
@@ -869,7 +913,8 @@ install-ps-am:
 installcheck-am: installcheck-binPROGRAMS
 
 maintainer-clean: maintainer-clean-am
-               -rm -f ./$(DEPDIR)/hb-ot-shape-closure.Po
+               -rm -f ./$(DEPDIR)/hb-info.Po
+       -rm -f ./$(DEPDIR)/hb-ot-shape-closure.Po
        -rm -f ./$(DEPDIR)/hb-shape.Po
        -rm -f ./$(DEPDIR)/hb-subset.Po
        -rm -f ./$(DEPDIR)/hb-view.Po
index df3ad4a..a64099e 100644 (file)
@@ -4,6 +4,7 @@ HB_VIEW_sources = \
        font-options.hh \
        hb-view.cc \
        helper-cairo-ansi.hh \
+       helper-cairo-ft.hh \
        helper-cairo.hh \
        main-font-text.hh \
        options.hh \
@@ -26,9 +27,18 @@ HB_SHAPE_sources = \
        shape-consumer.hh \
        shape-format.hh \
        shape-options.hh \
+       shape-output.hh \
        text-options.hh \
        $(NULL)
 
+HB_INFO_sources = \
+       batch.hh \
+       face-options.hh \
+       font-options.hh \
+       hb-info.cc \
+       options.hh \
+       $(NULL)
+
 HB_SUBSET_CLI_sources = \
        batch.hh \
        face-options.hh \
index 6476668..c96e0c7 100644 (file)
 
 #include "hb.hh"
 
+#include <cairo.h>
+
 #include <assert.h>
 #include <stdlib.h>
 #include <stddef.h>
 #include <string.h>
-#include <stdio.h>
 #include <math.h>
-#include <fcntl.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h> /* for isatty() */
-#endif
 
 #if defined (_MSC_VER) && (_MSC_VER < 1800)
 static inline long int
@@ -51,8 +48,6 @@ lround (double x)
 }
 #endif
 
-#define ESC_E (char)27
-
 #define CELL_W 8
 #define CELL_H (2 * CELL_W)
 
@@ -175,11 +170,11 @@ struct biimage_t
     for (unsigned int i = 1; i < 8; i++)
       if (freq[bg] < freq[i])
        bg = i;
-    fg = 0;
-    for (unsigned int i = 1; i < 8; i++)
-      if (i != bg && freq[fg] < freq[i])
+    fg = 8;
+    for (unsigned int i = 0; i < 8; i++)
+      if (i != bg && (fg == 8 || freq[fg] < freq[i]))
        fg = i;
-    if (fg == bg || freq[fg] == 0) {
+    if (freq[fg] == 0) {
       fg = bg;
       unicolor = true;
     }
@@ -196,11 +191,11 @@ struct biimage_t
     color_t bgc = color_t::from_ansi (bg);
     color_t fgc = color_t::from_ansi (fg);
     color_diff_t diff = fgc.diff (bgc);
-    int dd = diff.dot (diff);
+    double dd = sqrt (diff.dot (diff));
     for (unsigned int y = 0; y < height; y++)
       for (unsigned int x = 0; x < width; x++) {
-       int d = diff.dot (image (x, y).diff (bgc));
-       (*this)(x, y) = d < 0 ? 0 : d > dd ? 255 : lround (d * 255. / dd);
+       double d = sqrt (diff.dot (image (x, y).diff (bgc)));
+       (*this)(x, y) = d <= 0 ? 0 : d >= dd ? 255 : lround (d / dd * 255.);
       }
   }
 
@@ -356,13 +351,13 @@ block_best (const biimage_t &bi, bool *inverse)
        case 1:  c = "▟"; inv = true;  break;
        case 2:  c = "▙"; inv = true;  break;
        case 4:  c = "▖"; inv = false; break;
+       case 6:  c = "▞"; inv = false; break;
+       case 7:  c = "▛"; inv = false; break;
        case 8:  c = "▗"; inv = false; break;
        case 9:  c = "▚"; inv = false; break;
-       case 6:  c = "▞"; inv = false; break;
-       case 7:  c = "▜"; inv = true;  break;
-       case 11: c = "▜"; inv = true;  break;
-       case 13: c = "▙"; inv = true;  break;
-       case 14: c = "▟"; inv = true;  break;
+       case 11: c = "▜"; inv = false; break;
+       case 13: c = "▙"; inv = false; break;
+       case 14: c = "▟"; inv = false; break;
       }
       if (c) {
        score = qs;
@@ -379,7 +374,9 @@ static inline void
 ansi_print_image_rgb24 (const uint32_t *data,
                        unsigned int width,
                        unsigned int height,
-                       unsigned int stride)
+                       unsigned int stride,
+                       cairo_write_func_t      write_func,
+                       void                    *closure)
 {
   image_t image (width, height, data, stride);
 
@@ -388,37 +385,56 @@ ansi_print_image_rgb24 (const uint32_t *data,
   image_t cell (CELL_W, CELL_H);
   biimage_t bi (CELL_W, CELL_H);
   unsigned int last_bg = -1, last_fg = -1;
-  for (unsigned int row = 0; row < rows; row++) {
-    for (unsigned int col = 0; col < cols; col++) {
+  for (unsigned int row = 0; row < rows; row++)
+  {
+    for (unsigned int col = 0; col < cols; col++)
+    {
       image.copy_sub_image (cell, col * CELL_W, row * CELL_H, CELL_W, CELL_H);
       bi.set (cell);
-      if (bi.unicolor) {
-       if (last_bg != bi.bg) {
-         printf ("%c[%dm", ESC_E, 40 + bi.bg);
+      if (bi.unicolor)
+      {
+       if (last_bg != bi.bg)
+       {
+         char buf[] = "\033[40m";
+         buf[3] += bi.bg;
+         write_func (closure, (unsigned char *) buf, 5);
          last_bg = bi.bg;
        }
-       printf (" ");
-      } else {
+       write_func (closure, (unsigned char *) " ", 1);
+      }
+      else
+      {
        /* Figure out the closest character to the biimage */
        bool inverse = false;
        const char *c = block_best (bi, &inverse);
-       if (inverse) {
-         if (last_bg != bi.fg || last_fg != bi.bg) {
-           printf ("%c[%d;%dm", ESC_E, 30 + bi.bg, 40 + bi.fg);
+       if (inverse)
+       {
+         if (last_bg != bi.fg || last_fg != bi.bg)
+         {
+           char buf[] = "\033[30;40m";
+           buf[3] += bi.bg;
+           buf[6] += bi.fg;
+           write_func (closure, (unsigned char *) buf, 8);
            last_bg = bi.fg;
            last_fg = bi.bg;
          }
-       } else {
-         if (last_bg != bi.bg || last_fg != bi.fg) {
-           printf ("%c[%d;%dm", ESC_E, 40 + bi.bg, 30 + bi.fg);
+       }
+       else
+       {
+         if (last_bg != bi.bg || last_fg != bi.fg)
+         {
+           char buf[] = "\033[40;30m";
+           buf[3] += bi.bg;
+           buf[6] += bi.fg;
+           write_func (closure, (unsigned char *) buf, 8);
            last_bg = bi.bg;
            last_fg = bi.fg;
          }
        }
-       printf ("%s", c);
+       write_func (closure, (unsigned char *) c, strlen (c));
       }
     }
-    printf ("%c[0m\n", ESC_E); /* Reset */
+    write_func (closure, (unsigned char *) "\033[0m\n", 5); /* Reset */
     last_bg = last_fg = -1;
   }
 }
index f680e05..eae6d0d 100644 (file)
@@ -129,7 +129,7 @@ face_options_t::add_options (option_parser_t *parser)
   GOptionEntry entries[] =
   {
     {"font-file",      0, 0, G_OPTION_ARG_STRING,      &this->font_file,               "Set font file-name",                           "filename"},
-    {"face-index",     0, 0, G_OPTION_ARG_INT,         &this->face_index,              "Set face index (default: 0)",                  "index"},
+    {"face-index",     'y', 0, G_OPTION_ARG_INT,       &this->face_index,              "Set face index (default: 0)",                  "index"},
     {nullptr}
   };
   parser->add_group (entries,
index fa1cffa..8ec36c9 100644 (file)
@@ -44,7 +44,9 @@ struct font_options_t : face_options_t
 {
   ~font_options_t ()
   {
+#ifndef HB_NO_VAR
     free (variations);
+#endif
     g_free (font_funcs);
     hb_font_destroy (font);
   }
@@ -53,16 +55,24 @@ struct font_options_t : face_options_t
 
   void post_parse (GError **error);
 
+  hb_bool_t sub_font = false;
+#ifndef HB_NO_VAR
   hb_variation_t *variations = nullptr;
   unsigned int num_variations = 0;
+#endif
   int x_ppem = 0;
   int y_ppem = 0;
   double ptem = 0.;
+  double x_embolden = 0.;
+  double y_embolden = 0.;
+  hb_bool_t embolden_in_place = false;
+  double slant = 0.;
   unsigned int subpixel_bits = SUBPIXEL_BITS;
   mutable double font_size_x = DEFAULT_FONT_SIZE;
   mutable double font_size_y = DEFAULT_FONT_SIZE;
   char *font_funcs = nullptr;
   int ft_load_flags = 2;
+  unsigned int named_instance = HB_FONT_NO_VAR_NAMED_INSTANCE;
 
   hb_font_t *font = nullptr;
 };
@@ -73,10 +83,10 @@ static struct supported_font_funcs_t {
        void (*func) (hb_font_t *);
 } supported_font_funcs[] =
 {
+  {"ot",       hb_ot_font_set_funcs},
 #ifdef HAVE_FREETYPE
   {"ft",       hb_ft_font_set_funcs},
 #endif
-  {"ot",       hb_ot_font_set_funcs},
 };
 
 
@@ -94,11 +104,19 @@ font_options_t::post_parse (GError **error)
   hb_font_set_ppem (font, x_ppem, y_ppem);
   hb_font_set_ptem (font, ptem);
 
+  hb_font_set_synthetic_bold (font,
+                             (float) x_embolden, (float) y_embolden,
+                             embolden_in_place);
+  hb_font_set_synthetic_slant (font, slant);
+
   int scale_x = (int) scalbnf (font_size_x, subpixel_bits);
   int scale_y = (int) scalbnf (font_size_y, subpixel_bits);
   hb_font_set_scale (font, scale_x, scale_y);
 
+#ifndef HB_NO_VAR
+  hb_font_set_var_named_instance (font, named_instance);
   hb_font_set_variations (font, variations, num_variations);
+#endif
 
   void (*set_font_funcs) (hb_font_t *) = nullptr;
   if (!font_funcs)
@@ -137,9 +155,17 @@ font_options_t::post_parse (GError **error)
 #ifdef HAVE_FREETYPE
   hb_ft_font_set_load_flags (font, ft_load_flags);
 #endif
-}
 
+  if (sub_font)
+  {
+    hb_font_t *old_font = font;
+    font = hb_font_create_sub_font (old_font);
+    hb_font_set_scale (old_font, scale_x * 2, scale_y * 2);
+    hb_font_destroy (old_font);
+  }
+}
 
+#ifndef HB_NO_VAR
 static gboolean
 parse_variations (const char *name G_GNUC_UNUSED,
                  const char *arg,
@@ -161,7 +187,7 @@ parse_variations (const char *name G_GNUC_UNUSED,
   p = s;
   do {
     font_opts->num_variations++;
-    p = strchr (p, ',');
+    p = strpbrk (p, ", ");
     if (p)
       p++;
   } while (p);
@@ -174,7 +200,7 @@ parse_variations (const char *name G_GNUC_UNUSED,
   p = s;
   font_opts->num_variations = 0;
   while (p && *p) {
-    char *end = strchr (p, ',');
+    char *end = strpbrk (p, ", ");
     if (hb_variation_from_string (p, end ? end - p : -1, &font_opts->variations[font_opts->num_variations]))
       font_opts->num_variations++;
     p = end ? end + 1 : nullptr;
@@ -182,6 +208,7 @@ parse_variations (const char *name G_GNUC_UNUSED,
 
   return true;
 }
+#endif
 
 static gboolean
 parse_font_size (const char *name G_GNUC_UNUSED,
@@ -224,6 +251,46 @@ parse_font_ppem (const char *name G_GNUC_UNUSED,
   }
 }
 
+static gboolean
+parse_font_embolden (const char *name G_GNUC_UNUSED,
+                    const char *arg,
+                    gpointer    data,
+                    GError    **error G_GNUC_UNUSED)
+{
+  font_options_t *font_opts = (font_options_t *) data;
+  switch (sscanf (arg, "%lf%*[ ,]%lf", &font_opts->x_embolden, &font_opts->y_embolden)) {
+    case 1: font_opts->y_embolden = font_opts->x_embolden; HB_FALLTHROUGH;
+    case 2: return true;
+    default:
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                  "%s argument should be one or two space-separated numbers",
+                  name);
+      return false;
+  }
+}
+
+static gboolean
+parse_font_bold (const char *name G_GNUC_UNUSED,
+                const char *arg,
+                gpointer    data,
+                GError    **error G_GNUC_UNUSED)
+{
+  font_options_t *font_opts = (font_options_t *) data;
+  font_opts->embolden_in_place = false;
+  return parse_font_embolden ( name, arg, data, error);
+}
+
+static gboolean
+parse_font_grade (const char *name G_GNUC_UNUSED,
+                 const char *arg,
+                 gpointer    data,
+                 GError    **error G_GNUC_UNUSED)
+{
+  font_options_t *font_opts = (font_options_t *) data;
+  font_opts->embolden_in_place = true;
+  return parse_font_embolden ( name, arg, data, error);
+}
+
 void
 font_options_t::add_options (option_parser_t *parser)
 {
@@ -252,7 +319,7 @@ font_options_t::add_options (option_parser_t *parser)
     font_size_text = (char *) "Font size (default: upem)";
   else
   {
-    font_size_text = g_strdup_printf ("Font size (default: %d)", DEFAULT_FONT_SIZE);
+    font_size_text = g_strdup_printf ("Font size (default: %u)", DEFAULT_FONT_SIZE);
     parser->free_later (font_size_text);
   }
 
@@ -263,9 +330,17 @@ font_options_t::add_options (option_parser_t *parser)
                              G_OPTION_ARG_CALLBACK,    (gpointer) &parse_font_size,    font_size_text,                                 "1/2 integers or 'upem'"},
     {"font-ppem",      0, font_size_flags,
                              G_OPTION_ARG_CALLBACK,    (gpointer) &parse_font_ppem,    "Set x,y pixels per EM (default: 0; disabled)", "1/2 integers"},
-    {"font-ptem",      0, 0,
+    {"font-ptem",      0, font_size_flags,
                              G_OPTION_ARG_DOUBLE,      &this->ptem,                    "Set font point-size (default: 0; disabled)",   "point-size"},
+    {"font-bold",      0, font_size_flags,
+                             G_OPTION_ARG_CALLBACK,    (gpointer) &parse_font_bold,    "Set synthetic bold (default: 0)",              "1/2 numbers; eg. 0.05"},
+    {"font-grade",     0, font_size_flags,
+                             G_OPTION_ARG_CALLBACK,    (gpointer) &parse_font_grade,   "Set synthetic grade (default: 0)",             "1/2 numbers; eg. 0.05"},
+    {"font-slant",     0, font_size_flags,
+                             G_OPTION_ARG_DOUBLE,      &this->slant,                   "Set synthetic slant (default: 0)",              "slant ratio; eg. 0.2"},
     {"font-funcs",     0, 0, G_OPTION_ARG_STRING,      &this->font_funcs,              text,                                           "impl"},
+    {"sub-font",       0, G_OPTION_FLAG_HIDDEN,
+                             G_OPTION_ARG_NONE,        &this->sub_font,                "Create a sub-font (default: false)",           "boolean"},
     {"ft-load-flags",  0, 0, G_OPTION_ARG_INT,         &this->ft_load_flags,           "Set FreeType load-flags (default: 2)",         "integer"},
     {nullptr}
   };
@@ -276,6 +351,7 @@ font_options_t::add_options (option_parser_t *parser)
                     this,
                     false /* We add below. */);
 
+#ifndef HB_NO_VAR
   const gchar *variations_help = "Comma-separated list of font variations\n"
     "\n"
     "    Variations are set globally. The format for specifying variation settings\n"
@@ -290,6 +366,7 @@ font_options_t::add_options (option_parser_t *parser)
 
   GOptionEntry entries2[] =
   {
+    {"named-instance", 0, 0, G_OPTION_ARG_INT,         &this->named_instance,          "Set named-instance index (default: none)",     "index"},
     {"variations",     0, 0, G_OPTION_ARG_CALLBACK,    (gpointer) &parse_variations,   variations_help,        "list"},
     {nullptr}
   };
@@ -298,6 +375,7 @@ font_options_t::add_options (option_parser_t *parser)
                     "Variations options:",
                     "Options for font variations used",
                     this);
+#endif
 }
 
 #endif
diff --git a/util/hb-info.cc b/util/hb-info.cc
new file mode 100644 (file)
index 0000000..e514f90
--- /dev/null
@@ -0,0 +1,1450 @@
+/*
+ * Copyright © 2023  Behdad Esfahbod
+ *
+ *  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 "batch.hh"
+#include "font-options.hh"
+
+#ifdef HB_HAS_GOBJECT
+#include <hb-gobject.h>
+#endif
+
+#ifdef HAVE_CHAFA
+# include <chafa.h>
+#endif
+
+const unsigned DEFAULT_FONT_SIZE = FONT_SIZE_UPEM;
+const unsigned SUBPIXEL_BITS = 0;
+
+static void
+_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 */)
+{
+  static hb_language_t en = hb_language_from_string ("en", -1);
+
+  unsigned len = *text_size;
+  if (!hb_ot_name_get_utf8 (face, name_id,
+                           language,
+                           &len, text))
+  {
+    len = *text_size;
+    hb_ot_name_get_utf8 (face, name_id,
+                        en,
+                        &len, text);
+  }
+  *text_size = len;
+}
+
+struct info_t :
+       option_parser_t,
+       font_options_t
+{
+  void add_options ()
+  {
+    font_options_t::add_options (this);
+
+    GOptionEntry misc_entries[] =
+    {
+      {"direction",    0, 0, G_OPTION_ARG_STRING,      &this->direction_str,           "Set direction (default: ltr)",         "ltr/rtl/ttb/btt"},
+      {"script",       0, 0, G_OPTION_ARG_STRING,      &this->script_str,              "Set script (default: none)",           "ISO-15924 tag; eg. 'Latn'"},
+      {"language",     0, 0, G_OPTION_ARG_STRING,      &this->language_str,            "Set language (default: $LANG)",        "BCP 47 tag; eg. 'en'"},
+      {"ot-script",    0, 0, G_OPTION_ARG_STRING,      &this->ot_script_str,           "Set OpenType script tag (default: none)","tag; eg. 'latn'"},
+      {"ot-language",  0, 0, G_OPTION_ARG_STRING,      &this->ot_language_str,         "Set OpenType language tag (default: none)",    "tag; eg. 'ENG'"},
+
+      {nullptr}
+    };
+    add_group (misc_entries,
+              "misc",
+              "Miscellaneous options:",
+              "Miscellaneous options affecting queries",
+              this,
+              false /* We add below. */);
+
+    GOptionEntry query_entries[] =
+    {
+      {"all",          'a', 0, G_OPTION_ARG_NONE,      &this->all,                     "Show everything",              nullptr},
+
+      {"show-all",     0, 0, G_OPTION_ARG_NONE,        &this->show_all,                "Show all short information (default)", nullptr},
+      {"show-face-count",0, 0, G_OPTION_ARG_NONE,      &this->show_face_count,         "Show face count",              nullptr},
+      {"show-family",  0, 0, G_OPTION_ARG_NONE,        &this->show_family,             "Show family name",             nullptr},
+      {"show-subfamily",0, 0, G_OPTION_ARG_NONE,       &this->show_subfamily,          "Show subfamily name",          nullptr},
+      {"show-unique-name",0, 0, G_OPTION_ARG_NONE,     &this->show_unique_name,        "Show unique name",             nullptr},
+      {"show-full-name",0, 0, G_OPTION_ARG_NONE,       &this->show_full_name,          "Show full name",               nullptr},
+      {"show-postscript-name",0, 0, G_OPTION_ARG_NONE, &this->show_postscript_name,    "Show Postscript name",         nullptr},
+      {"show-version", 0, 0, G_OPTION_ARG_NONE,        &this->show_version,            "Show version",                 nullptr},
+      {"show-technology",0, 0, G_OPTION_ARG_NONE,      &this->show_technology,         "Show technology",              nullptr},
+      {"show-unicode-count",0, 0, G_OPTION_ARG_NONE,   &this->show_unicode_count,      "Show Unicode count",           nullptr},
+      {"show-glyph-count",0, 0, G_OPTION_ARG_NONE,     &this->show_glyph_count,        "Show glyph count",             nullptr},
+      {"show-upem",    0, 0, G_OPTION_ARG_NONE,        &this->show_upem,               "Show Units-Per-EM",            nullptr},
+      {"show-extents", 0, 0, G_OPTION_ARG_NONE,        &this->show_extents,            "Show extents",                 nullptr},
+
+      {"get-name",     0, 0, G_OPTION_ARG_STRING_ARRAY,&this->get_name,                "Get name",                     "name id; eg. '13'"},
+      {"get-style",    0, 0, G_OPTION_ARG_STRING_ARRAY,&this->get_style,               "Get style",                    "style tag; eg. 'wght'"},
+      {"get-metric",   0, 0, G_OPTION_ARG_STRING_ARRAY,&this->get_metric,              "Get metric",                   "metric tag; eg. 'hasc'"},
+      {"get-baseline", 0, 0, G_OPTION_ARG_STRING_ARRAY,&this->get_baseline,            "Get baseline",                 "baseline tag; eg. 'hang'"},
+      {"get-meta",     0, 0, G_OPTION_ARG_STRING_ARRAY,&this->get_meta,                "Get meta information",         "tag tag; eg. 'dlng'"},
+      {"get-table",    0, 0, G_OPTION_ARG_STRING,      &this->get_table,               "Get font table",               "table tag; eg. 'cmap'"},
+
+      {"list-all",     0, 0, G_OPTION_ARG_NONE,        &this->list_all,                "List all long information",    nullptr},
+      {"list-names",   0, 0, G_OPTION_ARG_NONE,        &this->list_names,              "List names",                   nullptr},
+#ifdef HB_HAS_GOBJECT
+      {"list-style",   0, 0, G_OPTION_ARG_NONE,        &this->list_style,              "List style",                   nullptr},
+      {"list-metrics", 0, 0, G_OPTION_ARG_NONE,        &this->list_metrics,            "List metrics",                 nullptr},
+      {"list-baselines",0, 0, G_OPTION_ARG_NONE,       &this->list_baselines,          "List baselines",               nullptr},
+#endif
+      {"list-tables",  'l', 0, G_OPTION_ARG_NONE,      &this->list_tables,             "List tables",                  nullptr},
+      {"list-unicodes",        0, 0, G_OPTION_ARG_NONE,        &this->list_unicodes,           "List characters",              nullptr},
+      {"list-glyphs",  0, 0, G_OPTION_ARG_NONE,        &this->list_glyphs,             "List glyphs",                  nullptr},
+      {"list-scripts", 0, 0, G_OPTION_ARG_NONE,        &this->list_scripts,            "List layout scripts",          nullptr},
+      {"list-features",        0, 0, G_OPTION_ARG_NONE,        &this->list_features,           "List layout features",         nullptr},
+#ifndef HB_NO_VAR
+      {"list-variations",0, 0, G_OPTION_ARG_NONE,      &this->list_variations,         "List variations",              nullptr},
+#endif
+      {"list-palettes",        0, 0, G_OPTION_ARG_NONE,        &this->list_palettes,           "List color palettes",          nullptr},
+      {"list-meta",    0, 0, G_OPTION_ARG_NONE,        &this->list_meta,               "List meta information",        nullptr},
+
+      {nullptr}
+    };
+    add_group (query_entries,
+              "query",
+              "Query options:",
+              "Options to query the font instance",
+              this,
+              true);
+
+    GOptionEntry entries[] =
+    {
+      {"quiet",                'q', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE,  &this->verbose, "Generate machine-readable output",     nullptr},
+      {G_OPTION_REMAINING,     0, G_OPTION_FLAG_IN_MAIN,
+                               G_OPTION_ARG_CALLBACK,  (gpointer) &collect_rest,       nullptr,        "[FONT-FILE]"},
+      {nullptr}
+    };
+    add_main_group (entries, this);
+
+    option_parser_t::add_options ();
+  }
+
+  static gboolean
+  collect_rest (const char *name G_GNUC_UNUSED,
+               const char *arg,
+               gpointer    data,
+               GError    **error)
+  {
+    info_t *thiz = (info_t *) data;
+
+    if (!thiz->font_file)
+    {
+      thiz->font_file = g_strdup (arg);
+      return true;
+    }
+
+    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
+                "Too many arguments on the command line");
+    return false;
+  }
+
+
+  protected:
+
+  hb_bool_t verbose = true;
+  hb_bool_t first_item = true;
+
+  char *direction_str = nullptr;
+  char *script_str = nullptr;
+  char *language_str = nullptr;
+  hb_direction_t direction = HB_DIRECTION_LTR;
+  hb_script_t script = HB_SCRIPT_INVALID;
+  hb_language_t language = HB_LANGUAGE_INVALID;
+  char *ot_script_str = nullptr;
+  char *ot_language_str = nullptr;
+
+  hb_bool_t all = false;
+
+  hb_bool_t show_all = false;
+  hb_bool_t show_face_count = false;
+  hb_bool_t show_family = false;
+  hb_bool_t show_subfamily = false;
+  hb_bool_t show_unique_name = false;
+  hb_bool_t show_full_name = false;
+  hb_bool_t show_postscript_name = false;
+  hb_bool_t show_version = false;
+  hb_bool_t show_technology = false;
+  hb_bool_t show_unicode_count = false;
+  hb_bool_t show_glyph_count = false;
+  hb_bool_t show_upem = false;
+  hb_bool_t show_extents = false;
+
+  char **get_name = nullptr;
+  char **get_style = nullptr;
+  char **get_metric = nullptr;
+  char **get_baseline = nullptr;
+  char **get_meta = nullptr;
+  char *get_table = nullptr;
+
+  hb_bool_t list_all = false;
+  hb_bool_t list_names = false;
+#ifdef HB_HAS_GOBJECT
+  hb_bool_t list_style = false;
+  hb_bool_t list_metrics = false;
+  hb_bool_t list_baselines = false;
+#endif
+  hb_bool_t list_tables = false;
+  hb_bool_t list_unicodes = false;
+  hb_bool_t list_glyphs = false;
+  hb_bool_t list_scripts = false;
+  hb_bool_t list_features = false;
+#ifndef HB_NO_VAR
+  hb_bool_t list_variations = false;
+#endif
+  hb_bool_t list_palettes = false;
+  hb_bool_t list_meta = false;
+
+  public:
+
+  void
+  post_parse (GError **error)
+  {
+    if (direction_str)
+      direction = hb_direction_from_string (direction_str, -1);
+    if (script_str)
+      script = hb_script_from_string (script_str, -1);
+    language = hb_language_get_default ();
+    if (language_str)
+      language = hb_language_from_string (language_str, -1);
+  }
+
+  int
+  operator () (int argc, char **argv)
+  {
+    add_options ();
+
+    if (argc == 2)
+      show_all = true;
+
+    parse (&argc, &argv);
+
+    if (all)
+    {
+      show_all =
+      list_all =
+      true;
+    }
+
+    if (show_all)
+    {
+      show_face_count =
+      show_family =
+      show_subfamily =
+      show_unique_name =
+      show_full_name =
+      show_postscript_name =
+      show_version =
+      show_technology =
+      show_unicode_count =
+      show_glyph_count =
+      show_upem =
+      show_extents =
+      true;
+      first_item = false;
+    }
+
+    if (list_all)
+    {
+      list_names =
+#ifdef HB_HAS_GOBJECT
+      list_style =
+      list_metrics =
+      list_baselines =
+#endif
+      list_tables =
+      list_unicodes =
+      list_glyphs =
+      list_scripts =
+      list_features =
+#ifndef HB_NO_VAR
+      list_variations =
+#endif
+      list_palettes =
+      list_meta =
+      true;
+    }
+
+    if (show_face_count)  _show_face_count ();
+    if (show_family)     _show_family ();
+    if (show_subfamily)          _show_subfamily ();
+    if (show_unique_name) _show_unique_name ();
+    if (show_full_name)          _show_full_name ();
+    if (show_postscript_name)_show_postscript_name ();
+    if (show_version)    _show_version ();
+    if (show_technology)  _show_technology ();
+    if (show_unicode_count)_show_unicode_count ();
+    if (show_glyph_count) _show_glyph_count ();
+    if (show_upem)       _show_upem ();
+    if (show_extents)    _show_extents ();
+
+    if (get_name)        _get_name ();
+    if (get_style)       _get_style ();
+    if (get_metric)      _get_metric ();
+    if (get_baseline)    _get_baseline ();
+    if (get_meta)        _get_meta ();
+    if (get_table)       _get_table ();
+
+    if (list_names)      _list_names ();
+#ifdef HB_HAS_GOBJECT
+    if (list_style)      _list_style ();
+    if (list_metrics)    _list_metrics ();
+    if (list_baselines)          _list_baselines ();
+#endif
+    if (list_tables)     _list_tables ();
+    if (list_unicodes)   _list_unicodes ();
+    if (list_glyphs)     _list_glyphs ();
+    if (list_scripts)    _list_scripts ();
+    if (list_features)   _list_features ();
+#ifndef HB_NO_VAR
+    if (list_variations)  _list_variations ();
+#endif
+    if (list_palettes)   _list_palettes ();
+    if (list_meta)       _list_meta ();
+
+    return 0;
+  }
+
+  protected:
+
+  void separator ()
+  {
+    if (first_item)
+    {
+      first_item = false;
+      return;
+    }
+    printf ("\n===\n\n");
+  }
+
+  void
+  _show_face_count ()
+  {
+    printf ("Face count: %u\n", hb_face_count (blob));
+  }
+
+  void
+  _show_name (const char *label, hb_ot_name_id_t name_id)
+  {
+    if (verbose)
+    {
+      printf ("%s: ", label);
+    }
+
+    char name[16384];
+    unsigned name_len = sizeof name;
+    _hb_ot_name_get_utf8 (face, name_id,
+                         language,
+                         &name_len, name);
+
+    printf ("%s\n", name);
+  }
+  void _show_family ()         { _show_name ("Family", 1); }
+  void _show_subfamily ()
+  {
+    hb_ot_name_id_t name_id = 2;
+
+    unsigned named_instance = hb_font_get_var_named_instance (font);
+    if (named_instance != HB_FONT_NO_VAR_NAMED_INSTANCE)
+      name_id = hb_ot_var_named_instance_get_subfamily_name_id (face, named_instance);
+
+    _show_name ("Subfamily", name_id);
+  }
+  void _show_unique_name ()    { _show_name ("Unique name", 3); }
+  void _show_full_name ()      { _show_name ("Full name", 4); }
+  void _show_postscript_name ()
+  {
+    hb_ot_name_id_t name_id = 6;
+
+    unsigned named_instance = hb_font_get_var_named_instance (font);
+    if (named_instance != HB_FONT_NO_VAR_NAMED_INSTANCE)
+      name_id = hb_ot_var_named_instance_get_postscript_name_id (face, named_instance);
+
+
+    _show_name ("Postscript name", name_id);
+  }
+  void _show_version ()                { _show_name ("Version", 5); }
+
+  bool _has_blob (hb_tag_t tag)
+  {
+    hb_blob_t *blob = hb_face_reference_table (face, tag);
+    bool ret = hb_blob_get_length (blob);
+    hb_blob_destroy (blob);
+    return ret;
+  }
+
+  void _show_technology ()
+  {
+    if (_has_blob (HB_TAG('g','l','y','f')))
+      printf ("Has TrueType outlines\n");
+    if (_has_blob (HB_TAG('C','F','F',' ')) || _has_blob (HB_TAG('C','F','F','2')))
+      printf ("Has Postscript outlines\n");
+
+    if (_has_blob (HB_TAG('f','p','g','m')) || _has_blob (HB_TAG('p','r','e','p')) || _has_blob (HB_TAG('c','v','t',' ')))
+      printf ("Has TrueType hinting\n");
+
+    if (_has_blob (HB_TAG('G','S','U','B')) || _has_blob (HB_TAG('G','P','O','S')))
+      printf ("Has OpenType layout\n");
+    if (_has_blob (HB_TAG('m','o','r','x')) || _has_blob (HB_TAG('k','e','r','x')))
+      printf ("Has AAT layout\n");
+    if (_has_blob (HB_TAG('S','i','l','f')))
+      printf ("Has Graphite layout\n");
+    if (_has_blob (HB_TAG('k','e','r','n')))
+      printf ("Has legacy kerning\n");
+
+    if (_has_blob (HB_TAG('E','B','D','T')))
+      printf ("Has monochrome bitmaps\n");
+
+    if (_has_blob (HB_TAG('C','B','D','T')) || _has_blob (HB_TAG('s','b','i','x')))
+      printf ("Has color bitmaps\n");
+    if (_has_blob (HB_TAG('S','V','G',' ')))
+      printf ("Has color SVGs\n");
+    if (_has_blob (HB_TAG('C','O','L','R')))
+      printf ("Has color paintings\n");
+
+    if (_has_blob (HB_TAG('f','v','a','r')))  printf ("Has variations\n");
+  }
+
+  void _show_unicode_count ()
+  {
+    if (verbose)
+    {
+      printf ("Unicode count: ");
+    }
+
+    hb_set_t *unicodes = hb_set_create ();
+    hb_face_collect_unicodes (face, unicodes);
+
+    printf ("%u\n", hb_set_get_population (unicodes));
+
+    hb_set_destroy (unicodes);
+  }
+
+  void _show_glyph_count ()
+  {
+    if (verbose)
+    {
+      printf ("Glyph count: ");
+    }
+
+    printf ("%u\n", hb_face_get_glyph_count (face));
+  }
+
+  void _show_upem ()
+  {
+    if (verbose)
+    {
+      printf ("Units-Per-EM: ");
+    }
+
+    printf ("%u\n", hb_face_get_upem (face));
+  }
+
+  void _show_extents ()
+  {
+    hb_font_extents_t extents;
+    hb_font_get_extents_for_direction (font, direction, &extents);
+
+    if (verbose) printf ("Ascender: ");
+    printf ("%d\n", extents.ascender);
+
+    if (verbose) printf ("Descender: ");
+    printf ("%d\n", extents.descender);
+
+    if (verbose) printf ("Line gap: ");
+    printf ("%d\n", extents.line_gap);
+  }
+
+  void _get_name ()
+  {
+    for (char **p = get_name; *p; p++)
+    {
+      hb_ot_name_id_t name_id = (hb_ot_name_id_t) atoi (*p);
+      _show_name (*p, name_id);
+    }
+  }
+
+  void _get_style ()
+  {
+    for (char **p = get_style; *p; p++)
+    {
+      hb_style_tag_t tag = (hb_style_tag_t) hb_tag_from_string (*p, -1);
+
+      if (verbose)
+       printf ("Style %c%c%c%c: ", HB_UNTAG (tag));
+
+      float v = hb_style_get_value (font, tag);
+      printf ("%g\n", (double) v);
+    }
+  }
+
+  void _get_metric ()
+  {
+    bool fallback = false;
+    for (char **p = get_metric; *p; p++)
+    {
+      hb_ot_metrics_tag_t tag = (hb_ot_metrics_tag_t) hb_tag_from_string (*p, -1);
+      hb_position_t position;
+
+      if (verbose)
+       printf ("Metric %c%c%c%c: ", HB_UNTAG (tag));
+
+      if (hb_ot_metrics_get_position (font, tag, &position))
+       printf ("%d     \n", position);
+      else
+      {
+       hb_ot_metrics_get_position_with_fallback (font, tag, &position);
+       printf ("%d     *\n", position);
+       fallback = true;
+      }
+    }
+
+    if (verbose && fallback)
+    {
+      printf ("\n[*] Fallback value\n");
+    }
+  }
+
+  void _get_baseline ()
+  {
+    hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
+    hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
+    unsigned script_count = HB_OT_MAX_TAGS_PER_SCRIPT;
+    unsigned language_count = HB_OT_MAX_TAGS_PER_LANGUAGE;
+
+    hb_ot_tags_from_script_and_language (script, language,
+                                        &script_count, script_tags,
+                                        &language_count, language_tags);
+
+    hb_tag_t script_tag = script_count ? script_tags[script_count - 1] : HB_TAG_NONE;
+    hb_tag_t language_tag = language_count ? language_tags[0] : HB_TAG_NONE;
+
+    if (ot_script_str)
+      script_tag = hb_tag_from_string (ot_script_str, -1);
+    if (ot_language_str)
+      language_tag = hb_tag_from_string (ot_language_str, -1);
+
+
+    bool fallback = false;
+    for (char **p = get_baseline; *p; p++)
+    {
+      hb_ot_layout_baseline_tag_t tag = (hb_ot_layout_baseline_tag_t) hb_tag_from_string (*p, -1);
+      hb_position_t position;
+
+      if (verbose)
+       printf ("Baseline %c%c%c%c: ", HB_UNTAG (tag));
+
+      if (hb_ot_layout_get_baseline (font, tag, direction, script_tag, language_tag, &position))
+       printf ("%d     \n", position);
+      else
+      {
+       hb_ot_layout_get_baseline_with_fallback (font, tag, direction, script_tag, language_tag, &position);
+       printf ("%d     *\n", position);
+       fallback = true;
+      }
+    }
+
+    if (verbose && fallback)
+    {
+      printf ("\n[*] Fallback value\n");
+    }
+  }
+
+  void _get_meta ()
+  {
+    for (char **p = get_meta; *p; p++)
+    {
+      hb_ot_meta_tag_t tag = (hb_ot_meta_tag_t) hb_tag_from_string (*p, -1);
+
+      hb_blob_t *blob = hb_ot_meta_reference_entry (face, tag);
+
+      if (verbose)
+       printf ("Meta %c%c%c%c: ", HB_UNTAG (tag));
+
+      printf ("%.*s\n",
+             (int) hb_blob_get_length (blob),
+             hb_blob_get_data (blob, nullptr));
+
+      hb_blob_destroy (blob);
+    }
+  }
+
+  void
+  _get_table ()
+  {
+    hb_blob_t *blob = hb_face_reference_table (face, hb_tag_from_string (get_table, -1));
+    unsigned count = 0;
+    const char *data = hb_blob_get_data (blob, &count);
+    fwrite (data, 1, count, stdout);
+    hb_blob_destroy (blob);
+  }
+
+  void _list_names ()
+  {
+    if (verbose)
+    {
+      separator ();
+      printf ("Name information:\n\n");
+      printf ("Id: Name                        Text\n------------------------------------\n");
+    }
+
+#ifdef HB_HAS_GOBJECT
+    GEnumClass *enum_class = (GEnumClass *) g_type_class_ref ((GType) HB_GOBJECT_TYPE_OT_NAME_ID_PREDEFINED);
+#endif
+
+    unsigned count;
+    const auto *entries = hb_ot_name_list_names (face, &count);
+    for (unsigned i = 0; i < count; i++)
+    {
+      char name[16384];
+      unsigned name_len = sizeof name;
+      _hb_ot_name_get_utf8 (face, entries[i].name_id,
+                           language,
+                           &name_len, name);
+
+#ifdef HB_HAS_GOBJECT
+      if (verbose)
+      {
+       GEnumValue *enum_value = g_enum_get_value (enum_class, entries[i].name_id);
+       printf ("%u: %-27s      %s\n", entries[i].name_id, enum_value ? enum_value->value_nick : "", name);
+      }
+      else
+#endif
+       printf ("%u     %s\n", entries[i].name_id, name);
+    }
+  }
+
+#ifdef HB_HAS_GOBJECT
+  void _list_style ()
+  {
+    if (verbose)
+    {
+      separator ();
+      printf ("Style information:\n\n");
+      printf ("Tag:  Name                              Value\n---------------------------------------------\n");
+    }
+
+    GEnumClass *enum_class = (GEnumClass *) g_type_class_ref ((GType) HB_GOBJECT_TYPE_STYLE_TAG);
+
+    unsigned count = enum_class->n_values;
+    const auto *entries = enum_class->values;
+    for (unsigned i = 0; i < count; i++)
+    {
+       float v = hb_style_get_value (font, (hb_style_tag_t) entries[i].value);
+       printf ("%c%c%c%c", HB_UNTAG(entries[i].value));
+       if (verbose)
+         printf (": %-33s", entries[i].value_nick);
+       printf ("       %g\n", (double) v);
+    }
+  }
+
+  void _list_metrics ()
+  {
+    if (verbose)
+    {
+      separator ();
+      printf ("Metrics information:\n\n");
+      printf ("Tag:  Name                              Value\n---------------------------------------------\n");
+    }
+
+    GEnumClass *enum_class = (GEnumClass *) g_type_class_ref ((GType) HB_GOBJECT_TYPE_OT_METRICS_TAG);
+
+    bool any_fallback = false;
+
+    unsigned count = enum_class->n_values;
+    const auto *entries = enum_class->values;
+    for (unsigned i = 0; i < count; i++)
+    {
+       bool fallback = false;
+       hb_position_t v;
+       if (!hb_ot_metrics_get_position (font,
+                                       (hb_ot_metrics_tag_t) entries[i].value,
+                                       &v))
+       {
+         hb_ot_metrics_get_position_with_fallback (font,
+                                                   (hb_ot_metrics_tag_t) entries[i].value,
+                                                   &v);
+         any_fallback = fallback = true;
+       }
+       printf ("%c%c%c%c", HB_UNTAG(entries[i].value));
+       if (verbose)
+         printf (": %-33s", entries[i].value_nick);
+       printf ("       %d      ", v);
+
+       if (fallback)
+         printf ("*");
+       printf ("\n");
+    }
+
+    if (verbose && any_fallback)
+    {
+      printf ("\n[*] Fallback value\n");
+    }
+  }
+
+  void _list_baselines ()
+  {
+    hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
+    hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
+    unsigned script_count = HB_OT_MAX_TAGS_PER_SCRIPT;
+    unsigned language_count = HB_OT_MAX_TAGS_PER_LANGUAGE;
+
+    hb_ot_tags_from_script_and_language (script, language,
+                                        &script_count, script_tags,
+                                        &language_count, language_tags);
+
+    hb_tag_t script_tag = script_count ? script_tags[script_count - 1] : HB_TAG_NONE;
+    hb_tag_t language_tag = language_count ? language_tags[0] : HB_TAG_NONE;
+
+    if (ot_script_str)
+      script_tag = hb_tag_from_string (ot_script_str, -1);
+    if (ot_language_str)
+      language_tag = hb_tag_from_string (ot_language_str, -1);
+
+
+    if (verbose)
+    {
+      separator ();
+      printf ("Baselines information:\n\n");
+      printf ("Tag:  Name                              Value\n---------------------------------------------\n");
+    }
+
+    GEnumClass *enum_class = (GEnumClass *) g_type_class_ref ((GType) HB_GOBJECT_TYPE_OT_LAYOUT_BASELINE_TAG);
+
+    bool any_fallback = false;
+
+    unsigned count = enum_class->n_values;
+    const auto *entries = enum_class->values;
+    for (unsigned i = 0; i < count; i++)
+    {
+       bool fallback = false;
+       hb_position_t v;
+       if (!hb_ot_layout_get_baseline (font, (hb_ot_layout_baseline_tag_t) entries[i].value,
+                                       direction, script_tag, language_tag,
+                                       &v))
+       {
+         hb_ot_layout_get_baseline_with_fallback (font, (hb_ot_layout_baseline_tag_t) entries[i].value,
+                                                  direction, script_tag, language_tag,
+                                                  &v);
+         any_fallback = fallback = true;
+       }
+       printf ("%c%c%c%c", HB_UNTAG(entries[i].value));
+       if (verbose)
+         printf (": %-33s", entries[i].value_nick);
+       printf ("       %d      ", v);
+
+       if (fallback)
+         printf ("*");
+       printf ("\n");
+    }
+
+    if (verbose && any_fallback)
+    {
+      printf ("\n[*] Fallback value\n");
+    }
+  }
+#endif
+
+  void _list_tables ()
+  {
+    if (verbose)
+    {
+      separator ();
+      printf ("Table information:\n\n");
+      printf ("Tag     Size\n------------\n");
+    }
+
+    unsigned count = hb_face_get_table_tags (face, 0, nullptr, nullptr);
+    hb_tag_t *tags = (hb_tag_t *) calloc (count, sizeof (hb_tag_t));
+    hb_face_get_table_tags (face, 0, &count, tags);
+
+    for (unsigned i = 0; i < count; i++)
+    {
+      hb_tag_t tag = tags[i];
+
+      hb_blob_t *blob = hb_face_reference_table (face, tag);
+
+      printf ("%c%c%c%c %8u bytes\n", HB_UNTAG (tag), hb_blob_get_length (blob));
+
+      hb_blob_destroy (blob);
+    }
+
+    free (tags);
+  }
+
+  void
+  _list_unicodes ()
+  {
+    if (verbose)
+    {
+      separator ();
+      printf ("Character-set information:\n\n");
+      printf ("Unicode Glyph name\n------------------\n");
+    }
+
+    hb_set_t *unicodes = hb_set_create ();
+    hb_map_t *cmap = hb_map_create ();
+
+    hb_face_collect_nominal_glyph_mapping (face, cmap, unicodes);
+
+    for (hb_codepoint_t u = HB_SET_VALUE_INVALID;
+        hb_set_next (unicodes, &u);)
+    {
+      hb_codepoint_t gid = hb_map_get (cmap, u);
+
+      char glyphname[64];
+      hb_font_glyph_to_string (font, gid,
+                              glyphname, sizeof glyphname);
+
+      printf ("U+%04X  %s\n", u, glyphname);
+    }
+
+    hb_map_destroy (cmap);
+
+
+    /* List variation-selector sequences. */
+    hb_set_t *vars = hb_set_create ();
+
+    hb_face_collect_variation_selectors (face, vars);
+
+    for (hb_codepoint_t vs = HB_SET_VALUE_INVALID;
+        hb_set_next (vars, &vs);)
+    {
+      hb_set_clear (unicodes);
+      hb_face_collect_variation_unicodes (face, vs, unicodes);
+
+      for (hb_codepoint_t u = HB_SET_VALUE_INVALID;
+          hb_set_next (unicodes, &u);)
+      {
+       hb_codepoint_t gid = 0;
+       HB_UNUSED bool b = hb_font_get_variation_glyph (font, u, vs, &gid);
+       assert (b);
+
+       char glyphname[64];
+       hb_font_glyph_to_string (font, gid,
+                                glyphname, sizeof glyphname);
+
+       printf ("U+%04X,U+%04X  %s\n", vs, u, glyphname);
+      }
+    }
+
+    hb_set_destroy (vars);
+    hb_set_destroy (unicodes);
+  }
+
+  void
+  _list_glyphs ()
+  {
+    if (verbose)
+    {
+      separator ();
+      printf ("Glyph-set information:\n\n");
+      printf ("GlyphID Glyph name\n------------------\n");
+    }
+
+    unsigned num_glyphs = hb_face_get_glyph_count (face);
+
+    for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
+    {
+      char glyphname[64];
+      hb_font_glyph_to_string (font, gid,
+                              glyphname, sizeof glyphname);
+
+      printf ("%u      %s\n", gid, glyphname);
+    }
+  }
+
+  void
+  _list_scripts ()
+  {
+    if (verbose)
+    {
+      separator ();
+      printf ("Layout script information:\n\n");
+    }
+
+    hb_tag_t table_tags[] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS, HB_TAG_NONE};
+
+    for (unsigned int i = 0; table_tags[i]; i++)
+    {
+      if (verbose) printf ("Table: ");
+      printf ("%c%c%c%c\n", HB_UNTAG (table_tags[i]));
+
+      hb_tag_t script_array[32];
+      unsigned script_count = sizeof script_array / sizeof script_array[0];
+      unsigned script_offset = 0;
+      do
+      {
+       hb_ot_layout_table_get_script_tags (face, table_tags[i],
+                                           script_offset,
+                                           &script_count,
+                                           script_array);
+
+       for (unsigned script_index = 0; script_index < script_count; script_index++)
+       {
+         printf ("     ");
+         if (verbose) printf ("Script: ");
+
+         hb_tag_t hb_sc = hb_script_to_iso15924_tag (hb_ot_tag_to_script (script_array[script_index]));
+         if (script_array[script_index] == HB_TAG ('D','F','L','T'))
+           hb_sc = HB_SCRIPT_COMMON;
+
+         printf ("%c%c%c%c (%c%c%c%c)\n",
+                 HB_UNTAG (hb_sc),
+                 HB_UNTAG (script_array[script_index]));
+
+         hb_tag_t language_array[32];
+         unsigned language_count = sizeof language_array / sizeof language_array[0];
+         unsigned language_offset = 0;
+         do
+         {
+           hb_ot_layout_script_get_language_tags (face, table_tags[i],
+                                                  script_offset + script_index,
+                                                  language_offset,
+                                                  &language_count,
+                                                  language_array);
+
+           for (unsigned language_index = 0; language_index < language_count; language_index++)
+           {
+             printf ("         ");
+             if (verbose) printf ("Language: ");
+             printf ("%s (%c%c%c%c)\n",
+                     hb_language_to_string (hb_ot_tag_to_language (language_array[language_index])),
+                     HB_UNTAG (language_array[language_index]));
+           }
+
+           language_offset += language_count;
+         }
+         while (language_count == sizeof language_array / sizeof language_array[0]);
+       }
+
+       script_offset += script_count;
+      }
+      while (script_count == sizeof script_array / sizeof script_array[0]);
+
+    }
+
+  }
+
+  void
+  _list_features_no_script ()
+  {
+    if (verbose)
+    {
+      printf ("Showing all font features with duplicates removed.\n\n");
+    }
+
+    hb_tag_t table_tags[] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS, HB_TAG_NONE};
+
+    hb_set_t *features = hb_set_create ();
+
+    for (unsigned int i = 0; table_tags[i]; i++)
+    {
+      if (verbose) printf ("Table: ");
+      printf ("%c%c%c%c\n", HB_UNTAG (table_tags[i]));
+
+      hb_set_clear (features);
+      hb_tag_t feature_array[32];
+      unsigned feature_count = sizeof feature_array / sizeof feature_array[0];
+      unsigned feature_offset = 0;
+      do
+      {
+       hb_ot_layout_table_get_feature_tags (face, table_tags[i],
+                                            feature_offset,
+                                            &feature_count,
+                                            feature_array);
+
+       for (unsigned feature_index = 0; feature_index < feature_count; feature_index++)
+       {
+         if (hb_set_has (features, feature_array[feature_index]))
+           continue;
+         hb_set_add (features, feature_array[feature_index]);
+
+         hb_ot_name_id_t label_id;
+
+         hb_ot_layout_feature_get_name_ids (face,
+                                            table_tags[i],
+                                            feature_offset + feature_index,
+                                            &label_id,
+                                            nullptr,
+                                            nullptr,
+                                            nullptr,
+                                            nullptr);
+
+         char name[64];
+         unsigned name_len = sizeof name;
+
+         _hb_ot_name_get_utf8 (face, label_id,
+                               language,
+                               &name_len, name);
+
+         printf ("     ");
+         if (verbose) printf ("Feature: ");
+         printf ("%c%c%c%c", HB_UNTAG (feature_array[feature_index]));
+
+         if (*name)
+           printf ("   %s", name);
+
+         printf ("\n");
+       }
+
+       feature_offset += feature_count;
+      }
+      while (feature_count == sizeof feature_array / sizeof feature_array[0]);
+    }
+
+    hb_set_destroy (features);
+  }
+
+  void
+  _list_features ()
+  {
+    if (verbose)
+    {
+      separator ();
+      printf ("Layout features information:\n\n");
+    }
+
+    hb_tag_t table_tags[] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS, HB_TAG_NONE};
+
+    if (script == HB_SCRIPT_INVALID && !ot_script_str)
+    {
+      _list_features_no_script ();
+      return;
+    }
+
+    for (unsigned int i = 0; table_tags[i]; i++)
+    {
+      if (verbose) printf ("Table: ");
+      printf ("%c%c%c%c\n", HB_UNTAG (table_tags[i]));
+
+      auto table_tag = table_tags[i];
+
+      hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
+      hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
+      unsigned script_count = HB_OT_MAX_TAGS_PER_SCRIPT;
+      unsigned language_count = HB_OT_MAX_TAGS_PER_LANGUAGE;
+
+      hb_ot_tags_from_script_and_language (script, language,
+                                          &script_count, script_tags,
+                                          &language_count, language_tags);
+
+      if (ot_script_str)
+      {
+       script_tags[0] = hb_tag_from_string (ot_script_str, -1);
+       script_count = 1;
+      }
+      if (ot_language_str)
+      {
+       language_tags[0] = hb_tag_from_string (ot_language_str, -1);
+       language_count = 1;
+      }
+
+      unsigned script_index;
+      hb_tag_t chosen_script;
+      hb_ot_layout_table_select_script (face, table_tag,
+                                       script_count, script_tags,
+                                       &script_index, &chosen_script);
+
+      unsigned language_index;
+      hb_tag_t chosen_language;
+      hb_ot_layout_script_select_language2 (face, table_tag,
+                                          script_index,
+                                          language_count, language_tags,
+                                          &language_index, &chosen_language);
+
+      if (verbose)
+      {
+        if (chosen_script)
+       {
+         printf ("     Script: %c%c%c%c\n", HB_UNTAG (chosen_script));
+         if (chosen_language)
+           printf ("   Language: %c%c%c%c\n", HB_UNTAG (chosen_language));
+         else
+           printf ("   Language: Default\n");
+       }
+      }
+
+      unsigned feature_array[32];
+      unsigned feature_count = sizeof feature_array / sizeof feature_array[0];
+      unsigned feature_offset = 0;
+      do
+      {
+       hb_ot_layout_language_get_feature_indexes (face, table_tag,
+                                                  script_index, language_index,
+                                                  feature_offset,
+                                                  &feature_count,
+                                                  feature_array);
+
+       for (unsigned feature_index = 0; feature_index < feature_count; feature_index++)
+       {
+         hb_ot_name_id_t label_id;
+
+         hb_ot_layout_feature_get_name_ids (face,
+                                            table_tags[i],
+                                            feature_array[feature_index],
+                                            &label_id,
+                                            nullptr,
+                                            nullptr,
+                                            nullptr,
+                                            nullptr);
+
+         char name[64];
+         unsigned name_len = sizeof name;
+
+         _hb_ot_name_get_utf8 (face, label_id,
+                               language,
+                               &name_len, name);
+
+         printf ("     ");
+         if (verbose) printf ("Feature: ");
+         hb_tag_t feature_tag;
+         unsigned f_count = 1;
+         hb_ot_layout_table_get_feature_tags (face, table_tag,
+                                              feature_array[feature_index],
+                                              &f_count, &feature_tag);
+         printf ("%c%c%c%c", HB_UNTAG (feature_tag));
+
+         if (*name)
+           printf ("   %s", name);
+
+         printf ("\n");
+       }
+
+       feature_offset += feature_count;
+      }
+      while (feature_count == sizeof feature_array / sizeof feature_array[0]);
+    }
+  }
+
+#ifndef HB_NO_VAR
+  void
+  _list_variations ()
+  {
+    if (verbose)
+    {
+      separator ();
+      printf ("Variations information:\n\n");
+    }
+
+    hb_ot_var_axis_info_t *axes;
+
+    unsigned count = hb_ot_var_get_axis_infos (face, 0, nullptr, nullptr);
+    axes = (hb_ot_var_axis_info_t *) calloc (count, sizeof (hb_ot_var_axis_info_t));
+    hb_ot_var_get_axis_infos (face, 0, &count, axes);
+
+    bool has_hidden = false;
+
+    if (verbose && count)
+    {
+      printf ("Varitation axes:\n\n");
+      printf ("Tag     Minimum Default Maximum Name\n------------------------------------\n");
+    }
+    for (unsigned i = 0; i < count; i++)
+    {
+      const auto &axis = axes[i];
+      if (axis.flags & HB_OT_VAR_AXIS_FLAG_HIDDEN)
+       has_hidden = true;
+
+      char name[64];
+      unsigned name_len = sizeof name;
+
+      _hb_ot_name_get_utf8 (face, axis.name_id,
+                           language,
+                           &name_len, name);
+
+      printf ("%c%c%c%c%s      %g      %g      %g      %s\n",
+             HB_UNTAG (axis.tag),
+             axis.flags & HB_OT_VAR_AXIS_FLAG_HIDDEN ? "*" : "",
+             (double) axis.min_value,
+             (double) axis.default_value,
+             (double) axis.max_value,
+             name);
+    }
+    if (verbose && has_hidden)
+      printf ("\n[*] Hidden axis\n");
+
+    free (axes);
+    axes = nullptr;
+
+    count = hb_ot_var_get_named_instance_count (face);
+    if (count)
+    {
+      if (verbose)
+      {
+       printf ("\n\nNamed instances:\n\n");
+      printf ("Index   Name                            Position\n------------------------------------------------\n");
+      }
+
+      for (unsigned i = 0; i < count; i++)
+      {
+       char name[64];
+       unsigned name_len = sizeof name;
+
+       hb_ot_name_id_t name_id = hb_ot_var_named_instance_get_subfamily_name_id (face, i);
+       _hb_ot_name_get_utf8 (face, name_id,
+                             language,
+                             &name_len, name);
+
+       unsigned coords_count = hb_ot_var_named_instance_get_design_coords (face, i, nullptr, nullptr);
+       float* coords;
+       coords = (float *) calloc (coords_count, sizeof (float));
+       hb_ot_var_named_instance_get_design_coords (face, i, &coords_count, coords);
+
+       printf ("%u     %-32s", i, name);
+       for (unsigned j = 0; j < coords_count; j++)
+         printf ("%g, ", (double) coords[j]);
+       printf ("\n");
+
+       free (coords);
+      }
+    }
+  }
+#endif
+
+#ifdef HAVE_CHAFA
+  GString *
+  _palette_chafa_str (unsigned palette_index)
+  {
+    unsigned count = hb_ot_color_palette_get_colors (face, palette_index, 0,
+                                                    nullptr, nullptr);
+
+    hb_color_t *palette = (hb_color_t *) malloc (count * sizeof (hb_color_t));
+    hb_ot_color_palette_get_colors (face, palette_index, 0,
+                                   &count, palette);
+
+#define REPEAT 16
+    hb_color_t *data = (hb_color_t *) malloc (count * REPEAT * sizeof (hb_color_t));
+    for (unsigned i = 0; i < count; i++)
+      for (unsigned j = 0; j < REPEAT; j++)
+       data[i * REPEAT + j] = palette[i];
+    free (palette);
+    palette = nullptr;
+
+    chafa_set_n_threads (1); // https://github.com/hpjansson/chafa/issues/125#issuecomment-1397475217
+                            //
+    gchar **environ = g_get_environ ();
+    ChafaTermInfo *term_info = chafa_term_db_detect (chafa_term_db_get_default (),
+                                                    environ);
+
+    ChafaCanvasMode mode;
+    ChafaPixelMode pixel_mode = CHAFA_PIXEL_MODE_SYMBOLS;
+    if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_DIRECT))
+      mode = CHAFA_CANVAS_MODE_TRUECOLOR;
+    else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_256))
+      mode = CHAFA_CANVAS_MODE_INDEXED_240;
+    else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_16))
+      mode = CHAFA_CANVAS_MODE_INDEXED_16;
+    else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_INVERT_COLORS))
+      mode = CHAFA_CANVAS_MODE_FGBG_BGFG;
+    else
+      mode = CHAFA_CANVAS_MODE_FGBG;
+
+    ChafaSymbolMap *symbol_map = chafa_symbol_map_new ();
+    chafa_symbol_map_add_by_tags (symbol_map,
+                                 (ChafaSymbolTags) (CHAFA_SYMBOL_TAG_BLOCK));
+
+    ChafaCanvasConfig *config = chafa_canvas_config_new ();
+    chafa_canvas_config_set_canvas_mode (config, mode);
+    chafa_canvas_config_set_pixel_mode (config, pixel_mode);
+    chafa_canvas_config_set_cell_geometry (config, REPEAT, 1);
+    chafa_canvas_config_set_geometry (config, 2 * count, 1);
+    chafa_canvas_config_set_symbol_map (config, symbol_map);
+    chafa_canvas_config_set_color_extractor (config, CHAFA_COLOR_EXTRACTOR_MEDIAN);
+    chafa_canvas_config_set_work_factor (config, 1.0f);
+
+    ChafaCanvas *canvas = chafa_canvas_new (config);
+    chafa_canvas_draw_all_pixels (canvas,
+                                 G_BYTE_ORDER == G_BIG_ENDIAN
+                                   ? CHAFA_PIXEL_BGRA8_UNASSOCIATED
+                                   : CHAFA_PIXEL_ARGB8_UNASSOCIATED,
+                                 (const guint8 *) data,
+                                 count * REPEAT,
+                                 1,
+                                 sizeof (hb_color_t));
+
+    free (data);
+
+    auto gs = chafa_canvas_print (canvas, term_info);
+
+    chafa_canvas_unref (canvas);
+    chafa_canvas_config_unref (config);
+    chafa_symbol_map_unref (symbol_map);
+    chafa_term_info_unref (term_info);
+    g_strfreev (environ);
+
+    return gs;
+  }
+#endif
+
+  void
+  _list_palettes ()
+  {
+    if (verbose)
+    {
+      separator ();
+      printf ("Color palettes information:\n");
+    }
+
+    {
+      if (verbose)
+      {
+       printf ("\nPalettes:\n\n");
+       printf ("Index  Flags   Name\n--------------------\n");
+      }
+      unsigned count = hb_ot_color_palette_get_count (face);
+      for (unsigned i = 0; i < count; i++)
+      {
+       hb_ot_name_id_t name_id = hb_ot_color_palette_get_name_id (face, i);
+       hb_ot_color_palette_flags_t flags = hb_ot_color_palette_get_flags (face, i);
+
+       char name[64];
+       unsigned name_len = sizeof name;
+
+       _hb_ot_name_get_utf8 (face, name_id,
+                             language,
+                             &name_len, name);
+        const char *type = "";
+       if (flags)
+       {
+         if (flags & HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND)
+          {
+           if (flags & HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND)
+             type = "Both";
+            else
+             type = "Light";
+          }
+          else {
+           type = "Dark";
+          }
+       }
+
+#ifdef HAVE_CHAFA
+       char *chafa_env = getenv ("HB_CHAFA");
+       bool use_chafa = !chafa_env || atoi (chafa_env);
+       if (verbose && use_chafa && isatty (fileno (stdout)))
+       {
+         GString *chafa_str = _palette_chafa_str (i);
+         printf ("%u   %s      %-23s   %*s\n", i, type, name,
+                 (int) chafa_str->len, chafa_str->str);
+         g_string_free (chafa_str, TRUE);
+       }
+       else
+#endif
+         printf ("%u   %s      %s\n", i, type, name);
+      }
+    }
+
+    {
+      if (verbose)
+      {
+       printf ("\nColors:\n\n");
+       printf ("Index  Name\n------------\n");
+      }
+      unsigned count = hb_ot_color_palette_get_colors (face, 0, 0, nullptr, nullptr);
+      for (unsigned i = 0; i < count; i++)
+      {
+       hb_ot_name_id_t name_id = hb_ot_color_palette_color_get_name_id (face, i);
+
+       char name[64];
+       unsigned name_len = sizeof name;
+       _hb_ot_name_get_utf8 (face, name_id,
+                             language,
+                             &name_len, name);
+
+       printf ("%u     %s\n", i, name);
+      }
+    }
+  }
+
+  void
+  _list_meta ()
+  {
+    if (verbose)
+    {
+      separator ();
+      printf ("Meta information:\n");
+    }
+
+    {
+      if (verbose)
+      {
+       printf ("\nTag  Data\n------------\n");
+      }
+      unsigned count = hb_ot_meta_get_entry_tags (face, 0, nullptr, nullptr);
+      for (unsigned i = 0; i < count; i++)
+      {
+       hb_ot_meta_tag_t tag;
+       unsigned len = 1;
+       hb_ot_meta_get_entry_tags (face, i, &len, &tag);
+
+       hb_blob_t *blob = hb_ot_meta_reference_entry (face, tag);
+
+       printf ("%c%c%c%c       %.*s\n", HB_UNTAG (tag),
+               (int) hb_blob_get_length (blob),
+               hb_blob_get_data (blob, nullptr));
+
+       hb_blob_destroy (blob);
+      }
+    }
+  }
+
+};
+
+
+template <typename consumer_t,
+         typename font_options_type>
+struct main_font_t :
+       option_parser_t,
+       font_options_type,
+       consumer_t
+{
+  int operator () (int argc, char **argv)
+  {
+    add_options ();
+
+    if (argc == 2)
+      consumer_t::show_all = true;
+
+    parse (&argc, &argv);
+
+    consumer_t::operator () (this);
+
+    return 0;
+  }
+};
+
+int
+main (int argc, char **argv)
+{
+  return batch_main<info_t> (argc, argv);
+}
index 7321f93..3b6751c 100644 (file)
@@ -59,8 +59,8 @@ struct shape_closure_consumer_t
     failed = false;
     buffer = hb_buffer_create ();
   }
-  template <typename text_options_t>
-  bool consume_line (text_options_t &text_opts)
+  template <typename text_options_type>
+  bool consume_line (text_options_type &text_opts)
   {
     unsigned int text_len;
     const char *text;
@@ -107,7 +107,7 @@ struct shape_closure_consumer_t
 
   protected:
   shape_options_t shaper;
-  hb_bool_t show_glyph_names = false;
+  hb_bool_t show_glyph_names = true;
 
   hb_set_t *glyphs = nullptr;
   hb_font_t *font = nullptr;
index 13c277a..9eec563 100644 (file)
 #include "batch.hh"
 #include "font-options.hh"
 #include "main-font-text.hh"
-#include "output-options.hh"
 #include "shape-consumer.hh"
-#include "shape-format.hh"
+#include "shape-output.hh"
 #include "text-options.hh"
 
 const unsigned DEFAULT_FONT_SIZE = FONT_SIZE_UPEM;
 const unsigned SUBPIXEL_BITS = 0;
 
-struct output_buffer_t : output_options_t<>
-{
-  void add_options (option_parser_t *parser)
-  {
-    parser->set_summary ("Shape text with given font.");
-    output_options_t::add_options (parser, hb_buffer_serialize_list_formats ());
-    format.add_options (parser);
-  }
-
-  void init (hb_buffer_t *buffer, const font_options_t *font_opts)
-  {
-    gs = g_string_new (nullptr);
-    line_no = 0;
-    font = hb_font_reference (font_opts->font);
-
-    if (!output_format)
-      serialize_format = HB_BUFFER_SERIALIZE_FORMAT_TEXT;
-    else
-      serialize_format = hb_buffer_serialize_format_from_string (output_format, -1);
-    /* An empty "output_format" parameter basically skips output generating.
-     * Useful for benchmarking. */
-    if ((!output_format || *output_format) &&
-       !hb_buffer_serialize_format_to_string (serialize_format))
-    {
-      if (explicit_output_format)
-       fail (false, "Unknown output format `%s'; supported formats are: %s",
-             output_format,
-             g_strjoinv ("/", const_cast<char**> (hb_buffer_serialize_list_formats ())));
-      else
-       /* Just default to TEXT if not explicitly requested and the
-        * file extension is not recognized. */
-       serialize_format = HB_BUFFER_SERIALIZE_FORMAT_TEXT;
-    }
-
-    unsigned int flags = HB_BUFFER_SERIALIZE_FLAG_DEFAULT;
-    if (!format.show_glyph_names)
-      flags |= HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES;
-    if (!format.show_clusters)
-      flags |= HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS;
-    if (!format.show_positions)
-      flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
-    if (!format.show_advances)
-      flags |= HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES;
-    if (format.show_extents)
-      flags |= HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS;
-    if (format.show_flags)
-      flags |= HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS;
-    serialize_flags = (hb_buffer_serialize_flags_t) flags;
-
-    if (format.trace)
-      hb_buffer_set_message_func (buffer, message_func, this, nullptr);
-  }
-  void new_line () { line_no++; }
-  void consume_text (hb_buffer_t  *buffer,
-                    const char   *text,
-                    unsigned int  text_len,
-                    hb_bool_t     utf8_clusters)
-  {
-    g_string_set_size (gs, 0);
-    format.serialize_buffer_of_text (buffer, line_no, text, text_len, font, gs);
-    fprintf (out_fp, "%s", gs->str);
-  }
-  void error (const char *message)
-  {
-    g_string_set_size (gs, 0);
-    format.serialize_message (line_no, "error", message, gs);
-    fprintf (out_fp, "%s", gs->str);
-  }
-  void consume_glyphs (hb_buffer_t  *buffer,
-                      const char   *text,
-                      unsigned int  text_len,
-                      hb_bool_t     utf8_clusters)
-  {
-    g_string_set_size (gs, 0);
-    format.serialize_buffer_of_glyphs (buffer, line_no, text, text_len, font,
-                                      serialize_format, serialize_flags, gs);
-    fprintf (out_fp, "%s", gs->str);
-  }
-  void finish (hb_buffer_t *buffer, const font_options_t *font_opts)
-  {
-    hb_buffer_set_message_func (buffer, nullptr, nullptr, nullptr);
-    hb_font_destroy (font);
-    g_string_free (gs, true);
-    gs = nullptr;
-    font = nullptr;
-  }
-
-  static hb_bool_t
-  message_func (hb_buffer_t *buffer,
-               hb_font_t *font,
-               const char *message,
-               void *user_data)
-  {
-    output_buffer_t *that = (output_buffer_t *) user_data;
-    that->trace (buffer, font, message);
-    return true;
-  }
-
-  void
-  trace (hb_buffer_t *buffer,
-        hb_font_t *font,
-        const char *message)
-  {
-    g_string_set_size (gs, 0);
-    format.serialize_line_no (line_no, gs);
-    g_string_append_printf (gs, "trace: %s     buffer: ", message);
-    format.serialize (buffer, font, serialize_format, serialize_flags, gs);
-    g_string_append_c (gs, '\n');
-    fprintf (out_fp, "%s", gs->str);
-  }
-
-
-  protected:
-
-  shape_format_options_t format;
-
-  GString *gs = nullptr;
-  unsigned int line_no = 0;
-  hb_font_t *font = nullptr;
-  hb_buffer_serialize_format_t serialize_format = HB_BUFFER_SERIALIZE_FORMAT_INVALID;
-  hb_buffer_serialize_flags_t serialize_flags = HB_BUFFER_SERIALIZE_FLAG_DEFAULT;
-};
-
 int
 main (int argc, char **argv)
 {
-  using main_t = main_font_text_t<shape_consumer_t<output_buffer_t>, font_options_t, shape_text_options_t>;
+  using main_t = main_font_text_t<shape_consumer_t<shape_output_t>, font_options_t, shape_text_options_t>;
   return batch_main<main_t> (argc, argv);
 }
index 82216d3..bd3df8f 100644 (file)
 
 #include <hb-subset.h>
 
+static hb_face_t* preprocess_face(hb_face_t* face)
+{
+  return hb_subset_preprocess (face);
+}
+
 /*
  * Command line interface to the harfbuzz font subsetter.
  */
@@ -103,11 +108,15 @@ struct subset_main_t : option_parser_t, face_options_t, output_options_t<false>
   {
     parse (argc, argv);
 
+    hb_face_t* orig_face = face;
+    if (preprocess)
+      orig_face = preprocess_face (face);
+
     hb_face_t *new_face = nullptr;
     for (unsigned i = 0; i < num_iterations; i++)
     {
       hb_face_destroy (new_face);
-      new_face = hb_subset_or_fail (face, input);
+      new_face = hb_subset_or_fail (orig_face, input);
     }
 
     bool success = new_face;
@@ -119,6 +128,8 @@ struct subset_main_t : option_parser_t, face_options_t, output_options_t<false>
     }
 
     hb_face_destroy (new_face);
+    if (preprocess)
+      hb_face_destroy (orig_face);
 
     return success ? 0 : 1;
   }
@@ -160,6 +171,7 @@ struct subset_main_t : option_parser_t, face_options_t, output_options_t<false>
   public:
 
   unsigned num_iterations = 1;
+  gboolean preprocess = false;
   hb_subset_input_t *input = nullptr;
 };
 
@@ -516,6 +528,19 @@ parse_name_languages (const char *name,
   return true;
 }
 
+static gboolean
+_keep_everything (const char *name,
+                 const char *arg,
+                 gpointer    data,
+                 GError    **error G_GNUC_UNUSED)
+{
+  subset_main_t *subset_main = (subset_main_t *) data;
+
+  hb_subset_input_keep_everything (subset_main->input);
+
+  return true;
+}
+
 template <hb_subset_flags_t flag>
 static gboolean
 set_flag (const char *name,
@@ -532,30 +557,31 @@ set_flag (const char *name,
 }
 
 static gboolean
-parse_layout_features (const char *name,
-                      const char *arg,
-                      gpointer    data,
-                      GError    **error G_GNUC_UNUSED)
+parse_layout_tag_list (hb_subset_sets_t set_type,
+                       const char *name,
+                       const char *arg,
+                       gpointer    data,
+                       GError    **error G_GNUC_UNUSED)
 {
   subset_main_t *subset_main = (subset_main_t *) data;
   hb_bool_t is_remove = (name[strlen (name) - 1] == '-');
   hb_bool_t is_add = (name[strlen (name) - 1] == '+');
-  hb_set_t *layout_features = hb_subset_input_set (subset_main->input, HB_SUBSET_SETS_LAYOUT_FEATURE_TAG);
+  hb_set_t *layout_tags = hb_subset_input_set (subset_main->input, set_type);
 
-  if (!is_remove && !is_add) hb_set_clear (layout_features);
+  if (!is_remove && !is_add) hb_set_clear (layout_tags);
 
   if (0 == strcmp (arg, "*"))
   {
-    hb_set_clear (layout_features);
+    hb_set_clear (layout_tags);
     if (!is_remove)
-      hb_set_invert (layout_features);
+      hb_set_invert (layout_tags);
     return true;
   }
 
   char *s = strtok((char *) arg, ", ");
   while (s)
   {
-    if (strlen (s) > 4) // table tags are at most 4 bytes
+    if (strlen (s) > 4) // tags are at most 4 bytes
     {
       g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
                    "Failed parsing table tag at: '%s'", s);
@@ -565,9 +591,9 @@ parse_layout_features (const char *name,
     hb_tag_t tag = hb_tag_from_string (s, strlen (s));
 
     if (!is_remove)
-      hb_set_add (layout_features, tag);
+      hb_set_add (layout_tags, tag);
     else
-      hb_set_del (layout_features, tag);
+      hb_set_del (layout_tags, tag);
 
     s = strtok(nullptr, ", ");
   }
@@ -576,6 +602,34 @@ parse_layout_features (const char *name,
 }
 
 static gboolean
+parse_layout_features (const char *name,
+                      const char *arg,
+                      gpointer    data,
+                      GError    **error)
+
+{
+  return parse_layout_tag_list (HB_SUBSET_SETS_LAYOUT_FEATURE_TAG,
+                                name,
+                                arg,
+                                data,
+                                error);
+}
+
+static gboolean
+parse_layout_scripts (const char *name,
+                      const char *arg,
+                      gpointer    data,
+                      GError    **error)
+
+{
+  return parse_layout_tag_list (HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG,
+                                name,
+                                arg,
+                                data,
+                                error);
+}
+
+static gboolean
 parse_drop_tables (const char *name,
                   const char *arg,
                   gpointer    data,
@@ -619,6 +673,186 @@ parse_drop_tables (const char *name,
   return true;
 }
 
+#ifndef HB_NO_VAR
+static gboolean
+parse_instance (const char *name,
+               const char *arg,
+               gpointer    data,
+               GError    **error)
+{
+  subset_main_t *subset_main = (subset_main_t *) data;
+  if (!subset_main->face) {
+    // There is no face, which is needed to set up instancing. Skip parsing these options.
+    return true;
+  }
+
+  char *s = strtok((char *) arg, "=");
+  while (s)
+  {
+    unsigned len = strlen (s);
+    if (len > 4)  //Axis tags are 4 bytes.
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                  "Failed parsing axis tag at: '%s'", s);
+      return false;
+    }
+
+    hb_tag_t axis_tag = hb_tag_from_string (s, len);
+
+    s = strtok(nullptr, ", ");
+    if (!s)
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                  "Value not specified for axis: %c%c%c%c", HB_UNTAG (axis_tag));
+      return false;
+    }
+
+#ifdef HB_EXPERIMENTAL_API
+    char *pp = s;
+    pp = strpbrk (pp, ":");
+    if (pp) // partial instancing
+    {
+      errno = 0;
+      char *pend;
+      float min_val = strtof (s, &pend);
+      if (errno || s == pend || pend != pp)
+      {
+        g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                     "Failed parsing axis value at: '%s'", s);
+        return false;
+      }
+      pp++;
+      float max_val = strtof (pp, &pend);
+      /* we need to specify 2 values or 3 values for partial instancing:
+       * at least new min and max values, new default is optional */
+      if (errno || pp == pend || (*pend != ':' && *pend != '\0'))
+      {
+        g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                     "Failed parsing axis value at: '%s'", s);
+        return false;
+      }
+      /* 3 values are specified */
+      float *def_val_p = nullptr;
+      float def_val;
+      if (*pend == ':')
+      {
+        def_val = max_val;
+        def_val_p = &def_val;
+        pp = pend + 1;
+        max_val = strtof (pp, &pend);
+        if (errno || pp == pend || *pend != '\0')
+        {
+          g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                     "Failed parsing axis value at: '%s'", s);
+          return false;
+        }
+      }
+      if (!hb_subset_input_set_axis_range (subset_main->input, subset_main->face, axis_tag, min_val, max_val, def_val_p))
+        {
+          g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                       "Error: axis: '%c%c%c%c', not present in fvar or invalid range with min:%.6f max:%.6f",
+                       HB_UNTAG (axis_tag), min_val, max_val);
+          return false;
+        }
+    }
+    else
+    {
+#endif
+      if (strcmp (s, "drop") == 0)
+      {
+        if (!hb_subset_input_pin_axis_to_default (subset_main->input, subset_main->face, axis_tag))
+        {
+          g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                       "Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag));
+          return false;
+        }
+      }
+      else
+      {
+        errno = 0;
+        char *p;
+        float axis_value = strtof (s, &p);
+        if (errno || s == p)
+        {
+          g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                       "Failed parsing axis value at: '%s'", s);
+          return false;
+        }
+  
+        if (!hb_subset_input_pin_axis_location (subset_main->input, subset_main->face, axis_tag, axis_value))
+        {
+          g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                       "Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag));
+          return false;
+        }
+      }
+#ifdef HB_EXPERIMENTAL_API
+    }
+#endif
+    s = strtok(nullptr, "=");
+  }
+
+  return true;
+}
+#endif
+
+static gboolean
+parse_glyph_map (const char *name,
+                const char *arg,
+                gpointer    data,
+                GError    **error)
+{
+  // Glyph map has the following format:
+  // <entry 1>,<entry 2>,...,<entry n>
+  // <entry> = <old gid>:<new gid>
+  subset_main_t *subset_main = (subset_main_t *) data;
+  hb_subset_input_t* input = subset_main->input;
+  hb_set_t *glyphs = hb_subset_input_glyph_set(input);
+
+  char *s = (char *) arg;
+  char *p;
+
+  while (s && *s)
+  {
+    while (*s && strchr (", ", *s))
+      s++;
+    if (!*s)
+      break;
+
+    errno = 0;
+    hb_codepoint_t start_code = strtoul (s, &p, 10);
+    if (s[0] == '-' || errno || s == p)
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                  "Failed parsing glyph map at: '%s'", s);
+      return false;
+    }
+
+    if (!p || p[0] != ':') // ranges
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                  "Failed parsing glyph map at: '%s'", s);
+      return false;
+    }
+
+    s = ++p;
+    hb_codepoint_t end_code = strtoul (s, &p, 10);
+    if (s[0] == '-' || errno || s == p)
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+               "Failed parsing glyph map at: '%s'", s);
+      return false;
+    }
+
+    hb_set_add(glyphs, start_code);
+    hb_map_set (hb_subset_input_old_to_new_glyph_mapping (input), start_code, end_code);
+
+    s = p;
+  }
+
+  return true;
+}
+
 template <GOptionArgFunc line_parser, bool allow_comments=true>
 static gboolean
 parse_file_for (const char *name,
@@ -728,9 +962,9 @@ subset_main_t::add_options ()
 
   GOptionEntry glyphset_entries[] =
   {
-    {"gids",           0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_gids,
+    {"gids",           'g', 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_gids,
      "Specify glyph IDs or ranges to include in the subset.\n"
-     "                                                       "
+     "                                                        "
      "Use --gids-=... to subtract codepoints from the current set.", "list of glyph indices/ranges or *"},
     {"gids-",          0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_gids,                 "Specify glyph IDs or ranges to remove from the subset", "list of glyph indices/ranges or *"},
     {"gids+",          0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_gids,                 "Specify glyph IDs or ranges to include in the subset", "list of glyph indices/ranges or *"},
@@ -742,19 +976,19 @@ subset_main_t::add_options ()
 
     {"glyphs-file",    0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_file_for<parse_glyphs>,  "Specify file to read glyph names from", "filename"},
 
-    {"text",           0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text,                    "Specify text to include in the subset. Use --text-=... to subtract codepoints from the current set.", "string"},
+    {"text",           't', 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text,                  "Specify text to include in the subset. Use --text-=... to subtract codepoints from the current set.", "string"},
     {"text-",          0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text,                 "Specify text to remove from the subset", "string"},
     {"text+",          0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text,                 "Specify text to include in the subset", "string"},
 
 
     {"text-file",      0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_file_for<parse_text, false>,"Specify file to read text from", "filename"},
-    {"unicodes",       0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes,
+    {"unicodes",       'u', 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes,
      "Specify Unicode codepoints or ranges to include in the subset. Use * to include all codepoints.\n"
-     "                                                       "
+     "                                                        "
      "--unicodes-=... can be used to subtract codepoints from the current set.\n"
-     "                                                       "
+     "                                                        "
      "For example: --unicodes=* --unicodes-=41,42,43 would create a subset with all codepoints\n"
-     "                                                       "
+     "                                                        "
      "except for 41, 42, 43.",
      "list of hex numbers/ranges or *"},
     {"unicodes-",      0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes, "Specify Unicode codepoints or ranges to remove from the subset", "list of hex numbers/ranges or *"},
@@ -771,18 +1005,35 @@ subset_main_t::add_options ()
 
   GOptionEntry other_entries[] =
   {
-    {"name-IDs",       0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids,         "Subset specified nameids. Use --name-IDs-=... to substract from the current set.", "list of int numbers or *"},
+    {"gid-map", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_glyph_map, "Specify a glyph mapping to use, any unmapped gids will be automatically assigned.", "List of pairs old_gid1:new_gid1,old_gid2:new_gid2,..."},
+    {"name-IDs",       0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids,         "Subset specified nameids. Use --name-IDs-=... to subtract from the current set.", "list of int numbers or *"},
     {"name-IDs-",      0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids,              "Subset specified nameids", "list of int numbers or *"},
     {"name-IDs+",      0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids,              "Subset specified nameids", "list of int numbers or *"},
-    {"name-languages", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_name_languages,  "Subset nameRecords with specified language IDs. Use --name-languages-=... to substract from the current set.", "list of int numbers or *"},
+    {"name-languages", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_name_languages,  "Subset nameRecords with specified language IDs. Use --name-languages-=... to subtract from the current set.", "list of int numbers or *"},
     {"name-languages-",        0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_name_languages,       "Subset nameRecords with specified language IDs", "list of int numbers or *"},
     {"name-languages+",        0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_name_languages,       "Subset nameRecords with specified language IDs", "list of int numbers or *"},
-    {"layout-features",        0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features, "Specify set of layout feature tags that will be preserved. Use --layout-features-=... to substract from the current set.", "list of string table tags or *"},
-    {"layout-features+",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features,     "Specify set of layout feature tags that will be preserved", "list of string table tags or *"},
-    {"layout-features-",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features,     "Specify set of layout feature tags that will be preserved", "list of string table tags or *"},
-    {"drop-tables",    0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables,     "Drop the specified tables. Use --drop-tables-=... to substract from the current set.", "list of string table tags or *"},
+
+    {"layout-features",        0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features, "Specify set of layout feature tags that will be preserved. Use --layout-features-=... to subtract from the current set.", "list of string table tags or *"},
+    {"layout-features+",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features,     "Specify set of layout feature tags that will be preserved", "list of string tags or *"},
+    {"layout-features-",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features,     "Specify set of layout feature tags that will be preserved", "list of string tags or *"},
+
+    {"layout-scripts", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_scripts,  "Specify set of layout script tags that will be preserved. Use --layout-scripts-=... to subtract from the current set.", "list of string table tags or *"},
+    {"layout-scripts+",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_scripts,       "Specify set of layout script tags that will be preserved", "list of string tags or *"},
+    {"layout-scripts-",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_scripts,       "Specify set of layout script tags that will be preserved", "list of string tags or *"},
+
+    {"drop-tables",    0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables,     "Drop the specified tables. Use --drop-tables-=... to subtract from the current set.", "list of string table tags or *"},
     {"drop-tables+",   0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables,  "Drop the specified tables.", "list of string table tags or *"},
     {"drop-tables-",   0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables,  "Drop the specified tables.", "list of string table tags or *"},
+#ifndef HB_NO_VAR
+    {"instance",       0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_instance,
+     "(Partially|Fully) Instantiate a variable font. A location consists of the tag of a variation axis, followed by '=', followed by a\n"
+     "number or the literal string 'drop'\n"
+     "                                                        "
+     "For example: --instance=\"wdth=100 wght=200\" or --instance=\"wdth=drop\"\n"
+     "                                                        "
+     "Note: currently only fully instancing is supported\n",
+     "list of comma separated axis-locations"},
+#endif
     {nullptr}
   };
   add_group (other_entries,
@@ -793,6 +1044,8 @@ subset_main_t::add_options ()
 
   GOptionEntry flag_entries[] =
   {
+    {"keep-everything",                0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &_keep_everything,
+     "Keep everything by default. Options after this can override the operation.", nullptr},
     {"no-hinting",             0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NO_HINTING>,               "Whether to drop hints", nullptr},
     {"retain-gids",            0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_RETAIN_GIDS>,              "If set don't renumber glyph ids in the subset.", nullptr},
     {"desubroutinize",         0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_DESUBROUTINIZE>,           "Remove CFF/CFF2 use of subroutines", nullptr},
@@ -800,7 +1053,13 @@ subset_main_t::add_options ()
     {"set-overlaps-flag",      0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG>,        "Set the overlaps flag on each glyph.", nullptr},
     {"notdef-outline",         0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NOTDEF_OUTLINE>,           "Keep the outline of \'.notdef\' glyph", nullptr},
     {"no-prune-unicode-ranges",        0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES>,  "Don't change the 'OS/2 ulUnicodeRange*' bits.", nullptr},
+    {"no-layout-closure",      0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE>,        "Don't perform glyph closure for layout substitution (GSUB).", nullptr},
     {"glyph-names",            0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_GLYPH_NAMES>,              "Keep PS glyph names in TT-flavored fonts. ", nullptr},
+    {"passthrough-tables",     0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED>, "Do not drop tables that the tool does not know how to subset.", nullptr},
+    {"preprocess-face",                0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &this->preprocess,
+     "Alternative name for --preprocess.", nullptr},
+    {"preprocess",             0, 0, G_OPTION_ARG_NONE, &this->preprocess,
+     "If set preprocesses the face with the add accelerator option before actually subsetting.", nullptr},
     {nullptr}
   };
   add_group (flag_entries,
index 8c8a1ee..1a743dd 100644 (file)
@@ -41,7 +41,9 @@
 # define CELL_H (2 * CELL_W)
 
 static void
-chafa_print_image_rgb24 (const void *data, int width, int height, int stride)
+chafa_print_image_rgb24 (const void *data, int width, int height, int stride, int level,
+                        cairo_write_func_t     write_func,
+                        void                   *closure)
 {
   ChafaTermInfo *term_info;
   ChafaSymbolMap *symbol_map;
@@ -57,6 +59,8 @@ chafa_print_image_rgb24 (const void *data, int width, int height, int stride)
   /* Adapt to terminal; use sixels if available, and fall back to symbols
    * with as many colors as are supported */
 
+  chafa_set_n_threads (1); // https://github.com/hpjansson/chafa/issues/125#issuecomment-1397475217
+
   environ = g_get_environ ();
   term_info = chafa_term_db_detect (chafa_term_db_get_default (),
                                     environ);
@@ -68,8 +72,8 @@ chafa_print_image_rgb24 (const void *data, int width, int height, int stride)
     pixel_mode = CHAFA_PIXEL_MODE_SIXELS;
     mode = CHAFA_CANVAS_MODE_TRUECOLOR;
   }
-//  else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_DIRECT))
-//    mode = CHAFA_CANVAS_MODE_TRUECOLOR;
+  else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_DIRECT))
+    mode = CHAFA_CANVAS_MODE_TRUECOLOR;
   else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_256))
     mode = CHAFA_CANVAS_MODE_INDEXED_240;
   else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_16))
@@ -84,12 +88,15 @@ chafa_print_image_rgb24 (const void *data, int width, int height, int stride)
   symbol_map = chafa_symbol_map_new ();
   chafa_symbol_map_add_by_tags (symbol_map,
                                 (ChafaSymbolTags) (CHAFA_SYMBOL_TAG_BLOCK
-                                                   | CHAFA_SYMBOL_TAG_SPACE));
+                                                   | CHAFA_SYMBOL_TAG_SPACE
+                                                  | (level >= 2 ? CHAFA_SYMBOL_TAG_WEDGE : 0)
+                                                  | (level >= 3 ? CHAFA_SYMBOL_TAG_ALL : 0)
+                               ));
 
   config = chafa_canvas_config_new ();
   chafa_canvas_config_set_canvas_mode (config, mode);
   chafa_canvas_config_set_pixel_mode (config, pixel_mode);
-  chafa_canvas_config_set_cell_geometry (config, 10, 20);
+  chafa_canvas_config_set_cell_geometry (config, CELL_W, CELL_H);
   chafa_canvas_config_set_geometry (config, cols, rows);
   chafa_canvas_config_set_symbol_map (config, symbol_map);
   chafa_canvas_config_set_color_extractor (config, CHAFA_COLOR_EXTRACTOR_MEDIAN);
@@ -111,10 +118,10 @@ chafa_print_image_rgb24 (const void *data, int width, int height, int stride)
 
   /* Print the string */
 
-  fwrite (gs->str, sizeof (char), gs->len, stdout);
+  write_func (closure, (const unsigned char *) gs->str, gs->len);
 
   if (pixel_mode != CHAFA_PIXEL_MODE_SIXELS)
-    fputc ('\n', stdout);
+    write_func (closure, (const unsigned char *) "\n", 1);
 
   /* Free resources */
 
@@ -164,6 +171,7 @@ helper_cairo_surface_write_to_ansi_stream (cairo_surface_t  *surface,
   uint32_t bg_color = data ? * (uint32_t *) data : 0;
 
   /* Drop first row while empty */
+  auto orig_data = data;
   while (height)
   {
     unsigned int i;
@@ -175,9 +183,14 @@ helper_cairo_surface_write_to_ansi_stream (cairo_surface_t *surface,
     data += stride / 4;
     height--;
   }
+  if (orig_data < data)
+  {
+    data -= stride / 4;
+    height++; /* Add one first blank row for padding. */
+  }
 
   /* Drop last row while empty */
-  unsigned int orig_height = height;
+  auto orig_height = height;
   while (height)
   {
     const uint32_t *row = data + (height - 1) * stride / 4;
@@ -195,11 +208,17 @@ helper_cairo_surface_write_to_ansi_stream (cairo_surface_t        *surface,
   if (width && height)
   {
 #ifdef HAVE_CHAFA
-    if (true)
-      chafa_print_image_rgb24 (data, width, height, stride);
+    const char *env = getenv ("HB_CHAFA");
+    int chafa_level = 1;
+    if (env)
+      chafa_level = atoi (env);
+    if (chafa_level)
+      chafa_print_image_rgb24 (data, width, height, stride, chafa_level,
+                              write_func, closure);
     else
 #endif
-      ansi_print_image_rgb24 (data, width, height, stride / 4);
+      ansi_print_image_rgb24 (data, width, height, stride / 4,
+                             write_func, closure);
   }
 
   cairo_surface_destroy (surface);
diff --git a/util/helper-cairo-ft.hh b/util/helper-cairo-ft.hh
new file mode 100644 (file)
index 0000000..8ec3728
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright © 2022  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 HELPER_CAIRO_FT_HH
+#define HELPER_CAIRO_FT_HH
+
+#include "font-options.hh"
+
+#include <cairo-ft.h>
+#include <hb-ft.h>
+#include FT_MULTIPLE_MASTERS_H
+
+static FT_Library ft_library;
+
+#ifdef HAVE_ATEXIT
+static inline
+void free_ft_library ()
+{
+  FT_Done_FreeType (ft_library);
+}
+#endif
+
+static void
+_release_blob (void *arg)
+{
+  FT_Face ft_face = (FT_Face) arg;
+  hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
+}
+
+static inline cairo_font_face_t *
+helper_cairo_create_ft_font_face (const font_options_t *font_opts)
+{
+  cairo_font_face_t *cairo_face;
+  /* We cannot use the FT_Face from hb_font_t, as doing so will confuse hb_font_t because
+   * cairo will reset the face size.  As such, create new face...
+   * TODO Perhaps add API to hb-ft to encapsulate this code. */
+  FT_Face ft_face = nullptr;//hb_ft_font_get_face (font);
+  if (!ft_face)
+  {
+    if (!ft_library)
+    {
+      FT_Init_FreeType (&ft_library);
+#ifdef HAVE_ATEXIT
+      atexit (free_ft_library);
+#endif
+    }
+
+    unsigned int blob_length;
+    const char *blob_data = hb_blob_get_data (font_opts->blob, &blob_length);
+
+    if (FT_New_Memory_Face (ft_library,
+                           (const FT_Byte *) blob_data,
+                           blob_length,
+                           font_opts->face_index,
+                           &ft_face))
+      fail (false, "FT_New_Memory_Face fail");
+  }
+  if (!ft_face)
+  {
+    /* This allows us to get some boxes at least... */
+    cairo_face = cairo_toy_font_face_create ("@cairo:sans",
+                                            CAIRO_FONT_SLANT_NORMAL,
+                                            CAIRO_FONT_WEIGHT_NORMAL);
+  }
+  else
+  {
+    ft_face->generic.data = hb_blob_reference (font_opts->blob);
+    ft_face->generic.finalizer = _release_blob;
+
+#if !defined(HB_NO_VAR) && defined(HAVE_FT_SET_VAR_BLEND_COORDINATES)
+    unsigned int num_coords;
+    const float *coords = hb_font_get_var_coords_design (font_opts->font, &num_coords);
+    if (num_coords)
+    {
+      FT_Fixed *ft_coords = (FT_Fixed *) calloc (num_coords, sizeof (FT_Fixed));
+      if (ft_coords)
+      {
+       for (unsigned int i = 0; i < num_coords; i++)
+         ft_coords[i] = coords[i] * 65536.f;
+       FT_Set_Var_Design_Coordinates (ft_face, num_coords, ft_coords);
+       free (ft_coords);
+      }
+    }
+#endif
+
+    cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, font_opts->ft_load_flags);
+  }
+  return cairo_face;
+}
+
+static inline bool
+helper_cairo_ft_scaled_font_has_color (cairo_scaled_font_t *scaled_font)
+{
+  bool ret = false;
+#ifdef FT_HAS_COLOR
+  FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
+  if (ft_face)
+  {
+    if (FT_HAS_COLOR (ft_face))
+      ret = true;
+    cairo_ft_scaled_font_unlock_face (scaled_font);
+  }
+#endif
+  return ret;
+}
+
+#endif
index b8d4612..d931d1b 100644 (file)
 
 #include "view-options.hh"
 #include "output-options.hh"
+#ifdef HAVE_CAIRO_FT
+#  include "helper-cairo-ft.hh"
+#endif
 
-#include <cairo-ft.h>
-#include <hb-ft.h>
-#include FT_MULTIPLE_MASTERS_H
+#include <cairo.h>
+#include <hb.h>
+#include <hb-cairo.h>
 
 #include "helper-cairo-ansi.hh"
 #ifdef CAIRO_HAS_SVG_SURFACE
@@ -65,74 +68,44 @@ _cairo_eps_surface_create_for_stream (cairo_write_func_t  write_func,
 #  endif
 #endif
 
-
-static FT_Library ft_library;
-
-#ifdef HAVE_ATEXIT
-static inline
-void free_ft_library ()
+static inline bool
+helper_cairo_use_hb_draw (const font_options_t *font_opts)
 {
-  FT_Done_FreeType (ft_library);
+  const char *env = getenv ("HB_DRAW");
+  if (!env)
+    /* Older cairo had a bug in rendering COLRv0 fonts in
+     * right-to-left direction as well as clipping issue
+     * with user-fonts.
+     *
+     * https://github.com/harfbuzz/harfbuzz/issues/4051 */
+    return cairo_version () >= CAIRO_VERSION_ENCODE (1, 17, 5);
+
+  return atoi (env);
 }
-#endif
 
 static inline cairo_scaled_font_t *
-helper_cairo_create_scaled_font (const font_options_t *font_opts)
+helper_cairo_create_scaled_font (const font_options_t *font_opts,
+                                const view_options_t *view_opts)
 {
-  hb_font_t *font = hb_font_reference (font_opts->font);
-
-  cairo_font_face_t *cairo_face;
-  /* We cannot use the FT_Face from hb_font_t, as doing so will confuse hb_font_t because
-   * cairo will reset the face size.  As such, create new face...
-   * TODO Perhaps add API to hb-ft to encapsulate this code. */
-  FT_Face ft_face = nullptr;//hb_ft_font_get_face (font);
-  if (!ft_face)
-  {
-    if (!ft_library)
-    {
-      FT_Init_FreeType (&ft_library);
-#ifdef HAVE_ATEXIT
-      atexit (free_ft_library);
+  hb_font_t *font = font_opts->font;
+  bool use_hb_draw = true;
+
+#ifdef HAVE_CAIRO_FT
+  use_hb_draw = helper_cairo_use_hb_draw (font_opts);
 #endif
-    }
 
-    unsigned int blob_length;
-    const char *blob_data = hb_blob_get_data (font_opts->blob, &blob_length);
 
-    if (FT_New_Memory_Face (ft_library,
-                           (const FT_Byte *) blob_data,
-                           blob_length,
-                           font_opts->face_index,
-                           &ft_face))
-      fail (false, "FT_New_Memory_Face fail");
-  }
-  if (!ft_face)
+  cairo_font_face_t *cairo_face = nullptr;
+  if (use_hb_draw)
   {
-    /* This allows us to get some boxes at least... */
-    cairo_face = cairo_toy_font_face_create ("@cairo:sans",
-                                            CAIRO_FONT_SLANT_NORMAL,
-                                            CAIRO_FONT_WEIGHT_NORMAL);
+    cairo_face = hb_cairo_font_face_create_for_font (font);
+    hb_cairo_font_face_set_scale_factor (cairo_face, 1 << font_opts->subpixel_bits);
   }
+#ifdef HAVE_CAIRO_FT
   else
-  {
-#ifdef HAVE_FT_SET_VAR_BLEND_COORDINATES
-    unsigned int num_coords;
-    const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
-    if (num_coords)
-    {
-      FT_Fixed *ft_coords = (FT_Fixed *) calloc (num_coords, sizeof (FT_Fixed));
-      if (ft_coords)
-      {
-       for (unsigned int i = 0; i < num_coords; i++)
-         ft_coords[i] = coords[i] << 2;
-       FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
-       free (ft_coords);
-      }
-    }
+    cairo_face = helper_cairo_create_ft_font_face (font_opts);
 #endif
 
-    cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, font_opts->ft_load_flags);
-  }
   cairo_matrix_t ctm, font_matrix;
   cairo_font_options_t *font_options;
 
@@ -140,9 +113,41 @@ helper_cairo_create_scaled_font (const font_options_t *font_opts)
   cairo_matrix_init_scale (&font_matrix,
                           font_opts->font_size_x,
                           font_opts->font_size_y);
+  if (!use_hb_draw)
+    font_matrix.xy = -font_opts->slant * font_opts->font_size_x;
+
   font_options = cairo_font_options_create ();
   cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
   cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF);
+#ifdef CAIRO_COLOR_PALETTE_DEFAULT
+  cairo_font_options_set_color_palette (font_options, view_opts->palette);
+#endif
+#ifdef HAVE_CAIRO_FONT_OPTIONS_GET_CUSTOM_PALETTE_COLOR
+  if (view_opts->custom_palette)
+  {
+    char **entries = g_strsplit (view_opts->custom_palette, ",", -1);
+    unsigned idx = 0;
+    for (unsigned i = 0; entries[i]; i++)
+    {
+      const char *p = strchr (entries[i], '=');
+      if (!p)
+        p = entries[i];
+      else
+      {
+       sscanf (entries[i], "%u", &idx);
+        p++;
+      }
+
+      unsigned fr, fg, fb, fa;
+      fr = fg = fb = fa = 0;
+      if (parse_color (p, fr, fg,fb, fa))
+       cairo_font_options_set_custom_palette_color (font_options, idx, fr / 255., fg / 255., fb / 255., fa / 255.);
+
+      idx++;
+    }
+    g_strfreev (entries);
+  }
+#endif
 
   cairo_scaled_font_t *scaled_font = cairo_scaled_font_create (cairo_face,
                                                               &font_matrix,
@@ -152,30 +157,24 @@ helper_cairo_create_scaled_font (const font_options_t *font_opts)
   cairo_font_options_destroy (font_options);
   cairo_font_face_destroy (cairo_face);
 
-  static cairo_user_data_key_t key;
-  if (cairo_scaled_font_set_user_data (scaled_font,
-                                      &key,
-                                      (void *) font,
-                                      (cairo_destroy_func_t) hb_font_destroy))
-    hb_font_destroy (font);
-
   return scaled_font;
 }
 
 static inline bool
 helper_cairo_scaled_font_has_color (cairo_scaled_font_t *scaled_font)
 {
-  bool ret = false;
-#ifdef FT_HAS_COLOR
-  FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
-  if (ft_face)
-  {
-    if (FT_HAS_COLOR (ft_face))
-      ret = true;
-    cairo_ft_scaled_font_unlock_face (scaled_font);
-  }
+  hb_font_t *font = hb_cairo_font_face_get_font (cairo_scaled_font_get_font_face (scaled_font));
+
+#ifdef HAVE_CAIRO_FT
+  if (!font)
+    return helper_cairo_ft_scaled_font_has_color (scaled_font);
 #endif
-  return ret;
+
+  hb_face_t *face = hb_font_get_face (font);
+
+  return hb_ot_color_has_png (face) ||
+         hb_ot_color_has_layers (face) ||
+         hb_ot_color_has_paint (face);
 }
 
 
@@ -427,11 +426,11 @@ static const char *helper_cairo_supported_formats[] =
 };
 
 template <typename view_options_t,
-        typename output_options_t>
+        typename output_options_type>
 static inline cairo_t *
 helper_cairo_create_context (double w, double h,
                             view_options_t *view_opts,
-                            output_options_t *out_opts,
+                            output_options_type *out_opts,
                             cairo_content_t content)
 {
   cairo_surface_t *(*constructor) (cairo_write_func_t write_func,
@@ -460,6 +459,12 @@ helper_cairo_create_context (double w, double h,
        extension = "png";
        protocol = image_protocol_t::ITERM2;
       }
+      else if ((name = getenv ("TERM_PROGRAM")) != nullptr &&
+         0 == g_ascii_strcasecmp (name, "WezTerm"))
+      {
+       extension = "png";
+       protocol = image_protocol_t::ITERM2;
+      }
       else if ((name = getenv ("TERM")) != nullptr &&
               0 == g_ascii_strcasecmp (name, "xterm-kitty"))
       {
@@ -510,16 +515,16 @@ helper_cairo_create_context (double w, double h,
 
   unsigned int fr, fg, fb, fa, br, bg, bb, ba;
   const char *color;
-  br = bg = bb = 0; ba = 255;
+  br = bg = bb = ba = 255;
   color = view_opts->back ? view_opts->back : DEFAULT_BACK;
-  sscanf (color + (*color=='#'), "%2x%2x%2x%2x", &br, &bg, &bb, &ba);
+  parse_color (color, br, bg, bb, ba);
   fr = fg = fb = 0; fa = 255;
   color = view_opts->fore ? view_opts->fore : DEFAULT_FORE;
-  sscanf (color + (*color=='#'), "%2x%2x%2x%2x", &fr, &fg, &fb, &fa);
+  parse_color (color, fr, fg, fb, fa);
 
   if (content == CAIRO_CONTENT_ALPHA)
   {
-    if (view_opts->annotate ||
+    if (view_opts->show_extents ||
        br != bg || bg != bb ||
        fr != fg || fg != fb)
       content = CAIRO_CONTENT_COLOR;
@@ -584,117 +589,46 @@ helper_cairo_destroy_context (cairo_t *cr)
 
 
 struct helper_cairo_line_t {
-  cairo_glyph_t *glyphs;
-  unsigned int num_glyphs;
-  char *utf8;
-  unsigned int utf8_len;
-  cairo_text_cluster_t *clusters;
-  unsigned int num_clusters;
-  cairo_text_cluster_flags_t cluster_flags;
-
-  void finish () {
+  cairo_glyph_t *glyphs = nullptr;
+  unsigned int num_glyphs = 0;
+  char *utf8 = nullptr;
+  unsigned int utf8_len = 0;
+  cairo_text_cluster_t *clusters = nullptr;
+  unsigned int num_clusters = 0;
+  cairo_text_cluster_flags_t cluster_flags = (cairo_text_cluster_flags_t) 0;
+
+  helper_cairo_line_t (const char          *utf8_,
+                      unsigned             utf8_len_,
+                      hb_buffer_t         *buffer,
+                      hb_bool_t            utf8_clusters,
+                      unsigned             subpixel_bits) :
+    utf8 (utf8_ ? g_strndup (utf8_, utf8_len_) : nullptr),
+    utf8_len (utf8_len_)
+  {
+    hb_cairo_glyphs_from_buffer (buffer,
+                                utf8_clusters,
+                                1 << subpixel_bits, 1 << subpixel_bits,
+                                0., 0.,
+                                utf8, utf8_len,
+                                &glyphs, &num_glyphs,
+                                &clusters, &num_clusters,
+                                &cluster_flags);
+  }
+
+  void finish ()
+  {
     if (glyphs)
       cairo_glyph_free (glyphs);
     if (clusters)
       cairo_text_cluster_free (clusters);
-    if (utf8)
-      g_free (utf8);
+    g_free (utf8);
   }
 
-  void get_advance (double *x_advance, double *y_advance) {
+  void get_advance (double *x_advance, double *y_advance)
+  {
     *x_advance = glyphs[num_glyphs].x;
     *y_advance = glyphs[num_glyphs].y;
   }
 };
 
-static inline void
-helper_cairo_line_from_buffer (helper_cairo_line_t *l,
-                              hb_buffer_t         *buffer,
-                              const char          *text,
-                              unsigned int         text_len,
-                              int                  scale_bits,
-                              hb_bool_t            utf8_clusters)
-{
-  memset (l, 0, sizeof (*l));
-
-  l->num_glyphs = hb_buffer_get_length (buffer);
-  hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos (buffer, nullptr);
-  hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions (buffer, nullptr);
-  l->glyphs = cairo_glyph_allocate (l->num_glyphs + 1);
-
-  if (text) {
-    l->utf8 = g_strndup (text, text_len);
-    l->utf8_len = text_len;
-    l->num_clusters = l->num_glyphs ? 1 : 0;
-    for (unsigned int i = 1; i < l->num_glyphs; i++)
-      if (hb_glyph[i].cluster != hb_glyph[i-1].cluster)
-       l->num_clusters++;
-    l->clusters = cairo_text_cluster_allocate (l->num_clusters);
-  }
-
-  if ((l->num_glyphs && !l->glyphs) ||
-      (l->utf8_len && !l->utf8) ||
-      (l->num_clusters && !l->clusters))
-  {
-    l->finish ();
-    return;
-  }
-
-  hb_position_t x = 0, y = 0;
-  int i;
-  for (i = 0; i < (int) l->num_glyphs; i++)
-  {
-    l->glyphs[i].index = hb_glyph[i].codepoint;
-    l->glyphs[i].x = scalbn ((double)  hb_position->x_offset + x, scale_bits);
-    l->glyphs[i].y = scalbn ((double) -hb_position->y_offset + y, scale_bits);
-    x +=  hb_position->x_advance;
-    y += -hb_position->y_advance;
-
-    hb_position++;
-  }
-  l->glyphs[i].index = -1;
-  l->glyphs[i].x = scalbn ((double) x, scale_bits);
-  l->glyphs[i].y = scalbn ((double) y, scale_bits);
-
-  if (l->num_clusters) {
-    memset ((void *) l->clusters, 0, l->num_clusters * sizeof (l->clusters[0]));
-    hb_bool_t backward = HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (buffer));
-    l->cluster_flags = backward ? CAIRO_TEXT_CLUSTER_FLAG_BACKWARD : (cairo_text_cluster_flags_t) 0;
-    unsigned int cluster = 0;
-    const char *start = l->utf8, *end;
-    l->clusters[cluster].num_glyphs++;
-    if (backward) {
-      for (i = l->num_glyphs - 2; i >= 0; i--) {
-       if (hb_glyph[i].cluster != hb_glyph[i+1].cluster) {
-         g_assert (hb_glyph[i].cluster > hb_glyph[i+1].cluster);
-         if (utf8_clusters)
-           end = start + hb_glyph[i].cluster - hb_glyph[i+1].cluster;
-         else
-           end = g_utf8_offset_to_pointer (start, hb_glyph[i].cluster - hb_glyph[i+1].cluster);
-         l->clusters[cluster].num_bytes = end - start;
-         start = end;
-         cluster++;
-       }
-       l->clusters[cluster].num_glyphs++;
-      }
-      l->clusters[cluster].num_bytes = l->utf8 + text_len - start;
-    } else {
-      for (i = 1; i < (int) l->num_glyphs; i++) {
-       if (hb_glyph[i].cluster != hb_glyph[i-1].cluster) {
-         g_assert (hb_glyph[i].cluster > hb_glyph[i-1].cluster);
-         if (utf8_clusters)
-           end = start + hb_glyph[i].cluster - hb_glyph[i-1].cluster;
-         else
-           end = g_utf8_offset_to_pointer (start, hb_glyph[i].cluster - hb_glyph[i-1].cluster);
-         l->clusters[cluster].num_bytes = end - start;
-         start = end;
-         cluster++;
-       }
-       l->clusters[cluster].num_glyphs++;
-      }
-      l->clusters[cluster].num_bytes = l->utf8 + text_len - start;
-    }
-  }
-}
-
 #endif
index dabbd32..ca39c5a 100644 (file)
 
 /* main() body for utilities taking font and processing text.*/
 
-template <typename consumer_t, typename font_options_t, typename text_options_t>
-struct main_font_text_t : option_parser_t, font_options_t, text_options_t, consumer_t
+template <typename consumer_t,
+         typename font_options_type,
+         typename text_options_type>
+struct main_font_text_t :
+       option_parser_t,
+       font_options_type,
+       text_options_type,
+       consumer_t
 {
   int operator () (int argc, char **argv)
   {
@@ -53,8 +59,8 @@ struct main_font_text_t : option_parser_t, font_options_t, text_options_t, consu
 
   void add_options ()
   {
-    font_options_t::add_options (this);
-    text_options_t::add_options (this);
+    font_options_type::add_options (this);
+    text_options_type::add_options (this);
     consumer_t::add_options (this);
 
     GOptionEntry entries[] =
index fdab620..e857384 100644 (file)
@@ -6,6 +6,10 @@ hb_shape_sources = [
   'hb-shape.cc',
 ]
 
+hb_info_sources = [
+  'hb-info.cc',
+]
+
 hb_ot_shape_closure_sources = [
   'hb-ot-shape-closure.cc',
 ]
@@ -17,15 +21,15 @@ hb_subset_cli_sources = [
 util_deps = [freetype_dep, cairo_dep, cairo_ft_dep, glib_dep]
 
 if conf.get('HAVE_GLIB', 0) == 1
-  if conf.get('HAVE_FREETYPE', 0) == 1 and conf.get('HAVE_CAIRO_FT', 0) == 1
-
+  if conf.get('HAVE_CAIRO', 0) == 1
     hb_view = executable('hb-view', hb_view_sources,
       cpp_args: cpp_args,
       include_directories: [incconfig, incsrc],
       dependencies: [util_deps, chafa_dep],
-      link_with: [libharfbuzz],
+      link_with: [libharfbuzz, libharfbuzz_cairo],
       install: true,
     )
+    meson.override_find_program('hb-view', hb_view)
   endif
 
   hb_shape = executable('hb-shape', hb_shape_sources,
@@ -35,6 +39,16 @@ if conf.get('HAVE_GLIB', 0) == 1
     link_with: [libharfbuzz],
     install: true,
   )
+  meson.override_find_program('hb-shape', hb_shape)
+
+  hb_info = executable('hb-info', [hb_info_sources, gobject_enums_h],
+    cpp_args: cpp_args,
+    include_directories: [incconfig, incsrc],
+    dependencies: [util_deps, libharfbuzz_gobject_dep, chafa_dep],
+    link_with: [libharfbuzz],
+    install: true,
+  )
+  meson.override_find_program('hb-info', hb_info)
 
   hb_subset = executable('hb-subset', hb_subset_cli_sources,
     cpp_args: cpp_args,
@@ -43,6 +57,7 @@ if conf.get('HAVE_GLIB', 0) == 1
     link_with: [libharfbuzz, libharfbuzz_subset],
     install: true,
   )
+  meson.override_find_program('hb-subset', hb_subset)
 
   hb_ot_shape_closure = executable('hb-ot-shape-closure', hb_ot_shape_closure_sources,
     cpp_args: cpp_args,
@@ -51,6 +66,7 @@ if conf.get('HAVE_GLIB', 0) == 1
     link_with: [libharfbuzz],
     install: true,
   )
+  meson.override_find_program('hb-ot-shape-closure', hb_ot_shape_closure)
 else
   # Disable tests that use this
   hb_shape = disabler()
index 790650b..07212be 100644 (file)
 #include <locale.h>
 #include <errno.h>
 #include <fcntl.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h> /* for isatty() */
-#endif
 #if defined(_WIN32) || defined(__CYGWIN__)
 #include <io.h> /* for setmode() under Windows */
 #endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* for isatty() */
+#endif
 
+
+#include <hb-features.h>
 #include <hb.h>
 #include <hb-ot.h>
+
 #include <glib.h>
 #include <glib/gprintf.h>
 
 
+
 static inline void fail (hb_bool_t suggest_help, const char *format, ...) G_GNUC_NORETURN G_GNUC_PRINTF (2, 3);
 
 static inline void
@@ -241,4 +245,44 @@ __inline float scalbnf (float x, int exp)
 }
 #endif
 
+static inline bool
+parse_color (const char *s,
+            unsigned &r,
+            unsigned &g,
+            unsigned &b,
+            unsigned &a)
+{
+  bool ret = false;
+
+  while (*s == ' ') s++;
+  if (*s == '#') s++;
+
+  unsigned sr, sg, sb, sa;
+  sa = 255;
+  if (sscanf (s, "%2x%2x%2x%2x", &sr, &sg, &sb, &sa) <= 2)
+  {
+    if (sscanf (s, "%1x%1x%1x%1x", &sr, &sg, &sb, &sa) >= 3)
+    {
+      sr *= 17;
+      sg *= 17;
+      sb *= 17;
+      sa *= 17;
+      ret = true;
+    }
+  }
+  else
+    ret = true;
+
+  if (ret)
+  {
+    r = sr;
+    g = sg;
+    b = sb;
+    a = sa;
+  }
+
+  return ret;
+}
+
+
 #endif
index 2115189..15c193f 100644 (file)
@@ -61,11 +61,11 @@ struct shape_consumer_t : shape_options_t
 
     for (unsigned int n = num_iterations; n; n--)
     {
-      const char *error = nullptr;
-
-      populate_buffer (buffer, text, text_len, app.text_before, app.text_after);
+      populate_buffer (buffer, text, text_len, app.text_before, app.text_after, app.font);
       if (n == 1)
        output.consume_text (buffer, text, text_len, utf8_clusters);
+
+      const char *error = nullptr;
       if (!shape (app.font, buffer, &error))
       {
        failed = true;
@@ -77,7 +77,10 @@ struct shape_consumer_t : shape_options_t
       }
     }
 
-    output.consume_glyphs (buffer, text, text_len, utf8_clusters);
+    if (glyphs)
+      output.consume_glyphs (buffer, nullptr, 0, false);
+    else
+      output.consume_glyphs (buffer, text, text_len, utf8_clusters);
     return true;
   }
   template <typename app_t>
index 18b0b96..128a53b 100644 (file)
@@ -124,7 +124,7 @@ shape_format_options_t::serialize_line_no (unsigned int  line_no,
                                           GString      *gs)
 {
   if (show_line_num)
-    g_string_append_printf (gs, "%d: ", line_no);
+    g_string_append_printf (gs, "%u: ", line_no);
 }
 inline void
 shape_format_options_t::serialize_buffer_of_text (hb_buffer_t  *buffer,
index 806b34b..b22b958 100644 (file)
@@ -52,6 +52,8 @@ struct shape_options_t
                                  (bot ? HB_BUFFER_FLAG_BOT : 0) |
                                  (eot ? HB_BUFFER_FLAG_EOT : 0) |
                                  (verify ? HB_BUFFER_FLAG_VERIFY : 0) |
+                                 (unsafe_to_concat ? HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT : 0) |
+                                 (safe_to_insert_tatweel ? HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL : 0) |
                                  (preserve_default_ignorables ? HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES : 0) |
                                  (remove_default_ignorables ? HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES : 0) |
                                  0));
@@ -62,9 +64,55 @@ struct shape_options_t
   }
 
   void populate_buffer (hb_buffer_t *buffer, const char *text, int text_len,
-                       const char *text_before, const char *text_after)
+                       const char *text_before, const char *text_after,
+                       hb_font_t *font)
   {
     hb_buffer_clear_contents (buffer);
+
+    if (glyphs)
+    {
+      /* Call the setup_buffer first while the buffer is empty,
+       * as guess_segment_properties doesn't like glyphs in the buffer. */
+
+      setup_buffer (buffer);
+      char *glyphs_text = (char *) text;
+      int glyphs_len = text_len;
+      if (glyphs_len < 0)
+       glyphs_len = strlen (glyphs_text);
+
+      if (glyphs_len && glyphs_text[glyphs_len - 1] != ']')
+      {
+       glyphs_text = g_strdup_printf ("%*s]", glyphs_len, glyphs_text);
+       glyphs_len = -1;
+      }
+
+      hb_buffer_deserialize_glyphs (buffer,
+                                   glyphs_text, glyphs_len,
+                                   nullptr,
+                                   font,
+                                   HB_BUFFER_SERIALIZE_FORMAT_TEXT);
+
+      if (!strchr (glyphs_text, '+'))
+      {
+        scale_advances = false;
+        unsigned count;
+       hb_direction_t direction = hb_buffer_get_direction (buffer);
+       hb_glyph_info_t *infos = hb_buffer_get_glyph_infos (buffer, &count);
+       hb_glyph_position_t *positions = hb_buffer_get_glyph_positions (buffer, &count);
+       for (unsigned i = 0; i < count; i++)
+         hb_font_get_glyph_advance_for_direction (font,
+                                                  infos[i].codepoint,
+                                                  direction,
+                                                  &positions[i].x_advance,
+                                                  &positions[i].y_advance);
+      }
+
+      if (glyphs_text != text)
+        g_free (glyphs_text);
+
+      return;
+    }
+
     if (text_before) {
       unsigned int len = strlen (text_before);
       hb_buffer_add_utf8 (buffer, text_before, len, len, 0);
@@ -91,11 +139,74 @@ struct shape_options_t
 
   hb_bool_t shape (hb_font_t *font, hb_buffer_t *buffer, const char **error=nullptr)
   {
-    if (!hb_shape_full (font, buffer, features, num_features, shapers))
+    if (glyphs)
+    {
+      /* Scale positions. */
+      int x_scale, y_scale;
+      hb_font_get_scale (font, &x_scale, &y_scale);
+      unsigned upem = hb_face_get_upem (hb_font_get_face (font));
+      unsigned count;
+      auto *positions = hb_buffer_get_glyph_positions (buffer, &count);
+      for (unsigned i = 0; i < count; i++)
+      {
+       auto &pos = positions[i];
+       pos.x_offset = pos.x_offset * x_scale / upem;
+       pos.y_offset = pos.y_offset * y_scale / upem;
+       if (scale_advances)
+       {
+         pos.x_advance = pos.x_advance * x_scale / upem;
+         pos.y_advance = pos.y_advance * y_scale / upem;
+       }
+      }
+    }
+    else
     {
-      if (error)
-       *error = "Shaping failed.";
-      goto fail;
+      if (advance <= 0)
+      {
+       if (!hb_shape_full (font, buffer, features, num_features, shapers))
+       {
+         if (error)
+           *error = "Shaping failed.";
+         goto fail;
+       }
+
+       if (advance < 0)
+       {
+         float unit = (1 << SUBPIXEL_BITS);
+
+         /* Calculate buffer advance */
+         float w = 0;
+         unsigned count = 0;
+         hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &count);
+         if (HB_DIRECTION_IS_HORIZONTAL (hb_buffer_get_direction (buffer)))
+           for (unsigned i = 0; i < count; i++)
+             w += pos[i].x_advance;
+         else
+           for (unsigned i = 0; i < count; i++)
+             w += pos[i].y_advance;
+
+         printf ("Default size: %u\n", (unsigned) roundf (w / unit));
+         exit (0);
+       }
+      }
+#ifdef HB_EXPERIMENTAL_API
+      else
+      {
+        float unit = (1 << SUBPIXEL_BITS);
+        float target_advance = advance * unit;
+       float w = 0;
+       hb_tag_t var_tag;
+       float var_value;
+       if (!hb_shape_justify (font, buffer, features, num_features, shapers,
+                              target_advance - unit * 0.5f, target_advance + unit * 0.5f,
+                              &w, &var_tag, &var_value))
+       {
+         if (error)
+           *error = "Shaping failed.";
+         goto fail;
+       }
+      }
+#endif
     }
 
     if (normalize_glyphs)
@@ -131,12 +242,17 @@ struct shape_options_t
   hb_feature_t *features = nullptr;
   unsigned int num_features = 0;
   char **shapers = nullptr;
+  signed advance = 0;
   hb_bool_t utf8_clusters = false;
   hb_codepoint_t invisible_glyph = 0;
   hb_codepoint_t not_found_glyph = 0;
   hb_buffer_cluster_level_t cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT;
   hb_bool_t normalize_glyphs = false;
+  hb_bool_t glyphs = false;
+  bool scale_advances = true;
   hb_bool_t verify = false;
+  hb_bool_t unsafe_to_concat = false;
+  hb_bool_t safe_to_insert_tatweel = false;
   unsigned int num_iterations = 1;
 };
 
@@ -216,7 +332,7 @@ parse_features (const char *name G_GNUC_UNUSED,
   p = s;
   do {
     shape_opts->num_features++;
-    p = strchr (p, ',');
+    p = strpbrk (p, ", ");
     if (p)
       p++;
   } while (p);
@@ -229,7 +345,7 @@ parse_features (const char *name G_GNUC_UNUSED,
   p = s;
   shape_opts->num_features = 0;
   while (p && *p) {
-    char *end = strchr (p, ',');
+    char *end = strpbrk (p, ", ");
     if (hb_feature_from_string (p, end ? end - p : -1, &shape_opts->features[shape_opts->num_features]))
       shape_opts->num_features++;
     p = end ? end + 1 : nullptr;
@@ -253,6 +369,10 @@ shape_options_t::add_options (option_parser_t *parser)
     {"script",         0, 0, G_OPTION_ARG_STRING,      &this->script,                  "Set text script (default: auto)",      "ISO-15924 tag"},
     {"bot",            0, 0, G_OPTION_ARG_NONE,        &this->bot,                     "Treat text as beginning-of-paragraph", nullptr},
     {"eot",            0, 0, G_OPTION_ARG_NONE,        &this->eot,                     "Treat text as end-of-paragraph",       nullptr},
+#ifdef HB_EXPERIMENTAL_API
+    {"justify-to",     0, 0,
+                             G_OPTION_ARG_INT,         &this->advance,                 "Target size to justify to",            "SIZE, or -1"},
+#endif
     {"preserve-default-ignorables",0, 0, G_OPTION_ARG_NONE,    &this->preserve_default_ignorables,     "Preserve Default-Ignorable characters",        nullptr},
     {"remove-default-ignorables",0, 0, G_OPTION_ARG_NONE,      &this->remove_default_ignorables,       "Remove Default-Ignorable characters",  nullptr},
     {"invisible-glyph",        0, 0, G_OPTION_ARG_INT,         &this->invisible_glyph,         "Glyph value to replace Default-Ignorables with",       nullptr},
@@ -260,8 +380,11 @@ shape_options_t::add_options (option_parser_t *parser)
     {"utf8-clusters",  0, 0, G_OPTION_ARG_NONE,        &this->utf8_clusters,           "Use UTF8 byte indices, not char indices",      nullptr},
     {"cluster-level",  0, 0, G_OPTION_ARG_INT,         &this->cluster_level,           "Cluster merging level (default: 0)",   "0/1/2"},
     {"normalize-glyphs",0, 0, G_OPTION_ARG_NONE,       &this->normalize_glyphs,        "Rearrange glyph clusters in nominal order",    nullptr},
+    {"unsafe-to-concat",0, 0, G_OPTION_ARG_NONE,       &this->unsafe_to_concat,        "Produce unsafe-to-concat glyph flag",  nullptr},
+    {"safe-to-insert-tatweel",0, 0, G_OPTION_ARG_NONE, &this->safe_to_insert_tatweel,  "Produce safe-to-insert-tatweel glyph flag",    nullptr},
+    {"glyphs",         0, 0, G_OPTION_ARG_NONE,        &this->glyphs,                  "Interpret input as glyph string",      nullptr},
     {"verify",         0, 0, G_OPTION_ARG_NONE,        &this->verify,                  "Perform sanity checks on shaping results",     nullptr},
-    {"num-iterations", 'n', G_OPTION_FLAG_IN_MAIN,
+    {"num-iterations", 'n',G_OPTION_FLAG_IN_MAIN,
                              G_OPTION_ARG_INT,         &this->num_iterations,          "Run shaper N times (default: 1)",      "N"},
     {nullptr}
   };
diff --git a/util/shape-output.hh b/util/shape-output.hh
new file mode 100644 (file)
index 0000000..ebf8dc4
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright © 2010  Behdad Esfahbod
+ * Copyright © 2011,2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_SHAPE_OUTPUT_HH
+#define HB_SHAPE_OUTPUT_HH
+
+#include "shape-format.hh"
+#include "output-options.hh"
+
+
+struct shape_output_t : output_options_t<>
+{
+  void add_options (option_parser_t *parser)
+  {
+    parser->set_summary ("Shape text with given font.");
+    output_options_t::add_options (parser, hb_buffer_serialize_list_formats ());
+    format.add_options (parser);
+  }
+
+  void init (hb_buffer_t *buffer, const font_options_t *font_opts)
+  {
+    gs = g_string_new (nullptr);
+    line_no = 0;
+    font = hb_font_reference (font_opts->font);
+
+    if (!output_format)
+      serialize_format = HB_BUFFER_SERIALIZE_FORMAT_TEXT;
+    else
+      serialize_format = hb_buffer_serialize_format_from_string (output_format, -1);
+    /* An empty "output_format" parameter basically skips output generating.
+     * Useful for benchmarking. */
+    if ((!output_format || *output_format) &&
+       !hb_buffer_serialize_format_to_string (serialize_format))
+    {
+      if (explicit_output_format)
+       fail (false, "Unknown output format `%s'; supported formats are: %s",
+             output_format,
+             g_strjoinv ("/", const_cast<char**> (hb_buffer_serialize_list_formats ())));
+      else
+       /* Just default to TEXT if not explicitly requested and the
+        * file extension is not recognized. */
+       serialize_format = HB_BUFFER_SERIALIZE_FORMAT_TEXT;
+    }
+
+    unsigned int flags = HB_BUFFER_SERIALIZE_FLAG_DEFAULT;
+    if (!format.show_glyph_names)
+      flags |= HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES;
+    if (!format.show_clusters)
+      flags |= HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS;
+    if (!format.show_positions)
+      flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
+    if (!format.show_advances)
+      flags |= HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES;
+    if (format.show_extents)
+      flags |= HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS;
+    if (format.show_flags)
+      flags |= HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS;
+    serialize_flags = (hb_buffer_serialize_flags_t) flags;
+
+    if (format.trace)
+      hb_buffer_set_message_func (buffer, message_func, this, nullptr);
+  }
+  void new_line () { line_no++; }
+  void consume_text (hb_buffer_t  *buffer,
+                    const char   *text,
+                    unsigned int  text_len,
+                    hb_bool_t     utf8_clusters)
+  {
+    g_string_set_size (gs, 0);
+    format.serialize_buffer_of_text (buffer, line_no, text, text_len, font, gs);
+    fprintf (out_fp, "%s", gs->str);
+  }
+  void error (const char *message)
+  {
+    g_string_set_size (gs, 0);
+    format.serialize_message (line_no, "error", message, gs);
+    fprintf (out_fp, "%s", gs->str);
+  }
+  void consume_glyphs (hb_buffer_t  *buffer,
+                      const char   *text,
+                      unsigned int  text_len,
+                      hb_bool_t     utf8_clusters)
+  {
+    g_string_set_size (gs, 0);
+    format.serialize_buffer_of_glyphs (buffer, line_no, text, text_len, font,
+                                      serialize_format, serialize_flags, gs);
+    fprintf (out_fp, "%s", gs->str);
+  }
+  void finish (hb_buffer_t *buffer, const font_options_t *font_opts)
+  {
+    hb_buffer_set_message_func (buffer, nullptr, nullptr, nullptr);
+    hb_font_destroy (font);
+    g_string_free (gs, true);
+    gs = nullptr;
+    font = nullptr;
+  }
+
+  static hb_bool_t
+  message_func (hb_buffer_t *buffer,
+               hb_font_t *font,
+               const char *message,
+               void *user_data)
+  {
+    shape_output_t *that = (shape_output_t *) user_data;
+    that->trace (buffer, font, message);
+    return true;
+  }
+
+  void
+  trace (hb_buffer_t *buffer,
+        hb_font_t *font,
+        const char *message)
+  {
+    g_string_set_size (gs, 0);
+    format.serialize_line_no (line_no, gs);
+    g_string_append_printf (gs, "trace: %s     buffer: ", message);
+    format.serialize (buffer, font, serialize_format, serialize_flags, gs);
+    g_string_append_c (gs, '\n');
+    fprintf (stderr, "%s", gs->str);
+  }
+
+
+  protected:
+
+  shape_format_options_t format;
+
+  GString *gs = nullptr;
+  unsigned int line_no = 0;
+  hb_font_t *font = nullptr;
+  hb_buffer_serialize_format_t serialize_format = HB_BUFFER_SERIALIZE_FORMAT_INVALID;
+  hb_buffer_serialize_flags_t serialize_flags = HB_BUFFER_SERIALIZE_FLAG_DEFAULT;
+};
+
+
+#endif
index 5ea0a2d..3043efc 100644 (file)
@@ -127,7 +127,7 @@ encode_unicodes (const char *unicodes,
                 GString    *gs,
                 GError    **error)
 {
-#define DELIMITERS "<+->{},;&#\\xXuUnNiI\n\t\v\f\r "
+#define DELIMITERS "<+-|>{},;&#\\xXuUnNiI\n\t\v\f\r "
 
   char *s = (char *) unicodes;
   char *p;
index 1578f13..c96003c 100644 (file)
@@ -48,7 +48,7 @@ struct view_cairo_t : view_options_t, output_options_t<>
   void init (hb_buffer_t *buffer, const font_options_t *font_opts)
   {
     lines = g_array_new (false, false, sizeof (helper_cairo_line_t));
-    scale_bits = - (int) font_opts->subpixel_bits;
+    subpixel_bits = font_opts->subpixel_bits;
   }
   void new_line () {}
   void consume_text (hb_buffer_t  *buffer,
@@ -63,8 +63,7 @@ struct view_cairo_t : view_options_t, output_options_t<>
                       hb_bool_t     utf8_clusters)
   {
     direction = hb_buffer_get_direction (buffer);
-    helper_cairo_line_t l;
-    helper_cairo_line_from_buffer (&l, buffer, text, text_len, scale_bits, utf8_clusters);
+    helper_cairo_line_t l (text, text_len, buffer, utf8_clusters, subpixel_bits);
     g_array_append_val (lines, l);
   }
   void finish (hb_buffer_t *buffer, const font_options_t *font_opts)
@@ -88,7 +87,7 @@ struct view_cairo_t : view_options_t, output_options_t<>
 
   hb_direction_t direction = HB_DIRECTION_INVALID; // Remove this, make segment_properties accessible
   GArray *lines = nullptr;
-  int scale_bits = 0;
+  unsigned subpixel_bits = 0;
 };
 
 inline void
@@ -107,9 +106,9 @@ view_cairo_t::render (const font_options_t *font_opts)
   {
     hb_font_extents_t hb_extents;
     hb_font_get_extents_for_direction (font, direction, &hb_extents);
-    font_extents.ascent = scalbn ((double) hb_extents.ascender, scale_bits);
-    font_extents.descent = -scalbn ((double) hb_extents.descender, scale_bits);
-    font_extents.line_gap = scalbn ((double) hb_extents.line_gap, scale_bits);
+    font_extents.ascent = scalbn ((double) hb_extents.ascender, - (int) subpixel_bits);
+    font_extents.descent = -scalbn ((double) hb_extents.descender, - (int) subpixel_bits);
+    font_extents.line_gap = scalbn ((double) hb_extents.line_gap, - (int) subpixel_bits);
     have_font_extents = true;
   }
 
@@ -132,7 +131,8 @@ view_cairo_t::render (const font_options_t *font_opts)
       w =  MAX (w, x_sign * x_advance);
   }
 
-  cairo_scaled_font_t *scaled_font = helper_cairo_create_scaled_font (font_opts);
+  cairo_scaled_font_t *scaled_font = helper_cairo_create_scaled_font (font_opts,
+                                                                     this);
 
   /* See if font needs color. */
   cairo_content_t content = CAIRO_CONTENT_ALPHA;
@@ -168,12 +168,12 @@ view_cairo_t::render (const font_options_t *font_opts)
 
     cairo_translate (cr, -vert * leading, +horiz * leading);
 
-    if (annotate) {
+    if (show_extents)
+    {
       cairo_save (cr);
 
-      /* Draw actual glyph origins */
       cairo_set_source_rgba (cr, 1., 0., 0., .5);
-      cairo_set_line_width (cr, 5);
+      cairo_set_line_width (cr, 10);
       cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
       for (unsigned i = 0; i < l.num_glyphs; i++) {
        cairo_move_to (cr, l.glyphs[i].x, l.glyphs[i].y);
@@ -182,19 +182,36 @@ view_cairo_t::render (const font_options_t *font_opts)
       cairo_stroke (cr);
 
       cairo_restore (cr);
+      cairo_save (cr);
+
+      cairo_set_source_rgba (cr, 1., 0., 1., .5);
+      cairo_set_line_width (cr, 3);
+      for (unsigned i = 0; i < l.num_glyphs; i++)
+      {
+       hb_glyph_extents_t hb_extents;
+       hb_font_get_glyph_extents (font, l.glyphs[i].index, &hb_extents);
+       double x1 = scalbn ((double) hb_extents.x_bearing, - (int) subpixel_bits);
+       double y1 = -scalbn ((double) hb_extents.y_bearing, - (int) subpixel_bits);
+       double width = scalbn ((double) hb_extents.width, - (int) subpixel_bits);
+       double height = -scalbn ((double) hb_extents.height, - (int) subpixel_bits);
+
+       cairo_rectangle (cr, l.glyphs[i].x + x1, l.glyphs[i].y + y1, width, height);
+      }
+      cairo_stroke (cr);
+
+      cairo_restore (cr);
     }
 
-    if (0 && cairo_surface_get_type (cairo_get_target (cr)) == CAIRO_SURFACE_TYPE_IMAGE) {
-      /* cairo_show_glyphs() doesn't support subpixel positioning */
-      cairo_glyph_path (cr, l.glyphs, l.num_glyphs);
-      cairo_fill (cr);
-    } else if (l.num_clusters)
+  // https://github.com/harfbuzz/harfbuzz/issues/4378
+#if CAIRO_VERSION >= 11705
+    if (l.num_clusters)
       cairo_show_text_glyphs (cr,
                              l.utf8, l.utf8_len,
                              l.glyphs, l.num_glyphs,
                              l.clusters, l.num_clusters,
                              l.cluster_flags);
     else
+#endif
       cairo_show_glyphs (cr, l.glyphs, l.num_glyphs);
   }
 
index 322009a..9d89802 100644 (file)
@@ -39,13 +39,15 @@ struct view_options_t
   {
     g_free (fore);
     g_free (back);
+    g_free (custom_palette);
   }
 
   void add_options (option_parser_t *parser);
 
-  hb_bool_t annotate = false;
   char *fore = nullptr;
   char *back = nullptr;
+  unsigned int palette = 0;
+  char *custom_palette = nullptr;
   double line_space = 0;
   bool have_font_extents = false;
   struct font_extents_t {
@@ -54,6 +56,7 @@ struct view_options_t
   struct margin_t {
     double t, r, b, l;
   } margin = {DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN};
+  hb_bool_t show_extents = false;
 };
 
 
@@ -105,12 +108,16 @@ view_options_t::add_options (option_parser_t *parser)
 {
   GOptionEntry entries[] =
   {
-    {"annotate",       0, 0, G_OPTION_ARG_NONE,        &this->annotate,                "Annotate output rendering",                            nullptr},
+    {"annotate",       0, G_OPTION_FLAG_HIDDEN,
+                             G_OPTION_ARG_NONE,        &this->show_extents,            "Annotate output rendering",                            nullptr},
     {"background",     0, 0, G_OPTION_ARG_STRING,      &this->back,                    "Set background color (default: " DEFAULT_BACK ")",     "rrggbb/rrggbbaa"},
     {"foreground",     0, 0, G_OPTION_ARG_STRING,      &this->fore,                    "Set foreground color (default: " DEFAULT_FORE ")",     "rrggbb/rrggbbaa"},
+    {"font-palette",    0, 0, G_OPTION_ARG_INT,         &this->palette,                 "Set font palette (default: 0)",                "index"},
+    {"custom-palette",  0, 0, G_OPTION_ARG_STRING,      &this->custom_palette,          "Custom palette",                               "comma-separated colors"},
     {"line-space",     0, 0, G_OPTION_ARG_DOUBLE,      &this->line_space,              "Set space between lines (default: 0)",                 "units"},
     {"font-extents",   0, 0, G_OPTION_ARG_CALLBACK,    (gpointer) &parse_font_extents, "Set font ascent/descent/line-gap (default: auto)","one to three numbers"},
     {"margin",         0, 0, G_OPTION_ARG_CALLBACK,    (gpointer) &parse_margin,       "Margin around output (default: " G_STRINGIFY(DEFAULT_MARGIN) ")","one to four numbers"},
+    {"show-extents",   0, 0, G_OPTION_ARG_NONE,        &this->show_extents,            "Draw glyph extents",                                                   nullptr},
     {nullptr}
   };
   parser->add_group (entries,